mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-27 15:43:18 +02:00
round seconds in command timing information if precision is >= 0; fix for readline word boundaries when quoted command substitutions appear; remove nameref attribute when converting nameref variable into an array; change how help strings are written to builtins.c; change read builtin to update unwind-protect if the input string is reallocated; fix crash when an expansion on the rhs of an assignment statement unsets the variable on the lhs
This commit is contained in:
+71
-6
@@ -13,7 +13,8 @@ Makefile.in
|
||||
-----
|
||||
builtins/wait.def
|
||||
- wait_builtin: don't assign the variable given with -p if there are no
|
||||
jobs to wait for. Report and fix from OÄuz <oguzismailuysal@gmail.com>
|
||||
jobs to wait for.
|
||||
Report and fix from OÄuz <oguzismailuysal@gmail.com>
|
||||
|
||||
arrayfunc.c
|
||||
- kvpair_assignment_p: return non-zero if argument L appears to be a
|
||||
@@ -28,8 +29,8 @@ arrayfunc.h
|
||||
subst.c
|
||||
- expand_oneword: detect whether VALUE appears to be a key-value
|
||||
pair compound assignment and call the appropriate function to expand
|
||||
each word in the resulting list. Fixes inconsistency reported by
|
||||
oguzismailuysal@gmail.com
|
||||
each word in the resulting list.
|
||||
Fixes inconsistency reported by oguzismailuysal@gmail.com
|
||||
|
||||
12/12
|
||||
-----
|
||||
@@ -152,8 +153,8 @@ variables.c
|
||||
array variable that was the value of a nameref (used in the original
|
||||
assignment), don't call make_variable_value on the value, since that
|
||||
messes up +=. Just call assign_array_element and let that take care
|
||||
of calling make_variable_value appropriately. Fixes bug reported by
|
||||
Oguz <oguzismailuysal@gmail.com>
|
||||
of calling make_variable_value appropriately.
|
||||
Fixes bug reported by Oguz <oguzismailuysal@gmail.com>
|
||||
|
||||
1/14
|
||||
----
|
||||
@@ -206,7 +207,8 @@ Makefile.in
|
||||
subst.c
|
||||
- param_expand: if a nameref expands to array[@] or array[*], make sure
|
||||
to call chk_atstar so the right variables are set to split the
|
||||
result. Report from Oguz <oguzismailuysal@gmail.com>
|
||||
result.
|
||||
Report from Oguz <oguzismailuysal@gmail.com>
|
||||
|
||||
1/22
|
||||
----
|
||||
@@ -12024,3 +12026,66 @@ lib/glob/sm_loop.c
|
||||
|
||||
oslib.c
|
||||
- bcopy: update function declaration to add `const'
|
||||
|
||||
execute_cmd.c
|
||||
- mkfmt: fix rounding of fractional part of the printed value to
|
||||
increment the seconds value if necessary (e.g., 0.9848 -> 1.0 if
|
||||
precision == 1)
|
||||
- mkfmt: compute the seconds and seconds fraction before writing
|
||||
anything into the buffer in case we increment the seconds
|
||||
Report and patch from Grisha Levit <grishalevit@gmail.com>
|
||||
|
||||
subst.h
|
||||
- SD_QUOTEDSTR: tell skip_to_delim that we're skipping over a quoted
|
||||
string; *delims is the close quote
|
||||
|
||||
subst.c
|
||||
- skip_to_delim: understand SD_QUOTEDSTR and call skip_single_quoted
|
||||
or skip_double_quoted immediately as appropriate
|
||||
|
||||
bashline.c
|
||||
- bash_forward_shellword: use SD_QUOTEDSTR in the call to skip_to_delim
|
||||
Fixes bug reported by Grisha Levit <grishalevit@gmail.com>
|
||||
|
||||
10/20
|
||||
-----
|
||||
execute_cmd.c
|
||||
- mkfmt: round when the precision is 0 like with other precision values
|
||||
Report and patch from Grisha Levit <grishalevit@gmail.com>
|
||||
|
||||
variables.c
|
||||
- make_local_array_variable,make_local_assoc_variable: if we're
|
||||
converting an unset nameref into an array, warn about it and turn
|
||||
off the nameref attribute
|
||||
Report from Grisha Levit <grishalevit@gmail.com>
|
||||
|
||||
builtins/mkbuiltins.c
|
||||
- write_documentation: change to use modern C-style strings, where
|
||||
adjacent strings are effectively concatenated
|
||||
- write_documentation: don't add indent to otherwise blank lines
|
||||
Original patch from Martin D Kealey <martin@kurahaupo.gen.nz>
|
||||
|
||||
10/21
|
||||
-----
|
||||
builtins/read.def
|
||||
- read_builtin: since referring to a pointer after realloc may have
|
||||
freed it is, in theory, undefined behavior, redo the unwind-protect
|
||||
every time we increase the size of input_string. This updates the
|
||||
CHERI-only change of 10/6
|
||||
From https://savannah.gnu.org/bugs/?67586
|
||||
|
||||
10/22
|
||||
-----
|
||||
arrayfunc.c
|
||||
- make_array_variable_value,assign_array_element_internal: set
|
||||
att_assigning while evaluating the value to be assigned so the rest
|
||||
of the shell knows not to unset the variable
|
||||
|
||||
variables.c
|
||||
- bind_variable_internal,bind_variable_value: set att_assigning
|
||||
around calls to make_variable_value to avoid unsetting the variable
|
||||
- makunbound: if we are assigning to the variable being unset, just
|
||||
empty it out and set it to invisible, assuming the variable will be
|
||||
marked as visible after assignment
|
||||
Report from Oguz <oguzismailuysal@gmail.com> back on 8/8/2025
|
||||
|
||||
|
||||
+13
-3
@@ -203,7 +203,13 @@ make_array_variable_value (SHELL_VAR *entry, arrayind_t ind, const char *key, co
|
||||
dispose_variable (dentry);
|
||||
}
|
||||
else
|
||||
newval = make_variable_value (entry, value, flags);
|
||||
{
|
||||
if (entry)
|
||||
VSETATTR (entry, att_assigning);
|
||||
newval = make_variable_value (entry, value, flags);
|
||||
if (entry)
|
||||
VUNSETATTR (entry, att_assigning);
|
||||
}
|
||||
|
||||
return newval;
|
||||
}
|
||||
@@ -227,7 +233,7 @@ bind_assoc_var_internal (SHELL_VAR *entry, HASH_TABLE *hash, char *key, const ch
|
||||
(*entry->assign_func) (entry, newval, 0, key);
|
||||
FREE (key);
|
||||
}
|
||||
else
|
||||
else if (assoc_p (entry))
|
||||
assoc_insert (hash, key, newval);
|
||||
|
||||
FREE (newval);
|
||||
@@ -251,7 +257,7 @@ bind_array_var_internal (SHELL_VAR *entry, arrayind_t ind, char *key, const char
|
||||
(*entry->assign_func) (entry, newval, ind, key);
|
||||
else if (assoc_p (entry))
|
||||
assoc_insert (assoc_cell (entry), key, newval);
|
||||
else
|
||||
else if (array_p (entry))
|
||||
array_insert (array_cell (entry), ind, newval);
|
||||
FREE (newval);
|
||||
|
||||
@@ -432,7 +438,11 @@ assign_array_element_internal (SHELL_VAR *entry, const char *name, char *vname,
|
||||
int avflags;
|
||||
|
||||
avflags = convert_assign_flags_to_arrayval_flags (flags);
|
||||
if (entry)
|
||||
VSETATTR (entry, att_assigning);
|
||||
ind = array_expand_index (entry, sub, sublen, avflags);
|
||||
if (entry)
|
||||
VUNSETATTR (entry, att_assigning);
|
||||
/* negative subscripts to indexed arrays count back from end */
|
||||
if (entry && ind < 0)
|
||||
ind = (array_p (entry) ? array_max_index (array_cell (entry)) : 0) + 1 + ind;
|
||||
|
||||
+4
-4
@@ -1114,10 +1114,10 @@ bash_forward_shellword (int count, int key)
|
||||
ADVANCE_CHAR (rl_line_buffer, slen, p);
|
||||
break;
|
||||
case '\'':
|
||||
p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP);
|
||||
p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP|SD_QUOTEDSTR|SD_COMPLETE);
|
||||
break;
|
||||
case '"':
|
||||
p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP);
|
||||
p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP|SD_QUOTEDSTR|SD_COMPLETE);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1145,10 +1145,10 @@ bash_forward_shellword (int count, int key)
|
||||
ADVANCE_CHAR (rl_line_buffer, slen, p);
|
||||
break;
|
||||
case '\'':
|
||||
p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP);
|
||||
p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP|SD_QUOTEDSTR|SD_COMPLETE);
|
||||
break;
|
||||
case '"':
|
||||
p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP);
|
||||
p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP|SD_QUOTEDSTR|SD_COMPLETE);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+47
-60
@@ -44,6 +44,7 @@
|
||||
#include "filecntl.h"
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -1391,68 +1392,53 @@ write_documentation (FILE *stream, char **documentation, int indentation, int fl
|
||||
{
|
||||
int i, j;
|
||||
char *line;
|
||||
int string_array, texinfo, base_indent, filename_p;
|
||||
int string_array, texinfo, filename_p;
|
||||
int full_indent, base_indent;
|
||||
|
||||
if (stream == 0)
|
||||
return;
|
||||
|
||||
string_array = flags & STRING_ARRAY;
|
||||
filename_p = flags & HELPFILE;
|
||||
texinfo = flags & TEXINFO;
|
||||
|
||||
base_indent = (string_array && single_longdoc_strings && filename_p == 0) ? BASE_INDENT : 0;
|
||||
full_indent = indentation + base_indent;
|
||||
|
||||
if (string_array)
|
||||
{
|
||||
fprintf (stream, " {\n#if defined (HELP_BUILTIN)\n"); /* } */
|
||||
if (single_longdoc_strings)
|
||||
{
|
||||
if (filename_p == 0)
|
||||
{
|
||||
if (documentation && documentation[0] && documentation[0][0])
|
||||
fprintf (stream, "N_(\"");
|
||||
else
|
||||
fprintf (stream, "N_(\" "); /* the empty string translates specially. */
|
||||
}
|
||||
else
|
||||
fprintf (stream, "\"");
|
||||
}
|
||||
if (filename_p == 0 && single_longdoc_strings)
|
||||
fprintf (stream, "N_(");
|
||||
}
|
||||
|
||||
base_indent = (string_array && single_longdoc_strings && filename_p == 0) ? BASE_INDENT : 0;
|
||||
|
||||
for (i = 0, texinfo = (flags & TEXINFO); documentation && (line = documentation[i]); i++)
|
||||
for (i = 0; documentation && (line = documentation[i]); i++)
|
||||
{
|
||||
bool first_line = i == 0;
|
||||
bool last_line = documentation[i+1] == 0;
|
||||
|
||||
/* Allow #ifdef's to be written out verbatim, but don't put them into
|
||||
separate help files. */
|
||||
if (*line == '#')
|
||||
{
|
||||
if (string_array && filename_p == 0 && single_longdoc_strings == 0)
|
||||
if (string_array)
|
||||
fprintf (stream, "%s\n", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* prefix with N_( for gettext */
|
||||
if (string_array && single_longdoc_strings == 0)
|
||||
{
|
||||
if (filename_p == 0)
|
||||
{
|
||||
if (line[0])
|
||||
fprintf (stream, " N_(\"");
|
||||
else
|
||||
fprintf (stream, " N_(\" "); /* the empty string translates specially. */
|
||||
}
|
||||
else
|
||||
fprintf (stream, " \"");
|
||||
}
|
||||
|
||||
if (indentation)
|
||||
for (j = 0; j < indentation; j++)
|
||||
fprintf (stream, " ");
|
||||
|
||||
/* Don't indent the first line, because of how the help builtin works. */
|
||||
if (i == 0)
|
||||
indentation += base_indent;
|
||||
|
||||
if (string_array)
|
||||
{
|
||||
if (filename_p == 0 && single_longdoc_strings == 0)
|
||||
fprintf (stream, "N_(");
|
||||
else if (first_line == 0)
|
||||
fputc ('\t', stream);
|
||||
fputc ('"', stream);
|
||||
if (filename_p == 0 && *line == 0 && last_line && first_line && indentation == 0)
|
||||
line = " "; /* the empty string translates specially. */
|
||||
if (indentation && *line)
|
||||
fprintf (stream, "%*.0s", indentation, "");
|
||||
|
||||
for (j = 0; line[j]; j++)
|
||||
{
|
||||
if (line[j] == '\\' || line[j] == '"')
|
||||
@@ -1460,20 +1446,18 @@ write_documentation (FILE *stream, char **documentation, int indentation, int fl
|
||||
fputc (line[j], stream);
|
||||
}
|
||||
|
||||
/* closing right paren for gettext */
|
||||
if (single_longdoc_strings == 0)
|
||||
{
|
||||
if (filename_p == 0)
|
||||
fprintf (stream, "\"),\n");
|
||||
else
|
||||
fprintf (stream, "\",\n");
|
||||
}
|
||||
else if (documentation[i+1])
|
||||
/* don't add extra newline after last line */
|
||||
fprintf (stream, "\\n\\\n");
|
||||
if (last_line == 0)
|
||||
fprintf (stream, "\\n");
|
||||
fputc ('"', stream);
|
||||
if (filename_p == 0 && single_longdoc_strings == 0)
|
||||
fprintf (stream, "),");
|
||||
if (last_line == 0)
|
||||
fprintf (stream, "\n");
|
||||
}
|
||||
else if (texinfo)
|
||||
{
|
||||
{
|
||||
if (indentation && *line)
|
||||
fprintf (stream, "%*.0s", indentation, "");
|
||||
for (j = 0; line[j]; j++)
|
||||
{
|
||||
switch (line[j])
|
||||
@@ -1489,20 +1473,23 @@ write_documentation (FILE *stream, char **documentation, int indentation, int fl
|
||||
fputc ('\n', stream);
|
||||
}
|
||||
else
|
||||
fprintf (stream, "%s\n", line);
|
||||
fprintf (stream, "%*.0s%s\n", indentation, "", line);
|
||||
|
||||
/* Don't indent the first line, because of how the help builtin works. */
|
||||
indentation = full_indent;
|
||||
}
|
||||
|
||||
/* closing right paren for gettext */
|
||||
if (string_array && single_longdoc_strings)
|
||||
{
|
||||
if (filename_p == 0)
|
||||
fprintf (stream, "\"),\n");
|
||||
else
|
||||
fprintf (stream, "\",\n");
|
||||
}
|
||||
|
||||
if (string_array)
|
||||
fprintf (stream, "#endif /* HELP_BUILTIN */\n (char *)NULL\n};\n");
|
||||
{
|
||||
if (single_longdoc_strings)
|
||||
{
|
||||
if (filename_p == 0)
|
||||
fputc (')', stream);
|
||||
fputc (',', stream);
|
||||
}
|
||||
fprintf (stream, "\n#endif /* HELP_BUILTIN */\n\t(char *)NULL\n};\n");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
+3
-2
@@ -816,8 +816,9 @@ read_builtin (WORD_LIST *list)
|
||||
char *x;
|
||||
x = (char *)xrealloc (input_string, size += 128);
|
||||
|
||||
/* Only need to change unwind-protect if input_string changes */
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
#if 0
|
||||
/* This is, in theory, undefined behavior, since input_string may
|
||||
have been freed. */
|
||||
if (x != input_string)
|
||||
#endif
|
||||
{
|
||||
|
||||
+33
-27
@@ -1273,18 +1273,48 @@ extern int timeval_to_cpu (struct timeval *, struct timeval *, struct timeval *)
|
||||
#define BASH_TIMEFORMAT "\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS"
|
||||
|
||||
static const int precs[] = { 0, 100000, 10000, 1000, 100, 10, 1 };
|
||||
static const int maxvals[] = { 1, 10, 100, 1000, 10000, 100000, 10000000 };
|
||||
static const int maxvals[] = { 1, 10, 100, 1000, 10000, 100000, 1000000 };
|
||||
|
||||
/* Expand one `%'-prefixed escape sequence from a time format string. */
|
||||
/* SEC_FRACTION is in usecs. We normalize and round that based on the
|
||||
precision. */
|
||||
int
|
||||
static int
|
||||
mkfmt (char *buf, int prec, int lng, time_t sec, long sec_fraction)
|
||||
{
|
||||
time_t min;
|
||||
char abuf[INT_STRLEN_BOUND(time_t) + 1];
|
||||
int ind, aind;
|
||||
|
||||
/* We want to add a decimal point and PREC places after it if PREC is
|
||||
nonzero. PREC is not greater than 6. SEC_FRACTION is between 0
|
||||
and 999999 (microseconds). */
|
||||
if (prec < 6)
|
||||
{
|
||||
/* We round here because we changed timeval_to_secs to return
|
||||
microseconds and normalized clock_t_to_secs's fractional return
|
||||
value to microseconds, deferring the work to be done to now.
|
||||
|
||||
sec_fraction is in microseconds. Take the value, cut off what we
|
||||
don't want, round up if necessary, then convert back to
|
||||
microseconds. */
|
||||
int frac, rest, maxval;
|
||||
|
||||
maxval = maxvals[6 - prec];
|
||||
frac = sec_fraction / maxval;
|
||||
rest = sec_fraction % maxval;
|
||||
|
||||
if (rest >= maxval/2)
|
||||
frac++;
|
||||
|
||||
if (frac == maxvals[prec])
|
||||
{
|
||||
sec++;
|
||||
sec_fraction = 0;
|
||||
}
|
||||
else
|
||||
sec_fraction = frac * (1000000 / maxvals[prec]);
|
||||
}
|
||||
|
||||
ind = 0;
|
||||
abuf[sizeof(abuf) - 1] = '\0';
|
||||
|
||||
@@ -1312,32 +1342,8 @@ mkfmt (char *buf, int prec, int lng, time_t sec, long sec_fraction)
|
||||
while (abuf[aind])
|
||||
buf[ind++] = abuf[aind++];
|
||||
|
||||
/* We want to add a decimal point and PREC places after it if PREC is
|
||||
nonzero. PREC is not greater than 6. SEC_FRACTION is between 0
|
||||
and 999999 (microseconds). */
|
||||
if (prec != 0)
|
||||
if (prec > 0)
|
||||
{
|
||||
/* We round here because we changed timeval_to_secs to return
|
||||
microseconds and normalized clock_t_to_secs's fractional return
|
||||
value to microseconds, deferring the work to be done to now.
|
||||
|
||||
sec_fraction is in microseconds. Take the value, cut off what we
|
||||
don't want, round up if necessary, then convert back to
|
||||
microseconds. */
|
||||
if (prec != 6)
|
||||
{
|
||||
int frac, rest, maxval;
|
||||
|
||||
maxval = maxvals[6 - prec];
|
||||
frac = sec_fraction / maxval;
|
||||
rest = sec_fraction % maxval;
|
||||
|
||||
if (rest >= maxval/2)
|
||||
frac++;
|
||||
|
||||
sec_fraction = frac * (1000000 / maxvals[prec]);
|
||||
}
|
||||
|
||||
buf[ind++] = locale_decpoint ();
|
||||
for (aind = 1; aind <= prec; aind++)
|
||||
{
|
||||
|
||||
@@ -2217,6 +2217,18 @@ skip_to_delim (const char *string, int start, const char *delims, int flags)
|
||||
arithexp = (flags & SD_ARITHEXP);
|
||||
skipcol = 0;
|
||||
|
||||
/* If the caller tells us we're skipping a quoted string after the opening
|
||||
quote, and the delimiter is a single- or double-quote, skip all the logic
|
||||
here and just call the same functions as word expansion. */
|
||||
if ((flags & SD_QUOTEDSTR) && (*delims == '\'' || *delims == '"') && delims[1] == '\0')
|
||||
{
|
||||
if (*delims == '\'')
|
||||
i = skip_single_quoted (string, slen, start, 0);
|
||||
else
|
||||
i = skip_double_quoted (string, slen, start, completeflag);
|
||||
CQ_RETURN (i);
|
||||
}
|
||||
|
||||
i = start;
|
||||
pass_next = backq = dquote = 0;
|
||||
while (c = string[i])
|
||||
|
||||
@@ -336,6 +336,7 @@ extern char *cond_expand_word (WORD_DESC *, int);
|
||||
#define SD_HISTEXP 0x200 /* skip_to_delim during history expansion */
|
||||
#define SD_ARITHEXP 0x400 /* skip_to_delim during arithmetic expansion */
|
||||
#define SD_NOERROR 0x800 /* don't print error messages */
|
||||
#define SD_QUOTEDSTR 0x1000 /* skipping a part of a single- or double-quoted string */
|
||||
|
||||
extern int skip_to_delim (const char *, int, const char *, int);
|
||||
|
||||
|
||||
+14
-2
@@ -1,10 +1,22 @@
|
||||
: ${BUILD_DIR:=/usr/local/build/chet/bash/bash-current}
|
||||
: ${BUILD_DIR:=$PWD}
|
||||
THIS_SH=$BUILD_DIR/bash
|
||||
PATH=$PATH:$BUILD_DIR
|
||||
|
||||
export THIS_SH PATH
|
||||
export THIS_SH PATH BUILD_DIR
|
||||
|
||||
: ${TMPDIR:=/tmp}
|
||||
export TMPDIR
|
||||
|
||||
export BASH_TSTOUT=/tmp/xx
|
||||
rm -f ${BASH_TSTOUT}
|
||||
|
||||
if [ -t 1 ]; then
|
||||
# can't rely on having $'...' or printf understanding \e
|
||||
# bright red background, white foreground text
|
||||
export CSTART=$(printf '\033[01;101;37m') CEND=$(printf '\033[0m')
|
||||
else
|
||||
export CSTART= CEND=
|
||||
fi
|
||||
export TAB=' '
|
||||
|
||||
${THIS_SH} "$@"
|
||||
|
||||
@@ -406,10 +406,10 @@ help: help [-dms] [pattern ...]
|
||||
shift - Shift positional parameters.
|
||||
shift: shift [n]
|
||||
Shift positional parameters.
|
||||
|
||||
|
||||
Rename the positional parameters $N+1,$N+2 ... to $1,$2 ... If N is
|
||||
not given, it is assumed to be 1.
|
||||
|
||||
|
||||
Exit Status:
|
||||
Returns success unless N is negative or greater than $#.
|
||||
builtin: builtin [shell-builtin [arg ...]]
|
||||
@@ -424,9 +424,9 @@ readarray: readarray [-d delim] [-n count] [-O origin] [-s count] [-t] [-u fd] [
|
||||
readonly: readonly [-aAf] [name[=value] ...] or readonly -p
|
||||
:: :
|
||||
Null command.
|
||||
|
||||
|
||||
No effect; the command does nothing.
|
||||
|
||||
|
||||
Exit Status:
|
||||
Always succeeds.
|
||||
NAME
|
||||
@@ -437,9 +437,9 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
Null command.
|
||||
|
||||
|
||||
No effect; the command does nothing.
|
||||
|
||||
|
||||
Exit Status:
|
||||
Always succeeds.
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
for f ; do
|
||||
echo $f
|
||||
sed 's|warning:|${CSTART}warning${CEND}:|' < $f > zzz && mv zzz $f
|
||||
done
|
||||
+68
-13
@@ -2824,6 +2824,13 @@ make_local_array_variable (const char *name, int flags)
|
||||
if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var)))
|
||||
return var;
|
||||
|
||||
/* array variables cannot be namerefs */
|
||||
if (var && nameref_p (var) && invisible_p (var))
|
||||
{
|
||||
internal_warning (_("%s: removing nameref attribute"), name);
|
||||
VUNSETATTR (var, att_nameref);
|
||||
}
|
||||
|
||||
/* Validate any value we inherited from a variable instance at a previous
|
||||
scope and discard anything that's invalid. */
|
||||
if (localvar_inherit && assoc_p (var))
|
||||
@@ -2880,6 +2887,13 @@ make_local_assoc_variable (const char *name, int flags)
|
||||
if (var == 0 || assoc_p (var) || (array_ok && array_p (var)))
|
||||
return var;
|
||||
|
||||
/* assoc variables cannot be namerefs */
|
||||
if (var && nameref_p (var) && invisible_p (var))
|
||||
{
|
||||
internal_warning (_("%s: removing nameref attribute"), name);
|
||||
VUNSETATTR (var, att_nameref);
|
||||
}
|
||||
|
||||
/* Validate any value we inherited from a variable instance at a previous
|
||||
scope and discard anything that's invalid. */
|
||||
if (localvar_inherit && array_p (var))
|
||||
@@ -3123,13 +3137,19 @@ bind_variable_internal (const char *name, const char *value, HASH_TABLE *table,
|
||||
#endif
|
||||
{
|
||||
entry = make_new_variable (newval, table);
|
||||
var_setvalue (entry, make_variable_value (entry, value, aflags));
|
||||
VSETATTR (entry, att_assigning);
|
||||
newval = make_variable_value (entry, value, aflags);
|
||||
VUNSETATTR (entry, att_assigning);
|
||||
var_setvalue (entry, newval);
|
||||
}
|
||||
}
|
||||
else if (entry == 0)
|
||||
{
|
||||
entry = make_new_variable (name, table);
|
||||
var_setvalue (entry, make_variable_value (entry, value, aflags)); /* XXX */
|
||||
VSETATTR (entry, att_assigning);
|
||||
newval = make_variable_value (entry, value, aflags); /* XXX */
|
||||
VUNSETATTR (entry, att_assigning);
|
||||
var_setvalue (entry, newval);
|
||||
}
|
||||
else if (entry->assign_func) /* array vars have assign functions now */
|
||||
{
|
||||
@@ -3141,7 +3161,9 @@ bind_variable_internal (const char *name, const char *value, HASH_TABLE *table,
|
||||
}
|
||||
|
||||
INVALIDATE_EXPORTSTR (entry);
|
||||
VSETATTR (entry, att_assigning);
|
||||
newval = (aflags & ASS_APPEND) ? make_variable_value (entry, value, aflags) : (char *)value;
|
||||
VUNSETATTR (entry, att_assigning);
|
||||
if (assoc_p (entry))
|
||||
entry = (*(entry->assign_func)) (entry, newval, -1, savestring ("0"));
|
||||
else if (array_p (entry))
|
||||
@@ -3162,9 +3184,6 @@ assign_value:
|
||||
return (entry);
|
||||
}
|
||||
|
||||
/* Variables which are bound are visible. */
|
||||
VUNSETATTR (entry, att_invisible);
|
||||
|
||||
/* If we can optimize the assignment, do so and return. Right now, we
|
||||
optimize appends to string variables. */
|
||||
if (can_optimize_assignment (entry, value, aflags))
|
||||
@@ -3178,15 +3197,23 @@ assign_value:
|
||||
if (exported_p (entry))
|
||||
array_needs_making = 1;
|
||||
|
||||
/* Variables which are bound are visible. */
|
||||
VUNSETATTR (entry, att_invisible);
|
||||
|
||||
return (entry);
|
||||
}
|
||||
|
||||
VSETATTR (entry, att_assigning);
|
||||
#if defined (ARRAY_VARS)
|
||||
if (assoc_p (entry) || array_p (entry))
|
||||
newval = make_array_variable_value (entry, 0, "0", value, aflags);
|
||||
else
|
||||
#endif
|
||||
newval = make_variable_value (entry, value, aflags); /* XXX */
|
||||
VUNSETATTR (entry, att_assigning);
|
||||
|
||||
/* Variables which are bound are visible. */
|
||||
VUNSETATTR (entry, att_invisible);
|
||||
|
||||
/* Invalidate any cached export string */
|
||||
INVALIDATE_EXPORTSTR (entry);
|
||||
@@ -3326,23 +3353,24 @@ SHELL_VAR *
|
||||
bind_variable_value (SHELL_VAR *var, char *value, int aflags)
|
||||
{
|
||||
char *t;
|
||||
int invis;
|
||||
|
||||
invis = invisible_p (var);
|
||||
VUNSETATTR (var, att_invisible);
|
||||
|
||||
if (var->assign_func)
|
||||
{
|
||||
/* If we're appending, we need the old value, so use
|
||||
make_variable_value */
|
||||
VSETATTR (var, att_assigning);
|
||||
t = (aflags & ASS_APPEND) ? make_variable_value (var, value, aflags) : value;
|
||||
VUNSETATTR (var, att_assigning);
|
||||
VUNSETATTR (var, att_invisible);
|
||||
(*(var->assign_func)) (var, t, -1, 0);
|
||||
if (t != value && t)
|
||||
free (t);
|
||||
}
|
||||
else
|
||||
{
|
||||
VSETATTR (var, att_assigning);
|
||||
t = make_variable_value (var, value, aflags);
|
||||
VUNSETATTR (var, att_assigning);
|
||||
if ((aflags & (ASS_NAMEREF|ASS_FORCE)) == ASS_NAMEREF && check_selfref (name_cell (var), t, 0))
|
||||
{
|
||||
if (variable_context)
|
||||
@@ -3351,20 +3379,17 @@ bind_variable_value (SHELL_VAR *var, char *value, int aflags)
|
||||
{
|
||||
internal_error (_("%s: nameref variable self references not allowed"), name_cell (var));
|
||||
free (t);
|
||||
if (invis)
|
||||
VSETATTR (var, att_invisible); /* XXX */
|
||||
return ((SHELL_VAR *)NULL);
|
||||
}
|
||||
}
|
||||
if ((aflags & ASS_NAMEREF) && (valid_nameref_value (t, 0) == 0))
|
||||
{
|
||||
free (t);
|
||||
if (invis)
|
||||
VSETATTR (var, att_invisible); /* XXX */
|
||||
return ((SHELL_VAR *)NULL);
|
||||
}
|
||||
FREE (value_cell (var));
|
||||
var_setvalue (var, t);
|
||||
VUNSETATTR (var, att_invisible);
|
||||
}
|
||||
|
||||
INVALIDATE_EXPORTSTR (var);
|
||||
@@ -4010,6 +4035,36 @@ makunbound (const char *name, VAR_CONTEXT *vc)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* If we are currently assigning this variable, but the evaluation of the
|
||||
value causes it to be unset, we need to make sure pointers to the
|
||||
variable struct remain valid, and insert a cleared-out version of the
|
||||
variable back into the correct hash table. */
|
||||
if (old_var && assigning_p (old_var))
|
||||
{
|
||||
dispose_variable_value (old_var);
|
||||
var_setvalue (old_var, (char *)NULL);
|
||||
|
||||
old_var->attributes = 0;
|
||||
VSETATTR (old_var, att_assigning);
|
||||
VSETATTR (old_var, att_invisible);
|
||||
|
||||
INVALIDATE_EXPORTSTR (old_var);
|
||||
|
||||
old_var->dynamic_value = NULL;
|
||||
old_var->assign_func = NULL;
|
||||
|
||||
/* leave the context unchanged if we're going to be assigning it */
|
||||
/* old_var->context = 0; */
|
||||
|
||||
new_elt = hash_insert (savestring (old_var->name), v->table, 0);
|
||||
new_elt->data = (PTR_T)old_var;
|
||||
stupidly_hack_special_variables (old_var->name);
|
||||
|
||||
free (elt->key);
|
||||
free (elt);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Have to save a copy of name here, because it might refer to
|
||||
old_var->name. If so, stupidly_hack_special_variables will
|
||||
reference freed memory. */
|
||||
|
||||
Reference in New Issue
Block a user