aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-04-25 11:55:42 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2021-04-28 11:29:33 +0200
commitacd3079fd1be1b350ab3f75338de67ad1e933024 (patch)
treec8f9c6f4ab15b8f3a702b0ff42dca98a224925f6
parent852ffbee341ccbcdb6400ad5cb4688b410e236b5 (diff)
downloadbusybox-w32-acd3079fd1be1b350ab3f75338de67ad1e933024.tar.gz
busybox-w32-acd3079fd1be1b350ab3f75338de67ad1e933024.tar.bz2
busybox-w32-acd3079fd1be1b350ab3f75338de67ad1e933024.zip
vi: expand '%' and '#' in colon commands
Track the current and alternate filenames. The placeholders '%' and '#' can be used in arguments to colon commands to represent the current and alternate filenames respectively. Backslash can be used to allow literal '%' and '#' characters to be entered. This feature is controlled by the configuration option FEATURE_VI_COLON_EXPAND. function old new delta expand_args - 198 +198 colon 3751 3927 +176 update_filename - 70 +70 init_filename - 48 +48 .rodata 105218 105239 +21 get_one_char 115 124 +9 edit_file 835 838 +3 do_cmd 4724 4727 +3 init_text_buffer 190 172 -18 ------------------------------------------------------------------------------ (add/remove: 3/0 grow/shrink: 5/1 up/down: 528/-18) Total: 510 bytes Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/vi.c126
1 files changed, 112 insertions, 14 deletions
diff --git a/editors/vi.c b/editors/vi.c
index 715961019..6a879fa8a 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -53,6 +53,14 @@
53//config: Enable a limited set of colon commands. This does not 53//config: Enable a limited set of colon commands. This does not
54//config: provide an "ex" mode. 54//config: provide an "ex" mode.
55//config: 55//config:
56//config:config FEATURE_VI_COLON_EXPAND
57//config: bool "Expand \"%\" and \"#\" in colon commands"
58//config: default y
59//config: depends on FEATURE_VI_COLON
60//config: help
61//config: Expand the special characters \"%\" (current filename)
62//config: and \"#\" (alternate filename) in colon commands.
63//config:
56//config:config FEATURE_VI_YANKMARK 64//config:config FEATURE_VI_YANKMARK
57//config: bool "Enable yank/put commands and mark cmds" 65//config: bool "Enable yank/put commands and mark cmds"
58//config: default y 66//config: default y
@@ -347,6 +355,9 @@ struct globals {
347 // [don't make smallint!] 355 // [don't make smallint!]
348 int last_status_cksum; // hash of current status line 356 int last_status_cksum; // hash of current status line
349 char *current_filename; 357 char *current_filename;
358#if ENABLE_FEATURE_VI_COLON_EXPAND
359 char *alt_filename;
360#endif
350 char *screenbegin; // index into text[], of top line on the screen 361 char *screenbegin; // index into text[], of top line on the screen
351 char *screen; // pointer to the virtual screen buffer 362 char *screen; // pointer to the virtual screen buffer
352 int screensize; // and its size 363 int screensize; // and its size
@@ -471,6 +482,7 @@ struct globals {
471#define have_status_msg (G.have_status_msg ) 482#define have_status_msg (G.have_status_msg )
472#define last_status_cksum (G.last_status_cksum ) 483#define last_status_cksum (G.last_status_cksum )
473#define current_filename (G.current_filename ) 484#define current_filename (G.current_filename )
485#define alt_filename (G.alt_filename )
474#define screen (G.screen ) 486#define screen (G.screen )
475#define screensize (G.screensize ) 487#define screensize (G.screensize )
476#define screenbegin (G.screenbegin ) 488#define screenbegin (G.screenbegin )
@@ -2198,6 +2210,41 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
2198 return p; 2210 return p;
2199} 2211}
2200 2212
2213#if ENABLE_FEATURE_VI_COLON_EXPAND
2214static void init_filename(char *fn)
2215{
2216 char *copy = xstrdup(fn);
2217
2218 if (current_filename == NULL) {
2219 current_filename = copy;
2220 } else {
2221 free(alt_filename);
2222 alt_filename = copy;
2223 }
2224}
2225#else
2226# define init_filename(f) ((void)(0))
2227#endif
2228
2229static void update_filename(char *fn)
2230{
2231#if ENABLE_FEATURE_VI_COLON_EXPAND
2232 if (fn == NULL)
2233 return;
2234
2235 if (current_filename == NULL || strcmp(fn, current_filename) != 0) {
2236 free(alt_filename);
2237 alt_filename = current_filename;
2238 current_filename = xstrdup(fn);
2239 }
2240#else
2241 if (fn != current_filename) {
2242 free(current_filename);
2243 current_filename = xstrdup(fn);
2244 }
2245#endif
2246}
2247
2201// read text from file or create an empty buf 2248// read text from file or create an empty buf
2202// will also update current_filename 2249// will also update current_filename
2203static int init_text_buffer(char *fn) 2250static int init_text_buffer(char *fn)
@@ -2209,10 +2256,7 @@ static int init_text_buffer(char *fn)
2209 text_size = 10240; 2256 text_size = 10240;
2210 screenbegin = dot = end = text = xzalloc(text_size); 2257 screenbegin = dot = end = text = xzalloc(text_size);
2211 2258
2212 if (fn != current_filename) { 2259 update_filename(fn);
2213 free(current_filename);
2214 current_filename = xstrdup(fn);
2215 }
2216 rc = file_insert(fn, text, 1); 2260 rc = file_insert(fn, text, 1);
2217 if (rc < 0) { 2261 if (rc < 0) {
2218 // file doesnt exist. Start empty buf with dummy line 2262 // file doesnt exist. Start empty buf with dummy line
@@ -2556,6 +2600,43 @@ static void setops(char *args, int flg_no)
2556} 2600}
2557# endif 2601# endif
2558 2602
2603# if ENABLE_FEATURE_VI_COLON_EXPAND
2604static char *expand_args(char *args)
2605{
2606 char *s, *t;
2607 const char *replace;
2608
2609 args = xstrdup(args);
2610 for (s = args; *s; s++) {
2611 if (*s == '%') {
2612 replace = current_filename;
2613 } else if (*s == '#') {
2614 replace = alt_filename;
2615 } else {
2616 if (*s == '\\' && s[1] != '\0') {
2617 for (t = s++; *t; t++)
2618 *t = t[1];
2619 }
2620 continue;
2621 }
2622
2623 if (replace == NULL) {
2624 free(args);
2625 status_line_bold("No previous filename");
2626 return NULL;
2627 }
2628
2629 *s = '\0';
2630 t = xasprintf("%s%s%s", args, replace, s+1);
2631 s = t + (s - args) + strlen(replace);
2632 free(args);
2633 args = t;
2634 }
2635 return args;
2636}
2637# else
2638# define expand_args(a) (a)
2639# endif
2559#endif /* FEATURE_VI_COLON */ 2640#endif /* FEATURE_VI_COLON */
2560 2641
2561// buf must be no longer than MAX_INPUT_LEN! 2642// buf must be no longer than MAX_INPUT_LEN!
@@ -2620,7 +2701,7 @@ static void colon(char *buf)
2620#else 2701#else
2621 2702
2622 char c, *buf1, *q, *r; 2703 char c, *buf1, *q, *r;
2623 char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args; 2704 char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args, *exp = NULL;
2624 int i, l, li, b, e; 2705 int i, l, li, b, e;
2625 int useforce; 2706 int useforce;
2626 2707
@@ -2708,9 +2789,12 @@ static void colon(char *buf)
2708 else if (cmd[0] == '!') { // run a cmd 2789 else if (cmd[0] == '!') { // run a cmd
2709 int retcode; 2790 int retcode;
2710 // :!ls run the <cmd> 2791 // :!ls run the <cmd>
2792 exp = expand_args(buf + 1);
2793 if (exp == NULL)
2794 goto ret;
2711 go_bottom_and_clear_to_eol(); 2795 go_bottom_and_clear_to_eol();
2712 cookmode(); 2796 cookmode();
2713 retcode = system(buf + 1); // run the cmd 2797 retcode = system(exp); // run the cmd
2714 if (retcode) 2798 if (retcode)
2715 printf("\nshell returned %i\n\n", retcode); 2799 printf("\nshell returned %i\n\n", retcode);
2716 rawmode(); 2800 rawmode();
@@ -2739,7 +2823,9 @@ static void colon(char *buf)
2739 } 2823 }
2740 if (args[0]) { 2824 if (args[0]) {
2741 // the user supplied a file name 2825 // the user supplied a file name
2742 fn = args; 2826 fn = exp = expand_args(args);
2827 if (exp == NULL)
2828 goto ret;
2743 } else if (current_filename == NULL) { 2829 } else if (current_filename == NULL) {
2744 // no user file name, no current name- punt 2830 // no user file name, no current name- punt
2745 status_line_bold("No current filename"); 2831 status_line_bold("No current filename");
@@ -2763,7 +2849,7 @@ static void colon(char *buf)
2763 status_line("'%s'%s" 2849 status_line("'%s'%s"
2764 IF_FEATURE_VI_READONLY("%s") 2850 IF_FEATURE_VI_READONLY("%s")
2765 " %uL, %uC", 2851 " %uL, %uC",
2766 current_filename, 2852 fn,
2767 (size < 0 ? " [New file]" : ""), 2853 (size < 0 ? " [New file]" : ""),
2768 IF_FEATURE_VI_READONLY( 2854 IF_FEATURE_VI_READONLY(
2769 ((readonly_mode) ? " [Readonly]" : ""), 2855 ((readonly_mode) ? " [Readonly]" : ""),
@@ -2777,8 +2863,10 @@ static void colon(char *buf)
2777 } 2863 }
2778 if (args[0]) { 2864 if (args[0]) {
2779 // user wants a new filename 2865 // user wants a new filename
2780 free(current_filename); 2866 exp = expand_args(args);
2781 current_filename = xstrdup(args); 2867 if (exp == NULL)
2868 goto ret;
2869 update_filename(exp);
2782 } else { 2870 } else {
2783 // user wants file status info 2871 // user wants file status info
2784 last_status_cksum = 0; // force status update 2872 last_status_cksum = 0; // force status update
@@ -2862,7 +2950,10 @@ static void colon(char *buf)
2862 2950
2863 if (args[0]) { 2951 if (args[0]) {
2864 // the user supplied a file name 2952 // the user supplied a file name
2865 fn = args; 2953 fn = exp = expand_args(args);
2954 if (exp == NULL)
2955 goto ret;
2956 init_filename(fn);
2866 } else if (current_filename == NULL) { 2957 } else if (current_filename == NULL) {
2867 // no user file name, no current name- punt 2958 // no user file name, no current name- punt
2868 status_line_bold("No current filename"); 2959 status_line_bold("No current filename");
@@ -3042,12 +3133,16 @@ static void colon(char *buf)
3042 if (args[0]) { 3133 if (args[0]) {
3043 struct stat statbuf; 3134 struct stat statbuf;
3044 3135
3045 if (!useforce && (fn == NULL || strcmp(fn, args) != 0) && 3136 exp = expand_args(args);
3046 stat(args, &statbuf) == 0) { 3137 if (exp == NULL)
3138 goto ret;
3139 if (!useforce && (fn == NULL || strcmp(fn, exp) != 0) &&
3140 stat(exp, &statbuf) == 0) {
3047 status_line_bold("File exists (:w! overrides)"); 3141 status_line_bold("File exists (:w! overrides)");
3048 goto ret; 3142 goto ret;
3049 } 3143 }
3050 fn = args; 3144 fn = exp;
3145 init_filename(fn);
3051 } 3146 }
3052# if ENABLE_FEATURE_VI_READONLY 3147# if ENABLE_FEATURE_VI_READONLY
3053 else if (readonly_mode && !useforce && fn) { 3148 else if (readonly_mode && !useforce && fn) {
@@ -3109,6 +3204,9 @@ static void colon(char *buf)
3109 not_implemented(cmd); 3204 not_implemented(cmd);
3110 } 3205 }
3111 ret: 3206 ret:
3207# if ENABLE_FEATURE_VI_COLON_EXPAND
3208 free(exp);
3209# endif
3112 dot = bound_dot(dot); // make sure "dot" is valid 3210 dot = bound_dot(dot); // make sure "dot" is valid
3113 return; 3211 return;
3114# if ENABLE_FEATURE_VI_SEARCH 3212# if ENABLE_FEATURE_VI_SEARCH