From b531baa7fdfeb527a1ec7ec18aec5189f75c490d Mon Sep 17 00:00:00 2001 From: tg Date: Sun, 12 Mar 2017 02:04:15 +0000 Subject: [PATCH] =?UTF-8?q?add=20a=20=E2=80=9C\builtin=E2=80=9D=20builtin,?= =?UTF-8?q?=20make=20it=20forward=20assignments,=20fix=20some=20bugs=20rel?= =?UTF-8?q?ated=20to=20that:=20=E2=80=A2=20while=20AT&T=20ksh=20may=20do?= =?UTF-8?q?=20it,=20POSIX=20says=20nothing=20about=20allowing=20=20=20decl?= =?UTF-8?q?aration=20commands=20only=20without=20vars=20and=20redirections?= =?UTF-8?q?,=20and=20=20=20=E2=80=9Cwithout=20vars=E2=80=9D=20especially?= =?UTF-8?q?=20seems=20against=20which=20commands=20they=20are=20=E2=80=A2?= =?UTF-8?q?=20fix=20relationship=20between=20forwarders=20and=20real=20dec?= =?UTF-8?q?laration=20commands=20=E2=80=A2=20clean=20up=20c=5Fbuiltin=20vs?= =?UTF-8?q?=20shcomexec=20mess?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also, re-run “make repool” with a fixed src/scripts/stringpool.sh,v 1.3 --- exec.c | 19 ++++++++++-- funcs.c | 13 +++++---- lex.c | 16 +++++----- sh.h | 90 +++++++++++++++++++++++++++++---------------------------- syn.c | 36 +++++++---------------- 5 files changed, 88 insertions(+), 86 deletions(-) diff --git a/exec.c b/exec.c index 85e930c..fd8de2c 100644 --- a/exec.c +++ b/exec.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.189 2017/03/11 23:22:34 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.190 2017/03/12 02:04:12 tg Exp $"); #ifndef MKSH_DEFAULT_EXECSHELL #define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh" @@ -982,8 +982,13 @@ scriptexec(struct op *tp, const char **ap) int c_builtin(const char **wp) { - return (call_builtin(ktsearch(&builtins, *wp, hash(*wp)), wp, - Tbuiltin, false)); + return (call_builtin(get_builtin(*wp), wp, Tbuiltin, false)); +} + +struct tbl * +get_builtin(const char *s) +{ + return (s && *s ? ktsearch(&builtins, s, hash(s)) : NULL); } /* @@ -1089,6 +1094,14 @@ builtin(const char *name, int (*func) (const char **)) /* external utility overrides built-in utility, with flags */ flag |= LOW_BI; break; + case '-': + /* is declaration utility if argv[1] is one (POSIX: command) */ + flag |= DECL_FWDR; + break; + case '^': + /* is declaration utility (POSIX: export, readonly) */ + flag |= DECL_UTIL; + break; default: goto flags_seen; } diff --git a/funcs.c b/funcs.c index d38288d..7888d36 100644 --- a/funcs.c +++ b/funcs.c @@ -38,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.325 2017/03/11 23:22:35 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.326 2017/03/12 02:04:13 tg Exp $"); #if HAVE_KILLPG /* @@ -92,6 +92,7 @@ c_false(const char **wp MKSH_A_UNUSED) /* * A leading = means assignments before command are kept. * A leading * means a POSIX special builtin. + * A leading ^ means declaration utility, - forwarder. */ const struct builtin mkshbuiltins[] = { {Tsgdot, c_dot}, @@ -100,19 +101,19 @@ const struct builtin mkshbuiltins[] = { /* no =: AT&T manual wrong */ {Talias, c_alias}, {"*=break", c_brkcont}, - {T_builtin, c_builtin}, + {T__builtin, c_builtin}, {Tbuiltin, c_builtin}, {Tbcat, c_cat}, {Tcd, c_cd}, /* dash compatibility hack */ {"chdir", c_cd}, - {Tcommand, c_command}, + {T_command, c_command}, {"*=continue", c_brkcont}, {"echo", c_print}, {"*=eval", c_eval}, {"*=exec", c_exec}, {"*=exit", c_exitreturn}, - {Tsgexport, c_typeset}, + {Tdsgexport, c_typeset}, {Tfalse, c_false}, {"fc", c_fc}, {Tgetopts, c_getopts}, @@ -124,7 +125,7 @@ const struct builtin mkshbuiltins[] = { {"print", c_print}, {"pwd", c_pwd}, {Tread, c_read}, - {Tsgreadonly, c_typeset}, + {Tdsgreadonly, c_typeset}, {"!realpath", c_realpath}, {"~rename", c_rename}, {"*=return", c_exitreturn}, @@ -138,7 +139,7 @@ const struct builtin mkshbuiltins[] = { {"*=times", c_times}, {"*=trap", c_trap}, {Ttrue, c_true}, - {Tgtypeset, c_typeset}, + {Tdgtypeset, c_typeset}, {"ulimit", c_ulimit}, {"umask", c_umask}, {Tunalias, c_unalias}, diff --git a/lex.c b/lex.c index 0596ea7..662c480 100644 --- a/lex.c +++ b/lex.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.229 2017/02/18 02:33:12 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.230 2017/03/12 02:04:14 tg Exp $"); /* * states while lexing word @@ -1014,15 +1014,12 @@ yylex(int cf) while ((dp - ident) < IDENT && (c = *sp++) == CHAR) *dp++ = *sp++; if (c != EOS) - /* word is not unquoted */ + /* word is not unquoted, or space ran out */ dp = ident; /* make sure the ident array stays NUL padded */ memset(dp, 0, (ident + IDENT) - dp + 1); - if (!(cf & (KEYWORD | ALIAS))) - return (LWORD); - - if (*ident != '\0') { + if (*ident != '\0' && (cf & (KEYWORD | ALIAS))) { struct tbl *p; uint32_t h = hash(ident); @@ -1077,9 +1074,12 @@ yylex(int cf) goto Again; } } - } else if (cf & ALIAS) { + } else if (*ident == '\0') { /* retain typeset et al. even when quoted */ - if (assign_command((dp = wdstrip(yylval.cp, 0)), true)) + struct tbl *tt = get_builtin((dp = wdstrip(yylval.cp, 0))); + uint32_t flag = tt ? tt->flag : 0; + + if (flag & (DECL_UTIL | DECL_FWDR)) strlcpy(ident, dp, sizeof(ident)); afree(dp, ATEMP); } diff --git a/sh.h b/sh.h index a6cae69..469b91a 100644 --- a/sh.h +++ b/sh.h @@ -175,9 +175,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.793 2017/02/18 02:33:14 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.794 2017/03/12 02:04:14 tg Exp $"); #endif -#define MKSH_VERSION "R54 2017/02/18" +#define MKSH_VERSION "R54 2017/03/11" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES @@ -847,8 +847,8 @@ EXTERN char null[] E_INIT(""); #ifndef HAVE_STRING_POOLING /* helpers for pooled strings */ EXTERN const char T4spaces[] E_INIT(" "); -#define T1space (T4spaces + 3) -EXTERN const char Tcolsp[] E_INIT(": "); +#define T1space (Treal_sp2 + 5) +#define Tcolsp (Tf_sD_ + 2) EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n"); #define TC_IFSWS (TC_LEX1 + 7) EXTERN const char TFCEDIT_dollaru[] E_INIT("${FCEDIT:-/bin/ed} $_"); @@ -857,15 +857,15 @@ EXTERN const char Tsgdot[] E_INIT("*=."); EXTERN const char Taugo[] E_INIT("augo"); EXTERN const char Tbracket[] E_INIT("["); #define Tdot (Tsgdot + 2) -EXTERN const char Talias[] E_INIT("alias"); -EXTERN const char Tbadsubst[] E_INIT("bad substitution"); +#define Talias (Tunalias + 2) +#define Tbadsubst (Tfg_badsubst + 10) EXTERN const char Tbg[] E_INIT("bg"); EXTERN const char Tbad_bsize[] E_INIT("bad shf/buf/bsize"); #define Tbsize (Tbad_bsize + 12) EXTERN const char Tbad_sig_ss[] E_INIT("%s: bad signal '%s'"); #define Tbad_sig_s (Tbad_sig_ss + 4) -EXTERN const char Tgbuiltin[] E_INIT("=builtin"); -#define Tbuiltin (Tgbuiltin + 1) +EXTERN const char T__builtin[] E_INIT("-\\builtin"); +#define Tbuiltin (T__builtin + 2) EXTERN const char Toomem[] E_INIT("can't allocate %zu data bytes"); EXTERN const char Tcant_cd[] E_INIT("restricted shell - can't cd"); EXTERN const char Tcant_find[] E_INIT("can't find"); @@ -874,26 +874,27 @@ EXTERN const char Tcant_open[] E_INIT("can't open"); EXTERN const char Tbcat[] E_INIT("!cat"); #define Tcat (Tbcat + 1) #define Tcd (Tcant_cd + 25) -EXTERN const char Tcommand[] E_INIT("command"); +#define T_command (T_funny_command + 9) +#define Tcommand (T_funny_command + 10) EXTERN const char Tcreate[] E_INIT("create"); EXTERN const char TELIF_unexpected[] E_INIT("TELIF unexpected"); EXTERN const char TEXECSHELL[] E_INIT("EXECSHELL"); -EXTERN const char Tsgexport[] E_INIT("*=export"); -#define Texport (Tsgexport + 2) +EXTERN const char Tdsgexport[] E_INIT("^*=export"); +#define Texport (Tdsgexport + 3) #ifdef __OS2__ EXTERN const char Textproc[] E_INIT("extproc"); #endif EXTERN const char Tfalse[] E_INIT("false"); EXTERN const char Tfg[] E_INIT("fg"); EXTERN const char Tfg_badsubst[] E_INIT("fileglob: bad substitution"); -EXTERN const char Tfile[] E_INIT("file"); +#define Tfile (Tfile_fd + 20) EXTERN const char Tfile_fd[] E_INIT("function definition file"); EXTERN const char TFPATH[] E_INIT("FPATH"); EXTERN const char T_function[] E_INIT(" function"); #define Tfunction (T_function + 1) -EXTERN const char T_funny_command[] E_INIT("funny $() command"); +EXTERN const char T_funny_command[] E_INIT("funny $()-command"); EXTERN const char Tgetopts[] E_INIT("getopts"); -EXTERN const char Thistory[] E_INIT("history"); +#define Thistory (Tnot_in_history + 7) EXTERN const char Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented"); EXTERN const char Tjobs[] E_INIT("jobs"); EXTERN const char Tjob_not_started[] E_INIT("job not started"); @@ -909,20 +910,20 @@ EXTERN const char Tnot_found_s[] E_INIT("%s not found"); #define TOLDPWD (Tno_OLDPWD + 3) #define Topen (Tcant_open + 6) #define TPATH (TFPATH + 1) -EXTERN const char Tpv[] E_INIT("pv"); +#define Tpv (TpVv + 1) EXTERN const char TpVv[] E_INIT("Vpv"); #define TPWD (Tno_OLDPWD + 6) -EXTERN const char Tread[] E_INIT("read"); -EXTERN const char Tsgreadonly[] E_INIT("*=readonly"); -#define Treadonly (Tsgreadonly + 2) +#define Tread (Tshf_read + 4) +EXTERN const char Tdsgreadonly[] E_INIT("^*=readonly"); +#define Treadonly (Tdsgreadonly + 3) EXTERN const char Tredirection_dup[] E_INIT("can't finish (dup) redirection"); #define Tredirection (Tredirection_dup + 19) -EXTERN const char Treal_sp1[] E_INIT("real "); +#define Treal_sp1 (Treal_sp2 + 1) EXTERN const char Treal_sp2[] E_INIT(" real "); EXTERN const char Treq_arg[] E_INIT("requires an argument"); EXTERN const char Tselect[] E_INIT("select"); EXTERN const char Tsgset[] E_INIT("*=set"); -#define Tset (Tsgset + 2) +#define Tset (Tf_parm + 18) #define Tsh (Tmksh + 2) #define TSHELL (TEXECSHELL + 4) EXTERN const char Tshf_read[] E_INIT("shf_read"); @@ -935,27 +936,27 @@ EXTERN const char Ttoo_many_args[] E_INIT("too many arguments"); EXTERN const char Ttrue[] E_INIT("true"); EXTERN const char Ttty_fd_dupof[] E_INIT("dup of tty fd"); #define Ttty_fd (Ttty_fd_dupof + 7) -EXTERN const char Tgtypeset[] E_INIT("=typeset"); -#define Ttypeset (Tgtypeset + 1) +EXTERN const char Tdgtypeset[] E_INIT("^=typeset"); +#define Ttypeset (Tdgtypeset + 2) #define Tugo (Taugo + 1) EXTERN const char Tunalias[] E_INIT("unalias"); #define Tunexpected (TELIF_unexpected + 6) EXTERN const char Tunknown_option[] E_INIT("unknown option"); -EXTERN const char Tuser_sp1[] E_INIT("user "); +#define Tuser_sp1 (Tuser_sp2 + 1) EXTERN const char Tuser_sp2[] E_INIT(" user "); #define Twrite (Tshf_write + 4) EXTERN const char Tf__S[] E_INIT(" %S"); -EXTERN const char Tf__d[] E_INIT(" %d"); +#define Tf__d (Tf_sd + 2) EXTERN const char Tf__ss[] E_INIT(" %s%s"); -EXTERN const char Tf__sN[] E_INIT(" %s\n"); +#define Tf__sN (Tf_s_s_sN + 5) EXTERN const char Tf_sSs[] E_INIT("%s/%s"); -EXTERN const char Tf_T[] E_INIT("%T"); +#define Tf_T (Tf_s_T + 3) EXTERN const char Tf_dN[] E_INIT("%d\n"); EXTERN const char Tf_s_[] E_INIT("%s "); EXTERN const char Tf_s_T[] E_INIT("%s %T"); EXTERN const char Tf_s_s_sN[] E_INIT("%s %s %s\n"); -EXTERN const char Tf_s_s[] E_INIT("%s %s"); -EXTERN const char Tf_s_sD_s[] E_INIT("%s %s: %s"); +#define Tf_s_s (Tf_sD_s_s + 4) +#define Tf_s_sD_s (Tf_cant + 6) EXTERN const char Tf_optfoo[] E_INIT("%s%s-%c: %s"); EXTERN const char Tf_sD_[] E_INIT("%s: "); EXTERN const char Tf_szs[] E_INIT("%s: %zd %s"); @@ -968,18 +969,18 @@ EXTERN const char Tf_nonnum[] E_INIT("non-numeric %s %s '%s'"); #endif EXTERN const char Tf_S_[] E_INIT("%S "); #define Tf_S (Tf__S + 1) -EXTERN const char Tf_lu[] E_INIT("%lu"); +#define Tf_lu (Tf_toolarge + 17) EXTERN const char Tf_toolarge[] E_INIT("%s %s too large: %lu"); EXTERN const char Tf_ldfailed[] E_INIT("%s %s(%d, %ld) failed: %s"); -#define Tf_ss (Tf__ss + 1) +#define Tf_ss (Tf_sss + 2) EXTERN const char Tf_sss[] E_INIT("%s%s%s"); EXTERN const char Tf_sD_s_sD_s[] E_INIT("%s: %s %s: %s"); EXTERN const char Tf_toomany[] E_INIT("too many %ss\n"); EXTERN const char Tf_sd[] E_INIT("%s %d"); -#define Tf_s (Tf__ss + 3) +#define Tf_s (Tf_temp + 28) EXTERN const char Tft_end[] E_INIT("%;"); EXTERN const char Tft_R[] E_INIT("%R"); -#define Tf_d (Tf__d + 1) +#define Tf_d (Tf_sd + 3) EXTERN const char Tf_sD_s_qs[] E_INIT("%s: %s '%s'"); EXTERN const char Tf_ro[] E_INIT("read-only: %s"); EXTERN const char Tf_flags[] E_INIT("%s: flags 0x%X"); @@ -988,8 +989,8 @@ EXTERN const char Tf_ssfaileds[] E_INIT("%s: %s failed: %s"); EXTERN const char Tf_sD_sD_s[] E_INIT("%s: %s: %s"); EXTERN const char Tf__c_[] E_INIT("-%c "); EXTERN const char Tf_sD_s_s[] E_INIT("%s: %s %s"); -#define Tf_sN (Tf__sN + 1) -#define Tf_sD_s (Tf_s_sD_s + 3) +#define Tf_sN (Tf_s_s_sN + 6) +#define Tf_sD_s (Tf_temp + 24) EXTERN const char T_devtty[] E_INIT("/dev/tty"); #else /* helpers for string pooling */ #define T4spaces " " @@ -1010,7 +1011,7 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty"); #define Tbsize "bsize" #define Tbad_sig_ss "%s: bad signal '%s'" #define Tbad_sig_s "bad signal '%s'" -#define Tgbuiltin "=builtin" +#define T__builtin "-\\builtin" #define Tbuiltin "builtin" #define Toomem "can't allocate %zu data bytes" #define Tcant_cd "restricted shell - can't cd" @@ -1020,11 +1021,12 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty"); #define Tbcat "!cat" #define Tcat "cat" #define Tcd "cd" +#define T_command "-command" #define Tcommand "command" #define Tcreate "create" #define TELIF_unexpected "TELIF unexpected" #define TEXECSHELL "EXECSHELL" -#define Tsgexport "*=export" +#define Tdsgexport "^*=export" #define Texport "export" #ifdef __OS2__ #define Textproc "extproc" @@ -1037,7 +1039,7 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty"); #define TFPATH "FPATH" #define T_function " function" #define Tfunction "function" -#define T_funny_command "funny $() command" +#define T_funny_command "funny $()-command" #define Tgetopts "getopts" #define Thistory "history" #define Tintovfl "integer overflow %zu %c %zu prevented" @@ -1059,7 +1061,7 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty"); #define TpVv "Vpv" #define TPWD "PWD" #define Tread "read" -#define Tsgreadonly "*=readonly" +#define Tdsgreadonly "^*=readonly" #define Treadonly "readonly" #define Tredirection_dup "can't finish (dup) redirection" #define Tredirection "redirection" @@ -1081,7 +1083,7 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty"); #define Ttrue "true" #define Ttty_fd_dupof "dup of tty fd" #define Ttty_fd "tty fd" -#define Tgtypeset "=typeset" +#define Tdgtypeset "^=typeset" #define Ttypeset "typeset" #define Tugo "ugo" #define Tunalias "unalias" @@ -1322,7 +1324,7 @@ EXTERN sigset_t sm_default, sm_sigchld; /* name of called builtin function (used by error functions) */ EXTERN const char *builtin_argv0; -/* is called builtin SPEC_BI? (also KEEPASN, odd use though) */ +/* is called builtin a POSIX special builtin? (error functions only) */ EXTERN bool builtin_spec; /* current working directory */ @@ -1492,6 +1494,8 @@ EXTERN bool last_lookup_was_array; #define SPEC_BI BIT(12) /* a POSIX special builtin */ #define LOWER_BI BIT(13) /* (with LOW_BI) override even w/o flags */ #define LOW_BI BIT(14) /* external utility overrides built-in one */ +#define DECL_UTIL BIT(15) /* is declaration utility */ +#define DECL_FWDR BIT(16) /* is declaration utility forwarder */ /* * Attributes that can be set by the user (used to decide if an unset @@ -2011,7 +2015,8 @@ int glob_str(char *, XPtrV *, bool); char *do_tilde(char *); /* exec.c */ int execute(struct op * volatile, volatile int, volatile int * volatile); -int shcomexec(const char **); +int c_builtin(const char **); +struct tbl *get_builtin(const char *); struct tbl *findfunc(const char *, uint32_t, bool); int define(const char *, struct op *); const char *builtin(const char *, int (*)(const char **)); @@ -2078,8 +2083,6 @@ int c_times(const char **); int timex(struct op *, int, volatile int *); void timex_hook(struct op *, char ** volatile *); int c_exec(const char **); -/* dummy function (just need pointer value), special case in comexec() */ -#define c_builtin shcomexec int c_test(const char **); #if HAVE_MKNOD int c_mknod(const char **); @@ -2287,7 +2290,6 @@ char *shf_smprintf(const char *, ...) ssize_t shf_vfprintf(struct shf *, const char *, va_list) MKSH_A_FORMAT(__printf__, 2, 0); /* syn.c */ -int assign_command(const char *, bool) MKSH_A_PURE; void initkeywords(void); struct op *compile(Source *, bool); bool parse_usec(const char *, struct timeval *); diff --git a/syn.c b/syn.c index f138c37..74661ff 100644 --- a/syn.c +++ b/syn.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.116 2017/03/11 22:49:56 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.117 2017/03/12 02:04:15 tg Exp $"); struct nesting_state { int start_token; /* token than began nesting (eg, FOR) */ @@ -289,11 +289,11 @@ get_command(int cf) t->lineno = source->line; goto get_command_start; while (/* CONSTCOND */ 1) { - bool check_assign_cmd; + bool check_decl_utility; if (XPsize(args) == 0) { get_command_start: - check_assign_cmd = true; + check_decl_utility = true; cf = sALIAS | CMDASN; } else if (t->u.evalflags) cf = CMDWORD | CMDASN; @@ -311,16 +311,15 @@ get_command(int cf) case LWORD: ACCEPT; - /* - * the iopn == 0 and XPsize(vars) == 0 are - * dubious but AT&T ksh acts this way - */ - if (iopn == 0 && XPsize(vars) == 0 && - check_assign_cmd) { - if (assign_command(ident, false)) + if (check_decl_utility) { + struct tbl *tt = get_builtin(ident); + uint32_t flag; + + flag = tt ? tt->flag : 0; + if (flag & DECL_UTIL) t->u.evalflags = DOVACHECK; - else if (strcmp(ident, Tcommand) != 0) - check_assign_cmd = false; + if (!(flag & DECL_FWDR)) + check_decl_utility = false; } if ((XPsize(args) == 0 || Flag(FKEYWORD)) && is_wdvarassign(yylval.cp)) @@ -937,19 +936,6 @@ compile(Source *s, bool skiputf8bom) return (outtree); } -/* lexical analysis for declaration utilities */ -int -assign_command(const char *s, bool docommand) -{ - if (!*s) - return (0); - return ((strcmp(s, Talias) == 0) || - (strcmp(s, Texport) == 0) || - (strcmp(s, Treadonly) == 0) || - (docommand && (strcmp(s, Tcommand) == 0)) || - (strcmp(s, Ttypeset) == 0)); -} - /* Check if we are in the middle of reading an alias */ static int inalias(struct source *s)