changes to make builtins that perform assignments work better with arbitrary associative array keys

This commit is contained in:
Chet Ramey
2022-01-04 10:54:28 -05:00
parent 186129835e
commit 1d17c604fc
12 changed files with 649 additions and 480 deletions
+48
View File
@@ -2815,3 +2815,51 @@ subst.c
unset A[$rkey]
work because the unset builtin sees the W_ARRAYREF flag on its
argument
12/29
-----
builtins/common.h
- SET_VFLAGS: take a set of word flags, and set flags for use with
valid_array_reference (vflags) and assign_array_element/bind_int_variable
(bindflags) based on those flags and the setting of assoc_expand_once
(moved from read.def and generalized)
arrayfunc.c
- array_variable_name: now exclusively takes AV_xxx flags; understands
how to translate AV_NOEXPAND to the right flag for skipsubscript;
understands AV_ONEWORD and AV_NOEXPAND
- array_variable_part: just passes the FLAGS arg to array_variable_name
- assign_array_element: translates ASS_ flags to AV_ flags for
array_variable_name
- array_value_internal: now just passes flags straight through to
array_variable_part (which sends them to array_variable_name)
builtins/common.[ch]
- builtin_bind_var_to_int: now takes a new FLAGS third argument; passes
it to bind_var_to_int
builtins/printf.def
- printf_builtin: use SET_VFLAGS to set flags for builtin_bind_variable
(bindflags); makes things like
declare -A A; key=']' ; printf -v A[$key] "foo"
work without a subscript error as long as assoc_expand_once is defined
builtins/read.def
- read_builtin: use new common version of SET_VFLAGS instead of
private version; changed to use new calling sequence; makes things like
declare -A A; key=']' ; read A[$key] <<<"foo"
work without a subscript error as long as assoc_expand_once is defined
builtins/wait.def
- wait_builtin: use SET_VFLAGS for variable name with -p option
- wait_builtin: call builtin_bind_var_to_int with new bindflags third
argument
expr.c
- expr_streval: just pass TFLAG (AV_xxx flags) straight through to
array_variable_part
variables.c
- bind_int_variable: translate the assignment flags (ASS_xxx) to
VA_xxx flags for valid_array_reference calls (ASS_ONEWORD); translate
assignment flags to AV_xxx flags for array_variable_part
+18 -5
View File
@@ -347,10 +347,15 @@ assign_array_element (name, value, flags, estatep)
array_eltstate_t *estatep;
{
char *sub, *vname;
int sublen, isassoc;
int sublen, isassoc, avflags;
SHELL_VAR *entry;
vname = array_variable_name (name, (flags & ASS_NOEXPAND) != 0, &sub, &sublen);
avflags = 0;
if (flags & ASS_NOEXPAND)
avflags |= AV_NOEXPAND;
if (flags & ASS_ONEWORD)
avflags |= AV_ONEWORD;
vname = array_variable_name (name, avflags, &sub, &sublen);
if (vname == 0)
return ((SHELL_VAR *)NULL);
@@ -1374,7 +1379,7 @@ array_variable_name (s, flags, subp, lenp)
int *lenp;
{
char *t, *ret;
int ind, ni;
int ind, ni, ssflags;
t = mbschr (s, '[');
if (t == 0)
@@ -1386,7 +1391,15 @@ array_variable_name (s, flags, subp, lenp)
return ((char *)NULL);
}
ind = t - s;
ni = skipsubscript (s, ind, flags&1); /* XXX - was 0 not flags */
if ((flags & (AV_NOEXPAND|AV_ONEWORD)) == (AV_NOEXPAND|AV_ONEWORD))
ni = strlen (s) - 1;
else
{
ssflags = 0;
if (flags & AV_NOEXPAND)
ssflags |= 1;
ni = skipsubscript (s, ind, ssflags);
}
if (ni <= ind + 1 || s[ni] != ']')
{
err_badarraysub (s);
@@ -1464,7 +1477,7 @@ array_value_internal (s, quoted, flags, estatep)
WORD_LIST *l;
SHELL_VAR *var;
var = array_variable_part (s, (flags&AV_NOEXPAND) ? 1 : 0, &t, &len); /* XXX */
var = array_variable_part (s, flags, &t, &len); /* XXX */
/* Expand the index, even if the variable doesn't exist, in case side
effects are needed, like ${w[i++]} where w is unset. */
+2 -1
View File
@@ -55,7 +55,8 @@ extern int assoc_expand_once;
/* The analog for indexed array subscripts */
extern int array_expand_once;
/* Flags for array_value_internal and callers array_value/get_array_value */
/* Flags for array_value_internal and callers array_value/get_array_value; also
used by array_variable_name and array_variable_part. */
#define AV_ALLOWALL 0x001 /* treat a[@] like $@ and a[*] like $* */
#define AV_QUOTED 0x002
#define AV_USEIND 0x004
+4 -6
View File
@@ -990,10 +990,7 @@ builtin_bind_variable (name, value, flags)
#if defined (ARRAY_VARS)
/* Callers are responsible for calling this with array references that have
already undergone valid_array_reference checks.
Affected builtins: read, printf
To make this *really* work, needs additional downstream support, starting
with assign_array_element and array_variable_name. */
already undergone valid_array_reference checks (read, printf). */
vflags = assoc_expand_once ? (VA_NOEXPAND|VA_ONEWORD) : 0;
bindflags = flags | (assoc_expand_once ? ASS_NOEXPAND : 0) | ASS_ALLOWALLSUB;
if (flags & ASS_NOEXPAND)
@@ -1016,13 +1013,14 @@ builtin_bind_variable (name, value, flags)
}
SHELL_VAR *
builtin_bind_var_to_int (name, val)
builtin_bind_var_to_int (name, val, flags)
char *name;
intmax_t val;
int flags;
{
SHELL_VAR *v;
v = bind_var_to_int (name, val, ASS_ALLOWALLSUB);
v = bind_var_to_int (name, val, flags|ASS_ALLOWALLSUB);
return v;
}
+16 -1
View File
@@ -232,7 +232,7 @@ extern sh_builtin_func_t *this_shell_builtin;
extern sh_builtin_func_t *last_shell_builtin;
extern SHELL_VAR *builtin_bind_variable PARAMS((char *, char *, int));
extern SHELL_VAR *builtin_bind_var_to_int PARAMS((char *, intmax_t));
extern SHELL_VAR *builtin_bind_var_to_int PARAMS((char *, intmax_t, int));
extern int builtin_unbind_variable PARAMS((const char *));
extern int builtin_arrayref_flags PARAMS((WORD_DESC *, int));
@@ -263,4 +263,19 @@ extern int source_uses_path;
/* variables from wait.def */
extern int wait_intr_flag;
/* common code to set flags for valid_array_reference and builtin_bind_variable */
#if defined (ARRAY_VARS)
#define SET_VFLAGS(wordflags, vflags, bindflags) \
do { \
vflags = assoc_expand_once ? VA_NOEXPAND : 0; \
bindflags = assoc_expand_once ? ASS_NOEXPAND : 0; \
if (assoc_expand_once && (wordflags & W_ARRAYREF)) \
vflags |= VA_ONEWORD|VA_NOEXPAND; \
if (vflags & VA_NOEXPAND) \
bindflags |= ASS_NOEXPAND; \
if (vflags & VA_ONEWORD) \
bindflags |= ASS_ONEWORD; \
} while (0)
#endif
#endif /* !__COMMON_H */
+4 -4
View File
@@ -151,7 +151,7 @@ extern int errno;
if (vflag) \
{ \
SHELL_VAR *v; \
v = builtin_bind_variable (vname, vbuf, 0); \
v = builtin_bind_variable (vname, vbuf, bindflags); \
stupidly_hack_special_variables (vname); \
if (v == 0 || readonly_p (v) || noassign_p (v)) \
return (EXECUTION_FAILURE); \
@@ -232,6 +232,7 @@ static int conversion_error;
/* printf -v var support */
static int vflag = 0;
static int bindflags = 0;
static char *vbuf, *vname;
static size_t vbsize;
static int vblen;
@@ -266,10 +267,9 @@ printf_builtin (list)
{
case 'v':
vname = list_optarg;
bindflags = 0;
#if defined (ARRAY_VARS)
arrayflags = assoc_expand_once ? VA_NOEXPAND : 0;
if (assoc_expand_once && (list_optflags & W_ARRAYREF))
arrayflags |= VA_ONEWORD|VA_NOEXPAND;
SET_VFLAGS (list_optflags, arrayflags, bindflags);
retval = legal_identifier (vname) || valid_array_reference (vname, arrayflags);
#else
retval = legal_identifier (vname);
+3 -17
View File
@@ -190,20 +190,6 @@ read_builtin_timeout (fd)
: shtimer_select (read_timeout));
}
#if defined (ARRAY_VARS)
#define SET_VFLAGS(wordflags) \
do { \
vflags = assoc_expand_once ? VA_NOEXPAND : 0; \
bindflags = assoc_expand_once ? ASS_NOEXPAND : 0; \
if (assoc_expand_once && (wordflags & W_ARRAYREF)) \
vflags |= VA_ONEWORD|VA_NOEXPAND; \
if (vflags & VA_NOEXPAND) \
bindflags |= ASS_NOEXPAND; \
if (vflags & VA_ONEWORD) \
bindflags |= ASS_ONEWORD; \
} while (0)
#endif
/* Read the value of the shell variables whose names follow.
The reading is done from the current input stream, whatever
that may be. Successive words of the input line are assigned
@@ -378,7 +364,7 @@ read_builtin (list)
variable names is a valid identifier, and bail early if so. */
#if defined (ARRAY_VARS)
if (list)
SET_VFLAGS (list->word->flags);
SET_VFLAGS (list->word->flags, vflags, bindflags);
if (list && legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word, vflags) == 0)
#else
bindflags = 0;
@@ -969,7 +955,7 @@ assign_vars:
{
varname = list->word->word;
#if defined (ARRAY_VARS)
SET_VFLAGS (list->word->flags);
SET_VFLAGS (list->word->flags, vflags, bindflags);
if (legal_identifier (varname) == 0 && valid_array_reference (varname, vflags) == 0)
#else
if (legal_identifier (varname) == 0)
@@ -1018,7 +1004,7 @@ assign_vars:
/* Now assign the rest of the line to the last variable argument. */
#if defined (ARRAY_VARS)
SET_VFLAGS (list->word->flags);
SET_VFLAGS (list->word->flags, vflags, bindflags);
if (legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word, vflags) == 0)
#else
if (legal_identifier (list->word->word) == 0)
+7 -11
View File
@@ -111,7 +111,7 @@ int
wait_builtin (list)
WORD_LIST *list;
{
int status, code, opt, nflag;
int status, code, opt, nflag, vflags, bindflags;
volatile int wflags;
char *vname;
SHELL_VAR *pidvar;
@@ -119,7 +119,7 @@ wait_builtin (list)
USE_VAR(list);
nflag = wflags = 0;
nflag = wflags = vflags = 0;
vname = NULL;
pidvar = (SHELL_VAR *)NULL;
reset_internal_getopt ();
@@ -136,6 +136,7 @@ wait_builtin (list)
break;
case 'p':
vname = list_optarg;
vflags = list_optflags;
break;
#endif
CASE_HELPOPT;
@@ -152,15 +153,10 @@ wait_builtin (list)
#if defined (ARRAY_VARS)
int arrayflags;
#if 0
arrayflags = assoc_expand_once ? VA_NOEXPAND : 0;
if (assoc_expand_once && (list_optflags & W_ARRAYREF))
arrayflags |= VA_ONEWORD|VA_NOEXPAND;
#else
arrayflags = 0; /* not yet without builtin_bind_var_to_int support */
#endif
SET_VFLAGS (vflags, arrayflags, bindflags);
if (legal_identifier (vname) == 0 && valid_array_reference (vname, arrayflags) == 0)
#else
bindflags = 0;
if (legal_identifier (vname) == 0)
#endif
{
@@ -225,7 +221,7 @@ wait_builtin (list)
status = wait_for_any_job (wflags, &pstat);
if (vname && status >= 0)
builtin_bind_var_to_int (vname, pstat.pid);
builtin_bind_var_to_int (vname, pstat.pid, bindflags);
if (status < 0)
status = 127;
@@ -241,7 +237,7 @@ wait_builtin (list)
{
wait_for_background_pids (&pstat);
if (vname)
builtin_bind_var_to_int (vname, pstat.pid);
builtin_bind_var_to_int (vname, pstat.pid, bindflags);
WAIT_RETURN (EXECUTION_SUCCESS);
}
+2 -2
View File
@@ -1161,12 +1161,12 @@ expr_streval (tok, e, lvalue)
initial_depth = expr_depth;
#if defined (ARRAY_VARS)
tflag = assoc_expand_once && already_expanded; /* for a start */
tflag = (assoc_expand_once && already_expanded) ? AV_NOEXPAND : 0; /* for a start */
#endif
/* [[[[[ */
#if defined (ARRAY_VARS)
aflag = (tflag) ? AV_NOEXPAND : 0;
aflag = tflag; /* use a different variable for now */
v = (e == ']') ? array_variable_part (tok, tflag, (char **)0, (int *)0) : find_variable (tok);
#else
v = find_variable (tok);
BIN
View File
Binary file not shown.
+535 -431
View File
File diff suppressed because it is too large Load Diff
+10 -2
View File
@@ -3401,16 +3401,24 @@ bind_int_variable (lhs, rhs, flags)
int flags;
{
register SHELL_VAR *v;
int isint, isarr, implicitarray, vflags;
int isint, isarr, implicitarray, vflags, avflags;
isint = isarr = implicitarray = 0;
#if defined (ARRAY_VARS)
/* Don't rely on VA_NOEXPAND being 1, set it explicitly */
vflags = (flags & ASS_NOEXPAND) ? VA_NOEXPAND : 0;
if (flags & ASS_ONEWORD)
vflags |= VA_ONEWORD;
if (valid_array_reference (lhs, vflags))
{
isarr = 1;
v = array_variable_part (lhs, (flags & ASS_NOEXPAND) != 0, (char **)0, (int *)0);
avflags = 0;
/* Common code to translate between assignment and reference flags. */
if (flags & ASS_NOEXPAND)
avflags |= AV_NOEXPAND;
if (flags & ASS_ONEWORD)
avflags |= AV_ONEWORD;
v = array_variable_part (lhs, avflags, (char **)0, (int *)0);
}
else if (legal_identifier (lhs) == 0)
{