summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston2021-04-25 11:55:42 +0100
committerDenys Vlasenko2021-04-28 11:29:33 +0200
commitacd3079fd1be1b350ab3f75338de67ad1e933024 (patch)
treec8f9c6f4ab15b8f3a702b0ff42dca98a224925f6
parent852ffbee341ccbcdb6400ad5cb4688b410e236b5 (diff)
downloadbusybox-acd3079fd1be1b350ab3f75338de67ad1e933024.zip
busybox-acd3079fd1be1b350ab3f75338de67ad1e933024.tar.gz
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 7159610..6a879fa 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -53,6 +53,14 @@
//config: Enable a limited set of colon commands. This does not
//config: provide an "ex" mode.
//config:
+//config:config FEATURE_VI_COLON_EXPAND
+//config: bool "Expand \"%\" and \"#\" in colon commands"
+//config: default y
+//config: depends on FEATURE_VI_COLON
+//config: help
+//config: Expand the special characters \"%\" (current filename)
+//config: and \"#\" (alternate filename) in colon commands.
+//config:
//config:config FEATURE_VI_YANKMARK
//config: bool "Enable yank/put commands and mark cmds"
//config: default y
@@ -347,6 +355,9 @@ struct globals {
// [don't make smallint!]
int last_status_cksum; // hash of current status line
char *current_filename;
+#if ENABLE_FEATURE_VI_COLON_EXPAND
+ char *alt_filename;
+#endif
char *screenbegin; // index into text[], of top line on the screen
char *screen; // pointer to the virtual screen buffer
int screensize; // and its size
@@ -471,6 +482,7 @@ struct globals {
#define have_status_msg (G.have_status_msg )
#define last_status_cksum (G.last_status_cksum )
#define current_filename (G.current_filename )
+#define alt_filename (G.alt_filename )
#define screen (G.screen )
#define screensize (G.screensize )
#define screenbegin (G.screenbegin )
@@ -2198,6 +2210,41 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
return p;
}
+#if ENABLE_FEATURE_VI_COLON_EXPAND
+static void init_filename(char *fn)
+{
+ char *copy = xstrdup(fn);
+
+ if (current_filename == NULL) {
+ current_filename = copy;
+ } else {
+ free(alt_filename);
+ alt_filename = copy;
+ }
+}
+#else
+# define init_filename(f) ((void)(0))
+#endif
+
+static void update_filename(char *fn)
+{
+#if ENABLE_FEATURE_VI_COLON_EXPAND
+ if (fn == NULL)
+ return;
+
+ if (current_filename == NULL || strcmp(fn, current_filename) != 0) {
+ free(alt_filename);
+ alt_filename = current_filename;
+ current_filename = xstrdup(fn);
+ }
+#else
+ if (fn != current_filename) {
+ free(current_filename);
+ current_filename = xstrdup(fn);
+ }
+#endif
+}
+
// read text from file or create an empty buf
// will also update current_filename
static int init_text_buffer(char *fn)
@@ -2209,10 +2256,7 @@ static int init_text_buffer(char *fn)
text_size = 10240;
screenbegin = dot = end = text = xzalloc(text_size);
- if (fn != current_filename) {
- free(current_filename);
- current_filename = xstrdup(fn);
- }
+ update_filename(fn);
rc = file_insert(fn, text, 1);
if (rc < 0) {
// file doesnt exist. Start empty buf with dummy line
@@ -2556,6 +2600,43 @@ static void setops(char *args, int flg_no)
}
# endif
+# if ENABLE_FEATURE_VI_COLON_EXPAND
+static char *expand_args(char *args)
+{
+ char *s, *t;
+ const char *replace;
+
+ args = xstrdup(args);
+ for (s = args; *s; s++) {
+ if (*s == '%') {
+ replace = current_filename;
+ } else if (*s == '#') {
+ replace = alt_filename;
+ } else {
+ if (*s == '\\' && s[1] != '\0') {
+ for (t = s++; *t; t++)
+ *t = t[1];
+ }
+ continue;
+ }
+
+ if (replace == NULL) {
+ free(args);
+ status_line_bold("No previous filename");
+ return NULL;
+ }
+
+ *s = '\0';
+ t = xasprintf("%s%s%s", args, replace, s+1);
+ s = t + (s - args) + strlen(replace);
+ free(args);
+ args = t;
+ }
+ return args;
+}
+# else
+# define expand_args(a) (a)
+# endif
#endif /* FEATURE_VI_COLON */
// buf must be no longer than MAX_INPUT_LEN!
@@ -2620,7 +2701,7 @@ static void colon(char *buf)
#else
char c, *buf1, *q, *r;
- char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args;
+ char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args, *exp = NULL;
int i, l, li, b, e;
int useforce;
@@ -2708,9 +2789,12 @@ static void colon(char *buf)
else if (cmd[0] == '!') { // run a cmd
int retcode;
// :!ls run the <cmd>
+ exp = expand_args(buf + 1);
+ if (exp == NULL)
+ goto ret;
go_bottom_and_clear_to_eol();
cookmode();
- retcode = system(buf + 1); // run the cmd
+ retcode = system(exp); // run the cmd
if (retcode)
printf("\nshell returned %i\n\n", retcode);
rawmode();
@@ -2739,7 +2823,9 @@ static void colon(char *buf)
}
if (args[0]) {
// the user supplied a file name
- fn = args;
+ fn = exp = expand_args(args);
+ if (exp == NULL)
+ goto ret;
} else if (current_filename == NULL) {
// no user file name, no current name- punt
status_line_bold("No current filename");
@@ -2763,7 +2849,7 @@ static void colon(char *buf)
status_line("'%s'%s"
IF_FEATURE_VI_READONLY("%s")
" %uL, %uC",
- current_filename,
+ fn,
(size < 0 ? " [New file]" : ""),
IF_FEATURE_VI_READONLY(
((readonly_mode) ? " [Readonly]" : ""),
@@ -2777,8 +2863,10 @@ static void colon(char *buf)
}
if (args[0]) {
// user wants a new filename
- free(current_filename);
- current_filename = xstrdup(args);
+ exp = expand_args(args);
+ if (exp == NULL)
+ goto ret;
+ update_filename(exp);
} else {
// user wants file status info
last_status_cksum = 0; // force status update
@@ -2862,7 +2950,10 @@ static void colon(char *buf)
if (args[0]) {
// the user supplied a file name
- fn = args;
+ fn = exp = expand_args(args);
+ if (exp == NULL)
+ goto ret;
+ init_filename(fn);
} else if (current_filename == NULL) {
// no user file name, no current name- punt
status_line_bold("No current filename");
@@ -3042,12 +3133,16 @@ static void colon(char *buf)
if (args[0]) {
struct stat statbuf;
- if (!useforce && (fn == NULL || strcmp(fn, args) != 0) &&
- stat(args, &statbuf) == 0) {
+ exp = expand_args(args);
+ if (exp == NULL)
+ goto ret;
+ if (!useforce && (fn == NULL || strcmp(fn, exp) != 0) &&
+ stat(exp, &statbuf) == 0) {
status_line_bold("File exists (:w! overrides)");
goto ret;
}
- fn = args;
+ fn = exp;
+ init_filename(fn);
}
# if ENABLE_FEATURE_VI_READONLY
else if (readonly_mode && !useforce && fn) {
@@ -3109,6 +3204,9 @@ static void colon(char *buf)
not_implemented(cmd);
}
ret:
+# if ENABLE_FEATURE_VI_COLON_EXPAND
+ free(exp);
+# endif
dot = bound_dot(dot); // make sure "dot" is valid
return;
# if ENABLE_FEATURE_VI_SEARCH