summaryrefslogtreecommitdiff
path: root/editors/vi.c
diff options
context:
space:
mode:
authorRon Yorston2021-04-06 22:11:21 +0100
committerDenys Vlasenko2021-04-08 12:50:01 +0200
commit9f017d9db0eb5522eb9c140a2d839461c677eb8e (patch)
tree154b0b9921a0cb009bcbf693557c82980b01101b /editors/vi.c
parent24198f652f10dca5603df7c704263358ca21f5ce (diff)
downloadbusybox-9f017d9db0eb5522eb9c140a2d839461c677eb8e.zip
busybox-9f017d9db0eb5522eb9c140a2d839461c677eb8e.tar.gz
vi: changes to option handling
Since commit 70ee23399 (vi: code shrink) the ':set' command is unable to process multiple options on a line. Fix this by temporarily null-terminating each option. Change the default setting for all options to off to match vim. Actually, 'flash' isn't an option in vim, only traditional vi, where it's on by default. In vim the corresponding option is 'visualbell' which defaults to off. POSIX doesn't have either of these. Allow the abbreviation 'ts' for the 'tabstop' option. Issue an error message if: - an option is not implemented - an option that takes a value has no '=' or has a 'no' prefix - a boolean option has a '=' function old new delta colon 2944 3003 +59 .rodata 103171 103189 +18 vi_main 274 270 -4 setops 73 - -73 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 2/1 up/down: 77/-77) Total: 0 bytes v2: Try harder to detect invalid options. Thanks to Peter D for pointing this out. Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'editors/vi.c')
-rw-r--r--editors/vi.c91
1 files changed, 57 insertions, 34 deletions
diff --git a/editors/vi.c b/editors/vi.c
index 04d584f..1c5a32b 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -278,16 +278,23 @@ struct globals {
int text_size; // size of the allocated buffer
// the rest
- smallint vi_setops;
-#define VI_AUTOINDENT 1
-#define VI_SHOWMATCH 2
-#define VI_IGNORECASE 4
-#define VI_ERR_METHOD 8
+ smallint vi_setops; // set by setops()
+#define VI_AUTOINDENT (1 << 0)
+#define VI_ERR_METHOD (1 << 1)
+#define VI_IGNORECASE (1 << 2)
+#define VI_SHOWMATCH (1 << 3)
+#define VI_TABSTOP (1 << 4)
#define autoindent (vi_setops & VI_AUTOINDENT)
-#define showmatch (vi_setops & VI_SHOWMATCH )
+#define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash
#define ignorecase (vi_setops & VI_IGNORECASE)
-// indicate error with beep or flash
-#define err_method (vi_setops & VI_ERR_METHOD)
+#define showmatch (vi_setops & VI_SHOWMATCH )
+// order of constants and strings must match
+#define OPTS_STR \
+ "ai\0""autoindent\0" \
+ "fl\0""flash\0" \
+ "ic\0""ignorecase\0" \
+ "sm\0""showmatch\0" \
+ "ts\0""tabstop\0"
#if ENABLE_FEATURE_VI_READONLY
smallint readonly_mode;
@@ -2380,17 +2387,38 @@ static char *get_address(char *p, int *b, int *e) // get two colon addrs, if pre
}
# if ENABLE_FEATURE_VI_SET && ENABLE_FEATURE_VI_SETOPTS
-static void setops(const char *args, const char *nm_longname, int flg_no, int opt)
+static void setops(char *args, int flg_no)
{
- const char *a = args + flg_no;
+ char *eq;
+ int index;
+
+ eq = strchr(args, '=');
+ if (eq) *eq = '\0';
+ index = index_in_strings(OPTS_STR, args + flg_no);
+ if (eq) *eq = '=';
+ if (index < 0) {
+ bad:
+ status_line_bold("bad option: %s", args);
+ return;
+ }
- if (strcmp(a, nm_longname) == 0
- || strcmp(a, nm_longname + 3) == 0
- ) {
- if (flg_no)
- vi_setops &= ~opt;
- else
- vi_setops |= opt;
+ index = 1 << (index >> 1); // convert to VI_bit
+
+ if (index & VI_TABSTOP) {
+ int t;
+ if (!eq || flg_no) // no "=NNN" or it is "notabstop"?
+ goto bad;
+ t = bb_strtou(eq + 1, NULL, 10);
+ if (t <= 0 || t > MAX_TABSTOP)
+ goto bad;
+ tabstop = t;
+ return;
+ }
+ if (eq) goto bad; // boolean option has "="?
+ if (flg_no) {
+ vi_setops &= ~index;
+ } else {
+ vi_setops |= index;
}
}
# endif
@@ -2750,10 +2778,10 @@ static void colon(char *buf)
# if ENABLE_FEATURE_VI_SET
} else if (strncmp(cmd, "set", i) == 0) { // set or clear features
# if ENABLE_FEATURE_VI_SETOPTS
- char *argp;
+ char *argp, *argn, oldch;
# endif
// only blank is regarded as args delimiter. What about tab '\t'?
- if (!args[0] || strcasecmp(args, "all") == 0) {
+ if (!args[0] || strcmp(args, "all") == 0) {
// print out values of all options
# if ENABLE_FEATURE_VI_SETOPTS
status_line_bold(
@@ -2777,17 +2805,12 @@ static void colon(char *buf)
i = 0;
if (argp[0] == 'n' && argp[1] == 'o') // "noXXX"
i = 2;
- setops(argp, "ai""\0""autoindent", i, VI_AUTOINDENT);
- setops(argp, "fl""\0""flash" , i, VI_ERR_METHOD);
- setops(argp, "ic""\0""ignorecase", i, VI_IGNORECASE);
- setops(argp, "sm""\0""showmatch" , i, VI_SHOWMATCH );
- if (strncmp(argp, "tabstop=", 8) == 0) {
- int t = bb_strtou(argp + 8, NULL, 10);
- if (t > 0 && t <= MAX_TABSTOP)
- tabstop = t;
- }
- argp = skip_non_whitespace(argp);
- argp = skip_whitespace(argp);
+ argn = skip_non_whitespace(argp);
+ oldch = *argn;
+ *argn = '\0';
+ setops(argp, i);
+ *argn = oldch;
+ argp = skip_whitespace(argn);
}
# endif /* FEATURE_VI_SETOPTS */
# endif /* FEATURE_VI_SET */
@@ -4383,10 +4406,10 @@ int vi_main(int argc, char **argv)
}
#endif
- // autoindent is not default in vim 7.3
- vi_setops = /*VI_AUTOINDENT |*/ VI_SHOWMATCH | VI_IGNORECASE;
- // 1- process $HOME/.exrc file (not inplemented yet)
- // 2- process EXINIT variable from environment
+ // 0: all of our options are disabled by default in vim
+ //vi_setops = 0;
+ // 1- process EXINIT variable from environment
+ // 2- if EXINIT is unset process $HOME/.exrc file (not inplemented yet)
// 3- process command line args
#if ENABLE_FEATURE_VI_COLON
{