Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/editors/vi.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 30  Line 30 
30  #if ENABLE_LOCALE_SUPPORT  #if ENABLE_LOCALE_SUPPORT
31    
32  #if ENABLE_FEATURE_VI_8BIT  #if ENABLE_FEATURE_VI_8BIT
33  #define Isprint(c) isprint(c)  //FIXME: this does not work properly for Unicode anyway
34    # define Isprint(c) (isprint)(c)
35  #else  #else
36  #define Isprint(c) (isprint(c) && (unsigned char)(c) < 0x7f)  # define Isprint(c) isprint_asciionly(c)
37  #endif  #endif
38    
39  #else  #else
# Line 151  struct globals { Line 152  struct globals {
152   char erase_char;         // the users erase character   char erase_char;         // the users erase character
153   char last_input_char;    // last char read from user   char last_input_char;    // last char read from user
154    
  smalluint chars_to_parse;  
155  #if ENABLE_FEATURE_VI_DOT_CMD  #if ENABLE_FEATURE_VI_DOT_CMD
156   smallint adding2q; // are we currently adding user input to q   smallint adding2q; // are we currently adding user input to q
157   int lmc_len;             // length of last_modifying_cmd   int lmc_len;             // length of last_modifying_cmd
# Line 235  struct globals { Line 235  struct globals {
235  #define last_forward_char       (G.last_forward_char  )  #define last_forward_char       (G.last_forward_char  )
236  #define erase_char              (G.erase_char         )  #define erase_char              (G.erase_char         )
237  #define last_input_char         (G.last_input_char    )  #define last_input_char         (G.last_input_char    )
 #define chars_to_parse          (G.chars_to_parse     )  
238  #if ENABLE_FEATURE_VI_READONLY  #if ENABLE_FEATURE_VI_READONLY
239  #define readonly_mode           (G.readonly_mode      )  #define readonly_mode           (G.readonly_mode      )
240  #else  #else
# Line 271  struct globals { Line 270  struct globals {
270   SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \   SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
271   last_file_modified = -1; \   last_file_modified = -1; \
272   /* "" but has space for 2 chars: */ \   /* "" but has space for 2 chars: */ \
273   USE_FEATURE_VI_SEARCH(last_search_pattern = xzalloc(2);) \   IF_FEATURE_VI_SEARCH(last_search_pattern = xzalloc(2);) \
274  } while (0)  } while (0)
275    
276    
# Line 300  static void dot_delete(void); // delete Line 299  static void dot_delete(void); // delete
299  static char *bound_dot(char *); // make sure  text[0] <= P < "end"  static char *bound_dot(char *); // make sure  text[0] <= P < "end"
300  static char *new_screen(int, int); // malloc virtual screen memory  static char *new_screen(int, int); // malloc virtual screen memory
301  static char *char_insert(char *, char); // insert the char c at 'p'  static char *char_insert(char *, char); // insert the char c at 'p'
302  static char *stupid_insert(char *, char); // stupidly insert the char c at 'p'  // might reallocate text[]! use p += stupid_insert(p, ...),
303    // and be careful to not use pointers into potentially freed text[]!
304    static uintptr_t stupid_insert(char *, char); // stupidly insert the char c at 'p'
305  static int find_range(char **, char **, char); // return pointers for an object  static int find_range(char **, char **, char); // return pointers for an object
306  static int st_test(char *, int, int, char *); // helper for skip_thing()  static int st_test(char *, int, int, char *); // helper for skip_thing()
307  static char *skip_thing(char *, int, int, int); // skip some object  static char *skip_thing(char *, int, int, int); // skip some object
308  static char *find_pair(char *, char); // find matching pair ()  []  {}  static char *find_pair(char *, char); // find matching pair ()  []  {}
309  static char *text_hole_delete(char *, char *); // at "p", delete a 'size' byte hole  static char *text_hole_delete(char *, char *); // at "p", delete a 'size' byte hole
310  static char *text_hole_make(char *, int); // at "p", make a 'size' byte hole  // might reallocate text[]! use p += text_hole_make(p, ...),
311    // and be careful to not use pointers into potentially freed text[]!
312    static uintptr_t text_hole_make(char *, int); // at "p", make a 'size' byte hole
313  static char *yank_delete(char *, char *, int, int); // yank text[] into register then delete  static char *yank_delete(char *, char *, int, int); // yank text[] into register then delete
314  static void show_help(void); // display some help info  static void show_help(void); // display some help info
315  static void rawmode(void); // set "raw" mode on tty  static void rawmode(void); // set "raw" mode on tty
# Line 316  static int mysleep(int); Line 319  static int mysleep(int);
319  static int readit(void); // read (maybe cursor) key from stdin  static int readit(void); // read (maybe cursor) key from stdin
320  static int get_one_char(void); // read 1 char from stdin  static int get_one_char(void); // read 1 char from stdin
321  static int file_size(const char *);   // what is the byte size of "fn"  static int file_size(const char *);   // what is the byte size of "fn"
322  #if ENABLE_FEATURE_VI_READONLY  #if !ENABLE_FEATURE_VI_READONLY
323  static int file_insert(const char *, char *, int);  #define file_insert(fn, p, update_ro_status) file_insert(fn, p)
 #else  
 static int file_insert(const char *, char *);  
