diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-04-16 15:46:44 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-04-16 15:46:44 +0000 |
commit | 1c0d311ff437823ee99019881d4fe4109def1a8c (patch) | |
tree | e08c48d0a4c26ba444a05e07ac09d793a55e3715 | |
parent | ae1c704c44573c710ff196fa9c8bcaebbfe34966 (diff) | |
download | busybox-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-- | Changelog | 11 | ||||
-rw-r--r-- | editors/vi.c | 289 | ||||
-rw-r--r-- | vi.c | 289 |
3 files changed, 430 insertions, 159 deletions
@@ -1,3 +1,12 @@ | |||
1 | 0.52 | ||
2 | |||
3 | * Sterling Huxley -- Several bugfixes for the vi applet. | ||
4 | |||
5 | |||
6 | -Erik Andersen, not yet released | ||
7 | |||
8 | |||
9 | |||
1 | 0.51 | 10 | 0.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 | ||
75 | 0.50 | 84 | 0.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 | ||
21 | char *vi_Version = | 21 | char *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 |
255 | static void Hit_Return(void); | 259 | static void Hit_Return(void); |
256 | static Byte *get_address(Byte *, int *); // get colon addr, if present | 260 | static Byte *get_one_address(Byte *, int *); // get colon addr, if present |
261 | static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present | ||
257 | static void colon(Byte *); // execute the "colon" mode cmds | 262 | static 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) | |||
379 | static void edit_file(Byte * fn) | 384 | static 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 |
1577 | static Byte *get_address(Byte * p, int *addr) // get colon addr, if present | 1603 | static 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 | ||
1666 | static 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 | } | ||
1688 | ga0: | ||
1689 | while (isblnk(*p)) | ||
1690 | p++; // skip over trailing spaces | ||
1691 | return (p); | ||
1692 | } | ||
1693 | |||
1640 | static void colon(Byte * buf) | 1694 | static 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) |
3268 | static Byte *get_input_line(Byte * prompt) // get input line- use "status line" | 3386 | static 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 | ||
3323 | static int file_insert(Byte * fn, Byte * p, int size) | 3441 | static 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 | ||
3528 | static void ni(Byte * s) // display messages | 3659 | static 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 ----------------------------- |
@@ -19,7 +19,7 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | char *vi_Version = | 21 | char *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 |
255 | static void Hit_Return(void); | 259 | static void Hit_Return(void); |
256 | static Byte *get_address(Byte *, int *); // get colon addr, if present | 260 | static Byte *get_one_address(Byte *, int *); // get colon addr, if present |
261 | static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present | ||
257 | static void colon(Byte *); // execute the "colon" mode cmds | 262 | static 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) | |||
379 | static void edit_file(Byte * fn) | 384 | static 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 |
1577 | static Byte *get_address(Byte * p, int *addr) // get colon addr, if present | 1603 | static 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 | ||
1666 | static 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 | } | ||
1688 | ga0: | ||
1689 | while (isblnk(*p)) | ||
1690 | p++; // skip over trailing spaces | ||
1691 | return (p); | ||
1692 | } | ||
1693 | |||
1640 | static void colon(Byte * buf) | 1694 | static 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) |
3268 | static Byte *get_input_line(Byte * prompt) // get input line- use "status line" | 3386 | static 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 | ||
3323 | static int file_insert(Byte * fn, Byte * p, int size) | 3441 | static 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 | ||
3528 | static void ni(Byte * s) // display messages | 3659 | static 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 ----------------------------- |