diff options
-rw-r--r-- | editors/vi.c | 359 |
1 files changed, 166 insertions, 193 deletions
diff --git a/editors/vi.c b/editors/vi.c index fcd139310..2abaf88b8 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -95,7 +95,7 @@ enum { | |||
95 | /* busybox build system provides that, but it's better */ | 95 | /* busybox build system provides that, but it's better */ |
96 | /* to audit and fix the source */ | 96 | /* to audit and fix the source */ |
97 | 97 | ||
98 | static int vi_setops; | 98 | static smallint vi_setops; |
99 | #define VI_AUTOINDENT 1 | 99 | #define VI_AUTOINDENT 1 |
100 | #define VI_SHOWMATCH 2 | 100 | #define VI_SHOWMATCH 2 |
101 | #define VI_IGNORECASE 4 | 101 | #define VI_IGNORECASE 4 |
@@ -122,7 +122,7 @@ static char *status_buffer; // mesages to the user | |||
122 | static int have_status_msg; // is default edit status needed? | 122 | static int have_status_msg; // is default edit status needed? |
123 | // [don't make smallint!] | 123 | // [don't make smallint!] |
124 | static int last_status_cksum; // hash of current status line | 124 | static int last_status_cksum; // hash of current status line |
125 | static char *cfn; // previous, current, and next file name | 125 | static char *current_filename; // current file name |
126 | //static char *text, *end; // pointers to the user data in memory | 126 | //static char *text, *end; // pointers to the user data in memory |
127 | static char *screen; // pointer to the virtual screen buffer | 127 | static char *screen; // pointer to the virtual screen buffer |
128 | static int screensize; // and its size | 128 | static int screensize; // and its size |
@@ -134,8 +134,18 @@ static char last_input_char; // last char read from user | |||
134 | static char last_forward_char; // last char searched for with 'f' | 134 | static char last_forward_char; // last char searched for with 'f' |
135 | 135 | ||
136 | #if ENABLE_FEATURE_VI_READONLY | 136 | #if ENABLE_FEATURE_VI_READONLY |
137 | static smallint vi_readonly, readonly; | 137 | //static smallint vi_readonly, readonly; |
138 | static smallint readonly_mode = 0; | ||
139 | #define SET_READONLY_FILE(flags) ((flags) |= 0x01) | ||
140 | #define SET_READONLY_MODE(flags) ((flags) |= 0x02) | ||
141 | #define UNSET_READONLY_FILE(flags) ((flags) &= 0xfe) | ||
142 | #else | ||
143 | #define readonly_mode 0 | ||
144 | #define SET_READONLY_FILE(flags) | ||
145 | #define SET_READONLY_MODE(flags) | ||
146 | #define UNSET_READONLY_FILE(flags) | ||
138 | #endif | 147 | #endif |
148 | |||
139 | #if ENABLE_FEATURE_VI_DOT_CMD | 149 | #if ENABLE_FEATURE_VI_DOT_CMD |
140 | static smallint adding2q; // are we currently adding user input to q | 150 | static smallint adding2q; // are we currently adding user input to q |
141 | static char *last_modifying_cmd; // last modifying cmd for "." | 151 | static char *last_modifying_cmd; // last modifying cmd for "." |
@@ -158,6 +168,7 @@ static char *last_search_pattern; // last pattern from a '/' or '?' search | |||
158 | struct globals { | 168 | struct globals { |
159 | /* many references - keep near the top of globals */ | 169 | /* many references - keep near the top of globals */ |
160 | char *text, *end; // pointers to the user data in memory | 170 | char *text, *end; // pointers to the user data in memory |
171 | int text_size; // size of the allocated buffer | ||
161 | char *dot; // where all the action takes place | 172 | char *dot; // where all the action takes place |
162 | #if ENABLE_FEATURE_VI_YANKMARK | 173 | #if ENABLE_FEATURE_VI_YANKMARK |
163 | char *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 | 174 | char *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 |
@@ -176,6 +187,7 @@ struct globals { | |||
176 | }; | 187 | }; |
177 | #define G (*ptr_to_globals) | 188 | #define G (*ptr_to_globals) |
178 | #define text (G.text ) | 189 | #define text (G.text ) |
190 | #define text_size (G.text_size ) | ||
179 | #define end (G.end ) | 191 | #define end (G.end ) |
180 | #define dot (G.dot ) | 192 | #define dot (G.dot ) |
181 | #define reg (G.reg ) | 193 | #define reg (G.reg ) |
@@ -189,8 +201,10 @@ struct globals { | |||
189 | #define term_vi (G.term_vi ) | 201 | #define term_vi (G.term_vi ) |
190 | #define initial_cmds (G.initial_cmds ) | 202 | #define initial_cmds (G.initial_cmds ) |
191 | 203 | ||
204 | static int init_text_buffer(char *); // init from file or create new | ||
192 | static void edit_file(char *); // edit one file | 205 | static void edit_file(char *); // edit one file |
193 | static void do_cmd(char); // execute a command | 206 | static void do_cmd(char); // execute a command |
207 | static int next_tabstop(int); | ||
194 | static void sync_cursor(char *, int *, int *); // synchronize the screen cursor to dot | 208 | static void sync_cursor(char *, int *, int *); // synchronize the screen cursor to dot |
195 | static char *begin_line(char *); // return pointer to cur line B-o-l | 209 | static char *begin_line(char *); // return pointer to cur line B-o-l |
196 | static char *end_line(char *); // return pointer to cur line E-o-l | 210 | static char *end_line(char *); // return pointer to cur line E-o-l |
@@ -200,7 +214,6 @@ static char *end_screen(void); // get pointer to last char on screen | |||
200 | static int count_lines(char *, char *); // count line from start to stop | 214 | static int count_lines(char *, char *); // count line from start to stop |
201 | static char *find_line(int); // find begining of line #li | 215 | static char *find_line(int); // find begining of line #li |
202 | static char *move_to_col(char *, int); // move "p" to column l | 216 | static char *move_to_col(char *, int); // move "p" to column l |
203 | static int isblnk(char); // is the char a blank or tab | ||
204 | static void dot_left(void); // move dot left- dont leave line | 217 | static void dot_left(void); // move dot left- dont leave line |
205 | static void dot_right(void); // move dot right- dont leave line | 218 | static void dot_right(void); // move dot right- dont leave line |
206 | static void dot_begin(void); // move dot to B-o-l | 219 | static void dot_begin(void); // move dot to B-o-l |
@@ -212,7 +225,6 @@ static void dot_skip_over_ws(void); // move dot pat WS | |||
212 | static void dot_delete(void); // delete the char at 'dot' | 225 | static void dot_delete(void); // delete the char at 'dot' |
213 | static char *bound_dot(char *); // make sure text[0] <= P < "end" | 226 | static char *bound_dot(char *); // make sure text[0] <= P < "end" |
214 | static char *new_screen(int, int); // malloc virtual screen memory | 227 | static char *new_screen(int, int); // malloc virtual screen memory |
215 | static char *new_text(int); // malloc memory for text[] buffer | ||
216 | static char *char_insert(char *, char); // insert the char c at 'p' | 228 | static char *char_insert(char *, char); // insert the char c at 'p' |
217 | static char *stupid_insert(char *, char); // stupidly insert the char c at 'p' | 229 | static char *stupid_insert(char *, char); // stupidly insert the char c at 'p' |
218 | static char find_range(char **, char **, char); // return pointers for an object | 230 | static char find_range(char **, char **, char); // return pointers for an object |
@@ -229,11 +241,10 @@ static int mysleep(int); // sleep for 'h' 1/100 seconds | |||
229 | static char readit(void); // read (maybe cursor) key from stdin | 241 | static char readit(void); // read (maybe cursor) key from stdin |
230 | static char get_one_char(void); // read 1 char from stdin | 242 | static char get_one_char(void); // read 1 char from stdin |
231 | static int file_size(const char *); // what is the byte size of "fn" | 243 | static int file_size(const char *); // what is the byte size of "fn" |
232 | static int file_insert(char *, char *); | ||
233 | #if ENABLE_FEATURE_VI_READONLY | 244 | #if ENABLE_FEATURE_VI_READONLY |
234 | static void update_ro_status(const char *); | 245 | static int file_insert(const char *, char *, int); |
235 | #else | 246 | #else |
236 | static ALWAYS_INLINE void update_ro_status(const char *name) {} | 247 | static int file_insert(const char *, char *); |
237 | #endif | 248 | #endif |
238 | static int file_write(char *, char *, char *); | 249 | static int file_write(char *, char *, char *); |
239 | static void place_cursor(int, int, int); | 250 | static void place_cursor(int, int, int); |
@@ -305,9 +316,6 @@ int vi_main(int argc, char **argv) | |||
305 | int c; | 316 | int c; |
306 | RESERVE_CONFIG_BUFFER(STATUS_BUFFER, STATUS_BUFFER_LEN); | 317 | RESERVE_CONFIG_BUFFER(STATUS_BUFFER, STATUS_BUFFER_LEN); |
307 | 318 | ||
308 | #if ENABLE_FEATURE_VI_YANKMARK | ||
309 | int i; | ||
310 | #endif | ||
311 | #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME | 319 | #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME |
312 | my_pid = getpid(); | 320 | my_pid = getpid(); |
313 | #endif | 321 | #endif |
@@ -320,19 +328,18 @@ int vi_main(int argc, char **argv) | |||
320 | 328 | ||
321 | status_buffer = STATUS_BUFFER; | 329 | status_buffer = STATUS_BUFFER; |
322 | last_status_cksum = 0; | 330 | last_status_cksum = 0; |
331 | text = NULL; | ||
323 | 332 | ||
324 | #if ENABLE_FEATURE_VI_READONLY | 333 | if (ENABLE_FEATURE_VI_READONLY && strncmp(argv[0], "view", 4) == 0) { |
325 | vi_readonly = readonly = FALSE; | 334 | SET_READONLY_MODE(readonly_mode); |
326 | if (strncmp(argv[0], "view", 4) == 0) { | ||
327 | readonly = TRUE; | ||
328 | vi_readonly = TRUE; | ||
329 | } | 335 | } |
330 | #endif | 336 | |
331 | vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE | VI_ERR_METHOD; | 337 | vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE | VI_ERR_METHOD; |
332 | #if ENABLE_FEATURE_VI_YANKMARK | 338 | #if ENABLE_FEATURE_VI_YANKMARK |
333 | for (i = 0; i < 28; i++) { | 339 | //for (i = 0; i < 28; i++) { |
334 | reg[i] = 0; | 340 | // reg[i] = 0; |
335 | } // init the yank regs | 341 | //} // init the yank regs |
342 | memset(reg, 0, sizeof(reg)); | ||
336 | #endif | 343 | #endif |
337 | #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK | 344 | #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK |
338 | modifying_cmds = (char *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[] | 345 | modifying_cmds = (char *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[] |
@@ -357,8 +364,7 @@ int vi_main(int argc, char **argv) | |||
357 | #endif | 364 | #endif |
358 | #if ENABLE_FEATURE_VI_READONLY | 365 | #if ENABLE_FEATURE_VI_READONLY |
359 | case 'R': // Read-only flag | 366 | case 'R': // Read-only flag |
360 | readonly = TRUE; | 367 | SET_READONLY_MODE(readonly_mode); |
361 | vi_readonly = TRUE; | ||
362 | break; | 368 | break; |
363 | #endif | 369 | #endif |
364 | //case 'r': // recover flag- ignore- we don't use tmp file | 370 | //case 'r': // recover flag- ignore- we don't use tmp file |
@@ -384,14 +390,10 @@ int vi_main(int argc, char **argv) | |||
384 | 390 | ||
385 | //----- This is the main file handling loop -------------- | 391 | //----- This is the main file handling loop -------------- |
386 | if (optind >= argc) { | 392 | if (optind >= argc) { |
387 | editing = 1; // 0= exit, 1= one file, 2 = multiple files | ||
388 | edit_file(0); | 393 | edit_file(0); |
389 | } else { | 394 | } else { |
390 | for (; optind < argc; optind++) { | 395 | for (; optind < argc; optind++) { |
391 | editing = 1; // 0=exit, 1=one file, 2+ = many files | 396 | edit_file(argv[optind]); |
392 | free(cfn); | ||
393 | cfn = xstrdup(argv[optind]); | ||
394 | edit_file(cfn); | ||
395 | } | 397 | } |
396 | } | 398 | } |
397 | //----------------------------------------------------------- | 399 | //----------------------------------------------------------- |
@@ -399,10 +401,45 @@ int vi_main(int argc, char **argv) | |||
399 | return 0; | 401 | return 0; |
400 | } | 402 | } |
401 | 403 | ||
404 | /* read text from file or create an empty buf */ | ||
405 | /* will also update current_filename */ | ||
406 | static int init_text_buffer(char *fn) | ||
407 | { | ||
408 | int rc; | ||
409 | int size = file_size(fn); // file size. -1 means does not exist. | ||
410 | |||
411 | /* allocate/reallocate text buffer */ | ||
412 | free(text); | ||
413 | text_size = size * 2; | ||
414 | if (text_size < 10240) | ||
415 | text_size = 10240; // have a minimum size for new files | ||
416 | screenbegin = dot = end = text = xzalloc(text_size); | ||
417 | |||
418 | if (fn != current_filename) { | ||
419 | free(current_filename); | ||
420 | current_filename = xstrdup(fn); | ||
421 | } | ||
422 | if (size < 0) { | ||
423 | // file dont exist. Start empty buf with dummy line | ||
424 | char_insert(text, '\n'); | ||
425 | rc = 0; | ||
426 | } else { | ||
427 | rc = file_insert(fn, text | ||
428 | USE_FEATURE_VI_READONLY(, 1)); | ||
429 | } | ||
430 | file_modified = 0; | ||
431 | last_file_modified = -1; | ||
432 | #if ENABLE_FEATURE_VI_YANKMARK | ||
433 | /* init the marks. */ | ||
434 | memset(mark, 0, sizeof(mark)); | ||
435 | #endif | ||
436 | return rc; | ||
437 | } | ||
438 | |||
402 | static void edit_file(char * fn) | 439 | static void edit_file(char * fn) |
403 | { | 440 | { |
404 | char c; | 441 | char c; |
405 | int cnt, size, ch; | 442 | int size; |
406 | 443 | ||
407 | #if ENABLE_FEATURE_VI_USE_SIGNALS | 444 | #if ENABLE_FEATURE_VI_USE_SIGNALS |
408 | int sig; | 445 | int sig; |
@@ -411,33 +448,19 @@ static void edit_file(char * fn) | |||
411 | static char *cur_line; | 448 | static char *cur_line; |
412 | #endif | 449 | #endif |
413 | 450 | ||
451 | editing = 1; // 0= exit, 1= one file, 2= multiple files | ||
414 | rawmode(); | 452 | rawmode(); |
415 | rows = 24; | 453 | rows = 24; |
416 | columns = 80; | 454 | columns = 80; |
417 | ch = -1; | 455 | size = 0; |
418 | if (ENABLE_FEATURE_VI_WIN_RESIZE) | 456 | if (ENABLE_FEATURE_VI_WIN_RESIZE) |
419 | get_terminal_width_height(0, &columns, &rows); | 457 | get_terminal_width_height(0, &columns, &rows); |
420 | new_screen(rows, columns); // get memory for virtual screen | 458 | new_screen(rows, columns); // get memory for virtual screen |
459 | init_text_buffer(fn); | ||
421 | 460 | ||
422 | cnt = file_size(fn); // file size | ||
423 | size = 2 * cnt; // 200% of file size | ||
424 | new_text(size); // get a text[] buffer | ||
425 | screenbegin = dot = end = text; | ||
426 | if (fn != 0) { | ||
427 | ch = file_insert(fn, text); | ||
428 | update_ro_status(fn); | ||
429 | } | ||
430 | if (ch < 1) { | ||
431 | char_insert(text, '\n'); // start empty buf with dummy line | ||
432 | } | ||
433 | file_modified = 0; | ||
434 | last_file_modified = -1; | ||
435 | #if ENABLE_FEATURE_VI_YANKMARK | 461 | #if ENABLE_FEATURE_VI_YANKMARK |
436 | YDreg = 26; // default Yank/Delete reg | 462 | YDreg = 26; // default Yank/Delete reg |
437 | Ureg = 27; // hold orig line for "U" cmd | 463 | Ureg = 27; // hold orig line for "U" cmd |
438 | for (cnt = 0; cnt < 28; cnt++) { | ||
439 | mark[cnt] = 0; | ||
440 | } // init the marks | ||
441 | mark[26] = mark[27] = text; // init "previous context" | 464 | mark[26] = mark[27] = text; // init "previous context" |
442 | #endif | 465 | #endif |
443 | 466 | ||
@@ -455,7 +478,6 @@ static void edit_file(char * fn) | |||
455 | } | 478 | } |
456 | #endif | 479 | #endif |
457 | 480 | ||
458 | editing = 1; | ||
459 | cmd_mode = 0; // 0=command 1=insert 2='R'eplace | 481 | cmd_mode = 0; // 0=command 1=insert 2='R'eplace |
460 | cmdcnt = 0; | 482 | cmdcnt = 0; |
461 | tabstop = 8; | 483 | tabstop = 8; |
@@ -468,7 +490,6 @@ static void edit_file(char * fn) | |||
468 | adding2q = 0; | 490 | adding2q = 0; |
469 | #endif | 491 | #endif |
470 | redraw(FALSE); // dont force every col re-draw | 492 | redraw(FALSE); // dont force every col re-draw |
471 | show_status_line(); | ||
472 | 493 | ||
473 | #if ENABLE_FEATURE_VI_COLON | 494 | #if ENABLE_FEATURE_VI_COLON |
474 | { | 495 | { |
@@ -612,7 +633,7 @@ static char *get_address(char *p, int *b, int *e) // get two colon addrs, if pre | |||
612 | { | 633 | { |
613 | //----- get the address' i.e., 1,3 'a,'b ----- | 634 | //----- get the address' i.e., 1,3 'a,'b ----- |
614 | // get FIRST addr, if present | 635 | // get FIRST addr, if present |
615 | while (isblnk(*p)) | 636 | while (isblank(*p)) |
616 | p++; // skip over leading spaces | 637 | p++; // skip over leading spaces |
617 | if (*p == '%') { // alias for 1,$ | 638 | if (*p == '%') { // alias for 1,$ |
618 | p++; | 639 | p++; |
@@ -621,17 +642,17 @@ static char *get_address(char *p, int *b, int *e) // get two colon addrs, if pre | |||
621 | goto ga0; | 642 | goto ga0; |
622 | } | 643 | } |
623 | p = get_one_address(p, b); | 644 | p = get_one_address(p, b); |
624 | while (isblnk(*p)) | 645 | while (isblank(*p)) |
625 | p++; | 646 | p++; |
626 | if (*p == ',') { // is there a address separator | 647 | if (*p == ',') { // is there a address separator |
627 | p++; | 648 | p++; |
628 | while (isblnk(*p)) | 649 | while (isblank(*p)) |
629 | p++; | 650 | p++; |
630 | // get SECOND addr, if present | 651 | // get SECOND addr, if present |
631 | p = get_one_address(p, e); | 652 | p = get_one_address(p, e); |
632 | } | 653 | } |
633 | ga0: | 654 | ga0: |
634 | while (isblnk(*p)) | 655 | while (isblank(*p)) |
635 | p++; // skip over trailing spaces | 656 | p++; // skip over trailing spaces |
636 | return p; | 657 | return p; |
637 | } | 658 | } |
@@ -686,7 +707,7 @@ static void colon(char * buf) | |||
686 | q = text; // assume 1,$ for the range | 707 | q = text; // assume 1,$ for the range |
687 | r = end - 1; | 708 | r = end - 1; |
688 | li = count_lines(text, end - 1); | 709 | li = count_lines(text, end - 1); |
689 | fn = cfn; // default to current file | 710 | fn = current_filename; // default to current file |
690 | memset(cmd, '\0', MAX_LINELEN); // clear cmd[] | 711 | memset(cmd, '\0', MAX_LINELEN); // clear cmd[] |
691 | memset(args, '\0', MAX_LINELEN); // clear args[] | 712 | memset(args, '\0', MAX_LINELEN); // clear args[] |
692 | 713 | ||
@@ -704,7 +725,7 @@ static void colon(char * buf) | |||
704 | *buf1++ = *buf++; | 725 | *buf1++ = *buf++; |
705 | } | 726 | } |
706 | // get any ARGuments | 727 | // get any ARGuments |
707 | while (isblnk(*buf)) | 728 | while (isblank(*buf)) |
708 | buf++; | 729 | buf++; |
709 | strcpy(args, buf); | 730 | strcpy(args, buf); |
710 | buf1 = last_char_is(cmd, '!'); | 731 | buf1 = last_char_is(cmd, '!'); |
@@ -738,12 +759,15 @@ static void colon(char * buf) | |||
738 | } | 759 | } |
739 | #if ENABLE_FEATURE_ALLOW_EXEC | 760 | #if ENABLE_FEATURE_ALLOW_EXEC |
740 | else if (strncmp(cmd, "!", 1) == 0) { // run a cmd | 761 | else if (strncmp(cmd, "!", 1) == 0) { // run a cmd |
762 | int retcode; | ||
741 | // :!ls run the <cmd> | 763 | // :!ls run the <cmd> |
742 | alarm(0); // wait for input- no alarms | 764 | alarm(0); // wait for input- no alarms |
743 | place_cursor(rows - 1, 0, FALSE); // go to Status line | 765 | place_cursor(rows - 1, 0, FALSE); // go to Status line |
744 | clear_to_eol(); // clear the line | 766 | clear_to_eol(); // clear the line |
745 | cookmode(); | 767 | cookmode(); |
746 | system(orig_buf + 1); // run the cmd | 768 | retcode = system(orig_buf + 1); // run the cmd |
769 | if (retcode) | ||
770 | printf("\nshell returned %i\n\n", retcode); | ||
747 | rawmode(); | 771 | rawmode(); |
748 | Hit_Return(); // let user see results | 772 | Hit_Return(); // let user see results |
749 | alarm(3); // done waiting for input | 773 | alarm(3); // done waiting for input |
@@ -762,9 +786,6 @@ static void colon(char * buf) | |||
762 | dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines | 786 | dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines |
763 | dot_skip_over_ws(); | 787 | dot_skip_over_ws(); |
764 | } else if (strncasecmp(cmd, "edit", i) == 0) { // Edit a file | 788 | } else if (strncasecmp(cmd, "edit", i) == 0) { // Edit a file |
765 | int sr; | ||
766 | struct stat st_buf; | ||
767 | sr= 0; | ||
768 | // don't edit, if the current file has been modified | 789 | // don't edit, if the current file has been modified |
769 | if (file_modified && ! useforce) { | 790 | if (file_modified && ! useforce) { |
770 | psbs("No write since last change (:edit! overrides)"); | 791 | psbs("No write since last change (:edit! overrides)"); |
@@ -773,58 +794,18 @@ static void colon(char * buf) | |||
773 | if (args[0]) { | 794 | if (args[0]) { |
774 | // the user supplied a file name | 795 | // the user supplied a file name |
775 | fn = args; | 796 | fn = args; |
776 | } else if (cfn && cfn[0]) { | 797 | } else if (current_filename && current_filename[0]) { |
777 | // no user supplied name- use the current filename | 798 | // no user supplied name- use the current filename |
778 | fn = cfn; | 799 | // fn = current_filename; was set by default |
779 | goto vc5; | ||
780 | } else { | 800 | } else { |
781 | // no user file name, no current name- punt | 801 | // no user file name, no current name- punt |
782 | psbs("No current filename"); | 802 | psbs("No current filename"); |
783 | goto vc1; | 803 | goto vc1; |
784 | } | 804 | } |
785 | 805 | ||
786 | // see if file exists- if not, its just a new file request | 806 | if (init_text_buffer(fn) < 0) |
787 | sr = stat(fn, &st_buf); | 807 | goto vc1; |
788 | if (sr < 0) { | ||
789 | // This is just a request for a new file creation. | ||
790 | // The file_insert below will fail but we get | ||
791 | // an empty buffer with a file name. Then the "write" | ||
792 | // command can do the create. | ||
793 | } else { | ||
794 | if ((st_buf.st_mode & S_IFREG) == 0) { | ||
795 | // This is not a regular file | ||
796 | psbs("\"%s\" is not a regular file", fn); | ||
797 | goto vc1; | ||
798 | } | ||
799 | if ((st_buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) { | ||
800 | // dont have any read permissions | ||
801 | psbs("\"%s\" is not readable", fn); | ||
802 | goto vc1; | ||
803 | } | ||
804 | } | ||
805 | |||
806 | // There is a read-able regular file | ||
807 | // make this the current file | ||
808 | q = xstrdup(fn); // save the cfn | ||
809 | free(cfn); // free the old name | ||
810 | cfn = q; // remember new cfn | ||
811 | |||
812 | vc5: | ||
813 | // delete all the contents of text[] | ||
814 | new_text(2 * file_size(fn)); | ||
815 | screenbegin = dot = end = text; | ||
816 | |||
817 | // insert new file | ||
818 | ch = file_insert(fn, text); | ||
819 | update_ro_status(fn); | ||
820 | 808 | ||
821 | if (ch < 1) { | ||
822 | // start empty buf with dummy line | ||
823 | char_insert(text, '\n'); | ||
824 | ch = 1; | ||
825 | } | ||
826 | file_modified = 0; | ||
827 | last_file_modified = -1; | ||
828 | #if ENABLE_FEATURE_VI_YANKMARK | 809 | #if ENABLE_FEATURE_VI_YANKMARK |
829 | if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { | 810 | if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { |
830 | free(reg[Ureg]); // free orig line reg- for 'U' | 811 | free(reg[Ureg]); // free orig line reg- for 'U' |
@@ -834,21 +815,16 @@ static void colon(char * buf) | |||
834 | free(reg[YDreg]); // free default yank/delete register | 815 | free(reg[YDreg]); // free default yank/delete register |
835 | reg[YDreg]= 0; | 816 | reg[YDreg]= 0; |
836 | } | 817 | } |
837 | for (li = 0; li < 28; li++) { | ||
838 | mark[li] = 0; | ||
839 | } // init the marks | ||
840 | #endif | 818 | #endif |
841 | // how many lines in text[]? | 819 | // how many lines in text[]? |
842 | li = count_lines(text, end - 1); | 820 | li = count_lines(text, end - 1); |
843 | psb("\"%s\"%s" | 821 | psb("\"%s\"%s" |
844 | #if ENABLE_FEATURE_VI_READONLY | 822 | USE_FEATURE_VI_READONLY("%s") |
845 | "%s" | 823 | " %dL, %dC", current_filename, |
846 | #endif | 824 | (file_size(fn) < 0 ? " [New file]" : ""), |
847 | " %dL, %dC", cfn, | 825 | USE_FEATURE_VI_READONLY( |
848 | (sr < 0 ? " [New file]" : ""), | 826 | ((readonly_mode) ? " [Readonly]" : ""), |
849 | #if ENABLE_FEATURE_VI_READONLY | 827 | ) |
850 | ((vi_readonly || readonly) ? " [Read only]" : ""), | ||
851 | #endif | ||
852 | li, ch); | 828 | li, ch); |
853 | } else if (strncasecmp(cmd, "file", i) == 0) { // what File is this | 829 | } else if (strncasecmp(cmd, "file", i) == 0) { // what File is this |
854 | if (b != -1 || e != -1) { | 830 | if (b != -1 || e != -1) { |
@@ -857,8 +833,8 @@ static void colon(char * buf) | |||
857 | } | 833 | } |
858 | if (args[0]) { | 834 | if (args[0]) { |
859 | // user wants a new filename | 835 | // user wants a new filename |
860 | free(cfn); | 836 | free(current_filename); |
861 | cfn = xstrdup(args); | 837 | current_filename = xstrdup(args); |
862 | } else { | 838 | } else { |
863 | // user wants file status info | 839 | // user wants file status info |
864 | last_status_cksum = 0; // force status update | 840 | last_status_cksum = 0; // force status update |
@@ -944,7 +920,7 @@ static void colon(char * buf) | |||
944 | // read after current line- unless user said ":0r foo" | 920 | // read after current line- unless user said ":0r foo" |
945 | if (b != 0) | 921 | if (b != 0) |
946 | q = next_line(q); | 922 | q = next_line(q); |
947 | ch = file_insert(fn, q); | 923 | ch = file_insert(fn, q USE_FEATURE_VI_READONLY(, 0)); |
948 | if (ch < 0) | 924 | if (ch < 0) |
949 | goto vc1; // nothing was inserted | 925 | goto vc1; // nothing was inserted |
950 | // how many lines in text[]? | 926 | // how many lines in text[]? |
@@ -952,7 +928,7 @@ static void colon(char * buf) | |||
952 | psb("\"%s\"" | 928 | psb("\"%s\"" |
953 | USE_FEATURE_VI_READONLY("%s") | 929 | USE_FEATURE_VI_READONLY("%s") |
954 | " %dL, %dC", fn, | 930 | " %dL, %dC", fn, |
955 | USE_FEATURE_VI_READONLY(((vi_readonly || readonly) ? " [Read only]" : ""),) | 931 | USE_FEATURE_VI_READONLY((readonly_mode ? " [Readonly]" : ""),) |
956 | li, ch); | 932 | li, ch); |
957 | if (ch > 0) { | 933 | if (ch > 0) { |
958 | // if the insert is before "dot" then we need to update | 934 | // if the insert is before "dot" then we need to update |
@@ -1080,7 +1056,7 @@ static void colon(char * buf) | |||
1080 | fn = args; | 1056 | fn = args; |
1081 | } | 1057 | } |
1082 | #if ENABLE_FEATURE_VI_READONLY | 1058 | #if ENABLE_FEATURE_VI_READONLY |
1083 | if ((vi_readonly || readonly) && !useforce) { | 1059 | if (readonly_mode && !useforce) { |
1084 | psbs("\"%s\" File is read only", fn); | 1060 | psbs("\"%s\" File is read only", fn); |
1085 | goto vc3; | 1061 | goto vc3; |
1086 | } | 1062 | } |
@@ -1104,7 +1080,7 @@ static void colon(char * buf) | |||
1104 | } | 1080 | } |
1105 | if (l < 0) { | 1081 | if (l < 0) { |
1106 | if (l == -1) | 1082 | if (l == -1) |
1107 | psbs("Write error: %s", strerror(errno)); | 1083 | psbs("\"%s\" %s", fn, strerror(errno)); |
1108 | } else { | 1084 | } else { |
1109 | psb("\"%s\" %dL, %dC", fn, li, l); | 1085 | psb("\"%s\" %dL, %dC", fn, li, l); |
1110 | if (q == text && r == end - 1 && l == ch) { | 1086 | if (q == text && r == end - 1 && l == ch) { |
@@ -1158,6 +1134,10 @@ static void Hit_Return(void) | |||
1158 | redraw(TRUE); // force redraw all | 1134 | redraw(TRUE); // force redraw all |
1159 | } | 1135 | } |
1160 | 1136 | ||
1137 | static int next_tabstop(int col) { //vda | ||
1138 | return col + ((tabstop - 1) - (col % tabstop)); | ||
1139 | } | ||
1140 | |||
1161 | //----- Synchronize the cursor to Dot -------------------------- | 1141 | //----- Synchronize the cursor to Dot -------------------------- |
1162 | static void sync_cursor(char * d, int *row, int *col) | 1142 | static void sync_cursor(char * d, int *row, int *col) |
1163 | { | 1143 | { |
@@ -1210,8 +1190,11 @@ static void sync_cursor(char * d, int *row, int *col) | |||
1210 | if (*tp == '\n' || *tp == '\0') | 1190 | if (*tp == '\n' || *tp == '\0') |
1211 | break; | 1191 | break; |
1212 | if (*tp == '\t') { | 1192 | if (*tp == '\t') { |
1213 | // 7 - (co % 8 ) | 1193 | if (d == tp && cmd_mode) { /* handle tabs like real vi */ |
1214 | co += ((tabstop - 1) - (co % tabstop)); | 1194 | break; |
1195 | } else { | ||
1196 | co = next_tabstop(co); | ||
1197 | } | ||
1215 | } else if (*tp < ' ' || *tp == 127) { | 1198 | } else if (*tp < ' ' || *tp == 127) { |
1216 | co++; // display as ^X, use 2 columns | 1199 | co++; // display as ^X, use 2 columns |
1217 | } | 1200 | } |
@@ -1365,8 +1348,7 @@ static char *move_to_col(char * p, int l) | |||
1365 | if (*p == '\n' || *p == '\0') | 1348 | if (*p == '\n' || *p == '\0') |
1366 | break; | 1349 | break; |
1367 | if (*p == '\t') { | 1350 | if (*p == '\t') { |
1368 | // 7 - (co % 8 ) | 1351 | co = next_tabstop(co); |
1369 | co += ((tabstop - 1) - (co % tabstop)); | ||
1370 | } else if (*p < ' ' || *p == 127) { | 1352 | } else if (*p < ' ' || *p == 127) { |
1371 | co++; // display as ^X, use 2 columns | 1353 | co++; // display as ^X, use 2 columns |
1372 | } | 1354 | } |
@@ -1462,28 +1444,15 @@ static char *new_screen(int ro, int co) | |||
1462 | return screen; | 1444 | return screen; |
1463 | } | 1445 | } |
1464 | 1446 | ||
1465 | static char *new_text(int size) | ||
1466 | { | ||
1467 | if (size < 10240) | ||
1468 | size = 10240; // have a minimum size for new files | ||
1469 | free(text); | ||
1470 | text = xmalloc(size + 8); | ||
1471 | memset(text, '\0', size); // clear new text[] | ||
1472 | //text += 4; // leave some room for "oops" | ||
1473 | return text; | ||
1474 | } | ||
1475 | |||
1476 | #if ENABLE_FEATURE_VI_SEARCH | 1447 | #if ENABLE_FEATURE_VI_SEARCH |
1477 | static int mycmp(const char * s1, const char * s2, int len) | 1448 | static int mycmp(const char * s1, const char * s2, int len) |
1478 | { | 1449 | { |
1479 | int i; | 1450 | int i; |
1480 | 1451 | ||
1481 | i = strncmp(s1, s2, len); | 1452 | i = strncmp(s1, s2, len); |
1482 | #if ENABLE_FEATURE_VI_SETOPTS | 1453 | if (ENABLE_FEATURE_VI_SETOPTS && ignorecase) { |
1483 | if (ignorecase) { | ||
1484 | i = strncasecmp(s1, s2, len); | 1454 | i = strncasecmp(s1, s2, len); |
1485 | } | 1455 | } |
1486 | #endif | ||
1487 | return i; | 1456 | return i; |
1488 | } | 1457 | } |
1489 | 1458 | ||
@@ -1621,7 +1590,7 @@ static char *char_insert(char * p, char c) // insert the char c at 'p' | |||
1621 | char *q; | 1590 | char *q; |
1622 | 1591 | ||
1623 | q = prev_line(p); // use prev line as templet | 1592 | q = prev_line(p); // use prev line as templet |
1624 | for (; isblnk(*q); q++) { | 1593 | for (; isblank(*q); q++) { |
1625 | p = stupid_insert(p, *q); // insert the char | 1594 | p = stupid_insert(p, *q); // insert the char |
1626 | } | 1595 | } |
1627 | } | 1596 | } |
@@ -1828,11 +1797,14 @@ static char *text_hole_make(char * p, int size) // at "p", make a 'size' byte ho | |||
1828 | src = p; | 1797 | src = p; |
1829 | dest = p + size; | 1798 | dest = p + size; |
1830 | cnt = end - src; // the rest of buffer | 1799 | cnt = end - src; // the rest of buffer |
1831 | if (memmove(dest, src, cnt) != dest) { | 1800 | if ( ((end + size) >= (text + text_size)) // TODO: realloc here |
1801 | || memmove(dest, src, cnt) != dest) { | ||
1832 | psbs("can't create room for new characters"); | 1802 | psbs("can't create room for new characters"); |
1803 | p = NULL; | ||
1804 | goto thm0; | ||
1833 | } | 1805 | } |
1834 | memset(p, ' ', size); // clear new hole | 1806 | memset(p, ' ', size); // clear new hole |
1835 | end = end + size; // adjust the new END | 1807 | end += size; // adjust the new END |
1836 | file_modified++; // has the file been modified | 1808 | file_modified++; // has the file been modified |
1837 | thm0: | 1809 | thm0: |
1838 | return p; | 1810 | return p; |
@@ -2010,15 +1982,16 @@ static char *string_insert(char * p, char * s) // insert the string at 'p' | |||
2010 | int cnt, i; | 1982 | int cnt, i; |
2011 | 1983 | ||
2012 | i = strlen(s); | 1984 | i = strlen(s); |
2013 | p = text_hole_make(p, i); | 1985 | if (text_hole_make(p, i)) { |
2014 | strncpy(p, s, i); | 1986 | strncpy(p, s, i); |
2015 | for (cnt = 0; *s != '\0'; s++) { | 1987 | for (cnt = 0; *s != '\0'; s++) { |
2016 | if (*s == '\n') | 1988 | if (*s == '\n') |
2017 | cnt++; | 1989 | cnt++; |
2018 | } | 1990 | } |
2019 | #if ENABLE_FEATURE_VI_YANKMARK | 1991 | #if ENABLE_FEATURE_VI_YANKMARK |
2020 | psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); | 1992 | psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); |
2021 | #endif | 1993 | #endif |
1994 | } | ||
2022 | return p; | 1995 | return p; |
2023 | } | 1996 | } |
2024 | #endif | 1997 | #endif |
@@ -2094,11 +2067,6 @@ static inline char *swap_context(char * p) // goto new context for '' command ma | |||
2094 | } | 2067 | } |
2095 | #endif /* FEATURE_VI_YANKMARK */ | 2068 | #endif /* FEATURE_VI_YANKMARK */ |
2096 | 2069 | ||
2097 | static int isblnk(char c) // is the char a blank or tab | ||
2098 | { | ||
2099 | return (c == ' ' || c == '\t'); | ||
2100 | } | ||
2101 | |||
2102 | //----- Set terminal attributes -------------------------------- | 2070 | //----- Set terminal attributes -------------------------------- |
2103 | static void rawmode(void) | 2071 | static void rawmode(void) |
2104 | { | 2072 | { |
@@ -2240,13 +2208,8 @@ static char readit(void) // read (maybe cursor) key from stdin | |||
2240 | if (n < 0) { | 2208 | if (n < 0) { |
2241 | if (errno == EINTR) | 2209 | if (errno == EINTR) |
2242 | goto ri0; // interrupted sys call | 2210 | goto ri0; // interrupted sys call |
2243 | if (errno == EBADF) | 2211 | if (errno == EBADF || errno == EFAULT || errno == EINVAL |
2244 | editing = 0; | 2212 | || errno == EIO) |
2245 | if (errno == EFAULT) | ||
2246 | editing = 0; | ||
2247 | if (errno == EINVAL) | ||
2248 | editing = 0; | ||
2249 | if (errno == EIO) | ||
2250 | editing = 0; | 2213 | editing = 0; |
2251 | errno = 0; | 2214 | errno = 0; |
2252 | } | 2215 | } |
@@ -2393,7 +2356,7 @@ static char *get_input_line(const char * prompt) // get input line- use "status | |||
2393 | return obufp; | 2356 | return obufp; |
2394 | } | 2357 | } |
2395 | 2358 | ||
2396 | static int file_size(const char * fn) // what is the byte size of "fn" | 2359 | static int file_size(const char *fn) // what is the byte size of "fn" |
2397 | { | 2360 | { |
2398 | struct stat st_buf; | 2361 | struct stat st_buf; |
2399 | int cnt; | 2362 | int cnt; |
@@ -2404,16 +2367,30 @@ static int file_size(const char * fn) // what is the byte size of "fn" | |||
2404 | return cnt; | 2367 | return cnt; |
2405 | } | 2368 | } |
2406 | 2369 | ||
2407 | static int file_insert(char *fn, char *p) | 2370 | static int file_insert(const char * fn, char *p |
2371 | USE_FEATURE_VI_READONLY(, int update_ro_status)) | ||
2408 | { | 2372 | { |
2409 | int cnt = -1; | 2373 | int cnt = -1; |
2410 | int fd, size; | 2374 | int fd, size; |
2411 | 2375 | struct stat statbuf; | |
2412 | size = file_size(fn); | 2376 | |
2413 | if (size < 0) { | 2377 | /* Validate file */ |
2414 | psbs("File does not exist"); | 2378 | if (stat(fn, &statbuf) < 0) { |
2379 | psbs("\"%s\" %s", fn, strerror(errno)); | ||
2415 | goto fi0; | 2380 | goto fi0; |
2416 | } | 2381 | } |
2382 | if ((statbuf.st_mode & S_IFREG) == 0) { | ||
2383 | // This is not a regular file | ||
2384 | psbs("\"%s\" Not a regular file", fn); | ||
2385 | goto fi0; | ||
2386 | } | ||
2387 | /* // this check is done by open() | ||
2388 | if ((statbuf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) { | ||
2389 | // dont have any read permissions | ||
2390 | psbs("\"%s\" Not readable", fn); | ||
2391 | goto fi0; | ||
2392 | } | ||
2393 | */ | ||
2417 | if (p < text || p > end) { | 2394 | if (p < text || p > end) { |
2418 | psbs("Trying to insert file outside of memory"); | 2395 | psbs("Trying to insert file outside of memory"); |
2419 | goto fi0; | 2396 | goto fi0; |
@@ -2422,16 +2399,17 @@ static int file_insert(char *fn, char *p) | |||
2422 | // read file to buffer | 2399 | // read file to buffer |
2423 | fd = open(fn, O_RDONLY); | 2400 | fd = open(fn, O_RDONLY); |
2424 | if (fd < 0) { | 2401 | if (fd < 0) { |
2425 | psbs("\"%s\" %s", fn, "cannot open file"); | 2402 | psbs("\"%s\" %s", fn, strerror(errno)); |
2426 | goto fi0; | 2403 | goto fi0; |
2427 | } | 2404 | } |
2405 | size = statbuf.st_size; | ||
2428 | p = text_hole_make(p, size); | 2406 | p = text_hole_make(p, size); |
2407 | if (p == NULL) | ||
2408 | goto fi0; | ||
2429 | cnt = read(fd, p, size); | 2409 | cnt = read(fd, p, size); |
2430 | close(fd); | ||
2431 | if (cnt < 0) { | 2410 | if (cnt < 0) { |
2432 | cnt = -1; | 2411 | psbs("\"%s\" %s", fn, strerror(errno)); |
2433 | p = text_hole_delete(p, p + size - 1); // un-do buffer insert | 2412 | p = text_hole_delete(p, p + size - 1); // un-do buffer insert |
2434 | psbs("cannot read file \"%s\"", fn); | ||
2435 | } else if (cnt < size) { | 2413 | } else if (cnt < size) { |
2436 | // There was a partial read, shrink unused space text[] | 2414 | // There was a partial read, shrink unused space text[] |
2437 | p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert | 2415 | p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert |
@@ -2439,22 +2417,19 @@ static int file_insert(char *fn, char *p) | |||
2439 | } | 2417 | } |
2440 | if (cnt >= size) | 2418 | if (cnt >= size) |
2441 | file_modified++; | 2419 | file_modified++; |
2420 | close(fd); | ||
2442 | fi0: | 2421 | fi0: |
2443 | return cnt; | 2422 | if (ENABLE_FEATURE_VI_READONLY && update_ro_status |
2444 | } | 2423 | && ((access(fn, W_OK) < 0) || |
2445 | |||
2446 | #if ENABLE_FEATURE_VI_READONLY | ||
2447 | static void update_ro_status(const char *fn) | ||
2448 | { | ||
2449 | struct stat sb; | ||
2450 | if (stat(fn, &sb) == 0) { | ||
2451 | readonly = vi_readonly || (access(fn, W_OK) < 0) || | ||
2452 | /* root will always have access() | 2424 | /* root will always have access() |
2453 | * so we check fileperms too */ | 2425 | * so we check fileperms too */ |
2454 | !(sb.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)); | 2426 | !(statbuf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))) |
2427 | { | ||
2428 | SET_READONLY_FILE(readonly_mode); | ||
2455 | } | 2429 | } |
2430 | return cnt; | ||
2456 | } | 2431 | } |
2457 | #endif | 2432 | |
2458 | 2433 | ||
2459 | static int file_write(char * fn, char * first, char * last) | 2434 | static int file_write(char * fn, char * first, char * last) |
2460 | { | 2435 | { |
@@ -2687,7 +2662,7 @@ static void ni(const char * s) // display messages | |||
2687 | static int format_edit_status(void) // show file status on status line | 2662 | static int format_edit_status(void) // show file status on status line |
2688 | { | 2663 | { |
2689 | static int tot; | 2664 | static int tot; |
2690 | 2665 | static const char cmd_mode_indicator[] = "-IR-"; | |
2691 | int cur, percent, ret, trunc_at; | 2666 | int cur, percent, ret, trunc_at; |
2692 | 2667 | ||
2693 | // file_modified is now a counter rather than a flag. this | 2668 | // file_modified is now a counter rather than a flag. this |
@@ -2726,12 +2701,12 @@ static int format_edit_status(void) // show file status on status line | |||
2726 | #else | 2701 | #else |
2727 | "%c %s%s %d/%d %d%%", | 2702 | "%c %s%s %d/%d %d%%", |
2728 | #endif | 2703 | #endif |
2729 | (cmd_mode ? (cmd_mode == 2 ? 'R':'I'):'-'), | 2704 | cmd_mode_indicator[cmd_mode & 3], |
2730 | (cfn != 0 ? cfn : "No file"), | 2705 | (current_filename != NULL ? current_filename : "No file"), |
2731 | #if ENABLE_FEATURE_VI_READONLY | 2706 | #if ENABLE_FEATURE_VI_READONLY |
2732 | ((vi_readonly || readonly) ? " [Read-only]" : ""), | 2707 | (readonly_mode ? " [Readonly]" : ""), |
2733 | #endif | 2708 | #endif |
2734 | (file_modified ? " [modified]" : ""), | 2709 | (file_modified ? " [Modified]" : ""), |
2735 | cur, tot, percent); | 2710 | cur, tot, percent); |
2736 | 2711 | ||
2737 | if (ret >= 0 && ret < trunc_at) | 2712 | if (ret >= 0 && ret < trunc_at) |
@@ -3391,14 +3366,14 @@ static void do_cmd(char c) | |||
3391 | || strncasecmp(p, "wn", cnt) == 0 | 3366 | || strncasecmp(p, "wn", cnt) == 0 |
3392 | || strncasecmp(p, "x", cnt) == 0 | 3367 | || strncasecmp(p, "x", cnt) == 0 |
3393 | ) { | 3368 | ) { |
3394 | cnt = file_write(cfn, text, end - 1); | 3369 | cnt = file_write(current_filename, text, end - 1); |
3395 | if (cnt < 0) { | 3370 | if (cnt < 0) { |
3396 | if (cnt == -1) | 3371 | if (cnt == -1) |
3397 | psbs("Write error: %s", strerror(errno)); | 3372 | psbs("Write error: %s", strerror(errno)); |
3398 | } else { | 3373 | } else { |
3399 | file_modified = 0; | 3374 | file_modified = 0; |
3400 | last_file_modified = -1; | 3375 | last_file_modified = -1; |
3401 | psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt); | 3376 | psb("\"%s\" %dL, %dC", current_filename, count_lines(text, end - 1), cnt); |
3402 | if (p[0] == 'x' || p[1] == 'q' || p[1] == 'n' | 3377 | if (p[0] == 'x' || p[1] == 'q' || p[1] == 'n' |
3403 | || p[0] == 'X' || p[1] == 'Q' || p[1] == 'N' | 3378 | || p[0] == 'X' || p[1] == 'Q' || p[1] == 'N' |
3404 | ) { | 3379 | ) { |
@@ -3516,7 +3491,7 @@ static void do_cmd(char c) | |||
3516 | if (dot < end - 1) { // make sure not last char in text[] | 3491 | if (dot < end - 1) { // make sure not last char in text[] |
3517 | *dot++ = ' '; // replace NL with space | 3492 | *dot++ = ' '; // replace NL with space |
3518 | file_modified++; | 3493 | file_modified++; |
3519 | while (isblnk(*dot)) { // delete leading WS | 3494 | while (isblank(*dot)) { // delete leading WS |
3520 | dot_delete(); | 3495 | dot_delete(); |
3521 | } | 3496 | } |
3522 | } | 3497 | } |
@@ -3583,13 +3558,11 @@ static void do_cmd(char c) | |||
3583 | break; | 3558 | break; |
3584 | } | 3559 | } |
3585 | if (file_modified) { | 3560 | if (file_modified) { |
3586 | #if ENABLE_FEATURE_VI_READONLY | 3561 | if (ENABLE_FEATURE_VI_READONLY && readonly_mode) { |
3587 | if (vi_readonly || readonly) { | 3562 | psbs("\"%s\" File is read only", current_filename); |
3588 | psbs("\"%s\" File is read only", cfn); | ||
3589 | break; | 3563 | break; |
3590 | } | 3564 | } |
3591 | #endif | 3565 | cnt = file_write(current_filename, text, end - 1); |
3592 | cnt = file_write(cfn, text, end - 1); | ||
3593 | if (cnt < 0) { | 3566 | if (cnt < 0) { |
3594 | if (cnt == -1) | 3567 | if (cnt == -1) |
3595 | psbs("Write error: %s", strerror(errno)); | 3568 | psbs("Write error: %s", strerror(errno)); |
@@ -3644,7 +3617,7 @@ static void do_cmd(char c) | |||
3644 | } else if (strchr("wW", c1)) { | 3617 | } else if (strchr("wW", c1)) { |
3645 | if (c == 'c') { | 3618 | if (c == 'c') { |
3646 | // don't include trailing WS as part of word | 3619 | // don't include trailing WS as part of word |
3647 | while (isblnk(*q)) { | 3620 | while (isblank(*q)) { |
3648 | if (q <= text || q[-1] == '\n') | 3621 | if (q <= text || q[-1] == '\n') |
3649 | break; | 3622 | break; |
3650 | q--; | 3623 | q--; |