From 382982ac00d81d9f71f1dbfeb670e544a6e56a55 Mon Sep 17 00:00:00 2001 From: Philippe Benard Date: Sat, 7 Jun 2025 19:21:57 +0200 Subject: [PATCH] bug-666: TLDR; - src/cmd/ksh93/include/shlex.h Implement yet another lex state funcalias, set to 1 when function keyword is an alias expansion. - src/cmd/ksh93/sh/lex.c Allow alias expansion on word following a 'function ' expansion. - src/cmd/ksh93/tests/alias.sh Update alias.sh to catch alias x='function ' failure. Explanations: Alias allows aliases to be chained while expanded alias value has a trailing space. Assuming alias 'x=function ' y=f Parsing x y { echo :\); } x is a simple cmd, a check for alias is done and is successfull we got 'function ' The parser then then enter funct() for parsing a function, the nex token fetch is not a simple cmd anymore, no check for alias will be done, next token is then y and become the function name. To fix this, when expanding to 'function ' we need to setup a lexer state, I called it funcalias in shlex.c, it is then set to 1 in sh_lex() When funct() parse y { ... the funcalias==1 allows a check for alias, we then get the 'f' expansion and reset funcalias. At this point other alias expansion are permitted, though hard to follow. $ alias 'x=function ' y=f z='{ ' t='echo ' u='AA ' v='}' $ x y z t u v $ f AA --- src/cmd/ksh93/include/shlex.h | 1 + src/cmd/ksh93/sh/lex.c | 36 ++++++++++++++++++++++++++++++++++- src/cmd/ksh93/tests/alias.sh | 6 ++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/cmd/ksh93/include/shlex.h b/src/cmd/ksh93/include/shlex.h index 0894a732f88f..e2eba00564a0 100644 --- a/src/cmd/ksh93/include/shlex.h +++ b/src/cmd/ksh93/include/shlex.h @@ -56,6 +56,7 @@ struct _shlex_pvt_lexdata_ char warn; char message; char arith; + char funcalias; /* bug-666: Phi: */ char *first; int level; int lastc; diff --git a/src/cmd/ksh93/sh/lex.c b/src/cmd/ksh93/sh/lex.c index 643fda58c444..ca2870562a48 100644 --- a/src/cmd/ksh93/sh/lex.c +++ b/src/cmd/ksh93/sh/lex.c @@ -1481,6 +1481,14 @@ int sh_lex(Lex_t* lp) } } c = 0; + /* + * bug-666: Phi: + * + */ + if(lp->lexd.funcalias==1) + { goto check_alias; + } + if(!lp->lex.skipword) { if(n>1 && lp->lex.reservok==1 && mode==ST_NAME && @@ -1519,6 +1527,8 @@ int sh_lex(Lex_t* lp) { /* check for aliases */ Namval_t* np; + + check_alias: /* bug-666: Phi: */ if(!lp->lex.incase && !assignment && fcpeek(0)!=LPAREN && (np=nv_search(state,sh.alias_tree,0)) && !nv_isattr(np,NV_NOEXPAND) @@ -1526,11 +1536,35 @@ int sh_lex(Lex_t* lp) && (!sh_isstate(SH_NOALIAS) || nv_isattr(np,NV_NOFREE)) && (state=nv_getval(np))) { + int t; /* bug-666: Phi: */ setupalias(lp,state,np); nv_onattr(np,NV_NOEXPAND); lp->lex.reservok = 1; lp->assignok |= lp->lex.reservok; - return sh_lex(lp); + /* + * bug-666: Phi: Check if we just expanded + * "function " (i.e trailig space), if so we + * got to set lp->lexd.funcalias=1; + * so that next funct() will have a chance to + * expand next word. The original return + * below is replaced with the funcalias + * setup + */ + /* return sh_lex(lp); */ + if(lp->lexd.funcalias==1) + { + lp->lexd.funcalias++; + } + t=sh_lex(lp); + if(strcmp(state,"function ")==0) + { + lp->lexd.funcalias=1; + } + else + { + lp->lexd.funcalias=0; + } + return t; } } lp->lex.reservok = 0; diff --git a/src/cmd/ksh93/tests/alias.sh b/src/cmd/ksh93/tests/alias.sh index a349485fd449..1b27f65a0da5 100755 --- a/src/cmd/ksh93/tests/alias.sh +++ b/src/cmd/ksh93/tests/alias.sh @@ -319,5 +319,11 @@ chmod +x bad_func # bug only triggered if file is executable (FPATH=$PWD; alias -t bad_func 2>/dev/null; typeset -f bad_func >/dev/null) (($? > 0)) || err_exit "'hash'/'alias -t' autoloads function" +# bug-666: Phi: +alias 'x=function ' y=f z='{ ' t='echo ' u='AA ' v='}' +x y z t u v +got=$(f) +[ "$got" = 'AA' ] || err_exit "alias x='function ' not working" + # ====== exit $((Errors<125?Errors:125))