diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-12-22 15:40:13 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-12-22 15:40:13 +0000 |
commit | 88adfcd17863361a827551a572f993e43356eefc (patch) | |
tree | 7ea5952f0f96e9488a3c822dcdaa1db9bc41d783 | |
parent | ee87ebf3815d37cbdcaf766a06ed40d4ca0dfe81 (diff) | |
download | busybox-w32-88adfcd17863361a827551a572f993e43356eefc.tar.gz busybox-w32-88adfcd17863361a827551a572f993e43356eefc.tar.bz2 busybox-w32-88adfcd17863361a827551a572f993e43356eefc.zip |
vi: change MAX_LINELEN meaning: now it is the biggest supported
screen wigth. Introduce MAX_TABSTOP and MAX_INPUT_LEN. Fix redraw
of very long lines and cursor movement past NULs.
-rw-r--r-- | editors/Config.in | 9 | ||||
-rw-r--r-- | editors/vi.c | 617 |
2 files changed, 309 insertions, 317 deletions
diff --git a/editors/Config.in b/editors/Config.in index 3361d89f1..7c06678fb 100644 --- a/editors/Config.in +++ b/editors/Config.in | |||
@@ -90,14 +90,13 @@ config VI | |||
90 | you may wish to use something else. | 90 | you may wish to use something else. |
91 | 91 | ||
92 | config FEATURE_VI_MAX_LEN | 92 | config FEATURE_VI_MAX_LEN |
93 | int "Maximum line length in vi" | 93 | int "Maximum screen width in vi" |
94 | range 256 16384 | 94 | range 256 16384 |
95 | default 1024 | 95 | default 4096 |
96 | depends on VI | 96 | depends on VI |
97 | help | 97 | help |
98 | vi uses on-stack buffers for intermediate line buffers. | 98 | Contrary to what you may think, this is not eating much. |
99 | You may want to decrease this parameter if your target machine | 99 | Make it smaller than 4k only if you are very limited on memory. |
100 | benefits from smaller stack usage. | ||
101 | 100 | ||
102 | config FEATURE_VI_COLON | 101 | config FEATURE_VI_COLON |
103 | bool "Enable \":\" colon commands (no \"ex\" mode)" | 102 | bool "Enable \":\" colon commands (no \"ex\" mode)" |
diff --git a/editors/vi.c b/editors/vi.c index e58d6b310..e1aabab01 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -33,9 +33,13 @@ | |||
33 | #endif | 33 | #endif |
34 | 34 | ||
35 | enum { | 35 | enum { |
36 | MAX_LINELEN = CONFIG_FEATURE_VI_MAX_LEN, | ||
37 | MAX_SCR_COLS = CONFIG_FEATURE_VI_MAX_LEN, | ||
38 | MAX_TABSTOP = 32, // sanity limit | 36 | MAX_TABSTOP = 32, // sanity limit |
37 | // User input len. Need not be extra big. | ||
38 | // Lines in file being edited *can* be bigger than this. | ||
39 | MAX_INPUT_LEN = 128, | ||
40 | // Sanity limits. We have only one buffer of this size. | ||
41 | MAX_SCR_COLS = CONFIG_FEATURE_VI_MAX_LEN, | ||
42 | MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN, | ||
39 | }; | 43 | }; |
40 | 44 | ||
41 | // Misc. non-Ascii keys that report an escape sequence | 45 | // Misc. non-Ascii keys that report an escape sequence |
@@ -46,20 +50,21 @@ enum { | |||
46 | #define VI_K_HOME (char)132 // Cursor Key Home | 50 | #define VI_K_HOME (char)132 // Cursor Key Home |
47 | #define VI_K_END (char)133 // Cursor Key End | 51 | #define VI_K_END (char)133 // Cursor Key End |
48 | #define VI_K_INSERT (char)134 // Cursor Key Insert | 52 | #define VI_K_INSERT (char)134 // Cursor Key Insert |
49 | #define VI_K_PAGEUP (char)135 // Cursor Key Page Up | 53 | #define VI_K_DELETE (char)135 // Cursor Key Insert |
50 | #define VI_K_PAGEDOWN (char)136 // Cursor Key Page Down | 54 | #define VI_K_PAGEUP (char)136 // Cursor Key Page Up |
51 | #define VI_K_FUN1 (char)137 // Function Key F1 | 55 | #define VI_K_PAGEDOWN (char)137 // Cursor Key Page Down |
52 | #define VI_K_FUN2 (char)138 // Function Key F2 | 56 | #define VI_K_FUN1 (char)138 // Function Key F1 |
53 | #define VI_K_FUN3 (char)139 // Function Key F3 | 57 | #define VI_K_FUN2 (char)139 // Function Key F2 |
54 | #define VI_K_FUN4 (char)140 // Function Key F4 | 58 | #define VI_K_FUN3 (char)140 // Function Key F3 |
55 | #define VI_K_FUN5 (char)141 // Function Key F5 | 59 | #define VI_K_FUN4 (char)141 // Function Key F4 |
56 | #define VI_K_FUN6 (char)142 // Function Key F6 | 60 | #define VI_K_FUN5 (char)142 // Function Key F5 |
57 | #define VI_K_FUN7 (char)143 // Function Key F7 | 61 | #define VI_K_FUN6 (char)143 // Function Key F6 |
58 | #define VI_K_FUN8 (char)144 // Function Key F8 | 62 | #define VI_K_FUN7 (char)144 // Function Key F7 |
59 | #define VI_K_FUN9 (char)145 // Function Key F9 | 63 | #define VI_K_FUN8 (char)145 // Function Key F8 |
60 | #define VI_K_FUN10 (char)146 // Function Key F10 | 64 | #define VI_K_FUN9 (char)146 // Function Key F9 |
61 | #define VI_K_FUN11 (char)147 // Function Key F11 | 65 | #define VI_K_FUN10 (char)147 // Function Key F10 |
62 | #define VI_K_FUN12 (char)148 // Function Key F12 | 66 | #define VI_K_FUN11 (char)148 // Function Key F11 |
67 | #define VI_K_FUN12 (char)149 // Function Key F12 | ||
63 | 68 | ||
64 | /* vt102 typical ESC sequence */ | 69 | /* vt102 typical ESC sequence */ |
65 | /* terminal standout start/normal ESC sequence */ | 70 | /* terminal standout start/normal ESC sequence */ |
@@ -150,7 +155,7 @@ static smallint readonly_mode = 0; | |||
150 | 155 | ||
151 | #if ENABLE_FEATURE_VI_DOT_CMD | 156 | #if ENABLE_FEATURE_VI_DOT_CMD |
152 | static smallint adding2q; // are we currently adding user input to q | 157 | static smallint adding2q; // are we currently adding user input to q |
153 | static char *last_modifying_cmd; // last modifying cmd for "." | 158 | static char *last_modifying_cmd; // [MAX_INPUT_LEN] last modifying cmd for "." |
154 | static char *ioq, *ioq_start; // pointer to string for get_one_char to "read" | 159 | static char *ioq, *ioq_start; // pointer to string for get_one_char to "read" |
155 | #endif | 160 | #endif |
156 | #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR | 161 | #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR |
@@ -170,23 +175,31 @@ static char *last_search_pattern; // last pattern from a '/' or '?' search | |||
170 | struct globals { | 175 | struct globals { |
171 | /* many references - keep near the top of globals */ | 176 | /* many references - keep near the top of globals */ |
172 | char *text, *end; // pointers to the user data in memory | 177 | char *text, *end; // pointers to the user data in memory |
173 | int text_size; // size of the allocated buffer | ||
174 | char *dot; // where all the action takes place | 178 | char *dot; // where all the action takes place |
179 | int text_size; // size of the allocated buffer | ||
175 | #if ENABLE_FEATURE_VI_YANKMARK | 180 | #if ENABLE_FEATURE_VI_YANKMARK |
176 | char *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 | ||
177 | int YDreg, Ureg; // default delete register and orig line for "U" | 181 | int YDreg, Ureg; // default delete register and orig line for "U" |
182 | char *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 | ||
178 | char *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' | 183 | char *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' |
179 | char *context_start, *context_end; | 184 | char *context_start, *context_end; |
180 | #endif | 185 | #endif |
181 | /* a few references only */ | 186 | /* a few references only */ |
182 | #if ENABLE_FEATURE_VI_USE_SIGNALS | 187 | #if ENABLE_FEATURE_VI_USE_SIGNALS |
183 | jmp_buf restart; // catch_sig() | 188 | jmp_buf restart; // catch_sig() |
184 | #endif | 189 | #endif |
185 | struct termios term_orig, term_vi; // remember what the cooked mode was | 190 | struct termios term_orig, term_vi; // remember what the cooked mode was |
186 | #if ENABLE_FEATURE_VI_COLON | 191 | #if ENABLE_FEATURE_VI_COLON |
187 | char *initial_cmds[3]; // currently 2 entries, NULL terminated | 192 | char *initial_cmds[3]; // currently 2 entries, NULL terminated |
188 | #endif | 193 | #endif |
189 | char readbuffer[MAX_LINELEN]; | 194 | // Should be just enough to hold a key sequence, |
195 | // but CRASME mode uses it as generated command buffer too | ||
196 | #if ENABLE_FEATURE_VI_CRASHME | ||
197 | char readbuffer[128]; | ||
198 | #else | ||
199 | char readbuffer[32]; | ||
200 | #endif | ||
201 | |||
202 | char scr_out_buf[MAX_SCR_COLS + MAX_TABSTOP * 2]; | ||
190 | }; | 203 | }; |
191 | #define G (*ptr_to_globals) | 204 | #define G (*ptr_to_globals) |
192 | #define text (G.text ) | 205 | #define text (G.text ) |
@@ -204,6 +217,7 @@ struct globals { | |||
204 | #define term_vi (G.term_vi ) | 217 | #define term_vi (G.term_vi ) |
205 | #define initial_cmds (G.initial_cmds ) | 218 | #define initial_cmds (G.initial_cmds ) |
206 | #define readbuffer (G.readbuffer ) | 219 | #define readbuffer (G.readbuffer ) |
220 | #define scr_out_buf (G.scr_out_buf ) | ||
207 | #define INIT_G() do { \ | 221 | #define INIT_G() do { \ |
208 | PTR_TO_GLOBALS = xzalloc(sizeof(G)); \ | 222 | PTR_TO_GLOBALS = xzalloc(sizeof(G)); \ |
209 | } while (0) | 223 | } while (0) |
@@ -266,12 +280,12 @@ static void standout_start(void); // send "start reverse video" sequence | |||
266 | static void standout_end(void); // send "end reverse video" sequence | 280 | static void standout_end(void); // send "end reverse video" sequence |
267 | static void flash(int); // flash the terminal screen | 281 | static void flash(int); // flash the terminal screen |
268 | static void show_status_line(void); // put a message on the bottom line | 282 | static void show_status_line(void); // put a message on the bottom line |
269 | static void psb(const char *, ...); // Print Status Buf | 283 | static void status_line(const char *, ...); // print to status buf |
270 | static void psbs(const char *, ...); // Print Status Buf in standout mode | 284 | static void status_line_bold(const char *, ...); |
271 | static void ni(const char *); // display messages | 285 | static void not_implemented(const char *); // display "Not implemented" message |
272 | static int format_edit_status(void); // format file status on status line | 286 | static int format_edit_status(void); // format file status on status line |
273 | static void redraw(int); // force a full screen refresh | 287 | static void redraw(int); // force a full screen refresh |
274 | static int format_line(char*, char*, int); | 288 | static char* format_line(char*, int); |
275 | static void refresh(int); // update the terminal from screen[] | 289 | static void refresh(int); // update the terminal from screen[] |
276 | 290 | ||
277 | static void Indicate_Error(void); // use flash or beep to indicate error | 291 | static void Indicate_Error(void); // use flash or beep to indicate error |
@@ -363,7 +377,7 @@ int vi_main(int argc, char **argv) | |||
363 | { | 377 | { |
364 | char *p = getenv("EXINIT"); | 378 | char *p = getenv("EXINIT"); |
365 | if (p && *p) | 379 | if (p && *p) |
366 | initial_cmds[0] = xstrdup(p); | 380 | initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN); |
367 | } | 381 | } |
368 | #endif | 382 | #endif |
369 | while ((c = getopt(argc, argv, "hCR" USE_FEATURE_VI_COLON("c:"))) != -1) { | 383 | while ((c = getopt(argc, argv, "hCR" USE_FEATURE_VI_COLON("c:"))) != -1) { |
@@ -384,7 +398,7 @@ int vi_main(int argc, char **argv) | |||
384 | #if ENABLE_FEATURE_VI_COLON | 398 | #if ENABLE_FEATURE_VI_COLON |
385 | case 'c': // cmd line vi command | 399 | case 'c': // cmd line vi command |
386 | if (*optarg) | 400 | if (*optarg) |
387 | initial_cmds[initial_cmds[0] != 0] = xstrdup(optarg); | 401 | initial_cmds[initial_cmds[0] != 0] = xstrndup(optarg, MAX_INPUT_LEN); |
388 | break; | 402 | break; |
389 | //case 'h': // help -- just use default | 403 | //case 'h': // help -- just use default |
390 | #endif | 404 | #endif |
@@ -447,7 +461,7 @@ static int init_text_buffer(char *fn) | |||
447 | return rc; | 461 | return rc; |
448 | } | 462 | } |
449 | 463 | ||
450 | static void edit_file(char * fn) | 464 | static void edit_file(char *fn) |
451 | { | 465 | { |
452 | char c; | 466 | char c; |
453 | int size; | 467 | int size; |
@@ -459,13 +473,16 @@ static void edit_file(char * fn) | |||
459 | static char *cur_line; | 473 | static char *cur_line; |
460 | #endif | 474 | #endif |
461 | 475 | ||
462 | editing = 1; // 0= exit, 1= one file, 2= multiple files | 476 | editing = 1; // 0 = exit, 1 = one file, 2 = multiple files |
463 | rawmode(); | 477 | rawmode(); |
464 | rows = 24; | 478 | rows = 24; |
465 | columns = 80; | 479 | columns = 80; |
466 | size = 0; | 480 | size = 0; |
467 | if (ENABLE_FEATURE_VI_WIN_RESIZE) | 481 | if (ENABLE_FEATURE_VI_WIN_RESIZE) { |
468 | get_terminal_width_height(0, &columns, &rows); | 482 | get_terminal_width_height(0, &columns, &rows); |
483 | if (rows > MAX_SCR_ROWS) rows = MAX_SCR_ROWS; | ||
484 | if (columns > MAX_SCR_COLS) columns = MAX_SCR_COLS; | ||
485 | } | ||
469 | new_screen(rows, columns); // get memory for virtual screen | 486 | new_screen(rows, columns); // get memory for virtual screen |
470 | init_text_buffer(fn); | 487 | init_text_buffer(fn); |
471 | 488 | ||
@@ -510,7 +527,7 @@ static void edit_file(char * fn) | |||
510 | while ((p = initial_cmds[n])) { | 527 | while ((p = initial_cmds[n])) { |
511 | do { | 528 | do { |
512 | q = p; | 529 | q = p; |
513 | p = strchr(q,'\n'); | 530 | p = strchr(q, '\n'); |
514 | if (p) | 531 | if (p) |
515 | while (*p == '\n') | 532 | while (*p == '\n') |
516 | *p++ = '\0'; | 533 | *p++ = '\0'; |
@@ -547,7 +564,7 @@ static void edit_file(char * fn) | |||
547 | #if ENABLE_FEATURE_VI_DOT_CMD | 564 | #if ENABLE_FEATURE_VI_DOT_CMD |
548 | // These are commands that change text[]. | 565 | // These are commands that change text[]. |
549 | // Remember the input for the "." command | 566 | // Remember the input for the "." command |
550 | if (!adding2q && ioq_start == 0 | 567 | if (!adding2q && ioq_start == NULL |
551 | && strchr(modifying_cmds, c) | 568 | && strchr(modifying_cmds, c) |
552 | ) { | 569 | ) { |
553 | start_new_cmd_q(c); | 570 | start_new_cmd_q(c); |
@@ -577,25 +594,21 @@ static void edit_file(char * fn) | |||
577 | 594 | ||
578 | //----- The Colon commands ------------------------------------- | 595 | //----- The Colon commands ------------------------------------- |
579 | #if ENABLE_FEATURE_VI_COLON | 596 | #if ENABLE_FEATURE_VI_COLON |
580 | static char *get_one_address(char * p, int *addr) // get colon addr, if present | 597 | static char *get_one_address(char *p, int *addr) // get colon addr, if present |
581 | { | 598 | { |
582 | int st; | 599 | int st; |
583 | char *q; | 600 | char *q; |
584 | 601 | USE_FEATURE_VI_YANKMARK(char c;) | |
585 | #if ENABLE_FEATURE_VI_YANKMARK | 602 | USE_FEATURE_VI_SEARCH(char *pat;) |
586 | char c; | ||
587 | #endif | ||
588 | #if ENABLE_FEATURE_VI_SEARCH | ||
589 | char *pat, buf[MAX_LINELEN]; | ||
590 | #endif | ||
591 | 603 | ||
592 | *addr = -1; // assume no addr | 604 | *addr = -1; // assume no addr |
593 | if (*p == '.') { // the current line | 605 | if (*p == '.') { // the current line |
594 | p++; | 606 | p++; |
595 | q = begin_line(dot); | 607 | q = begin_line(dot); |
596 | *addr = count_lines(text, q); | 608 | *addr = count_lines(text, q); |
609 | } | ||
597 | #if ENABLE_FEATURE_VI_YANKMARK | 610 | #if ENABLE_FEATURE_VI_YANKMARK |
598 | } else if (*p == '\'') { // is this a mark addr | 611 | else if (*p == '\'') { // is this a mark addr |
599 | p++; | 612 | p++; |
600 | c = tolower(*p); | 613 | c = tolower(*p); |
601 | p++; | 614 | p++; |
@@ -607,17 +620,13 @@ static char *get_one_address(char * p, int *addr) // get colon addr, if present | |||
607 | *addr = count_lines(text, q); // count lines | 620 | *addr = count_lines(text, q); // count lines |
608 | } | 621 | } |
609 | } | 622 | } |
623 | } | ||
610 | #endif | 624 | #endif |
611 | #if ENABLE_FEATURE_VI_SEARCH | 625 | #if ENABLE_FEATURE_VI_SEARCH |
612 | } else if (*p == '/') { // a search pattern | 626 | else if (*p == '/') { // a search pattern |
613 | q = buf; | 627 | q = strchrnul(++p, '/'); |
614 | for (p++; *p; p++) { | 628 | pat = xstrndup(p, q - p); // save copy of pattern |
615 | if (*p == '/') | 629 | p = q; |
616 | break; | ||
617 | *q++ = *p; | ||
618 | *q = '\0'; | ||
619 | } | ||
620 | pat = xstrdup(buf); // save copy of pattern | ||
621 | if (*p == '/') | 630 | if (*p == '/') |
622 | p++; | 631 | p++; |
623 | q = char_search(dot, pat, FORWARD, FULL); | 632 | q = char_search(dot, pat, FORWARD, FULL); |
@@ -625,16 +634,17 @@ static char *get_one_address(char * p, int *addr) // get colon addr, if present | |||
625 | *addr = count_lines(text, q); | 634 | *addr = count_lines(text, q); |
626 | } | 635 | } |
627 | free(pat); | 636 | free(pat); |
637 | } | ||
628 | #endif | 638 | #endif |
629 | } else if (*p == '$') { // the last line in file | 639 | else if (*p == '$') { // the last line in file |
630 | p++; | 640 | p++; |
631 | q = begin_line(end - 1); | 641 | q = begin_line(end - 1); |
632 | *addr = count_lines(text, q); | 642 | *addr = count_lines(text, q); |
633 | } else if (isdigit(*p)) { // specific line number | 643 | } else if (isdigit(*p)) { // specific line number |
634 | sscanf(p, "%d%n", addr, &st); | 644 | sscanf(p, "%d%n", addr, &st); |
635 | p += st; | 645 | p += st; |
636 | } else { // I don't reconise this | 646 | } else { |
637 | // unrecognised address- assume -1 | 647 | // unrecognised address - assume -1 |
638 | *addr = -1; | 648 | *addr = -1; |
639 | } | 649 | } |
640 | return p; | 650 | return p; |
@@ -686,12 +696,13 @@ static void setops(const char *args, const char *opname, int flg_no, | |||
686 | } | 696 | } |
687 | #endif | 697 | #endif |
688 | 698 | ||
689 | static void colon(char * buf) | 699 | // buf must be no longer than MAX_INPUT_LEN! |
700 | static void colon(char *buf) | ||
690 | { | 701 | { |
691 | char c, *orig_buf, *buf1, *q, *r; | 702 | char c, *orig_buf, *buf1, *q, *r; |
692 | char *fn, cmd[MAX_LINELEN], args[MAX_LINELEN]; | 703 | char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN]; |
693 | int i, l, li, ch, b, e; | 704 | int i, l, li, ch, b, e; |
694 | int useforce = FALSE, forced = FALSE; | 705 | int useforce, forced = FALSE; |
695 | 706 | ||
696 | // :3154 // if (-e line 3154) goto it else stay put | 707 | // :3154 // if (-e line 3154) goto it else stay put |
697 | // :4,33w! foo // write a portion of buffer to file "foo" | 708 | // :4,33w! foo // write a portion of buffer to file "foo" |
@@ -718,9 +729,7 @@ static void colon(char * buf) | |||
718 | q = text; // assume 1,$ for the range | 729 | q = text; // assume 1,$ for the range |
719 | r = end - 1; | 730 | r = end - 1; |
720 | li = count_lines(text, end - 1); | 731 | li = count_lines(text, end - 1); |
721 | fn = current_filename; // default to current file | 732 | fn = current_filename; |
722 | memset(cmd, '\0', MAX_LINELEN); // clear cmd[] | ||
723 | memset(args, '\0', MAX_LINELEN); // clear args[] | ||
724 | 733 | ||
725 | // look for optional address(es) :. :1 :1,9 :'q,'a :% | 734 | // look for optional address(es) :. :1 :1,9 :'q,'a :% |
726 | buf = get_address(buf, &b, &e); | 735 | buf = get_address(buf, &b, &e); |
@@ -735,10 +744,12 @@ static void colon(char * buf) | |||
735 | break; | 744 | break; |
736 | *buf1++ = *buf++; | 745 | *buf1++ = *buf++; |
737 | } | 746 | } |
747 | *buf1 = '\0'; | ||
738 | // get any ARGuments | 748 | // get any ARGuments |
739 | while (isblank(*buf)) | 749 | while (isblank(*buf)) |
740 | buf++; | 750 | buf++; |
741 | strcpy(args, buf); | 751 | strcpy(args, buf); |
752 | useforce = FALSE; | ||
742 | buf1 = last_char_is(cmd, '!'); | 753 | buf1 = last_char_is(cmd, '!'); |
743 | if (buf1) { | 754 | if (buf1) { |
744 | useforce = TRUE; | 755 | useforce = TRUE; |
@@ -788,7 +799,7 @@ static void colon(char * buf) | |||
788 | if (b < 0) { // no addr given- use defaults | 799 | if (b < 0) { // no addr given- use defaults |
789 | b = e = count_lines(text, dot); | 800 | b = e = count_lines(text, dot); |
790 | } | 801 | } |
791 | psb("%d", b); | 802 | status_line("%d", b); |
792 | } else if (strncasecmp(cmd, "delete", i) == 0) { // delete lines | 803 | } else if (strncasecmp(cmd, "delete", i) == 0) { // delete lines |
793 | if (b < 0) { // no addr given- use defaults | 804 | if (b < 0) { // no addr given- use defaults |
794 | q = begin_line(dot); // assume .,. for the range | 805 | q = begin_line(dot); // assume .,. for the range |
@@ -798,8 +809,8 @@ static void colon(char * buf) | |||
798 | dot_skip_over_ws(); | 809 | dot_skip_over_ws(); |
799 | } else if (strncasecmp(cmd, "edit", i) == 0) { // Edit a file | 810 | } else if (strncasecmp(cmd, "edit", i) == 0) { // Edit a file |
800 | // don't edit, if the current file has been modified | 811 | // don't edit, if the current file has been modified |
801 | if (file_modified && ! useforce) { | 812 | if (file_modified && !useforce) { |
802 | psbs("No write since last change (:edit! overrides)"); | 813 | status_line_bold("No write since last change (:edit! overrides)"); |
803 | goto vc1; | 814 | goto vc1; |
804 | } | 815 | } |
805 | if (args[0]) { | 816 | if (args[0]) { |
@@ -810,7 +821,7 @@ static void colon(char * buf) | |||
810 | // fn = current_filename; was set by default | 821 | // fn = current_filename; was set by default |
811 | } else { | 822 | } else { |
812 | // no user file name, no current name- punt | 823 | // no user file name, no current name- punt |
813 | psbs("No current filename"); | 824 | status_line_bold("No current filename"); |
814 | goto vc1; | 825 | goto vc1; |
815 | } | 826 | } |
816 | 827 | ||
@@ -829,7 +840,7 @@ static void colon(char * buf) | |||
829 | #endif | 840 | #endif |
830 | // how many lines in text[]? | 841 | // how many lines in text[]? |
831 | li = count_lines(text, end - 1); | 842 | li = count_lines(text, end - 1); |
832 | psb("\"%s\"%s" | 843 | status_line("\"%s\"%s" |
833 | USE_FEATURE_VI_READONLY("%s") | 844 | USE_FEATURE_VI_READONLY("%s") |
834 | " %dL, %dC", current_filename, | 845 | " %dL, %dC", current_filename, |
835 | (file_size(fn) < 0 ? " [New file]" : ""), | 846 | (file_size(fn) < 0 ? " [New file]" : ""), |
@@ -839,7 +850,7 @@ static void colon(char * buf) | |||
839 | li, ch); | 850 | li, ch); |
840 | } else if (strncasecmp(cmd, "file", i) == 0) { // what File is this | 851 | } else if (strncasecmp(cmd, "file", i) == 0) { // what File is this |
841 | if (b != -1 || e != -1) { | 852 | if (b != -1 || e != -1) { |
842 | ni("No address allowed on this command"); | 853 | not_implemented("No address allowed on this command"); |
843 | goto vc1; | 854 | goto vc1; |
844 | } | 855 | } |
845 | if (args[0]) { | 856 | if (args[0]) { |
@@ -905,24 +916,24 @@ static void colon(char * buf) | |||
905 | } | 916 | } |
906 | // don't exit if the file been modified | 917 | // don't exit if the file been modified |
907 | if (file_modified) { | 918 | if (file_modified) { |
908 | psbs("No write since last change (:%s! overrides)", | 919 | status_line_bold("No write since last change (:%s! overrides)", |
909 | (*cmd == 'q' ? "quit" : "next")); | 920 | (*cmd == 'q' ? "quit" : "next")); |
910 | goto vc1; | 921 | goto vc1; |
911 | } | 922 | } |
912 | // are there other file to edit | 923 | // are there other file to edit |
913 | if (*cmd == 'q' && optind < save_argc - 1) { | 924 | if (*cmd == 'q' && optind < save_argc - 1) { |
914 | psbs("%d more file to edit", (save_argc - optind - 1)); | 925 | status_line_bold("%d more file to edit", (save_argc - optind - 1)); |
915 | goto vc1; | 926 | goto vc1; |
916 | } | 927 | } |
917 | if (*cmd == 'n' && optind >= save_argc - 1) { | 928 | if (*cmd == 'n' && optind >= save_argc - 1) { |
918 | psbs("No more files to edit"); | 929 | status_line_bold("No more files to edit"); |
919 | goto vc1; | 930 | goto vc1; |
920 | } | 931 | } |
921 | editing = 0; | 932 | editing = 0; |
922 | } else if (strncasecmp(cmd, "read", i) == 0) { // read file into text[] | 933 | } else if (strncasecmp(cmd, "read", i) == 0) { // read file into text[] |
923 | fn = args; | 934 | fn = args; |
924 | if (!fn[0]) { | 935 | if (!fn[0]) { |
925 | psbs("No filename given"); | 936 | status_line_bold("No filename given"); |
926 | goto vc1; | 937 | goto vc1; |
927 | } | 938 | } |
928 | if (b < 0) { // no addr given- use defaults | 939 | if (b < 0) { // no addr given- use defaults |
@@ -936,7 +947,7 @@ static void colon(char * buf) | |||
936 | goto vc1; // nothing was inserted | 947 | goto vc1; // nothing was inserted |
937 | // how many lines in text[]? | 948 | // how many lines in text[]? |
938 | li = count_lines(q, q + ch - 1); | 949 | li = count_lines(q, q + ch - 1); |
939 | psb("\"%s\"" | 950 | status_line("\"%s\"" |
940 | USE_FEATURE_VI_READONLY("%s") | 951 | USE_FEATURE_VI_READONLY("%s") |
941 | " %dL, %dC", fn, | 952 | " %dL, %dC", fn, |
942 | USE_FEATURE_VI_READONLY((readonly_mode ? " [Readonly]" : ""),) | 953 | USE_FEATURE_VI_READONLY((readonly_mode ? " [Readonly]" : ""),) |
@@ -948,8 +959,8 @@ static void colon(char * buf) | |||
948 | file_modified++; | 959 | file_modified++; |
949 | } | 960 | } |
950 | } else if (strncasecmp(cmd, "rewind", i) == 0) { // rewind cmd line args | 961 | } else if (strncasecmp(cmd, "rewind", i) == 0) { // rewind cmd line args |
951 | if (file_modified && ! useforce) { | 962 | if (file_modified && !useforce) { |
952 | psbs("No write since last change (:rewind! overrides)"); | 963 | status_line_bold("No write since last change (:rewind! overrides)"); |
953 | } else { | 964 | } else { |
954 | // reset the filenames to edit | 965 | // reset the filenames to edit |
955 | optind = fn_start - 1; | 966 | optind = fn_start - 1; |
@@ -1056,7 +1067,7 @@ static void colon(char * buf) | |||
1056 | } | 1067 | } |
1057 | #endif /* FEATURE_VI_SEARCH */ | 1068 | #endif /* FEATURE_VI_SEARCH */ |
1058 | } else if (strncasecmp(cmd, "version", i) == 0) { // show software version | 1069 | } else if (strncasecmp(cmd, "version", i) == 0) { // show software version |
1059 | psb("%s", BB_VER " " BB_BT); | 1070 | status_line("%s", BB_VER " " BB_BT); |
1060 | } else if (strncasecmp(cmd, "write", i) == 0 // write text to file | 1071 | } else if (strncasecmp(cmd, "write", i) == 0 // write text to file |
1061 | || strncasecmp(cmd, "wq", i) == 0 | 1072 | || strncasecmp(cmd, "wq", i) == 0 |
1062 | || strncasecmp(cmd, "wn", i) == 0 | 1073 | || strncasecmp(cmd, "wn", i) == 0 |
@@ -1068,7 +1079,7 @@ static void colon(char * buf) | |||
1068 | } | 1079 | } |
1069 | #if ENABLE_FEATURE_VI_READONLY | 1080 | #if ENABLE_FEATURE_VI_READONLY |
1070 | if (readonly_mode && !useforce) { | 1081 | if (readonly_mode && !useforce) { |
1071 | psbs("\"%s\" File is read only", fn); | 1082 | status_line_bold("\"%s\" File is read only", fn); |
1072 | goto vc3; | 1083 | goto vc3; |
1073 | } | 1084 | } |
1074 | #endif | 1085 | #endif |
@@ -1091,9 +1102,9 @@ static void colon(char * buf) | |||
1091 | } | 1102 | } |
1092 | if (l < 0) { | 1103 | if (l < 0) { |
1093 | if (l == -1) | 1104 | if (l == -1) |
1094 | psbs("\"%s\" %s", fn, strerror(errno)); | 1105 | status_line_bold("\"%s\" %s", fn, strerror(errno)); |
1095 | } else { | 1106 | } else { |
1096 | psb("\"%s\" %dL, %dC", fn, li, l); | 1107 | status_line("\"%s\" %dL, %dC", fn, li, l); |
1097 | if (q == text && r == end - 1 && l == ch) { | 1108 | if (q == text && r == end - 1 && l == ch) { |
1098 | file_modified = 0; | 1109 | file_modified = 0; |
1099 | last_file_modified = -1; | 1110 | last_file_modified = -1; |
@@ -1115,19 +1126,19 @@ static void colon(char * buf) | |||
1115 | } | 1126 | } |
1116 | text_yank(q, r, YDreg); | 1127 | text_yank(q, r, YDreg); |
1117 | li = count_lines(q, r); | 1128 | li = count_lines(q, r); |
1118 | psb("Yank %d lines (%d chars) into [%c]", | 1129 | status_line("Yank %d lines (%d chars) into [%c]", |
1119 | li, strlen(reg[YDreg]), what_reg()); | 1130 | li, strlen(reg[YDreg]), what_reg()); |
1120 | #endif | 1131 | #endif |
1121 | } else { | 1132 | } else { |
1122 | // cmd unknown | 1133 | // cmd unknown |
1123 | ni(cmd); | 1134 | not_implemented(cmd); |
1124 | } | 1135 | } |
1125 | vc1: | 1136 | vc1: |
1126 | dot = bound_dot(dot); // make sure "dot" is valid | 1137 | dot = bound_dot(dot); // make sure "dot" is valid |
1127 | return; | 1138 | return; |
1128 | #if ENABLE_FEATURE_VI_SEARCH | 1139 | #if ENABLE_FEATURE_VI_SEARCH |
1129 | colon_s_fail: | 1140 | colon_s_fail: |
1130 | psb(":s expression missing delimiters"); | 1141 | status_line(":s expression missing delimiters"); |
1131 | #endif | 1142 | #endif |
1132 | } | 1143 | } |
1133 | 1144 | ||
@@ -1140,8 +1151,8 @@ static void Hit_Return(void) | |||
1140 | standout_start(); // start reverse video | 1151 | standout_start(); // start reverse video |
1141 | write1("[Hit return to continue]"); | 1152 | write1("[Hit return to continue]"); |
1142 | standout_end(); // end reverse video | 1153 | standout_end(); // end reverse video |
1143 | while ((c = get_one_char()) != '\n' && c != '\r') /*do nothing */ | 1154 | while ((c = get_one_char()) != '\n' && c != '\r') |
1144 | ; | 1155 | continue; |
1145 | redraw(TRUE); // force redraw all | 1156 | redraw(TRUE); // force redraw all |
1146 | } | 1157 | } |
1147 | 1158 | ||
@@ -1199,7 +1210,7 @@ static void sync_cursor(char * d, int *row, int *col) | |||
1199 | // find out what col "d" is on | 1210 | // find out what col "d" is on |
1200 | co = 0; | 1211 | co = 0; |
1201 | do { // drive "co" to correct column | 1212 | do { // drive "co" to correct column |
1202 | if (*tp == '\n' || *tp == '\0') | 1213 | if (*tp == '\n') //vda || *tp == '\0') |
1203 | break; | 1214 | break; |
1204 | if (*tp == '\t') { | 1215 | if (*tp == '\t') { |
1205 | if (d == tp && cmd_mode) { /* handle tabs like real vi */ | 1216 | if (d == tp && cmd_mode) { /* handle tabs like real vi */ |
@@ -1350,14 +1361,14 @@ static void dot_end(void) | |||
1350 | dot = end_line(dot); // return pointer to last char cur line | 1361 | dot = end_line(dot); // return pointer to last char cur line |
1351 | } | 1362 | } |
1352 | 1363 | ||
1353 | static char *move_to_col(char * p, int l) | 1364 | static char *move_to_col(char *p, int l) |
1354 | { | 1365 | { |
1355 | int co; | 1366 | int co; |
1356 | 1367 | ||
1357 | p = begin_line(p); | 1368 | p = begin_line(p); |
1358 | co = 0; | 1369 | co = 0; |
1359 | do { | 1370 | do { |
1360 | if (*p == '\n' || *p == '\0') | 1371 | if (*p == '\n') //vda || *p == '\0') |
1361 | break; | 1372 | break; |
1362 | if (*p == '\t') { | 1373 | if (*p == '\t') { |
1363 | co = next_tabstop(co); | 1374 | co = next_tabstop(co); |
@@ -1527,7 +1538,7 @@ static char *char_search(char * p, const char * pat, int dir, int range) | |||
1527 | q = re_compile_pattern(pat, strlen(pat), &preg); | 1538 | q = re_compile_pattern(pat, strlen(pat), &preg); |
1528 | if (q != 0) { | 1539 | if (q != 0) { |
1529 | // The pattern was not compiled | 1540 | // The pattern was not compiled |
1530 | psbs("bad search pattern: \"%s\": %s", pat, q); | 1541 | status_line_bold("bad search pattern: \"%s\": %s", pat, q); |
1531 | i = 0; // return p if pattern not compiled | 1542 | i = 0; // return p if pattern not compiled |
1532 | goto cs1; | 1543 | goto cs1; |
1533 | } | 1544 | } |
@@ -1811,7 +1822,7 @@ static char *text_hole_make(char * p, int size) // at "p", make a 'size' byte ho | |||
1811 | cnt = end - src; // the rest of buffer | 1822 | cnt = end - src; // the rest of buffer |
1812 | if ( ((end + size) >= (text + text_size)) // TODO: realloc here | 1823 | if ( ((end + size) >= (text + text_size)) // TODO: realloc here |
1813 | || memmove(dest, src, cnt) != dest) { | 1824 | || memmove(dest, src, cnt) != dest) { |
1814 | psbs("can't create room for new characters"); | 1825 | status_line_bold("can't create room for new characters"); |
1815 | p = NULL; | 1826 | p = NULL; |
1816 | goto thm0; | 1827 | goto thm0; |
1817 | } | 1828 | } |
@@ -1845,7 +1856,7 @@ static char *text_hole_delete(char * p, char * q) // delete "p" thru "q", inclus | |||
1845 | if (src >= end) | 1856 | if (src >= end) |
1846 | goto thd_atend; // just delete the end of the buffer | 1857 | goto thd_atend; // just delete the end of the buffer |
1847 | if (memmove(dest, src, cnt) != dest) { | 1858 | if (memmove(dest, src, cnt) != dest) { |
1848 | psbs("can't delete the character"); | 1859 | status_line_bold("can't delete the character"); |
1849 | } | 1860 | } |
1850 | thd_atend: | 1861 | thd_atend: |
1851 | end = end - hole_size; // adjust the new END | 1862 | end = end - hole_size; // adjust the new END |
@@ -1928,52 +1939,19 @@ static void show_help(void) | |||
1928 | ); | 1939 | ); |
1929 | } | 1940 | } |
1930 | 1941 | ||
1931 | static void print_literal(char * buf, const char * s) // copy s to buf, convert unprintable | ||
1932 | { | ||
1933 | unsigned char c; | ||
1934 | char b[2]; | ||
1935 | |||
1936 | b[1] = '\0'; | ||
1937 | buf[0] = '\0'; | ||
1938 | if (!s[0]) | ||
1939 | s = "(NULL)"; | ||
1940 | for (; *s; s++) { | ||
1941 | int c_is_no_print; | ||
1942 | |||
1943 | c = *s; | ||
1944 | c_is_no_print = (c & 0x80) && !Isprint(c); | ||
1945 | if (c_is_no_print) { | ||
1946 | strcat(buf, SOn); | ||
1947 | c = '.'; | ||
1948 | } | ||
1949 | if (c < ' ' || c == 127) { | ||
1950 | strcat(buf, "^"); | ||
1951 | if (c == 127) | ||
1952 | c = '?'; | ||
1953 | else | ||
1954 | c += '@'; | ||
1955 | } | ||
1956 | b[0] = c; | ||
1957 | strcat(buf, b); | ||
1958 | if (c_is_no_print) | ||
1959 | strcat(buf, SOs); | ||
1960 | if (*s == '\n') | ||
1961 | strcat(buf, "$"); | ||
1962 | } | ||
1963 | } | ||
1964 | |||
1965 | #if ENABLE_FEATURE_VI_DOT_CMD | 1942 | #if ENABLE_FEATURE_VI_DOT_CMD |
1966 | static void start_new_cmd_q(char c) | 1943 | static void start_new_cmd_q(char c) |
1967 | { | 1944 | { |
1968 | // release old cmd | ||
1969 | free(last_modifying_cmd); | ||
1970 | // get buffer for new cmd | 1945 | // get buffer for new cmd |
1971 | last_modifying_cmd = xzalloc(MAX_LINELEN); | 1946 | if (!last_modifying_cmd) |
1947 | last_modifying_cmd = xzalloc(MAX_INPUT_LEN); | ||
1972 | // if there is a current cmd count put it in the buffer first | 1948 | // if there is a current cmd count put it in the buffer first |
1973 | if (cmdcnt > 0) | 1949 | if (cmdcnt > 0) |
1974 | sprintf(last_modifying_cmd, "%d%c", cmdcnt, c); | 1950 | sprintf(last_modifying_cmd, "%d%c", cmdcnt, c); |
1975 | else // just save char c onto queue | 1951 | else { // just save char c onto queue |
1976 | last_modifying_cmd[0] = c; | 1952 | last_modifying_cmd[0] = c; |
1953 | last_modifying_cmd[1] = '\0'; | ||
1954 | } | ||
1977 | adding2q = 1; | 1955 | adding2q = 1; |
1978 | } | 1956 | } |
1979 | 1957 | ||
@@ -2001,7 +1979,7 @@ static char *string_insert(char * p, char * s) // insert the string at 'p' | |||
2001 | cnt++; | 1979 | cnt++; |
2002 | } | 1980 | } |
2003 | #if ENABLE_FEATURE_VI_YANKMARK | 1981 | #if ENABLE_FEATURE_VI_YANKMARK |
2004 | psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); | 1982 | status_line("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); |
2005 | #endif | 1983 | #endif |
2006 | } | 1984 | } |
2007 | return p; | 1985 | return p; |
@@ -2104,8 +2082,11 @@ static void cookmode(void) | |||
2104 | static void winch_sig(int sig ATTRIBUTE_UNUSED) | 2082 | static void winch_sig(int sig ATTRIBUTE_UNUSED) |
2105 | { | 2083 | { |
2106 | signal(SIGWINCH, winch_sig); | 2084 | signal(SIGWINCH, winch_sig); |
2107 | if (ENABLE_FEATURE_VI_WIN_RESIZE) | 2085 | if (ENABLE_FEATURE_VI_WIN_RESIZE) { |
2108 | get_terminal_width_height(0, &columns, &rows); | 2086 | get_terminal_width_height(0, &columns, &rows); |
2087 | if (rows > MAX_SCR_ROWS) rows = MAX_SCR_ROWS; | ||
2088 | if (columns > MAX_SCR_COLS) columns = MAX_SCR_COLS; | ||
2089 | } | ||
2109 | new_screen(rows, columns); // get memory for virtual screen | 2090 | new_screen(rows, columns); // get memory for virtual screen |
2110 | redraw(TRUE); // re-draw the screen | 2091 | redraw(TRUE); // re-draw the screen |
2111 | } | 2092 | } |
@@ -2165,40 +2146,41 @@ static char readit(void) // read (maybe cursor) key from stdin | |||
2165 | }; | 2146 | }; |
2166 | 2147 | ||
2167 | static const struct esc_cmds esccmds[] = { | 2148 | static const struct esc_cmds esccmds[] = { |
2168 | {"OA", VI_K_UP}, // cursor key Up | 2149 | {"OA" , VI_K_UP }, // cursor key Up |
2169 | {"OB", VI_K_DOWN}, // cursor key Down | 2150 | {"OB" , VI_K_DOWN }, // cursor key Down |
2170 | {"OC", VI_K_RIGHT}, // Cursor Key Right | 2151 | {"OC" , VI_K_RIGHT }, // Cursor Key Right |
2171 | {"OD", VI_K_LEFT}, // cursor key Left | 2152 | {"OD" , VI_K_LEFT }, // cursor key Left |
2172 | {"OH", VI_K_HOME}, // Cursor Key Home | 2153 | {"OH" , VI_K_HOME }, // Cursor Key Home |
2173 | {"OF", VI_K_END}, // Cursor Key End | 2154 | {"OF" , VI_K_END }, // Cursor Key End |
2174 | {"[A", VI_K_UP}, // cursor key Up | 2155 | {"[A" , VI_K_UP }, // cursor key Up |
2175 | {"[B", VI_K_DOWN}, // cursor key Down | 2156 | {"[B" , VI_K_DOWN }, // cursor key Down |
2176 | {"[C", VI_K_RIGHT}, // Cursor Key Right | 2157 | {"[C" , VI_K_RIGHT }, // Cursor Key Right |
2177 | {"[D", VI_K_LEFT}, // cursor key Left | 2158 | {"[D" , VI_K_LEFT }, // cursor key Left |
2178 | {"[H", VI_K_HOME}, // Cursor Key Home | 2159 | {"[H" , VI_K_HOME }, // Cursor Key Home |
2179 | {"[F", VI_K_END}, // Cursor Key End | 2160 | {"[F" , VI_K_END }, // Cursor Key End |
2180 | {"[1~", VI_K_HOME}, // Cursor Key Home | 2161 | {"[1~" , VI_K_HOME }, // Cursor Key Home |
2181 | {"[2~", VI_K_INSERT}, // Cursor Key Insert | 2162 | {"[2~" , VI_K_INSERT }, // Cursor Key Insert |
2182 | {"[4~", VI_K_END}, // Cursor Key End | 2163 | {"[3~" , VI_K_DELETE }, // Cursor Key Delete |
2183 | {"[5~", VI_K_PAGEUP}, // Cursor Key Page Up | 2164 | {"[4~" , VI_K_END }, // Cursor Key End |
2184 | {"[6~", VI_K_PAGEDOWN},// Cursor Key Page Down | 2165 | {"[5~" , VI_K_PAGEUP }, // Cursor Key Page Up |
2185 | {"OP", VI_K_FUN1}, // Function Key F1 | 2166 | {"[6~" , VI_K_PAGEDOWN}, // Cursor Key Page Down |
2186 | {"OQ", VI_K_FUN2}, // Function Key F2 | 2167 | {"OP" , VI_K_FUN1 }, // Function Key F1 |
2187 | {"OR", VI_K_FUN3}, // Function Key F3 | 2168 | {"OQ" , VI_K_FUN2 }, // Function Key F2 |
2188 | {"OS", VI_K_FUN4}, // Function Key F4 | 2169 | {"OR" , VI_K_FUN3 }, // Function Key F3 |
2170 | {"OS" , VI_K_FUN4 }, // Function Key F4 | ||
2189 | // careful: these have no terminating NUL! | 2171 | // careful: these have no terminating NUL! |
2190 | {"[15~", VI_K_FUN5}, // Function Key F5 | 2172 | {"[11~", VI_K_FUN1 }, // Function Key F1 |
2191 | {"[17~", VI_K_FUN6}, // Function Key F6 | 2173 | {"[12~", VI_K_FUN2 }, // Function Key F2 |
2192 | {"[18~", VI_K_FUN7}, // Function Key F7 | 2174 | {"[13~", VI_K_FUN3 }, // Function Key F3 |
2193 | {"[19~", VI_K_FUN8}, // Function Key F8 | 2175 | {"[14~", VI_K_FUN4 }, // Function Key F4 |
2194 | {"[20~", VI_K_FUN9}, // Function Key F9 | 2176 | {"[15~", VI_K_FUN5 }, // Function Key F5 |
2195 | {"[21~", VI_K_FUN10}, // Function Key F10 | 2177 | {"[17~", VI_K_FUN6 }, // Function Key F6 |
2196 | {"[23~", VI_K_FUN11}, // Function Key F11 | 2178 | {"[18~", VI_K_FUN7 }, // Function Key F7 |
2197 | {"[24~", VI_K_FUN12}, // Function Key F12 | 2179 | {"[19~", VI_K_FUN8 }, // Function Key F8 |
2198 | {"[11~", VI_K_FUN1}, // Function Key F1 | 2180 | {"[20~", VI_K_FUN9 }, // Function Key F9 |
2199 | {"[12~", VI_K_FUN2}, // Function Key F2 | 2181 | {"[21~", VI_K_FUN10 }, // Function Key F10 |
2200 | {"[13~", VI_K_FUN3}, // Function Key F3 | 2182 | {"[23~", VI_K_FUN11 }, // Function Key F11 |
2201 | {"[14~", VI_K_FUN4}, // Function Key F4 | 2183 | {"[24~", VI_K_FUN12 }, // Function Key F12 |
2202 | }; | 2184 | }; |
2203 | enum { ESCCMDS_COUNT = ARRAY_SIZE(esccmds) }; | 2185 | enum { ESCCMDS_COUNT = ARRAY_SIZE(esccmds) }; |
2204 | 2186 | ||
@@ -2208,11 +2190,11 @@ static char readit(void) // read (maybe cursor) key from stdin | |||
2208 | // get input from User- are there already input chars in Q? | 2190 | // get input from User- are there already input chars in Q? |
2209 | if (n <= 0) { | 2191 | if (n <= 0) { |
2210 | // the Q is empty, wait for a typed char | 2192 | // the Q is empty, wait for a typed char |
2211 | n = safe_read(0, readbuffer, MAX_LINELEN - 1); | 2193 | n = safe_read(0, readbuffer, sizeof(readbuffer)); |
2212 | if (n < 0) { | 2194 | if (n < 0) { |
2213 | if (errno == EBADF || errno == EFAULT || errno == EINVAL | 2195 | if (errno == EBADF || errno == EFAULT || errno == EINVAL |
2214 | || errno == EIO) | 2196 | || errno == EIO) |
2215 | editing = 0; | 2197 | editing = 0; // want to exit |
2216 | errno = 0; | 2198 | errno = 0; |
2217 | } | 2199 | } |
2218 | if (n <= 0) | 2200 | if (n <= 0) |
@@ -2225,10 +2207,11 @@ static char readit(void) // read (maybe cursor) key from stdin | |||
2225 | struct pollfd pfd[1]; | 2207 | struct pollfd pfd[1]; |
2226 | pfd[0].fd = 0; | 2208 | pfd[0].fd = 0; |
2227 | pfd[0].events = POLLIN; | 2209 | pfd[0].events = POLLIN; |
2228 | // keep reading while there are input chars and room in buffer | 2210 | // keep reading while there are input chars, and room in buffer |
2229 | while (safe_poll(pfd, 1, 0) > 0 && n <= (MAX_LINELEN - 5)) { | 2211 | // for a complete ESC sequence (assuming 8 chars is enough) |
2212 | while (safe_poll(pfd, 1, 0) > 0 && n <= (sizeof(readbuffer) - 8)) { | ||
2230 | // read the rest of the ESC string | 2213 | // read the rest of the ESC string |
2231 | int r = safe_read(0, readbuffer + n, MAX_LINELEN - n); | 2214 | int r = safe_read(0, readbuffer + n, sizeof(readbuffer) - n); |
2232 | if (r > 0) | 2215 | if (r > 0) |
2233 | n += r; | 2216 | n += r; |
2234 | } | 2217 | } |
@@ -2242,27 +2225,21 @@ static char readit(void) // read (maybe cursor) key from stdin | |||
2242 | 2225 | ||
2243 | for (eindex = esccmds; eindex < &esccmds[ESCCMDS_COUNT]; eindex++) { | 2226 | for (eindex = esccmds; eindex < &esccmds[ESCCMDS_COUNT]; eindex++) { |
2244 | int cnt = strnlen(eindex->seq, 4); | 2227 | int cnt = strnlen(eindex->seq, 4); |
2245 | |||
2246 | if (n <= cnt) | 2228 | if (n <= cnt) |
2247 | continue; | 2229 | continue; |
2248 | if (strncmp(eindex->seq, readbuffer + 1, cnt)) | 2230 | if (strncmp(eindex->seq, readbuffer + 1, cnt) != 0) |
2249 | continue; | 2231 | continue; |
2250 | // is a Cursor key- put derived value back into Q | 2232 | c = eindex->val; // magic char value |
2251 | c = eindex->val; | 2233 | n = cnt + 1; // squeeze out the ESC sequence |
2252 | // for squeeze out the ESC sequence | 2234 | goto found; |
2253 | n = cnt + 1; | ||
2254 | break; | ||
2255 | } | 2235 | } |
2256 | if (eindex == &esccmds[ESCCMDS_COUNT]) { | 2236 | // defined ESC sequence not found |
2257 | /* defined ESC sequence not found, set only one ESC */ | ||
2258 | n = 1; | ||
2259 | } | ||
2260 | } else { | ||
2261 | n = 1; | ||
2262 | } | 2237 | } |
2238 | n = 1; | ||
2239 | found: | ||
2263 | // remove key sequence from Q | 2240 | // remove key sequence from Q |
2264 | chars_to_parse -= n; | 2241 | chars_to_parse -= n; |
2265 | memmove(readbuffer, readbuffer + n, MAX_LINELEN - n); | 2242 | memmove(readbuffer, readbuffer + n, sizeof(readbuffer) - n); |
2266 | alarm(3); // we are done waiting for input, turn alarm ON | 2243 | alarm(3); // we are done waiting for input, turn alarm ON |
2267 | return c; | 2244 | return c; |
2268 | } | 2245 | } |
@@ -2297,8 +2274,8 @@ static char get_one_char(void) | |||
2297 | c = readit(); // get the users input | 2274 | c = readit(); // get the users input |
2298 | if (last_modifying_cmd != NULL) { | 2275 | if (last_modifying_cmd != NULL) { |
2299 | int len = strlen(last_modifying_cmd); | 2276 | int len = strlen(last_modifying_cmd); |
2300 | if (len >= MAX_LINELEN - 1) { | 2277 | if (len >= MAX_INPUT_LEN - 1) { |
2301 | psbs("last_modifying_cmd overrun"); | 2278 | status_line_bold("last_modifying_cmd overrun"); |
2302 | } else { | 2279 | } else { |
2303 | // add new char to q | 2280 | // add new char to q |
2304 | last_modifying_cmd[len] = c; | 2281 | last_modifying_cmd[len] = c; |
@@ -2311,14 +2288,15 @@ static char get_one_char(void) | |||
2311 | return c; | 2288 | return c; |
2312 | } | 2289 | } |
2313 | 2290 | ||
2314 | static char *get_input_line(const char * prompt) // get input line- use "status line" | 2291 | // Get input line (uses "status line" area) |
2292 | static char *get_input_line(const char *prompt) | ||
2315 | { | 2293 | { |
2316 | static char *buf; // [MAX_LINELEN] | 2294 | static char *buf; // [MAX_INPUT_LEN] |
2317 | 2295 | ||
2318 | char c; | 2296 | char c; |
2319 | int i; | 2297 | int i; |
2320 | 2298 | ||
2321 | if (!buf) buf = xmalloc(MAX_LINELEN); | 2299 | if (!buf) buf = xmalloc(MAX_INPUT_LEN); |
2322 | 2300 | ||
2323 | strcpy(buf, prompt); | 2301 | strcpy(buf, prompt); |
2324 | last_status_cksum = 0; // force status update | 2302 | last_status_cksum = 0; // force status update |
@@ -2327,24 +2305,20 @@ static char *get_input_line(const char * prompt) // get input line- use "status | |||
2327 | write1(prompt); // write out the :, /, or ? prompt | 2305 | write1(prompt); // write out the :, /, or ? prompt |
2328 | 2306 | ||
2329 | i = strlen(buf); | 2307 | i = strlen(buf); |
2330 | while (i < MAX_LINELEN) { | 2308 | while (i < MAX_INPUT_LEN) { |
2331 | c = get_one_char(); // read user input | 2309 | c = get_one_char(); |
2332 | if (c == '\n' || c == '\r' || c == 27) | 2310 | if (c == '\n' || c == '\r' || c == 27) |
2333 | break; // is this end of input | 2311 | break; // this is end of input |
2334 | if (c == erase_char || c == 8 || c == 127) { | 2312 | if (c == erase_char || c == 8 || c == 127) { |
2335 | // user wants to erase prev char | 2313 | // user wants to erase prev char |
2336 | i--; // backup to prev char | 2314 | buf[--i] = '\0'; |
2337 | buf[i] = '\0'; // erase the char | 2315 | write1("\b \b"); // erase char on screen |
2338 | //buf[i + 1] = '\0'; // null terminate buffer | 2316 | if (i <= 0) // user backs up before b-o-l, exit |
2339 | write1("\b \b"); // erase char on screen | ||
2340 | if (i <= 0) { // user backs up before b-o-l, exit | ||
2341 | break; | 2317 | break; |
2342 | } | ||
2343 | } else { | 2318 | } else { |
2344 | buf[i] = c; // save char in buffer | 2319 | buf[i] = c; |
2345 | buf[i + 1] = '\0'; // make sure buffer is null terminated | 2320 | buf[++i] = '\0'; |
2346 | bb_putchar(c); // echo the char back to user | 2321 | bb_putchar(c); |
2347 | i++; | ||
2348 | } | 2322 | } |
2349 | } | 2323 | } |
2350 | refresh(FALSE); | 2324 | refresh(FALSE); |
@@ -2371,30 +2345,30 @@ static int file_insert(const char * fn, char *p | |||
2371 | 2345 | ||
2372 | /* Validate file */ | 2346 | /* Validate file */ |
2373 | if (stat(fn, &statbuf) < 0) { | 2347 | if (stat(fn, &statbuf) < 0) { |
2374 | psbs("\"%s\" %s", fn, strerror(errno)); | 2348 | status_line_bold("\"%s\" %s", fn, strerror(errno)); |
2375 | goto fi0; | 2349 | goto fi0; |
2376 | } | 2350 | } |
2377 | if ((statbuf.st_mode & S_IFREG) == 0) { | 2351 | if ((statbuf.st_mode & S_IFREG) == 0) { |
2378 | // This is not a regular file | 2352 | // This is not a regular file |
2379 | psbs("\"%s\" Not a regular file", fn); | 2353 | status_line_bold("\"%s\" Not a regular file", fn); |
2380 | goto fi0; | 2354 | goto fi0; |
2381 | } | 2355 | } |
2382 | /* // this check is done by open() | 2356 | /* // this check is done by open() |
2383 | if ((statbuf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) { | 2357 | if ((statbuf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) { |
2384 | // dont have any read permissions | 2358 | // dont have any read permissions |
2385 | psbs("\"%s\" Not readable", fn); | 2359 | status_line_bold("\"%s\" Not readable", fn); |
2386 | goto fi0; | 2360 | goto fi0; |
2387 | } | 2361 | } |
2388 | */ | 2362 | */ |
2389 | if (p < text || p > end) { | 2363 | if (p < text || p > end) { |
2390 | psbs("Trying to insert file outside of memory"); | 2364 | status_line_bold("Trying to insert file outside of memory"); |
2391 | goto fi0; | 2365 | goto fi0; |
2392 | } | 2366 | } |
2393 | 2367 | ||
2394 | // read file to buffer | 2368 | // read file to buffer |
2395 | fd = open(fn, O_RDONLY); | 2369 | fd = open(fn, O_RDONLY); |
2396 | if (fd < 0) { | 2370 | if (fd < 0) { |
2397 | psbs("\"%s\" %s", fn, strerror(errno)); | 2371 | status_line_bold("\"%s\" %s", fn, strerror(errno)); |
2398 | goto fi0; | 2372 | goto fi0; |
2399 | } | 2373 | } |
2400 | size = statbuf.st_size; | 2374 | size = statbuf.st_size; |
@@ -2403,12 +2377,12 @@ static int file_insert(const char * fn, char *p | |||
2403 | goto fi0; | 2377 | goto fi0; |
2404 | cnt = safe_read(fd, p, size); | 2378 | cnt = safe_read(fd, p, size); |
2405 | if (cnt < 0) { | 2379 | if (cnt < 0) { |
2406 | psbs("\"%s\" %s", fn, strerror(errno)); | 2380 | status_line_bold("\"%s\" %s", fn, strerror(errno)); |
2407 | p = text_hole_delete(p, p + size - 1); // un-do buffer insert | 2381 | p = text_hole_delete(p, p + size - 1); // un-do buffer insert |
2408 | } else if (cnt < size) { | 2382 | } else if (cnt < size) { |
2409 | // There was a partial read, shrink unused space text[] | 2383 | // There was a partial read, shrink unused space text[] |
2410 | p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert | 2384 | p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert |
2411 | psbs("cannot read all of file \"%s\"", fn); | 2385 | status_line_bold("cannot read all of file \"%s\"", fn); |
2412 | } | 2386 | } |
2413 | if (cnt >= size) | 2387 | if (cnt >= size) |
2414 | file_modified++; | 2388 | file_modified++; |
@@ -2434,7 +2408,7 @@ static int file_write(char * fn, char * first, char * last) | |||
2434 | int fd, cnt, charcnt; | 2408 | int fd, cnt, charcnt; |
2435 | 2409 | ||
2436 | if (fn == 0) { | 2410 | if (fn == 0) { |
2437 | psbs("No current filename"); | 2411 | status_line_bold("No current filename"); |
2438 | return -2; | 2412 | return -2; |
2439 | } | 2413 | } |
2440 | charcnt = 0; | 2414 | charcnt = 0; |
@@ -2467,7 +2441,7 @@ static int file_write(char * fn, char * first, char * last) | |||
2467 | //----- Move the cursor to row x col (count from 0, not 1) ------- | 2441 | //----- Move the cursor to row x col (count from 0, not 1) ------- |
2468 | static void place_cursor(int row, int col, int optimize) | 2442 | static void place_cursor(int row, int col, int optimize) |
2469 | { | 2443 | { |
2470 | char cm1[32]; | 2444 | char cm1[sizeof(CMrc) + sizeof(int)*3 * 2]; |
2471 | char *cm; | 2445 | char *cm; |
2472 | 2446 | ||
2473 | if (row < 0) row = 0; | 2447 | if (row < 0) row = 0; |
@@ -2481,9 +2455,18 @@ static void place_cursor(int row, int col, int optimize) | |||
2481 | 2455 | ||
2482 | #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR | 2456 | #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR |
2483 | if (optimize && col < 16) { | 2457 | if (optimize && col < 16) { |
2484 | char cm2[MAX_LINELEN]; // better size estimate? | 2458 | enum { |
2459 | SZ_UP = sizeof(CMup), | ||
2460 | SZ_DN = sizeof(CMdown), | ||
2461 | SEQ_SIZE = SZ_UP > SZ_DN ? SZ_UP : SZ_DN, | ||
2462 | }; | ||
2463 | char cm2[SEQ_SIZE * 5 + 32]; // bigger than worst case size | ||
2485 | char *screenp; | 2464 | char *screenp; |
2486 | int Rrow = last_row; | 2465 | int Rrow = last_row; |
2466 | int diff = Rrow - row; | ||
2467 | |||
2468 | if (diff < -5 || diff > 5) | ||
2469 | goto skip; | ||
2487 | 2470 | ||
2488 | //----- find the minimum # of chars to move cursor ------------- | 2471 | //----- find the minimum # of chars to move cursor ------------- |
2489 | //----- 2. Try moving with discreet chars (Newline, [back]space, ...) | 2472 | //----- 2. Try moving with discreet chars (Newline, [back]space, ...) |
@@ -2511,9 +2494,11 @@ static void place_cursor(int row, int col, int optimize) | |||
2511 | if (strlen(cm2) < strlen(cm)) { | 2494 | if (strlen(cm2) < strlen(cm)) { |
2512 | cm = cm2; | 2495 | cm = cm2; |
2513 | } | 2496 | } |
2497 | skip: ; | ||
2514 | } | 2498 | } |
2515 | #endif /* FEATURE_VI_OPTIMIZE_CURSOR */ | 2499 | #endif /* FEATURE_VI_OPTIMIZE_CURSOR */ |
2516 | write1(cm); | 2500 | write1(cm); |
2501 | last_row = row; | ||
2517 | } | 2502 | } |
2518 | 2503 | ||
2519 | //----- Erase from cursor to end of line ----------------------- | 2504 | //----- Erase from cursor to end of line ----------------------- |
@@ -2592,7 +2577,7 @@ static void show_status_line(void) | |||
2592 | cksum = bufsum(status_buffer, cnt); | 2577 | cksum = bufsum(status_buffer, cnt); |
2593 | } | 2578 | } |
2594 | if (have_status_msg || ((cnt > 0 && last_status_cksum != cksum))) { | 2579 | if (have_status_msg || ((cnt > 0 && last_status_cksum != cksum))) { |
2595 | last_status_cksum= cksum; // remember if we have seen this line | 2580 | last_status_cksum = cksum; // remember if we have seen this line |
2596 | place_cursor(rows - 1, 0, FALSE); // put cursor on status line | 2581 | place_cursor(rows - 1, 0, FALSE); // put cursor on status line |
2597 | write1(status_buffer); | 2582 | write1(status_buffer); |
2598 | clear_to_eol(); | 2583 | clear_to_eol(); |
@@ -2611,13 +2596,13 @@ static void show_status_line(void) | |||
2611 | 2596 | ||
2612 | //----- format the status buffer, the bottom line of screen ------ | 2597 | //----- format the status buffer, the bottom line of screen ------ |
2613 | // format status buffer, with STANDOUT mode | 2598 | // format status buffer, with STANDOUT mode |
2614 | static void psbs(const char *format, ...) | 2599 | static void status_line_bold(const char *format, ...) |
2615 | { | 2600 | { |
2616 | va_list args; | 2601 | va_list args; |
2617 | 2602 | ||
2618 | va_start(args, format); | 2603 | va_start(args, format); |
2619 | strcpy(status_buffer, SOs); // Terminal standout mode on | 2604 | strcpy(status_buffer, SOs); // Terminal standout mode on |
2620 | vsprintf(status_buffer + strlen(status_buffer), format, args); | 2605 | vsprintf(status_buffer + sizeof(SOs)-1, format, args); |
2621 | strcat(status_buffer, SOn); // Terminal standout mode off | 2606 | strcat(status_buffer, SOn); // Terminal standout mode off |
2622 | va_end(args); | 2607 | va_end(args); |
2623 | 2608 | ||
@@ -2625,7 +2610,7 @@ static void psbs(const char *format, ...) | |||
2625 | } | 2610 | } |
2626 | 2611 | ||
2627 | // format status buffer | 2612 | // format status buffer |
2628 | static void psb(const char *format, ...) | 2613 | static void status_line(const char *format, ...) |
2629 | { | 2614 | { |
2630 | va_list args; | 2615 | va_list args; |
2631 | 2616 | ||
@@ -2636,15 +2621,53 @@ static void psb(const char *format, ...) | |||
2636 | have_status_msg = 1; | 2621 | have_status_msg = 1; |
2637 | } | 2622 | } |
2638 | 2623 | ||
2639 | static void ni(const char * s) // display messages | 2624 | // copy s to buf, convert unprintable |
2625 | static void print_literal(char *buf, const char *s) | ||
2640 | { | 2626 | { |
2641 | char buf[MAX_LINELEN]; | 2627 | unsigned char c; |
2628 | char b[2]; | ||
2629 | |||
2630 | b[1] = '\0'; | ||
2631 | buf[0] = '\0'; | ||
2632 | if (!s[0]) | ||
2633 | s = "(NULL)"; | ||
2634 | for (; *s; s++) { | ||
2635 | int c_is_no_print; | ||
2636 | |||
2637 | c = *s; | ||
2638 | c_is_no_print = (c & 0x80) && !Isprint(c); | ||
2639 | if (c_is_no_print) { | ||
2640 | strcat(buf, SOn); | ||
2641 | c = '.'; | ||
2642 | } | ||
2643 | if (c < ' ' || c == 127) { | ||
2644 | strcat(buf, "^"); | ||
2645 | if (c == 127) | ||
2646 | c = '?'; | ||
2647 | else | ||
2648 | c += '@'; | ||
2649 | } | ||
2650 | b[0] = c; | ||
2651 | strcat(buf, b); | ||
2652 | if (c_is_no_print) | ||
2653 | strcat(buf, SOs); | ||
2654 | if (*s == '\n') | ||
2655 | strcat(buf, "$"); | ||
2656 | if (strlen(buf) > MAX_INPUT_LEN - 10) // paranoia | ||
2657 | break; | ||
2658 | } | ||
2659 | } | ||
2660 | |||
2661 | static void not_implemented(const char *s) | ||
2662 | { | ||
2663 | char buf[MAX_INPUT_LEN]; | ||
2642 | 2664 | ||
2643 | print_literal(buf, s); | 2665 | print_literal(buf, s); |
2644 | psbs("\'%s\' is not implemented", buf); | 2666 | status_line_bold("\'%s\' is not implemented", buf); |
2645 | } | 2667 | } |
2646 | 2668 | ||
2647 | static int format_edit_status(void) // show file status on status line | 2669 | // show file status on status line |
2670 | static int format_edit_status(void) | ||
2648 | { | 2671 | { |
2649 | static int tot; | 2672 | static int tot; |
2650 | static const char cmd_mode_indicator[] ALIGN1 = "-IR-"; | 2673 | static const char cmd_mode_indicator[] ALIGN1 = "-IR-"; |
@@ -2714,67 +2737,57 @@ static void redraw(int full_screen) | |||
2714 | //----- Format a text[] line into a buffer --------------------- | 2737 | //----- Format a text[] line into a buffer --------------------- |
2715 | // Returns number of leading chars which should be ignored | 2738 | // Returns number of leading chars which should be ignored |
2716 | // (return value is always <= offset) | 2739 | // (return value is always <= offset) |
2717 | static int format_line(char *dest, char *src, int li) | 2740 | static char* format_line(char *src, int li) |
2718 | { | 2741 | { |
2719 | char c; | 2742 | char c; |
2720 | int co; | 2743 | int co; |
2721 | int ofs = offset; | 2744 | int ofs = offset; |
2745 | char *dest = scr_out_buf; // [MAX_SCR_COLS + MAX_TABSTOP * 2] | ||
2722 | 2746 | ||
2723 | memset(dest, ' ', MAX_SCR_COLS); | 2747 | memset(dest, ' ', MAX_SCR_COLS + MAX_TABSTOP * 2); |
2724 | for (co = 0; co < MAX_SCR_COLS; co++) { | 2748 | |
2725 | c = ' '; // assume blank | 2749 | c = '~'; // char in col 0 in non-existent lines is '~' |
2726 | if (li > 0 && co == 0) { | 2750 | for (co = 0; co < MAX_SCR_COLS + MAX_TABSTOP; co++) { |
2727 | c = '~'; // not first line, assume Tilde | ||
2728 | } | ||
2729 | // are there chars in text[] and have we gone past the end | 2751 | // are there chars in text[] and have we gone past the end |
2730 | if (text < end && src < end) { | 2752 | if (src < end) { |
2731 | c = *src++; | 2753 | c = *src++; |
2732 | |||
2733 | if (c == '\n') | 2754 | if (c == '\n') |
2734 | break; | 2755 | break; |
2735 | if ((c & 0x80) && !Isprint(c)) { | 2756 | if ((c & 0x80) && !Isprint(c)) { |
2736 | c = '.'; | 2757 | c = '.'; |
2737 | } | 2758 | } |
2738 | if ((unsigned char)(c) < ' ' || c == 0x7f) { | 2759 | if ((unsigned char)c < ' ' || c == 0x7f) { |
2739 | if (c == '\t') { | 2760 | if (c == '\t') { |
2740 | c = ' '; | 2761 | c = ' '; |
2741 | // co % 8 != 7 | 2762 | // co % 8 != 7 |
2742 | while ((co % tabstop) != (tabstop - 1)) { | 2763 | while ((co % tabstop) != (tabstop - 1)) { |
2743 | dest[co++] = c; | 2764 | dest[co++] = c; |
2744 | if (co >= MAX_SCR_COLS) | ||
2745 | goto ret; | ||
2746 | } | 2765 | } |
2747 | } else { | 2766 | } else { |
2748 | dest[co++] = '^'; | 2767 | dest[co++] = '^'; |
2749 | if (co >= MAX_SCR_COLS) | ||
2750 | goto ret; | ||
2751 | if (c == 0x7f) | 2768 | if (c == 0x7f) |
2752 | c = '?'; | 2769 | c = '?'; |
2753 | else | 2770 | else |
2754 | c += '@'; // make it visible | 2771 | c += '@'; // Ctrl-X -> 'X' |
2755 | } | 2772 | } |
2756 | } | 2773 | } |
2757 | } | 2774 | } |
2758 | // the co++ is done here so that the column will | ||
2759 | // not be overwritten when we blank-out the rest of line | ||
2760 | dest[co] = c; | 2775 | dest[co] = c; |
2761 | // discard scrolled-off portion, in tabstop-sized pieces | 2776 | // discard scrolled-off-to-the-left portion, |
2777 | // in tabstop-sized pieces | ||
2762 | if (ofs >= tabstop && co >= tabstop) { | 2778 | if (ofs >= tabstop && co >= tabstop) { |
2779 | memmove(dest, dest + tabstop, co + 1); | ||
2763 | co -= tabstop; | 2780 | co -= tabstop; |
2764 | ofs -= tabstop; | 2781 | ofs -= tabstop; |
2765 | memset(&dest[co + 1], ' ', tabstop); | ||
2766 | } | 2782 | } |
2767 | if (src >= end) | 2783 | if (src >= end) |
2768 | break; | 2784 | break; |
2769 | } | 2785 | } |
2770 | ret: | 2786 | // check "short line, gigantic offset" case |
2771 | if (co < ofs) { | 2787 | if (co < ofs) |
2772 | // entire line has scrolled off, make it entirely blank | 2788 | ofs = co + 1; |
2773 | memset(dest, ' ', MAX_SCR_COLS); | 2789 | dest[ofs + MAX_SCR_COLS] = '\0'; |
2774 | ofs = 0; | 2790 | return &dest[ofs]; |
2775 | } | ||
2776 | dest[MAX_SCR_COLS-1] = '\0'; | ||
2777 | return ofs; | ||
2778 | } | 2791 | } |
2779 | 2792 | ||
2780 | //----- Refresh the changed screen lines ----------------------- | 2793 | //----- Refresh the changed screen lines ----------------------- |
@@ -2787,29 +2800,29 @@ static void refresh(int full_screen) | |||
2787 | static int old_offset; | 2800 | static int old_offset; |
2788 | 2801 | ||
2789 | int li, changed; | 2802 | int li, changed; |
2790 | char buf[MAX_SCR_COLS]; | ||
2791 | char *tp, *sp; // pointer into text[] and screen[] | 2803 | char *tp, *sp; // pointer into text[] and screen[] |
2792 | #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR | ||
2793 | int last_li = -2; // last line that changed- for optimizing cursor movement | ||
2794 | #endif | ||
2795 | 2804 | ||
2796 | if (ENABLE_FEATURE_VI_WIN_RESIZE) | 2805 | if (ENABLE_FEATURE_VI_WIN_RESIZE) { |
2806 | int c = columns, r = rows; | ||
2797 | get_terminal_width_height(0, &columns, &rows); | 2807 | get_terminal_width_height(0, &columns, &rows); |
2808 | if (rows > MAX_SCR_ROWS) rows = MAX_SCR_ROWS; | ||
2809 | if (columns > MAX_SCR_COLS) columns = MAX_SCR_COLS; | ||
2810 | full_screen |= (c - columns) | (r - rows); | ||
2811 | } | ||
2798 | sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot") | 2812 | sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot") |
2799 | tp = screenbegin; // index into text[] of top line | 2813 | tp = screenbegin; // index into text[] of top line |
2800 | 2814 | ||
2801 | // compare text[] to screen[] and mark screen[] lines that need updating | 2815 | // compare text[] to screen[] and mark screen[] lines that need updating |
2802 | for (li = 0; li < rows - 1; li++) { | 2816 | for (li = 0; li < rows - 1; li++) { |
2803 | int ofs; | ||
2804 | int cs, ce; // column start & end | 2817 | int cs, ce; // column start & end |
2805 | // format current text line into buf | 2818 | // format current text line |
2806 | ofs = format_line(buf, tp, li); | 2819 | char *out_buf = format_line(tp, li); |
2807 | 2820 | ||
2808 | // skip to the end of the current text[] line | 2821 | // skip to the end of the current text[] line |
2809 | while (tp < end && *tp++ != '\n') | 2822 | while (tp < end && *tp++ != '\n') |
2810 | continue; | 2823 | continue; |
2811 | 2824 | ||
2812 | // see if there are any changes between vitual screen and buf | 2825 | // see if there are any changes between vitual screen and out_buf |
2813 | changed = FALSE; // assume no change | 2826 | changed = FALSE; // assume no change |
2814 | cs = 0; | 2827 | cs = 0; |
2815 | ce = columns - 1; | 2828 | ce = columns - 1; |
@@ -2821,15 +2834,15 @@ static void refresh(int full_screen) | |||
2821 | // compare newly formatted buffer with virtual screen | 2834 | // compare newly formatted buffer with virtual screen |
2822 | // look forward for first difference between buf and screen | 2835 | // look forward for first difference between buf and screen |
2823 | for (; cs <= ce; cs++) { | 2836 | for (; cs <= ce; cs++) { |
2824 | if (buf[cs + ofs] != sp[cs]) { | 2837 | if (out_buf[cs] != sp[cs]) { |
2825 | changed = TRUE; // mark for redraw | 2838 | changed = TRUE; // mark for redraw |
2826 | break; | 2839 | break; |
2827 | } | 2840 | } |
2828 | } | 2841 | } |
2829 | 2842 | ||
2830 | // look backward for last difference between buf and screen | 2843 | // look backward for last difference between out_buf and screen |
2831 | for (; ce >= cs; ce--) { | 2844 | for (; ce >= cs; ce--) { |
2832 | if (buf[ce + ofs] != sp[ce]) { | 2845 | if (out_buf[ce] != sp[ce]) { |
2833 | changed = TRUE; // mark for redraw | 2846 | changed = TRUE; // mark for redraw |
2834 | break; | 2847 | break; |
2835 | } | 2848 | } |
@@ -2846,50 +2859,26 @@ static void refresh(int full_screen) | |||
2846 | if (cs < 0) cs = 0; | 2859 | if (cs < 0) cs = 0; |
2847 | if (ce > columns - 1) ce = columns - 1; | 2860 | if (ce > columns - 1) ce = columns - 1; |
2848 | if (cs > ce) { cs = 0; ce = columns - 1; } | 2861 | if (cs > ce) { cs = 0; ce = columns - 1; } |
2849 | // is there a change between vitual screen and buf | 2862 | // is there a change between vitual screen and out_buf |
2850 | if (changed) { | 2863 | if (changed) { |
2851 | // copy changed part of buffer to virtual screen | 2864 | // copy changed part of buffer to virtual screen |
2852 | memmove(sp+cs, buf+(cs+ofs), ce-cs+1); | 2865 | memcpy(sp+cs, out_buf+cs, ce-cs+1); |
2853 | 2866 | ||
2854 | // move cursor to column of first change | 2867 | // move cursor to column of first change |
2855 | if (offset != old_offset) { | 2868 | //if (offset != old_offset) { |
2856 | // opti_cur_move is still too stupid | 2869 | // // place_cursor is still too stupid |
2857 | // to handle offsets correctly | 2870 | // // to handle offsets correctly |
2858 | place_cursor(li, cs, FALSE); | 2871 | // place_cursor(li, cs, FALSE); |
2859 | } else { | 2872 | //} else { |
2860 | #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR | 2873 | place_cursor(li, cs, TRUE); |
2861 | // if this just the next line | 2874 | //} |
2862 | // try to optimize cursor movement | ||
2863 | // otherwise, use standard ESC sequence | ||
2864 | place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE); | ||
2865 | last_li = li; | ||
2866 | #else | ||
2867 | place_cursor(li, cs, FALSE); // use standard ESC sequence | ||
2868 | #endif /* FEATURE_VI_OPTIMIZE_CURSOR */ | ||
2869 | } | ||
2870 | 2875 | ||
2871 | // write line out to terminal | 2876 | // write line out to terminal |
2872 | { | 2877 | fwrite(&sp[cs], ce - cs + 1, 1, stdout); |
2873 | int nic = ce - cs + 1; | ||
2874 | char *out = sp + cs; | ||
2875 | |||
2876 | while (--nic >= 0) { | ||
2877 | bb_putchar(*out); | ||
2878 | out++; | ||
2879 | } | ||
2880 | } | ||
2881 | #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR | ||
2882 | last_row = li; | ||
2883 | #endif | ||
2884 | } | 2878 | } |
2885 | } | 2879 | } |
2886 | 2880 | ||
2887 | #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR | 2881 | place_cursor(crow, ccol, TRUE); |
2888 | place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE); | ||
2889 | last_row = crow; | ||
2890 | #else | ||
2891 | place_cursor(crow, ccol, FALSE); | ||
2892 | #endif | ||
2893 | 2882 | ||
2894 | old_offset = offset; | 2883 | old_offset = offset; |
2895 | } | 2884 | } |
@@ -2919,13 +2908,14 @@ static void refresh(int full_screen) | |||
2919 | static void do_cmd(char c) | 2908 | static void do_cmd(char c) |
2920 | { | 2909 | { |
2921 | const char *msg; | 2910 | const char *msg; |
2922 | char c1, *p, *q, buf[9], *save_dot; | 2911 | char c1, *p, *q, *save_dot; |
2912 | char buf[12]; | ||
2923 | int cnt, i, j, dir, yf; | 2913 | int cnt, i, j, dir, yf; |
2924 | 2914 | ||
2925 | c1 = c; // quiet the compiler | 2915 | // c1 = c; // quiet the compiler |
2926 | cnt = yf = dir = 0; // quiet the compiler | 2916 | // cnt = yf = dir = 0; // quiet the compiler |
2927 | msg = p = q = save_dot = buf; // quiet the compiler | 2917 | // msg = p = q = save_dot = buf; // quiet the compiler |
2928 | memset(buf, '\0', 9); // clear buf | 2918 | memset(buf, '\0', 12); |
2929 | 2919 | ||
2930 | show_status_line(); | 2920 | show_status_line(); |
2931 | 2921 | ||
@@ -3022,7 +3012,7 @@ static void do_cmd(char c) | |||
3022 | buf[1] = c + '@'; | 3012 | buf[1] = c + '@'; |
3023 | buf[2] = '\0'; | 3013 | buf[2] = '\0'; |
3024 | } | 3014 | } |
3025 | ni(buf); | 3015 | not_implemented(buf); |
3026 | end_cmd_q(); // stop adding to q | 3016 | end_cmd_q(); // stop adding to q |
3027 | case 0x00: // nul- ignore | 3017 | case 0x00: // nul- ignore |
3028 | break; | 3018 | break; |
@@ -3156,7 +3146,7 @@ static void do_cmd(char c) | |||
3156 | case 'p': // p- put register after | 3146 | case 'p': // p- put register after |
3157 | p = reg[YDreg]; | 3147 | p = reg[YDreg]; |
3158 | if (p == 0) { | 3148 | if (p == 0) { |
3159 | psbs("Nothing in register %c", what_reg()); | 3149 | status_line_bold("Nothing in register %c", what_reg()); |
3160 | break; | 3150 | break; |
3161 | } | 3151 | } |
3162 | // are we putting whole lines or strings | 3152 | // are we putting whole lines or strings |
@@ -3319,7 +3309,7 @@ static void do_cmd(char c) | |||
3319 | } | 3309 | } |
3320 | dc2: | 3310 | dc2: |
3321 | if (*msg) | 3311 | if (*msg) |
3322 | psbs("%s", msg); | 3312 | status_line_bold("%s", msg); |
3323 | break; | 3313 | break; |
3324 | case '{': // {- move backward paragraph | 3314 | case '{': // {- move backward paragraph |
3325 | q = char_search(dot, "\n\n", BACK, FULL); | 3315 | q = char_search(dot, "\n\n", BACK, FULL); |
@@ -3364,7 +3354,7 @@ static void do_cmd(char c) | |||
3364 | || strncasecmp(p, "q!", cnt) == 0 // delete lines | 3354 | || strncasecmp(p, "q!", cnt) == 0 // delete lines |
3365 | ) { | 3355 | ) { |
3366 | if (file_modified && p[1] != '!') { | 3356 | if (file_modified && p[1] != '!') { |
3367 | psbs("No write since last change (:quit! overrides)"); | 3357 | status_line_bold("No write since last change (:quit! overrides)"); |
3368 | } else { | 3358 | } else { |
3369 | editing = 0; | 3359 | editing = 0; |
3370 | } | 3360 | } |
@@ -3376,11 +3366,11 @@ static void do_cmd(char c) | |||
3376 | cnt = file_write(current_filename, text, end - 1); | 3366 | cnt = file_write(current_filename, text, end - 1); |
3377 | if (cnt < 0) { | 3367 | if (cnt < 0) { |
3378 | if (cnt == -1) | 3368 | if (cnt == -1) |
3379 | psbs("Write error: %s", strerror(errno)); | 3369 | status_line_bold("Write error: %s", strerror(errno)); |
3380 | } else { | 3370 | } else { |
3381 | file_modified = 0; | 3371 | file_modified = 0; |
3382 | last_file_modified = -1; | 3372 | last_file_modified = -1; |
3383 | psb("\"%s\" %dL, %dC", current_filename, count_lines(text, end - 1), cnt); | 3373 | status_line("\"%s\" %dL, %dC", current_filename, count_lines(text, end - 1), cnt); |
3384 | if (p[0] == 'x' || p[1] == 'q' || p[1] == 'n' | 3374 | if (p[0] == 'x' || p[1] == 'q' || p[1] == 'n' |
3385 | || p[0] == 'X' || p[1] == 'Q' || p[1] == 'N' | 3375 | || p[0] == 'X' || p[1] == 'Q' || p[1] == 'N' |
3386 | ) { | 3376 | ) { |
@@ -3393,7 +3383,7 @@ static void do_cmd(char c) | |||
3393 | dot = find_line(j); // go to line # j | 3383 | dot = find_line(j); // go to line # j |
3394 | dot_skip_over_ws(); | 3384 | dot_skip_over_ws(); |
3395 | } else { // unrecognised cmd | 3385 | } else { // unrecognised cmd |
3396 | ni(p); | 3386 | not_implemented(p); |
3397 | } | 3387 | } |
3398 | #endif /* !FEATURE_VI_COLON */ | 3388 | #endif /* !FEATURE_VI_COLON */ |
3399 | break; | 3389 | break; |
@@ -3539,6 +3529,9 @@ static void do_cmd(char c) | |||
3539 | dc5: | 3529 | dc5: |
3540 | cmd_mode = 2; | 3530 | cmd_mode = 2; |
3541 | break; | 3531 | break; |
3532 | case VI_K_DELETE: | ||
3533 | c = 'x'; | ||
3534 | // fall through | ||
3542 | case 'X': // X- delete char before dot | 3535 | case 'X': // X- delete char before dot |
3543 | case 'x': // x- delete the current char | 3536 | case 'x': // x- delete the current char |
3544 | case 's': // s- substitute the current char | 3537 | case 's': // s- substitute the current char |
@@ -3566,13 +3559,13 @@ static void do_cmd(char c) | |||
3566 | } | 3559 | } |
3567 | if (file_modified) { | 3560 | if (file_modified) { |
3568 | if (ENABLE_FEATURE_VI_READONLY && readonly_mode) { | 3561 | if (ENABLE_FEATURE_VI_READONLY && readonly_mode) { |
3569 | psbs("\"%s\" File is read only", current_filename); | 3562 | status_line_bold("\"%s\" File is read only", current_filename); |
3570 | break; | 3563 | break; |
3571 | } | 3564 | } |
3572 | cnt = file_write(current_filename, text, end - 1); | 3565 | cnt = file_write(current_filename, text, end - 1); |
3573 | if (cnt < 0) { | 3566 | if (cnt < 0) { |
3574 | if (cnt == -1) | 3567 | if (cnt == -1) |
3575 | psbs("Write error: %s", strerror(errno)); | 3568 | status_line_bold("Write error: %s", strerror(errno)); |
3576 | } else if (cnt == (end - 1 - text + 1)) { | 3569 | } else if (cnt == (end - 1 - text + 1)) { |
3577 | editing = 0; | 3570 | editing = 0; |
3578 | } | 3571 | } |
@@ -3671,7 +3664,7 @@ static void do_cmd(char c) | |||
3671 | if (*p == '\n') | 3664 | if (*p == '\n') |
3672 | cnt++; | 3665 | cnt++; |
3673 | } | 3666 | } |
3674 | psb("%s %d lines (%d chars) using [%c]", | 3667 | status_line("%s %d lines (%d chars) using [%c]", |
3675 | buf, cnt, strlen(reg[YDreg]), what_reg()); | 3668 | buf, cnt, strlen(reg[YDreg]), what_reg()); |
3676 | #endif | 3669 | #endif |
3677 | end_cmd_q(); // stop adding to q | 3670 | end_cmd_q(); // stop adding to q |
@@ -3793,15 +3786,15 @@ static int Ip = 97; // Insert command Probability | |||
3793 | static int Yp = 98; // Yank command Probability | 3786 | static int Yp = 98; // Yank command Probability |
3794 | static int Pp = 99; // Put command Probability | 3787 | static int Pp = 99; // Put command Probability |
3795 | static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0; | 3788 | static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0; |
3796 | const char chars[20] = "\t012345 abcdABCD-=.$"; | 3789 | static const char chars[20] = "\t012345 abcdABCD-=.$"; |
3797 | const char *const words[20] = { | 3790 | static const char *const words[20] = { |
3798 | "this", "is", "a", "test", | 3791 | "this", "is", "a", "test", |
3799 | "broadcast", "the", "emergency", "of", | 3792 | "broadcast", "the", "emergency", "of", |
3800 | "system", "quick", "brown", "fox", | 3793 | "system", "quick", "brown", "fox", |
3801 | "jumped", "over", "lazy", "dogs", | 3794 | "jumped", "over", "lazy", "dogs", |
3802 | "back", "January", "Febuary", "March" | 3795 | "back", "January", "Febuary", "March" |
3803 | }; | 3796 | }; |
3804 | const char *const lines[20] = { | 3797 | static const char *const lines[20] = { |
3805 | "You should have received a copy of the GNU General Public License\n", | 3798 | "You should have received a copy of the GNU General Public License\n", |
3806 | "char c, cm, *cmd, *cmd1;\n", | 3799 | "char c, cm, *cmd, *cmd1;\n", |
3807 | "generate a command by percentages\n", | 3800 | "generate a command by percentages\n", |
@@ -3823,7 +3816,7 @@ const char *const lines[20] = { | |||
3823 | "The last command will be automatically run.\n", | 3816 | "The last command will be automatically run.\n", |
3824 | "This is too much english for a computer geek.\n", | 3817 | "This is too much english for a computer geek.\n", |
3825 | }; | 3818 | }; |
3826 | char *multilines[20] = { | 3819 | static char *multilines[20] = { |
3827 | "You should have received a copy of the GNU General Public License\n", | 3820 | "You should have received a copy of the GNU General Public License\n", |
3828 | "char c, cm, *cmd, *cmd1;\n", | 3821 | "char c, cm, *cmd, *cmd1;\n", |
3829 | "generate a command by percentages\n", | 3822 | "generate a command by percentages\n", |
@@ -3862,7 +3855,7 @@ static void crash_dummy() | |||
3862 | cd0: | 3855 | cd0: |
3863 | startrbi = rbi = 0; | 3856 | startrbi = rbi = 0; |
3864 | sleeptime = 0; // how long to pause between commands | 3857 | sleeptime = 0; // how long to pause between commands |
3865 | memset(readbuffer, '\0', MAX_LINELEN); // clear the read buffer | 3858 | memset(readbuffer, '\0', sizeof(readbuffer)); |
3866 | // generate a command by percentages | 3859 | // generate a command by percentages |
3867 | percent = (int) lrand48() % 100; // get a number from 0-99 | 3860 | percent = (int) lrand48() % 100; // get a number from 0-99 |
3868 | if (percent < Mp) { // Movement commands | 3861 | if (percent < Mp) { // Movement commands |
@@ -3947,7 +3940,7 @@ static void crash_test() | |||
3947 | static time_t oldtim; | 3940 | static time_t oldtim; |
3948 | 3941 | ||
3949 | time_t tim; | 3942 | time_t tim; |
3950 | char d[2], msg[MAX_LINELEN]; | 3943 | char d[2], msg[80]; |
3951 | 3944 | ||
3952 | msg[0] = '\0'; | 3945 | msg[0] = '\0'; |
3953 | if (end < text) { | 3946 | if (end < text) { |
@@ -3980,7 +3973,7 @@ static void crash_test() | |||
3980 | } | 3973 | } |
3981 | alarm(3); | 3974 | alarm(3); |
3982 | } | 3975 | } |
3983 | tim = (time_t) time((time_t *) 0); | 3976 | tim = time(NULL); |
3984 | if (tim >= (oldtim + 3)) { | 3977 | if (tim >= (oldtim + 3)) { |
3985 | sprintf(status_buffer, | 3978 | sprintf(status_buffer, |
3986 | "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d", | 3979 | "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d", |