From 897475ab023040efed9f199af5daffe43451c1d2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 1 Jun 2019 16:35:09 +0200 Subject: [PATCH] ash: allocate line editing structure only if needed function old new delta optschanged 91 128 +37 historycmd 13 17 +4 setcmd 80 78 -2 ash_main 1167 1150 -17 options 576 552 -24 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/3 up/down: 41/-43) Total: -2 bytes Signed-off-by: Denys Vlasenko --- shell/ash.c | 107 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 37 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index 924e17f32..c8857366c 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -315,9 +315,16 @@ static const char *const optletters_optnames[] = { "e" "errexit", "f" "noglob", "I" "ignoreeof", +/* The below allows this invocation: + * ash -c 'set -i; echo $-; sleep 5; echo $-' + * to be ^C-ed and get to interactive ash prompt. + * bash does not support this "set -i". bash also has no + * "set -o interactive". + */ "i" "interactive", "m" "monitor", "n" "noexec", +/* Ditto: bash has no "set -s" and "set -o stdin" */ "s" "stdin", "x" "xtrace", "v" "verbose", @@ -334,10 +341,25 @@ static const char *const optletters_optnames[] = { ,"\0" "debug" #endif }; +//bash 4.4.23 also has these opts (with these defaults): +//braceexpand on +//emacs on +//errtrace off +//functrace off +//hashall on +//histexpand off +//history on +//interactive-comments on +//keyword off +//onecmd off +//physical off +//posix off +//privileged off #define optletters(n) optletters_optnames[n][0] #define optnames(n) (optletters_optnames[n] + 1) + enum { NOPTS = ARRAY_SIZE(optletters_optnames) }; @@ -9514,8 +9536,8 @@ setinteractive(int on) setsignal(SIGINT); setsignal(SIGQUIT); setsignal(SIGTERM); -#if !ENABLE_FEATURE_SH_EXTRA_QUIET if (is_interactive > 1) { +#if !ENABLE_FEATURE_SH_EXTRA_QUIET /* Looks like they want an interactive shell */ static smallint did_banner; @@ -9529,8 +9551,12 @@ setinteractive(int on) ); did_banner = 1; } - } #endif +#if ENABLE_FEATURE_EDITING + if (!line_input_state) + line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); +#endif + } } static void @@ -9542,10 +9568,12 @@ optschanged(void) setinteractive(iflag); setjobctl(mflag); #if ENABLE_FEATURE_EDITING_VI - if (viflag) - line_input_state->flags |= VI_MODE; - else - line_input_state->flags &= ~VI_MODE; + if (line_input_state) { + if (viflag) + line_input_state->flags |= VI_MODE; + else + line_input_state->flags &= ~VI_MODE; + } #else viflag = 0; /* forcibly keep the option off */ #endif @@ -10519,13 +10547,11 @@ preadfd(void) else { # if ENABLE_ASH_IDLE_TIMEOUT int timeout = -1; - if (iflag) { - const char *tmout_var = lookupvar("TMOUT"); - if (tmout_var) { - timeout = atoi(tmout_var) * 1000; - if (timeout <= 0) - timeout = -1; - } + const char *tmout_var = lookupvar("TMOUT"); + if (tmout_var) { + timeout = atoi(tmout_var) * 1000; + if (timeout <= 0) + timeout = -1; } line_input_state->timeout = timeout; # endif @@ -11086,14 +11112,17 @@ setoption(int flag, int val) ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag); /* NOTREACHED */ } +/* If login_sh is not NULL, we are called to parse command line opts, + * not "set -opts" + */ static int -options(int cmdline, int *login_sh) +options(int *login_sh) { char *p; int val; int c; - if (cmdline) + if (login_sh) minusc = NULL; while ((p = *argptr) != NULL) { c = *p++; @@ -11104,7 +11133,7 @@ options(int cmdline, int *login_sh) if (c == '-') { val = 1; if (p[0] == '\0' || LONE_DASH(p)) { - if (!cmdline) { + if (!login_sh) { /* "-" means turn off -x and -v */ if (p[0] == '\0') xflag = vflag = 0; @@ -11117,26 +11146,31 @@ options(int cmdline, int *login_sh) } /* first char was + or - */ while ((c = *p++) != '\0') { - /* bash 3.2 indeed handles -c CMD and +c CMD the same */ - if (c == 'c' && cmdline) { - minusc = p; /* command is after shell args */ - } else if (c == 'o') { + if (login_sh) { + /* bash 3.2 indeed handles -c CMD and +c CMD the same */ + if (c == 'c') { + minusc = p; /* command is after shell args */ + continue; + } + if (c == 'l') { + *login_sh = 1; /* -l or +l == --login */ + continue; + } + /* bash does not accept +-login, we also won't */ + if (val && (c == '-')) { /* long options */ + if (strcmp(p, "login") == 0) { + *login_sh = 1; + } + break; + } + } + if (c == 'o') { if (plus_minus_o(*argptr, val)) { /* it already printed err message */ return 1; /* error */ } if (*argptr) argptr++; - } else if (cmdline && (c == 'l')) { /* -l or +l == --login */ - if (login_sh) - *login_sh = 1; - /* bash does not accept +-login, we also won't */ - } else if (cmdline && val && (c == '-')) { /* long options */ - if (strcmp(p, "login") == 0) { - if (login_sh) - *login_sh = 1; - } - break; } else { setoption(c, val); } @@ -11227,7 +11261,7 @@ setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) return showvars(nullstr, 0, VUNSET); INT_OFF; - retval = options(/*cmdline:*/ 0, NULL); + retval = options(/*login_sh:*/ NULL); if (retval == 0) { /* if no parse error... */ optschanged(); if (*argptr != NULL) { @@ -13685,7 +13719,8 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) static int FAST_FUNC historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { - show_history(line_input_state); + if (line_input_state) + show_history(line_input_state); return EXIT_SUCCESS; } #endif @@ -14001,7 +14036,8 @@ exitshell(void) int status; #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT - save_history(line_input_state); + if (line_input_state) + save_history(line_input_state); #endif status = exitstatus; TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); @@ -14123,7 +14159,7 @@ procargs(char **argv) argptr = xargv; for (i = 0; i < NOPTS; i++) optlist[i] = 2; - if (options(/*cmdline:*/ 1, &login_sh)) { + if (options(&login_sh)) { /* it already printed err message */ raise_exception(EXERROR); } @@ -14249,9 +14285,6 @@ int ash_main(int argc UNUSED_PARAM, char **argv) monitor(4, etext, profile_buf, sizeof(profile_buf), 50); #endif -#if ENABLE_FEATURE_EDITING - line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); -#endif state = 0; if (setjmp(jmploc.loc)) { smallint e;