diff options
author | Ron Yorston <rmy@pobox.com> | 2021-04-25 11:55:42 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-04-28 11:29:33 +0200 |
commit | acd3079fd1be1b350ab3f75338de67ad1e933024 (patch) | |
tree | c8f9c6f4ab15b8f3a702b0ff42dca98a224925f6 | |
parent | 852ffbee341ccbcdb6400ad5cb4688b410e236b5 (diff) | |
download | busybox-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.c | 126 |
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 | ||
2214 | static 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 | |||
2229 | static 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 |
2203 | static int init_text_buffer(char *fn) | 2250 | static 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 | ||
2604 | static 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 |