From 8e72608c1c21ef1a50863aecbfa16c7b6ec2bf57 Mon Sep 17 00:00:00 2001 From: Johnothan King Date: Thu, 3 Feb 2022 21:52:53 -0800 Subject: [PATCH] Export all variables assigned to while allexport is on (#431) All variables that are assigned a value should be exported while the allexport shell option is enabled. This works in most cases, but variables assigned to with ${var:=foo} or $((var=123)) aren't exported while allexport is on. src/cmd/ksh93/sh/name.c: - nv_putval(): This is the central assignment function; all forms of variable assignment end up here. So this is the best place to check for SH_ALLEXPORT and turn on the export attribute. - nv_setlist(): Remove allexport handling, now redundant. src/cmd/ksh93/bltins/read.c: sh_readline(): - Remove allexport handling, now redundant. src/cmd/ksh93/sh/main.c: sh_main(): - nv_putval() is used to initialize PS4 and IFS using nv_putval(); this is after an -a/--allexport specified on the ksh command line has been processed, so temporarily turn that off. Co-authored-by: Martijn Dekker --- NEWS | 6 ++++++ src/cmd/ksh93/bltins/read.c | 5 ----- src/cmd/ksh93/data/builtins.c | 5 ++--- src/cmd/ksh93/include/version.h | 2 +- src/cmd/ksh93/sh.1 | 3 ++- src/cmd/ksh93/sh/main.c | 10 +++++++-- src/cmd/ksh93/sh/name.c | 9 +++++--- src/cmd/ksh93/tests/attributes.sh | 27 +++++++++++++++++++++++- src/cmd/ksh93/tests/namespace.sh | 35 ++++++++++++++++++++++++++++++- 9 files changed, 85 insertions(+), 17 deletions(-) diff --git a/NEWS b/NEWS index 2e06fe309..33b902b10 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,12 @@ For full details, see the git log at: https://github.com/ksh93/ksh/tree/1.0 Any uppercase BUG_* names are modernish shell bug IDs. +2022-02-02: + +- Fixed the -a/allexport option to export all variables that are assigned + values. Previously, arithmetic $((var=1)) or conditional ${var:=value} + assignments were not exported even with allexport on. + 2022-02-01: - Upon invocation, the interactive shell no longer leaves the user without diff --git a/src/cmd/ksh93/bltins/read.c b/src/cmd/ksh93/bltins/read.c index 8bc37fec9..39bfb5c62 100644 --- a/src/cmd/ksh93/bltins/read.c +++ b/src/cmd/ksh93/bltins/read.c @@ -801,11 +801,6 @@ int sh_readline(char **names, volatile int fd, int flags, ssize_t size, long tim } while(1) { - if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.') && !nv_isattr(np,NV_EXPORT)) - { - nv_onattr(np,NV_EXPORT); - sh_envput(sh.env,np); - } if(name) { nv_close(np); diff --git a/src/cmd/ksh93/data/builtins.c b/src/cmd/ksh93/data/builtins.c index e05179422..446d8adef 100644 --- a/src/cmd/ksh93/data/builtins.c +++ b/src/cmd/ksh93/data/builtins.c @@ -168,9 +168,8 @@ const struct shtable3 shtab_builtins[] = const char sh_set[] = -"[a?Set the export attribute for each variable whose name does not " - "contain a \b.\b that you assign a value in the current shell " - "environment.]" +"[a?All variables that are assigned a value while this option is on are " + "automatically exported.]" "[b?The shell writes a message to standard error as soon it detects that " "a background job completes rather than waiting until the next prompt.]" "[e?A simple command that has an non-zero exit status will cause the shell " diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index c66fb0022..6a69bd738 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -21,7 +21,7 @@ #define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */ #define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */ -#define SH_RELEASE_DATE "2022-02-01" /* must be in this format for $((.sh.version)) */ +#define SH_RELEASE_DATE "2022-02-02" /* must be in this format for $((.sh.version)) */ #define SH_RELEASE_CPYR "(c) 2020-2022 Contributors to ksh " SH_RELEASE_FORK /* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */ diff --git a/src/cmd/ksh93/sh.1 b/src/cmd/ksh93/sh.1 index 8ec08e19c..7e927a5ef 100644 --- a/src/cmd/ksh93/sh.1 +++ b/src/cmd/ksh93/sh.1 @@ -7387,7 +7387,8 @@ See \f2History Expansion\fP above. . .TP 8 .B \-a -All subsequent variables that are defined are automatically exported. +All variables that are assigned a value while this option is on +are automatically exported. .TP 8 .B \-b Prints job completion messages as soon as a background job changes diff --git a/src/cmd/ksh93/sh/main.c b/src/cmd/ksh93/sh/main.c index 4da08a3d1..53e3cfb81 100644 --- a/src/cmd/ksh93/sh/main.c +++ b/src/cmd/ksh93/sh/main.c @@ -142,8 +142,6 @@ int sh_main(int ac, char *av[], Shinit_f userinit) } sh.fn_depth = sh.dot_depth = 0; command = error_info.id; - if(nv_isnull(PS4NOD)) - nv_putval(PS4NOD,e_traceprompt,NV_RDONLY); path_pwd(); iop = (Sfio_t*)0; if(sh_isoption(SH_POSIX)) @@ -358,7 +356,15 @@ int sh_main(int ac, char *av[], Shinit_f userinit) sh_onoption(SH_EMACS); #endif /* SHOPT_ESH */ } + /* (Re)set PS4 and IFS, but don't export these now even if allexport is on. */ + i = (sh_isoption(SH_ALLEXPORT) != 0); + sh_offoption(SH_ALLEXPORT); + if(nv_isnull(PS4NOD)) + nv_putval(PS4NOD,e_traceprompt,NV_RDONLY); nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY); + if(i) + sh_onoption(SH_ALLEXPORT); + /* Start main execution loop. */ exfile(iop,fdin); sh_done(0); } diff --git a/src/cmd/ksh93/sh/name.c b/src/cmd/ksh93/sh/name.c index a0da49ba0..0cbb80721 100644 --- a/src/cmd/ksh93/sh/name.c +++ b/src/cmd/ksh93/sh/name.c @@ -289,8 +289,6 @@ void nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ) flags |= NV_NOSCOPE; #endif /* SHOPT_NAMESPACE */ flags &= ~(NV_TYPE|NV_ARRAY|NV_IARRAY); - if(sh_isoption(SH_ALLEXPORT)) - flags |= NV_EXPORT; if(sh.prefix) { flags &= ~(NV_IDENT|NV_EXPORT); @@ -1617,7 +1615,12 @@ void nv_putval(register Namval_t *np, const char *string, int flags) sh.argaddr = 0; if(sh.subshell && !nv_local && !(flags&NV_RDONLY)) np = sh_assignok(np,1); - + /* Export the variable if 'set -o allexport' is enabled */ + if(sh_isoption(SH_ALLEXPORT)) + { + flags |= NV_EXPORT; + nv_onattr(np,NV_EXPORT); + } if(np->nvfun && np->nvfun->disc && !(flags&NV_NODISC) && !nv_isref(np)) { /* This function contains disc */ diff --git a/src/cmd/ksh93/tests/attributes.sh b/src/cmd/ksh93/tests/attributes.sh index d8fb41364..3d2911350 100755 --- a/src/cmd/ksh93/tests/attributes.sh +++ b/src/cmd/ksh93/tests/attributes.sh @@ -2,7 +2,7 @@ # # # This software is part of the ast package # # Copyright (c) 1982-2012 AT&T Intellectual Property # -# Copyright (c) 2020-2021 Contributors to ksh 93u+m # +# Copyright (c) 2020-2022 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -705,5 +705,30 @@ do (( ${var:=1} == 0 )) || err_exit "\${var:=1} should yield 0 after typeset -$flag var=0 (got '$var')" done +# ====== +# allexport tests +# https://github.com/ksh93/ksh/pull/431 +set -o allexport +unset bar +: ${bar:=baz} +exp='typeset -x bar=baz' +got=$(typeset -p bar) +[[ $got == "$exp" ]] || err_exit 'Variable ${bar} should be exported' \ + "(expected $(printf %q "$exp"), got $(printf %q "$got"))" +# Set variable in arithmetic expressions +unset bar +((bar=1)) +exp='typeset -x bar=1' +got=$(typeset -p bar) +[[ $got == "$exp" ]] || err_exit 'Variable ${bar} should be exported' \ + "(expected $(printf %q "$exp"), got $(printf %q "$got"))" +unset bar +: $((bar=2)) +exp='typeset -x bar=2' +got=$(typeset -p bar) +[[ $got == "$exp" ]] || err_exit 'Variable ${bar} should be exported' \ + "(expected $(printf %q "$exp"), got $(printf %q "$got"))" +set +o allexport + # ====== exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/namespace.sh b/src/cmd/ksh93/tests/namespace.sh index 83ed0ccd1..1d596d53a 100755 --- a/src/cmd/ksh93/tests/namespace.sh +++ b/src/cmd/ksh93/tests/namespace.sh @@ -2,7 +2,7 @@ # # # This software is part of the ast package # # Copyright (c) 1982-2012 AT&T Intellectual Property # -# Copyright (c) 2020-2021 Contributors to ksh 93u+m # +# Copyright (c) 2020-2022 Contributors to ksh 93u+m # # and is licensed under the # # Eclipse Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -98,4 +98,37 @@ false false [[ $(.x.runxrun) == 'xfun local bar' ]] || err_exit 'namespace function on FPATH failed' +# ====== +# Namespace variables should retain their exoprt attribute, even +# though they are not actually exported outside the namespace block. +set -o allexport +namespace foo_nam +{ + typeset bar + typeset foo + typeset baz=baz + integer three +} +: ${.foo_nam.bar:=BAZ} +exp='typeset -x .foo_nam.bar=BAZ' +got=$(typeset -p .foo_nam.bar) +[[ $got == "$exp" ]] || err_exit 'Variable ${.foo_nam.bar} did not retain -x attribute' \ + "(expected $(printf %q "$exp"), got $(printf %q "$got"))" +.foo_nam.foo=FOO +exp='typeset -x .foo_nam.foo=FOO' +got=$(typeset -p .foo_nam.foo) +[[ $got == "$exp" ]] || err_exit 'Variable ${.foo_nam.foo} did not retain -x attribute' \ + "(expected $(printf %q "$exp"), got $(printf %q "$got"))" +exp='typeset -x .foo_nam.baz=baz' +got=$(typeset -p .foo_nam.baz) +[[ $got == "$exp" ]] || err_exit 'Variable ${.foo_nam.baz} did not retain -x attribute' \ + "(expected $(printf %q "$exp"), got $(printf %q "$got"))" +((.foo_nam.three=3)) +exp='typeset -x -l -i .foo_nam.three=3' +got=$(typeset -p .foo_nam.three) +[[ $got == "$exp" ]] || err_exit 'Variable ${.foo_nam.three} did not retain -x attribute' \ + "(expected $(printf %q "$exp"), got $(printf %q "$got"))" +set +o allexport + +# ====== exit $((Errors<125?Errors:125))