1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

New feature: 'typeset -g' as in bash 4.2+

typeset -g allows directly manipulating the attributes of variables
at the global level from any context. This feature already exists
on bash 4.2 and later.

mksh (R50+), yash and zsh have this flag as well, but it's slightly
different: it ignores the current local scope, but a parent local
scope from a calling function may still be used -- whereas on bash,
'-g' always refers to the global scope. Since ksh93 uses static
scoping (see III.Q28 at <http://kornshell.com/doc/faq.html>), only
the bash behaviour makes sense here.

Note that the implementation needs to be done both in nv_setlist()
(name.c) and in b_typeset() (typeset.c) because assignments are
executed before the typeset built-in itself. Hence also the
pre-parsing of typeset options in sh_exec().

src/cmd/ksh93/include/nval.h:
- Add new NV_GLOBAL bit flag, using a previously unused bit that
  still falls within the 32-bit integer range.

src/cmd/ksh93/sh/xec.c: sh_exec():
- When pre-parsing typeset flags, make -g pass the NV_GLOBAL flag
  to the nv_setlist() call that processes shell assignments prior
  to running the command.

src/cmd/ksh93/sh/name.c: nv_setlist():
- When the NV_GLOBAL bit flag is passed, save the current variable
  tree pointer (sh.var_tree) as well as the current namespace
  (sh.namespace) and temporarily set the former to the global
  variable tree (sh.var_base) and the latter to NULL. This makes
  assignments global and ignores namesapces.

src/cmd/ksh93/bltins/typeset.c:
- b_typeset():
  - Use NV_GLOBAL bit flag for -g.
  - Allow combining -n with -g, permitting 'typeset -gn var' or
    'nameref -g var' to create a global nameref from a function.
  - Do not allow a nonsensical use of -g when using nested typeset
    to define member variables of 'typeset -T' types. (Type method
    functions can still use it as normal.)
- setall():
  - If NV_GLOBAL is passed, use sh.var_base and deactivate
    sh.namespace as in nv_setlist(). This allows attributes
    to be set correctly for global variables.

src/cmd/ksh93/tests/{functions,namespace}.sh:
- Add regression tests based on reproducers for problems found
  by @hyenias in preliminary versions of this feature.

Resolves: https://github.com/ksh93/ksh/issues/479
This commit is contained in:
Martijn Dekker 2022-06-01 17:14:51 +01:00
parent f73b8617dd
commit ea300089a1
11 changed files with 167 additions and 8 deletions

View file

@ -1341,5 +1341,44 @@ got=$( { "$SHELL" "$tmp/crash_rhbz1117404.ksh"; } 2>&1)
((!(e = $?))) || err_exit 'crash while handling function-local trap' \
"(got status $e$( ((e>128)) && print -n /SIG && kill -l "$e"), $(printf %q "$got"))"
# ======
# 'typeset -g' should cause the active function scope to be ignored.
# https://github.com/ksh93/ksh/issues/479#issuecomment-1140523291
if ! command typeset -g x 2>/dev/null
then
warning "shell does not have 'typeset -g'; skipping those tests"
else
unset x arr a b c
# must specify the length for -X as the default is -X 24 on 32-bit systems and -X 32 on 64-bit systems
typeset -A exp=(
['x=123; function f { typeset -g x=456; }; function g { typeset x=789; f; }; g; typeset -p x']='x=456'
['x=123; function f { typeset -g -i x; }; f; typeset -p x']='typeset -i x=123'
['x=123; function f { typeset -g -F x; }; f; typeset -p x']='typeset -F x=123.0000000000'
['x=123; function f { typeset -g -E x; }; f; typeset -p x']='typeset -E x=123'
['x=123; function f { typeset -g -X24 x; }; f; typeset -p x']='typeset -X 24 x=0x1.ec0000000000000000000000p+6'
['x=aBc; function f { typeset -g -u x; }; f; typeset -p x']='typeset -u x=ABC'
['x=aBc; function f { typeset -g -l x; }; f; typeset -p x']='typeset -l x=abc'
['x=aBc; function f { typeset -g -L x; }; f; typeset -p x']='typeset -L 3 x=aBc'
['x=aBc; function f { typeset -g -R x; }; f; typeset -p x']='typeset -R 3 x=aBc'
['x=aBc; function f { typeset -g -Z x; }; f; typeset -p x']='typeset -Z 3 -R 3 x=aBc'
['x=aBc; function f { typeset -g -L2 x; }; f; typeset -p x']='typeset -L 2 x=aB'
['x=aBc; function f { typeset -g -R2 x; }; f; typeset -p x']='typeset -R 2 x=Bc'
['x=aBc; function f { typeset -g -Z2 x; }; f; typeset -p x']='typeset -Z 2 -R 2 x=Bc'
['x=8; function f { typeset -g -i2 x; }; f; typeset -p x']='typeset -i 2 x=2#1000'
['x=8; function f { typeset -g -i8 x; }; f; typeset -p x']='typeset -i 8 x=8#10'
['arr=(a b c); function f { typeset -g -i arr[1]=(1 2 3); }; f; typeset -p arr']='typeset -a -i arr=(0 (1 2 3) 0)'
['arr=(a b c); function f { typeset -g -F arr[1]=(1 2 3); }; f; typeset -p arr']='typeset -a -F arr=(0.0000000000 (1.0000000000 2.0000000000 3.0000000000) 0.0000000000)'
['arr=(a b c); function f { typeset -g -E arr[1]=(1 2 3); }; f; typeset -p arr']='typeset -a -E arr=(0 (1 2 3) 0)'
['arr=(a b c); function f { typeset -g -X24 arr[1]=(1 2 3); }; f; typeset -p arr']='typeset -a -X 24 arr=(0x0.000000000000000000000000p+0 (0x1.000000000000000000000000p+0 0x1.000000000000000000000000p+1 0x1.800000000000000000000000p+1) 0x0.000000000000000000000000p+0)'
)
for cmd in "${!exp[@]}"
do
got=$(set +x; eval "$cmd" 2>&1)
[[ $got == "${exp[$cmd]}" ]] || err_exit "typeset -g in $(printf %q "$cmd") failed to activate global" \
"scope from ksh function (expected $(printf %q "${exp[$cmd]}"), got $(printf %q "$got"))"
done
unset exp
fi
# ======
exit $((Errors<125?Errors:125))