From 43cd8da2fe043a83c7fb82db686cd2c13efa3472 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Sun, 28 Nov 2021 00:31:46 +0100 Subject: [PATCH] Fix 'command' prefix in enum type def pre-parsing (re: 1dc18346) Symptom: $ ksh -c 'command enum -i P_t=(a b); P_t -A v=([f]=b); typeset -p v' ksh: syntax error at line 1: `(' unexpected Expected: no syntax error, and output of 'P_t -A v=([f]=b)'. src/cmd/ksh93/sh/parse.c: check_typedef(): - For enum, skip over any possible 'command' prefixes before pre-parsing options with optget (or, technically, skip anything else that might come before 'enum', though I don't think anything else is possible). - The sh_addbuiltin() call at the end to pre-add the builtin obtained the node pointer to the built-in and the node flags from the parser tree. This did not work if a 'command' prefix was present. However, we don't actually need this. For parsing purposes, the BLT_DCL flag for a declaration built-in is sufficient; this is what gets the parser to accept assignment-arguments including parentheses. So just apply that. In addition, let's point it to an actual dummy built-in, 'true' (SYSTRUE), so that if a user does run something like 'if false; then enum Foo_t=(...); fi', the leaked Foo_t dummy at least won't do anything (not even crash). --- src/cmd/ksh93/sh/parse.c | 9 ++++----- src/cmd/ksh93/tests/enum.sh | 10 ++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/cmd/ksh93/sh/parse.c b/src/cmd/ksh93/sh/parse.c index 7f55ce510..0f7373184 100644 --- a/src/cmd/ksh93/sh/parse.c +++ b/src/cmd/ksh93/sh/parse.c @@ -222,6 +222,9 @@ static void check_typedef(struct comnod *tp, char intypeset) char **argv = dp->dolval + ARG_SPARE; if(intypeset==2) { + /* Skip over possible 'command' prefix(es) */ + while(*argv && strcmp(*argv, SYSENUM->nvname)) + argv++; /* Skip over 'enum' options */ opt_info.index = 0; while(optget(argv, sh_optenum)) @@ -245,11 +248,7 @@ static void check_typedef(struct comnod *tp, char intypeset) } } if(cp) - { - Namval_t *mp=(Namval_t*)tp->comnamp ,*bp; - bp = sh_addbuiltin(cp, (Shbltin_f)mp->nvalue.bfp, (void*)0); - nv_onattr(bp,nv_isattr(mp,NV_PUBLIC)); - } + nv_onattr(sh_addbuiltin(cp, (Shbltin_f)SYSTRUE->nvalue.bfp, NIL(void*)), NV_BLTIN|BLT_DCL); } /* diff --git a/src/cmd/ksh93/tests/enum.sh b/src/cmd/ksh93/tests/enum.sh index c67e3a498..437752b86 100755 --- a/src/cmd/ksh93/tests/enum.sh +++ b/src/cmd/ksh93/tests/enum.sh @@ -146,5 +146,15 @@ a=orange; let "a+=2" 2>/dev/null && err_exit "arithmetic can assign out of range a=green; let "a-=2" 2>/dev/null && err_exit "arithmetic can assign out of range (subtract)" a=blue; let "a*=3" 2>/dev/null && err_exit "arithmetic can assign out of range (multiply)" +# ====== +# Enum types should parse with 'command' prefix(es) and options and instantly +# recognise subsequent builtins it creates, even as a oneliner, even with +# shcomp. (This requires an ugly parser hack that this tests for.) +got=$(eval 2>&1 'command command command enum -i -i -iii --igno -ii PARSER_t=(r g b); '\ +'command command PARSER_t -r -rrAAA -A -rArArA -Arrrrrrr hack=([C]=G); typeset -p hack') +exp='PARSER_t -r -A hack=([C]=g)' +[[ $got == "$exp" ]] || err_exit "incorrect typeset output for enum with command prefix and options" \ + "(expected $(printf %q "$exp"); got $(printf %q "$got"))" + # ====== exit $((Errors<125?Errors:125))