*/
array_dispose_element(new);
free(element_value(ae));
- ae->value = savestring(v);
+ ae->value = v ? savestring(v) : (char *)NULL;
return(0);
} else if (element_index(ae) > i) {
ADD_BEFORE(ae, new);
var = find_variable (t);
free (t);
- return var;
+ return (var == 0 || invisible_p (var)) ? (SHELL_VAR *)0 : var;
}
/* Return a string containing the elements in the array and subscript
#endif
/* Helper functions for Readline. */
+static int bash_directory_expansion __P((char **));
static int bash_directory_completion_hook __P((char **));
static int filename_completion_ignore __P((char **));
static int bash_push_line __P((void));
/* See if we have anything to do. */
at = strchr (rl_completer_word_break_characters, '@');
if ((at == 0 && on_or_off == 0) || (at != 0 && on_or_off != 0))
- return;
+ return old_value;
/* We have something to do. Do it. */
nval = (char *)xmalloc (strlen (rl_completer_word_break_characters) + 1 + on_or_off);
filename. */
if (*hint_text == '~')
{
- int l, tl, vl;
+ int l, tl, vl, dl;
+ char *rd;
vl = strlen (val);
tl = strlen (hint_text);
+#if 0
l = vl - hint_len; /* # of chars added */
+#else
+ rd = savestring (filename_hint);
+ bash_directory_expansion (&rd);
+ dl = strlen (rd);
+ l = vl - dl; /* # of chars added */
+ free (rd);
+#endif
temp = (char *)xmalloc (l + 2 + tl);
strcpy (temp, hint_text);
strcpy (temp + tl, val + vl - l);
return 0;
}
+/* Simulate the expansions that will be performed by
+ rl_filename_completion_function. This must be called with the address of
+ a pointer to malloc'd memory. */
+static int
+bash_directory_expansion (dirname)
+ char **dirname;
+{
+ char *d;
+
+ d = savestring (*dirname);
+
+ if (rl_directory_rewrite_hook)
+ (*rl_directory_rewrite_hook) (&d);
+
+ if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d))
+ {
+ free (*dirname);
+ *dirname = d;
+ }
+}
+
/* Handle symbolic link references and other directory name
expansions while hacking completion. */
static int
static char **matches = (char **)NULL;
static int ind;
int glen;
- char *ret;
+ char *ret, *ttext;
if (state == 0)
{
FREE (globorig);
FREE (globtext);
+ ttext = bash_tilde_expand (text, 0);
+
if (rl_explicit_arg)
{
- globorig = savestring (text);
- glen = strlen (text);
+ globorig = savestring (ttext);
+ glen = strlen (ttext);
globtext = (char *)xmalloc (glen + 2);
- strcpy (globtext, text);
+ strcpy (globtext, ttext);
globtext[glen] = '*';
globtext[glen+1] = '\0';
}
else
- globtext = globorig = savestring (text);
+ globtext = globorig = savestring (ttext);
+
+ if (ttext != text)
+ free (ttext);
matches = shell_glob_filename (globtext);
if (GLOB_FAILED (matches))
if (lhs_t == ST_CHAR)
{
- lhs_v = lhs[0];
- rhs_v = rhs[0];
+ lhs_v = (unsigned char)lhs[0];
+ rhs_v = (unsigned char)rhs[0];
}
else
{
{
pass_next = 1;
i++;
+ if (quoted == 0)
+ level++;
continue;
}
#endif
$BUILTIN trap
$FUNCTION trap_builtin
-$SHORT_DOC trap [-lp] [[arg] signal_spec ...]
+$SHORT_DOC trap [-lp] [arg signal_spec ...]
The command ARG is to be read and executed when the shell receives
signal(s) SIGNAL_SPEC. If ARG is absent (and a single SIGNAL_SPEC
is supplied) or `-', each specified signal is reset to its original
trap_builtin (list)
WORD_LIST *list;
{
- int list_signal_names, display, result, opt;
+ int list_signal_names, display, result, opt, first_signal;
list_signal_names = display = 0;
result = EXECUTION_SUCCESS;
else
{
char *first_arg;
- int operation, sig;
+ int operation, sig, first_signal;
operation = SET;
first_arg = list->word->word;
+ first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt);
+
+ /* Backwards compatibility */
+ if (first_signal)
+ operation = REVERT;
/* When in posix mode, the historical behavior of looking for a
missing first argument is disabled. To revert to the original
signal handling disposition, use `-' as the first argument. */
- if (posixly_correct == 0 && first_arg && *first_arg &&
+ else if (posixly_correct == 0 && first_arg && *first_arg &&
(*first_arg != '-' || first_arg[1]) &&
signal_object_p (first_arg, opt) && list->next == 0)
operation = REVERT;
@item
The @code{trap} builtin doesn't check the first argument for a possible
signal specification and revert the signal handling to the original
-disposition if it is. If users want to reset the handler for a given
+disposition if it is, unless that argument consists solely of digits and
+is a valid signal number. If users want to reset the handler for a given
signal to the original disposition, they should use @samp{-} as the
first argument.
c = string[indx = 0];
#if defined (ARRAY_VARS)
- if ((legal_variable_starter (c) == 0) && (flags && c != '[')) /* ] */
+ if ((legal_variable_starter (c) == 0) && (flags == 0 || c != '[')) /* ] */
#else
if (legal_variable_starter (c) == 0)
#endif
extern size_t xmbsrtowcs __P((wchar_t *, const char **, size_t, mbstate_t *));
extern size_t xdupmbstowcs __P((wchar_t **, char ***, const char *));
+extern size_t mbstrlen __P((const char *));
+
extern char *xstrchr __P((const char *, int));
#ifndef MB_INVALIDCH
#define MB_NULLWCH(x) ((x) == 0)
#endif
+#define MBSLEN(s) (((s) && (s)[0]) ? ((s)[1] ? mbstrlen (s) : 1) : 0)
+#define MB_STRLEN(s) ((MB_CUR_MAX > 1) ? MBSLEN (s) : STRLEN (s))
+
#else /* !HANDLE_MULTIBYTE */
#undef MB_LEN_MAX
#define MB_NULLWCH(x) (0)
#endif
+#define MB_STRLEN(s) (STRLEN(s))
+
#endif /* !HANDLE_MULTIBYTE */
/* Declare and initialize a multibyte state. Call must be terminated
if (pipefail_opt)
{
fail = 0;
- for (p = jobs[job]->pipe; p->next != jobs[job]->pipe; p = p->next)
- if (p->status != EXECUTION_SUCCESS) fail = p->status;
+ p = jobs[job]->pipe;
+ do
+ {
+ if (p->status != EXECUTION_SUCCESS) fail = p->status;
+ p = p->next;
+ }
+ while (p != jobs[job]->pipe);
return fail;
}
int *lp, *lip, *niflp, *vlp;
{
char *r, *ret, *p;
- int l, rl, last, ignoring, ninvis, invfl, ind, pind, physchars;
+ int l, rl, last, ignoring, ninvis, invfl, invflset, ind, pind, physchars;
/* Short-circuit if we can. */
if ((MB_CUR_MAX <= 1 || rl_byte_oriented) && strchr (pmt, RL_PROMPT_START_IGNORE) == 0)
r = ret = (char *)xmalloc (l + 1);
invfl = 0; /* invisible chars in first line of prompt */
+ invflset = 0; /* we only want to set invfl once */
for (rl = ignoring = last = ninvis = physchars = 0, p = pmt; p && *p; p++)
{
while (l--)
*r++ = *p++;
if (!ignoring)
- rl += ind - pind;
+ {
+ rl += ind - pind;
+ physchars += _rl_col_width (pmt, pind, ind);
+ }
else
ninvis += ind - pind;
p--; /* compensate for later increment */
{
*r++ = *p;
if (!ignoring)
- rl++; /* visible length byte counter */
+ {
+ rl++; /* visible length byte counter */
+ physchars++;
+ }
else
ninvis++; /* invisible chars byte counter */
}
- if (rl >= _rl_screenwidth)
- invfl = ninvis;
-
- if (ignoring == 0)
- physchars++;
+ if (invflset == 0 && rl >= _rl_screenwidth)
+ {
+ invfl = ninvis;
+ invflset = 1;
+ }
}
}
local_prompt = expand_prompt (p, &prompt_visible_length,
&prompt_last_invisible,
(int *)NULL,
- (int *)NULL);
+ &prompt_physical_chars);
c = *t; *t = '\0';
/* The portion of the prompt string up to and including the
final newline is now null-terminated. */
local_prompt_prefix = expand_prompt (prompt, &prompt_prefix_length,
(int *)NULL,
&prompt_invis_chars_first_line,
- &prompt_physical_chars);
+ (int *)NULL);
*t = c;
return (prompt_prefix_length);
}
register int in, out, c, linenum, cursor_linenum;
register char *line;
int c_pos, inv_botlin, lb_botlin, lb_linenum;
- int newlines, lpos, temp, modmark;
+ int newlines, lpos, temp, modmark, n0, num;
char *prompt_this_line;
#if defined (HANDLE_MULTIBYTE)
wchar_t wc;
#if defined (HANDLE_MULTIBYTE)
memset (_rl_wrapped_line, 0, vis_lbsize);
+ num = 0;
#endif
/* prompt_invis_chars_first_line is the number of invisible characters in
probably too much work for the benefit gained. How many people have
prompts that exceed two physical lines?
Additional logic fix from Edward Catmur <ed@catmur.co.uk> */
+#if defined (HANDLE_MULTIBYTE)
+ n0 = num;
+ temp = local_prompt ? strlen (local_prompt) : 0;
+ while (num < temp)
+ {
+ if (_rl_col_width (local_prompt, n0, num) > _rl_screenwidth)
+ {
+ num = _rl_find_prev_mbchar (local_prompt, num, MB_FIND_ANY);
+ break;
+ }
+ num++;
+ }
+ temp = num +
+#else
temp = ((newlines + 1) * _rl_screenwidth) +
+#endif /* !HANDLE_MULTIBYTE */
((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line
: ((newlines == 1) ? wrap_offset : 0))
: ((newlines == 0) ? wrap_offset :0));
inv_lbreaks[++newlines] = temp;
+#if defined (HANDLE_MULTIBYTE)
+ lpos -= _rl_col_width (local_prompt, n0, num);
+#else
lpos -= _rl_screenwidth;
+#endif
}
prompt_last_screen_line = newlines;
if (find_non_zero)
{
tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
- while (wcwidth (wc) == 0)
+ while (tmp > 0 && wcwidth (wc) == 0)
{
point += tmp;
tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
- if (tmp == (size_t)(0) || tmp == (size_t)(-1) || tmp == (size_t)(-2))
+ if (MB_NULLWCH (tmp) || MB_INVALIDCH (tmp))
break;
}
}
_rl_saved_line_for_history->line = savestring (rl_line_buffer);
_rl_saved_line_for_history->data = (char *)rl_undo_list;
}
- else if (STREQ (rl_line_buffer, _rl_saved_line_for_history->line) == 0)
- {
- free (_rl_saved_line_for_history->line);
- _rl_saved_line_for_history->line = savestring (rl_line_buffer);
- _rl_saved_line_for_history->data = (char *)rl_undo_list; /* XXX possible memleak */
- }
return 0;
}
switch (key)
{
case '?':
+ _rl_free_saved_history_line ();
rl_noninc_forward_search (count, key);
break;
case '/':
+ _rl_free_saved_history_line ();
rl_noninc_reverse_search (count, key);
break;
{
wchar_t wc;
char mb[MB_LEN_MAX+1];
- int mblen;
+ int mblen, p;
mbstate_t ps;
memset (&ps, 0, sizeof (mbstate_t));
/* Vi is kind of strange here. */
if (wc)
{
+ p = rl_point;
mblen = wcrtomb (mb, wc, &ps);
if (mblen >= 0)
mb[mblen] = '\0';
rl_begin_undo_group ();
- rl_delete (1, 0);
+ rl_vi_delete (1, 0);
+ if (rl_point < p) /* Did we retreat at EOL? */
+ rl_point++; /* XXX - should we advance more than 1 for mbchar? */
rl_insert_text (mb);
rl_end_undo_group ();
rl_vi_check ();
rl_vi_delete (1, c);
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
- while (_rl_insert_char (1, c))
- {
- RL_SETSTATE (RL_STATE_MOREINPUT);
- c = rl_read_key ();
- RL_UNSETSTATE (RL_STATE_MOREINPUT);
- }
+ {
+ if (rl_point < p) /* Did we retreat at EOL? */
+ rl_point++;
+ while (_rl_insert_char (1, c))
+ {
+ RL_SETSTATE (RL_STATE_MOREINPUT);
+ c = rl_read_key ();
+ RL_UNSETSTATE (RL_STATE_MOREINPUT);
+ }
+ }
else
#endif
{
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
looks for to find the patch level (for the sccs version string). */
-#define PATCHLEVEL 0
+#define PATCHLEVEL 16
#endif /* _PATCHLEVEL_H_ */
if (array_p (v) == 0)
v = convert_var_to_array (v);
v = assign_array_var_from_word_list (v, lwords);
+
+ VUNSETATTR (v, att_invisible);
return v;
}
#endif /* ARRAY_VARS */
if (array_p (v) == 0)
v = convert_var_to_array (v);
+ VUNSETATTR (v, att_invisible);
+
a = array_cell (v);
if (a == 0 || array_empty (a))
sl = (STRINGLIST *)NULL;
legal_identifier (name + 1)); /* ${#PS1} */
}
+#if defined (HANDLE_MULTIBYTE)
+size_t
+mbstrlen (s)
+ const char *s;
+{
+ size_t clen, nc;
+ mbstate_t mbs;
+
+ nc = 0;
+ memset (&mbs, 0, sizeof (mbs));
+ while ((clen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0 && (MB_INVALIDCH(clen) == 0))
+ {
+ s += clen;
+ nc++;
+ }
+ return nc;
+}
+#endif
+
+
/* Handle the parameter brace expansion that requires us to return the
length of a parameter. */
static intmax_t
if (legal_number (name + 1, &arg_index)) /* ${#1} */
{
t = get_dollar_var_value (arg_index);
- number = STRLEN (t);
+ number = MB_STRLEN (t);
FREE (t);
}
#if defined (ARRAY_VARS)
- else if ((var = find_variable (name + 1)) && array_p (var))
+ else if ((var = find_variable (name + 1)) && (invisible_p (var) == 0) && array_p (var))
{
t = array_reference (array_cell (var), 0);
- number = STRLEN (t);
+ number = MB_STRLEN (t);
}
#endif
else /* ${#PS1} */
if (list)
dispose_words (list);
- number = STRLEN (t);
+ number = MB_STRLEN (t);
FREE (t);
}
}
{
case VT_VARIABLE:
case VT_ARRAYMEMBER:
- len = strlen (value);
+ len = MB_STRLEN (value);
break;
case VT_POSPARMS:
len = number_of_args () + 1;
#if defined (ARRAY_VARS)
case VT_ARRAYVAR:
a = (ARRAY *)value;
- /* For arrays, the first value deals with array indices. */
- len = array_max_index (a); /* arrays index from 0 to n - 1 */
+ /* For arrays, the first value deals with array indices. Negative
+ offsets count from one past the array's maximum index. */
+ len = array_max_index (a) + (*e1p < 0); /* arrays index from 0 to n - 1 */
break;
#endif
}
if (*e1p < 0) /* negative offsets count from end */
*e1p += len;
- if (*e1p >= len || *e1p < 0)
+ if (*e1p > len || *e1p < 0)
return (-1);
#if defined (ARRAY_VARS)
else
return -1;
}
- else if ((v = find_variable (varname)) && array_p (v))
+ else if ((v = find_variable (varname)) && (invisible_p (v) == 0) && array_p (v))
{
vtype = VT_ARRAYMEMBER;
*varp = v;
three five seven
positive offset - expect five seven
five seven
-negative offset - expect five seven
-five seven
+negative offset to unset element - expect seven
+seven
positive offset 2 - expect seven
seven
negative offset 2 - expect seven
echo positive offset - expect five seven
echo ${av[@]:5:2}
-echo negative offset - expect five seven
+echo negative offset to unset element - expect seven
echo ${av[@]: -2:2}
echo positive offset 2 - expect seven
trap 'print_debug_trap $LINENO' DEBUG
trap 'print_return_trap $LINENO' RETURN
-# Funcname is now an array. Vanilla Bash 2.05 doesn't have FUNCNAME array.
-echo "FUNCNAME" ${FUNCNAME[0]}
+# Funcname is now an array, but you still can't see it outside a function
+echo "FUNCNAME" ${FUNCNAME[0]:-main}
# We should trace into the below.
# Start easy with a simple function.
./errors.tests: line 213: /bin/sh + 0: syntax error: operand expected (error token is "/bin/sh + 0")
./errors.tests: line 216: trap: NOSIG: invalid signal specification
./errors.tests: line 219: trap: -s: invalid option
-trap: usage: trap [-lp] [[arg] signal_spec ...]
+trap: usage: trap [-lp] [arg signal_spec ...]
./errors.tests: line 225: return: can only `return' from a function or sourced script
./errors.tests: line 229: break: 0: loop count out of range
./errors.tests: line 233: continue: 0: loop count out of range
v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign);
# if defined (DEBUGGER)
- v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, (att_invisible|att_noassign));
- v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, (att_invisible|att_noassign));
+ v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, att_noassign);
+ v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign);
# endif /* DEBUGGER */
- v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, (att_invisible|att_noassign));
- v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, (att_invisible|att_noassign));
+ v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign);
+ v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign);
#endif
v = init_funcname_var ();
/* local foo; local foo; is a no-op. */
old_var = find_variable (name);
if (old_var && local_p (old_var) && old_var->context == variable_context)
- return (old_var);
+ {
+ VUNSETATTR (old_var, att_invisible);
+ return (old_var);
+ }
was_tmpvar = old_var && tempvar_p (old_var);
if (was_tmpvar)