aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editors/vi.c115
1 files changed, 52 insertions, 63 deletions
diff --git a/editors/vi.c b/editors/vi.c
index 425d14c9c..a11e06040 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -235,9 +235,10 @@ enum {
235 * Full sequence is "ESC [ <num> J", 235 * Full sequence is "ESC [ <num> J",
236 * <num> is 0/1/2 = "erase below/above/all".) 236 * <num> is 0/1/2 = "erase below/above/all".)
237 */ 237 */
238#define ESC_CLEAR2EOS ESC"[J" 238#define ESC_CLEAR2EOS ESC"[J"
239/* Cursor to given coordinate (1,1: top left) */ 239/* Cursor to given coordinate (1,1: top left) */
240#define ESC_SET_CURSOR_POS ESC"[%u;%uH" 240#define ESC_SET_CURSOR_POS ESC"[%u;%uH"
241#define ESC_SET_CURSOR_TOPLEFT ESC"[H"
241//UNUSED 242//UNUSED
242///* Cursor up and down */ 243///* Cursor up and down */
243//#define ESC_CURSOR_UP ESC"[A" 244//#define ESC_CURSOR_UP ESC"[A"
@@ -352,7 +353,7 @@ struct globals {
352 char *context_start, *context_end; 353 char *context_start, *context_end;
353#endif 354#endif
354#if ENABLE_FEATURE_VI_USE_SIGNALS 355#if ENABLE_FEATURE_VI_USE_SIGNALS
355 sigjmp_buf restart; // catch_sig() 356 sigjmp_buf restart; // int_handler() jumps to location remembered here
356#endif 357#endif
357 struct termios term_orig; // remember what the cooked mode was 358 struct termios term_orig; // remember what the cooked mode was
358#if ENABLE_FEATURE_VI_COLON 359#if ENABLE_FEATURE_VI_COLON
@@ -535,15 +536,11 @@ static void rawmode(void); // set "raw" mode on tty
535static void cookmode(void); // return to "cooked" mode on tty 536static void cookmode(void); // return to "cooked" mode on tty
536// sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready) 537// sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready)
537static int mysleep(int); 538static int mysleep(int);
538static int readit(void); // read (maybe cursor) key from stdin
539static int get_one_char(void); // read 1 char from stdin 539static int get_one_char(void); // read 1 char from stdin
540// file_insert might reallocate text[]! 540// file_insert might reallocate text[]!
541static int file_insert(const char *, char *, int); 541static int file_insert(const char *, char *, int);
542static int file_write(char *, char *, char *); 542static int file_write(char *, char *, char *);
543static void place_cursor(int, int);
544static void screen_erase(void); 543static void screen_erase(void);
545static void clear_to_eol(void);
546static void clear_to_eos(void);
547static void go_bottom_and_clear_to_eol(void); 544static void go_bottom_and_clear_to_eol(void);
548static void standout_start(void); // send "start reverse video" sequence 545static void standout_start(void); // send "start reverse video" sequence
549static void standout_end(void); // send "end reverse video" sequence 546static void standout_end(void); // send "end reverse video" sequence
@@ -570,9 +567,9 @@ static char *get_address(char *, int *, int *); // get two colon addrs, if prese
570#endif 567#endif
571static void colon(char *); // execute the "colon" mode cmds 568static void colon(char *); // execute the "colon" mode cmds
572#if ENABLE_FEATURE_VI_USE_SIGNALS 569#if ENABLE_FEATURE_VI_USE_SIGNALS
573static void winch_sig(int); // catch window size changes 570static void winch_handler(int); // catch window size changes
574static void suspend_sig(int); // catch ctrl-Z 571static void tstp_handler(int); // catch ctrl-Z
575static void catch_sig(int); // catch ctrl-C and alarm time-outs 572static void int_handler(int); // catch ctrl-C
576#endif 573#endif
577#if ENABLE_FEATURE_VI_DOT_CMD 574#if ENABLE_FEATURE_VI_DOT_CMD
578static void start_new_cmd_q(char); // new queue for command 575static void start_new_cmd_q(char); // new queue for command
@@ -598,11 +595,11 @@ static void check_context(char); // remember context for '' command
598#endif 595#endif
599#if ENABLE_FEATURE_VI_UNDO 596#if ENABLE_FEATURE_VI_UNDO
600static void flush_undo_data(void); 597static void flush_undo_data(void);
601static void undo_push(char *, unsigned int, unsigned char); // Push an operation on the undo stack 598static void undo_push(char *, unsigned, unsigned char); // push an operation on the undo stack
602static void undo_push_insert(char *, int, int); // convenience function 599static void undo_push_insert(char *, int, int); // convenience function
603static void undo_pop(void); // Undo the last operation 600static void undo_pop(void); // undo the last operation
604# if ENABLE_FEATURE_VI_UNDO_QUEUE 601# if ENABLE_FEATURE_VI_UNDO_QUEUE
605static void undo_queue_commit(void); // Flush any queued objects to the undo stack 602static void undo_queue_commit(void); // flush any queued objects to the undo stack
606# else 603# else
607# define undo_queue_commit() ((void)0) 604# define undo_queue_commit() ((void)0)
608# endif 605# endif
@@ -644,7 +641,7 @@ int vi_main(int argc, char **argv)
644 srand((long) my_pid); 641 srand((long) my_pid);
645#endif 642#endif
646#ifdef NO_SUCH_APPLET_YET 643#ifdef NO_SUCH_APPLET_YET
647 /* If we aren't "vi", we are "view" */ 644 // if we aren't "vi", we are "view"
648 if (ENABLE_FEATURE_VI_READONLY && applet_name[2]) { 645 if (ENABLE_FEATURE_VI_READONLY && applet_name[2]) {
649 SET_READONLY_MODE(readonly_mode); 646 SET_READONLY_MODE(readonly_mode);
650 } 647 }
@@ -682,7 +679,7 @@ int vi_main(int argc, char **argv)
682#endif 679#endif
683 case 'H': 680 case 'H':
684 show_help(); 681 show_help();
685 /* fall through */ 682 // fall through
686 default: 683 default:
687 bb_show_usage(); 684 bb_show_usage();
688 return 1; 685 return 1;
@@ -699,7 +696,7 @@ int vi_main(int argc, char **argv)
699 // "Save cursor, use alternate screen buffer, clear screen" 696 // "Save cursor, use alternate screen buffer, clear screen"
700 write1(ESC"[?1049h"); 697 write1(ESC"[?1049h");
701 while (1) { 698 while (1) {
702 edit_file(argv[optind]); /* param might be NULL */ 699 edit_file(argv[optind]); // param might be NULL
703 if (++optind >= argc) 700 if (++optind >= argc)
704 break; 701 break;
705 } 702 }
@@ -804,13 +801,15 @@ static void edit_file(char *fn)
804 ccol = 0; 801 ccol = 0;
805 802
806#if ENABLE_FEATURE_VI_USE_SIGNALS 803#if ENABLE_FEATURE_VI_USE_SIGNALS
807 signal(SIGINT, catch_sig); 804 signal(SIGWINCH, winch_handler);
808 signal(SIGWINCH, winch_sig); 805 signal(SIGTSTP, tstp_handler);
809 signal(SIGTSTP, suspend_sig);
810 sig = sigsetjmp(restart, 1); 806 sig = sigsetjmp(restart, 1);
811 if (sig != 0) { 807 if (sig != 0) {
812 screenbegin = dot = text; 808 screenbegin = dot = text;
813 } 809 }
810 // int_handler() can jump to "restart",
811 // must install handler *after* initializing "restart"
812 signal(SIGINT, int_handler);
814#endif 813#endif
815 814
816 cmd_mode = 0; // 0=command 1=insert 2='R'eplace 815 cmd_mode = 0; // 0=command 1=insert 2='R'eplace
@@ -994,7 +993,7 @@ static void setops(const char *args, const char *opname, int flg_no,
994 const char *short_opname, int opt) 993 const char *short_opname, int opt)
995{ 994{
996 const char *a = args + flg_no; 995 const char *a = args + flg_no;
997 int l = strlen(opname) - 1; /* opname have + ' ' */ 996 int l = strlen(opname) - 1; // opname have + ' '
998 997
999 // maybe strncmp? we had tons of erroneous strncasecmp's... 998 // maybe strncmp? we had tons of erroneous strncasecmp's...
1000 if (strncasecmp(a, opname, l) == 0 999 if (strncasecmp(a, opname, l) == 0
@@ -1014,7 +1013,7 @@ static void setops(const char *args, const char *opname, int flg_no,
1014static void colon(char *buf) 1013static void colon(char *buf)
1015{ 1014{
1016#if !ENABLE_FEATURE_VI_COLON 1015#if !ENABLE_FEATURE_VI_COLON
1017 /* Simple ":cmd" handler with minimal set of commands */ 1016 // Simple ":cmd" handler with minimal set of commands
1018 char *p = buf; 1017 char *p = buf;
1019 int cnt; 1018 int cnt;
1020 1019
@@ -1357,7 +1356,7 @@ static void colon(char *buf)
1357 status_line_bold("No write since last change (:%s! overrides)", cmd); 1356 status_line_bold("No write since last change (:%s! overrides)", cmd);
1358 } else { 1357 } else {
1359 // reset the filenames to edit 1358 // reset the filenames to edit
1360 optind = -1; /* start from 0th file */ 1359 optind = -1; // start from 0th file
1361 editing = 0; 1360 editing = 0;
1362 } 1361 }
1363# if ENABLE_FEATURE_VI_SET 1362# if ENABLE_FEATURE_VI_SET
@@ -2218,7 +2217,7 @@ static char *find_pair(char *p, const char c)
2218 dir = strchr(braces, c) - braces; 2217 dir = strchr(braces, c) - braces;
2219 dir ^= 1; 2218 dir ^= 1;
2220 match = braces[dir]; 2219 match = braces[dir];
2221 dir = ((dir & 1) << 1) - 1; /* 1 for ([{, -1 for )\} */ 2220 dir = ((dir & 1) << 1) - 1; // 1 for ([{, -1 for )\}
2222 2221
2223 // look for match, count levels of pairs (( )) 2222 // look for match, count levels of pairs (( ))
2224 level = 1; 2223 level = 1;
@@ -2271,7 +2270,8 @@ static void flush_undo_data(void)
2271} 2270}
2272 2271
2273// Undo functions and hooks added by Jody Bruchon (jody@jodybruchon.com) 2272// Undo functions and hooks added by Jody Bruchon (jody@jodybruchon.com)
2274static void undo_push(char *src, unsigned int length, uint8_t u_type) // Add to the undo stack 2273// Add to the undo stack
2274static void undo_push(char *src, unsigned length, uint8_t u_type)
2275{ 2275{
2276 struct undo_object *undo_entry; 2276 struct undo_object *undo_entry;
2277 2277
@@ -2389,7 +2389,8 @@ static void undo_push_insert(char *p, int len, int undo)
2389 } 2389 }
2390} 2390}
2391 2391
2392static void undo_pop(void) // Undo the last operation 2392// Undo the last operation
2393static void undo_pop(void)
2393{ 2394{
2394 int repeat; 2395 int repeat;
2395 char *u_start, *u_end; 2396 char *u_start, *u_end;
@@ -2453,7 +2454,8 @@ static void undo_pop(void) // Undo the last operation
2453} 2454}
2454 2455
2455#if ENABLE_FEATURE_VI_UNDO_QUEUE 2456#if ENABLE_FEATURE_VI_UNDO_QUEUE
2456static void undo_queue_commit(void) // Flush any queued objects to the undo stack 2457// Flush any queued objects to the undo stack
2458static void undo_queue_commit(void)
2457{ 2459{
2458 // Pushes the queue object onto the undo stack 2460 // Pushes the queue object onto the undo stack
2459 if (undo_q > 0) { 2461 if (undo_q > 0) {
@@ -2758,49 +2760,44 @@ static void cookmode(void)
2758} 2760}
2759 2761
2760#if ENABLE_FEATURE_VI_USE_SIGNALS 2762#if ENABLE_FEATURE_VI_USE_SIGNALS
2761//----- Come here when we get a window resize signal --------- 2763static void winch_handler(int sig UNUSED_PARAM)
2762static void winch_sig(int sig UNUSED_PARAM)
2763{ 2764{
2764 int save_errno = errno; 2765 int save_errno = errno;
2765 // FIXME: do it in main loop!!! 2766 // FIXME: do it in main loop!!!
2766 signal(SIGWINCH, winch_sig); 2767 signal(SIGWINCH, winch_handler);
2767 query_screen_dimensions(); 2768 query_screen_dimensions();
2768 new_screen(rows, columns); // get memory for virtual screen 2769 new_screen(rows, columns); // get memory for virtual screen
2769 redraw(TRUE); // re-draw the screen 2770 redraw(TRUE); // re-draw the screen
2770 errno = save_errno; 2771 errno = save_errno;
2771} 2772}
2772 2773static void cont_handler(int sig UNUSED_PARAM)
2773//----- Come here when we get a continue signal -------------------
2774static void cont_sig(int sig UNUSED_PARAM)
2775{ 2774{
2776 int save_errno = errno; 2775 int save_errno = errno;
2777 rawmode(); // terminal to "raw" 2776 rawmode(); // terminal to "raw"
2778 last_status_cksum = 0; // force status update 2777 last_status_cksum = 0; // force status update
2779 redraw(TRUE); // re-draw the screen 2778 redraw(TRUE); // re-draw the screen
2780 2779
2781 signal(SIGTSTP, suspend_sig); 2780 signal(SIGTSTP, tstp_handler);
2782 signal(SIGCONT, SIG_DFL); 2781 signal(SIGCONT, SIG_DFL);
2783 //kill(my_pid, SIGCONT); // huh? why? we are already "continued"... 2782 //kill(my_pid, SIGCONT); // huh? why? we are already "continued"...
2784 errno = save_errno; 2783 errno = save_errno;
2785} 2784}
2786 2785static void tstp_handler(int sig UNUSED_PARAM)
2787//----- Come here when we get a Suspend signal -------------------
2788static void suspend_sig(int sig UNUSED_PARAM)
2789{ 2786{
2790 int save_errno = errno; 2787 int save_errno = errno;
2791 go_bottom_and_clear_to_eol(); 2788 go_bottom_and_clear_to_eol();
2792 cookmode(); // terminal to "cooked" 2789 cookmode(); // terminal to "cooked"
2793 2790
2794 signal(SIGCONT, cont_sig); 2791 signal(SIGCONT, cont_handler);
2795 signal(SIGTSTP, SIG_DFL); 2792 signal(SIGTSTP, SIG_DFL);
2796 kill(my_pid, SIGTSTP); 2793 kill(my_pid, SIGTSTP);
2797 errno = save_errno; 2794 errno = save_errno;
2798} 2795}
2799 2796
2800//----- Come here when we get a signal --------------------------- 2797//----- Come here when we get a signal ---------------------------
2801static void catch_sig(int sig) 2798static void int_handler(int sig)
2802{ 2799{
2803 signal(SIGINT, catch_sig); 2800 signal(SIGINT, int_handler);
2804 siglongjmp(restart, sig); 2801 siglongjmp(restart, sig);
2805} 2802}
2806#endif /* FEATURE_VI_USE_SIGNALS */ 2803#endif /* FEATURE_VI_USE_SIGNALS */
@@ -2934,7 +2931,7 @@ static int file_insert(const char *fn, char *p, int initial)
2934 return cnt; 2931 return cnt;
2935 } 2932 }
2936 2933
2937 /* Validate file */ 2934 // Validate file
2938 if (fstat(fd, &statbuf) < 0) { 2935 if (fstat(fd, &statbuf) < 0) {
2939 status_line_bold_errno(fn); 2936 status_line_bold_errno(fn);
2940 goto fi; 2937 goto fi;
@@ -2960,8 +2957,8 @@ static int file_insert(const char *fn, char *p, int initial)
2960#if ENABLE_FEATURE_VI_READONLY 2957#if ENABLE_FEATURE_VI_READONLY
2961 if (initial 2958 if (initial
2962 && ((access(fn, W_OK) < 0) || 2959 && ((access(fn, W_OK) < 0) ||
2963 /* root will always have access() 2960 // root will always have access()
2964 * so we check fileperms too */ 2961 // so we check fileperms too
2965 !(statbuf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) 2962 !(statbuf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))
2966 ) 2963 )
2967 ) { 2964 ) {
@@ -2979,10 +2976,9 @@ static int file_write(char *fn, char *first, char *last)
2979 status_line_bold("No current filename"); 2976 status_line_bold("No current filename");
2980 return -2; 2977 return -2;
2981 } 2978 }
2982 /* By popular request we do not open file with O_TRUNC, 2979 // By popular request we do not open file with O_TRUNC,
2983 * but instead ftruncate() it _after_ successful write. 2980 // but instead ftruncate() it _after_ successful write.
2984 * Might reduce amount of data lost on power fail etc. 2981 // Might reduce amount of data lost on power fail etc.
2985 */
2986 fd = open(fn, (O_WRONLY | O_CREAT), 0666); 2982 fd = open(fn, (O_WRONLY | O_CREAT), 0666);
2987 if (fd < 0) 2983 if (fd < 0)
2988 return -1; 2984 return -1;
@@ -3036,12 +3032,6 @@ static void go_bottom_and_clear_to_eol(void)
3036 clear_to_eol(); 3032 clear_to_eol();
3037} 3033}
3038 3034
3039//----- Erase from cursor to end of screen -----------------------
3040static void clear_to_eos(void)
3041{
3042 write1(ESC_CLEAR2EOS);
3043}
3044
3045//----- Start standout mode ------------------------------------ 3035//----- Start standout mode ------------------------------------
3046static void standout_start(void) 3036static void standout_start(void)
3047{ 3037{
@@ -3068,7 +3058,7 @@ static void indicate_error(void)
3068{ 3058{
3069#if ENABLE_FEATURE_VI_CRASHME 3059#if ENABLE_FEATURE_VI_CRASHME
3070 if (crashme > 0) 3060 if (crashme > 0)
3071 return; // generate a random command 3061 return;
3072#endif 3062#endif
3073 if (!err_method) { 3063 if (!err_method) {
3074 write1(ESC_BELL); 3064 write1(ESC_BELL);
@@ -3177,7 +3167,7 @@ static void print_literal(char *buf, const char *s)
3177 } 3167 }
3178 if (c < ' ' || c == 0x7f) { 3168 if (c < ' ' || c == 0x7f) {
3179 *d++ = '^'; 3169 *d++ = '^';
3180 c |= '@'; /* 0x40 */ 3170 c |= '@'; // 0x40
3181 if (c == 0x7f) 3171 if (c == 0x7f)
3182 c = '?'; 3172 c = '?';
3183 } 3173 }
@@ -3259,17 +3249,17 @@ static int format_edit_status(void)
3259 cur, tot, percent); 3249 cur, tot, percent);
3260 3250
3261 if (ret >= 0 && ret < trunc_at) 3251 if (ret >= 0 && ret < trunc_at)
3262 return ret; /* it all fit */ 3252 return ret; // it all fit
3263 3253
3264 return trunc_at; /* had to truncate */ 3254 return trunc_at; // had to truncate
3265#undef tot 3255#undef tot
3266} 3256}
3267 3257
3268//----- Force refresh of all Lines ----------------------------- 3258//----- Force refresh of all Lines -----------------------------
3269static void redraw(int full_screen) 3259static void redraw(int full_screen)
3270{ 3260{
3271 place_cursor(0, 0); 3261 // cursor to top,left; clear to the end of screen
3272 clear_to_eos(); 3262 write1(ESC_SET_CURSOR_TOPLEFT ESC_CLEAR2EOS);
3273 screen_erase(); // erase the internal screen buffer 3263 screen_erase(); // erase the internal screen buffer
3274 last_status_cksum = 0; // force status update 3264 last_status_cksum = 0; // force status update
3275 refresh(full_screen); // this will redraw the entire display 3265 refresh(full_screen); // this will redraw the entire display
@@ -3354,7 +3344,7 @@ static void refresh(int full_screen)
3354#else 3344#else
3355 if (c != columns || r != rows) { 3345 if (c != columns || r != rows) {
3356 full_screen = TRUE; 3346 full_screen = TRUE;
3357 /* update screen memory since SIGWINCH won't have done it */ 3347 // update screen memory since SIGWINCH won't have done it
3358 new_screen(rows, columns); 3348 new_screen(rows, columns);
3359 } 3349 }
3360#endif 3350#endif
@@ -3431,7 +3421,6 @@ static void refresh(int full_screen)
3431 3421
3432//--------------------------------------------------------------------- 3422//---------------------------------------------------------------------
3433//----- the Ascii Chart ----------------------------------------------- 3423//----- the Ascii Chart -----------------------------------------------
3434//
3435// 00 nul 01 soh 02 stx 03 etx 04 eot 05 enq 06 ack 07 bel 3424// 00 nul 01 soh 02 stx 03 etx 04 eot 05 enq 06 ack 07 bel
3436// 08 bs 09 ht 0a nl 0b vt 0c np 0d cr 0e so 0f si 3425// 08 bs 09 ht 0a nl 0b vt 0c np 0d cr 0e so 0f si
3437// 10 dle 11 dc1 12 dc2 13 dc3 14 dc4 15 nak 16 syn 17 etb 3426// 10 dle 11 dc1 12 dc2 13 dc3 14 dc4 15 nak 16 syn 17 etb
@@ -3466,7 +3455,7 @@ static void do_cmd(int c)
3466 3455
3467 show_status_line(); 3456 show_status_line();
3468 3457
3469 /* if this is a cursor key, skip these checks */ 3458 // if this is a cursor key, skip these checks
3470 switch (c) { 3459 switch (c) {
3471 case KEYCODE_UP: 3460 case KEYCODE_UP:
3472 case KEYCODE_DOWN: 3461 case KEYCODE_DOWN:
@@ -3499,7 +3488,7 @@ static void do_cmd(int c)
3499 } 3488 }
3500 } 3489 }
3501 if (cmd_mode == 1) { 3490 if (cmd_mode == 1) {
3502 // hitting "Insert" twice means "R" replace mode 3491 // hitting "Insert" twice means "R" replace mode
3503 if (c == KEYCODE_INSERT) goto dc5; 3492 if (c == KEYCODE_INSERT) goto dc5;
3504 // insert the char c at "dot" 3493 // insert the char c at "dot"
3505 if (1 <= c || Isprint(c)) { 3494 if (1 <= c || Isprint(c)) {
@@ -3958,7 +3947,7 @@ static void do_cmd(int c)
3958 } 3947 }
3959 if (cmdcnt == 0) 3948 if (cmdcnt == 0)
3960 cmdcnt = 1; 3949 cmdcnt = 1;
3961 /* fall through */ 3950 // fall through
3962 case 'G': // G- goto to a line number (default= E-O-F) 3951 case 'G': // G- goto to a line number (default= E-O-F)
3963 dot = end - 1; // assume E-O-F 3952 dot = end - 1; // assume E-O-F
3964 if (cmdcnt > 0) { 3953 if (cmdcnt > 0) {