aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-12-22 15:40:13 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-12-22 15:40:13 +0000
commit88adfcd17863361a827551a572f993e43356eefc (patch)
tree7ea5952f0f96e9488a3c822dcdaa1db9bc41d783
parentee87ebf3815d37cbdcaf766a06ed40d4ca0dfe81 (diff)
downloadbusybox-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.in9
-rw-r--r--editors/vi.c617
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
92config FEATURE_VI_MAX_LEN 92config 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
102config FEATURE_VI_COLON 101config 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
35enum { 35enum {
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
152static smallint adding2q; // are we currently adding user input to q 157static smallint adding2q; // are we currently adding user input to q
153static char *last_modifying_cmd; // last modifying cmd for "." 158static char *last_modifying_cmd; // [MAX_INPUT_LEN] last modifying cmd for "."
154static char *ioq, *ioq_start; // pointer to string for get_one_char to "read" 159static 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
170struct globals { 175struct 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
266static void standout_end(void); // send "end reverse video" sequence 280static void standout_end(void); // send "end reverse video" sequence
267static void flash(int); // flash the terminal screen 281static void flash(int); // flash the terminal screen
268static void show_status_line(void); // put a message on the bottom line 282static void show_status_line(void); // put a message on the bottom line
269static void psb(const char *, ...); // Print Status Buf 283static void status_line(const char *, ...); // print to status buf
270static void psbs(const char *, ...); // Print Status Buf in standout mode 284static void status_line_bold(const char *, ...);
271static void ni(const char *); // display messages 285static void not_implemented(const char *); // display "Not implemented" message
272static int format_edit_status(void); // format file status on status line 286static int format_edit_status(void); // format file status on status line
273static void redraw(int); // force a full screen refresh 287static void redraw(int); // force a full screen refresh
274static int format_line(char*, char*, int); 288static char* format_line(char*, int);
275static void refresh(int); // update the terminal from screen[] 289static void refresh(int); // update the terminal from screen[]
276 290
277static void Indicate_Error(void); // use flash or beep to indicate error 291static 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
450static void edit_file(char * fn) 464static 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
580static char *get_one_address(char * p, int *addr) // get colon addr, if present 597static 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
689static void colon(char * buf) 699// buf must be no longer than MAX_INPUT_LEN!
700static 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
1353static char *move_to_col(char * p, int l) 1364static 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
1931static 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
1966static void start_new_cmd_q(char c) 1943static 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)
2104static void winch_sig(int sig ATTRIBUTE_UNUSED) 2082static 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
2314static char *get_input_line(const char * prompt) // get input line- use "status line" 2291// Get input line (uses "status line" area)
2292static 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) -------
2468static void place_cursor(int row, int col, int optimize) 2442static 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
2614static void psbs(const char *format, ...) 2599static 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
2628static void psb(const char *format, ...) 2613static 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
2639static void ni(const char * s) // display messages 2624// copy s to buf, convert unprintable
2625static 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
2661static 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
2647static int format_edit_status(void) // show file status on status line 2669// show file status on status line
2670static 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)
2717static int format_line(char *dest, char *src, int li) 2740static 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)
2919static void do_cmd(char c) 2908static 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
3793static int Yp = 98; // Yank command Probability 3786static int Yp = 98; // Yank command Probability
3794static int Pp = 99; // Put command Probability 3787static int Pp = 99; // Put command Probability
3795static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0; 3788static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0;
3796const char chars[20] = "\t012345 abcdABCD-=.$"; 3789static const char chars[20] = "\t012345 abcdABCD-=.$";
3797const char *const words[20] = { 3790static 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};
3804const char *const lines[20] = { 3797static 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};
3826char *multilines[20] = { 3819static 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",