aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-04-16 15:46:44 +0000
committerEric Andersen <andersen@codepoet.org>2001-04-16 15:46:44 +0000
commit1c0d311ff437823ee99019881d4fe4109def1a8c (patch)
treee08c48d0a4c26ba444a05e07ac09d793a55e3715
parentae1c704c44573c710ff196fa9c8bcaebbfe34966 (diff)
downloadbusybox-w32-1c0d311ff437823ee99019881d4fe4109def1a8c.tar.gz
busybox-w32-1c0d311ff437823ee99019881d4fe4109def1a8c.tar.bz2
busybox-w32-1c0d311ff437823ee99019881d4fe4109def1a8c.zip
Several fixes from Sterling Huxley for the vi applet.
-rw-r--r--Changelog11
-rw-r--r--editors/vi.c289
-rw-r--r--vi.c289
3 files changed, 430 insertions, 159 deletions
diff --git a/Changelog b/Changelog
index 296106d49..df69fe407 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,12 @@
10.52
2
3 * Sterling Huxley -- Several bugfixes for the vi applet.
4
5
6 -Erik Andersen, not yet released
7
8
9
10.51 100.51
2 Critical Bugfixes: 11 Critical Bugfixes:
3 * Erik Andersen -- Fixed a bug that could crash the shell in 0.50 12 * Erik Andersen -- Fixed a bug that could crash the shell in 0.50
@@ -69,7 +78,7 @@
69 restarting an aborted download. 78 restarting an aborted download.
70 79
71 80
72 -Erik Andersen, not yet released 81 -Erik Andersen, 10 April 2001
73 82
74 83
750.50 840.50
diff --git a/editors/vi.c b/editors/vi.c
index e4014362d..6a93fc1fe 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -19,7 +19,7 @@
19 */ 19 */
20 20
21char *vi_Version = 21char *vi_Version =
22 "$Id: vi.c,v 1.3 2001/04/04 19:33:32 andersen Exp $"; 22 "$Id: vi.c,v 1.4 2001/04/16 15:46:44 andersen Exp $";
23 23
24/* 24/*
25 * To compile for standalone use: 25 * To compile for standalone use:
@@ -32,13 +32,17 @@ char *vi_Version =
32/* 32/*
33 * Things To Do: 33 * Things To Do:
34 * EXINIT 34 * EXINIT
35 * $HOME/.exrc 35 * $HOME/.exrc and ./.exrc
36 * add magic to search /foo.*bar 36 * add magic to search /foo.*bar
37 * add :help command 37 * add :help command
38 * :map macros 38 * :map macros
39 * how about mode lines: vi: set sw=8 ts=8: 39 * how about mode lines: vi: set sw=8 ts=8:
40 * if mark[] values were line numbers rather than pointers 40 * if mark[] values were line numbers rather than pointers
41 * it would be easier to change the mark when add/delete lines 41 * it would be easier to change the mark when add/delete lines
42 * More intelligence in refresh()
43 * ":r !cmd" and "!cmd" to filter text through an external command
44 * A true "undo" facility
45 * An "ex" line oriented mode- maybe using "cmdedit"
42 */ 46 */
43 47
44//---- Feature -------------- Bytes to immplement 48//---- Feature -------------- Bytes to immplement
@@ -87,7 +91,7 @@ char *vi_Version =
87#define TRUE ((int)1) 91#define TRUE ((int)1)
88#define FALSE ((int)0) 92#define FALSE ((int)0)
89#endif /* TRUE */ 93#endif /* TRUE */
90#define MAX_SCR_COLS 300 94#define MAX_SCR_COLS BUFSIZ
91 95
92// Misc. non-Ascii keys that report an escape sequence 96// Misc. non-Ascii keys that report an escape sequence
93#define VI_K_UP 128 // cursor key Up 97#define VI_K_UP 128 // cursor key Up
@@ -253,7 +257,8 @@ static int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase"
253#endif /* BB_FEATURE_VI_SEARCH */ 257#endif /* BB_FEATURE_VI_SEARCH */
254#ifdef BB_FEATURE_VI_COLON 258#ifdef BB_FEATURE_VI_COLON
255static void Hit_Return(void); 259static void Hit_Return(void);
256static Byte *get_address(Byte *, int *); // get colon addr, if present 260static Byte *get_one_address(Byte *, int *); // get colon addr, if present
261static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present
257static void colon(Byte *); // execute the "colon" mode cmds 262static void colon(Byte *); // execute the "colon" mode cmds
258#endif /* BB_FEATURE_VI_COLON */ 263#endif /* BB_FEATURE_VI_COLON */
259#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON) 264#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON)
@@ -379,7 +384,7 @@ extern int vi_main(int argc, char **argv)
379static void edit_file(Byte * fn) 384static void edit_file(Byte * fn)
380{ 385{
381 char c; 386 char c;
382 int cnt, size; 387 int cnt, size, ch;
383 388
384#ifdef BB_FEATURE_VI_USE_SIGNALS 389#ifdef BB_FEATURE_VI_USE_SIGNALS
385 char *msg; 390 char *msg;
@@ -397,13 +402,15 @@ static void edit_file(Byte * fn)
397#endif /* BB_FEATURE_VI_WIN_RESIZE */ 402#endif /* BB_FEATURE_VI_WIN_RESIZE */
398 new_screen(rows, columns); // get memory for virtual screen 403 new_screen(rows, columns); // get memory for virtual screen
399 404
405 ch= 0;
400 cnt = file_size(fn); // file size 406 cnt = file_size(fn); // file size
401 size = 2 * cnt; // 200% of file size 407 size = 2 * cnt; // 200% of file size
402 new_text(size); // get a text[] buffer 408 new_text(size); // get a text[] buffer
403 screenbegin = dot = end = text; 409 screenbegin = dot = end = text;
404 if (fn != 0) { 410 if (fn != 0) {
405 file_insert(fn, text, cnt); 411 ch= file_insert(fn, text, cnt);
406 } else { 412 }
413 if (ch < 1) {
407 (void) char_insert(text, '\n'); // start empty buf with dummy line 414 (void) char_insert(text, '\n'); // start empty buf with dummy line
408 } 415 }
409 file_modified = FALSE; 416 file_modified = FALSE;
@@ -459,6 +466,7 @@ static void edit_file(Byte * fn)
459 msg = "(alarm)"; 466 msg = "(alarm)";
460 467
461 psbs("-- caught signal %d %s--", sig, msg); 468 psbs("-- caught signal %d %s--", sig, msg);
469 screenbegin = dot = text;
462 } 470 }
463#endif /* BB_FEATURE_VI_USE_SIGNALS */ 471#endif /* BB_FEATURE_VI_USE_SIGNALS */
464 472
@@ -693,7 +701,7 @@ static void crash_test()
693{ 701{
694 static time_t oldtim; 702 static time_t oldtim;
695 time_t tim; 703 time_t tim;
696 char d[2], buf[100], msg[BUFSIZ]; 704 char d[2], buf[BUFSIZ], msg[BUFSIZ];
697 705
698 msg[0] = '\0'; 706 msg[0] = '\0';
699 if (end < text) { 707 if (end < text) {
@@ -785,6 +793,8 @@ static void do_cmd(Byte c)
785 } 793 }
786 } 794 }
787 if (cmd_mode == 1) { 795 if (cmd_mode == 1) {
796 // hitting "Insert" twice means "R" replace mode
797 if (c == VI_K_INSERT) goto dc5;
788 // insert the char c at "dot" 798 // insert the char c at "dot"
789 if (1 <= c && c <= 127) { 799 if (1 <= c && c <= 127) {
790 dot = char_insert(dot, c); // only ASCII chars 800 dot = char_insert(dot, c); // only ASCII chars
@@ -800,13 +810,12 @@ static void do_cmd(Byte c)
800 //case 0x0f: // si 810 //case 0x0f: // si
801 //case 0x10: // dle 811 //case 0x10: // dle
802 //case 0x11: // dc1 812 //case 0x11: // dc1
803 //case 0x12: // dc2
804 //case 0x13: // dc3 813 //case 0x13: // dc3
805 case 0x14: // dc4 ctrl-T
806#ifdef BB_FEATURE_VI_CRASHME 814#ifdef BB_FEATURE_VI_CRASHME
815 case 0x14: // dc4 ctrl-T
807 crashme = (crashme == 0) ? 1 : 0; 816 crashme = (crashme == 0) ? 1 : 0;
808#endif /* BB_FEATURE_VI_CRASHME */
809 break; 817 break;
818#endif /* BB_FEATURE_VI_CRASHME */
810 //case 0x16: // syn 819 //case 0x16: // syn
811 //case 0x17: // etb 820 //case 0x17: // etb
812 //case 0x18: // can 821 //case 0x18: // can
@@ -824,9 +833,7 @@ static void do_cmd(Byte c)
824 //case '=': // =- 833 //case '=': // =-
825 //case '@': // @- 834 //case '@': // @-
826 //case 'F': // F- 835 //case 'F': // F-
827 //case 'G': // G-
828 //case 'K': // K- 836 //case 'K': // K-
829 //case 'M': // M-
830 //case 'Q': // Q- 837 //case 'Q': // Q-
831 //case 'S': // S- 838 //case 'S': // S-
832 //case 'T': // T- 839 //case 'T': // T-
@@ -837,8 +844,8 @@ static void do_cmd(Byte c)
837 //case '_': // _- 844 //case '_': // _-
838 //case '`': // `- 845 //case '`': // `-
839 //case 'g': // g- 846 //case 'g': // g-
840 //case 'm': // m-
841 //case 't': // t- 847 //case 't': // t-
848 //case 'u': // u- FIXME- there is no undo
842 //case 'v': // v- 849 //case 'v': // v-
843 default: // unrecognised command 850 default: // unrecognised command
844 buf[0] = c; 851 buf[0] = c;
@@ -879,7 +886,7 @@ static void do_cmd(Byte c)
879 break; 886 break;
880 case 'h': // h- move left 887 case 'h': // h- move left
881 case VI_K_LEFT: // cursor key Left 888 case VI_K_LEFT: // cursor key Left
882 case 8: // ^h- move left (This may be ERASE char) 889 case 8: // ctrl-H- move left (This may be ERASE char)
883 case 127: // DEL- move left (This may be ERASE char) 890 case 127: // DEL- move left (This may be ERASE char)
884 if (cmdcnt-- > 1) { 891 if (cmdcnt-- > 1) {
885 do_cmd(c); 892 do_cmd(c);
@@ -896,6 +903,7 @@ static void do_cmd(Byte c)
896 dot = move_to_col(dot, ccol + offset); // try stay in same col 903 dot = move_to_col(dot, ccol + offset); // try stay in same col
897 break; 904 break;
898 case 12: // ctrl-L force redraw whole screen 905 case 12: // ctrl-L force redraw whole screen
906 case 18: // ctrl-R force redraw
899 place_cursor(0, 0); // put cursor in correct place 907 place_cursor(0, 0); // put cursor in correct place
900 clear_to_eos(); // tel terminal to erase display 908 clear_to_eos(); // tel terminal to erase display
901 (void) mysleep(10); 909 (void) mysleep(10);
@@ -1003,7 +1011,6 @@ static void do_cmd(Byte c)
1003 dot = string_insert(dot, p); // insert the string 1011 dot = string_insert(dot, p); // insert the string
1004 end_cmd_q(); // stop adding to q 1012 end_cmd_q(); // stop adding to q
1005 break; 1013 break;
1006 case 'u': // u-
1007 case 'U': // U- Undo; replace current line with original version 1014 case 'U': // U- Undo; replace current line with original version
1008 if (reg[Ureg] != 0) { 1015 if (reg[Ureg] != 0) {
1009 p = begin_line(dot); 1016 p = begin_line(dot);
@@ -1185,7 +1192,7 @@ static void do_cmd(Byte c)
1185 write(1, ":", 1); // write out the : prompt 1192 write(1, ":", 1); // write out the : prompt
1186 for (cnt = 0; cnt < 8; cnt++) { 1193 for (cnt = 0; cnt < 8; cnt++) {
1187 c1 = get_one_char(); 1194 c1 = get_one_char();
1188 if (c1 == '\n' || c1 == '\r') { 1195 if (c1 == '\n' || c1 == '\r' || c1 == 27) {
1189 break; 1196 break;
1190 } 1197 }
1191 buf[cnt] = c1; 1198 buf[cnt] = c1;
@@ -1280,6 +1287,13 @@ static void do_cmd(Byte c)
1280 end_cmd_q(); // stop adding to q 1287 end_cmd_q(); // stop adding to q
1281#endif /* BB_FEATURE_VI_DOT_CMD */ 1288#endif /* BB_FEATURE_VI_DOT_CMD */
1282 break; 1289 break;
1290 case 'G': // G- goto to a line number (default= E-O-F)
1291 dot = end - 1; // assume E-O-F
1292 if (cmdcnt > 0) {
1293 dot = find_line(cmdcnt); // what line is #cmdcnt
1294 }
1295 dot_skip_over_ws();
1296 break;
1283 case 'H': // H- goto top line on screen 1297 case 'H': // H- goto top line on screen
1284 dot = screenbegin; 1298 dot = screenbegin;
1285 if (cmdcnt > (rows - 1)) { 1299 if (cmdcnt > (rows - 1)) {
@@ -1324,6 +1338,11 @@ static void do_cmd(Byte c)
1324 dot_begin(); 1338 dot_begin();
1325 dot_skip_over_ws(); 1339 dot_skip_over_ws();
1326 break; 1340 break;
1341 case 'M': // M- goto middle line on screen
1342 dot = screenbegin;
1343 for (cnt = 0; cnt < (rows-1) / 2; cnt++)
1344 dot = next_line(dot);
1345 break;
1327 case 'O': // O- open a empty line above 1346 case 'O': // O- open a empty line above
1328 // 0i\n\033-i 1347 // 0i\n\033-i
1329 p = begin_line(dot); 1348 p = begin_line(dot);
@@ -1340,6 +1359,7 @@ static void do_cmd(Byte c)
1340 goto dc_i; 1359 goto dc_i;
1341 break; 1360 break;
1342 case 'R': // R- continuous Replace char 1361 case 'R': // R- continuous Replace char
1362 dc5:
1343 cmd_mode = 2; 1363 cmd_mode = 2;
1344 psb("-- Replace --"); 1364 psb("-- Replace --");
1345 break; 1365 break;
@@ -1432,13 +1452,19 @@ static void do_cmd(Byte c)
1432 } 1452 }
1433 } 1453 }
1434 dot = yank_delete(p, q, 0, yf); // delete word 1454 dot = yank_delete(p, q, 0, yf); // delete word
1435 } else if (strchr("0bBeE$", c1)) { 1455 } else if (strchr("^0bBeE$", c1)) {
1436 // single line copy text into a register and delete 1456 // single line copy text into a register and delete
1437 dot = yank_delete(p, q, 0, yf); // delete word 1457 dot = yank_delete(p, q, 0, yf); // delete word
1438 } else if (strchr("cdykjHL+-{}\r\n", c1)) { 1458 } else if (strchr("cdykjHL%+-{}\r\n", c1)) {
1439 // multiple line copy text into a register and delete 1459 // multiple line copy text into a register and delete
1440 dot = yank_delete(p, q, 1, yf); // delete lines 1460 dot = yank_delete(p, q, 1, yf); // delete lines
1441 if (c == 'd') { 1461 if (c == 'c') {
1462 dot = char_insert(dot, '\n');
1463 // on the last line of file don't move to prev line
1464 if (dot != (end-1)) {
1465 dot_prev();
1466 }
1467 } else if (c == 'd') {
1442 dot_begin(); 1468 dot_begin();
1443 dot_skip_over_ws(); 1469 dot_skip_over_ws();
1444 } 1470 }
@@ -1574,7 +1600,7 @@ static void do_cmd(Byte c)
1574 1600
1575//----- The Colon commands ------------------------------------- 1601//----- The Colon commands -------------------------------------
1576#ifdef BB_FEATURE_VI_COLON 1602#ifdef BB_FEATURE_VI_COLON
1577static Byte *get_address(Byte * p, int *addr) // get colon addr, if present 1603static Byte *get_one_address(Byte * p, int *addr) // get colon addr, if present
1578{ 1604{
1579 int st; 1605 int st;
1580 Byte *q; 1606 Byte *q;
@@ -1583,7 +1609,7 @@ static Byte *get_address(Byte * p, int *addr) // get colon addr, if present
1583 Byte c; 1609 Byte c;
1584#endif /* BB_FEATURE_VI_YANKMARK */ 1610#endif /* BB_FEATURE_VI_YANKMARK */
1585#ifdef BB_FEATURE_VI_SEARCH 1611#ifdef BB_FEATURE_VI_SEARCH
1586 Byte *pat, buf[1024]; 1612 Byte *pat, buf[BUFSIZ];
1587#endif /* BB_FEATURE_VI_SEARCH */ 1613#endif /* BB_FEATURE_VI_SEARCH */
1588 1614
1589 *addr = -1; // assume no addr 1615 *addr = -1; // assume no addr
@@ -1637,12 +1663,41 @@ static Byte *get_address(Byte * p, int *addr) // get colon addr, if present
1637 return (p); 1663 return (p);
1638} 1664}
1639 1665
1666static Byte *get_address(Byte *p, int *b, int *e) // get two colon addrs, if present
1667{
1668 //----- get the address' i.e., 1,3 'a,'b -----
1669 // get FIRST addr, if present
1670 while (isblnk(*p))
1671 p++; // skip over leading spaces
1672 if (*p == '%') { // alias for 1,$
1673 p++;
1674 *b = 1;
1675 *e = count_lines(text, end-1);
1676 goto ga0;
1677 }
1678 p = get_one_address(p, b);
1679 while (isblnk(*p))
1680 p++;
1681 if (*p == ',') { // is there a address seperator
1682 p++;
1683 while (isblnk(*p))
1684 p++;
1685 // get SECOND addr, if present
1686 p = get_one_address(p, e);
1687 }
1688ga0:
1689 while (isblnk(*p))
1690 p++; // skip over trailing spaces
1691 return (p);
1692}
1693
1640static void colon(Byte * buf) 1694static void colon(Byte * buf)
1641{ 1695{
1642 Byte c, *orig_buf, *buf1, *q, *r; 1696 Byte c, *orig_buf, *buf1, *q, *r;
1643 Byte *fn, cmd[100], args[100]; 1697 Byte *fn, cmd[BUFSIZ], args[BUFSIZ];
1644 int i, l, li, ch, st, b, e; 1698 int i, l, li, ch, st, b, e;
1645 int useforce, forced; 1699 int useforce, forced;
1700 struct stat st_buf;
1646 1701
1647 // :3154 // if (-e line 3154) goto it else stay put 1702 // :3154 // if (-e line 3154) goto it else stay put
1648 // :4,33w! foo // write a portion of buffer to file "foo" 1703 // :4,33w! foo // write a portion of buffer to file "foo"
@@ -1656,6 +1711,7 @@ static void colon(Byte * buf)
1656 // :/123/,/abc/d // delete lines from "123" line to "abc" line 1711 // :/123/,/abc/d // delete lines from "123" line to "abc" line
1657 // :/xyz/ // goto the "xyz" line 1712 // :/xyz/ // goto the "xyz" line
1658 // :s/find/replace/ // substitute pattern "find" with "replace" 1713 // :s/find/replace/ // substitute pattern "find" with "replace"
1714 // :!<cmd> // run <cmd> then return
1659 // 1715 //
1660 if (strlen((char *) buf) <= 0) 1716 if (strlen((char *) buf) <= 0)
1661 goto vc1; 1717 goto vc1;
@@ -1669,36 +1725,21 @@ static void colon(Byte * buf)
1669 r = end - 1; 1725 r = end - 1;
1670 li = count_lines(text, end - 1); 1726 li = count_lines(text, end - 1);
1671 fn = cfn; // default to current file 1727 fn = cfn; // default to current file
1728 memset(cmd, '\0', BUFSIZ); // clear cmd[]
1729 memset(args, '\0', BUFSIZ); // clear args[]
1672 1730
1673 // look for optional FIRST address(es) :. :1 :1,9 :'q,'a 1731 // look for optional address(es) :. :1 :1,9 :'q,'a :%
1674 while (isblnk(*buf)) 1732 buf = get_address(buf, &b, &e);
1675 buf++;
1676
1677 // get FIRST addr, if present
1678 buf = get_address(buf, &b);
1679 while (isblnk(*buf))
1680 buf++;
1681 if (*buf == ',') {
1682 buf++;
1683 while (isblnk(*buf))
1684 buf++;
1685 // look for SECOND address
1686 buf = get_address(buf, &e);
1687 }
1688 while (isblnk(*buf))
1689 buf++;
1690 1733
1691 // remember orig command line 1734 // remember orig command line
1692 orig_buf = buf; 1735 orig_buf = buf;
1693 1736
1694 // get the COMMAND into cmd[] 1737 // get the COMMAND into cmd[]
1695 buf1 = cmd; 1738 buf1 = cmd;
1696 *buf1 = '\0';
1697 while (*buf != '\0') { 1739 while (*buf != '\0') {
1698 if (isspace(*buf)) 1740 if (isspace(*buf))
1699 break; 1741 break;
1700 *buf1++ = *buf++; 1742 *buf1++ = *buf++;
1701 *buf1 = '\0';
1702 } 1743 }
1703 // get any ARGuments 1744 // get any ARGuments
1704 while (isblnk(*buf)) 1745 while (isblnk(*buf))
@@ -1731,6 +1772,16 @@ static void colon(Byte * buf)
1731 dot = find_line(b); // what line is #b 1772 dot = find_line(b); // what line is #b
1732 dot_skip_over_ws(); 1773 dot_skip_over_ws();
1733 } 1774 }
1775 } else if (strncmp((char *) cmd, "!", 1) == 0) { // run a cmd
1776 // :!ls run the <cmd>
1777 (void) alarm(0); // wait for input- no alarms
1778 place_cursor(rows - 1, 0); // go to Status line
1779 clear_to_eol(); // clear the line
1780 cookmode();
1781 system(orig_buf+1); // run the cmd
1782 rawmode();
1783 Hit_Return(); // let user see results
1784 (void) alarm(3); // done waiting for input
1734 } else if (strncmp((char *) cmd, "=", i) == 0) { // where is the address 1785 } else if (strncmp((char *) cmd, "=", i) == 0) { // where is the address
1735 if (b < 0) { // no addr given- use defaults 1786 if (b < 0) { // no addr given- use defaults
1736 b = e = count_lines(text, dot); 1787 b = e = count_lines(text, dot);
@@ -1744,39 +1795,91 @@ static void colon(Byte * buf)
1744 dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines 1795 dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines
1745 dot_skip_over_ws(); 1796 dot_skip_over_ws();
1746 } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file 1797 } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file
1747 // don't exit if the file been modified 1798 int sr;
1799 sr= 0;
1800 // don't edit, if the current file has been modified
1748 if (file_modified == TRUE && useforce != TRUE) { 1801 if (file_modified == TRUE && useforce != TRUE) {
1749 psbs("No write since last change (:edit! overrides)"); 1802 psbs("No write since last change (:edit! overrides)");
1750 goto vc1; 1803 goto vc1;
1751 } 1804 }
1752 fn = args; 1805 if (strlen(args) > 0) {
1753 if (strlen((char *) fn) <= 0) { 1806 // the user supplied a file name
1754 // no file name given, re-edit current file 1807 fn= args;
1755 fn = cfn; 1808 } else if (cfn != 0 && strlen(cfn) > 0) {
1809 // no user supplied name- use the current filename
1810 fn= cfn;
1811 goto vc5;
1812 } else {
1813 // no user file name, no current name- punt
1814 psbs("No current filename");
1815 goto vc1;
1816 }
1817
1818 // see if file exists- if not, its just a new file request
1819 if ((sr=stat((char*)fn, &st_buf)) < 0) {
1820 // This is just a request for a new file creation.
1821 // The file_insert below will fail but we get
1822 // an empty buffer with a file name. Then the "write"
1823 // command can do the create.
1824 } else {
1825 if ((st_buf.st_mode & (S_IFREG)) == 0) {
1826 // This is not a regular file
1827 psbs("\"%s\" is not a regular file", fn);
1828 goto vc1;
1829 }
1830 if ((st_buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) {
1831 // dont have any read permissions
1832 psbs("\"%s\" is not readable", fn);
1833 goto vc1;
1834 }
1756 } 1835 }
1836
1837 // There is a read-able regular file
1838 // make this the current file
1839 q = (Byte *) strdup((char *) fn); // save the cfn
1757 if (cfn != 0) 1840 if (cfn != 0)
1758 free(cfn); 1841 free(cfn); // free the old name
1759 cfn = (Byte *) strdup((char *) fn); // make this the current file 1842 cfn = q; // remember new cfn
1843
1844 vc5:
1760 // delete all the contents of text[] 1845 // delete all the contents of text[]
1761 new_text(2 * file_size(fn)); 1846 new_text(2 * file_size(fn));
1762 screenbegin = dot = end = text; 1847 screenbegin = dot = end = text;
1848
1763 // insert new file 1849 // insert new file
1764 if (fn != 0) { 1850 ch = file_insert(fn, text, file_size(fn));
1765 ch = file_insert(fn, text, file_size(fn)); 1851
1852 if (ch < 1) {
1853 // start empty buf with dummy line
1854 (void) char_insert(text, '\n');
1855 ch= 1;
1766 } 1856 }
1767 file_modified = FALSE; 1857 file_modified = FALSE;
1768#ifdef BB_FEATURE_VI_YANKMARK 1858#ifdef BB_FEATURE_VI_YANKMARK
1769 if (reg[Ureg] != 0) 1859 if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {
1770 free(reg[Ureg]); // free orig line reg- for 'U' 1860 free(reg[Ureg]); // free orig line reg- for 'U'
1771 if (reg[YDreg] != 0) 1861 reg[Ureg]= 0;
1862 }
1863 if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) {
1772 free(reg[YDreg]); // free default yank/delete register 1864 free(reg[YDreg]); // free default yank/delete register
1865 reg[YDreg]= 0;
1866 }
1773 for (li = 0; li < 28; li++) { 1867 for (li = 0; li < 28; li++) {
1774 mark[li] = 0; 1868 mark[li] = 0;
1775 } // init the marks 1869 } // init the marks
1776#endif /* BB_FEATURE_VI_YANKMARK */ 1870#endif /* BB_FEATURE_VI_YANKMARK */
1777 // how many lines in text[]? 1871 // how many lines in text[]?
1778 li = count_lines(text, end - 1); 1872 li = count_lines(text, end - 1);
1779 psb("\"%s\" %dL, %dC", cfn, li, ch); 1873 psb("\"%s\"%s"
1874#ifdef BB_FEATURE_VI_READONLY
1875 "%s"
1876#endif /* BB_FEATURE_VI_READONLY */
1877 " %dL, %dC", cfn,
1878 (sr < 0 ? " [New file]" : ""),
1879#ifdef BB_FEATURE_VI_READONLY
1880 (readonly == TRUE ? " [Read only]" : ""),
1881#endif /* BB_FEATURE_VI_READONLY */
1882 li, ch);
1780 } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this 1883 } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this
1781 if (b != -1 || e != -1) { 1884 if (b != -1 || e != -1) {
1782 ni((Byte *) "No address allowed on this command"); 1885 ni((Byte *) "No address allowed on this command");
@@ -1863,12 +1966,22 @@ static void colon(Byte * buf)
1863 // read after current line- unless user said ":0r foo" 1966 // read after current line- unless user said ":0r foo"
1864 if (b != 0) 1967 if (b != 0)
1865 q = next_line(q); 1968 q = next_line(q);
1969 l= readonly; // remember current files' status
1866 ch = file_insert(fn, q, file_size(fn)); 1970 ch = file_insert(fn, q, file_size(fn));
1971 readonly= l;
1867 if (ch < 0) 1972 if (ch < 0)
1868 goto vc1; // nothing was inserted 1973 goto vc1; // nothing was inserted
1869 // how many lines in text[]? 1974 // how many lines in text[]?
1870 li = count_lines(q, q + ch - 1); 1975 li = count_lines(q, q + ch - 1);
1871 psb("\"%s\" %dL, %dC", fn, li, ch); 1976 psb("\"%s\""
1977#ifdef BB_FEATURE_VI_READONLY
1978 "%s"
1979#endif /* BB_FEATURE_VI_READONLY */
1980 " %dL, %dC", fn,
1981#ifdef BB_FEATURE_VI_READONLY
1982 (readonly == TRUE ? " [Read only]" : ""),
1983#endif /* BB_FEATURE_VI_READONLY */
1984 li, ch);
1872 if (ch > 0) { 1985 if (ch > 0) {
1873 // if the insert is before "dot" then we need to update 1986 // if the insert is before "dot" then we need to update
1874 if (q <= dot) 1987 if (q <= dot)
@@ -1983,7 +2096,7 @@ static void colon(Byte * buf)
1983 fn = args; 2096 fn = args;
1984 } 2097 }
1985#ifdef BB_FEATURE_VI_READONLY 2098#ifdef BB_FEATURE_VI_READONLY
1986 if (readonly == TRUE) { 2099 if (readonly == TRUE && useforce == FALSE) {
1987 psbs("\"%s\" File is read only", fn); 2100 psbs("\"%s\" File is read only", fn);
1988 goto vc3; 2101 goto vc3;
1989 } 2102 }
@@ -1991,6 +2104,7 @@ static void colon(Byte * buf)
1991 // how many lines in text[]? 2104 // how many lines in text[]?
1992 li = count_lines(q, r); 2105 li = count_lines(q, r);
1993 ch = r - q + 1; 2106 ch = r - q + 1;
2107 // see if file exists- if not, its just a new file request
1994 if (useforce == TRUE) { 2108 if (useforce == TRUE) {
1995 // if "fn" is not write-able, chmod u+w 2109 // if "fn" is not write-able, chmod u+w
1996 // sprintf(syscmd, "chmod u+w %s", fn); 2110 // sprintf(syscmd, "chmod u+w %s", fn);
@@ -2547,12 +2661,14 @@ static Byte find_range(Byte ** start, Byte ** stop, Byte c)
2547 p = q = dot; 2661 p = q = dot;
2548 2662
2549 if (strchr("cdy><", c)) { 2663 if (strchr("cdy><", c)) {
2664 // these cmds operate on whole lines
2550 p = q = begin_line(p); 2665 p = q = begin_line(p);
2551 for (cnt = 1; cnt < cmdcnt; cnt++) { 2666 for (cnt = 1; cnt < cmdcnt; cnt++) {
2552 q = next_line(q); 2667 q = next_line(q);
2553 } 2668 }
2554 q = end_line(q); 2669 q = end_line(q);
2555 } else if (strchr("$0bBeE", c)) { 2670 } else if (strchr("^%$0bBeE", c)) {
2671 // These cmds operate on char positions
2556 do_cmd(c); // execute movement cmd 2672 do_cmd(c); // execute movement cmd
2557 q = dot; 2673 q = dot;
2558 } else if (strchr("wW", c)) { 2674 } else if (strchr("wW", c)) {
@@ -2563,11 +2679,13 @@ static Byte find_range(Byte ** start, Byte ** stop, Byte c)
2563 dot--; // stay off NL 2679 dot--; // stay off NL
2564 q = dot; 2680 q = dot;
2565 } else if (strchr("H-k{", c)) { 2681 } else if (strchr("H-k{", c)) {
2682 // these operate on multi-lines backwards
2566 q = end_line(dot); // find NL 2683 q = end_line(dot); // find NL
2567 do_cmd(c); // execute movement cmd 2684 do_cmd(c); // execute movement cmd
2568 dot_begin(); 2685 dot_begin();
2569 p = dot; 2686 p = dot;
2570 } else if (strchr("L+j}\r\n", c)) { 2687 } else if (strchr("L+j}\r\n", c)) {
2688 // these operate on multi-lines forwards
2571 p = begin_line(dot); 2689 p = begin_line(dot);
2572 do_cmd(c); // execute movement cmd 2690 do_cmd(c); // execute movement cmd
2573 dot_end(); // find NL 2691 dot_end(); // find NL
@@ -3190,7 +3308,7 @@ static Byte readit(void) // read (maybe cursor) key from stdin
3190 FD_ZERO(&rfds); 3308 FD_ZERO(&rfds);
3191 FD_SET(0, &rfds); 3309 FD_SET(0, &rfds);
3192 tv.tv_sec = 0; 3310 tv.tv_sec = 0;
3193 tv.tv_usec = 10000; // Wait 1/100 seconds- 1 Sec=1000000 3311 tv.tv_usec = 50000; // Wait 5/100 seconds- 1 Sec=1000000
3194 3312
3195 // keep reading while there are input chars and room in buffer 3313 // keep reading while there are input chars and room in buffer
3196 while (select(1, &rfds, NULL, NULL, &tv) > 0 && bufsiz <= (BUFSIZ - 5)) { 3314 while (select(1, &rfds, NULL, NULL, &tv) > 0 && bufsiz <= (BUFSIZ - 5)) {
@@ -3267,7 +3385,7 @@ static Byte get_one_char()
3267#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON) 3385#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON)
3268static Byte *get_input_line(Byte * prompt) // get input line- use "status line" 3386static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
3269{ 3387{
3270 Byte buf[500]; 3388 Byte buf[BUFSIZ];
3271 Byte c; 3389 Byte c;
3272 int i; 3390 int i;
3273 static Byte *obufp = NULL; 3391 static Byte *obufp = NULL;
@@ -3278,9 +3396,9 @@ static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
3278 clear_to_eol(); // clear the line 3396 clear_to_eol(); // clear the line
3279 write(1, prompt, strlen((char *) prompt)); // write out the :, /, or ? prompt 3397 write(1, prompt, strlen((char *) prompt)); // write out the :, /, or ? prompt
3280 3398
3281 for (i = strlen((char *) buf); i < 500;) { 3399 for (i = strlen((char *) buf); i < BUFSIZ;) {
3282 c = get_one_char(); // read user input 3400 c = get_one_char(); // read user input
3283 if (c == '\n' || c == '\r') 3401 if (c == '\n' || c == '\r' || c == 27)
3284 break; // is this end of input 3402 break; // is this end of input
3285 if (c == erase_char) { // user wants to erase prev char 3403 if (c == erase_char) { // user wants to erase prev char
3286 i--; // backup to prev char 3404 i--; // backup to prev char
@@ -3310,7 +3428,7 @@ static int file_size(Byte * fn) // what is the byte size of "fn"
3310 struct stat st_buf; 3428 struct stat st_buf;
3311 int cnt, sr; 3429 int cnt, sr;
3312 3430
3313 if (fn == 0) 3431 if (fn == 0 || strlen(fn) <= 0)
3314 return (-1); 3432 return (-1);
3315 cnt = -1; 3433 cnt = -1;
3316 sr = stat((char *) fn, &st_buf); // see if file exists 3434 sr = stat((char *) fn, &st_buf); // see if file exists
@@ -3322,31 +3440,44 @@ static int file_size(Byte * fn) // what is the byte size of "fn"
3322 3440
3323static int file_insert(Byte * fn, Byte * p, int size) 3441static int file_insert(Byte * fn, Byte * p, int size)
3324{ 3442{
3325 int fd, cnt, sr; 3443 int fd, cnt;
3326 struct stat st_buf;
3327 3444
3328 cnt = -1; 3445 cnt = -1;
3329 if (fn == 0) { 3446#ifdef BB_FEATURE_VI_READONLY
3447 readonly = FALSE;
3448#endif /* BB_FEATURE_VI_READONLY */
3449 if (fn == 0 || strlen((char*) fn) <= 0) {
3330 psbs("No filename given"); 3450 psbs("No filename given");
3331 goto fi0; 3451 goto fi0;
3332 } 3452 }
3333 sr = stat((char *) fn, &st_buf); // see if file exists 3453 if (size == 0) {
3334 if (sr < 0) { 3454 // OK- this is just a no-op
3335 psbs("\"%s\" %s", fn, "count not stat file"); 3455 cnt = 0;
3336 goto fi0; 3456 goto fi0;
3337 } 3457 }
3338 if (size <= 0 || (int) st_buf.st_size <= 0) { 3458 if (size < 0) {
3339 psbs("The file size (%d) is too small", size); 3459 psbs("Trying to insert a negative number (%d) of characters", size);
3340 if ((int) st_buf.st_size <= 0)
3341 psbs("\"%s\" is empty", fn);
3342 goto fi0; 3460 goto fi0;
3343 } 3461 }
3344 // There is a file with content 3462 if (p < text || p > end) {
3345 fd = open((char *) fn, O_RDWR); 3463 psbs("Trying to insert file outside of memory");
3346 if (fd < 0) {
3347 psbs("\"%s\" %s", fn, "could not open file");
3348 goto fi0; 3464 goto fi0;
3349 } 3465 }
3466
3467 // see if we can open the file
3468 fd = open((char *) fn, O_RDWR); // assume read & write
3469 if (fd < 0) {
3470 // could not open for writing- maybe file is read only
3471 fd = open((char *) fn, O_RDONLY); // try read-only
3472 if (fd < 0) {
3473 psbs("\"%s\" %s", fn, "could not open file");
3474 goto fi0;
3475 }
3476#ifdef BB_FEATURE_VI_READONLY
3477 // got the file- read-only
3478 readonly = TRUE;
3479#endif /* BB_FEATURE_VI_READONLY */
3480 }
3350 p = text_hole_make(p, size); 3481 p = text_hole_make(p, size);
3351 cnt = read(fd, p, size); 3482 cnt = read(fd, p, size);
3352 close(fd); 3483 close(fd);
@@ -3527,7 +3658,7 @@ static void psb(char *format, ...)
3527 3658
3528static void ni(Byte * s) // display messages 3659static void ni(Byte * s) // display messages
3529{ 3660{
3530 Byte buf[9]; 3661 Byte buf[BUFSIZ];
3531 3662
3532 print_literal(buf, s); 3663 print_literal(buf, s);
3533 psbs("\'%s\' is not implemented", buf); 3664 psbs("\'%s\' is not implemented", buf);
@@ -3552,13 +3683,13 @@ static void edit_status(void) // show file status on status line
3552#ifdef BB_FEATURE_VI_READONLY 3683#ifdef BB_FEATURE_VI_READONLY
3553 "%s" 3684 "%s"
3554#endif /* BB_FEATURE_VI_READONLY */ 3685#endif /* BB_FEATURE_VI_READONLY */
3555 "%s line %d of %d --%d%%-- (%dx%d)", 3686 "%s line %d of %d --%d%%--",
3556 (cfn != 0 ? (char *) cfn : "No file"), 3687 (cfn != 0 ? (char *) cfn : "No file"),
3557#ifdef BB_FEATURE_VI_READONLY 3688#ifdef BB_FEATURE_VI_READONLY
3558 (readonly == TRUE ? " [Read only]" : ""), 3689 (readonly == TRUE ? " [Read only]" : ""),
3559#endif /* BB_FEATURE_VI_READONLY */ 3690#endif /* BB_FEATURE_VI_READONLY */
3560 (file_modified == TRUE ? " [modified]" : ""), 3691 (file_modified == TRUE ? " [modified]" : ""),
3561 cur, tot, percent, rows, columns); 3692 cur, tot, percent);
3562} 3693}
3563 3694
3564//----- Force refresh of all Lines ----------------------------- 3695//----- Force refresh of all Lines -----------------------------
diff --git a/vi.c b/vi.c
index e4014362d..6a93fc1fe 100644
--- a/vi.c
+++ b/vi.c
@@ -19,7 +19,7 @@
19 */ 19 */
20 20
21char *vi_Version = 21char *vi_Version =
22 "$Id: vi.c,v 1.3 2001/04/04 19:33:32 andersen Exp $"; 22 "$Id: vi.c,v 1.4 2001/04/16 15:46:44 andersen Exp $";
23 23
24/* 24/*
25 * To compile for standalone use: 25 * To compile for standalone use:
@@ -32,13 +32,17 @@ char *vi_Version =
32/* 32/*
33 * Things To Do: 33 * Things To Do:
34 * EXINIT 34 * EXINIT
35 * $HOME/.exrc 35 * $HOME/.exrc and ./.exrc
36 * add magic to search /foo.*bar 36 * add magic to search /foo.*bar
37 * add :help command 37 * add :help command
38 * :map macros 38 * :map macros
39 * how about mode lines: vi: set sw=8 ts=8: 39 * how about mode lines: vi: set sw=8 ts=8:
40 * if mark[] values were line numbers rather than pointers 40 * if mark[] values were line numbers rather than pointers
41 * it would be easier to change the mark when add/delete lines 41 * it would be easier to change the mark when add/delete lines
42 * More intelligence in refresh()
43 * ":r !cmd" and "!cmd" to filter text through an external command
44 * A true "undo" facility
45 * An "ex" line oriented mode- maybe using "cmdedit"
42 */ 46 */
43 47
44//---- Feature -------------- Bytes to immplement 48//---- Feature -------------- Bytes to immplement
@@ -87,7 +91,7 @@ char *vi_Version =
87#define TRUE ((int)1) 91#define TRUE ((int)1)
88#define FALSE ((int)0) 92#define FALSE ((int)0)
89#endif /* TRUE */ 93#endif /* TRUE */
90#define MAX_SCR_COLS 300 94#define MAX_SCR_COLS BUFSIZ
91 95
92// Misc. non-Ascii keys that report an escape sequence 96// Misc. non-Ascii keys that report an escape sequence
93#define VI_K_UP 128 // cursor key Up 97#define VI_K_UP 128 // cursor key Up
@@ -253,7 +257,8 @@ static int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase"
253#endif /* BB_FEATURE_VI_SEARCH */ 257#endif /* BB_FEATURE_VI_SEARCH */
254#ifdef BB_FEATURE_VI_COLON 258#ifdef BB_FEATURE_VI_COLON
255static void Hit_Return(void); 259static void Hit_Return(void);
256static Byte *get_address(Byte *, int *); // get colon addr, if present 260static Byte *get_one_address(Byte *, int *); // get colon addr, if present
261static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present
257static void colon(Byte *); // execute the "colon" mode cmds 262static void colon(Byte *); // execute the "colon" mode cmds
258#endif /* BB_FEATURE_VI_COLON */ 263#endif /* BB_FEATURE_VI_COLON */
259#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON) 264#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON)
@@ -379,7 +384,7 @@ extern int vi_main(int argc, char **argv)
379static void edit_file(Byte * fn) 384static void edit_file(Byte * fn)
380{ 385{
381 char c; 386 char c;
382 int cnt, size; 387 int cnt, size, ch;
383 388
384#ifdef BB_FEATURE_VI_USE_SIGNALS 389#ifdef BB_FEATURE_VI_USE_SIGNALS
385 char *msg; 390 char *msg;
@@ -397,13 +402,15 @@ static void edit_file(Byte * fn)
397#endif /* BB_FEATURE_VI_WIN_RESIZE */ 402#endif /* BB_FEATURE_VI_WIN_RESIZE */
398 new_screen(rows, columns); // get memory for virtual screen 403 new_screen(rows, columns); // get memory for virtual screen
399 404
405 ch= 0;
400 cnt = file_size(fn); // file size 406 cnt = file_size(fn); // file size
401 size = 2 * cnt; // 200% of file size 407 size = 2 * cnt; // 200% of file size
402 new_text(size); // get a text[] buffer 408 new_text(size); // get a text[] buffer
403 screenbegin = dot = end = text; 409 screenbegin = dot = end = text;
404 if (fn != 0) { 410 if (fn != 0) {
405 file_insert(fn, text, cnt); 411 ch= file_insert(fn, text, cnt);
406 } else { 412 }
413 if (ch < 1) {
407 (void) char_insert(text, '\n'); // start empty buf with dummy line 414 (void) char_insert(text, '\n'); // start empty buf with dummy line
408 } 415 }
409 file_modified = FALSE; 416 file_modified = FALSE;
@@ -459,6 +466,7 @@ static void edit_file(Byte * fn)
459 msg = "(alarm)"; 466 msg = "(alarm)";
460 467
461 psbs("-- caught signal %d %s--", sig, msg); 468 psbs("-- caught signal %d %s--", sig, msg);
469 screenbegin = dot = text;
462 } 470 }
463#endif /* BB_FEATURE_VI_USE_SIGNALS */ 471#endif /* BB_FEATURE_VI_USE_SIGNALS */
464 472
@@ -693,7 +701,7 @@ static void crash_test()
693{ 701{
694 static time_t oldtim; 702 static time_t oldtim;
695 time_t tim; 703 time_t tim;
696 char d[2], buf[100], msg[BUFSIZ]; 704 char d[2], buf[BUFSIZ], msg[BUFSIZ];
697 705
698 msg[0] = '\0'; 706 msg[0] = '\0';
699 if (end < text) { 707 if (end < text) {
@@ -785,6 +793,8 @@ static void do_cmd(Byte c)
785 } 793 }
786 } 794 }
787 if (cmd_mode == 1) { 795 if (cmd_mode == 1) {
796 // hitting "Insert" twice means "R" replace mode
797 if (c == VI_K_INSERT) goto dc5;
788 // insert the char c at "dot" 798 // insert the char c at "dot"
789 if (1 <= c && c <= 127) { 799 if (1 <= c && c <= 127) {
790 dot = char_insert(dot, c); // only ASCII chars 800 dot = char_insert(dot, c); // only ASCII chars
@@ -800,13 +810,12 @@ static void do_cmd(Byte c)
800 //case 0x0f: // si 810 //case 0x0f: // si
801 //case 0x10: // dle 811 //case 0x10: // dle
802 //case 0x11: // dc1 812 //case 0x11: // dc1
803 //case 0x12: // dc2
804 //case 0x13: // dc3 813 //case 0x13: // dc3
805 case 0x14: // dc4 ctrl-T
806#ifdef BB_FEATURE_VI_CRASHME 814#ifdef BB_FEATURE_VI_CRASHME
815 case 0x14: // dc4 ctrl-T
807 crashme = (crashme == 0) ? 1 : 0; 816 crashme = (crashme == 0) ? 1 : 0;
808#endif /* BB_FEATURE_VI_CRASHME */
809 break; 817 break;
818#endif /* BB_FEATURE_VI_CRASHME */
810 //case 0x16: // syn 819 //case 0x16: // syn
811 //case 0x17: // etb 820 //case 0x17: // etb
812 //case 0x18: // can 821 //case 0x18: // can
@@ -824,9 +833,7 @@ static void do_cmd(Byte c)
824 //case '=': // =- 833 //case '=': // =-
825 //case '@': // @- 834 //case '@': // @-
826 //case 'F': // F- 835 //case 'F': // F-
827 //case 'G': // G-
828 //case 'K': // K- 836 //case 'K': // K-
829 //case 'M': // M-
830 //case 'Q': // Q- 837 //case 'Q': // Q-
831 //case 'S': // S- 838 //case 'S': // S-
832 //case 'T': // T- 839 //case 'T': // T-
@@ -837,8 +844,8 @@ static void do_cmd(Byte c)
837 //case '_': // _- 844 //case '_': // _-
838 //case '`': // `- 845 //case '`': // `-
839 //case 'g': // g- 846 //case 'g': // g-
840 //case 'm': // m-
841 //case 't': // t- 847 //case 't': // t-
848 //case 'u': // u- FIXME- there is no undo
842 //case 'v': // v- 849 //case 'v': // v-
843 default: // unrecognised command 850 default: // unrecognised command
844 buf[0] = c; 851 buf[0] = c;
@@ -879,7 +886,7 @@ static void do_cmd(Byte c)
879 break; 886 break;
880 case 'h': // h- move left 887 case 'h': // h- move left
881 case VI_K_LEFT: // cursor key Left 888 case VI_K_LEFT: // cursor key Left
882 case 8: // ^h- move left (This may be ERASE char) 889 case 8: // ctrl-H- move left (This may be ERASE char)
883 case 127: // DEL- move left (This may be ERASE char) 890 case 127: // DEL- move left (This may be ERASE char)
884 if (cmdcnt-- > 1) { 891 if (cmdcnt-- > 1) {
885 do_cmd(c); 892 do_cmd(c);
@@ -896,6 +903,7 @@ static void do_cmd(Byte c)
896 dot = move_to_col(dot, ccol + offset); // try stay in same col 903 dot = move_to_col(dot, ccol + offset); // try stay in same col
897 break; 904 break;
898 case 12: // ctrl-L force redraw whole screen 905 case 12: // ctrl-L force redraw whole screen
906 case 18: // ctrl-R force redraw
899 place_cursor(0, 0); // put cursor in correct place 907 place_cursor(0, 0); // put cursor in correct place
900 clear_to_eos(); // tel terminal to erase display 908 clear_to_eos(); // tel terminal to erase display
901 (void) mysleep(10); 909 (void) mysleep(10);
@@ -1003,7 +1011,6 @@ static void do_cmd(Byte c)
1003 dot = string_insert(dot, p); // insert the string 1011 dot = string_insert(dot, p); // insert the string
1004 end_cmd_q(); // stop adding to q 1012 end_cmd_q(); // stop adding to q
1005 break; 1013 break;
1006 case 'u': // u-
1007 case 'U': // U- Undo; replace current line with original version 1014 case 'U': // U- Undo; replace current line with original version
1008 if (reg[Ureg] != 0) { 1015 if (reg[Ureg] != 0) {
1009 p = begin_line(dot); 1016 p = begin_line(dot);
@@ -1185,7 +1192,7 @@ static void do_cmd(Byte c)
1185 write(1, ":", 1); // write out the : prompt 1192 write(1, ":", 1); // write out the : prompt
1186 for (cnt = 0; cnt < 8; cnt++) { 1193 for (cnt = 0; cnt < 8; cnt++) {
1187 c1 = get_one_char(); 1194 c1 = get_one_char();
1188 if (c1 == '\n' || c1 == '\r') { 1195 if (c1 == '\n' || c1 == '\r' || c1 == 27) {
1189 break; 1196 break;
1190 } 1197 }
1191 buf[cnt] = c1; 1198 buf[cnt] = c1;
@@ -1280,6 +1287,13 @@ static void do_cmd(Byte c)
1280 end_cmd_q(); // stop adding to q 1287 end_cmd_q(); // stop adding to q
1281#endif /* BB_FEATURE_VI_DOT_CMD */ 1288#endif /* BB_FEATURE_VI_DOT_CMD */
1282 break; 1289 break;
1290 case 'G': // G- goto to a line number (default= E-O-F)
1291 dot = end - 1; // assume E-O-F
1292 if (cmdcnt > 0) {
1293 dot = find_line(cmdcnt); // what line is #cmdcnt
1294 }
1295 dot_skip_over_ws();
1296 break;
1283 case 'H': // H- goto top line on screen 1297 case 'H': // H- goto top line on screen
1284 dot = screenbegin; 1298 dot = screenbegin;
1285 if (cmdcnt > (rows - 1)) { 1299 if (cmdcnt > (rows - 1)) {
@@ -1324,6 +1338,11 @@ static void do_cmd(Byte c)
1324 dot_begin(); 1338 dot_begin();
1325 dot_skip_over_ws(); 1339 dot_skip_over_ws();
1326 break; 1340 break;
1341 case 'M': // M- goto middle line on screen
1342 dot = screenbegin;
1343 for (cnt = 0; cnt < (rows-1) / 2; cnt++)
1344 dot = next_line(dot);
1345 break;
1327 case 'O': // O- open a empty line above 1346 case 'O': // O- open a empty line above
1328 // 0i\n\033-i 1347 // 0i\n\033-i
1329 p = begin_line(dot); 1348 p = begin_line(dot);
@@ -1340,6 +1359,7 @@ static void do_cmd(Byte c)
1340 goto dc_i; 1359 goto dc_i;
1341 break; 1360 break;
1342 case 'R': // R- continuous Replace char 1361 case 'R': // R- continuous Replace char
1362 dc5:
1343 cmd_mode = 2; 1363 cmd_mode = 2;
1344 psb("-- Replace --"); 1364 psb("-- Replace --");
1345 break; 1365 break;
@@ -1432,13 +1452,19 @@ static void do_cmd(Byte c)
1432 } 1452 }
1433 } 1453 }
1434 dot = yank_delete(p, q, 0, yf); // delete word 1454 dot = yank_delete(p, q, 0, yf); // delete word
1435 } else if (strchr("0bBeE$", c1)) { 1455 } else if (strchr("^0bBeE$", c1)) {
1436 // single line copy text into a register and delete 1456 // single line copy text into a register and delete
1437 dot = yank_delete(p, q, 0, yf); // delete word 1457 dot = yank_delete(p, q, 0, yf); // delete word
1438 } else if (strchr("cdykjHL+-{}\r\n", c1)) { 1458 } else if (strchr("cdykjHL%+-{}\r\n", c1)) {
1439 // multiple line copy text into a register and delete 1459 // multiple line copy text into a register and delete
1440 dot = yank_delete(p, q, 1, yf); // delete lines 1460 dot = yank_delete(p, q, 1, yf); // delete lines
1441 if (c == 'd') { 1461 if (c == 'c') {
1462 dot = char_insert(dot, '\n');
1463 // on the last line of file don't move to prev line
1464 if (dot != (end-1)) {
1465 dot_prev();
1466 }
1467 } else if (c == 'd') {
1442 dot_begin(); 1468 dot_begin();
1443 dot_skip_over_ws(); 1469 dot_skip_over_ws();
1444 } 1470 }
@@ -1574,7 +1600,7 @@ static void do_cmd(Byte c)
1574 1600
1575//----- The Colon commands ------------------------------------- 1601//----- The Colon commands -------------------------------------
1576#ifdef BB_FEATURE_VI_COLON 1602#ifdef BB_FEATURE_VI_COLON
1577static Byte *get_address(Byte * p, int *addr) // get colon addr, if present 1603static Byte *get_one_address(Byte * p, int *addr) // get colon addr, if present
1578{ 1604{
1579 int st; 1605 int st;
1580 Byte *q; 1606 Byte *q;
@@ -1583,7 +1609,7 @@ static Byte *get_address(Byte * p, int *addr) // get colon addr, if present
1583 Byte c; 1609 Byte c;
1584#endif /* BB_FEATURE_VI_YANKMARK */ 1610#endif /* BB_FEATURE_VI_YANKMARK */
1585#ifdef BB_FEATURE_VI_SEARCH 1611#ifdef BB_FEATURE_VI_SEARCH
1586 Byte *pat, buf[1024]; 1612 Byte *pat, buf[BUFSIZ];
1587#endif /* BB_FEATURE_VI_SEARCH */ 1613#endif /* BB_FEATURE_VI_SEARCH */
1588 1614
1589 *addr = -1; // assume no addr 1615 *addr = -1; // assume no addr
@@ -1637,12 +1663,41 @@ static Byte *get_address(Byte * p, int *addr) // get colon addr, if present
1637 return (p); 1663 return (p);
1638} 1664}
1639 1665
1666static Byte *get_address(Byte *p, int *b, int *e) // get two colon addrs, if present
1667{
1668 //----- get the address' i.e., 1,3 'a,'b -----
1669 // get FIRST addr, if present
1670 while (isblnk(*p))
1671 p++; // skip over leading spaces
1672 if (*p == '%') { // alias for 1,$
1673 p++;
1674 *b = 1;
1675 *e = count_lines(text, end-1);
1676 goto ga0;
1677 }
1678 p = get_one_address(p, b);
1679 while (isblnk(*p))
1680 p++;
1681 if (*p == ',') { // is there a address seperator
1682 p++;
1683 while (isblnk(*p))
1684 p++;
1685 // get SECOND addr, if present
1686 p = get_one_address(p, e);
1687 }
1688ga0:
1689 while (isblnk(*p))
1690 p++; // skip over trailing spaces
1691 return (p);
1692}
1693
1640static void colon(Byte * buf) 1694static void colon(Byte * buf)
1641{ 1695{
1642 Byte c, *orig_buf, *buf1, *q, *r; 1696 Byte c, *orig_buf, *buf1, *q, *r;
1643 Byte *fn, cmd[100], args[100]; 1697 Byte *fn, cmd[BUFSIZ], args[BUFSIZ];
1644 int i, l, li, ch, st, b, e; 1698 int i, l, li, ch, st, b, e;
1645 int useforce, forced; 1699 int useforce, forced;
1700 struct stat st_buf;
1646 1701
1647 // :3154 // if (-e line 3154) goto it else stay put 1702 // :3154 // if (-e line 3154) goto it else stay put
1648 // :4,33w! foo // write a portion of buffer to file "foo" 1703 // :4,33w! foo // write a portion of buffer to file "foo"
@@ -1656,6 +1711,7 @@ static void colon(Byte * buf)
1656 // :/123/,/abc/d // delete lines from "123" line to "abc" line 1711 // :/123/,/abc/d // delete lines from "123" line to "abc" line
1657 // :/xyz/ // goto the "xyz" line 1712 // :/xyz/ // goto the "xyz" line
1658 // :s/find/replace/ // substitute pattern "find" with "replace" 1713 // :s/find/replace/ // substitute pattern "find" with "replace"
1714 // :!<cmd> // run <cmd> then return
1659 // 1715 //
1660 if (strlen((char *) buf) <= 0) 1716 if (strlen((char *) buf) <= 0)
1661 goto vc1; 1717 goto vc1;
@@ -1669,36 +1725,21 @@ static void colon(Byte * buf)
1669 r = end - 1; 1725 r = end - 1;
1670 li = count_lines(text, end - 1); 1726 li = count_lines(text, end - 1);
1671 fn = cfn; // default to current file 1727 fn = cfn; // default to current file
1728 memset(cmd, '\0', BUFSIZ); // clear cmd[]
1729 memset(args, '\0', BUFSIZ); // clear args[]
1672 1730
1673 // look for optional FIRST address(es) :. :1 :1,9 :'q,'a 1731 // look for optional address(es) :. :1 :1,9 :'q,'a :%
1674 while (isblnk(*buf)) 1732 buf = get_address(buf, &b, &e);
1675 buf++;
1676
1677 // get FIRST addr, if present
1678 buf = get_address(buf, &b);
1679 while (isblnk(*buf))
1680 buf++;
1681 if (*buf == ',') {
1682 buf++;
1683 while (isblnk(*buf))
1684 buf++;
1685 // look for SECOND address
1686 buf = get_address(buf, &e);
1687 }
1688 while (isblnk(*buf))
1689 buf++;
1690 1733
1691 // remember orig command line 1734 // remember orig command line
1692 orig_buf = buf; 1735 orig_buf = buf;
1693 1736
1694 // get the COMMAND into cmd[] 1737 // get the COMMAND into cmd[]
1695 buf1 = cmd; 1738 buf1 = cmd;
1696 *buf1 = '\0';
1697 while (*buf != '\0') { 1739 while (*buf != '\0') {
1698 if (isspace(*buf)) 1740 if (isspace(*buf))
1699 break; 1741 break;
1700 *buf1++ = *buf++; 1742 *buf1++ = *buf++;
1701 *buf1 = '\0';
1702 } 1743 }
1703 // get any ARGuments 1744 // get any ARGuments
1704 while (isblnk(*buf)) 1745 while (isblnk(*buf))
@@ -1731,6 +1772,16 @@ static void colon(Byte * buf)
1731 dot = find_line(b); // what line is #b 1772 dot = find_line(b); // what line is #b
1732 dot_skip_over_ws(); 1773 dot_skip_over_ws();
1733 } 1774 }
1775 } else if (strncmp((char *) cmd, "!", 1) == 0) { // run a cmd
1776 // :!ls run the <cmd>
1777 (void) alarm(0); // wait for input- no alarms
1778 place_cursor(rows - 1, 0); // go to Status line
1779 clear_to_eol(); // clear the line
1780 cookmode();
1781 system(orig_buf+1); // run the cmd
1782 rawmode();
1783 Hit_Return(); // let user see results
1784 (void) alarm(3); // done waiting for input
1734 } else if (strncmp((char *) cmd, "=", i) == 0) { // where is the address 1785 } else if (strncmp((char *) cmd, "=", i) == 0) { // where is the address
1735 if (b < 0) { // no addr given- use defaults 1786 if (b < 0) { // no addr given- use defaults
1736 b = e = count_lines(text, dot); 1787 b = e = count_lines(text, dot);
@@ -1744,39 +1795,91 @@ static void colon(Byte * buf)
1744 dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines 1795 dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines
1745 dot_skip_over_ws(); 1796 dot_skip_over_ws();
1746 } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file 1797 } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file
1747 // don't exit if the file been modified 1798 int sr;
1799 sr= 0;
1800 // don't edit, if the current file has been modified
1748 if (file_modified == TRUE && useforce != TRUE) { 1801 if (file_modified == TRUE && useforce != TRUE) {
1749 psbs("No write since last change (:edit! overrides)"); 1802 psbs("No write since last change (:edit! overrides)");
1750 goto vc1; 1803 goto vc1;
1751 } 1804 }
1752 fn = args; 1805 if (strlen(args) > 0) {
1753 if (strlen((char *) fn) <= 0) { 1806 // the user supplied a file name
1754 // no file name given, re-edit current file 1807 fn= args;
1755 fn = cfn; 1808 } else if (cfn != 0 && strlen(cfn) > 0) {
1809 // no user supplied name- use the current filename
1810 fn= cfn;
1811 goto vc5;
1812 } else {
1813 // no user file name, no current name- punt
1814 psbs("No current filename");
1815 goto vc1;
1816 }
1817
1818 // see if file exists- if not, its just a new file request
1819 if ((sr=stat((char*)fn, &st_buf)) < 0) {
1820 // This is just a request for a new file creation.
1821 // The file_insert below will fail but we get
1822 // an empty buffer with a file name. Then the "write"
1823 // command can do the create.
1824 } else {
1825 if ((st_buf.st_mode & (S_IFREG)) == 0) {
1826 // This is not a regular file
1827 psbs("\"%s\" is not a regular file", fn);
1828 goto vc1;
1829 }
1830 if ((st_buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) {
1831 // dont have any read permissions
1832 psbs("\"%s\" is not readable", fn);
1833 goto vc1;
1834 }
1756 } 1835 }
1836
1837 // There is a read-able regular file
1838 // make this the current file
1839 q = (Byte *) strdup((char *) fn); // save the cfn
1757 if (cfn != 0) 1840 if (cfn != 0)
1758 free(cfn); 1841 free(cfn); // free the old name
1759 cfn = (Byte *) strdup((char *) fn); // make this the current file 1842 cfn = q; // remember new cfn
1843
1844 vc5:
1760 // delete all the contents of text[] 1845 // delete all the contents of text[]
1761 new_text(2 * file_size(fn)); 1846 new_text(2 * file_size(fn));
1762 screenbegin = dot = end = text; 1847 screenbegin = dot = end = text;
1848
1763 // insert new file 1849 // insert new file
1764 if (fn != 0) { 1850 ch = file_insert(fn, text, file_size(fn));
1765 ch = file_insert(fn, text, file_size(fn)); 1851
1852 if (ch < 1) {
1853 // start empty buf with dummy line
1854 (void) char_insert(text, '\n');
1855 ch= 1;
1766 } 1856 }
1767 file_modified = FALSE; 1857 file_modified = FALSE;
1768#ifdef BB_FEATURE_VI_YANKMARK 1858#ifdef BB_FEATURE_VI_YANKMARK
1769 if (reg[Ureg] != 0) 1859 if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {
1770 free(reg[Ureg]); // free orig line reg- for 'U' 1860 free(reg[Ureg]); // free orig line reg- for 'U'
1771 if (reg[YDreg] != 0) 1861 reg[Ureg]= 0;
1862 }
1863 if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) {
1772 free(reg[YDreg]); // free default yank/delete register 1864 free(reg[YDreg]); // free default yank/delete register
1865 reg[YDreg]= 0;
1866 }
1773 for (li = 0; li < 28; li++) { 1867 for (li = 0; li < 28; li++) {
1774 mark[li] = 0; 1868 mark[li] = 0;
1775 } // init the marks 1869 } // init the marks
1776#endif /* BB_FEATURE_VI_YANKMARK */ 1870#endif /* BB_FEATURE_VI_YANKMARK */
1777 // how many lines in text[]? 1871 // how many lines in text[]?
1778 li = count_lines(text, end - 1); 1872 li = count_lines(text, end - 1);
1779 psb("\"%s\" %dL, %dC", cfn, li, ch); 1873 psb("\"%s\"%s"
1874#ifdef BB_FEATURE_VI_READONLY
1875 "%s"
1876#endif /* BB_FEATURE_VI_READONLY */
1877 " %dL, %dC", cfn,
1878 (sr < 0 ? " [New file]" : ""),
1879#ifdef BB_FEATURE_VI_READONLY
1880 (readonly == TRUE ? " [Read only]" : ""),
1881#endif /* BB_FEATURE_VI_READONLY */
1882 li, ch);
1780 } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this 1883 } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this
1781 if (b != -1 || e != -1) { 1884 if (b != -1 || e != -1) {
1782 ni((Byte *) "No address allowed on this command"); 1885 ni((Byte *) "No address allowed on this command");
@@ -1863,12 +1966,22 @@ static void colon(Byte * buf)
1863 // read after current line- unless user said ":0r foo" 1966 // read after current line- unless user said ":0r foo"
1864 if (b != 0) 1967 if (b != 0)
1865 q = next_line(q); 1968 q = next_line(q);
1969 l= readonly; // remember current files' status
1866 ch = file_insert(fn, q, file_size(fn)); 1970 ch = file_insert(fn, q, file_size(fn));
1971 readonly= l;
1867 if (ch < 0) 1972 if (ch < 0)
1868 goto vc1; // nothing was inserted 1973 goto vc1; // nothing was inserted
1869 // how many lines in text[]? 1974 // how many lines in text[]?
1870 li = count_lines(q, q + ch - 1); 1975 li = count_lines(q, q + ch - 1);
1871 psb("\"%s\" %dL, %dC", fn, li, ch); 1976 psb("\"%s\""
1977#ifdef BB_FEATURE_VI_READONLY
1978 "%s"
1979#endif /* BB_FEATURE_VI_READONLY */
1980 " %dL, %dC", fn,
1981#ifdef BB_FEATURE_VI_READONLY
1982 (readonly == TRUE ? " [Read only]" : ""),
1983#endif /* BB_FEATURE_VI_READONLY */
1984 li, ch);
1872 if (ch > 0) { 1985 if (ch > 0) {
1873 // if the insert is before "dot" then we need to update 1986 // if the insert is before "dot" then we need to update
1874 if (q <= dot) 1987 if (q <= dot)
@@ -1983,7 +2096,7 @@ static void colon(Byte * buf)
1983 fn = args; 2096 fn = args;
1984 } 2097 }
1985#ifdef BB_FEATURE_VI_READONLY 2098#ifdef BB_FEATURE_VI_READONLY
1986 if (readonly == TRUE) { 2099 if (readonly == TRUE && useforce == FALSE) {
1987 psbs("\"%s\" File is read only", fn); 2100 psbs("\"%s\" File is read only", fn);
1988 goto vc3; 2101 goto vc3;
1989 } 2102 }
@@ -1991,6 +2104,7 @@ static void colon(Byte * buf)
1991 // how many lines in text[]? 2104 // how many lines in text[]?
1992 li = count_lines(q, r); 2105 li = count_lines(q, r);
1993 ch = r - q + 1; 2106 ch = r - q + 1;
2107 // see if file exists- if not, its just a new file request
1994 if (useforce == TRUE) { 2108 if (useforce == TRUE) {
1995 // if "fn" is not write-able, chmod u+w 2109 // if "fn" is not write-able, chmod u+w
1996 // sprintf(syscmd, "chmod u+w %s", fn); 2110 // sprintf(syscmd, "chmod u+w %s", fn);
@@ -2547,12 +2661,14 @@ static Byte find_range(Byte ** start, Byte ** stop, Byte c)
2547 p = q = dot; 2661 p = q = dot;
2548 2662
2549 if (strchr("cdy><", c)) { 2663 if (strchr("cdy><", c)) {
2664 // these cmds operate on whole lines
2550 p = q = begin_line(p); 2665 p = q = begin_line(p);
2551 for (cnt = 1; cnt < cmdcnt; cnt++) { 2666 for (cnt = 1; cnt < cmdcnt; cnt++) {
2552 q = next_line(q); 2667 q = next_line(q);
2553 } 2668 }
2554 q = end_line(q); 2669 q = end_line(q);
2555 } else if (strchr("$0bBeE", c)) { 2670 } else if (strchr("^%$0bBeE", c)) {
2671 // These cmds operate on char positions
2556 do_cmd(c); // execute movement cmd 2672 do_cmd(c); // execute movement cmd
2557 q = dot; 2673 q = dot;
2558 } else if (strchr("wW", c)) { 2674 } else if (strchr("wW", c)) {
@@ -2563,11 +2679,13 @@ static Byte find_range(Byte ** start, Byte ** stop, Byte c)
2563 dot--; // stay off NL 2679 dot--; // stay off NL
2564 q = dot; 2680 q = dot;
2565 } else if (strchr("H-k{", c)) { 2681 } else if (strchr("H-k{", c)) {
2682 // these operate on multi-lines backwards
2566 q = end_line(dot); // find NL 2683 q = end_line(dot); // find NL
2567 do_cmd(c); // execute movement cmd 2684 do_cmd(c); // execute movement cmd
2568 dot_begin(); 2685 dot_begin();
2569 p = dot; 2686 p = dot;
2570 } else if (strchr("L+j}\r\n", c)) { 2687 } else if (strchr("L+j}\r\n", c)) {
2688 // these operate on multi-lines forwards
2571 p = begin_line(dot); 2689 p = begin_line(dot);
2572 do_cmd(c); // execute movement cmd 2690 do_cmd(c); // execute movement cmd
2573 dot_end(); // find NL 2691 dot_end(); // find NL
@@ -3190,7 +3308,7 @@ static Byte readit(void) // read (maybe cursor) key from stdin
3190 FD_ZERO(&rfds); 3308 FD_ZERO(&rfds);
3191 FD_SET(0, &rfds); 3309 FD_SET(0, &rfds);
3192 tv.tv_sec = 0; 3310 tv.tv_sec = 0;
3193 tv.tv_usec = 10000; // Wait 1/100 seconds- 1 Sec=1000000 3311 tv.tv_usec = 50000; // Wait 5/100 seconds- 1 Sec=1000000
3194 3312
3195 // keep reading while there are input chars and room in buffer 3313 // keep reading while there are input chars and room in buffer
3196 while (select(1, &rfds, NULL, NULL, &tv) > 0 && bufsiz <= (BUFSIZ - 5)) { 3314 while (select(1, &rfds, NULL, NULL, &tv) > 0 && bufsiz <= (BUFSIZ - 5)) {
@@ -3267,7 +3385,7 @@ static Byte get_one_char()
3267#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON) 3385#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON)
3268static Byte *get_input_line(Byte * prompt) // get input line- use "status line" 3386static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
3269{ 3387{
3270 Byte buf[500]; 3388 Byte buf[BUFSIZ];
3271 Byte c; 3389 Byte c;
3272 int i; 3390 int i;
3273 static Byte *obufp = NULL; 3391 static Byte *obufp = NULL;
@@ -3278,9 +3396,9 @@ static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
3278 clear_to_eol(); // clear the line 3396 clear_to_eol(); // clear the line
3279 write(1, prompt, strlen((char *) prompt)); // write out the :, /, or ? prompt 3397 write(1, prompt, strlen((char *) prompt)); // write out the :, /, or ? prompt
3280 3398
3281 for (i = strlen((char *) buf); i < 500;) { 3399 for (i = strlen((char *) buf); i < BUFSIZ;) {
3282 c = get_one_char(); // read user input 3400 c = get_one_char(); // read user input
3283 if (c == '\n' || c == '\r') 3401 if (c == '\n' || c == '\r' || c == 27)
3284 break; // is this end of input 3402 break; // is this end of input
3285 if (c == erase_char) { // user wants to erase prev char 3403 if (c == erase_char) { // user wants to erase prev char
3286 i--; // backup to prev char 3404 i--; // backup to prev char
@@ -3310,7 +3428,7 @@ static int file_size(Byte * fn) // what is the byte size of "fn"
3310 struct stat st_buf; 3428 struct stat st_buf;
3311 int cnt, sr; 3429 int cnt, sr;
3312 3430
3313 if (fn == 0) 3431 if (fn == 0 || strlen(fn) <= 0)
3314 return (-1); 3432 return (-1);
3315 cnt = -1; 3433 cnt = -1;
3316 sr = stat((char *) fn, &st_buf); // see if file exists 3434 sr = stat((char *) fn, &st_buf); // see if file exists
@@ -3322,31 +3440,44 @@ static int file_size(Byte * fn) // what is the byte size of "fn"
3322 3440
3323static int file_insert(Byte * fn, Byte * p, int size) 3441static int file_insert(Byte * fn, Byte * p, int size)
3324{ 3442{
3325 int fd, cnt, sr; 3443 int fd, cnt;
3326 struct stat st_buf;
3327 3444
3328 cnt = -1; 3445 cnt = -1;
3329 if (fn == 0) { 3446#ifdef BB_FEATURE_VI_READONLY
3447 readonly = FALSE;
3448#endif /* BB_FEATURE_VI_READONLY */
3449 if (fn == 0 || strlen((char*) fn) <= 0) {
3330 psbs("No filename given"); 3450 psbs("No filename given");
3331 goto fi0; 3451 goto fi0;
3332 } 3452 }
3333 sr = stat((char *) fn, &st_buf); // see if file exists 3453 if (size == 0) {
3334 if (sr < 0) { 3454 // OK- this is just a no-op
3335 psbs("\"%s\" %s", fn, "count not stat file"); 3455 cnt = 0;
3336 goto fi0; 3456 goto fi0;
3337 } 3457 }
3338 if (size <= 0 || (int) st_buf.st_size <= 0) { 3458 if (size < 0) {
3339 psbs("The file size (%d) is too small", size); 3459 psbs("Trying to insert a negative number (%d) of characters", size);
3340 if ((int) st_buf.st_size <= 0)
3341 psbs("\"%s\" is empty", fn);
3342 goto fi0; 3460 goto fi0;
3343 } 3461 }
3344 // There is a file with content 3462 if (p < text || p > end) {
3345 fd = open((char *) fn, O_RDWR); 3463 psbs("Trying to insert file outside of memory");
3346 if (fd < 0) {
3347 psbs("\"%s\" %s", fn, "could not open file");
3348 goto fi0; 3464 goto fi0;
3349 } 3465 }
3466
3467 // see if we can open the file
3468 fd = open((char *) fn, O_RDWR); // assume read & write
3469 if (fd < 0) {
3470 // could not open for writing- maybe file is read only
3471 fd = open((char *) fn, O_RDONLY); // try read-only
3472 if (fd < 0) {
3473 psbs("\"%s\" %s", fn, "could not open file");
3474 goto fi0;
3475 }
3476#ifdef BB_FEATURE_VI_READONLY
3477 // got the file- read-only
3478 readonly = TRUE;
3479#endif /* BB_FEATURE_VI_READONLY */
3480 }
3350 p = text_hole_make(p, size); 3481 p = text_hole_make(p, size);
3351 cnt = read(fd, p, size); 3482 cnt = read(fd, p, size);
3352 close(fd); 3483 close(fd);
@@ -3527,7 +3658,7 @@ static void psb(char *format, ...)
3527 3658
3528static void ni(Byte * s) // display messages 3659static void ni(Byte * s) // display messages
3529{ 3660{
3530 Byte buf[9]; 3661 Byte buf[BUFSIZ];
3531 3662
3532 print_literal(buf, s); 3663 print_literal(buf, s);
3533 psbs("\'%s\' is not implemented", buf); 3664 psbs("\'%s\' is not implemented", buf);
@@ -3552,13 +3683,13 @@ static void edit_status(void) // show file status on status line
3552#ifdef BB_FEATURE_VI_READONLY 3683#ifdef BB_FEATURE_VI_READONLY
3553 "%s" 3684 "%s"
3554#endif /* BB_FEATURE_VI_READONLY */ 3685#endif /* BB_FEATURE_VI_READONLY */
3555 "%s line %d of %d --%d%%-- (%dx%d)", 3686 "%s line %d of %d --%d%%--",
3556 (cfn != 0 ? (char *) cfn : "No file"), 3687 (cfn != 0 ? (char *) cfn : "No file"),
3557#ifdef BB_FEATURE_VI_READONLY 3688#ifdef BB_FEATURE_VI_READONLY
3558 (readonly == TRUE ? " [Read only]" : ""), 3689 (readonly == TRUE ? " [Read only]" : ""),
3559#endif /* BB_FEATURE_VI_READONLY */ 3690#endif /* BB_FEATURE_VI_READONLY */
3560 (file_modified == TRUE ? " [modified]" : ""), 3691 (file_modified == TRUE ? " [modified]" : ""),
3561 cur, tot, percent, rows, columns); 3692 cur, tot, percent);
3562} 3693}
3563 3694
3564//----- Force refresh of all Lines ----------------------------- 3695//----- Force refresh of all Lines -----------------------------