mode characters and doesn't contain any shell break characters that
would need to be quoted when defining a function. Fixes issue
reported by Great Big Dot <greatbigdot@gmail.com>
+
+ 1/28
+ ----
+variables.c
+ - dispose_temporary_env: make sure to save temporary_env to a temp
+ pointer and set temporary_env to NULL before trying to dispose it,
+ so no flush function ever tries to add a temporary variable back
+ into the table (e.g., bind_variable())
+
+ 1/29
+ ----
+builtins/evalstring.c
+ - can_optimize_connection,optimize_fork: add the last command in lists
+ separated by `;' to the list of candidates for fork optimization
+
+ 1/30
+ ----
+examples/loadables/strftime.c
+ - strftime_builtin: try to extend the buffer longer than tbsize*3,
+ which is a minimum of 24 characters, in case some of the formats
+ (e.g., %c) expand to something longer than that. Fixes bug
+ reported by Stan Marsh <gazelle@xmission.com>
+
+ 1/31
+ ----
+lib/readline/undo.c
+ - rl_do_undo: before inserting text while undoing UNDO_DELETE, or
+ performing a deletion while undoing UNDO_INSERT, make sure that
+ rl_point is valid by calling _rl_fix_point. Fuzzing bug and fix
+ from Eduardo Bustamante <dualbus@gmail.com>
+
+lib/readline/search.c
+ - _rl_nsearch_abort: validate new values for rl_point and rl_mark by
+ calling _rl_fix_point(). Fuzzing bug and fix from
+ Eduardo Bustamante <dualbus@gmail.com>
+
+subst.c
+ - string_extract_double_quoted: if we parse a syntactically-incorrect
+ $( expression while extracting a double-quoted string, si will
+ appear to go `backward'. Just skip over the rest of the string and
+ continue. Fuzzing bug from Eduardo Bustamante <dualbus@gmail.com>
+
+lib/readline/text.c
+ - rl_change_case: if towupper or towlower returns a valid wide char
+ that can't be converted back to a valid multibyte character, use
+ the original character and go on. Fuzzing bug from
+ Eduardo Bustamante <dualbus@gmail.com>
+
+lib/glob/glob.c
+ - wdequote_pathname: if there are no multibyte characters in pathname,
+ just call udequote_pathname and don't bother converting it to wide
+ characters
+ - glob_pattern_p: if there are no multibyte characters in the pattern,
+ just call internal_glob_pattern_p right away
+
+lib/glob/glob_loop.c
+ - INTERNAL_GLOB_PATTERN_P: return 2 if we see only backslash-quoted
+ characters without any other unquoted glob pattern characters, so
+ interested callers can shortcut and just dequote the pathname
+
+pathexp.c
+ - unquoted_glob_pattern_p: return 2 if we see only backslash-quoted
+ characters without any other unquoted glob pattern characters,
+ consistent with the glob library
+ - unquoted_glob_pattern_p: don't count a backslash quoting a slash as
+ a backslash that will trigger a call to shell_glob_filename, since
+ backslashes at the end of patterns (pathname components) will always
+ fail to match. XXX - this is provisional
tests/glob2.sub f
tests/glob3.sub f
tests/glob4.sub f
+tests/glob5.sub f
tests/glob.right f
tests/globstar.tests f
tests/globstar.right f
COMMAND *command;
{
return (*bash_input.location.string == '\0' &&
- (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR) &&
+ (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
command->value.Connection->second->type == cm_simple);
}
COMMAND *command;
{
if (command->type == cm_connection &&
- (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR) &&
+ (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
(command->value.Connection->second->flags & CMD_TRY_OPTIMIZING) &&
should_suppress_fork (command->value.Connection->second))
{
/* Now try to figure out how big the buffer should really be. strftime(3)
will return the number of bytes placed in the buffer unless it's greater
than MAXSIZE, in which case it returns 0. */
- for (n = 1; n < 4; n++)
+ for (n = 1; n <= 8; n++)
{
tbuf = xrealloc (tbuf, tbsize * n);
tsize = strftime (tbuf, tbsize * n, format, t);
break;
}
- printf ("%s\n", tbuf);
+ if (tsize)
+ printf ("%s\n", tbuf);
free (tbuf);
return (EXECUTION_SUCCESS);
wchar_t *wpattern;
int r;
- if (MB_CUR_MAX == 1)
+ if (MB_CUR_MAX == 1 || mbsmbchar (pattern) == 0)
return (internal_glob_pattern_p ((unsigned char *)pattern));
/* Convert strings to wide chars, and call the multibyte version. */
return r;
#else
- return (internal_glob_pattern_p (pattern));
+ return (internal_glob_pattern_p ((unsigned char *)pattern));
#endif
}
int i, j;
wchar_t *orig_wpathname;
+ if (mbsmbchar (pathname) == 0)
+ {
+ udequote_pathname (pathname);
+ return;
+ }
+
len = strlen (pathname);
/* Convert the strings into wide characters. */
n = xdupmbstowcs (&wpathname, NULL, pathname);
char *directory_name, *filename, *dname, *fn;
unsigned int directory_len;
int free_dirname; /* flag */
- int dflags;
+ int dflags, hasglob;
result = (char **) malloc (sizeof (char *));
result_size = 1;
free_dirname = 1;
}
+ hasglob = 0;
/* If directory_name contains globbing characters, then we
- have to expand the previous levels. Just recurse. */
- if (directory_len > 0 && glob_pattern_p (directory_name))
+ have to expand the previous levels. Just recurse.
+ If glob_pattern_p returns != [0,1] we have a pattern that has backslash
+ quotes but no unquoted glob pattern characters. We dequote it below. */
+ if (directory_len > 0 && (hasglob = glob_pattern_p (directory_name)) == 1)
{
char **directories, *d, *p;
register unsigned int i;
free (directory_name);
return (NULL);
}
+ if (directory_len > 0 && hasglob == 2) /* need to dequote */
+ {
+ dequote_pathname (directory_name);
+ directory_len = strlen (directory_name);
+ }
/* Handle GX_MARKDIRS here. */
result[0] = (char *) malloc (directory_len + 1);
if (result[0] == NULL)
{
register const GCHAR *p;
register GCHAR c;
- int bopen;
+ int bopen, bsquote;
p = pattern;
- bopen = 0;
+ bopen = bsquote = 0;
while ((c = *p++) != L('\0'))
switch (c)
case L('\\'):
/* Don't let the pattern end in a backslash (GMATCH returns no match
- if the pattern ends in a backslash anyway), but otherwise return 1,
- since the matching engine uses backslash as an escape character
- and it can be removed. */
- return (*p != L('\0'));
+ if the pattern ends in a backslash anyway), but otherwise note that
+ we have seen this, since the matching engine uses backslash as an
+ escape character and it can be removed. We return 2 later if we
+ have seen only backslash-escaped characters, so interested callers
+ know they can shortcut and just dequote the pathname. */
+ if (*p != L('\0'))
+ {
+ p++;
+ bsquote = 1;
+ }
+ else if (*p == L('\0'))
+ return 0;
+ continue;
}
- return 0;
+ return bsquote ? 2 : 0;
}
#undef INTERNAL_GLOB_PATTERN_P
if (MB_CUR_MAX == 1)
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
- if (mbsmbchar (string) == 0 && mbsmbchar (pattern) == 0 && posix_cclass_only (pattern) )
+ if (mbsmbchar (string) == 0 && mbsmbchar (pattern) == 0 && posix_cclass_only (pattern))
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
n = xdupmbstowcs (&wpattern, NULL, pattern);
rl_clear_message ();
rl_point = cxt->save_point;
rl_mark = cxt->save_mark;
+ _rl_fix_point (1);
rl_restore_prompt ();
RL_UNSETSTATE (RL_STATE_NSEARCH);
if (nwc != wc) /* just skip unchanged characters */
{
char *s, *e;
- mlen = wcrtomb (mb, nwc, &mps);
+ mbstate_t ts;
+
+ memset (&ts, 0, sizeof (mbstate_t));
+ mlen = wcrtomb (mb, nwc, &ts);
+ if (mlen < 0)
+ {
+ nwc = wc;
+ memset (&ts, 0, sizeof (mbstate_t));
+ mlen = wcrtomb (mb, nwc, &ts);
+ if (mlen < 0) /* should not happen */
+ strncpy (mb, rl_line_buffer + start, mlen = m);
+ }
if (mlen > 0)
mb[mlen] = '\0';
/* what to do if m != mlen? adjust below */
/* Undoing deletes means inserting some text. */
case UNDO_DELETE:
rl_point = start;
+ _rl_fix_point (1);
rl_insert_text (rl_undo_list->text);
xfree (rl_undo_list->text);
break;
case UNDO_INSERT:
rl_delete_text (start, end);
rl_point = start;
+ _rl_fix_point (1);
break;
/* Undoing an END means undoing everything 'til we get to a BEGIN. */
{
register int c;
char *send;
- int open;
+ int open, bsquote;
DECLARE_MBSTATE;
- open = 0;
+ open = bsquote = 0;
send = string + strlen (string);
while (c = *string++)
can be removed by the matching engine, so we have to run it through
globbing. */
case '\\':
- return (*string != 0);
+ if (*string != '\0' && *string != '/')
+ {
+ bsquote = 1;
+ string++;
+ continue;
+ }
+ else if (*string == 0)
+ return (0);
case CTLESC:
if (*string++ == '\0')
ADVANCE_CHAR_P (string, send - string);
#endif
}
- return (0);
+
+ return (bsquote ? 2 : 0);
}
/* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
temp[j] = ret[t];
temp[j] = string[si];
- if (string[si])
+ if (si < i + 2) /* we went back? */
+ i += 2;
+ else if (string[si])
{
j++;
i = si + 1;
-BUILD_DIR=/usr/local/build/chet/bash/bash-current
+BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
aa
<define\/\
/>
+/tmp/a/b/c /tmp/a/b/c /tmp/a/b/c
+/tmp/a/b/c /tmp/a/b/c /tmp/a/b/c
+/tmp/a/b/c
+/tmp/a/b/c
+/tmp\/a/b/c
+/tm[p]\/a/b/c
argv[1] = <a>
argv[2] = <abc>
argv[3] = <abd>
argv[3] = <abd>
argv[4] = <abe>
tmp/l1 tmp/l2 tmp/*4 tmp/l3
-./glob.tests: line 47: no match: tmp/*4
+./glob.tests: line 48: no match: tmp/*4
argv[1] = <bdir/>
argv[1] = <*>
argv[1] = <a*>
${THIS_SH} ./glob2.sub
${THIS_SH} ./glob3.sub
${THIS_SH} ./glob4.sub
+${THIS_SH} ./glob5.sub
MYDIR=$PWD # save where we are
--- /dev/null
+mkdir -m700 /tmp/a /tmp/a/b
+touch /tmp/a/b/c
+
+echo /tmp/a/b/* "/tmp/a/"b/* "/tmp/a/b"/*
+
+chmod -r /tmp/a
+echo /tmp/a/b/* "/tmp/a/"b/* "/tmp/a/b"/*
+echo "/tmp/a/b"/*
+
+bs=\\
+echo /tmp${bs}/a/b/*
+echo /tmp${bs}/a/b/c
+echo /tm[p]${bs}/a/b/c
+
+chmod +r /tmp/a
+rm -rf /tmp/a
else if (nv == &nameref_maxloop_value)
{
internal_warning (_("%s: circular name reference"), v->name);
-#if 1
- /* TAG:bash-5.1 */
return (bind_global_variable (v->name, value, flags));
-#else
- v = 0; /* backwards compat */
-#endif
}
else
v = nv;
else if (nv == &nameref_maxloop_value)
{
internal_warning (_("%s: circular name reference"), v->name);
-#if 1
- /* TAG:bash-5.1 */
return (bind_global_variable (v->name, value, flags));
-#else
- v = 0; /* backwards compat */
-#endif
}
else
v = nv;
var = (SHELL_VAR *)data;
+#if 0 /* TAG:bash-5.1 */
+ /* Just like do_assignment_internal(). This makes assignments preceding
+ special builtins act like standalone assignment statements when in
+ posix mode. */
+ v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP);
+
+ /* If this modifies an existing local variable, v->context will be non-zero.
+ If it comes back with v->context == 0, we bound at the global context.
+ Set binding_table appropriately. It doesn't matter whether it's correct
+ if the variable is local, only that it's not global_variables->table */
+ binding_table = v->context ? shell_variables->table : global_variables->table;
+#else
binding_table = global_variables->table;
if (binding_table == 0)
binding_table = global_variables->table = hash_create (VARIABLES_HASH_BUCKETS);
v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP);
+#endif
/* global variables are no longer temporary and don't need propagating. */
- var->attributes &= ~(att_tempvar|att_propagate);
+ if (binding_table == global_variables->table)
+ var->attributes &= ~(att_tempvar|att_propagate);
+
if (v)
- v->attributes |= var->attributes;
+ {
+ v->attributes |= var->attributes;
+ v->attributes &= ~att_tempvar; /* not a temp var now */
+#if 1 /* TAG:bash-5.1 code doesn't need this, disable for bash-5.1 */
+ v->context = (binding_table == global_variables->table) ? 0 : shell_variables->scope;
+#endif
+ }
if (find_special_var (var->name) >= 0)
tempvar_list[tvlist_ind++] = savestring (var->name);
sh_free_func_t *pushf;
{
int i;
+ HASH_TABLE *disposer;
tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1);
tempvar_list[tvlist_ind = 0] = 0;
-
- hash_flush (temporary_env, pushf);
- hash_dispose (temporary_env);
+
+ disposer = temporary_env;
temporary_env = (HASH_TABLE *)NULL;
+ hash_flush (disposer, pushf);
+ hash_dispose (disposer);
+
tempvar_list[tvlist_ind] = 0;
array_needs_making = 1;