324  #endif  #endif
325    // file_insert might reallocate text[]!
326    static int file_insert(const char *, char *, int);
327  static int file_write(char *, char *, char *);  static int file_write(char *, char *, char *);
328  #if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR  #if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
329  #define place_cursor(a, b, optimize) place_cursor(a, b)  #define place_cursor(a, b, optimize) place_cursor(a, b)
# Line 370  static void end_cmd_q(void); // stop sav Line 373  static void end_cmd_q(void); // stop sav
373  static void showmatching(char *); // show the matching pair ()  []  {}  static void showmatching(char *); // show the matching pair ()  []  {}
374  #endif  #endif
375  #if ENABLE_FEATURE_VI_YANKMARK || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) || ENABLE_FEATURE_VI_CRASHME  #if ENABLE_FEATURE_VI_YANKMARK || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) || ENABLE_FEATURE_VI_CRASHME
376  static char *string_insert(char *, char *); // insert the string at 'p'  // might reallocate text[]! use p += string_insert(p, ...),
377    // and be careful to not use pointers into potentially freed text[]!
378    static uintptr_t string_insert(char *, const char *); // insert the string at 'p'
379  #endif  #endif
380  #if ENABLE_FEATURE_VI_YANKMARK  #if ENABLE_FEATURE_VI_YANKMARK
381  static char *text_yank(char *, char *, int); // save copy of "p" into a register  static char *text_yank(char *, char *, int); // save copy of "p" into a register
# Line 420  int vi_main(int argc, char **argv) Line 425  int vi_main(int argc, char **argv)
425   initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN);   initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN);
426   }   }
427  #endif  #endif
428   while ((c = getopt(argc, argv, "hCRH" USE_FEATURE_VI_COLON("c:"))) != -1) {   while ((c = getopt(argc, argv, "hCRH" IF_FEATURE_VI_COLON("c:"))) != -1) {
429   switch (c) {   switch (c) {
430  #if ENABLE_FEATURE_VI_CRASHME  #if ENABLE_FEATURE_VI_CRASHME
431   case 'C':   case 'C':
# Line 486  static int init_text_buffer(char *fn) Line 491  static int init_text_buffer(char *fn)
491   char_insert(text, '\n');   char_insert(text, '\n');
492   rc = 0;   rc = 0;
493   } else {   } else {
494   rc = file_insert(fn, text   rc = file_insert(fn, text, 1);
  USE_FEATURE_VI_READONLY(, 1));  
495   }   }
496   file_modified = 0;   file_modified = 0;
497   last_file_modified = -1;   last_file_modified = -1;
# Line 584  static void edit_file(char *fn) Line 588  static void edit_file(char *fn)
588   crash_dummy(); // generate a random command   crash_dummy(); // generate a random command
589   } else {   } else {
590   crashme = 0;   crashme = 0;
591   dot = string_insert(text, "\n\n#####  Ran out of text to work on.  #####\n\n"); // insert the string   string_insert(text, "\n\n#####  Ran out of text to work on.  #####\n\n"); // insert the string
592     dot = text;
593   refresh(FALSE);   refresh(FALSE);
594   }   }
595   }   }
# Line 614  static void edit_file(char *fn) Line 619  static void edit_file(char *fn)
619   // poll to see if there is input already waiting. if we are   // poll to see if there is input already waiting. if we are
620   // not able to display output fast enough to keep up, skip   // not able to display output fast enough to keep up, skip
621   // the display update until we catch up with input.   // the display update until we catch up with input.
622   if (!chars_to_parse && mysleep(0) == 0) {   if (!readbuffer[0] && mysleep(0) == 0) {
623   // no input pending - so update output   // no input pending - so update output
624   refresh(FALSE);   refresh(FALSE);
625   show_status_line();   show_status_line();
# Line 637  static char *get_one_address(char *p, in Line 642  static char *get_one_address(char *p, in
642  {  {
643   int st;   int st;
644   char *q;   char *q;
645   USE_FEATURE_VI_YANKMARK(char c;)   IF_FEATURE_VI_YANKMARK(char c;)
646   USE_FEATURE_VI_SEARCH(char *pat;)   IF_FEATURE_VI_SEARCH(char *pat;)
647    
648   *addr = -1; // assume no addr   *addr = -1; // assume no addr
649   if (*p == '.') { // the current line   if (*p == '.') { // the current line
# Line 656  static char *get_one_address(char *p, in Line 661  static char *get_one_address(char *p, in
661   c = c - 'a';   c = c - 'a';
662   q = mark[(unsigned char) c];   q = mark[(unsigned char) c];
663   if (q != NULL) { // is mark valid   if (q != NULL) { // is mark valid
664   *addr = count_lines(text, q); // count lines   *addr = count_lines(text, q);
665   }   }
666   }   }
667   }   }
# Line 683  static char *get_one_address(char *p, in Line 688  static char *get_one_address(char *p, in
688   sscanf(p, "%d%n", addr, &st);   sscanf(p, "%d%n", addr, &st);
689   p += st;   p += st;
690   } else {   } else {
691   // unrecognised address - assume -1   // unrecognized address - assume -1
692   *addr = -1;   *addr = -1;
693   }   }
694   return p;   return p;
# Line 724  static void setops(const char *args, con Line 729  static void setops(const char *args, con
729   const char *a = args + flg_no;   const char *a = args + flg_no;
730   int l = strlen(opname) - 1; /* opname have + ' ' */   int l = strlen(opname) - 1; /* opname have + ' ' */
731    
732     // maybe strncmp? we had tons of erroneous strncasecmp's...
733   if (strncasecmp(a, opname, l) == 0   if (strncasecmp(a, opname, l) == 0
734   || strncasecmp(a, short_opname, 2) == 0   || strncasecmp(a, short_opname, 2) == 0
735   ) {   ) {
# Line 819  static void colon(char *buf) Line 825  static void colon(char *buf)
825   }   }
826   }   }
827  #if ENABLE_FEATURE_ALLOW_EXEC  #if ENABLE_FEATURE_ALLOW_EXEC
828   else if (strncmp(cmd, "!", 1) == 0) { // run a cmd   else if (cmd[0] == '!') { // run a cmd
829   int retcode;   int retcode;
830   // :!ls   run the <cmd>   // :!ls   run the <cmd>
831   go_bottom_and_clear_to_eol();   go_bottom_and_clear_to_eol();
# Line 831  static void colon(char *buf) Line 837  static void colon(char *buf)
837   Hit_Return(); // let user see results   Hit_Return(); // let user see results
838   }   }
839  #endif  #endif
840   else if (strncmp(cmd, "=", i) == 0) { // where is the address   else if (cmd[0] == '=' && !cmd[1]) { // where is the address
841   if (b < 0) { // no addr given- use defaults   if (b < 0) { // no addr given- use defaults
842   b = e = count_lines(text, dot);   b = e = count_lines(text, dot);
843   }   }
844   status_line("%d", b);   status_line("%d", b);
845   } else if (strncasecmp(cmd, "delete", i) == 0) { // delete lines   } else if (strncmp(cmd, "delete", i) == 0) { // delete lines
846   if (b < 0) { // no addr given- use defaults   if (b < 0) { // no addr given- use defaults
847   q = begin_line(dot); // assume .,. for the range   q = begin_line(dot); // assume .,. for the range
848   r = end_line(dot);   r = end_line(dot);
849   }   }
850   dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines   dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines
851   dot_skip_over_ws();   dot_skip_over_ws();
852   } else if (strncasecmp(cmd, "edit", i) == 0) { // Edit a file   } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file
853   // don't edit, if the current file has been modified   // don't edit, if the current file has been modified
854   if (file_modified && !useforce) {   if (file_modified && !useforce) {
855   status_line_bold("No write since last change (:edit! overrides)");   status_line_bold("No write since last change (:edit! overrides)");
# Line 877  static void colon(char *buf) Line 883  static void colon(char *buf)
883   // how many lines in text[]?   // how many lines in text[]?
884   li = count_lines(text, end - 1);   li = count_lines(text, end - 1);
885   status_line("\"%s\"%s"   status_line("\"%s\"%s"
886   USE_FEATURE_VI_READONLY("%s")   IF_FEATURE_VI_READONLY("%s")
887   " %dL, %dC", current_filename,   " %dL, %dC", current_filename,
888   (file_size(fn) < 0 ? " [New file]" : ""),   (file_size(fn) < 0 ? " [New file]" : ""),
889   USE_FEATURE_VI_READONLY(   IF_FEATURE_VI_READONLY(
890   ((readonly_mode) ? " [Readonly]" : ""),   ((readonly_mode) ? " [Readonly]" : ""),
891   )   )
892   li, ch);   li, ch);
893   } else if (strncasecmp(cmd, "file", i) == 0) { // what File is this   } else if (strncmp(cmd, "file", i) == 0) { // what File is this
894   if (b != -1 || e != -1) {   if (b != -1 || e != -1) {
895   not_implemented("No address allowed on this command");   status_line_bold("No address allowed on this command");
896   goto vc1;   goto vc1;
897   }   }
898   if (args[0]) {   if (args[0]) {
# Line 897  static void colon(char *buf) Line 903  static void colon(char *buf)
903   // user wants file status info   // user wants file status info
904   last_status_cksum = 0; // force status update   last_status_cksum = 0; // force status update
905   }   }
906   } else if (strncasecmp(cmd, "features", i) == 0) { // what features are available   } else if (strncmp(cmd, "features", i) == 0) { // what features are available
907   // print out values of all features   // print out values of all features
908   go_bottom_and_clear_to_eol();   go_bottom_and_clear_to_eol();
909   cookmode();   cookmode();
910   show_help();   show_help();
911   rawmode();   rawmode();
912   Hit_Return();   Hit_Return();
913   } else if (strncasecmp(cmd, "list", i) == 0) { // literal print line   } else if (strncmp(cmd, "list", i) == 0) { // literal print line
914   if (b < 0) { // no addr given- use defaults   if (b < 0) { // no addr given- use defaults
915   q = begin_line(dot); // assume .,. for the range   q = begin_line(dot); // assume .,. for the range
916   r = end_line(dot);   r = end_line(dot);
# Line 937  static void colon(char *buf) Line 943  static void colon(char *buf)
943   vc2:   vc2:
944  #endif  #endif
945   Hit_Return();   Hit_Return();
946   } else if (strncasecmp(cmd, "quit", i) == 0 // Quit   } else if (strncmp(cmd, "quit", i) == 0 // Quit
947          || strncasecmp(cmd, "next", i) == 0 // edit next file          || strncmp(cmd, "next", i) == 0 // edit next file
948   ) {   ) {
949   if (useforce) {   if (useforce) {
950   // force end of argv list   // force end of argv list
# Line 964  static void colon(char *buf) Line 970  static void colon(char *buf)
970   goto vc1;   goto vc1;
971   }   }
972   editing = 0;   editing = 0;
973   } else if (strncasecmp(cmd, "read", i) == 0) { // read file into text[]   } else if (strncmp(cmd, "read", i) == 0) { // read file into text[]
974   fn = args;   fn = args;
975   if (!fn[0]) {   if (!fn[0]) {
976   status_line_bold("No filename given");   status_line_bold("No filename given");
# Line 976  static void colon(char *buf) Line 982  static void colon(char *buf)
982   // read after current line- unless user said ":0r foo"   // read after current line- unless user said ":0r foo"
983   if (b != 0)   if (b != 0)
984   q = next_line(q);   q = next_line(q);
985   ch = file_insert(fn, q  USE_FEATURE_VI_READONLY(, 0));   { // dance around potentially-reallocated text[]
986     uintptr_t ofs = q - text;
987     ch = file_insert(fn, q, 0);
988     q = text + ofs;
989     }
990   if (ch < 0)   if (ch < 0)
991   goto vc1; // nothing was inserted   goto vc1; // nothing was inserted
992   // how many lines in text[]?   // how many lines in text[]?
993   li = count_lines(q, q + ch - 1);   li = count_lines(q, q + ch - 1);
994   status_line("\"%s\""   status_line("\"%s\""
995   USE_FEATURE_VI_READONLY("%s")   IF_FEATURE_VI_READONLY("%s")
996   " %dL, %dC", fn,   " %dL, %dC", fn,
997   USE_FEATURE_VI_READONLY((readonly_mode ? " [Readonly]" : ""),)   IF_FEATURE_VI_READONLY((readonly_mode ? " [Readonly]" : ""),)
998   li, ch);   li, ch);
999   if (ch > 0) {   if (ch > 0) {
1000   // if the insert is before "dot" then we need to update   // if the insert is before "dot" then we need to update
1001   if (q <= dot)   if (q <= dot)
1002   dot += ch;   dot += ch;
1003   file_modified++;   /*file_modified++; - done by file_insert */
1004   }   }
1005   } else if (strncasecmp(cmd, "rewind", i) == 0) { // rewind cmd line args   } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args
1006   if (file_modified && !useforce) {   if (file_modified && !useforce) {
1007   status_line_bold("No write since last change (:rewind! overrides)");   status_line_bold("No write since last change (:rewind! overrides)");
1008   } else {   } else {
# Line 1001  static void colon(char *buf) Line 1011  static void colon(char *buf)
1011   editing = 0;   editing = 0;
1012   }   }
1013  #if ENABLE_FEATURE_VI_SET  #if ENABLE_FEATURE_VI_SET
1014   } else if (strncasecmp(cmd, "set", i) == 0) { // set or clear features   } else if (strncmp(cmd, "set", i) == 0) { // set or clear features
1015  #if ENABLE_FEATURE_VI_SETOPTS  #if ENABLE_FEATURE_VI_SETOPTS
1016   char *argp;   char *argp;
1017  #endif  #endif
# Line 1032  static void colon(char *buf) Line 1042  static void colon(char *buf)
1042  #if ENABLE_FEATURE_VI_SETOPTS  #if ENABLE_FEATURE_VI_SETOPTS
1043   argp = args;   argp = args;
1044   while (*argp) {   while (*argp) {
1045   if (strncasecmp(argp, "no", 2) == 0)   if (strncmp(argp, "no", 2) == 0)
1046   i = 2; // ":set noautoindent"   i = 2; // ":set noautoindent"
1047   setops(argp, "autoindent ", i, "ai", VI_AUTOINDENT);   setops(argp, "autoindent ", i, "ai", VI_AUTOINDENT);
1048   setops(argp, "flash ", i, "fl", VI_ERR_METHOD);   setops(argp, "flash ", i, "fl", VI_ERR_METHOD);
1049   setops(argp, "ignorecase ", i, "ic", VI_IGNORECASE);   setops(argp, "ignorecase ", i, "ic", VI_IGNORECASE);
1050   setops(argp, "showmatch ", i, "ic", VI_SHOWMATCH);   setops(argp, "showmatch ", i, "ic", VI_SHOWMATCH);
1051   /* tabstopXXXX */   /* tabstopXXXX */
1052   if (strncasecmp(argp + i, "tabstop=%d ", 7) == 0) {   if (strncmp(argp + i, "tabstop=%d ", 7) == 0) {
1053   sscanf(strchr(argp + i, '='), "tabstop=%d" + 7, &ch);   sscanf(strchr(argp + i, '='), "tabstop=%d" + 7, &ch);
1054   if (ch > 0 && ch <= MAX_TABSTOP)   if (ch > 0 && ch <= MAX_TABSTOP)
1055   tabstop = ch;   tabstop = ch;
# Line 1052  static void colon(char *buf) Line 1062  static void colon(char *buf)
1062  #endif /* FEATURE_VI_SETOPTS */  #endif /* FEATURE_VI_SETOPTS */
1063  #endif /* FEATURE_VI_SET */  #endif /* FEATURE_VI_SET */
1064  #if ENABLE_FEATURE_VI_SEARCH  #if ENABLE_FEATURE_VI_SEARCH
1065   } else if (strncasecmp(cmd, "s", 1) == 0) { // substitute a pattern with a replacement pattern   } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern
1066   char *ls, *F, *R;   char *ls, *F, *R;
1067   int gflag;   int gflag;
1068    
# Line 1063  static void colon(char *buf) Line 1073  static void colon(char *buf)
1073   c = orig_buf[1]; // what is the delimiter   c = orig_buf[1]; // what is the delimiter
1074   F = orig_buf + 2; // start of "find"   F = orig_buf + 2; // start of "find"
1075   R = strchr(F, c); // middle delimiter   R = strchr(F, c); // middle delimiter
1076   if (!R) goto colon_s_fail;   if (!R)
1077     goto colon_s_fail;
1078   *R++ = '\0'; // terminate "find"   *R++ = '\0'; // terminate "find"
1079   buf1 = strchr(R, c);   buf1 = strchr(R, c);
1080   if (!buf1) goto colon_s_fail;   if (!buf1)
1081     goto colon_s_fail;
1082   *buf1++ = '\0'; // terminate "replace"   *buf1++ = '\0'; // terminate "replace"
1083   if (*buf1 == 'g') { // :s/foo/bar/g   if (*buf1 == 'g') { // :s/foo/bar/g
1084   buf1++;   buf1++;
# Line 1084  static void colon(char *buf) Line 1096  static void colon(char *buf)
1096   vc4:   vc4:
1097   buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find"   buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find"
1098   if (buf1) {   if (buf1) {
1099     uintptr_t bias;
1100   // we found the "find" pattern - delete it   // we found the "find" pattern - delete it
1101   text_hole_delete(buf1, buf1 + strlen(F) - 1);   text_hole_delete(buf1, buf1 + strlen(F) - 1);
1102   // inset the "replace" patern   // inset the "replace" patern
1103   string_insert(buf1, R); // insert the string   bias = string_insert(buf1, R); // insert the string
1104     buf1 += bias;
1105     ls += bias;
1106     /*q += bias; - recalculated anyway */
1107   // check for "global"  :s/foo/bar/g   // check for "global"  :s/foo/bar/g
1108   if (gflag == 1) {   if (gflag == 1) {
1109   if ((buf1 + strlen(R)) < end_line(ls)) {   if ((buf1 + strlen(R)) < end_line(ls)) {
# Line 1099  static void colon(char *buf) Line 1115  static void colon(char *buf)
1115   q = next_line(ls);   q = next_line(ls);
1116   }   }
1117  #endif /* FEATURE_VI_SEARCH */  #endif /* FEATURE_VI_SEARCH */
1118   } else if (strncasecmp(cmd, "version", i) == 0) {  // show software version   } else if (strncmp(cmd, "version", i) == 0) {  // show software version
1119   status_line(BB_VER " " BB_BT);   status_line(BB_VER " " BB_BT);
1120   } else if (strncasecmp(cmd, "write", i) == 0  // write text to file   } else if (strncmp(cmd, "write", i) == 0  // write text to file
1121          || strncasecmp(cmd, "wq", i) == 0          || strncmp(cmd, "wq", i) == 0
1122          || strncasecmp(cmd, "wn", i) == 0          || strncmp(cmd, "wn", i) == 0
1123          || strncasecmp(cmd, "x", i) == 0          || (cmd[0] == 'x' && !cmd[1])
1124   ) {   ) {
1125   // is there a file name to write to?   // is there a file name to write to?
1126   if (args[0]) {   if (args[0]) {
# Line 1152  static void colon(char *buf) Line 1168  static void colon(char *buf)
1168   vc3:;   vc3:;
1169  #endif  #endif
1170  #if ENABLE_FEATURE_VI_YANKMARK  #if ENABLE_FEATURE_VI_YANKMARK
1171   } else if (strncasecmp(cmd, "yank", i) == 0) { // yank lines   } else if (strncmp(cmd, "yank", i) == 0) { // yank lines
1172   if (b < 0) { // no addr given- use defaults   if (b < 0) { // no addr given- use defaults
1173   q = begin_line(dot); // assume .,. for the range   q = begin_line(dot); // assume .,. for the range
1174   r = end_line(dot);   r = end_line(dot);
# Line 1195  static int next_tabstop(int col) Line 1211  static int next_tabstop(int col)
1211  }  }
1212    
1213  //----- Synchronize the cursor to Dot --------------------------  //----- Synchronize the cursor to Dot --------------------------
1214  static void sync_cursor(char *d, int *row, int *col)  static NOINLINE void sync_cursor(char *d, int *row, int *col)
1215  {  {
1216   char *beg_cur; // begin and end of "d" line   char *beg_cur; // begin and end of "d" line
1217   char *tp;   char *tp;
# Line 1517  static char *new_screen(int ro, int co) Line 1533  static char *new_screen(int ro, int co)
1533  #if ENABLE_FEATURE_VI_SEARCH  #if ENABLE_FEATURE_VI_SEARCH
1534  static int mycmp(const char *s1, const char *s2, int len)  static int mycmp(const char *s1, const char *s2, int len)
1535  {  {
  int i;  
   
  i = strncmp(s1, s2, len);  
1536   if (ENABLE_FEATURE_VI_SETOPTS && ignorecase) {   if (ENABLE_FEATURE_VI_SETOPTS && ignorecase) {
1537   i = strncasecmp(s1, s2, len);   return strncasecmp(s1, s2, len);
1538   }   }
1539   return i;   return strncmp(s1, s2, len);
1540  }  }
1541    
1542  // search for pattern starting at p  // search for pattern starting at p
# Line 1623  static char *char_search(char *p, const Line 1636  static char *char_search(char *p, const
1636  static char *char_insert(char *p, char c) // insert the char c at 'p'  static char *char_insert(char *p, char c) // insert the char c at 'p'
1637  {  {
1638   if (c == 22) { // Is this an ctrl-V?   if (c == 22) { // Is this an ctrl-V?
1639   p = stupid_insert(p, '^'); // use ^ to indicate literal next   p += stupid_insert(p, '^'); // use ^ to indicate literal next
  p--; // backup onto ^  
1640   refresh(FALSE); // show the ^   refresh(FALSE); // show the ^
1641   c = get_one_char();   c = get_one_char();
1642   *p = c;   *p = c;
# Line 1651  static char *char_insert(char *p, char c Line 1663  static char *char_insert(char *p, char c
1663   if (c == 13)   if (c == 13)
1664   c = '\n'; // translate \r to \n   c = '\n'; // translate \r to \n
1665   sp = p; // remember addr of insert   sp = p; // remember addr of insert
1666   p = stupid_insert(p, c); // insert the char   p += 1 + stupid_insert(p, c); // insert the char
1667  #if ENABLE_FEATURE_VI_SETOPTS  #if ENABLE_FEATURE_VI_SETOPTS
1668   if (showmatch && strchr(")]}", *sp) != NULL) {   if (showmatch && strchr(")]}", *sp) != NULL) {
1669   showmatching(sp);   showmatching(sp);
1670   }   }
1671   if (autoindent && c == '\n') { // auto indent the new line   if (autoindent && c == '\n') { // auto indent the new line
1672   char *q;   char *q;
1673     size_t len;
1674   q = prev_line(p); // use prev line as templet   q = prev_line(p); // use prev line as template
1675   for (; isblank(*q); q++) {   len = strspn(q, " \t"); // space or tab
1676   p = stupid_insert(p, *q); // insert the char   if (len) {
1677     uintptr_t bias;
1678     bias = text_hole_make(p, len);
1679     p += bias;
1680     q += bias;
1681     memcpy(p, q, len);
1682     p += len;
1683   }   }
1684   }   }
1685  #endif  #endif
# Line 1669  static char *char_insert(char *p, char c Line 1687  static char *char_insert(char *p, char c
1687   return p;   return p;
1688  }  }
1689    
1690  static char *stupid_insert(char *p, char c) // stupidly insert the char c at 'p'  // might reallocate text[]! use p += stupid_insert(p, ...),
1691  {  // and be careful to not use pointers into potentially freed text[]!
1692   p = text_hole_make(p, 1);  static uintptr_t stupid_insert(char *p, char c) // stupidly insert the char c at 'p'
1693    {
1694     uintptr_t bias;
1695     bias = text_hole_make(p, 1);
1696     p += bias;
1697   *p = c;   *p = c;
1698   //file_modified++; - done by text_hole_make()   //file_modified++; - done by text_hole_make()
1699   return p + 1;   return bias;
1700  }  }
1701    
1702  static int find_range(char **start, char **stop, char c)  static int find_range(char **start, char **stop, char c)
# Line 1762  static int st_test(char *p, int type, in Line 1784  static int st_test(char *p, int type, in
1784    
1785   if (type == S_BEFORE_WS) {   if (type == S_BEFORE_WS) {
1786   c = ci;   c = ci;
1787   test = ((!isspace(c)) || c == '\n');   test = (!isspace(c) || c == '\n');
1788   }   }
1789   if (type == S_TO_WS) {   if (type == S_TO_WS) {
1790   c = c0;   c = c0;
1791   test = ((!isspace(c)) || c == '\n');   test = (!isspace(c) || c == '\n');
1792   }   }
1793   if (type == S_OVER_WS) {   if (type == S_OVER_WS) {
1794   c = c0;   c = c0;
1795   test = ((isspace(c)));   test = isspace(c);
1796   }   }
1797   if (type == S_END_PUNCT) {   if (type == S_END_PUNCT) {
1798   c = ci;   c = ci;
1799   test = ((ispunct(c)));   test = ispunct(c);
1800   }   }
1801   if (type == S_END_ALNUM) {   if (type == S_END_ALNUM) {
1802   c = ci;   c = ci;
1803   test = ((isalnum(c)) || c == '_');   test = (isalnum(c) || c == '_');
1804   }   }
1805   *tested = c;   *tested = c;
1806   return test;   return test;
# Line 1854  static void showmatching(char *p) Line 1876  static void showmatching(char *p)
1876  }  }
1877  #endif /* FEATURE_VI_SETOPTS */  #endif /* FEATURE_VI_SETOPTS */
1878    
1879  //  open a hole in text[]  // open a hole in text[]
1880  static char *text_hole_make(char *p, int size) // at "p", make a 'size' byte hole  // might reallocate text[]! use p += text_hole_make(p, ...),
1881    // and be careful to not use pointers into potentially freed text[]!
1882    static uintptr_t text_hole_make(char *p, int size) // at "p", make a 'size' byte hole
1883  {  {
1884     uintptr_t bias = 0;
1885    
1886   if (size <= 0)   if (size <= 0)
1887   return p;   return bias;
1888   end += size; // adjust the new END   end += size; // adjust the new END
1889   if (end >= (text + text_size)) {   if (end >= (text + text_size)) {
1890   char *new_text;   char *new_text;
1891   text_size += end - (text + text_size) + 10240;   text_size += end - (text + text_size) + 10240;
1892   new_text = xrealloc(text, text_size);   new_text = xrealloc(text, text_size);
1893   screenbegin = new_text + (screenbegin - text);   bias = (new_text - text);
1894   dot         = new_text + (dot         - text);   screenbegin += bias;
1895   end         = new_text + (end         - text);   dot         += bias;
1896   p           = new_text + (p           - text);   end         += bias;
1897     p           += bias;
1898   text = new_text;   text = new_text;
1899   }   }
1900   memmove(p + size, p, end - size - p);   memmove(p + size, p, end - size - p);
1901   memset(p, ' ', size); // clear new hole   memset(p, ' ', size); // clear new hole
1902   file_modified++;   file_modified++;
1903   return p;   return bias;
1904  }  }
1905    
1906  //  close a hole in text[]  //  close a hole in text[]
# Line 2006  static void end_cmd_q(void) Line 2033  static void end_cmd_q(void)
2033  #if ENABLE_FEATURE_VI_YANKMARK \  #if ENABLE_FEATURE_VI_YANKMARK \
2034   || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) \   || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) \
2035   || ENABLE_FEATURE_VI_CRASHME   || ENABLE_FEATURE_VI_CRASHME
2036  static char *string_insert(char *p, char *s) // insert the string at 'p'  // might reallocate text[]! use p += string_insert(p, ...),
2037    // and be careful to not use pointers into potentially freed text[]!
2038    static uintptr_t string_insert(char *p, const char *s) // insert the string at 'p'
2039  {  {
2040   int cnt, i;   uintptr_t bias;
2041     int i;
2042    
2043   i = strlen(s);   i = strlen(s);
2044   text_hole_make(p, i);   bias = text_hole_make(p, i);
2045   strncpy(p, s, i);   p += bias;
2046   for (cnt = 0; *s != '\0'; s++) {   memcpy(p, s, i);
  if (*s == '\n')  
  cnt++;  
  }  
2047  #if ENABLE_FEATURE_VI_YANKMARK  #if ENABLE_FEATURE_VI_YANKMARK
2048   status_line("Put %d lines (%d chars) from [%c]", cnt, i, what_reg());   {
2049     int cnt;
2050     for (cnt = 0; *s != '\0'; s++) {
2051     if (*s == '\n')
2052     cnt++;
2053     }
2054     status_line("Put %d lines (%d chars) from [%c]", cnt, i, what_reg());
2055     }
2056  #endif  #endif
2057   return p;   return bias;
2058  }  }
2059  #endif  #endif
2060    
2061  #if ENABLE_FEATURE_VI_YANKMARK  #if ENABLE_FEATURE_VI_YANKMARK
2062  static char *text_yank(char *p, char *q, int dest) // copy text into a register  static char *text_yank(char *p, char *q, int dest) // copy text into a register
2063  {  {
2064   char *t;   int cnt = q - p;
2065   int cnt;   if (cnt < 0) { // they are backwards- reverse them
2066     p = q;
2067   if (q < p) { // they are backwards- reverse them   cnt = -cnt;
  t = q;  
  q = p;  
  p = t;  
2068   }   }
2069   cnt = q - p + 1;   free(reg[dest]); //  if already a yank register, free it
2070   t = reg[dest];   reg[dest] = xstrndup(p, cnt + 1);
  free(t); //  if already a yank register, free it  
  t = xmalloc(cnt + 1); // get a new register  
  memset(t, '\0', cnt + 1); // clear new text[]  
  strncpy(t, p, cnt); // copy text[] into bufer  
  reg[dest] = t;  
2071   return p;   return p;
2072  }  }
2073    
# Line 2111  static void rawmode(void) Line 2137  static void rawmode(void)
2137    
2138  static void cookmode(void)  static void cookmode(void)
2139  {  {
2140   fflush(stdout);   fflush_all();
2141   tcsetattr_stdin_TCSANOW(&term_orig);   tcsetattr_stdin_TCSANOW(&term_orig);
2142  }  }
2143    
# Line 2162  static void catch_sig(int sig) Line 2188  static void catch_sig(int sig)
2188  }  }
2189  #endif /* FEATURE_VI_USE_SIGNALS */  #endif /* FEATURE_VI_USE_SIGNALS */
2190    
2191  static int mysleep(int hund) // sleep for 'h' 1/100 seconds  static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready
2192  {  {
2193   struct pollfd pfd[1];   struct pollfd pfd[1];
2194    
2195   pfd[0].fd = 0;   pfd[0].fd = STDIN_FILENO;
2196   pfd[0].events = POLLIN;   pfd[0].events = POLLIN;
2197   return safe_poll(pfd, 1, hund*10) > 0;   return safe_poll(pfd, 1, hund*10) > 0;
2198  }  }
# Line 2176  static int readit(void) // read (maybe c Line 2202  static int readit(void) // read (maybe c
2202  {  {
2203   int c;   int c;
2204    
2205   fflush(stdout);   fflush_all();
2206   c = read_key(STDIN_FILENO, &chars_to_parse, readbuffer);   c = read_key(STDIN_FILENO, readbuffer);
2207   if (c == -1) { // EOF/error   if (c == -1) { // EOF/error
2208   go_bottom_and_clear_to_eol();   go_bottom_and_clear_to_eol();
2209   cookmode(); // terminal to "cooked"   cookmode(); // terminal to "cooked"
# Line 2273  static int file_size(const char *fn) // Line 2299  static int file_size(const char *fn) //
2299   return cnt;   return cnt;
2300  }  }
2301    
2302  static int file_insert(const char *fn, char *p  // might reallocate text[]!
2303   USE_FEATURE_VI_READONLY(, int update_ro_status))  static int file_insert(const char *fn, char *p, int update_ro_status)
2304  {  {
2305   int cnt = -1;   int cnt = -1;
2306   int fd, size;   int fd, size;
# Line 2302  static int file_insert(const char *fn, c Line 2328  static int file_insert(const char *fn, c
2328   goto fi0;   goto fi0;
2329   }   }
2330   size = statbuf.st_size;   size = statbuf.st_size;
2331   p = text_hole_make(p, size);   p += text_hole_make(p, size);
2332   cnt = safe_read(fd, p, size);   cnt = safe_read(fd, p, size);
2333   if (cnt < 0) {   if (cnt < 0) {
2334   status_line_bold("\"%s\" %s", fn, strerror(errno));   status_line_bold("\"%s\" %s", fn, strerror(errno));
# Line 2310  static int file_insert(const char *fn, c Line 2336  static int file_insert(const char *fn, c
2336   } else if (cnt < size) {   } else if (cnt < size) {
2337   // There was a partial read, shrink unused space text[]   // There was a partial read, shrink unused space text[]
2338   p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert   p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert
2339   status_line_bold("cannot read all of file \"%s\"", fn);   status_line_bold("can't read all of file \"%s\"", fn);
2340   }   }
2341   if (cnt >= size)   if (cnt >= size)
2342   file_modified++;   file_modified++;
# Line 2530  static void show_status_line(void) Line 2556  static void show_status_line(void)
2556   }   }
2557   place_cursor(crow, ccol, FALSE); // put cursor back in correct place   place_cursor(crow, ccol, FALSE); // put cursor back in correct place
2558   }   }
2559   fflush(stdout);   fflush_all();
2560  }  }
2561    
2562  //----- format the status buffer, the bottom line of screen ------  //----- format the status buffer, the bottom line of screen ------
# Line 2563  static void status_line(const char *form Line 2589  static void status_line(const char *form
2589  // copy s to buf, convert unprintable  // copy s to buf, convert unprintable
2590  static void print_literal(char *buf, const char *s)  static void print_literal(char *buf, const char *s)
2591  {  {
2592     char *d;
2593   unsigned char c;   unsigned char c;
  char b[2];  
2594    
  b[1] = '\0';  
2595   buf[0] = '\0';   buf[0] = '\0';
2596   if (!s[0])   if (!s[0])
2597   s = "(NULL)";   s = "(NULL)";
2598    
2599     d = buf;
2600   for (; *s; s++) {   for (; *s; s++) {
2601   int c_is_no_print;   int c_is_no_print;
2602    
2603   c = *s;   c = *s;
2604   c_is_no_print = (c & 0x80) && !Isprint(c);   c_is_no_print = (c & 0x80) && !Isprint(c);
2605   if (c_is_no_print) {   if (c_is_no_print) {
2606   strcat(buf, SOn);   strcpy(d, SOn);
2607     d += sizeof(SOn)-1;
2608   c = '.';   c = '.';
2609   }   }
2610   if (c < ' ' || c == 127) {   if (c < ' ' || c == 0x7f) {
2611   strcat(buf, "^");   *d++ = '^';
2612   if (c == 127)   c |= '@'; /* 0x40 */
2613     if (c == 0x7f)
2614   c = '?';   c = '?';
  else  
  c += '@';  
2615   }   }
2616   b[0] = c;   *d++ = c;
2617   strcat(buf, b);   *d = '\0';
2618   if (c_is_no_print)   if (c_is_no_print) {
2619   strcat(buf, SOs);   strcpy(d, SOs);
2620   if (*s == '\n')   d += sizeof(SOs)-1;
2621   strcat(buf, "$");   }
2622   if (strlen(buf) > MAX_INPUT_LEN - 10) // paranoia   if (*s == '\n') {
2623     *d++ = '$';
2624     *d = '\0';
2625     }
2626     if (d - buf > MAX_INPUT_LEN - 10) // paranoia
2627   break;   break;
2628   }   }
2629  }  }
# Line 2954  static void do_cmd(int c) Line 2985  static void do_cmd(int c)
2985   //case '`': // `-   //case '`': // `-
2986   //case 'u': // u- FIXME- there is no undo   //case 'u': // u- FIXME- there is no undo
2987   //case 'v': // v-   //case 'v': // v-
2988   default: // unrecognised command   default: // unrecognized command
2989   buf[0] = c;   buf[0] = c;
2990   buf[1] = '\0';   buf[1] = '\0';
  if (c < ' ') {  
  buf[0] = '^';  
  buf[1] = c + '@';  
  buf[2] = '\0';  
  }  
2991   not_implemented(buf);   not_implemented(buf);
2992   end_cmd_q(); // stop adding to q   end_cmd_q(); // stop adding to q
2993   case 0x00: // nul- ignore   case 0x00: // nul- ignore
# Line 3082  static void do_cmd(int c) Line 3108  static void do_cmd(int c)
3108   case 'P': // P- Put register before   case 'P': // P- Put register before
3109   case 'p': // p- put register after   case 'p': // p- put register after
3110   p = reg[YDreg];   p = reg[YDreg];
3111   if (p == 0) {   if (p == NULL) {
3112   status_line_bold("Nothing in register %c", what_reg());   status_line_bold("Nothing in register %c", what_reg());
3113   break;   break;
3114   }   }
# Line 3103  static void do_cmd(int c) Line 3129  static void do_cmd(int c)
3129   if (c == 'p')   if (c == 'p')
3130   dot_right(); // move to right, can move to NL   dot_right(); // move to right, can move to NL
3131   }   }
3132   dot = string_insert(dot, p); // insert the string   string_insert(dot, p); // insert the string
3133   end_cmd_q(); // stop adding to q   end_cmd_q(); // stop adding to q
3134   break;   break;
3135   case 'U': // U- Undo; replace current line with original version   case 'U': // U- Undo; replace current line with original version
# Line 3111  static void do_cmd(int c) Line 3137  static void do_cmd(int c)
3137   p = begin_line(dot);   p = begin_line(dot);
3138   q = end_line(dot);   q = end_line(dot);
3139   p = text_hole_delete(p, q); // delete cur line   p = text_hole_delete(p, q); // delete cur line
3140   p = string_insert(p, reg[Ureg]); // insert orig line   p += string_insert(p, reg[Ureg]); // insert orig line
3141   dot = p;   dot = p;
3142   dot_skip_over_ws();   dot_skip_over_ws();
3143   }   }
# Line 3299  static void do_cmd(int c) Line 3325  static void do_cmd(int c)
3325   cnt = strlen(p);   cnt = strlen(p);
3326   if (cnt <= 0)   if (cnt <= 0)
3327   break;   break;
3328   if (strncasecmp(p, "quit", cnt) == 0   if (strncmp(p, "quit", cnt) == 0
3329   || strncasecmp(p, "q!", cnt) == 0   // delete lines   || strncmp(p, "q!", cnt) == 0   // delete lines
3330   ) {   ) {
3331   if (file_modified && p[1] != '!') {   if (file_modified && p[1] != '!') {
3332   status_line_bold("No write since last change (:quit! overrides)");   status_line_bold("No write since last change (:quit! overrides)");
3333   } else {   } else {
3334   editing = 0;   editing = 0;
3335   }   }
3336   } else if (strncasecmp(p, "write", cnt) == 0   } else if (strncmp(p, "write", cnt) == 0
3337          || strncasecmp(p, "wq", cnt) == 0          || strncmp(p, "wq", cnt) == 0
3338          || strncasecmp(p, "wn", cnt) == 0          || strncmp(p, "wn", cnt) == 0
3339          || strncasecmp(p, "x", cnt) == 0          || (p[0] == 'x' && !p[1])
3340   ) {   ) {
3341   cnt = file_write(current_filename, text, end - 1);   cnt = file_write(current_filename, text, end - 1);
3342   if (cnt < 0) {   if (cnt < 0) {
# Line 3326  static void do_cmd(int c) Line 3352  static void do_cmd(int c)
3352   editing = 0;   editing = 0;
3353   }   }
3354   }   }
3355   } else if (strncasecmp(p, "file", cnt) == 0) {   } else if (strncmp(p, "file", cnt) == 0) {
3356   last_status_cksum = 0; // force status update   last_status_cksum = 0; // force status update
3357   } else if (sscanf(p, "%d", &j) > 0) {   } else if (sscanf(p, "%d", &j) > 0) {
3358   dot = find_line(j); // go to line # j   dot = find_line(j); // go to line # j
3359   dot_skip_over_ws();   dot_skip_over_ws();
3360   } else { // unrecognised cmd   } else { // unrecognized cmd
3361   not_implemented(p);   not_implemented(p);
3362   }   }
3363  #endif /* !FEATURE_VI_COLON */  #endif /* !FEATURE_VI_COLON */
# Line 3822  static void crash_dummy() Line 3848  static void crash_dummy()
3848   cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL";   cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL";
3849    
3850   // is there already a command running?   // is there already a command running?
3851   if (chars_to_parse > 0)   if (readbuffer[0] > 0)
3852   goto cd1;   goto cd1;
3853   cd0:   cd0:
3854   startrbi = rbi = 0;   readbuffer[0] = 'X';
3855     startrbi = rbi = 1;
3856   sleeptime = 0;          // how long to pause between commands   sleeptime = 0;          // how long to pause between commands
3857   memset(readbuffer, '\0', sizeof(readbuffer));   memset(readbuffer, '\0', sizeof(readbuffer));
3858   // generate a command by percentages   // generate a command by percentages
# Line 3899  static void crash_dummy() Line 3926  static void crash_dummy()
3926   }   }
3927   strcat(readbuffer, "\033");   strcat(readbuffer, "\033");
3928   }   }
3929   chars_to_parse = strlen(readbuffer);   readbuffer[0] = strlen(readbuffer + 1);
3930   cd1:   cd1:
3931   totalcmds++;   totalcmds++;
3932   if (sleeptime > 0)   if (sleeptime > 0)
# Line 3937  static void crash_test() Line 3964  static void crash_test()
3964   if (msg[0]) {   if (msg[0]) {
3965   printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",   printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
3966   totalcmds, last_input_char, msg, SOs, SOn);   totalcmds, last_input_char, msg, SOs, SOn);
3967   fflush(stdout);   fflush_all();
3968   while (safe_read(STDIN_FILENO, d, 1) > 0) {   while (safe_read(STDIN_FILENO, d, 1) > 0) {
3969   if (d[0] == '\n' || d[0] == '\r')   if (d[0] == '\n' || d[0] == '\r')
3970   break;   break;

Legend:
Removed from v.983  
changed lines
  Added in v.984