mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-07-05 11:20:50 +02:00
commit bash-20110622 snapshot
This commit is contained in:
@@ -11824,3 +11824,83 @@ arrayfunc.c
|
||||
|
||||
This fixes problems with double-expansion and quote removal being
|
||||
performed on the array indices
|
||||
|
||||
6/13
|
||||
----
|
||||
doc/{bash.1,bashref.texi}
|
||||
- Add a little text to make it clear that the locale determines how
|
||||
range expressions in glob patterns are handled.
|
||||
|
||||
|
||||
6/21
|
||||
----
|
||||
builtins/read.def
|
||||
- display a message and return error status if -a is used with an
|
||||
existing associative array. Fixes bug reported by Curtis Doty
|
||||
<curtis@greenkey.net>
|
||||
|
||||
6/24
|
||||
----
|
||||
{jobs,nojobs}.c
|
||||
- non-interactive shells now react to the setting of checkwinsize
|
||||
and set LINES and COLUMNS after a foreground job exits. From a
|
||||
suggestion by Leslie Rhorer <lrhorer@satx.rr.com>
|
||||
|
||||
lib/readline/histfile.c
|
||||
- history_backupfile: new file, creates a backup history file name
|
||||
given a filename (appending `-')
|
||||
- history_do_write: when overwriting the history file, back it up
|
||||
before writing. Restore backup file on a write error. Suggested
|
||||
by chkno@chkno.net
|
||||
|
||||
bashline.c
|
||||
- find_cmd_name: two new arguments, return the start and end of the
|
||||
actual text string used to find the command name, without taking
|
||||
whitespace into account
|
||||
- attempt_shell_completion: small changes to make sure that completion
|
||||
attempted at the beginning of a non-empty line does not find a
|
||||
programmable completion, even if the command name starts at point
|
||||
- attempt_shell_completion: small change to make sure that completion
|
||||
does not find a progcomp when in whitespace before the command
|
||||
name
|
||||
- attempt_shell_completion: small change to make sure that completion
|
||||
does not find a progcomp when point is at the first character of a
|
||||
command name, even when there is leading whitespace (similar to
|
||||
above). Fixes problems noted by Ville Skytta <ville.skytta@iki.fi>
|
||||
|
||||
subst.c
|
||||
- brace_expand_word_list: since the individual strings in the strvec
|
||||
returned by brace_expand are already allocated, don't copy them to
|
||||
newly-allocated memory when building the WORD_LIST, just use them
|
||||
intact
|
||||
|
||||
locale.c
|
||||
- locale_mb_cur_max: cache value of MB_CUR_MAX when we set or change
|
||||
the locale to avoid a function call every time we need to read it
|
||||
|
||||
shell.h
|
||||
- new struct to save shell_input_line and associated variables:
|
||||
shell_input_line_state_t
|
||||
- add members of sh_parser_state_t to save and restore token and the
|
||||
size of the token buffer
|
||||
|
||||
parse.y
|
||||
- {save,restore}_input_line_state: new functions to save and restore
|
||||
shell_input_line and associated variables
|
||||
- {save,restore}_parser_state: add code to save and restore the token
|
||||
and token buffer size
|
||||
- xparse_dolparen: call save_ and restore_input_line_state to avoid
|
||||
problems with overwriting shell_input_line when we recursively
|
||||
call the parser to parse a command substitution. Fixes bug
|
||||
reported by Rui Santos <rsantos@grupopie.com>
|
||||
|
||||
include/shmbutil.h
|
||||
- use locale_mb_cur_max instead of MB_CUR_MAX in ADVANCE_CHAR and
|
||||
similar macros
|
||||
|
||||
lib/glob/smatch.c
|
||||
- rangecmp,rangecmp_wc: change to take an additional argument, which
|
||||
forces the use of strcoll/wscoll when non-zero. If it's 0, a new
|
||||
variable `glob_asciirange' controls whether or not we use strcoll/
|
||||
wscoll. If it's non-zero, we use straight C-locale-like ordering.
|
||||
Suggested by Aharon Robbins <arnold@skeeve.com>
|
||||
|
||||
@@ -11810,3 +11810,90 @@ doc/{bash.1,bashref.texi}
|
||||
option) to make it clear that only interactive shells set a
|
||||
handler for SIGWINCH and update LINES and COLUMNS. Original
|
||||
report submitted by Jonathan Nieder <jrnieder@gmail.com>
|
||||
|
||||
arrayfunc.c
|
||||
- expand_compound_array_assignment: defer expansion of words between
|
||||
parens when performing compound assignmnt to an associative array
|
||||
variable
|
||||
- assign_compound_array_list: perform the same expansions when doing
|
||||
a compound array assignment to an associative array variable as
|
||||
when doing a straight array index assignment. The idea is that
|
||||
foo=( [ind1]=bar [ind2]=quux)
|
||||
is the same as
|
||||
foo[ind1]=bar ; foo[ind2]=quux
|
||||
|
||||
This fixes problems with double-expansion and quote removal being
|
||||
performed on the array indices
|
||||
|
||||
6/13
|
||||
----
|
||||
doc/{bash.1,bashref.texi}
|
||||
- Add a little text to make it clear that the locale determines how
|
||||
range expressions in glob patterns are handled.
|
||||
|
||||
|
||||
6/21
|
||||
----
|
||||
builtins/read.def
|
||||
- display a message and return error status if -a is used with an
|
||||
existing associative array. Fixes bug reported by Curtis Doty
|
||||
<curtis@greenkey.net>
|
||||
|
||||
6/24
|
||||
----
|
||||
{jobs,nojobs}.c
|
||||
- non-interactive shells now react to the setting of checkwinsize
|
||||
and set LINES and COLUMNS after a foreground job exits. From a
|
||||
suggestion by Leslie Rhorer <lrhorer@satx.rr.com>
|
||||
|
||||
lib/readline/histfile.c
|
||||
- history_backupfile: new file, creates a backup history file name
|
||||
given a filename (appending `-')
|
||||
- history_do_write: when overwriting the history file, back it up
|
||||
before writing. Restore backup file on a write error. Suggested
|
||||
by chkno@chkno.net
|
||||
|
||||
bashline.c
|
||||
- find_cmd_name: two new arguments, return the start and end of the
|
||||
actual text string used to find the command name, without taking
|
||||
whitespace into account
|
||||
- attempt_shell_completion: small changes to make sure that completion
|
||||
attempted at the beginning of a non-empty line does not find a
|
||||
programmable completion, even if the command name starts at point
|
||||
- attempt_shell_completion: small change to make sure that completion
|
||||
does not find a progcomp when in whitespace before the command
|
||||
name
|
||||
- attempt_shell_completion: small change to make sure that completion
|
||||
does not find a progcomp when point is at the first character of a
|
||||
command name, even when there is leading whitespace (similar to
|
||||
above). Fixes problems noted by Ville Skytta <ville.skytta@iki.fi>
|
||||
|
||||
subst.c
|
||||
- brace_expand_word_list: since the individual strings in the strvec
|
||||
returned by brace_expand are already allocated, don't copy them to
|
||||
newly-allocated memory when building the WORD_LIST, just use them
|
||||
intact
|
||||
|
||||
locale.c
|
||||
- locale_mb_cur_max: cache value of MB_CUR_MAX when we set or change
|
||||
the locale to avoid a function call every time we need to read it
|
||||
|
||||
shell.h
|
||||
- new struct to save shell_input_line and associated variables:
|
||||
shell_input_line_state_t
|
||||
- add members of sh_parser_state_t to save and restore token and the
|
||||
size of the token buffer
|
||||
|
||||
parse.y
|
||||
- {save,restore}_input_line_state: new functions to save and restore
|
||||
shell_input_line and associated variables
|
||||
- {save,restore}_parser_state: add code to save and restore the token
|
||||
and token buffer size
|
||||
- xparse_dolparen: call save_ and restore_input_line_state to avoid
|
||||
problems with overwriting shell_input_line when we recursively
|
||||
call the parser to parse a command substitution. Fixes bug
|
||||
reported by Rui Santos <rsantos@grupopie.com>
|
||||
|
||||
include/shmbutil.h
|
||||
- use locale_mb_cur_max instead of MB_CUR_MAX in ADVANCE_CHAR and
|
||||
similar macros
|
||||
|
||||
@@ -773,6 +773,7 @@ tests/array8.sub f
|
||||
tests/array9.sub f
|
||||
tests/array10.sub f
|
||||
tests/array11.sub f
|
||||
tests/array12.sub f
|
||||
tests/array-at-star f
|
||||
tests/array2.right f
|
||||
tests/assoc.tests f
|
||||
|
||||
@@ -484,6 +484,8 @@ po/ca.gmo f
|
||||
po/ca.po f
|
||||
po/cs.gmo f
|
||||
po/cs.po f
|
||||
po/da.gmo f
|
||||
po/da.po f
|
||||
po/de.gmo f
|
||||
po/de.po f
|
||||
po/eo.gmo f
|
||||
@@ -518,6 +520,8 @@ po/ru.gmo f
|
||||
po/ru.po f
|
||||
po/sk.gmo f
|
||||
po/sk.po f
|
||||
po/sl.gmo f
|
||||
po/sl.po f
|
||||
po/sv.gmo f
|
||||
po/sv.po f
|
||||
po/tr.gmo f
|
||||
@@ -768,6 +772,7 @@ tests/array7.sub f
|
||||
tests/array8.sub f
|
||||
tests/array9.sub f
|
||||
tests/array10.sub f
|
||||
tests/array11.sub f
|
||||
tests/array-at-star f
|
||||
tests/array2.right f
|
||||
tests/assoc.tests f
|
||||
@@ -828,6 +833,7 @@ tests/dollar-at-star f
|
||||
tests/dollar-at1.sub f
|
||||
tests/dollar-at2.sub f
|
||||
tests/dollar-at3.sub f
|
||||
tests/dollar-at4.sub f
|
||||
tests/dollar-star1.sub f
|
||||
tests/dollar-star2.sub f
|
||||
tests/dollar-star3.sub f
|
||||
@@ -840,6 +846,7 @@ tests/dstack2.tests f
|
||||
tests/dstack2.right f
|
||||
tests/errors.tests f
|
||||
tests/errors.right f
|
||||
tests/errors1.sub f
|
||||
tests/execscript f
|
||||
tests/exec.right f
|
||||
tests/exec1.sub f 755
|
||||
@@ -857,6 +864,8 @@ tests/exp1.sub f
|
||||
tests/exp2.sub f
|
||||
tests/exp3.sub f
|
||||
tests/exp4.sub f
|
||||
tests/exp5.sub f
|
||||
tests/exp6.sub f
|
||||
tests/extglob.tests f
|
||||
tests/extglob.right f
|
||||
tests/extglob1.sub f
|
||||
@@ -888,6 +897,8 @@ tests/globstar1.sub f
|
||||
tests/heredoc.tests f
|
||||
tests/heredoc.right f
|
||||
tests/heredoc1.sub f
|
||||
tests/heredoc2.sub f
|
||||
tests/heredoc3.sub f
|
||||
tests/herestr.tests f
|
||||
tests/herestr.right f
|
||||
tests/histexp.tests f
|
||||
@@ -1103,6 +1114,7 @@ tests/type.right f
|
||||
tests/type1.sub f
|
||||
tests/type2.sub f
|
||||
tests/type3.sub f
|
||||
tests/type4.sub f
|
||||
tests/varenv.right f
|
||||
tests/varenv.sh f
|
||||
tests/varenv1.sub f
|
||||
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
# Makefile for bash-4.2, version 4.4
|
||||
# Makefile for bash-4.2, version 4.5
|
||||
#
|
||||
# Copyright (C) 1996-2010 Free Software Foundation, Inc.
|
||||
|
||||
@@ -1139,6 +1139,7 @@ bashline.o: make_cmd.h subst.h sig.h pathnames.h externs.h
|
||||
bashline.o: builtins.h bashhist.h bashline.h execute_cmd.h findcmd.h pathexp.h
|
||||
bashline.o: $(DEFSRC)/common.h $(GLOB_LIBSRC)/glob.h alias.h
|
||||
bashline.o: pcomplete.h ${BASHINCDIR}/chartypes.h input.h
|
||||
bashline.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h
|
||||
bracecomp.o: config.h bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
bracecomp.o: shell.h syntax.h config.h bashjmp.h ${BASHINCDIR}/posixjmp.h
|
||||
bracecomp.o: command.h ${BASHINCDIR}/stdc.h error.h
|
||||
|
||||
+1529
File diff suppressed because it is too large
Load Diff
+47
-14
@@ -166,7 +166,7 @@ static int bash_event_hook __P((void));
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
static int find_cmd_start __P((int));
|
||||
static int find_cmd_end __P((int));
|
||||
static char *find_cmd_name __P((int));
|
||||
static char *find_cmd_name __P((int, int *, int *));
|
||||
static char *prog_complete_return __P((const char *, int));
|
||||
|
||||
static char **prog_complete_matches;
|
||||
@@ -1249,8 +1249,9 @@ find_cmd_end (end)
|
||||
}
|
||||
|
||||
static char *
|
||||
find_cmd_name (start)
|
||||
find_cmd_name (start, sp, ep)
|
||||
int start;
|
||||
int *sp, *ep;
|
||||
{
|
||||
char *name;
|
||||
register int s, e;
|
||||
@@ -1263,6 +1264,11 @@ find_cmd_name (start)
|
||||
|
||||
name = substring (rl_line_buffer, s, e);
|
||||
|
||||
if (sp)
|
||||
*sp = s;
|
||||
if (ep)
|
||||
*ep = e;
|
||||
|
||||
return (name);
|
||||
}
|
||||
|
||||
@@ -1365,7 +1371,7 @@ attempt_shell_completion (text, start, end)
|
||||
prog_completion_enabled && (progcomp_size () > 0) &&
|
||||
current_prompt_string == ps1_prompt)
|
||||
{
|
||||
int s, e, foundcs;
|
||||
int s, e, s1, e1, foundcs;
|
||||
char *n;
|
||||
|
||||
/* XXX - don't free the members */
|
||||
@@ -1375,9 +1381,15 @@ attempt_shell_completion (text, start, end)
|
||||
|
||||
s = find_cmd_start (start);
|
||||
e = find_cmd_end (end);
|
||||
n = find_cmd_name (s);
|
||||
if (e == 0 && e == s && text[0] == '\0')
|
||||
n = find_cmd_name (s, &s1, &e1);
|
||||
if (start == 0 && end == 0 && e != 0 && text[0] == '\0') /* beginning of non-empty line */
|
||||
foundcs = 0;
|
||||
else if (start == end && start == s1 && e != 0 && e1 > end) /* beginning of command name, leading whitespace */
|
||||
foundcs = 0;
|
||||
else if (e == 0 && e == s && text[0] == '\0') /* beginning of empty line */
|
||||
prog_complete_matches = programmable_completions ("_EmptycmD_", text, s, e, &foundcs);
|
||||
else if (start == end && text[0] == '\0' && s1 > start && whitespace (rl_line_buffer[start]))
|
||||
foundcs = 0; /* whitespace before command name */
|
||||
else if (e > s && assignment (n, 0) == 0)
|
||||
prog_complete_matches = programmable_completions (n, text, s, e, &foundcs);
|
||||
else
|
||||
@@ -1533,7 +1545,7 @@ command_word_completion_function (hint_text, state)
|
||||
#if defined (ALIAS)
|
||||
static alias_t **alias_list = (alias_t **)NULL;
|
||||
#endif /* ALIAS */
|
||||
char *temp;
|
||||
char *temp, *cval;
|
||||
|
||||
/* We have to map over the possibilities for command words. If we have
|
||||
no state, then make one just for that purpose. */
|
||||
@@ -1859,19 +1871,38 @@ globword:
|
||||
freetemp = match = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* If we have found a match, and it is an executable file or a
|
||||
directory name, return it. */
|
||||
if (match && executable_or_directory (val))
|
||||
#else
|
||||
/* If we have found a match, and it is an executable file, return it.
|
||||
We don't return directory names when searching $PATH, since the
|
||||
bash execution code won't find executables in directories which
|
||||
appear in directories in $PATH when they're specified using
|
||||
relative pathnames. */
|
||||
if (match && (searching_path ? executable_file (val) : executable_or_directory (val)))
|
||||
#endif
|
||||
relative pathnames. */
|
||||
#if 0
|
||||
/* If we're not searching $PATH and we have a relative pathname, we
|
||||
need to re-canonicalize it before testing whether or not it's an
|
||||
executable or a directory so the shell treats .. relative to $PWD
|
||||
according to the physical/logical option. The shell already
|
||||
canonicalizes the directory name in order to tell readline where
|
||||
to look, so not doing it here will be inconsistent. */
|
||||
/* XXX -- currently not used -- will introduce more inconsistency,
|
||||
since shell does not canonicalize ../foo before passing it to
|
||||
shell_execve(). */
|
||||
if (match && searching_path == 0 && *val == '.')
|
||||
{
|
||||
char *t, *t1;
|
||||
|
||||
t = get_working_directory ("command-word-completion");
|
||||
t1 = make_absolute (val, t);
|
||||
free (t);
|
||||
cval = sh_canonpath (t1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
cval = val;
|
||||
|
||||
if (match && (searching_path ? executable_file (val) : executable_or_directory (cval)))
|
||||
{
|
||||
if (cval != val)
|
||||
free (cval);
|
||||
free (val);
|
||||
val = ""; /* So it won't be NULL. */
|
||||
return (temp);
|
||||
@@ -1880,6 +1911,8 @@ globword:
|
||||
{
|
||||
if (freetemp)
|
||||
free (temp);
|
||||
if (cval != val)
|
||||
free (cval);
|
||||
free (val);
|
||||
goto inner;
|
||||
}
|
||||
|
||||
+54
-15
@@ -166,7 +166,7 @@ static int bash_event_hook __P((void));
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
static int find_cmd_start __P((int));
|
||||
static int find_cmd_end __P((int));
|
||||
static char *find_cmd_name __P((int));
|
||||
static char *find_cmd_name __P((int, int *, int *));
|
||||
static char *prog_complete_return __P((const char *, int));
|
||||
|
||||
static char **prog_complete_matches;
|
||||
@@ -563,7 +563,13 @@ bashline_set_event_hook ()
|
||||
{
|
||||
rl_event_hook = bash_event_hook;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bashline_reset_event_hook ()
|
||||
{
|
||||
rl_event_hook = 0;
|
||||
}
|
||||
|
||||
/* On Sun systems at least, rl_attempted_completion_function can end up
|
||||
getting set to NULL, and rl_completion_entry_function set to do command
|
||||
word completion if Bash is interrupted while trying to complete a command
|
||||
@@ -1243,8 +1249,9 @@ find_cmd_end (end)
|
||||
}
|
||||
|
||||
static char *
|
||||
find_cmd_name (start)
|
||||
find_cmd_name (start, sp, ep)
|
||||
int start;
|
||||
int *sp, *ep;
|
||||
{
|
||||
char *name;
|
||||
register int s, e;
|
||||
@@ -1257,6 +1264,11 @@ find_cmd_name (start)
|
||||
|
||||
name = substring (rl_line_buffer, s, e);
|
||||
|
||||
if (sp)
|
||||
*sp = s;
|
||||
if (ep)
|
||||
*ep = e;
|
||||
|
||||
return (name);
|
||||
}
|
||||
|
||||
@@ -1359,7 +1371,7 @@ attempt_shell_completion (text, start, end)
|
||||
prog_completion_enabled && (progcomp_size () > 0) &&
|
||||
current_prompt_string == ps1_prompt)
|
||||
{
|
||||
int s, e, foundcs;
|
||||
int s, e, s1, e1, foundcs;
|
||||
char *n;
|
||||
|
||||
/* XXX - don't free the members */
|
||||
@@ -1369,9 +1381,15 @@ attempt_shell_completion (text, start, end)
|
||||
|
||||
s = find_cmd_start (start);
|
||||
e = find_cmd_end (end);
|
||||
n = find_cmd_name (s);
|
||||
if (e == 0 && e == s && text[0] == '\0')
|
||||
n = find_cmd_name (s, &s1, &e1);
|
||||
if (start == 0 && end == 0 && e != 0 && text[0] == '\0') /* beginning of non-empty line */
|
||||
foundcs = 0;
|
||||
else if (start == end && start == s1 && e1 > end)
|
||||
foundcs = 0;
|
||||
else if (e == 0 && e == s && text[0] == '\0') /* beginning of empty line */
|
||||
prog_complete_matches = programmable_completions ("_EmptycmD_", text, s, e, &foundcs);
|
||||
else if (start == end && text[0] == '\0' && s1 > start && whitespace (rl_line_buffer[start]))
|
||||
foundcs = 0; /* whitespace before command name */
|
||||
else if (e > s && assignment (n, 0) == 0)
|
||||
prog_complete_matches = programmable_completions (n, text, s, e, &foundcs);
|
||||
else
|
||||
@@ -1527,7 +1545,7 @@ command_word_completion_function (hint_text, state)
|
||||
#if defined (ALIAS)
|
||||
static alias_t **alias_list = (alias_t **)NULL;
|
||||
#endif /* ALIAS */
|
||||
char *temp;
|
||||
char *temp, *cval;
|
||||
|
||||
/* We have to map over the possibilities for command words. If we have
|
||||
no state, then make one just for that purpose. */
|
||||
@@ -1853,19 +1871,38 @@ globword:
|
||||
freetemp = match = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* If we have found a match, and it is an executable file or a
|
||||
directory name, return it. */
|
||||
if (match && executable_or_directory (val))
|
||||
#else
|
||||
/* If we have found a match, and it is an executable file, return it.
|
||||
We don't return directory names when searching $PATH, since the
|
||||
bash execution code won't find executables in directories which
|
||||
appear in directories in $PATH when they're specified using
|
||||
relative pathnames. */
|
||||
if (match && (searching_path ? executable_file (val) : executable_or_directory (val)))
|
||||
#endif
|
||||
relative pathnames. */
|
||||
#if 0
|
||||
/* If we're not searching $PATH and we have a relative pathname, we
|
||||
need to re-canonicalize it before testing whether or not it's an
|
||||
executable or a directory so the shell treats .. relative to $PWD
|
||||
according to the physical/logical option. The shell already
|
||||
canonicalizes the directory name in order to tell readline where
|
||||
to look, so not doing it here will be inconsistent. */
|
||||
/* XXX -- currently not used -- will introduce more inconsistency,
|
||||
since shell does not canonicalize ../foo before passing it to
|
||||
shell_execve(). */
|
||||
if (match && searching_path == 0 && *val == '.')
|
||||
{
|
||||
char *t, *t1;
|
||||
|
||||
t = get_working_directory ("command-word-completion");
|
||||
t1 = make_absolute (val, t);
|
||||
free (t);
|
||||
cval = sh_canonpath (t1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
cval = val;
|
||||
|
||||
if (match && (searching_path ? executable_file (val) : executable_or_directory (cval)))
|
||||
{
|
||||
if (cval != val)
|
||||
free (cval);
|
||||
free (val);
|
||||
val = ""; /* So it won't be NULL. */
|
||||
return (temp);
|
||||
@@ -1874,6 +1911,8 @@ globword:
|
||||
{
|
||||
if (freetemp)
|
||||
free (temp);
|
||||
if (cval != val)
|
||||
free (cval);
|
||||
free (val);
|
||||
goto inner;
|
||||
}
|
||||
|
||||
@@ -641,6 +641,12 @@ assign_vars:
|
||||
xfree (input_string);
|
||||
return EXECUTION_FAILURE; /* readonly or noassign */
|
||||
}
|
||||
if (assoc_p (var))
|
||||
{
|
||||
builtin_error (_("%s: cannot convert associative to indexed array"), arrayname);
|
||||
xfree (input_string);
|
||||
return EXECUTION_FAILURE; /* existing associative array */
|
||||
}
|
||||
array_flush (array_cell (var));
|
||||
|
||||
alist = list_string (input_string, ifs_chars, 0);
|
||||
|
||||
+3
-4
@@ -5,12 +5,12 @@
|
||||
.\" Case Western Reserve University
|
||||
.\" chet@po.cwru.edu
|
||||
.\"
|
||||
.\" Last Change: Mon May 9 12:23:35 EDT 2011
|
||||
.\" Last Change: Fri Jun 24 11:28:14 EDT 2011
|
||||
.\"
|
||||
.\" bash_builtins, strip all but Built-Ins section
|
||||
.if \n(zZ=1 .ig zZ
|
||||
.if \n(zY=1 .ig zY
|
||||
.TH BASH 1 "2011 May 9" "GNU Bash 4.2"
|
||||
.TH BASH 1 "2011 June 24" "GNU Bash 4.2"
|
||||
.\"
|
||||
.\" There's some problem with having a `@'
|
||||
.\" in a tagged paragraph with the BSD man macros.
|
||||
@@ -8925,8 +8925,7 @@ above). The shell always
|
||||
postpones exiting if any jobs are stopped.
|
||||
.TP 8
|
||||
.B checkwinsize
|
||||
If set, \fBbash\fP checks the window size after each command when running
|
||||
interactively
|
||||
If set, \fBbash\fP checks the window size after each command
|
||||
and, if necessary, updates the values of
|
||||
.SM
|
||||
.B LINES
|
||||
|
||||
+18
-6
@@ -10,7 +10,7 @@
|
||||
.\" bash_builtins, strip all but Built-Ins section
|
||||
.if \n(zZ=1 .ig zZ
|
||||
.if \n(zY=1 .ig zY
|
||||
.TH BASH 1 "2011 May 9" "GNU Bash 4.2"
|
||||
.TH BASH 1 "2011 June 24" "GNU Bash 4.2"
|
||||
.\"
|
||||
.\" There's some problem with having a `@'
|
||||
.\" in a tagged paragraph with the BSD man macros.
|
||||
@@ -1866,7 +1866,8 @@ A sample value is
|
||||
.TP
|
||||
.B COLUMNS
|
||||
Used by the \fBselect\fP compound command to determine the terminal width
|
||||
when printing selection lists. Automatically set upon receipt of a
|
||||
when printing selection lists. Automatically set in an interactive shell
|
||||
upon receipt of a
|
||||
.SM
|
||||
.BR SIGWINCH .
|
||||
.TP
|
||||
@@ -2098,7 +2099,8 @@ This variable determines the locale category used for number formatting.
|
||||
.TP
|
||||
.B LINES
|
||||
Used by the \fBselect\fP compound command to determine the column length
|
||||
for printing selection lists. Automatically set upon receipt of a
|
||||
for printing selection lists. Automatically set by an interactive shell
|
||||
upon receipt of a
|
||||
.SM
|
||||
.BR SIGWINCH .
|
||||
.TP
|
||||
@@ -3254,11 +3256,21 @@ or a
|
||||
.B ^
|
||||
then any character not enclosed is matched.
|
||||
The sorting order of characters in range expressions is determined by
|
||||
the current locale and the value of the
|
||||
the current locale and the values of the
|
||||
.SM
|
||||
.B LC_COLLATE
|
||||
shell variable,
|
||||
if set.
|
||||
or
|
||||
.SM
|
||||
.B LC_ALL
|
||||
shell variables, if set.
|
||||
To obtain the traditional interpretation of range expressions, where
|
||||
.B [a\-d]
|
||||
is equivalent to
|
||||
.BR [abcd] ,
|
||||
set value of the
|
||||
.B LC_ALL
|
||||
shell variable to
|
||||
.BR C .
|
||||
A
|
||||
.B \-
|
||||
may be matched by including it as the first or last character
|
||||
|
||||
+2
-2
@@ -4513,8 +4513,8 @@ intervening command (@pxref{Job Control}).
|
||||
The shell always postpones exiting if any jobs are stopped.
|
||||
|
||||
@item checkwinsize
|
||||
If set, Bash checks the window size after each command when running
|
||||
interactively and, if necessary, updates the values of
|
||||
If set, Bash checks the window size after each command
|
||||
and, if necessary, updates the values of
|
||||
@env{LINES} and @env{COLUMNS}.
|
||||
|
||||
@item cmdhist
|
||||
|
||||
+8
-6
@@ -2124,8 +2124,8 @@ may be matched by including it as the first or last character
|
||||
in the set. A @samp{]} may be matched by including it as the first
|
||||
character in the set.
|
||||
The sorting order of characters in range expressions is determined by
|
||||
the current locale and the value of the @env{LC_COLLATE} shell variable,
|
||||
if set.
|
||||
the current locale and the values of the
|
||||
@env{LC_COLLATE} and @env{LC_ALL} shell variables, if set.
|
||||
|
||||
For example, in the default C locale, @samp{[a-dx-z]} is equivalent to
|
||||
@samp{[abcdxyz]}. Many locales sort characters in dictionary order, and in
|
||||
@@ -4513,8 +4513,8 @@ intervening command (@pxref{Job Control}).
|
||||
The shell always postpones exiting if any jobs are stopped.
|
||||
|
||||
@item checkwinsize
|
||||
If set, Bash checks the window size after each command
|
||||
and, if necessary, updates the values of
|
||||
If set, Bash checks the window size after each command when running
|
||||
interactively and, if necessary, updates the values of
|
||||
@env{LINES} and @env{COLUMNS}.
|
||||
|
||||
@item cmdhist
|
||||
@@ -5008,7 +5008,8 @@ being closed.
|
||||
|
||||
@item COLUMNS
|
||||
Used by the @code{select} command to determine the terminal width
|
||||
when printing selection lists. Automatically set upon receipt of a
|
||||
when printing selection lists. Automatically set by an interactive shell
|
||||
upon receipt of a
|
||||
@code{SIGWINCH}.
|
||||
|
||||
@item COMP_CWORD
|
||||
@@ -5297,7 +5298,8 @@ The line number in the script or shell function currently executing.
|
||||
|
||||
@item LINES
|
||||
Used by the @code{select} command to determine the column length
|
||||
for printing selection lists. Automatically set upon receipt of a
|
||||
for printing selection lists. Automatically set by an interactive shell
|
||||
upon receipt of a
|
||||
@code{SIGWINCH}.
|
||||
|
||||
@item MACHTYPE
|
||||
|
||||
+3
-3
@@ -2,9 +2,9 @@
|
||||
Copyright (C) 1988-2011 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set LASTCHANGE Mon May 9 12:23:18 EDT 2011
|
||||
@set LASTCHANGE Fri Jun 24 11:28:28 EDT 2011
|
||||
|
||||
@set EDITION 4.2
|
||||
@set VERSION 4.2
|
||||
@set UPDATED 9 May 2011
|
||||
@set UPDATED-MONTH May 2011
|
||||
@set UPDATED 24 June 2011
|
||||
@set UPDATED-MONTH June 2011
|
||||
|
||||
+3
-3
@@ -2,9 +2,9 @@
|
||||
Copyright (C) 1988-2011 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set LASTCHANGE Tue Dec 28 13:41:22 EST 2010
|
||||
@set LASTCHANGE Mon May 9 12:23:18 EDT 2011
|
||||
|
||||
@set EDITION 4.2
|
||||
@set VERSION 4.2
|
||||
@set UPDATED 28 December 2010
|
||||
@set UPDATED-MONTH December 2010
|
||||
@set UPDATED 9 May 2011
|
||||
@set UPDATED-MONTH May 2011
|
||||
|
||||
+11
-9
@@ -36,6 +36,8 @@ extern size_t mbstrlen __P((const char *));
|
||||
|
||||
extern char *xstrchr __P((const char *, int));
|
||||
|
||||
extern int locale_mb_cur_max; /* XXX */
|
||||
|
||||
#ifndef MB_INVALIDCH
|
||||
#define MB_INVALIDCH(x) ((x) == (size_t)-1 || (x) == (size_t)-2)
|
||||
#define MB_NULLWCH(x) ((x) == 0)
|
||||
@@ -98,7 +100,7 @@ extern char *xstrchr __P((const char *, int));
|
||||
# define ADVANCE_CHAR(_str, _strsize, _i) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
@@ -138,7 +140,7 @@ extern char *xstrchr __P((const char *, int));
|
||||
# define ADVANCE_CHAR_P(_str, _strsize) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
@@ -173,7 +175,7 @@ extern char *xstrchr __P((const char *, int));
|
||||
# define BACKUP_CHAR(_str, _strsize, _i) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
@@ -215,7 +217,7 @@ extern char *xstrchr __P((const char *, int));
|
||||
# define BACKUP_CHAR_P(_base, _strsize, _str) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
@@ -256,7 +258,7 @@ extern char *xstrchr __P((const char *, int));
|
||||
# define COPY_CHAR_P(_dst, _src, _srcend) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
@@ -295,7 +297,7 @@ extern char *xstrchr __P((const char *, int));
|
||||
# define COPY_CHAR_I(_dst, _di, _src, _srcend, _si) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
@@ -338,7 +340,7 @@ extern char *xstrchr __P((const char *, int));
|
||||
# define SCOPY_CHAR_I(_dst, _escchar, _sc, _src, _si, _slen) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
@@ -385,7 +387,7 @@ extern char *xstrchr __P((const char *, int));
|
||||
# define SCOPY_CHAR_M(_dst, _src, _srcend, _si) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
@@ -429,7 +431,7 @@ extern char *xstrchr __P((const char *, int));
|
||||
# define SADD_MBCHAR(_dst, _src, _si, _srcsize) \
|
||||
do \
|
||||
{ \
|
||||
if (MB_CUR_MAX > 1) \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
int i; \
|
||||
mbstate_t state_bak; \
|
||||
|
||||
@@ -0,0 +1,501 @@
|
||||
/* shmbutil.h -- utility functions for multibyte characters. */
|
||||
|
||||
/* Copyright (C) 2002-2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_SH_MBUTIL_H_)
|
||||
#define _SH_MBUTIL_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
/* Include config.h for HANDLE_MULTIBYTE */
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
#include "shmbchar.h"
|
||||
|
||||
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_INVALIDCH(x) ((x) == (size_t)-1 || (x) == (size_t)-2)
|
||||
#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))
|
||||
|
||||
#define MBLEN(s, n) ((MB_CUR_MAX > 1) ? mblen ((s), (n)) : 1)
|
||||
#define MBRLEN(s, n, p) ((MB_CUR_MAX > 1) ? mbrlen ((s), (n), (p)) : 1)
|
||||
|
||||
#else /* !HANDLE_MULTIBYTE */
|
||||
|
||||
#undef MB_LEN_MAX
|
||||
#undef MB_CUR_MAX
|
||||
|
||||
#define MB_LEN_MAX 1
|
||||
#define MB_CUR_MAX 1
|
||||
|
||||
#undef xstrchr
|
||||
#define xstrchr(s, c) strchr(s, c)
|
||||
|
||||
#ifndef MB_INVALIDCH
|
||||
#define MB_INVALIDCH(x) (0)
|
||||
#define MB_NULLWCH(x) (0)
|
||||
#endif
|
||||
|
||||
#define MB_STRLEN(s) (STRLEN(s))
|
||||
|
||||
#define MBLEN(s, n) 1
|
||||
#define MBRLEN(s, n, p) 1
|
||||
|
||||
#ifndef wchar_t
|
||||
# define wchar_t int
|
||||
#endif
|
||||
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Declare and initialize a multibyte state. Call must be terminated
|
||||
with `;'. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define DECLARE_MBSTATE \
|
||||
mbstate_t state; \
|
||||
memset (&state, '\0', sizeof (mbstate_t))
|
||||
#else
|
||||
# define DECLARE_MBSTATE
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Initialize or reinitialize a multibyte state named `state'. Call must be
|
||||
terminated with `;'. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define INITIALIZE_MBSTATE memset (&state, '\0', sizeof (mbstate_t))
|
||||
#else
|
||||
# define INITIALIZE_MBSTATE
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Advance one (possibly multi-byte) character in string _STR of length
|
||||
_STRSIZE, starting at index _I. STATE must have already been declared. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define ADVANCE_CHAR(_str, _strsize, _i) \
|
||||
do \
|
||||
{ \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _f; \
|
||||
\
|
||||
_f = is_basic ((_str)[_i]); \
|
||||
if (_f) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_str) + (_i), (_strsize) - (_i), &state); \
|
||||
} \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
(_i)++; \
|
||||
} \
|
||||
else if (mblength == 0) \
|
||||
(_i)++; \
|
||||
else \
|
||||
(_i) += mblength; \
|
||||
} \
|
||||
else \
|
||||
(_i)++; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define ADVANCE_CHAR(_str, _strsize, _i) (_i)++
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Advance one (possibly multibyte) character in the string _STR of length
|
||||
_STRSIZE.
|
||||
SPECIAL: assume that _STR will be incremented by 1 after this call. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define ADVANCE_CHAR_P(_str, _strsize) \
|
||||
do \
|
||||
{ \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _f; \
|
||||
\
|
||||
_f = is_basic (*(_str)); \
|
||||
if (_f) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_str), (_strsize), &state); \
|
||||
} \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
(_str) += (mblength < 1) ? 0 : (mblength - 1); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define ADVANCE_CHAR_P(_str, _strsize)
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Back up one (possibly multi-byte) character in string _STR of length
|
||||
_STRSIZE, starting at index _I. STATE must have already been declared. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define BACKUP_CHAR(_str, _strsize, _i) \
|
||||
do \
|
||||
{ \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _x, _p; /* _x == temp index into string, _p == prev index */ \
|
||||
\
|
||||
_x = _p = 0; \
|
||||
while (_x < (_i)) \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_str) + (_x), (_strsize) - (_x), &state); \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
_x++; \
|
||||
} \
|
||||
else if (mblength == 0) \
|
||||
_x++; \
|
||||
else \
|
||||
{ \
|
||||
_p = _x; /* _p == start of prev mbchar */ \
|
||||
_x += mblength; \
|
||||
} \
|
||||
} \
|
||||
(_i) = _p; \
|
||||
} \
|
||||
else \
|
||||
(_i)--; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define BACKUP_CHAR(_str, _strsize, _i) (_i)--
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Back up one (possibly multibyte) character in the string _BASE of length
|
||||
_STRSIZE starting at _STR (_BASE <= _STR <= (_BASE + _STRSIZE) ).
|
||||
SPECIAL: DO NOT assume that _STR will be decremented by 1 after this call. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define BACKUP_CHAR_P(_base, _strsize, _str) \
|
||||
do \
|
||||
{ \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
char *_x, _p; /* _x == temp pointer into string, _p == prev pointer */ \
|
||||
\
|
||||
_x = _p = _base; \
|
||||
while (_x < (_str)) \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen (_x, (_strsize) - _x, &state); \
|
||||
\
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
_x++; \
|
||||
} \
|
||||
else if (mblength == 0) \
|
||||
_x++; \
|
||||
else \
|
||||
{ \
|
||||
_p = _x; /* _p == start of prev mbchar */ \
|
||||
_x += mblength; \
|
||||
} \
|
||||
} \
|
||||
(_str) = _p; \
|
||||
} \
|
||||
else \
|
||||
(_str)--; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define BACKUP_CHAR_P(_base, _strsize, _str) (_str)--
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Copy a single character from the string _SRC to the string _DST.
|
||||
_SRCEND is a pointer to the end of _SRC. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define COPY_CHAR_P(_dst, _src, _srcend) \
|
||||
do \
|
||||
{ \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _k; \
|
||||
\
|
||||
_k = is_basic (*(_src)); \
|
||||
if (_k) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src), (_srcend) - (_src), &state); \
|
||||
} \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
mblength = (mblength < 1) ? 1 : mblength; \
|
||||
\
|
||||
for (_k = 0; _k < mblength; _k++) \
|
||||
*(_dst)++ = *(_src)++; \
|
||||
} \
|
||||
else \
|
||||
*(_dst)++ = *(_src)++; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define COPY_CHAR_P(_dst, _src, _srcend) *(_dst)++ = *(_src)++
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/* Copy a single character from the string _SRC at index _SI to the string
|
||||
_DST at index _DI. _SRCEND is a pointer to the end of _SRC. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define COPY_CHAR_I(_dst, _di, _src, _srcend, _si) \
|
||||
do \
|
||||
{ \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _k; \
|
||||
\
|
||||
_k = is_basic (*((_src) + (_si))); \
|
||||
if (_k) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{\
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src)+(_si)), &state); \
|
||||
} \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
mblength = (mblength < 1) ? 1 : mblength; \
|
||||
\
|
||||
for (_k = 0; _k < mblength; _k++) \
|
||||
_dst[_di++] = _src[_si++]; \
|
||||
} \
|
||||
else \
|
||||
_dst[_di++] = _src[_si++]; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define COPY_CHAR_I(_dst, _di, _src, _srcend, _si) _dst[_di++] = _src[_si++]
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
/****************************************************************
|
||||
* *
|
||||
* The following are only guaranteed to work in subst.c *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define SCOPY_CHAR_I(_dst, _escchar, _sc, _src, _si, _slen) \
|
||||
do \
|
||||
{ \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _i; \
|
||||
\
|
||||
_i = is_basic (*((_src) + (_si))); \
|
||||
if (_i) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_slen) - (_si), &state); \
|
||||
} \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
mblength = (mblength < 1) ? 1 : mblength; \
|
||||
\
|
||||
temp = xmalloc (mblength + 2); \
|
||||
temp[0] = _escchar; \
|
||||
for (_i = 0; _i < mblength; _i++) \
|
||||
temp[_i + 1] = _src[_si++]; \
|
||||
temp[mblength + 1] = '\0'; \
|
||||
\
|
||||
goto add_string; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
_dst[0] = _escchar; \
|
||||
_dst[1] = _sc; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define SCOPY_CHAR_I(_dst, _escchar, _sc, _src, _si, _slen) \
|
||||
_dst[0] = _escchar; \
|
||||
_dst[1] = _sc
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define SCOPY_CHAR_M(_dst, _src, _srcend, _si) \
|
||||
do \
|
||||
{ \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
int _i; \
|
||||
\
|
||||
_i = is_basic (*((_src) + (_si))); \
|
||||
if (_i) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcend) - ((_src) + (_si)), &state); \
|
||||
} \
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
else \
|
||||
mblength = (mblength < 1) ? 1 : mblength; \
|
||||
\
|
||||
FASTCOPY(((_src) + (_si)), (_dst), mblength); \
|
||||
\
|
||||
(_dst) += mblength; \
|
||||
(_si) += mblength; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
*(_dst)++ = _src[(_si)]; \
|
||||
(_si)++; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define SCOPY_CHAR_M(_dst, _src, _srcend, _si) \
|
||||
*(_dst)++ = _src[(_si)]; \
|
||||
(_si)++
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
#if HANDLE_MULTIBYTE
|
||||
# define SADD_MBCHAR(_dst, _src, _si, _srcsize) \
|
||||
do \
|
||||
{ \
|
||||
if (locale_mb_cur_max > 1) \
|
||||
{ \
|
||||
int i; \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
\
|
||||
i = is_basic (*((_src) + (_si))); \
|
||||
if (i) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \
|
||||
} \
|
||||
if (mblength == (size_t)-1 || mblength == (size_t)-2) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
if (mblength < 1) \
|
||||
mblength = 1; \
|
||||
\
|
||||
_dst = (char *)xmalloc (mblength + 1); \
|
||||
for (i = 0; i < mblength; i++) \
|
||||
(_dst)[i] = (_src)[(_si)++]; \
|
||||
(_dst)[mblength] = '\0'; \
|
||||
\
|
||||
goto add_string; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#else
|
||||
# define SADD_MBCHAR(_dst, _src, _si, _srcsize)
|
||||
#endif
|
||||
|
||||
/* Watch out when using this -- it's just straight textual subsitution */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
# define SADD_MBQCHAR_BODY(_dst, _src, _si, _srcsize) \
|
||||
\
|
||||
int i; \
|
||||
mbstate_t state_bak; \
|
||||
size_t mblength; \
|
||||
\
|
||||
i = is_basic (*((_src) + (_si))); \
|
||||
if (i) \
|
||||
mblength = 1; \
|
||||
else \
|
||||
{ \
|
||||
state_bak = state; \
|
||||
mblength = mbrlen ((_src) + (_si), (_srcsize) - (_si), &state); \
|
||||
} \
|
||||
if (mblength == (size_t)-1 || mblength == (size_t)-2) \
|
||||
{ \
|
||||
state = state_bak; \
|
||||
mblength = 1; \
|
||||
} \
|
||||
if (mblength < 1) \
|
||||
mblength = 1; \
|
||||
\
|
||||
(_dst) = (char *)xmalloc (mblength + 2); \
|
||||
(_dst)[0] = CTLESC; \
|
||||
for (i = 0; i < mblength; i++) \
|
||||
(_dst)[i+1] = (_src)[(_si)++]; \
|
||||
(_dst)[mblength+1] = '\0'; \
|
||||
\
|
||||
goto add_string
|
||||
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
#endif /* _SH_MBUTIL_H_ */
|
||||
@@ -2612,6 +2612,8 @@ if (job == NO_JOB)
|
||||
kill (getpid (), SIGINT);
|
||||
}
|
||||
}
|
||||
else if (interactive_shell == 0 && IS_FOREGROUND (job) && check_window_size)
|
||||
get_new_window_size (0, (int *)0, (int *)0);
|
||||
|
||||
/* Moved here from set_job_status_and_cleanup, which is in the SIGCHLD
|
||||
signal handler path */
|
||||
|
||||
@@ -2612,6 +2612,8 @@ if (job == NO_JOB)
|
||||
kill (getpid (), SIGINT);
|
||||
}
|
||||
}
|
||||
else if (interactive_shell == 0 && IS_FOREGROUND (job) && check_window_size)
|
||||
get_new_window_size (0, (int *)0, (int *)0);
|
||||
|
||||
/* Moved here from set_job_status_and_cleanup, which is in the SIGCHLD
|
||||
signal handler path */
|
||||
@@ -3556,6 +3558,9 @@ notify_of_job_status ()
|
||||
case JDEAD:
|
||||
if (interactive_shell == 0 && termsig && WIFSIGNALED (s) &&
|
||||
termsig != SIGINT &&
|
||||
#if defined (DONT_REPORT_SIGTERM)
|
||||
termsig != SIGTERM &&
|
||||
#endif
|
||||
#if defined (DONT_REPORT_SIGPIPE)
|
||||
termsig != SIGPIPE &&
|
||||
#endif
|
||||
|
||||
+7
-4
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 1991-2006 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1991-2011 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -290,7 +290,7 @@ BRACKMATCH (p, test, flags)
|
||||
{
|
||||
register CHAR cstart, cend, c;
|
||||
register int not; /* Nonzero if the sense of the character class is inverted. */
|
||||
int brcnt;
|
||||
int brcnt, forcecoll;;
|
||||
INT pc;
|
||||
CHAR *savep;
|
||||
|
||||
@@ -311,6 +311,7 @@ BRACKMATCH (p, test, flags)
|
||||
/* Initialize cstart and cend in case `-' is the last
|
||||
character of the pattern. */
|
||||
cstart = cend = c;
|
||||
forcecoll = 0;
|
||||
|
||||
/* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find
|
||||
the end of the equivalence class, move the pattern pointer past
|
||||
@@ -400,6 +401,7 @@ BRACKMATCH (p, test, flags)
|
||||
range. If it is, we set cstart to one greater than `test',
|
||||
so any comparisons later will fail. */
|
||||
cstart = (pc == INVALID) ? test + 1 : pc;
|
||||
forcecoll = 1;
|
||||
}
|
||||
|
||||
if (!(flags & FNM_NOESCAPE) && c == L('\\'))
|
||||
@@ -443,6 +445,7 @@ BRACKMATCH (p, test, flags)
|
||||
range expression. If we get one, we set cend to one fewer
|
||||
than the test character to make sure the range test fails. */
|
||||
cend = (pc == INVALID) ? test - 1 : pc;
|
||||
forcecoll = 1;
|
||||
}
|
||||
cend = FOLD (cend);
|
||||
|
||||
@@ -453,7 +456,7 @@ BRACKMATCH (p, test, flags)
|
||||
the expression shall be treated as invalid.'' Note that this
|
||||
applies to only the range expression; the rest of the bracket
|
||||
expression is still checked for matches. */
|
||||
if (RANGECMP (cstart, cend) > 0)
|
||||
if (RANGECMP (cstart, cend, forcecoll) > 0)
|
||||
{
|
||||
if (c == L(']'))
|
||||
break;
|
||||
@@ -462,7 +465,7 @@ BRACKMATCH (p, test, flags)
|
||||
}
|
||||
}
|
||||
|
||||
if (RANGECMP (test, cstart) >= 0 && RANGECMP (test, cend) <= 0)
|
||||
if (RANGECMP (test, cstart, forcecoll) >= 0 && RANGECMP (test, cend, forcecoll) <= 0)
|
||||
goto matched;
|
||||
|
||||
if (c == L(']'))
|
||||
|
||||
@@ -0,0 +1,772 @@
|
||||
/* Copyright (C) 1991-2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
int FCT __P((CHAR *, CHAR *, int));
|
||||
|
||||
static int GMATCH __P((CHAR *, CHAR *, CHAR *, CHAR *, int));
|
||||
static CHAR *PARSE_COLLSYM __P((CHAR *, INT *));
|
||||
static CHAR *BRACKMATCH __P((CHAR *, U_CHAR, int));
|
||||
static int EXTMATCH __P((INT, CHAR *, CHAR *, CHAR *, CHAR *, int));
|
||||
static CHAR *PATSCAN __P((CHAR *, CHAR *, INT));
|
||||
|
||||
int
|
||||
FCT (pattern, string, flags)
|
||||
CHAR *pattern;
|
||||
CHAR *string;
|
||||
int flags;
|
||||
{
|
||||
CHAR *se, *pe;
|
||||
|
||||
if (string == 0 || pattern == 0)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
se = string + STRLEN ((XCHAR *)string);
|
||||
pe = pattern + STRLEN ((XCHAR *)pattern);
|
||||
|
||||
return (GMATCH (string, se, pattern, pe, flags));
|
||||
}
|
||||
|
||||
/* Match STRING against the filename pattern PATTERN, returning zero if
|
||||
it matches, FNM_NOMATCH if not. */
|
||||
static int
|
||||
GMATCH (string, se, pattern, pe, flags)
|
||||
CHAR *string, *se;
|
||||
CHAR *pattern, *pe;
|
||||
int flags;
|
||||
{
|
||||
CHAR *p, *n; /* pattern, string */
|
||||
INT c; /* current pattern character - XXX U_CHAR? */
|
||||
INT sc; /* current string character - XXX U_CHAR? */
|
||||
|
||||
p = pattern;
|
||||
n = string;
|
||||
|
||||
if (string == 0 || pattern == 0)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
#if DEBUG_MATCHING
|
||||
fprintf(stderr, "gmatch: string = %s; se = %s\n", string, se);
|
||||
fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
|
||||
#endif
|
||||
|
||||
while (p < pe)
|
||||
{
|
||||
c = *p++;
|
||||
c = FOLD (c);
|
||||
|
||||
sc = n < se ? *n : '\0';
|
||||
|
||||
#ifdef EXTENDED_GLOB
|
||||
/* EXTMATCH () will handle recursively calling GMATCH, so we can
|
||||
just return what EXTMATCH() returns. */
|
||||
if ((flags & FNM_EXTMATCH) && *p == L('(') &&
|
||||
(c == L('+') || c == L('*') || c == L('?') || c == L('@') || c == L('!'))) /* ) */
|
||||
{
|
||||
int lflags;
|
||||
/* If we're not matching the start of the string, we're not
|
||||
concerned about the special cases for matching `.' */
|
||||
lflags = (n == string) ? flags : (flags & ~FNM_PERIOD);
|
||||
return (EXTMATCH (c, n, se, p, pe, lflags));
|
||||
}
|
||||
#endif /* EXTENDED_GLOB */
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case L('?'): /* Match single character */
|
||||
if (sc == '\0')
|
||||
return FNM_NOMATCH;
|
||||
else if ((flags & FNM_PATHNAME) && sc == L('/'))
|
||||
/* If we are matching a pathname, `?' can never match a `/'. */
|
||||
return FNM_NOMATCH;
|
||||
else if ((flags & FNM_PERIOD) && sc == L('.') &&
|
||||
(n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
|
||||
/* `?' cannot match a `.' if it is the first character of the
|
||||
string or if it is the first character following a slash and
|
||||
we are matching a pathname. */
|
||||
return FNM_NOMATCH;
|
||||
break;
|
||||
|
||||
case L('\\'): /* backslash escape removes special meaning */
|
||||
if (p == pe)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
if ((flags & FNM_NOESCAPE) == 0)
|
||||
{
|
||||
c = *p++;
|
||||
/* A trailing `\' cannot match. */
|
||||
if (p > pe)
|
||||
return FNM_NOMATCH;
|
||||
c = FOLD (c);
|
||||
}
|
||||
if (FOLD (sc) != (U_CHAR)c)
|
||||
return FNM_NOMATCH;
|
||||
break;
|
||||
|
||||
case '*': /* Match zero or more characters */
|
||||
if (p == pe)
|
||||
return 0;
|
||||
|
||||
if ((flags & FNM_PERIOD) && sc == L('.') &&
|
||||
(n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
|
||||
/* `*' cannot match a `.' if it is the first character of the
|
||||
string or if it is the first character following a slash and
|
||||
we are matching a pathname. */
|
||||
return FNM_NOMATCH;
|
||||
|
||||
/* Collapse multiple consecutive `*' and `?', but make sure that
|
||||
one character of the string is consumed for each `?'. */
|
||||
for (c = *p++; (c == L('?') || c == L('*')); c = *p++)
|
||||
{
|
||||
if ((flags & FNM_PATHNAME) && sc == L('/'))
|
||||
/* A slash does not match a wildcard under FNM_PATHNAME. */
|
||||
return FNM_NOMATCH;
|
||||
#ifdef EXTENDED_GLOB
|
||||
else if ((flags & FNM_EXTMATCH) && c == L('?') && *p == L('(')) /* ) */
|
||||
{
|
||||
CHAR *newn;
|
||||
for (newn = n; newn < se; ++newn)
|
||||
{
|
||||
if (EXTMATCH (c, newn, se, p, pe, flags) == 0)
|
||||
return (0);
|
||||
}
|
||||
/* We didn't match. If we have a `?(...)', that's failure. */
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
#endif
|
||||
else if (c == L('?'))
|
||||
{
|
||||
if (sc == L('\0'))
|
||||
return FNM_NOMATCH;
|
||||
/* One character of the string is consumed in matching
|
||||
this ? wildcard, so *??? won't match if there are
|
||||
fewer than three characters. */
|
||||
n++;
|
||||
sc = n < se ? *n : '\0';
|
||||
}
|
||||
|
||||
#ifdef EXTENDED_GLOB
|
||||
/* Handle ******(patlist) */
|
||||
if ((flags & FNM_EXTMATCH) && c == L('*') && *p == L('(')) /*)*/
|
||||
{
|
||||
CHAR *newn;
|
||||
/* We need to check whether or not the extended glob
|
||||
pattern matches the remainder of the string.
|
||||
If it does, we match the entire pattern. */
|
||||
for (newn = n; newn < se; ++newn)
|
||||
{
|
||||
if (EXTMATCH (c, newn, se, p, pe, flags) == 0)
|
||||
return (0);
|
||||
}
|
||||
/* We didn't match the extended glob pattern, but
|
||||
that's OK, since we can match 0 or more occurrences.
|
||||
We need to skip the glob pattern and see if we
|
||||
match the rest of the string. */
|
||||
newn = PATSCAN (p + 1, pe, 0);
|
||||
/* If NEWN is 0, we have an ill-formed pattern. */
|
||||
p = newn ? newn : pe;
|
||||
}
|
||||
#endif
|
||||
if (p == pe)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we've hit the end of the pattern and the last character of
|
||||
the pattern was handled by the loop above, we've succeeded.
|
||||
Otherwise, we need to match that last character. */
|
||||
if (p == pe && (c == L('?') || c == L('*')))
|
||||
return (0);
|
||||
|
||||
/* General case, use recursion. */
|
||||
{
|
||||
U_CHAR c1;
|
||||
|
||||
c1 = ((flags & FNM_NOESCAPE) == 0 && c == L('\\')) ? *p : c;
|
||||
c1 = FOLD (c1);
|
||||
for (--p; n < se; ++n)
|
||||
{
|
||||
/* Only call strmatch if the first character indicates a
|
||||
possible match. We can check the first character if
|
||||
we're not doing an extended glob match. */
|
||||
if ((flags & FNM_EXTMATCH) == 0 && c != L('[') && FOLD (*n) != c1) /*]*/
|
||||
continue;
|
||||
|
||||
/* If we're doing an extended glob match and the pattern is not
|
||||
one of the extended glob patterns, we can check the first
|
||||
character. */
|
||||
if ((flags & FNM_EXTMATCH) && p[1] != L('(') && /*)*/
|
||||
STRCHR (L("?*+@!"), *p) == 0 && c != L('[') && FOLD (*n) != c1) /*]*/
|
||||
continue;
|
||||
|
||||
/* Otherwise, we just recurse. */
|
||||
if (GMATCH (n, se, p, pe, flags & ~FNM_PERIOD) == 0)
|
||||
return (0);
|
||||
}
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
case L('['):
|
||||
{
|
||||
if (sc == L('\0') || n == se)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
/* A character class cannot match a `.' if it is the first
|
||||
character of the string or if it is the first character
|
||||
following a slash and we are matching a pathname. */
|
||||
if ((flags & FNM_PERIOD) && sc == L('.') &&
|
||||
(n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
p = BRACKMATCH (p, sc, flags);
|
||||
if (p == 0)
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((U_CHAR)c != FOLD (sc))
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
|
||||
++n;
|
||||
}
|
||||
|
||||
if (n == se)
|
||||
return (0);
|
||||
|
||||
if ((flags & FNM_LEADING_DIR) && *n == L('/'))
|
||||
/* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
|
||||
return 0;
|
||||
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
|
||||
/* Parse a bracket expression collating symbol ([.sym.]) starting at P, find
|
||||
the value of the symbol, and move P past the collating symbol expression.
|
||||
The value is returned in *VP, if VP is not null. */
|
||||
static CHAR *
|
||||
PARSE_COLLSYM (p, vp)
|
||||
CHAR *p;
|
||||
INT *vp;
|
||||
{
|
||||
register int pc;
|
||||
INT val;
|
||||
|
||||
p++; /* move past the `.' */
|
||||
|
||||
for (pc = 0; p[pc]; pc++)
|
||||
if (p[pc] == L('.') && p[pc+1] == L(']'))
|
||||
break;
|
||||
val = COLLSYM (p, pc);
|
||||
if (vp)
|
||||
*vp = val;
|
||||
return (p + pc + 2);
|
||||
}
|
||||
|
||||
/* Use prototype definition here because of type promotion. */
|
||||
static CHAR *
|
||||
#if defined (PROTOTYPES)
|
||||
BRACKMATCH (CHAR *p, U_CHAR test, int flags)
|
||||
#else
|
||||
BRACKMATCH (p, test, flags)
|
||||
CHAR *p;
|
||||
U_CHAR test;
|
||||
int flags;
|
||||
#endif
|
||||
{
|
||||
register CHAR cstart, cend, c;
|
||||
register int not; /* Nonzero if the sense of the character class is inverted. */
|
||||
int brcnt, forcecoll;;
|
||||
INT pc;
|
||||
CHAR *savep;
|
||||
|
||||
test = FOLD (test);
|
||||
|
||||
savep = p;
|
||||
|
||||
/* POSIX.2 3.13.1 says that an exclamation mark (`!') shall replace the
|
||||
circumflex (`^') in its role in a `nonmatching list'. A bracket
|
||||
expression starting with an unquoted circumflex character produces
|
||||
unspecified results. This implementation treats the two identically. */
|
||||
if (not = (*p == L('!') || *p == L('^')))
|
||||
++p;
|
||||
|
||||
c = *p++;
|
||||
for (;;)
|
||||
{
|
||||
/* Initialize cstart and cend in case `-' is the last
|
||||
character of the pattern. */
|
||||
cstart = cend = c;
|
||||
forcecoll = 0;
|
||||
|
||||
/* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find
|
||||
the end of the equivalence class, move the pattern pointer past
|
||||
it, and check for equivalence. XXX - this handles only
|
||||
single-character equivalence classes, which is wrong, or at
|
||||
least incomplete. */
|
||||
if (c == L('[') && *p == L('=') && p[2] == L('=') && p[3] == L(']'))
|
||||
{
|
||||
pc = FOLD (p[1]);
|
||||
p += 4;
|
||||
if (COLLEQUIV (test, pc))
|
||||
{
|
||||
/*[*/ /* Move past the closing `]', since the first thing we do at
|
||||
the `matched:' label is back p up one. */
|
||||
p++;
|
||||
goto matched;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = *p++;
|
||||
if (c == L('\0'))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0); /*]*/
|
||||
c = FOLD (c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* POSIX.2 character class expression. See POSIX.2 2.8.3.2. */
|
||||
if (c == L('[') && *p == L(':'))
|
||||
{
|
||||
CHAR *close, *ccname;
|
||||
|
||||
pc = 0; /* make sure invalid char classes don't match. */
|
||||
/* Find end of character class name */
|
||||
for (close = p + 1; *close != '\0'; close++)
|
||||
if (*close == L(':') && *(close+1) == L(']'))
|
||||
break;
|
||||
|
||||
if (*close != L('\0'))
|
||||
{
|
||||
ccname = (CHAR *)malloc ((close - p) * sizeof (CHAR));
|
||||
if (ccname == 0)
|
||||
pc = 0;
|
||||
else
|
||||
{
|
||||
bcopy (p + 1, ccname, (close - p - 1) * sizeof (CHAR));
|
||||
*(ccname + (close - p - 1)) = L('\0');
|
||||
pc = IS_CCLASS (test, (XCHAR *)ccname);
|
||||
}
|
||||
if (pc == -1)
|
||||
pc = 0;
|
||||
else
|
||||
p = close + 2;
|
||||
|
||||
free (ccname);
|
||||
}
|
||||
|
||||
if (pc)
|
||||
{
|
||||
/*[*/ /* Move past the closing `]', since the first thing we do at
|
||||
the `matched:' label is back p up one. */
|
||||
p++;
|
||||
goto matched;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* continue the loop here, since this expression can't be
|
||||
the first part of a range expression. */
|
||||
c = *p++;
|
||||
if (c == L('\0'))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0);
|
||||
else if (c == L(']'))
|
||||
break;
|
||||
c = FOLD (c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* POSIX.2 collating symbols. See POSIX.2 2.8.3.2. Find the end of
|
||||
the symbol name, make sure it is terminated by `.]', translate
|
||||
the name to a character using the external table, and do the
|
||||
comparison. */
|
||||
if (c == L('[') && *p == L('.'))
|
||||
{
|
||||
p = PARSE_COLLSYM (p, &pc);
|
||||
/* An invalid collating symbol cannot be the first point of a
|
||||
range. If it is, we set cstart to one greater than `test',
|
||||
so any comparisons later will fail. */
|
||||
cstart = (pc == INVALID) ? test + 1 : pc;
|
||||
forcecoll = 1;
|
||||
}
|
||||
|
||||
if (!(flags & FNM_NOESCAPE) && c == L('\\'))
|
||||
{
|
||||
if (*p == '\0')
|
||||
return (CHAR *)0;
|
||||
cstart = cend = *p++;
|
||||
}
|
||||
|
||||
cstart = cend = FOLD (cstart);
|
||||
|
||||
/* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that
|
||||
is not preceded by a backslash and is not part of a bracket
|
||||
expression produces undefined results.' This implementation
|
||||
treats the `[' as just a character to be matched if there is
|
||||
not a closing `]'. */
|
||||
if (c == L('\0'))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0);
|
||||
|
||||
c = *p++;
|
||||
c = FOLD (c);
|
||||
|
||||
if ((flags & FNM_PATHNAME) && c == L('/'))
|
||||
/* [/] can never match when matching a pathname. */
|
||||
return (CHAR *)0;
|
||||
|
||||
/* This introduces a range, unless the `-' is the last
|
||||
character of the class. Find the end of the range
|
||||
and move past it. */
|
||||
if (c == L('-') && *p != L(']'))
|
||||
{
|
||||
cend = *p++;
|
||||
if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
|
||||
cend = *p++;
|
||||
if (cend == L('\0'))
|
||||
return (CHAR *)0;
|
||||
if (cend == L('[') && *p == L('.'))
|
||||
{
|
||||
p = PARSE_COLLSYM (p, &pc);
|
||||
/* An invalid collating symbol cannot be the second part of a
|
||||
range expression. If we get one, we set cend to one fewer
|
||||
than the test character to make sure the range test fails. */
|
||||
cend = (pc == INVALID) ? test - 1 : pc;
|
||||
forcecoll = 1;
|
||||
}
|
||||
cend = FOLD (cend);
|
||||
|
||||
c = *p++;
|
||||
|
||||
/* POSIX.2 2.8.3.2: ``The ending range point shall collate
|
||||
equal to or higher than the starting range point; otherwise
|
||||
the expression shall be treated as invalid.'' Note that this
|
||||
applies to only the range expression; the rest of the bracket
|
||||
expression is still checked for matches. */
|
||||
if (RANGECMP (cstart, cend, forcecoll) > 0)
|
||||
{
|
||||
if (c == L(']'))
|
||||
break;
|
||||
c = FOLD (c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (RANGECMP (test, cstart, forcecoll) >= 0 && RANGECMP (test, cend, forcecoll) <= 0)
|
||||
goto matched;
|
||||
|
||||
if (c == L(']'))
|
||||
break;
|
||||
}
|
||||
/* No match. */
|
||||
return (!not ? (CHAR *)0 : p);
|
||||
|
||||
matched:
|
||||
/* Skip the rest of the [...] that already matched. */
|
||||
c = *--p;
|
||||
brcnt = 1;
|
||||
while (brcnt > 0)
|
||||
{
|
||||
/* A `[' without a matching `]' is just another character to match. */
|
||||
if (c == L('\0'))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0);
|
||||
|
||||
c = *p++;
|
||||
if (c == L('[') && (*p == L('=') || *p == L(':') || *p == L('.')))
|
||||
brcnt++;
|
||||
else if (c == L(']'))
|
||||
brcnt--;
|
||||
else if (!(flags & FNM_NOESCAPE) && c == L('\\'))
|
||||
{
|
||||
if (*p == '\0')
|
||||
return (CHAR *)0;
|
||||
/* XXX 1003.2d11 is unclear if this is right. */
|
||||
++p;
|
||||
}
|
||||
}
|
||||
return (not ? (CHAR *)0 : p);
|
||||
}
|
||||
|
||||
#if defined (EXTENDED_GLOB)
|
||||
/* ksh-like extended pattern matching:
|
||||
|
||||
[?*+@!](pat-list)
|
||||
|
||||
where pat-list is a list of one or patterns separated by `|'. Operation
|
||||
is as follows:
|
||||
|
||||
?(patlist) match zero or one of the given patterns
|
||||
*(patlist) match zero or more of the given patterns
|
||||
+(patlist) match one or more of the given patterns
|
||||
@(patlist) match exactly one of the given patterns
|
||||
!(patlist) match anything except one of the given patterns
|
||||
*/
|
||||
|
||||
/* Scan a pattern starting at STRING and ending at END, keeping track of
|
||||
embedded () and []. If DELIM is 0, we scan until a matching `)'
|
||||
because we're scanning a `patlist'. Otherwise, we scan until we see
|
||||
DELIM. In all cases, we never scan past END. The return value is the
|
||||
first character after the matching DELIM. */
|
||||
static CHAR *
|
||||
PATSCAN (string, end, delim)
|
||||
CHAR *string, *end;
|
||||
INT delim;
|
||||
{
|
||||
int pnest, bnest, skip;
|
||||
INT cchar;
|
||||
CHAR *s, c, *bfirst;
|
||||
|
||||
pnest = bnest = skip = 0;
|
||||
cchar = 0;
|
||||
bfirst = NULL;
|
||||
|
||||
for (s = string; c = *s; s++)
|
||||
{
|
||||
if (s >= end)
|
||||
return (s);
|
||||
if (skip)
|
||||
{
|
||||
skip = 0;
|
||||
continue;
|
||||
}
|
||||
switch (c)
|
||||
{
|
||||
case L('\\'):
|
||||
skip = 1;
|
||||
break;
|
||||
|
||||
case L('\0'):
|
||||
return ((CHAR *)NULL);
|
||||
|
||||
/* `[' is not special inside a bracket expression, but it may
|
||||
introduce one of the special POSIX bracket expressions
|
||||
([.SYM.], [=c=], [: ... :]) that needs special handling. */
|
||||
case L('['):
|
||||
if (bnest == 0)
|
||||
{
|
||||
bfirst = s + 1;
|
||||
if (*bfirst == L('!') || *bfirst == L('^'))
|
||||
bfirst++;
|
||||
bnest++;
|
||||
}
|
||||
else if (s[1] == L(':') || s[1] == L('.') || s[1] == L('='))
|
||||
cchar = s[1];
|
||||
break;
|
||||
|
||||
/* `]' is not special if it's the first char (after a leading `!'
|
||||
or `^') in a bracket expression or if it's part of one of the
|
||||
special POSIX bracket expressions ([.SYM.], [=c=], [: ... :]) */
|
||||
case L(']'):
|
||||
if (bnest)
|
||||
{
|
||||
if (cchar && s[-1] == cchar)
|
||||
cchar = 0;
|
||||
else if (s != bfirst)
|
||||
{
|
||||
bnest--;
|
||||
bfirst = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case L('('):
|
||||
if (bnest == 0)
|
||||
pnest++;
|
||||
break;
|
||||
|
||||
case L(')'):
|
||||
if (bnest == 0 && pnest-- <= 0)
|
||||
return ++s;
|
||||
break;
|
||||
|
||||
case L('|'):
|
||||
if (bnest == 0 && pnest == 0 && delim == L('|'))
|
||||
return ++s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Return 0 if dequoted pattern matches S in the current locale. */
|
||||
static int
|
||||
STRCOMPARE (p, pe, s, se)
|
||||
CHAR *p, *pe, *s, *se;
|
||||
{
|
||||
int ret;
|
||||
CHAR c1, c2;
|
||||
|
||||
c1 = *pe;
|
||||
c2 = *se;
|
||||
|
||||
*pe = *se = '\0';
|
||||
#if HAVE_MULTIBYTE || defined (HAVE_STRCOLL)
|
||||
ret = STRCOLL ((XCHAR *)p, (XCHAR *)s);
|
||||
#else
|
||||
ret = STRCMP ((XCHAR *)p, (XCHAR *)s);
|
||||
#endif
|
||||
|
||||
*pe = c1;
|
||||
*se = c2;
|
||||
|
||||
return (ret == 0 ? ret : FNM_NOMATCH);
|
||||
}
|
||||
|
||||
/* Match a ksh extended pattern specifier. Return FNM_NOMATCH on failure or
|
||||
0 on success. This is handed the entire rest of the pattern and string
|
||||
the first time an extended pattern specifier is encountered, so it calls
|
||||
gmatch recursively. */
|
||||
static int
|
||||
EXTMATCH (xc, s, se, p, pe, flags)
|
||||
INT xc; /* select which operation */
|
||||
CHAR *s, *se;
|
||||
CHAR *p, *pe;
|
||||
int flags;
|
||||
{
|
||||
CHAR *prest; /* pointer to rest of pattern */
|
||||
CHAR *psub; /* pointer to sub-pattern */
|
||||
CHAR *pnext; /* pointer to next sub-pattern */
|
||||
CHAR *srest; /* pointer to rest of string */
|
||||
int m1, m2, xflags; /* xflags = flags passed to recursive matches */
|
||||
|
||||
#if DEBUG_MATCHING
|
||||
fprintf(stderr, "extmatch: xc = %c\n", xc);
|
||||
fprintf(stderr, "extmatch: s = %s; se = %s\n", s, se);
|
||||
fprintf(stderr, "extmatch: p = %s; pe = %s\n", p, pe);
|
||||
fprintf(stderr, "extmatch: flags = %d\n", flags);
|
||||
#endif
|
||||
|
||||
prest = PATSCAN (p + (*p == L('(')), pe, 0); /* ) */
|
||||
if (prest == 0)
|
||||
/* If PREST is 0, we failed to scan a valid pattern. In this
|
||||
case, we just want to compare the two as strings. */
|
||||
return (STRCOMPARE (p - 1, pe, s, se));
|
||||
|
||||
switch (xc)
|
||||
{
|
||||
case L('+'): /* match one or more occurrences */
|
||||
case L('*'): /* match zero or more occurrences */
|
||||
/* If we can get away with no matches, don't even bother. Just
|
||||
call GMATCH on the rest of the pattern and return success if
|
||||
it succeeds. */
|
||||
if (xc == L('*') && (GMATCH (s, se, prest, pe, flags) == 0))
|
||||
return 0;
|
||||
|
||||
/* OK, we have to do this the hard way. First, we make sure one of
|
||||
the subpatterns matches, then we try to match the rest of the
|
||||
string. */
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = PATSCAN (psub, pe, L('|'));
|
||||
for (srest = s; srest <= se; srest++)
|
||||
{
|
||||
/* Match this substring (S -> SREST) against this
|
||||
subpattern (psub -> pnext - 1) */
|
||||
m1 = GMATCH (s, srest, psub, pnext - 1, flags) == 0;
|
||||
/* OK, we matched a subpattern, so make sure the rest of the
|
||||
string matches the rest of the pattern. Also handle
|
||||
multiple matches of the pattern. */
|
||||
if (m1)
|
||||
{
|
||||
/* if srest > s, we are not at start of string */
|
||||
xflags = (srest > s) ? (flags & ~FNM_PERIOD) : flags;
|
||||
m2 = (GMATCH (srest, se, prest, pe, xflags) == 0) ||
|
||||
(s != srest && GMATCH (srest, se, p - 1, pe, xflags) == 0);
|
||||
}
|
||||
if (m1 && m2)
|
||||
return (0);
|
||||
}
|
||||
if (pnext == prest)
|
||||
break;
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
case L('?'): /* match zero or one of the patterns */
|
||||
case L('@'): /* match one (or more) of the patterns */
|
||||
/* If we can get away with no matches, don't even bother. Just
|
||||
call gmatch on the rest of the pattern and return success if
|
||||
it succeeds. */
|
||||
if (xc == L('?') && (GMATCH (s, se, prest, pe, flags) == 0))
|
||||
return 0;
|
||||
|
||||
/* OK, we have to do this the hard way. First, we see if one of
|
||||
the subpatterns matches, then, if it does, we try to match the
|
||||
rest of the string. */
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = PATSCAN (psub, pe, L('|'));
|
||||
srest = (prest == pe) ? se : s;
|
||||
for ( ; srest <= se; srest++)
|
||||
{
|
||||
/* if srest > s, we are not at start of string */
|
||||
xflags = (srest > s) ? (flags & ~FNM_PERIOD) : flags;
|
||||
if (GMATCH (s, srest, psub, pnext - 1, flags) == 0 &&
|
||||
GMATCH (srest, se, prest, pe, xflags) == 0)
|
||||
return (0);
|
||||
}
|
||||
if (pnext == prest)
|
||||
break;
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
case '!': /* match anything *except* one of the patterns */
|
||||
for (srest = s; srest <= se; srest++)
|
||||
{
|
||||
m1 = 0;
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = PATSCAN (psub, pe, L('|'));
|
||||
/* If one of the patterns matches, just bail immediately. */
|
||||
if (m1 = (GMATCH (s, srest, psub, pnext - 1, flags) == 0))
|
||||
break;
|
||||
if (pnext == prest)
|
||||
break;
|
||||
}
|
||||
/* if srest > s, we are not at start of string */
|
||||
xflags = (srest > s) ? (flags & ~FNM_PERIOD) : flags;
|
||||
if (m1 == 0 && GMATCH (srest, se, prest, pe, xflags) == 0)
|
||||
return (0);
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
#endif /* EXTENDED_GLOB */
|
||||
|
||||
#undef IS_CCLASS
|
||||
#undef FOLD
|
||||
#undef CHAR
|
||||
#undef U_CHAR
|
||||
#undef XCHAR
|
||||
#undef INT
|
||||
#undef INVALID
|
||||
#undef FCT
|
||||
#undef GMATCH
|
||||
#undef COLLSYM
|
||||
#undef PARSE_COLLSYM
|
||||
#undef PATSCAN
|
||||
#undef STRCOMPARE
|
||||
#undef EXTMATCH
|
||||
#undef BRACKMATCH
|
||||
#undef STRCHR
|
||||
#undef STRCOLL
|
||||
#undef STRLEN
|
||||
#undef STRCMP
|
||||
#undef COLLEQUIV
|
||||
#undef RANGECMP
|
||||
#undef L
|
||||
+21
-14
@@ -43,15 +43,21 @@
|
||||
#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
|
||||
#define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0)
|
||||
|
||||
int glob_asciirange = 0;
|
||||
|
||||
/* We use strcoll(3) for range comparisons in bracket expressions,
|
||||
even though it can have unwanted side effects in locales
|
||||
other than POSIX or US. For instance, in the de locale, [A-Z] matches
|
||||
all characters. */
|
||||
all characters. If GLOB_ASCIIRANGE is non-zero, and we're not forcing
|
||||
the use of strcoll (e.g., for explicit collating symbols), we use
|
||||
straight ordering as if in the C locale. */
|
||||
|
||||
#if defined (HAVE_STRCOLL)
|
||||
/* Helper function for collating symbol equivalence. */
|
||||
static int rangecmp (c1, c2)
|
||||
static int
|
||||
rangecmp (c1, c2, forcecoll)
|
||||
int c1, c2;
|
||||
int forcecoll;
|
||||
{
|
||||
static char s1[2] = { ' ', '\0' };
|
||||
static char s2[2] = { ' ', '\0' };
|
||||
@@ -64,6 +70,9 @@ static int rangecmp (c1, c2)
|
||||
if (c1 == c2)
|
||||
return (0);
|
||||
|
||||
if (forcecoll == 0 && glob_asciirange)
|
||||
return (c1 - c2);
|
||||
|
||||
s1[0] = c1;
|
||||
s2[0] = c2;
|
||||
|
||||
@@ -72,7 +81,7 @@ static int rangecmp (c1, c2)
|
||||
return (c1 - c2);
|
||||
}
|
||||
#else /* !HAVE_STRCOLL */
|
||||
# define rangecmp(c1, c2) ((int)(c1) - (int)(c2))
|
||||
# define rangecmp(c1, c2, f) ((int)(c1) - (int)(c2))
|
||||
#endif /* !HAVE_STRCOLL */
|
||||
|
||||
#if defined (HAVE_STRCOLL)
|
||||
@@ -80,7 +89,7 @@ static int
|
||||
collequiv (c1, c2)
|
||||
int c1, c2;
|
||||
{
|
||||
return (rangecmp (c1, c2) == 0);
|
||||
return (rangecmp (c1, c2, 1) == 0);
|
||||
}
|
||||
#else
|
||||
# define collequiv(c1, c2) ((c1) == (c2))
|
||||
@@ -221,7 +230,7 @@ is_cclass (c, name)
|
||||
#define STRCOLL(S1, S2) strcoll((S1), (S2))
|
||||
#define STRLEN(S) strlen(S)
|
||||
#define STRCMP(S1, S2) strcmp((S1), (S2))
|
||||
#define RANGECMP(C1, C2) rangecmp((C1), (C2))
|
||||
#define RANGECMP(C1, C2, F) rangecmp((C1), (C2), (F))
|
||||
#define COLLEQUIV(C1, C2) collequiv((C1), (C2))
|
||||
#define CTYPE_T enum char_class
|
||||
#define IS_CCLASS(C, S) is_cclass((C), (S))
|
||||
@@ -244,8 +253,9 @@ is_cclass (c, name)
|
||||
extern char *mbsmbchar __P((const char *));
|
||||
|
||||
static int
|
||||
rangecmp_wc (c1, c2)
|
||||
rangecmp_wc (c1, c2, forcecoll)
|
||||
wint_t c1, c2;
|
||||
int forcecoll;
|
||||
{
|
||||
static wchar_t s1[2] = { L' ', L'\0' };
|
||||
static wchar_t s2[2] = { L' ', L'\0' };
|
||||
@@ -253,6 +263,9 @@ rangecmp_wc (c1, c2)
|
||||
if (c1 == c2)
|
||||
return 0;
|
||||
|
||||
if (forcecoll == 0 && glob_asciirange && c1 <= UCHAR_MAX && c2 <= UCHAR_MAX)
|
||||
return ((int)(c1 - c2));
|
||||
|
||||
s1[0] = c1;
|
||||
s2[0] = c2;
|
||||
|
||||
@@ -263,7 +276,7 @@ static int
|
||||
collequiv_wc (c, equiv)
|
||||
wint_t c, equiv;
|
||||
{
|
||||
return (!(c - equiv));
|
||||
return (c == equiv);
|
||||
}
|
||||
|
||||
/* Helper function for collating symbol. */
|
||||
@@ -349,7 +362,7 @@ is_wcclass (wc, name)
|
||||
#define STRCOLL(S1, S2) wcscoll((S1), (S2))
|
||||
#define STRLEN(S) wcslen(S)
|
||||
#define STRCMP(S1, S2) wcscmp((S1), (S2))
|
||||
#define RANGECMP(C1, C2) rangecmp_wc((C1), (C2))
|
||||
#define RANGECMP(C1, C2, F) rangecmp_wc((C1), (C2), (F))
|
||||
#define COLLEQUIV(C1, C2) collequiv_wc((C1), (C2))
|
||||
#define CTYPE_T enum char_class
|
||||
#define IS_CCLASS(C, S) is_wcclass((C), (S))
|
||||
@@ -369,13 +382,7 @@ xstrmatch (pattern, string, flags)
|
||||
wchar_t *wpattern, *wstring;
|
||||
size_t plen, slen, mplen, mslen;
|
||||
|
||||
#if 0
|
||||
plen = strlen (pattern);
|
||||
mplen = mbstrlen (pattern);
|
||||
if (plen == mplen && strlen (string) == mbstrlen (string))
|
||||
#else
|
||||
if (mbsmbchar (string) == 0 && mbsmbchar (pattern) == 0)
|
||||
#endif
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
|
||||
if (MB_CUR_MAX == 1)
|
||||
|
||||
@@ -0,0 +1,409 @@
|
||||
/* strmatch.c -- ksh-like extended pattern matching for the shell and filename
|
||||
globbing. */
|
||||
|
||||
/* Copyright (C) 1991-2011 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h> /* for debugging */
|
||||
|
||||
#include "strmatch.h"
|
||||
#include <chartypes.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shmbutil.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* First, compile `sm_loop.c' for single-byte characters. */
|
||||
#define CHAR unsigned char
|
||||
#define U_CHAR unsigned char
|
||||
#define XCHAR char
|
||||
#define INT int
|
||||
#define L(CS) CS
|
||||
#define INVALID -1
|
||||
|
||||
#undef STREQ
|
||||
#undef STREQN
|
||||
#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
|
||||
#define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0)
|
||||
|
||||
int glob_asciirange = 0;
|
||||
|
||||
/* We use strcoll(3) for range comparisons in bracket expressions,
|
||||
even though it can have unwanted side effects in locales
|
||||
other than POSIX or US. For instance, in the de locale, [A-Z] matches
|
||||
all characters. */
|
||||
|
||||
#if defined (HAVE_STRCOLL)
|
||||
/* Helper function for collating symbol equivalence. */
|
||||
static int
|
||||
rangecmp (c1, c2, forcecoll)
|
||||
int c1, c2;
|
||||
int forcecoll;
|
||||
{
|
||||
static char s1[2] = { ' ', '\0' };
|
||||
static char s2[2] = { ' ', '\0' };
|
||||
int ret;
|
||||
|
||||
/* Eight bits only. Period. */
|
||||
c1 &= 0xFF;
|
||||
c2 &= 0xFF;
|
||||
|
||||
if (c1 == c2)
|
||||
return (0);
|
||||
|
||||
if (forcecoll == 0 && glob_asciirange)
|
||||
return (c1 - c2);
|
||||
|
||||
s1[0] = c1;
|
||||
s2[0] = c2;
|
||||
|
||||
if ((ret = strcoll (s1, s2)) != 0)
|
||||
return ret;
|
||||
return (c1 - c2);
|
||||
}
|
||||
#else /* !HAVE_STRCOLL */
|
||||
# define rangecmp(c1, c2, f) ((int)(c1) - (int)(c2))
|
||||
#endif /* !HAVE_STRCOLL */
|
||||
|
||||
#if defined (HAVE_STRCOLL)
|
||||
static int
|
||||
collequiv (c1, c2)
|
||||
int c1, c2;
|
||||
{
|
||||
return (rangecmp (c1, c2, 1) == 0);
|
||||
}
|
||||
#else
|
||||
# define collequiv(c1, c2) ((c1) == (c2))
|
||||
#endif
|
||||
|
||||
#define _COLLSYM _collsym
|
||||
#define __COLLSYM __collsym
|
||||
#define POSIXCOLL posix_collsyms
|
||||
#include "collsyms.h"
|
||||
|
||||
static int
|
||||
collsym (s, len)
|
||||
CHAR *s;
|
||||
int len;
|
||||
{
|
||||
register struct _collsym *csp;
|
||||
char *x;
|
||||
|
||||
x = (char *)s;
|
||||
for (csp = posix_collsyms; csp->name; csp++)
|
||||
{
|
||||
if (STREQN(csp->name, x, len) && csp->name[len] == '\0')
|
||||
return (csp->code);
|
||||
}
|
||||
if (len == 1)
|
||||
return s[0];
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
/* unibyte character classification */
|
||||
#if !defined (isascii) && !defined (HAVE_ISASCII)
|
||||
# define isascii(c) ((unsigned int)(c) <= 0177)
|
||||
#endif
|
||||
|
||||
enum char_class
|
||||
{
|
||||
CC_NO_CLASS = 0,
|
||||
CC_ASCII, CC_ALNUM, CC_ALPHA, CC_BLANK, CC_CNTRL, CC_DIGIT, CC_GRAPH,
|
||||
CC_LOWER, CC_PRINT, CC_PUNCT, CC_SPACE, CC_UPPER, CC_WORD, CC_XDIGIT
|
||||
};
|
||||
|
||||
static char const *const cclass_name[] =
|
||||
{
|
||||
"",
|
||||
"ascii", "alnum", "alpha", "blank", "cntrl", "digit", "graph",
|
||||
"lower", "print", "punct", "space", "upper", "word", "xdigit"
|
||||
};
|
||||
|
||||
#define N_CHAR_CLASS (sizeof(cclass_name) / sizeof (cclass_name[0]))
|
||||
|
||||
static int
|
||||
is_cclass (c, name)
|
||||
int c;
|
||||
const char *name;
|
||||
{
|
||||
enum char_class char_class = CC_NO_CLASS;
|
||||
int i, result;
|
||||
|
||||
for (i = 1; i < N_CHAR_CLASS; i++)
|
||||
{
|
||||
if (STREQ (name, cclass_name[i]))
|
||||
{
|
||||
char_class = (enum char_class)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (char_class == 0)
|
||||
return -1;
|
||||
|
||||
switch (char_class)
|
||||
{
|
||||
case CC_ASCII:
|
||||
result = isascii (c);
|
||||
break;
|
||||
case CC_ALNUM:
|
||||
result = ISALNUM (c);
|
||||
break;
|
||||
case CC_ALPHA:
|
||||
result = ISALPHA (c);
|
||||
break;
|
||||
case CC_BLANK:
|
||||
result = ISBLANK (c);
|
||||
break;
|
||||
case CC_CNTRL:
|
||||
result = ISCNTRL (c);
|
||||
break;
|
||||
case CC_DIGIT:
|
||||
result = ISDIGIT (c);
|
||||
break;
|
||||
case CC_GRAPH:
|
||||
result = ISGRAPH (c);
|
||||
break;
|
||||
case CC_LOWER:
|
||||
result = ISLOWER (c);
|
||||
break;
|
||||
case CC_PRINT:
|
||||
result = ISPRINT (c);
|
||||
break;
|
||||
case CC_PUNCT:
|
||||
result = ISPUNCT (c);
|
||||
break;
|
||||
case CC_SPACE:
|
||||
result = ISSPACE (c);
|
||||
break;
|
||||
case CC_UPPER:
|
||||
result = ISUPPER (c);
|
||||
break;
|
||||
case CC_WORD:
|
||||
result = (ISALNUM (c) || c == '_');
|
||||
break;
|
||||
case CC_XDIGIT:
|
||||
result = ISXDIGIT (c);
|
||||
break;
|
||||
default:
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Now include `sm_loop.c' for single-byte characters. */
|
||||
/* The result of FOLD is an `unsigned char' */
|
||||
# define FOLD(c) ((flags & FNM_CASEFOLD) \
|
||||
? TOLOWER ((unsigned char)c) \
|
||||
: ((unsigned char)c))
|
||||
|
||||
#define FCT internal_strmatch
|
||||
#define GMATCH gmatch
|
||||
#define COLLSYM collsym
|
||||
#define PARSE_COLLSYM parse_collsym
|
||||
#define BRACKMATCH brackmatch
|
||||
#define PATSCAN patscan
|
||||
#define STRCOMPARE strcompare
|
||||
#define EXTMATCH extmatch
|
||||
#define STRCHR(S, C) strchr((S), (C))
|
||||
#define STRCOLL(S1, S2) strcoll((S1), (S2))
|
||||
#define STRLEN(S) strlen(S)
|
||||
#define STRCMP(S1, S2) strcmp((S1), (S2))
|
||||
#define RANGECMP(C1, C2, F) rangecmp((C1), (C2), (F))
|
||||
#define COLLEQUIV(C1, C2) collequiv((C1), (C2))
|
||||
#define CTYPE_T enum char_class
|
||||
#define IS_CCLASS(C, S) is_cclass((C), (S))
|
||||
#include "sm_loop.c"
|
||||
|
||||
#if HANDLE_MULTIBYTE
|
||||
|
||||
# define CHAR wchar_t
|
||||
# define U_CHAR wint_t
|
||||
# define XCHAR wchar_t
|
||||
# define INT wint_t
|
||||
# define L(CS) L##CS
|
||||
# define INVALID WEOF
|
||||
|
||||
# undef STREQ
|
||||
# undef STREQN
|
||||
# define STREQ(s1, s2) ((wcscmp (s1, s2) == 0))
|
||||
# define STREQN(a, b, n) ((a)[0] == (b)[0] && wcsncmp(a, b, n) == 0)
|
||||
|
||||
extern char *mbsmbchar __P((const char *));
|
||||
|
||||
static int
|
||||
rangecmp_wc (c1, c2, forcecoll)
|
||||
wint_t c1, c2;
|
||||
int forcecoll;
|
||||
{
|
||||
static wchar_t s1[2] = { L' ', L'\0' };
|
||||
static wchar_t s2[2] = { L' ', L'\0' };
|
||||
|
||||
if (c1 == c2)
|
||||
return 0;
|
||||
|
||||
if (forcecoll == 0 && glob_asciirange && c1 <= UCHAR_MAX && c2 <= UCHAR_MAX)
|
||||
return ((int)(c1 - c2));
|
||||
|
||||
s1[0] = c1;
|
||||
s2[0] = c2;
|
||||
|
||||
return (wcscoll (s1, s2));
|
||||
}
|
||||
|
||||
static int
|
||||
collequiv_wc (c, equiv)
|
||||
wint_t c, equiv;
|
||||
{
|
||||
return (c == equiv);
|
||||
}
|
||||
|
||||
/* Helper function for collating symbol. */
|
||||
# define _COLLSYM _collwcsym
|
||||
# define __COLLSYM __collwcsym
|
||||
# define POSIXCOLL posix_collwcsyms
|
||||
# include "collsyms.h"
|
||||
|
||||
static wint_t
|
||||
collwcsym (s, len)
|
||||
wchar_t *s;
|
||||
int len;
|
||||
{
|
||||
register struct _collwcsym *csp;
|
||||
|
||||
for (csp = posix_collwcsyms; csp->name; csp++)
|
||||
{
|
||||
if (STREQN(csp->name, s, len) && csp->name[len] == L'\0')
|
||||
return (csp->code);
|
||||
}
|
||||
if (len == 1)
|
||||
return s[0];
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
static int
|
||||
is_wcclass (wc, name)
|
||||
wint_t wc;
|
||||
wchar_t *name;
|
||||
{
|
||||
char *mbs;
|
||||
mbstate_t state;
|
||||
size_t mbslength;
|
||||
wctype_t desc;
|
||||
int want_word;
|
||||
|
||||
if ((wctype ("ascii") == (wctype_t)0) && (wcscmp (name, L"ascii") == 0))
|
||||
{
|
||||
int c;
|
||||
|
||||
if ((c = wctob (wc)) == EOF)
|
||||
return 0;
|
||||
else
|
||||
return (c <= 0x7F);
|
||||
}
|
||||
|
||||
want_word = (wcscmp (name, L"word") == 0);
|
||||
if (want_word)
|
||||
name = L"alnum";
|
||||
|
||||
memset (&state, '\0', sizeof (mbstate_t));
|
||||
mbs = (char *) malloc (wcslen(name) * MB_CUR_MAX + 1);
|
||||
mbslength = wcsrtombs (mbs, (const wchar_t **)&name, (wcslen(name) * MB_CUR_MAX + 1), &state);
|
||||
|
||||
if (mbslength == (size_t)-1 || mbslength == (size_t)-2)
|
||||
{
|
||||
free (mbs);
|
||||
return -1;
|
||||
}
|
||||
desc = wctype (mbs);
|
||||
free (mbs);
|
||||
|
||||
if (desc == (wctype_t)0)
|
||||
return -1;
|
||||
|
||||
if (want_word)
|
||||
return (iswctype (wc, desc) || wc == L'_');
|
||||
else
|
||||
return (iswctype (wc, desc));
|
||||
}
|
||||
|
||||
/* Now include `sm_loop.c' for multibyte characters. */
|
||||
#define FOLD(c) ((flags & FNM_CASEFOLD) && iswupper (c) ? towlower (c) : (c))
|
||||
#define FCT internal_wstrmatch
|
||||
#define GMATCH gmatch_wc
|
||||
#define COLLSYM collwcsym
|
||||
#define PARSE_COLLSYM parse_collwcsym
|
||||
#define BRACKMATCH brackmatch_wc
|
||||
#define PATSCAN patscan_wc
|
||||
#define STRCOMPARE wscompare
|
||||
#define EXTMATCH extmatch_wc
|
||||
#define STRCHR(S, C) wcschr((S), (C))
|
||||
#define STRCOLL(S1, S2) wcscoll((S1), (S2))
|
||||
#define STRLEN(S) wcslen(S)
|
||||
#define STRCMP(S1, S2) wcscmp((S1), (S2))
|
||||
#define RANGECMP(C1, C2, F) rangecmp_wc((C1), (C2), (F))
|
||||
#define COLLEQUIV(C1, C2) collequiv_wc((C1), (C2))
|
||||
#define CTYPE_T enum char_class
|
||||
#define IS_CCLASS(C, S) is_wcclass((C), (S))
|
||||
#include "sm_loop.c"
|
||||
|
||||
#endif /* HAVE_MULTIBYTE */
|
||||
|
||||
int
|
||||
xstrmatch (pattern, string, flags)
|
||||
char *pattern;
|
||||
char *string;
|
||||
int flags;
|
||||
{
|
||||
#if HANDLE_MULTIBYTE
|
||||
int ret;
|
||||
size_t n;
|
||||
wchar_t *wpattern, *wstring;
|
||||
size_t plen, slen, mplen, mslen;
|
||||
|
||||
if (mbsmbchar (string) == 0 && mbsmbchar (pattern) == 0)
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
|
||||
if (MB_CUR_MAX == 1)
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
|
||||
n = xdupmbstowcs (&wpattern, NULL, pattern);
|
||||
if (n == (size_t)-1 || n == (size_t)-2)
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
|
||||
n = xdupmbstowcs (&wstring, NULL, string);
|
||||
if (n == (size_t)-1 || n == (size_t)-2)
|
||||
{
|
||||
free (wpattern);
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
}
|
||||
|
||||
ret = internal_wstrmatch (wpattern, wstring, flags);
|
||||
|
||||
free (wpattern);
|
||||
free (wstring);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
}
|
||||
+39
-3
@@ -141,6 +141,21 @@ history_filename (filename)
|
||||
return (return_val);
|
||||
}
|
||||
|
||||
static char *
|
||||
history_backupfile (filename)
|
||||
const char *filename;
|
||||
{
|
||||
char *ret;
|
||||
size_t len;
|
||||
|
||||
len = strlen (filename);
|
||||
ret = xmalloc (len + 2);
|
||||
strcpy (ret, filename);
|
||||
ret[len] = '-';
|
||||
ret[len+1] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Add the contents of FILENAME to the history list, a line at a time.
|
||||
If FILENAME is NULL, then read from ~/.history. Returns 0 if
|
||||
successful, or errno if not. */
|
||||
@@ -433,13 +448,22 @@ history_do_write (filename, nelements, overwrite)
|
||||
mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
|
||||
#endif
|
||||
output = history_filename (filename);
|
||||
bakname = (overwrite && output) ? history_backupfile (output) : 0;
|
||||
|
||||
if (output && bakname)
|
||||
rename (output, bakname);
|
||||
|
||||
file = output ? open (output, mode, 0600) : -1;
|
||||
rv = 0;
|
||||
|
||||
if (file == -1)
|
||||
{
|
||||
rv = errno;
|
||||
if (output && bakname)
|
||||
rename (bakname, output);
|
||||
FREE (output);
|
||||
return (errno);
|
||||
FREE (bakname);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
#ifdef HISTORY_USE_MMAP
|
||||
@@ -479,8 +503,11 @@ history_do_write (filename, nelements, overwrite)
|
||||
{
|
||||
mmap_error:
|
||||
rv = errno;
|
||||
FREE (output);
|
||||
close (file);
|
||||
if (output && bakname)
|
||||
rename (bakname, output);
|
||||
FREE (output);
|
||||
FREE (bakname);
|
||||
return rv;
|
||||
}
|
||||
#else
|
||||
@@ -488,8 +515,11 @@ mmap_error:
|
||||
if (buffer == 0)
|
||||
{
|
||||
rv = errno;
|
||||
FREE (output);
|
||||
close (file);
|
||||
if (output && bakname)
|
||||
rename (bakname, output);
|
||||
FREE (output);
|
||||
FREE (bakname);
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
@@ -519,7 +549,13 @@ mmap_error:
|
||||
|
||||
close (file);
|
||||
|
||||
if (rv != 0 && output && bakname)
|
||||
rename (bakname, output);
|
||||
else if (rv == 0 && bakname)
|
||||
unlink (bakname);
|
||||
|
||||
FREE (output);
|
||||
FREE (bakname);
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
+41
-12
@@ -125,14 +125,7 @@ history_filename (filename)
|
||||
home = sh_get_env_value ("HOME");
|
||||
|
||||
if (home == 0)
|
||||
{
|
||||
#if 0
|
||||
home = ".";
|
||||
home_len = 1;
|
||||
#else
|
||||
return (NULL);
|
||||
#endif
|
||||
}
|
||||
return (NULL);
|
||||
else
|
||||
home_len = strlen (home);
|
||||
|
||||
@@ -148,6 +141,21 @@ history_filename (filename)
|
||||
return (return_val);
|
||||
}
|
||||
|
||||
static char *
|
||||
history_backupfile (filename)
|
||||
const char *filename;
|
||||
{
|
||||
char *ret;
|
||||
size_t len;
|
||||
|
||||
len = strlen (filename);
|
||||
ret = xmalloc (len + 2);
|
||||
strcpy (ret, filename);
|
||||
ret[len] = '-';
|
||||
ret[len+1] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Add the contents of FILENAME to the history list, a line at a time.
|
||||
If FILENAME is NULL, then read from ~/.history. Returns 0 if
|
||||
successful, or errno if not. */
|
||||
@@ -430,7 +438,7 @@ history_do_write (filename, nelements, overwrite)
|
||||
int nelements, overwrite;
|
||||
{
|
||||
register int i;
|
||||
char *output;
|
||||
char *output, *bakname;
|
||||
int file, mode, rv;
|
||||
#ifdef HISTORY_USE_MMAP
|
||||
size_t cursize;
|
||||
@@ -440,13 +448,22 @@ history_do_write (filename, nelements, overwrite)
|
||||
mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
|
||||
#endif
|
||||
output = history_filename (filename);
|
||||
bakname = output ? history_backupfile (output) : 0;
|
||||
|
||||
if (output && bakname)
|
||||
rename (output, bakname);
|
||||
|
||||
file = output ? open (output, mode, 0600) : -1;
|
||||
rv = 0;
|
||||
|
||||
if (file == -1)
|
||||
{
|
||||
rv = errno;
|
||||
if (output && bakname)
|
||||
rename (bakname, output);
|
||||
FREE (output);
|
||||
return (errno);
|
||||
FREE (bakname);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
#ifdef HISTORY_USE_MMAP
|
||||
@@ -486,8 +503,11 @@ history_do_write (filename, nelements, overwrite)
|
||||
{
|
||||
mmap_error:
|
||||
rv = errno;
|
||||
FREE (output);
|
||||
close (file);
|
||||
if (output && bakname)
|
||||
rename (bakname, output);
|
||||
FREE (output);
|
||||
FREE (bakname);
|
||||
return rv;
|
||||
}
|
||||
#else
|
||||
@@ -495,8 +515,11 @@ mmap_error:
|
||||
if (buffer == 0)
|
||||
{
|
||||
rv = errno;
|
||||
FREE (output);
|
||||
close (file);
|
||||
if (output && bakname)
|
||||
rename (bakname, output);
|
||||
FREE (output);
|
||||
FREE (bakname);
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
@@ -526,7 +549,13 @@ mmap_error:
|
||||
|
||||
close (file);
|
||||
|
||||
if (rv != 0 && output && bakname)
|
||||
rename (bakname, output);
|
||||
else if (rv == 0 && bakname)
|
||||
unlink (bakname);
|
||||
|
||||
FREE (output);
|
||||
FREE (bakname);
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ extern int errno;
|
||||
#endif
|
||||
|
||||
int locale_utf8locale; /* unused for now */
|
||||
int locale_mb_cur_max; /* value of MB_CUR_MAX for current locale (LC_CTYPE) */
|
||||
|
||||
extern int dump_translatable_strings, dump_po_strings;
|
||||
|
||||
@@ -81,6 +82,8 @@ set_default_locale ()
|
||||
#endif /* HAVE_SETLOCALE */
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
locale_mb_cur_max = MB_CUR_MAX;
|
||||
}
|
||||
|
||||
/* Set default values for LC_CTYPE, LC_COLLATE, LC_MESSAGES, LC_NUMERIC and
|
||||
@@ -99,6 +102,7 @@ set_default_locale_vars ()
|
||||
{
|
||||
setlocale (LC_CTYPE, lc_all);
|
||||
locale_setblanks ();
|
||||
locale_mb_cur_max = MB_CUR_MAX;
|
||||
}
|
||||
# endif
|
||||
|
||||
@@ -201,6 +205,7 @@ set_locale_var (var, value)
|
||||
internal_warning(_("setlocale: LC_ALL: cannot change locale (%s): %s"), lc_all, strerror (errno));
|
||||
}
|
||||
locale_setblanks ();
|
||||
locale_mb_cur_max = MB_CUR_MAX;
|
||||
return r;
|
||||
#else
|
||||
return (1);
|
||||
@@ -215,6 +220,7 @@ set_locale_var (var, value)
|
||||
{
|
||||
x = setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE"));
|
||||
locale_setblanks ();
|
||||
locale_mb_cur_max = MB_CUR_MAX;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
@@ -346,6 +352,7 @@ reset_locale_vars ()
|
||||
# endif
|
||||
|
||||
locale_setblanks ();
|
||||
locale_mb_cur_max = MB_CUR_MAX;
|
||||
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
@@ -0,0 +1,568 @@
|
||||
/* locale.c - Miscellaneous internationalization functions. */
|
||||
|
||||
/* Copyright (C) 1996-2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_LANGINFO_CODESET
|
||||
# include <langinfo.h>
|
||||
#endif
|
||||
|
||||
#include "bashintl.h"
|
||||
#include "bashansi.h"
|
||||
#include <stdio.h>
|
||||
#include "chartypes.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "input.h" /* For bash_input */
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
int locale_utf8locale; /* unused for now */
|
||||
int locale_mb_cur_max; /* value of MB_CUR_MAX for current locale (LC_CTYPE) */
|
||||
|
||||
extern int dump_translatable_strings, dump_po_strings;
|
||||
|
||||
/* The current locale when the program begins */
|
||||
static char *default_locale;
|
||||
|
||||
/* The current domain for textdomain(3). */
|
||||
static char *default_domain;
|
||||
static char *default_dir;
|
||||
|
||||
/* tracks the value of LC_ALL; used to override values for other locale
|
||||
categories */
|
||||
static char *lc_all;
|
||||
|
||||
/* tracks the value of LC_ALL; used to provide defaults for locale
|
||||
categories */
|
||||
static char *lang;
|
||||
|
||||
/* Called to reset all of the locale variables to their appropriate values
|
||||
if (and only if) LC_ALL has not been assigned a value. */
|
||||
static int reset_locale_vars __P((void));
|
||||
|
||||
static void locale_setblanks __P((void));
|
||||
static int locale_isutf8 __P((char *));
|
||||
|
||||
/* Set the value of default_locale and make the current locale the
|
||||
system default locale. This should be called very early in main(). */
|
||||
void
|
||||
set_default_locale ()
|
||||
{
|
||||
#if defined (HAVE_SETLOCALE)
|
||||
default_locale = setlocale (LC_ALL, "");
|
||||
if (default_locale)
|
||||
default_locale = savestring (default_locale);
|
||||
#endif /* HAVE_SETLOCALE */
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
locale_mb_cur_max = MB_CUR_MAX;
|
||||
itrace("set_default_locale: locale_mb_cur_max -> %d", locale_mb_cur_max);
|
||||
}
|
||||
|
||||
/* Set default values for LC_CTYPE, LC_COLLATE, LC_MESSAGES, LC_NUMERIC and
|
||||
LC_TIME if they are not specified in the environment, but LC_ALL is. This
|
||||
should be called from main() after parsing the environment. */
|
||||
void
|
||||
set_default_locale_vars ()
|
||||
{
|
||||
char *val;
|
||||
|
||||
#if defined (HAVE_SETLOCALE)
|
||||
|
||||
# if defined (LC_CTYPE)
|
||||
val = get_string_value ("LC_CTYPE");
|
||||
if (val == 0 && lc_all && *lc_all)
|
||||
{
|
||||
setlocale (LC_CTYPE, lc_all);
|
||||
locale_setblanks ();
|
||||
locale_mb_cur_max = MB_CUR_MAX;
|
||||
itrace("set_default_locale_vars: locale_mb_cur_max -> %d", locale_mb_cur_max);
|
||||
}
|
||||
# endif
|
||||
|
||||
# if defined (LC_COLLATE)
|
||||
val = get_string_value ("LC_COLLATE");
|
||||
if (val == 0 && lc_all && *lc_all)
|
||||
setlocale (LC_COLLATE, lc_all);
|
||||
# endif /* LC_COLLATE */
|
||||
|
||||
# if defined (LC_MESSAGES)
|
||||
val = get_string_value ("LC_MESSAGES");
|
||||
if (val == 0 && lc_all && *lc_all)
|
||||
setlocale (LC_MESSAGES, lc_all);
|
||||
# endif /* LC_MESSAGES */
|
||||
|
||||
# if defined (LC_NUMERIC)
|
||||
val = get_string_value ("LC_NUMERIC");
|
||||
if (val == 0 && lc_all && *lc_all)
|
||||
setlocale (LC_NUMERIC, lc_all);
|
||||
# endif /* LC_NUMERIC */
|
||||
|
||||
# if defined (LC_TIME)
|
||||
val = get_string_value ("LC_TIME");
|
||||
if (val == 0 && lc_all && *lc_all)
|
||||
setlocale (LC_TIME, lc_all);
|
||||
# endif /* LC_TIME */
|
||||
|
||||
#endif /* HAVE_SETLOCALE */
|
||||
|
||||
val = get_string_value ("TEXTDOMAIN");
|
||||
if (val && *val)
|
||||
{
|
||||
FREE (default_domain);
|
||||
default_domain = savestring (val);
|
||||
#if 0
|
||||
/* Don't want to override the shell's textdomain as the default */
|
||||
textdomain (default_domain);
|
||||
#endif
|
||||
}
|
||||
|
||||
val = get_string_value ("TEXTDOMAINDIR");
|
||||
if (val && *val)
|
||||
{
|
||||
FREE (default_dir);
|
||||
default_dir = savestring (val);
|
||||
if (default_domain && *default_domain)
|
||||
bindtextdomain (default_domain, default_dir);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set one of the locale categories (specified by VAR) to VALUE. Returns 1
|
||||
if successful, 0 otherwise. */
|
||||
int
|
||||
set_locale_var (var, value)
|
||||
char *var, *value;
|
||||
{
|
||||
int r;
|
||||
char *x;
|
||||
|
||||
x = "";
|
||||
errno = 0;
|
||||
if (var[0] == 'T' && var[10] == 0) /* TEXTDOMAIN */
|
||||
{
|
||||
FREE (default_domain);
|
||||
default_domain = value ? savestring (value) : (char *)NULL;
|
||||
#if 0
|
||||
/* Don't want to override the shell's textdomain as the default */
|
||||
textdomain (default_domain);
|
||||
#endif
|
||||
return (1);
|
||||
}
|
||||
else if (var[0] == 'T') /* TEXTDOMAINDIR */
|
||||
{
|
||||
FREE (default_dir);
|
||||
default_dir = value ? savestring (value) : (char *)NULL;
|
||||
if (default_domain && *default_domain)
|
||||
bindtextdomain (default_domain, default_dir);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* var[0] == 'L' && var[1] == 'C' && var[2] == '_' */
|
||||
|
||||
else if (var[3] == 'A') /* LC_ALL */
|
||||
{
|
||||
FREE (lc_all);
|
||||
if (value)
|
||||
lc_all = savestring (value);
|
||||
else
|
||||
{
|
||||
lc_all = (char *)xmalloc (1);
|
||||
lc_all[0] = '\0';
|
||||
}
|
||||
#if defined (HAVE_SETLOCALE)
|
||||
r = *lc_all ? ((x = setlocale (LC_ALL, lc_all)) != 0) : reset_locale_vars ();
|
||||
if (x == 0)
|
||||
{
|
||||
if (errno == 0)
|
||||
internal_warning(_("setlocale: LC_ALL: cannot change locale (%s)"), lc_all);
|
||||
else
|
||||
internal_warning(_("setlocale: LC_ALL: cannot change locale (%s): %s"), lc_all, strerror (errno));
|
||||
}
|
||||
locale_setblanks ();
|
||||
locale_mb_cur_max = MB_CUR_MAX;
|
||||
itrace("set_locale_var: locale_mb_cur_max -> %d", locale_mb_cur_max);
|
||||
return r;
|
||||
#else
|
||||
return (1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined (HAVE_SETLOCALE)
|
||||
else if (var[3] == 'C' && var[4] == 'T') /* LC_CTYPE */
|
||||
{
|
||||
# if defined (LC_CTYPE)
|
||||
if (lc_all == 0 || *lc_all == '\0')
|
||||
{
|
||||
x = setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE"));
|
||||
locale_setblanks ();
|
||||
locale_mb_cur_max = MB_CUR_MAX;
|
||||
itrace("set_locale_var: locale_mb_cur_max -> %d", locale_mb_cur_max);
|
||||
}
|
||||
# endif
|
||||
}
|
||||
else if (var[3] == 'C' && var[4] == 'O') /* LC_COLLATE */
|
||||
{
|
||||
# if defined (LC_COLLATE)
|
||||
if (lc_all == 0 || *lc_all == '\0')
|
||||
x = setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE"));
|
||||
# endif /* LC_COLLATE */
|
||||
}
|
||||
else if (var[3] == 'M' && var[4] == 'E') /* LC_MESSAGES */
|
||||
{
|
||||
# if defined (LC_MESSAGES)
|
||||
if (lc_all == 0 || *lc_all == '\0')
|
||||
x = setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES"));
|
||||
# endif /* LC_MESSAGES */
|
||||
}
|
||||
else if (var[3] == 'N' && var[4] == 'U') /* LC_NUMERIC */
|
||||
{
|
||||
# if defined (LC_NUMERIC)
|
||||
if (lc_all == 0 || *lc_all == '\0')
|
||||
x = setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC"));
|
||||
# endif /* LC_NUMERIC */
|
||||
}
|
||||
else if (var[3] == 'T' && var[4] == 'I') /* LC_TIME */
|
||||
{
|
||||
# if defined (LC_TIME)
|
||||
if (lc_all == 0 || *lc_all == '\0')
|
||||
x = setlocale (LC_TIME, get_locale_var ("LC_TIME"));
|
||||
# endif /* LC_TIME */
|
||||
}
|
||||
#endif /* HAVE_SETLOCALE */
|
||||
|
||||
if (x == 0)
|
||||
{
|
||||
if (errno == 0)
|
||||
internal_warning(_("setlocale: %s: cannot change locale (%s)"), var, get_locale_var (var));
|
||||
else
|
||||
internal_warning(_("setlocale: %s: cannot change locale (%s): %s"), var, get_locale_var (var), strerror (errno));
|
||||
}
|
||||
|
||||
return (x != 0);
|
||||
}
|
||||
|
||||
/* Called when LANG is assigned a value. Tracks value in `lang'. Calls
|
||||
reset_locale_vars() to reset any default values if LC_ALL is unset or
|
||||
null. */
|
||||
int
|
||||
set_lang (var, value)
|
||||
char *var, *value;
|
||||
{
|
||||
FREE (lang);
|
||||
if (value)
|
||||
lang = savestring (value);
|
||||
else
|
||||
{
|
||||
lang = (char *)xmalloc (1);
|
||||
lang[0] = '\0';
|
||||
}
|
||||
|
||||
return ((lc_all == 0 || *lc_all == 0) ? reset_locale_vars () : 0);
|
||||
}
|
||||
|
||||
/* Set default values for LANG and LC_ALL. Default values for all other
|
||||
locale-related variables depend on these. */
|
||||
void
|
||||
set_default_lang ()
|
||||
{
|
||||
char *v;
|
||||
|
||||
v = get_string_value ("LC_ALL");
|
||||
set_locale_var ("LC_ALL", v);
|
||||
|
||||
v = get_string_value ("LANG");
|
||||
set_lang ("LANG", v);
|
||||
}
|
||||
|
||||
/* Get the value of one of the locale variables (LC_MESSAGES, LC_CTYPE).
|
||||
The precedence is as POSIX.2 specifies: LC_ALL has precedence over
|
||||
the specific locale variables, and LANG, if set, is used as the default. */
|
||||
char *
|
||||
get_locale_var (var)
|
||||
char *var;
|
||||
{
|
||||
char *locale;
|
||||
|
||||
locale = lc_all;
|
||||
|
||||
if (locale == 0 || *locale == 0)
|
||||
locale = get_string_value (var); /* XXX - mem leak? */
|
||||
if (locale == 0 || *locale == 0)
|
||||
locale = lang;
|
||||
if (locale == 0 || *locale == 0)
|
||||
#if 0
|
||||
locale = default_locale; /* system-dependent; not really portable. should it be "C"? */
|
||||
#else
|
||||
locale = "";
|
||||
#endif
|
||||
return (locale);
|
||||
}
|
||||
|
||||
/* Called to reset all of the locale variables to their appropriate values
|
||||
if (and only if) LC_ALL has not been assigned a value. DO NOT CALL THIS
|
||||
IF LC_ALL HAS BEEN ASSIGNED A VALUE. */
|
||||
static int
|
||||
reset_locale_vars ()
|
||||
{
|
||||
char *t;
|
||||
#if defined (HAVE_SETLOCALE)
|
||||
if (lang == 0 || *lang == '\0')
|
||||
maybe_make_export_env (); /* trust that this will change environment for setlocale */
|
||||
if (setlocale (LC_ALL, lang ? lang : "") == 0)
|
||||
return 0;
|
||||
|
||||
# if defined (LC_CTYPE)
|
||||
t = setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE"));
|
||||
# endif
|
||||
# if defined (LC_COLLATE)
|
||||
t = setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE"));
|
||||
# endif
|
||||
# if defined (LC_MESSAGES)
|
||||
t = setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES"));
|
||||
# endif
|
||||
# if defined (LC_NUMERIC)
|
||||
t = setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC"));
|
||||
# endif
|
||||
# if defined (LC_TIME)
|
||||
t = setlocale (LC_TIME, get_locale_var ("LC_TIME"));
|
||||
# endif
|
||||
|
||||
locale_setblanks ();
|
||||
locale_mb_cur_max = MB_CUR_MAX;
|
||||
itrace("reset_locale_vars: locale_mb_cur_max -> %d", locale_mb_cur_max);
|
||||
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Translate the contents of STRING, a $"..." quoted string, according
|
||||
to the current locale. In the `C' or `POSIX' locale, or if gettext()
|
||||
is not available, the passed string is returned unchanged. The
|
||||
length of the translated string is returned in LENP, if non-null. */
|
||||
char *
|
||||
localetrans (string, len, lenp)
|
||||
char *string;
|
||||
int len, *lenp;
|
||||
{
|
||||
char *locale, *t;
|
||||
char *translated;
|
||||
int tlen;
|
||||
|
||||
/* Don't try to translate null strings. */
|
||||
if (string == 0 || *string == 0)
|
||||
{
|
||||
if (lenp)
|
||||
*lenp = 0;
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
locale = get_locale_var ("LC_MESSAGES");
|
||||
|
||||
/* If we don't have setlocale() or the current locale is `C' or `POSIX',
|
||||
just return the string. If we don't have gettext(), there's no use
|
||||
doing anything else. */
|
||||
if (locale == 0 || locale[0] == '\0' ||
|
||||
(locale[0] == 'C' && locale[1] == '\0') || STREQ (locale, "POSIX"))
|
||||
{
|
||||
t = (char *)xmalloc (len + 1);
|
||||
strcpy (t, string);
|
||||
if (lenp)
|
||||
*lenp = len;
|
||||
return (t);
|
||||
}
|
||||
|
||||
/* Now try to translate it. */
|
||||
if (default_domain && *default_domain)
|
||||
translated = dgettext (default_domain, string);
|
||||
else
|
||||
translated = string;
|
||||
|
||||
if (translated == string) /* gettext returns its argument if untranslatable */
|
||||
{
|
||||
t = (char *)xmalloc (len + 1);
|
||||
strcpy (t, string);
|
||||
if (lenp)
|
||||
*lenp = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
tlen = strlen (translated);
|
||||
t = (char *)xmalloc (tlen + 1);
|
||||
strcpy (t, translated);
|
||||
if (lenp)
|
||||
*lenp = tlen;
|
||||
}
|
||||
return (t);
|
||||
}
|
||||
|
||||
/* Change a bash string into a string suitable for inclusion in a `po' file.
|
||||
This backslash-escapes `"' and `\' and changes newlines into \\\n"\n". */
|
||||
char *
|
||||
mk_msgstr (string, foundnlp)
|
||||
char *string;
|
||||
int *foundnlp;
|
||||
{
|
||||
register int c, len;
|
||||
char *result, *r, *s;
|
||||
|
||||
for (len = 0, s = string; s && *s; s++)
|
||||
{
|
||||
len++;
|
||||
if (*s == '"' || *s == '\\')
|
||||
len++;
|
||||
else if (*s == '\n')
|
||||
len += 5;
|
||||
}
|
||||
|
||||
r = result = (char *)xmalloc (len + 3);
|
||||
*r++ = '"';
|
||||
|
||||
for (s = string; s && (c = *s); s++)
|
||||
{
|
||||
if (c == '\n') /* <NL> -> \n"<NL>" */
|
||||
{
|
||||
*r++ = '\\';
|
||||
*r++ = 'n';
|
||||
*r++ = '"';
|
||||
*r++ = '\n';
|
||||
*r++ = '"';
|
||||
if (foundnlp)
|
||||
*foundnlp = 1;
|
||||
continue;
|
||||
}
|
||||
if (c == '"' || c == '\\')
|
||||
*r++ = '\\';
|
||||
*r++ = c;
|
||||
}
|
||||
|
||||
*r++ = '"';
|
||||
*r++ = '\0';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* $"..." -- Translate the portion of STRING between START and END
|
||||
according to current locale using gettext (if available) and return
|
||||
the result. The caller will take care of leaving the quotes intact.
|
||||
The string will be left without the leading `$' by the caller.
|
||||
If translation is performed, the translated string will be double-quoted
|
||||
by the caller. The length of the translated string is returned in LENP,
|
||||
if non-null. */
|
||||
char *
|
||||
localeexpand (string, start, end, lineno, lenp)
|
||||
char *string;
|
||||
int start, end, lineno, *lenp;
|
||||
{
|
||||
int len, tlen, foundnl;
|
||||
char *temp, *t, *t2;
|
||||
|
||||
temp = (char *)xmalloc (end - start + 1);
|
||||
for (tlen = 0, len = start; len < end; )
|
||||
temp[tlen++] = string[len++];
|
||||
temp[tlen] = '\0';
|
||||
|
||||
/* If we're just dumping translatable strings, don't do anything with the
|
||||
string itself, but if we're dumping in `po' file format, convert it into
|
||||
a form more palatable to gettext(3) and friends by quoting `"' and `\'
|
||||
with backslashes and converting <NL> into `\n"<NL>"'. If we find a
|
||||
newline in TEMP, we first output a `msgid ""' line and then the
|
||||
translated string; otherwise we output the `msgid' and translated
|
||||
string all on one line. */
|
||||
if (dump_translatable_strings)
|
||||
{
|
||||
if (dump_po_strings)
|
||||
{
|
||||
foundnl = 0;
|
||||
t = mk_msgstr (temp, &foundnl);
|
||||
t2 = foundnl ? "\"\"\n" : "";
|
||||
|
||||
printf ("#: %s:%d\nmsgid %s%s\nmsgstr \"\"\n",
|
||||
yy_input_name (), lineno, t2, t);
|
||||
free (t);
|
||||
}
|
||||
else
|
||||
printf ("\"%s\"\n", temp);
|
||||
|
||||
if (lenp)
|
||||
*lenp = tlen;
|
||||
return (temp);
|
||||
}
|
||||
else if (*temp)
|
||||
{
|
||||
t = localetrans (temp, tlen, &len);
|
||||
free (temp);
|
||||
if (lenp)
|
||||
*lenp = len;
|
||||
return (t);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lenp)
|
||||
*lenp = 0;
|
||||
return (temp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set every character in the <blank> character class to be a shell break
|
||||
character for the lexical analyzer when the locale changes. */
|
||||
static void
|
||||
locale_setblanks ()
|
||||
{
|
||||
int x;
|
||||
|
||||
for (x = 0; x < sh_syntabsiz; x++)
|
||||
{
|
||||
if (isblank (x))
|
||||
sh_syntaxtab[x] |= CSHBRK|CBLANK;
|
||||
else if (member (x, shell_break_chars))
|
||||
{
|
||||
sh_syntaxtab[x] |= CSHBRK;
|
||||
sh_syntaxtab[x] &= ~CBLANK;
|
||||
}
|
||||
else
|
||||
sh_syntaxtab[x] &= ~(CSHBRK|CBLANK);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
locale_isutf8 (lspec)
|
||||
char *lspec;
|
||||
{
|
||||
char *cp;
|
||||
|
||||
#if HAVE_LANGINFO_CODESET
|
||||
cp = nl_langinfo (CODESET);
|
||||
return (STREQ (cp, "UTF-8") || STREQ (cp, "utf8"));
|
||||
#else
|
||||
/* Take a shot */
|
||||
return (strstr (lspec, "UTF-8") || strstr (lspec, "utf8"));
|
||||
#endif
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
/* This file works under BSD, System V, minix, and Posix systems. It does
|
||||
not implement job control. */
|
||||
|
||||
/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2011 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -826,6 +826,8 @@ wait_for (pid)
|
||||
else
|
||||
get_tty_state ();
|
||||
}
|
||||
else if (interactive_shell == 0 && subshell_environment == 0 && check_window_size)
|
||||
get_new_window_size (0, (int *)0, (int *)0);
|
||||
|
||||
return (return_val);
|
||||
}
|
||||
|
||||
@@ -801,13 +801,17 @@ wait_for (pid)
|
||||
return_val = process_exit_status (status);
|
||||
last_command_exit_signal = get_termsig (status);
|
||||
|
||||
#if !defined (DONT_REPORT_SIGPIPE)
|
||||
if ((WIFSTOPPED (status) == 0) && WIFSIGNALED (status) &&
|
||||
(WTERMSIG (status) != SIGINT))
|
||||
#if defined (DONT_REPORT_SIGPIPE) && defined (DONT_REPORT_SIGTERM)
|
||||
# define REPORTSIG(x) ((x) != SIGINT && (x) != SIGPIPE && (x) != SIGTERM)
|
||||
#elif !defined (DONT_REPORT_SIGPIPE) && !defined (DONT_REPORT_SIGTERM)
|
||||
# define REPORTSIG(x) ((x) != SIGINT)
|
||||
#elif defined (DONT_REPORT_SIGPIPE)
|
||||
# define REPORTSIG(x) ((x) != SIGINT && (x) != SIGPIPE)
|
||||
#else
|
||||
if ((WIFSTOPPED (status) == 0) && WIFSIGNALED (status) &&
|
||||
(WTERMSIG (status) != SIGINT) && (WTERMSIG (status) != SIGPIPE))
|
||||
#endif
|
||||
# define REPORTSIG(x) ((x) != SIGINT && (x) != SIGTERM)
|
||||
#endiof
|
||||
|
||||
if ((WIFSTOPPED (status) == 0) && WIFSIGNALED (status) && REPORTSIG(WTERMSIG (status)))
|
||||
{
|
||||
fprintf (stderr, "%s", j_strsignal (WTERMSIG (status)));
|
||||
if (WIFCORED (status))
|
||||
@@ -822,6 +826,8 @@ wait_for (pid)
|
||||
else
|
||||
get_tty_state ();
|
||||
}
|
||||
else if (interactive_shell == 0 && subshell_environment == 0 && check_window_size)
|
||||
get_new_window_size (0, (int *)0, (int *)0);
|
||||
|
||||
return (return_val);
|
||||
}
|
||||
|
||||
@@ -3848,6 +3848,7 @@ xparse_dolparen (base, string, indp, flags)
|
||||
int flags;
|
||||
{
|
||||
sh_parser_state_t ps;
|
||||
sh_input_line_state_t ls;
|
||||
int orig_ind, nc, sflags;
|
||||
char *ret, *s, *ep, *ostring;
|
||||
|
||||
@@ -3855,10 +3856,12 @@ xparse_dolparen (base, string, indp, flags)
|
||||
orig_ind = *indp;
|
||||
ostring = string;
|
||||
|
||||
/*itrace("xparse_dolparen: size = %d shell_input_line = `%s'", shell_input_line_size, shell_input_line);*/
|
||||
sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE;
|
||||
if (flags & SX_NOLONGJMP)
|
||||
sflags |= SEVAL_NOLONGJMP;
|
||||
save_parser_state (&ps);
|
||||
save_input_line_state (&ls);
|
||||
|
||||
/*(*/
|
||||
parser_state |= PST_CMDSUBST|PST_EOFTOKEN; /* allow instant ')' */ /*(*/
|
||||
@@ -3867,6 +3870,8 @@ xparse_dolparen (base, string, indp, flags)
|
||||
|
||||
restore_parser_state (&ps);
|
||||
reset_parser ();
|
||||
/* reset_parser clears shell_input_line and associated variables */
|
||||
restore_input_line_state (&ls);
|
||||
if (interactive)
|
||||
token_to_read = 0;
|
||||
|
||||
@@ -5914,6 +5919,12 @@ save_parser_state (ps)
|
||||
ps->expand_aliases = expand_aliases;
|
||||
ps->echo_input_at_read = echo_input_at_read;
|
||||
|
||||
ps->token = token;
|
||||
ps->token_buffer_size = token_buffer_size;
|
||||
/* Force reallocation on next call to read_token_word */
|
||||
token = 0;
|
||||
token_buffer_size = 0;
|
||||
|
||||
return (ps);
|
||||
}
|
||||
|
||||
@@ -5955,6 +5966,42 @@ restore_parser_state (ps)
|
||||
|
||||
expand_aliases = ps->expand_aliases;
|
||||
echo_input_at_read = ps->echo_input_at_read;
|
||||
|
||||
FREE (token);
|
||||
token = ps->token;
|
||||
token_buffer_size = ps->token_buffer_size;
|
||||
}
|
||||
|
||||
sh_input_line_state_t *
|
||||
save_input_line_state (ls)
|
||||
sh_input_line_state_t *ls;
|
||||
{
|
||||
if (ls == 0)
|
||||
ls = (sh_input_line_state_t *)xmalloc (sizeof (sh_input_line_state_t));
|
||||
if (ls == 0)
|
||||
return ((sh_input_line_state_t *)NULL);
|
||||
|
||||
ls->input_line = shell_input_line;
|
||||
ls->input_line_size = shell_input_line_size;
|
||||
ls->input_line_len = shell_input_line_len;
|
||||
ls->input_line_index = shell_input_line_index;
|
||||
|
||||
/* force reallocation */
|
||||
shell_input_line = 0;
|
||||
shell_input_line_size = shell_input_line_len = shell_input_line_index = 0;
|
||||
}
|
||||
|
||||
void
|
||||
restore_input_line_state (ls)
|
||||
sh_input_line_state_t *ls;
|
||||
{
|
||||
FREE (shell_input_line);
|
||||
shell_input_line = ls->input_line;
|
||||
shell_input_line_size = ls->input_line_size;
|
||||
shell_input_line_len = ls->input_line_len;
|
||||
shell_input_line_index = ls->input_line_index;
|
||||
|
||||
set_line_mbstate ();
|
||||
}
|
||||
|
||||
/************************************************
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
*** ../bash-4.2-patched/parse.y 2011-02-26 19:19:05.000000000 -0500
|
||||
--- parse.y 2011-06-24 20:08:22.000000000 -0400
|
||||
***************
|
||||
*** 3843,3846 ****
|
||||
--- 3849,3853 ----
|
||||
{
|
||||
sh_parser_state_t ps;
|
||||
+ sh_input_line_state_t ls;
|
||||
int orig_ind, nc, sflags;
|
||||
char *ret, *s, *ep, *ostring;
|
||||
***************
|
||||
*** 3850,3857 ****
|
||||
--- 3857,3866 ----
|
||||
ostring = string;
|
||||
|
||||
+ /*itrace("xparse_dolparen: size = %d shell_input_line = `%s'", shell_input_line_size, shell_input_line);*/
|
||||
sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE;
|
||||
if (flags & SX_NOLONGJMP)
|
||||
sflags |= SEVAL_NOLONGJMP;
|
||||
save_parser_state (&ps);
|
||||
+ save_input_line_state (&ls);
|
||||
|
||||
/*(*/
|
||||
***************
|
||||
*** 3862,3865 ****
|
||||
--- 3871,3876 ----
|
||||
restore_parser_state (&ps);
|
||||
reset_parser ();
|
||||
+ /* reset_parser clears shell_input_line and associated variables */
|
||||
+ restore_input_line_state (&ls);
|
||||
if (interactive)
|
||||
token_to_read = 0;
|
||||
***************
|
||||
*** 5909,5912 ****
|
||||
--- 5920,5929 ----
|
||||
ps->echo_input_at_read = echo_input_at_read;
|
||||
|
||||
+ ps->token = token;
|
||||
+ ps->token_buffer_size = token_buffer_size;
|
||||
+ /* Force reallocation on next call to read_token_word */
|
||||
+ token = 0;
|
||||
+ token_buffer_size = 0;
|
||||
+
|
||||
return (ps);
|
||||
}
|
||||
***************
|
||||
*** 5950,5953 ****
|
||||
--- 5967,6006 ----
|
||||
expand_aliases = ps->expand_aliases;
|
||||
echo_input_at_read = ps->echo_input_at_read;
|
||||
+
|
||||
+ FREE (token);
|
||||
+ token = ps->token;
|
||||
+ token_buffer_size = ps->token_buffer_size;
|
||||
+ }
|
||||
+
|
||||
+ sh_input_line_state_t *
|
||||
+ save_input_line_state (ls)
|
||||
+ sh_input_line_state_t *ls;
|
||||
+ {
|
||||
+ if (ls == 0)
|
||||
+ ls = (sh_input_line_state_t *)xmalloc (sizeof (sh_input_line_state_t));
|
||||
+ if (ls == 0)
|
||||
+ return ((sh_input_line_state_t *)NULL);
|
||||
+
|
||||
+ ls->input_line = shell_input_line;
|
||||
+ ls->input_line_size = shell_input_line_size;
|
||||
+ ls->input_line_len = shell_input_line_len;
|
||||
+ ls->input_line_index = shell_input_line_index;
|
||||
+
|
||||
+ /* force reallocation */
|
||||
+ shell_input_line = 0;
|
||||
+ shell_input_line_size = shell_input_line_len = shell_input_line_index = 0;
|
||||
+ }
|
||||
+
|
||||
+ void
|
||||
+ restore_input_line_state (ls)
|
||||
+ sh_input_line_state_t *ls;
|
||||
+ {
|
||||
+ FREE (shell_input_line);
|
||||
+ shell_input_line = ls->input_line;
|
||||
+ shell_input_line_size = ls->input_line_size;
|
||||
+ shell_input_line_len = ls->input_line_len;
|
||||
+ shell_input_line_index = ls->input_line_index;
|
||||
+
|
||||
+ set_line_mbstate ();
|
||||
}
|
||||
|
||||
+312
@@ -0,0 +1,312 @@
|
||||
*** ../bash-4.2-patched/parse.y 2011-02-26 19:19:05.000000000 -0500
|
||||
--- parse.y 2011-06-24 20:08:22.000000000 -0400
|
||||
***************
|
||||
*** 1439,1448 ****
|
||||
old_sigint = (SigHandler *)set_signal_handler (SIGINT, sigint_sighandler);
|
||||
}
|
||||
- terminate_immediately = 1;
|
||||
|
||||
current_readline_line = readline (current_readline_prompt ?
|
||||
current_readline_prompt : "");
|
||||
|
||||
! terminate_immediately = 0;
|
||||
if (signal_is_ignored (SIGINT) == 0)
|
||||
{
|
||||
--- 1439,1447 ----
|
||||
old_sigint = (SigHandler *)set_signal_handler (SIGINT, sigint_sighandler);
|
||||
}
|
||||
|
||||
current_readline_line = readline (current_readline_prompt ?
|
||||
current_readline_prompt : "");
|
||||
|
||||
! CHECK_TERMSIG;
|
||||
if (signal_is_ignored (SIGINT) == 0)
|
||||
{
|
||||
***************
|
||||
*** 1604,1617 ****
|
||||
{
|
||||
if (interactive)
|
||||
! {
|
||||
! interrupt_immediately++;
|
||||
! terminate_immediately++;
|
||||
! }
|
||||
result = getc_with_restart (bash_input.location.file);
|
||||
if (interactive)
|
||||
! {
|
||||
! interrupt_immediately--;
|
||||
! terminate_immediately--;
|
||||
! }
|
||||
}
|
||||
return (result);
|
||||
--- 1603,1615 ----
|
||||
{
|
||||
if (interactive)
|
||||
! interrupt_immediately++;
|
||||
!
|
||||
! /* XXX - don't need terminate_immediately; getc_with_restart checks
|
||||
! for terminating signals itself if read returns < 0 */
|
||||
result = getc_with_restart (bash_input.location.file);
|
||||
+
|
||||
if (interactive)
|
||||
! interrupt_immediately--;
|
||||
!
|
||||
}
|
||||
return (result);
|
||||
***************
|
||||
*** 3211,3215 ****
|
||||
--- 3209,3217 ----
|
||||
|
||||
RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
|
||||
+ #if 0
|
||||
if MBTEST(ch == CTLESC || ch == CTLNUL)
|
||||
+ #else
|
||||
+ if MBTEST(ch == CTLESC)
|
||||
+ #endif
|
||||
ret[retind++] = CTLESC;
|
||||
ret[retind++] = ch;
|
||||
***************
|
||||
*** 3530,3534 ****
|
||||
--- 3532,3540 ----
|
||||
|
||||
RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
|
||||
+ #if 0
|
||||
if MBTEST(ch == CTLESC || ch == CTLNUL)
|
||||
+ #else
|
||||
+ if MBTEST(ch == CTLESC)
|
||||
+ #endif
|
||||
ret[retind++] = CTLESC;
|
||||
ret[retind++] = ch;
|
||||
***************
|
||||
*** 3843,3846 ****
|
||||
--- 3849,3853 ----
|
||||
{
|
||||
sh_parser_state_t ps;
|
||||
+ sh_input_line_state_t ls;
|
||||
int orig_ind, nc, sflags;
|
||||
char *ret, *s, *ep, *ostring;
|
||||
***************
|
||||
*** 3850,3857 ****
|
||||
--- 3857,3866 ----
|
||||
ostring = string;
|
||||
|
||||
+ /*itrace("xparse_dolparen: size = %d shell_input_line = `%s'", shell_input_line_size, shell_input_line);*/
|
||||
sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE;
|
||||
if (flags & SX_NOLONGJMP)
|
||||
sflags |= SEVAL_NOLONGJMP;
|
||||
save_parser_state (&ps);
|
||||
+ save_input_line_state (&ls);
|
||||
|
||||
/*(*/
|
||||
***************
|
||||
*** 3862,3865 ****
|
||||
--- 3871,3876 ----
|
||||
restore_parser_state (&ps);
|
||||
reset_parser ();
|
||||
+ /* reset_parser clears shell_input_line and associated variables */
|
||||
+ restore_input_line_state (&ls);
|
||||
if (interactive)
|
||||
token_to_read = 0;
|
||||
***************
|
||||
*** 4432,4436 ****
|
||||
if (ttok == &matched_pair_error)
|
||||
return -1; /* Bail immediately. */
|
||||
! RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
--- 4443,4447 ----
|
||||
if (ttok == &matched_pair_error)
|
||||
return -1; /* Bail immediately. */
|
||||
! RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
***************
|
||||
*** 4454,4458 ****
|
||||
peek_char = shell_getc (1);
|
||||
/* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */
|
||||
! if MBTEST(peek_char == '(' || \
|
||||
((peek_char == '{' || peek_char == '[') && character == '$')) /* ) ] } */
|
||||
{
|
||||
--- 4465,4469 ----
|
||||
peek_char = shell_getc (1);
|
||||
/* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */
|
||||
! if MBTEST(peek_char == '(' ||
|
||||
((peek_char == '{' || peek_char == '[') && character == '$')) /* ) ] } */
|
||||
{
|
||||
***************
|
||||
*** 4474,4478 ****
|
||||
if (ttok == &matched_pair_error)
|
||||
return -1; /* Bail immediately. */
|
||||
! RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
--- 4485,4489 ----
|
||||
if (ttok == &matched_pair_error)
|
||||
return -1; /* Bail immediately. */
|
||||
! RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
***************
|
||||
*** 4525,4529 ****
|
||||
}
|
||||
|
||||
! RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 2,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
--- 4536,4540 ----
|
||||
}
|
||||
|
||||
! RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 1,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
***************
|
||||
*** 4539,4553 ****
|
||||
else if MBTEST(character == '$' && peek_char == '$')
|
||||
{
|
||||
- ttok = (char *)xmalloc (3);
|
||||
- ttok[0] = ttok[1] = '$';
|
||||
- ttok[2] = '\0';
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, 3,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
! strcpy (token + token_index, ttok);
|
||||
! token_index += 2;
|
||||
dollar_present = 1;
|
||||
all_digit_token = 0;
|
||||
- FREE (ttok);
|
||||
goto next_character;
|
||||
}
|
||||
--- 4550,4560 ----
|
||||
else if MBTEST(character == '$' && peek_char == '$')
|
||||
{
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, 3,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
! token[token_index++] = '$';
|
||||
! token[token_index++] = peek_char;
|
||||
dollar_present = 1;
|
||||
all_digit_token = 0;
|
||||
goto next_character;
|
||||
}
|
||||
***************
|
||||
*** 4619,4637 ****
|
||||
}
|
||||
|
||||
! got_character:
|
||||
|
||||
if (character == CTLESC || character == CTLNUL)
|
||||
! token[token_index++] = CTLESC;
|
||||
|
||||
! got_escaped_character:
|
||||
|
||||
all_digit_token &= DIGIT (character);
|
||||
dollar_present |= character == '$';
|
||||
|
||||
- token[token_index++] = character;
|
||||
-
|
||||
- RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size,
|
||||
- TOKEN_DEFAULT_GROW_SIZE);
|
||||
-
|
||||
next_character:
|
||||
if (character == '\n' && SHOULD_PROMPT ())
|
||||
--- 4626,4647 ----
|
||||
}
|
||||
|
||||
! got_character:
|
||||
|
||||
if (character == CTLESC || character == CTLNUL)
|
||||
! {
|
||||
! RESIZE_MALLOCED_BUFFER (token, token_index, 2, token_buffer_size,
|
||||
! TOKEN_DEFAULT_GROW_SIZE);
|
||||
! token[token_index++] = CTLESC;
|
||||
! }
|
||||
! else
|
||||
! got_escaped_character:
|
||||
! RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size,
|
||||
! TOKEN_DEFAULT_GROW_SIZE);
|
||||
|
||||
! token[token_index++] = character;
|
||||
|
||||
all_digit_token &= DIGIT (character);
|
||||
dollar_present |= character == '$';
|
||||
|
||||
next_character:
|
||||
if (character == '\n' && SHOULD_PROMPT ())
|
||||
***************
|
||||
*** 4647,4650 ****
|
||||
--- 4657,4661 ----
|
||||
got_token:
|
||||
|
||||
+ /* Calls to RESIZE_MALLOCED_BUFFER ensure there is sufficient room. */
|
||||
token[token_index] = '\0';
|
||||
|
||||
***************
|
||||
*** 4653,4658 ****
|
||||
a '>' or '<', then, and ONLY then, is this input token a NUMBER.
|
||||
Otherwise, it is just a word, and should be returned as such. */
|
||||
! if MBTEST(all_digit_token && (character == '<' || character == '>' || \
|
||||
! last_read_token == LESS_AND || \
|
||||
last_read_token == GREATER_AND))
|
||||
{
|
||||
--- 4664,4669 ----
|
||||
a '>' or '<', then, and ONLY then, is this input token a NUMBER.
|
||||
Otherwise, it is just a word, and should be returned as such. */
|
||||
! if MBTEST(all_digit_token && (character == '<' || character == '>' ||
|
||||
! last_read_token == LESS_AND ||
|
||||
last_read_token == GREATER_AND))
|
||||
{
|
||||
***************
|
||||
*** 5909,5912 ****
|
||||
--- 5920,5929 ----
|
||||
ps->echo_input_at_read = echo_input_at_read;
|
||||
|
||||
+ ps->token = token;
|
||||
+ ps->token_buffer_size = token_buffer_size;
|
||||
+ /* Force reallocation on next call to read_token_word */
|
||||
+ token = 0;
|
||||
+ token_buffer_size = 0;
|
||||
+
|
||||
return (ps);
|
||||
}
|
||||
***************
|
||||
*** 5950,5953 ****
|
||||
--- 5967,6006 ----
|
||||
expand_aliases = ps->expand_aliases;
|
||||
echo_input_at_read = ps->echo_input_at_read;
|
||||
+
|
||||
+ FREE (token);
|
||||
+ token = ps->token;
|
||||
+ token_buffer_size = ps->token_buffer_size;
|
||||
+ }
|
||||
+
|
||||
+ sh_input_line_state_t *
|
||||
+ save_input_line_state (ls)
|
||||
+ sh_input_line_state_t *ls;
|
||||
+ {
|
||||
+ if (ls == 0)
|
||||
+ ls = (sh_input_line_state_t *)xmalloc (sizeof (sh_input_line_state_t));
|
||||
+ if (ls == 0)
|
||||
+ return ((sh_input_line_state_t *)NULL);
|
||||
+
|
||||
+ ls->input_line = shell_input_line;
|
||||
+ ls->input_line_size = shell_input_line_size;
|
||||
+ ls->input_line_len = shell_input_line_len;
|
||||
+ ls->input_line_index = shell_input_line_index;
|
||||
+
|
||||
+ /* force reallocation */
|
||||
+ shell_input_line = 0;
|
||||
+ shell_input_line_size = shell_input_line_len = shell_input_line_index = 0;
|
||||
+ }
|
||||
+
|
||||
+ void
|
||||
+ restore_input_line_state (ls)
|
||||
+ sh_input_line_state_t *ls;
|
||||
+ {
|
||||
+ FREE (shell_input_line);
|
||||
+ shell_input_line = ls->input_line;
|
||||
+ shell_input_line_size = ls->input_line_size;
|
||||
+ shell_input_line_len = ls->input_line_len;
|
||||
+ shell_input_line_index = ls->input_line_index;
|
||||
+
|
||||
+ set_line_mbstate ();
|
||||
}
|
||||
|
||||
@@ -1438,12 +1438,11 @@ yy_readline_get ()
|
||||
interrupt_immediately++;
|
||||
old_sigint = (SigHandler *)set_signal_handler (SIGINT, sigint_sighandler);
|
||||
}
|
||||
terminate_immediately = 1;
|
||||
|
||||
current_readline_line = readline (current_readline_prompt ?
|
||||
current_readline_prompt : "");
|
||||
|
||||
terminate_immediately = 0;
|
||||
CHECK_TERMSIG;
|
||||
if (signal_is_ignored (SIGINT) == 0)
|
||||
{
|
||||
interrupt_immediately--;
|
||||
@@ -1603,16 +1602,15 @@ yy_stream_get ()
|
||||
if (bash_input.location.file)
|
||||
{
|
||||
if (interactive)
|
||||
{
|
||||
interrupt_immediately++;
|
||||
terminate_immediately++;
|
||||
}
|
||||
interrupt_immediately++;
|
||||
|
||||
/* XXX - don't need terminate_immediately; getc_with_restart checks
|
||||
for terminating signals itself if read returns < 0 */
|
||||
result = getc_with_restart (bash_input.location.file);
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
interrupt_immediately--;
|
||||
terminate_immediately--;
|
||||
}
|
||||
interrupt_immediately--;
|
||||
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
@@ -3210,7 +3208,11 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
||||
}
|
||||
|
||||
RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
|
||||
#if 0
|
||||
if MBTEST(ch == CTLESC || ch == CTLNUL)
|
||||
#else
|
||||
if MBTEST(ch == CTLESC)
|
||||
#endif
|
||||
ret[retind++] = CTLESC;
|
||||
ret[retind++] = ch;
|
||||
continue;
|
||||
@@ -3529,7 +3531,11 @@ eof_error:
|
||||
}
|
||||
|
||||
RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
|
||||
#if 0
|
||||
if MBTEST(ch == CTLESC || ch == CTLNUL)
|
||||
#else
|
||||
if MBTEST(ch == CTLESC)
|
||||
#endif
|
||||
ret[retind++] = CTLESC;
|
||||
ret[retind++] = ch;
|
||||
continue;
|
||||
@@ -3842,6 +3848,7 @@ xparse_dolparen (base, string, indp, flags)
|
||||
int flags;
|
||||
{
|
||||
sh_parser_state_t ps;
|
||||
sh_input_line_state_t ls;
|
||||
int orig_ind, nc, sflags;
|
||||
char *ret, *s, *ep, *ostring;
|
||||
|
||||
@@ -3849,10 +3856,12 @@ xparse_dolparen (base, string, indp, flags)
|
||||
orig_ind = *indp;
|
||||
ostring = string;
|
||||
|
||||
/*itrace("xparse_dolparen: size = %d shell_input_line = `%s'", shell_input_line_size, shell_input_line);*/
|
||||
sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE;
|
||||
if (flags & SX_NOLONGJMP)
|
||||
sflags |= SEVAL_NOLONGJMP;
|
||||
save_parser_state (&ps);
|
||||
save_input_line_state (&ls);
|
||||
|
||||
/*(*/
|
||||
parser_state |= PST_CMDSUBST|PST_EOFTOKEN; /* allow instant ')' */ /*(*/
|
||||
@@ -3861,6 +3870,8 @@ xparse_dolparen (base, string, indp, flags)
|
||||
|
||||
restore_parser_state (&ps);
|
||||
reset_parser ();
|
||||
/* reset_parser clears shell_input_line and associated variables */
|
||||
restore_input_line_state (&ls);
|
||||
if (interactive)
|
||||
token_to_read = 0;
|
||||
|
||||
@@ -4431,7 +4442,7 @@ read_token_word (character)
|
||||
pop_delimiter (dstack);
|
||||
if (ttok == &matched_pair_error)
|
||||
return -1; /* Bail immediately. */
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
token[token_index++] = character;
|
||||
@@ -4453,7 +4464,7 @@ read_token_word (character)
|
||||
{
|
||||
peek_char = shell_getc (1);
|
||||
/* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */
|
||||
if MBTEST(peek_char == '(' || \
|
||||
if MBTEST(peek_char == '(' ||
|
||||
((peek_char == '{' || peek_char == '[') && character == '$')) /* ) ] } */
|
||||
{
|
||||
if (peek_char == '{') /* } */
|
||||
@@ -4473,7 +4484,7 @@ read_token_word (character)
|
||||
ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0);
|
||||
if (ttok == &matched_pair_error)
|
||||
return -1; /* Bail immediately. */
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 3,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
token[token_index++] = character;
|
||||
@@ -4524,7 +4535,7 @@ read_token_word (character)
|
||||
ttrans = ttok;
|
||||
}
|
||||
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 2,
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 1,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
strcpy (token + token_index, ttrans);
|
||||
@@ -4538,17 +4549,13 @@ read_token_word (character)
|
||||
shell's single-character parameter expansions, and set flags.*/
|
||||
else if MBTEST(character == '$' && peek_char == '$')
|
||||
{
|
||||
ttok = (char *)xmalloc (3);
|
||||
ttok[0] = ttok[1] = '$';
|
||||
ttok[2] = '\0';
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, 3,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
strcpy (token + token_index, ttok);
|
||||
token_index += 2;
|
||||
token[token_index++] = '$';
|
||||
token[token_index++] = peek_char;
|
||||
dollar_present = 1;
|
||||
all_digit_token = 0;
|
||||
FREE (ttok);
|
||||
goto next_character;
|
||||
}
|
||||
else
|
||||
@@ -4618,20 +4625,23 @@ read_token_word (character)
|
||||
goto got_token;
|
||||
}
|
||||
|
||||
got_character:
|
||||
got_character:
|
||||
|
||||
if (character == CTLESC || character == CTLNUL)
|
||||
token[token_index++] = CTLESC;
|
||||
|
||||
got_escaped_character:
|
||||
|
||||
all_digit_token &= DIGIT (character);
|
||||
dollar_present |= character == '$';
|
||||
{
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, 2, token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
token[token_index++] = CTLESC;
|
||||
}
|
||||
else
|
||||
got_escaped_character:
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
|
||||
token[token_index++] = character;
|
||||
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
all_digit_token &= DIGIT (character);
|
||||
dollar_present |= character == '$';
|
||||
|
||||
next_character:
|
||||
if (character == '\n' && SHOULD_PROMPT ())
|
||||
@@ -4646,14 +4656,15 @@ read_token_word (character)
|
||||
|
||||
got_token:
|
||||
|
||||
/* Calls to RESIZE_MALLOCED_BUFFER ensure there is sufficient room. */
|
||||
token[token_index] = '\0';
|
||||
|
||||
/* Check to see what thing we should return. If the last_read_token
|
||||
is a `<', or a `&', or the character which ended this token is
|
||||
a '>' or '<', then, and ONLY then, is this input token a NUMBER.
|
||||
Otherwise, it is just a word, and should be returned as such. */
|
||||
if MBTEST(all_digit_token && (character == '<' || character == '>' || \
|
||||
last_read_token == LESS_AND || \
|
||||
if MBTEST(all_digit_token && (character == '<' || character == '>' ||
|
||||
last_read_token == LESS_AND ||
|
||||
last_read_token == GREATER_AND))
|
||||
{
|
||||
if (legal_number (token, &lvalue) && (int)lvalue == lvalue)
|
||||
@@ -5136,8 +5147,7 @@ decode_prompt_string (string)
|
||||
/* Make the current time/date into a string. */
|
||||
(void) time (&the_time);
|
||||
#if defined (HAVE_TZSET)
|
||||
if (chkexport ("TZ"))
|
||||
sv_tz ("TZ"); /* XXX -- just make sure */
|
||||
sv_tz ("TZ"); /* XXX -- just make sure */
|
||||
#endif
|
||||
tm = localtime (&the_time);
|
||||
|
||||
@@ -5909,6 +5919,12 @@ save_parser_state (ps)
|
||||
ps->expand_aliases = expand_aliases;
|
||||
ps->echo_input_at_read = echo_input_at_read;
|
||||
|
||||
ps->token = token;
|
||||
ps->token_buffer_size = token_buffer_size;
|
||||
/* Force reallocation on next call to read_token_word */
|
||||
token = 0;
|
||||
token_buffer_size = 0;
|
||||
|
||||
return (ps);
|
||||
}
|
||||
|
||||
@@ -5950,6 +5966,42 @@ restore_parser_state (ps)
|
||||
|
||||
expand_aliases = ps->expand_aliases;
|
||||
echo_input_at_read = ps->echo_input_at_read;
|
||||
|
||||
FREE (token);
|
||||
token = ps->token;
|
||||
token_buffer_size = ps->token_buffer_size;
|
||||
}
|
||||
|
||||
sh_input_line_state_t *
|
||||
save_input_line_state (ls)
|
||||
sh_input_line_state_t *ls;
|
||||
{
|
||||
if (ls == 0)
|
||||
ls = (sh_input_line_state_t *)xmalloc (sizeof (sh_input_line_state_t));
|
||||
if (ls == 0)
|
||||
return ((sh_input_line_state_t *)NULL);
|
||||
|
||||
ls->input_line = shell_input_line;
|
||||
ls->input_line_size = shell_input_line_size;
|
||||
ls->input_line_len = shell_input_line_len;
|
||||
ls->input_line_index = shell_input_line_index;
|
||||
|
||||
/* force reallocation */
|
||||
shell_input_line = 0;
|
||||
shell_input_line_size = shell_input_line_len = shell_input_line_index = 0;
|
||||
}
|
||||
|
||||
void
|
||||
restore_input_line_state (ls)
|
||||
sh_input_line_state_t *ls;
|
||||
{
|
||||
FREE (shell_input_line);
|
||||
shell_input_line = ls->input_line;
|
||||
shell_input_line_size = ls->input_line_size;
|
||||
shell_input_line_len = ls->input_line_len;
|
||||
shell_input_line_index = ls->input_line_index;
|
||||
|
||||
set_line_mbstate ();
|
||||
}
|
||||
|
||||
/************************************************
|
||||
|
||||
@@ -96,6 +96,8 @@ extern int startup_state;
|
||||
extern int subshell_environment;
|
||||
extern int shell_compatibility_level;
|
||||
|
||||
extern int locale_mb_cur_max;
|
||||
|
||||
/* Structure to pass around that holds a bitmap of file descriptors
|
||||
to close, and the size of that structure. Used in execute_cmd.c. */
|
||||
struct fd_bitmap {
|
||||
@@ -136,6 +138,9 @@ typedef struct _sh_parser_state_t {
|
||||
int parser_state;
|
||||
int *token_state;
|
||||
|
||||
char *token;
|
||||
int token_buffer_size;
|
||||
|
||||
/* input line state -- line number saved elsewhere */
|
||||
int input_line_terminator;
|
||||
int eof_encountered;
|
||||
@@ -166,6 +171,16 @@ typedef struct _sh_parser_state_t {
|
||||
|
||||
} sh_parser_state_t;
|
||||
|
||||
typedef struct _sh_input_line_state_t {
|
||||
char *input_line;
|
||||
int input_line_index;
|
||||
int input_line_size;
|
||||
int input_line_len;
|
||||
} sh_input_line_state_t;
|
||||
|
||||
/* Let's try declaring these here. */
|
||||
extern sh_parser_state_t *save_parser_state __P((sh_parser_state_t *));
|
||||
extern void restore_parser_state __P((sh_parser_state_t *));
|
||||
|
||||
extern sh_input_line_state_t *save_input_line_state __P((sh_input_line_state_t *));
|
||||
extern void restore_input_line_state __P((sh_input_line_state_t *));
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
*** ../bash-4.2-patched/shell.h 2011-01-06 22:16:55.000000000 -0500
|
||||
--- shell.h 2011-06-24 19:12:25.000000000 -0400
|
||||
***************
|
||||
*** 137,140 ****
|
||||
--- 139,145 ----
|
||||
int *token_state;
|
||||
|
||||
+ char *token;
|
||||
+ int token_buffer_size;
|
||||
+
|
||||
/* input line state -- line number saved elsewhere */
|
||||
int input_line_terminator;
|
||||
***************
|
||||
*** 167,171 ****
|
||||
--- 172,186 ----
|
||||
} sh_parser_state_t;
|
||||
|
||||
+ typedef struct _sh_input_line_state_t {
|
||||
+ char *input_line;
|
||||
+ int input_line_index;
|
||||
+ int input_line_size;
|
||||
+ int input_line_len;
|
||||
+ } sh_input_line_state_t;
|
||||
+
|
||||
/* Let's try declaring these here. */
|
||||
extern sh_parser_state_t *save_parser_state __P((sh_parser_state_t *));
|
||||
extern void restore_parser_state __P((sh_parser_state_t *));
|
||||
+
|
||||
+ extern sh_input_line_state_t *save_input_line_state __P((sh_input_line_state_t *));
|
||||
+ extern void restore_input_line_state __P((sh_input_line_state_t *));
|
||||
@@ -0,0 +1,39 @@
|
||||
*** ../bash-4.2-patched/shell.h 2011-01-06 22:16:55.000000000 -0500
|
||||
--- shell.h 2011-06-24 19:12:25.000000000 -0400
|
||||
***************
|
||||
*** 97,100 ****
|
||||
--- 97,102 ----
|
||||
extern int shell_compatibility_level;
|
||||
|
||||
+ extern int locale_mb_cur_max;
|
||||
+
|
||||
/* Structure to pass around that holds a bitmap of file descriptors
|
||||
to close, and the size of that structure. Used in execute_cmd.c. */
|
||||
***************
|
||||
*** 137,140 ****
|
||||
--- 139,145 ----
|
||||
int *token_state;
|
||||
|
||||
+ char *token;
|
||||
+ int token_buffer_size;
|
||||
+
|
||||
/* input line state -- line number saved elsewhere */
|
||||
int input_line_terminator;
|
||||
***************
|
||||
*** 167,171 ****
|
||||
--- 172,186 ----
|
||||
} sh_parser_state_t;
|
||||
|
||||
+ typedef struct _sh_input_line_state_t {
|
||||
+ char *input_line;
|
||||
+ int input_line_index;
|
||||
+ int input_line_size;
|
||||
+ int input_line_len;
|
||||
+ } sh_input_line_state_t;
|
||||
+
|
||||
/* Let's try declaring these here. */
|
||||
extern sh_parser_state_t *save_parser_state __P((sh_parser_state_t *));
|
||||
extern void restore_parser_state __P((sh_parser_state_t *));
|
||||
+
|
||||
+ extern sh_input_line_state_t *save_input_line_state __P((sh_input_line_state_t *));
|
||||
+ extern void restore_input_line_state __P((sh_input_line_state_t *));
|
||||
@@ -0,0 +1,181 @@
|
||||
/* shell.h -- The data structures used by the shell */
|
||||
|
||||
/* Copyright (C) 1993-2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "bashjmp.h"
|
||||
|
||||
#include "command.h"
|
||||
#include "syntax.h"
|
||||
#include "general.h"
|
||||
#include "error.h"
|
||||
#include "variables.h"
|
||||
#include "arrayfunc.h"
|
||||
#include "quit.h"
|
||||
#include "maxpath.h"
|
||||
#include "unwind_prot.h"
|
||||
#include "dispose_cmd.h"
|
||||
#include "make_cmd.h"
|
||||
#include "ocache.h"
|
||||
#include "subst.h"
|
||||
#include "sig.h"
|
||||
#include "pathnames.h"
|
||||
#include "externs.h"
|
||||
|
||||
extern int EOF_Reached;
|
||||
|
||||
#define NO_PIPE -1
|
||||
#define REDIRECT_BOTH -2
|
||||
|
||||
#define NO_VARIABLE -1
|
||||
|
||||
/* Values that can be returned by execute_command (). */
|
||||
#define EXECUTION_FAILURE 1
|
||||
#define EXECUTION_SUCCESS 0
|
||||
|
||||
/* Usage messages by builtins result in a return status of 2. */
|
||||
#define EX_BADUSAGE 2
|
||||
|
||||
#define EX_MISCERROR 2
|
||||
|
||||
/* Special exit statuses used by the shell, internally and externally. */
|
||||
#define EX_RETRYFAIL 124
|
||||
#define EX_WEXPCOMSUB 125
|
||||
#define EX_BINARY_FILE 126
|
||||
#define EX_NOEXEC 126
|
||||
#define EX_NOINPUT 126
|
||||
#define EX_NOTFOUND 127
|
||||
|
||||
#define EX_SHERRBASE 256 /* all special error values are > this. */
|
||||
|
||||
#define EX_BADSYNTAX 257 /* shell syntax error */
|
||||
#define EX_USAGE 258 /* syntax error in usage */
|
||||
#define EX_REDIRFAIL 259 /* redirection failed */
|
||||
#define EX_BADASSIGN 260 /* variable assignment error */
|
||||
#define EX_EXPFAIL 261 /* word expansion failed */
|
||||
|
||||
/* Flag values that control parameter pattern substitution. */
|
||||
#define MATCH_ANY 0x000
|
||||
#define MATCH_BEG 0x001
|
||||
#define MATCH_END 0x002
|
||||
|
||||
#define MATCH_TYPEMASK 0x003
|
||||
|
||||
#define MATCH_GLOBREP 0x010
|
||||
#define MATCH_QUOTED 0x020
|
||||
#define MATCH_STARSUB 0x040
|
||||
|
||||
/* Some needed external declarations. */
|
||||
extern char **shell_environment;
|
||||
extern WORD_LIST *rest_of_args;
|
||||
|
||||
/* Generalized global variables. */
|
||||
extern int debugging_mode;
|
||||
extern int executing, login_shell;
|
||||
extern int interactive, interactive_shell;
|
||||
extern int startup_state;
|
||||
extern int subshell_environment;
|
||||
extern int shell_compatibility_level;
|
||||
|
||||
extern int locale_mb_cur_max;
|
||||
|
||||
/* Structure to pass around that holds a bitmap of file descriptors
|
||||
to close, and the size of that structure. Used in execute_cmd.c. */
|
||||
struct fd_bitmap {
|
||||
int size;
|
||||
char *bitmap;
|
||||
};
|
||||
|
||||
#define FD_BITMAP_SIZE 32
|
||||
|
||||
#define CTLESC '\001'
|
||||
#define CTLNUL '\177'
|
||||
|
||||
/* Information about the current user. */
|
||||
struct user_info {
|
||||
uid_t uid, euid;
|
||||
gid_t gid, egid;
|
||||
char *user_name;
|
||||
char *shell; /* shell from the password file */
|
||||
char *home_dir;
|
||||
};
|
||||
|
||||
extern struct user_info current_user;
|
||||
|
||||
/* Force gcc to not clobber X on a longjmp(). Old versions of gcc mangle
|
||||
this badly. */
|
||||
#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ > 8)
|
||||
# define USE_VAR(x) ((void) &(x))
|
||||
#else
|
||||
# define USE_VAR(x)
|
||||
#endif
|
||||
|
||||
/* Structure in which to save partial parsing state when doing things like
|
||||
PROMPT_COMMAND and bash_execute_unix_command execution. */
|
||||
|
||||
typedef struct _sh_parser_state_t {
|
||||
|
||||
/* parsing state */
|
||||
int parser_state;
|
||||
int *token_state;
|
||||
|
||||
char *token;
|
||||
int token_buffer_size;
|
||||
|
||||
/* input line state -- line number saved elsewhere */
|
||||
char *input_line;
|
||||
int input_line_index;
|
||||
int input_line_size;
|
||||
int input_line_len;
|
||||
|
||||
int input_line_terminator;
|
||||
int eof_encountered;
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
/* Nothing right now for multibyte state, but might want something later. */
|
||||
#endif
|
||||
|
||||
char **prompt_string_pointer;
|
||||
|
||||
/* history state affecting or modified by the parser */
|
||||
int current_command_line_count;
|
||||
#if defined (HISTORY)
|
||||
int remember_on_history;
|
||||
int history_expansion_inhibited;
|
||||
#endif
|
||||
|
||||
/* execution state possibly modified by the parser */
|
||||
int last_command_exit_value;
|
||||
#if defined (ARRAY_VARS)
|
||||
ARRAY *pipestatus;
|
||||
#endif
|
||||
sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;
|
||||
|
||||
/* flags state affecting the parser */
|
||||
int expand_aliases;
|
||||
int echo_input_at_read;
|
||||
|
||||
} sh_parser_state_t;
|
||||
|
||||
/* Let's try declaring these here. */
|
||||
extern sh_parser_state_t *save_parser_state __P((sh_parser_state_t *));
|
||||
extern void restore_parser_state __P((sh_parser_state_t *));
|
||||
@@ -9120,14 +9120,18 @@ brace_expand_word_list (tlist, eflags)
|
||||
|
||||
for (eindex = 0; temp_string = expansions[eindex]; eindex++)
|
||||
{
|
||||
w = make_word (temp_string);
|
||||
w = alloc_word_desc ();
|
||||
w->word = temp_string;
|
||||
|
||||
/* If brace expansion didn't change the word, preserve
|
||||
the flags. We may want to preserve the flags
|
||||
unconditionally someday -- XXX */
|
||||
if (STREQ (temp_string, tlist->word->word))
|
||||
w->flags = tlist->word->flags;
|
||||
else
|
||||
w = make_word_flags (w, temp_string);
|
||||
|
||||
output_list = make_word_list (w, output_list);
|
||||
free (expansions[eindex]);
|
||||
}
|
||||
free (expansions);
|
||||
|
||||
|
||||
@@ -1170,7 +1170,7 @@ extract_process_subst (string, starter, sindex)
|
||||
char *starter;
|
||||
int *sindex;
|
||||
{
|
||||
return (extract_delimited_string (string, sindex, starter, "(", ")", 0));
|
||||
return (extract_delimited_string (string, sindex, starter, "(", ")", SX_COMMAND));
|
||||
}
|
||||
#endif /* PROCESS_SUBSTITUTION */
|
||||
|
||||
@@ -3709,7 +3709,10 @@ remove_quoted_nulls (string)
|
||||
break;
|
||||
}
|
||||
else if (string[i] == CTLNUL)
|
||||
i++;
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
prev_i = i;
|
||||
ADVANCE_CHAR (string, slen, i);
|
||||
@@ -5527,7 +5530,7 @@ array_length_reference (s)
|
||||
}
|
||||
else
|
||||
{
|
||||
ind = array_expand_index (t, len);
|
||||
ind = array_expand_index (var, t, len);
|
||||
if (ind < 0)
|
||||
{
|
||||
err_badarraysub (t);
|
||||
@@ -8359,7 +8362,10 @@ add_twochars:
|
||||
temp = (char *)NULL;
|
||||
|
||||
/* We do not want to add quoted nulls to strings that are only
|
||||
partially quoted; we can throw them away. */
|
||||
partially quoted; we can throw them away. The execption to
|
||||
this is when we are going to be performing word splitting,
|
||||
since we have to preserve a null argument if the next character
|
||||
will cause word splitting. */
|
||||
if (temp == 0 && quoted_state == PARTIALLY_QUOTED && (word->flags & (W_NOSPLIT|W_NOSPLIT2)))
|
||||
continue;
|
||||
|
||||
@@ -9114,14 +9120,24 @@ brace_expand_word_list (tlist, eflags)
|
||||
|
||||
for (eindex = 0; temp_string = expansions[eindex]; eindex++)
|
||||
{
|
||||
#if 0
|
||||
w = make_word (temp_string);
|
||||
#else
|
||||
w = alloc_word_desc ();
|
||||
w->word = temp_string;
|
||||
#endif
|
||||
|
||||
/* If brace expansion didn't change the word, preserve
|
||||
the flags. We may want to preserve the flags
|
||||
unconditionally someday -- XXX */
|
||||
if (STREQ (temp_string, tlist->word->word))
|
||||
w->flags = tlist->word->flags;
|
||||
else
|
||||
w = make_word_flags (w, temp_string);
|
||||
output_list = make_word_list (w, output_list);
|
||||
#if 0
|
||||
free (expansions[eindex]);
|
||||
#endif
|
||||
}
|
||||
free (expansions);
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
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
|
||||
|
||||
|
||||
@@ -349,3 +349,9 @@ version[agent] foo[bar]
|
||||
version.agent bowl
|
||||
foobar] foo foo[bar]
|
||||
bleh bbb bleh
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
|
||||
@@ -0,0 +1,351 @@
|
||||
|
||||
./array.tests: line 15: syntax error near unexpected token `&'
|
||||
./array.tests: line 15: `test=(first & second)'
|
||||
1
|
||||
abcde
|
||||
abcde
|
||||
abcde bdef
|
||||
abcde bdef
|
||||
declare -a BASH_ARGC='()'
|
||||
declare -a BASH_ARGV='()'
|
||||
declare -a BASH_LINENO='([0]="0")'
|
||||
declare -a BASH_SOURCE='([0]="./array.tests")'
|
||||
declare -a DIRSTACK='()'
|
||||
declare -a FUNCNAME='([0]="main")'
|
||||
declare -a a='([0]="abcde" [1]="" [2]="bdef")'
|
||||
declare -a b='()'
|
||||
declare -ar c='()'
|
||||
abcde bdef
|
||||
abcde bdef
|
||||
abcde
|
||||
abcde
|
||||
abcde
|
||||
|
||||
bdef
|
||||
hello world
|
||||
11
|
||||
3
|
||||
bdef hello world test expression test 2
|
||||
./array.tests: line 76: readonly: `a[5]': not a valid identifier
|
||||
declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression" [15]="test 2")'
|
||||
declare -ar c='()'
|
||||
declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression" [15]="test 2")'
|
||||
declare -ar c='()'
|
||||
readonly -a a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression" [15]="test 2")'
|
||||
readonly -a c='()'
|
||||
a test
|
||||
declare -a BASH_ARGC='()'
|
||||
declare -a BASH_ARGV='()'
|
||||
declare -a BASH_LINENO='([0]="0")'
|
||||
declare -a BASH_SOURCE='([0]="./array.tests")'
|
||||
declare -a DIRSTACK='()'
|
||||
declare -a FUNCNAME='([0]="main")'
|
||||
declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression" [15]="test 2")'
|
||||
declare -a b='([0]="this" [1]="is" [2]="a" [3]="test" [4]="" [5]="/etc/passwd")'
|
||||
declare -ar c='()'
|
||||
declare -a d='([1]="" [2]="bdef" [5]="hello world" [6]="test" [9]="ninth element")'
|
||||
declare -a e='([0]="test")'
|
||||
declare -a f='([0]="" [1]="bdef" [2]="hello world" [3]="test" [4]="ninth element")'
|
||||
./array.tests: line 100: a: readonly variable
|
||||
./array.tests: line 102: b[]: bad array subscript
|
||||
./array.tests: line 103: b[*]: bad array subscript
|
||||
./array.tests: line 104: ${b[ ]}: bad substitution
|
||||
./array.tests: line 106: c[-2]: bad array subscript
|
||||
./array.tests: line 107: c: bad array subscript
|
||||
|
||||
./array.tests: line 109: d[7]: cannot assign list to array member
|
||||
./array.tests: line 111: []=abcde: bad array subscript
|
||||
./array.tests: line 111: [*]=last: cannot assign to non-numeric index
|
||||
./array.tests: line 111: [-65]=negative: bad array subscript
|
||||
declare -a BASH_ARGC='()'
|
||||
declare -a BASH_ARGV='()'
|
||||
declare -a BASH_LINENO='([0]="0")'
|
||||
declare -a BASH_SOURCE='([0]="./array.tests")'
|
||||
declare -a DIRSTACK='()'
|
||||
declare -a FUNCNAME='([0]="main")'
|
||||
declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression" [15]="test 2")'
|
||||
declare -a b='([0]="this" [1]="is" [2]="a" [3]="test" [4]="" [5]="/etc/passwd")'
|
||||
declare -ar c='()'
|
||||
declare -a d='([1]="test test")'
|
||||
declare -a f='([0]="" [1]="bdef" [2]="hello world" [3]="test" [4]="ninth element")'
|
||||
./array.tests: line 119: unset: ps1: not an array variable
|
||||
./array.tests: line 123: declare: c: cannot destroy array variables in this way
|
||||
this of
|
||||
this is a test of read using arrays
|
||||
this test
|
||||
this is a test of arrays
|
||||
declare -a BASH_ARGC='()'
|
||||
declare -a BASH_ARGV='()'
|
||||
declare -a BASH_LINENO='([0]="0")'
|
||||
declare -a BASH_SOURCE='([0]="./array.tests")'
|
||||
declare -a DIRSTACK='()'
|
||||
declare -a FUNCNAME='([0]="main")'
|
||||
declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression" [15]="test 2")'
|
||||
declare -a b='([0]="this" [1]="is" [2]="a" [3]="test" [4]="" [5]="/etc/passwd")'
|
||||
declare -ar c='()'
|
||||
declare -a d='([1]="test test")'
|
||||
declare -a f='([0]="" [1]="bdef" [2]="hello world" [3]="test" [4]="ninth element")'
|
||||
declare -a rv='([0]="this" [1]="is" [2]="a" [3]="test" [4]="of" [5]="read" [6]="using" [7]="arrays")'
|
||||
abde
|
||||
abde
|
||||
bbb
|
||||
efgh
|
||||
wxyz
|
||||
wxyz
|
||||
./array.tests
|
||||
a
|
||||
b c
|
||||
d
|
||||
e f g
|
||||
h
|
||||
./array.tests
|
||||
a
|
||||
b c
|
||||
d
|
||||
e f g
|
||||
h
|
||||
/bin /usr/bin /usr/ucb /usr/local/bin . /sbin /usr/sbin
|
||||
bin bin ucb bin . sbin sbin
|
||||
bin
|
||||
/ / / / / /
|
||||
/
|
||||
argv[1] = <bin>
|
||||
argv[1] = </>
|
||||
argv[1] = <sbin>
|
||||
argv[1] = </>
|
||||
\bin \usr/bin \usr/ucb \usr/local/bin . \sbin \usr/sbin
|
||||
\bin \usr\bin \usr\ucb \usr\local\bin . \sbin \usr\sbin
|
||||
\bin \usr\bin \usr\ucb \usr\local\bin . \sbin \usr\sbin
|
||||
4 -- 4
|
||||
7 -- 7
|
||||
55
|
||||
49
|
||||
6 -- 6
|
||||
42 14 44
|
||||
grep [ 123 ] *
|
||||
6 7 9
|
||||
6 7 9 5
|
||||
length = 3
|
||||
value = new1 new2 new3
|
||||
./array.tests: line 239: narray: unbound variable
|
||||
./array1.sub: line 1: syntax error near unexpected token `('
|
||||
./array1.sub: line 1: `printf "%s\n" -a a=(a 'b c')'
|
||||
./array2.sub: line 1: syntax error near unexpected token `('
|
||||
./array2.sub: line 1: `declare -a ''=(a 'b c')'
|
||||
9
|
||||
9
|
||||
|
||||
|
||||
7 8 9
|
||||
8 11
|
||||
8 11
|
||||
6
|
||||
6
|
||||
nordholz
|
||||
8
|
||||
8
|
||||
8
|
||||
|
||||
a b c d e f g
|
||||
for case if then else
|
||||
<> < > !
|
||||
12 14 16 18 20
|
||||
4414758999202
|
||||
aaa bbb
|
||||
./array.tests: line 289: syntax error near unexpected token `<>'
|
||||
./array.tests: line 289: `metas=( <> < > ! )'
|
||||
./array.tests: line 290: syntax error near unexpected token `<>'
|
||||
./array.tests: line 290: `metas=( [1]=<> [2]=< [3]=> [4]=! )'
|
||||
abc 3
|
||||
case 4
|
||||
abc case if then else 5
|
||||
abc case if then else 5
|
||||
0
|
||||
case 4
|
||||
case if then else 5
|
||||
case if then else 5
|
||||
argv[1] = <0>
|
||||
argv[2] = <1>
|
||||
argv[3] = <4>
|
||||
argv[4] = <10>
|
||||
argv[1] = <0>
|
||||
argv[2] = <1>
|
||||
argv[3] = <4>
|
||||
argv[4] = <10>
|
||||
argv[1] = <0>
|
||||
argv[2] = <1>
|
||||
argv[3] = <4>
|
||||
argv[4] = <10>
|
||||
argv[1] = <0 1 4 10>
|
||||
include null element -- expect one
|
||||
one
|
||||
include unset element -- expect three five
|
||||
three five
|
||||
start at unset element -- expect five seven
|
||||
five seven
|
||||
too many elements -- expect three five seven
|
||||
three five seven
|
||||
positive 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
|
||||
seven
|
||||
out-of-range offset
|
||||
|
||||
e
|
||||
4
|
||||
1 4 7 10
|
||||
'b
|
||||
b c
|
||||
$0
|
||||
t
|
||||
[3]=abcde r s t u v
|
||||
e
|
||||
9
|
||||
2
|
||||
a b c
|
||||
argv[1] = <"-iname '"a>
|
||||
argv[2] = <"-iname '"b>
|
||||
argv[3] = <"-iname '"c>
|
||||
'hey'
|
||||
hey
|
||||
''hey
|
||||
'hey'
|
||||
argv[1] = <c>
|
||||
argv[2] = <d>
|
||||
argv[3] = <e>
|
||||
argv[4] = <f>
|
||||
argv[1] = <c d>
|
||||
argv[2] = <e f>
|
||||
argv[1] = <c d>
|
||||
argv[2] = <e f>
|
||||
argv[1] = <c d>
|
||||
argv[2] = <e f>
|
||||
argv[1] = <"-iname '"abc>
|
||||
argv[2] = <"-iname '"def>
|
||||
argv[1] = <-iname 'abc>
|
||||
argv[2] = <-iname 'def>
|
||||
argv[1] = <-iname \'abc>
|
||||
argv[2] = <-iname \'def>
|
||||
argv[1] = <-iname>
|
||||
argv[2] = <'abc>
|
||||
argv[3] = <-iname>
|
||||
argv[4] = <'def>
|
||||
argv[1] = <"-iname '"abc>
|
||||
argv[2] = <"-iname '"def>
|
||||
argv[1] = <-iname 'abc>
|
||||
argv[2] = <-iname 'def>
|
||||
*.* OK
|
||||
1
|
||||
a1 2 3c
|
||||
argv[1] = <var with spaces>
|
||||
argv[1] = <var with spaces>
|
||||
argv[1] = <var with spacesab>
|
||||
argv[2] = <cd>
|
||||
argv[3] = <ef>
|
||||
argv[1] = <var with spacesab>
|
||||
argv[2] = <cd>
|
||||
argv[3] = <ef>
|
||||
argv[1] = <var with spacesab>
|
||||
argv[2] = <cd>
|
||||
argv[3] = <ef>
|
||||
argv[1] = <var with spacesab>
|
||||
argv[2] = <cd>
|
||||
argv[3] = <ef>
|
||||
argv[1] = <var with spacesab>
|
||||
argv[2] = <cd>
|
||||
argv[3] = <ef>
|
||||
argv[1] = <var with spacesab>
|
||||
argv[2] = <cd>
|
||||
argv[3] = <ef>
|
||||
2
|
||||
argv[1] = <element1 with spaces>
|
||||
argv[2] = <element2 with spaces>
|
||||
argv[1] = <element1 with spaces>
|
||||
argv[2] = <element2 with spaces>
|
||||
nord!olz
|
||||
|
||||
rdholz
|
||||
|
||||
rdholz
|
||||
rdho
|
||||
|
||||
|
||||
argv[1] = <fooq//barq/>
|
||||
argv[1] = <fooq>
|
||||
argv[2] = <>
|
||||
argv[3] = <barq>
|
||||
argv[4] = <>
|
||||
argv[1] = <foo!//bar!/>
|
||||
argv[1] = <foo!>
|
||||
argv[2] = <>
|
||||
argv[3] = <bar!>
|
||||
argv[4] = <>
|
||||
argv[1] = <ooq//arq/>
|
||||
argv[1] = <ooq>
|
||||
argv[2] = <>
|
||||
argv[3] = <arq>
|
||||
argv[4] = <>
|
||||
argv[1] = <Fooq//Barq/>
|
||||
argv[1] = <Fooq>
|
||||
argv[2] = <>
|
||||
argv[3] = <Barq>
|
||||
argv[4] = <>
|
||||
argv[1] = <FOOQ//BARQ/>
|
||||
argv[1] = <FOOQ>
|
||||
argv[2] = <>
|
||||
argv[3] = <BARQ>
|
||||
argv[4] = <>
|
||||
126
|
||||
127
|
||||
128
|
||||
argv[1] = <€>
|
||||
argv[1] = <~>
|
||||
argv[2] = <^?>
|
||||
argv[3] = <€>
|
||||
argv[1] = <~>
|
||||
argv[2] = <^?>
|
||||
argv[3] = <€>
|
||||
argv[1] = <~>
|
||||
argv[2] = <^?>
|
||||
argv[3] = <€>
|
||||
Monday Tuesday Wednesday Thursday Friday Saturday Sunday
|
||||
Monday
|
||||
Monday
|
||||
Tuesday
|
||||
Monday
|
||||
Monday
|
||||
Tuesday
|
||||
Monday
|
||||
Tuesday
|
||||
Wednesday
|
||||
Monday
|
||||
Tuesday
|
||||
Wednesday
|
||||
monday, monday, tuesday
|
||||
wednesday, wednesday, thursday
|
||||
monday, monday, tuesday
|
||||
Wednesday, Wednesday, Thursday
|
||||
nday
|
||||
esday
|
||||
dnesday
|
||||
nday
|
||||
esday
|
||||
dnesday
|
||||
onday
|
||||
uesday
|
||||
ednesday
|
||||
onday
|
||||
uesday
|
||||
ednesday
|
||||
version[agent]
|
||||
version.agent
|
||||
version[agent]
|
||||
version.agent
|
||||
version[agent] foo[bar]
|
||||
version.agent bowl
|
||||
foobar] foo foo[bar]
|
||||
bleh bbb bleh
|
||||
@@ -390,3 +390,5 @@ ${THIS_SH} ./array9.sub
|
||||
${THIS_SH} ./array10.sub
|
||||
|
||||
${THIS_SH} ./array11.sub
|
||||
|
||||
${THIS_SH} ./array12.sub
|
||||
|
||||
@@ -0,0 +1,392 @@
|
||||
# this is needed so that the bad assignments (b[]=bcde, for example) do not
|
||||
# cause fatal shell errors when in posix mode
|
||||
set +o posix
|
||||
|
||||
set +a
|
||||
# The calls to egrep -v are to filter out builtin array variables that are
|
||||
# automatically set and possibly contain values that vary.
|
||||
|
||||
# first make sure we handle the basics
|
||||
x=()
|
||||
echo ${x[@]}
|
||||
unset x
|
||||
|
||||
# this should be an error
|
||||
test=(first & second)
|
||||
echo $?
|
||||
unset test
|
||||
|
||||
# make sure declare -a converts an existing variable to an array
|
||||
unset a
|
||||
a=abcde
|
||||
declare -a a
|
||||
echo ${a[0]}
|
||||
|
||||
unset a
|
||||
a=abcde
|
||||
a[2]=bdef
|
||||
|
||||
unset b
|
||||
declare -a b[256]
|
||||
|
||||
unset c[2]
|
||||
unset c[*]
|
||||
|
||||
a[1]=
|
||||
|
||||
_ENV=/bin/true
|
||||
x=${_ENV[(_$-=0)+(_=1)-_${-%%*i*}]}
|
||||
|
||||
declare -r c[100]
|
||||
|
||||
echo ${a[0]} ${a[4]}
|
||||
echo ${a[@]}
|
||||
|
||||
echo ${a[*]}
|
||||
|
||||
# this should print out values, too
|
||||
declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
|
||||
|
||||
unset a[7]
|
||||
echo ${a[*]}
|
||||
|
||||
unset a[4]
|
||||
echo ${a[*]}
|
||||
|
||||
echo ${a}
|
||||
echo "${a}"
|
||||
echo $a
|
||||
|
||||
unset a[0]
|
||||
echo ${a}
|
||||
|
||||
echo ${a[@]}
|
||||
|
||||
a[5]="hello world"
|
||||
echo ${a[5]}
|
||||
echo ${#a[5]}
|
||||
|
||||
echo ${#a[@]}
|
||||
|
||||
a[4+5/2]="test expression"
|
||||
declare a["7 + 8"]="test 2"
|
||||
a[7 + 8]="test 2"
|
||||
echo ${a[@]}
|
||||
|
||||
readonly a[5]
|
||||
readonly a
|
||||
# these two lines should output `declare' commands
|
||||
readonly -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
|
||||
declare -ar | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
|
||||
# this line should output `readonly' commands, even for arrays
|
||||
set -o posix
|
||||
readonly -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
|
||||
set +o posix
|
||||
|
||||
declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")'
|
||||
d[9]="ninth element"
|
||||
|
||||
declare -a e[10]=test # this works in post-bash-2.05 versions
|
||||
declare -a e[10]='(test)'
|
||||
|
||||
pass=/etc/passwd
|
||||
declare -a f='("${d[@]}")'
|
||||
b=([0]=this [1]=is [2]=a [3]=test [4]="$PS1" [5]=$pass)
|
||||
|
||||
echo ${b[@]:2:3}
|
||||
|
||||
declare -pa | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
|
||||
|
||||
a[3]="this is a test"
|
||||
|
||||
b[]=bcde
|
||||
b[*]=aaa
|
||||
echo ${b[ ]}
|
||||
|
||||
c[-2]=4
|
||||
echo ${c[-4]}
|
||||
|
||||
d[7]=(abdedfegeee)
|
||||
|
||||
d=([]=abcde [1]="test test" [*]=last [-65]=negative )
|
||||
|
||||
unset d[12]
|
||||
unset e[*]
|
||||
|
||||
declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
|
||||
|
||||
ps1='hello'
|
||||
unset ps1[2]
|
||||
unset ${ps1[2]}
|
||||
|
||||
declare +a ps1
|
||||
declare +a c
|
||||
|
||||
# the prompt should not print when using a here doc
|
||||
read -p "array test: " -a rv <<!
|
||||
this is a test of read using arrays
|
||||
!
|
||||
|
||||
echo ${rv[0]} ${rv[4]}
|
||||
echo ${rv[@]}
|
||||
|
||||
# the variable should be converted to an array when `read -a' is done
|
||||
vv=1
|
||||
read -a vv <<!
|
||||
this is a test of arrays
|
||||
!
|
||||
echo ${vv[0]} ${vv[3]}
|
||||
echo ${vv[@]}
|
||||
unset vv
|
||||
|
||||
declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
|
||||
|
||||
export rv
|
||||
#set
|
||||
|
||||
x[4]=bbb
|
||||
x=abde
|
||||
echo $x
|
||||
echo ${x[0]}
|
||||
echo ${x[4]}
|
||||
echo efgh | ( read x[1] ; echo ${x[1]} )
|
||||
echo wxyz | ( declare -a x ; read x ; echo $x ; echo ${x[0]} )
|
||||
|
||||
# Make sure that arrays can be used to save the positional paramters verbatim
|
||||
set -- a 'b c' d 'e f g' h
|
||||
|
||||
ARGV=( [0]=$0 "$@" )
|
||||
|
||||
for z in "${ARGV[@]}"
|
||||
do
|
||||
echo "$z"
|
||||
done
|
||||
|
||||
echo "$0"
|
||||
for z in "$@"
|
||||
do
|
||||
echo "$z"
|
||||
done
|
||||
|
||||
# do various pattern removal and length tests
|
||||
XPATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:.:/sbin:/usr/sbin
|
||||
|
||||
xpath=( $( IFS=: ; echo $XPATH ) )
|
||||
|
||||
echo ${xpath[@]}
|
||||
echo ${xpath[@]##*/}
|
||||
echo ${xpath[0]##*/}
|
||||
echo ${xpath[@]%%[!/]*}
|
||||
echo ${xpath[0]%%[!/]*}
|
||||
recho ${xpath##*/}
|
||||
recho ${xpath%%[!/]*}
|
||||
recho ${xpath[5]##*/}
|
||||
recho ${xpath[5]%%[!/]*}
|
||||
|
||||
# let's try to make it a DOS-style path
|
||||
|
||||
zecho "${xpath[@]/\//\\}"
|
||||
zecho "${xpath[@]//\//\\}"
|
||||
zecho "${xpath[@]//[\/]/\\}"
|
||||
|
||||
# length of the first element of the array, since array without subscript
|
||||
# is equivalent to referencing first element
|
||||
echo ${#xpath} -- ${#xpath[0]}
|
||||
|
||||
# number of elements in the array
|
||||
nelem=${#xpath[@]}
|
||||
echo ${#xpath[@]} -- $nelem
|
||||
|
||||
# total length of all elements in the array, including space separators
|
||||
xx="${xpath[*]}"
|
||||
echo ${#xx}
|
||||
|
||||
# total length of all elements in the array
|
||||
xx=$( IFS='' ; echo "${xpath[*]}" )
|
||||
echo ${#xx}
|
||||
|
||||
unset xpath[nelem-1]
|
||||
|
||||
nelem=${#xpath[@]}
|
||||
echo ${#xpath[@]} -- $nelem
|
||||
|
||||
# arrays and things that look like index assignments
|
||||
array=(42 [1]=14 [2]=44)
|
||||
|
||||
array2=(grep [ 123 ] \*)
|
||||
|
||||
echo ${array[@]}
|
||||
echo "${array2[@]}"
|
||||
|
||||
# arrays and implicit arithmetic evaluation
|
||||
declare -i -a iarray
|
||||
|
||||
iarray=( 2+4 1+6 7+2 )
|
||||
echo ${iarray[@]}
|
||||
|
||||
iarray[4]=4+1
|
||||
echo ${iarray[@]}
|
||||
|
||||
# make sure assignment using the compound assignment syntax removes all
|
||||
# of the old elements from the array value
|
||||
barray=(old1 old2 old3 old4 old5)
|
||||
barray=(new1 new2 new3)
|
||||
echo "length = ${#barray[@]}"
|
||||
echo "value = ${barray[*]}"
|
||||
|
||||
# make sure the array code behaves correctly with respect to unset variables
|
||||
set -u
|
||||
( echo ${#narray[4]} )
|
||||
|
||||
${THIS_SH} ./array1.sub
|
||||
${THIS_SH} ./array2.sub
|
||||
|
||||
# some old bugs and ksh93 compatibility tests
|
||||
${THIS_SH} ./array3.sub
|
||||
|
||||
# some compound assingment parsing problems that showed up in bash-3.1-release
|
||||
${THIS_SH} ./array4.sub
|
||||
|
||||
set +u
|
||||
cd /tmp
|
||||
|
||||
touch 1=bar
|
||||
foo=([10]="bar")
|
||||
echo ${foo[0]}
|
||||
rm 1=bar
|
||||
|
||||
cd $OLDPWD
|
||||
|
||||
foo=(a b c d e f g)
|
||||
echo ${foo[@]}
|
||||
|
||||
# quoted reserved words are ok
|
||||
foo=(\for \case \if \then \else)
|
||||
echo ${foo[@]}
|
||||
|
||||
# quoted metacharacters are ok
|
||||
foo=( [1]='<>' [2]='<' [3]='>' [4]='!' )
|
||||
echo ${foo[@]}
|
||||
|
||||
# numbers are just words when not in a redirection context
|
||||
foo=( 12 14 16 18 20 )
|
||||
echo ${foo[@]}
|
||||
|
||||
foo=( 4414758999202 )
|
||||
echo ${foo[@]}
|
||||
|
||||
# this was a bug in all versions of bash 2.x up to and including bash-2.04
|
||||
declare -a ddd=(aaa
|
||||
bbb)
|
||||
echo ${ddd[@]}
|
||||
|
||||
# errors until post-bash-2.05a; now reserved words are OK
|
||||
foo=(a b c for case if then else)
|
||||
|
||||
foo=(for case if then else)
|
||||
|
||||
# errors
|
||||
metas=( <> < > ! )
|
||||
metas=( [1]=<> [2]=< [3]=> [4]=! )
|
||||
|
||||
# various expansions that didn't really work right until post-bash-2.04
|
||||
foo='abc'
|
||||
echo ${foo[0]} ${#foo[0]}
|
||||
echo ${foo[1]} ${#foo[1]}
|
||||
echo ${foo[@]} ${#foo[@]}
|
||||
echo ${foo[*]} ${#foo[*]}
|
||||
|
||||
foo=''
|
||||
echo ${foo[0]} ${#foo[0]}
|
||||
echo ${foo[1]} ${#foo[1]}
|
||||
echo ${foo[@]} ${#foo[@]}
|
||||
echo ${foo[*]} ${#foo[*]}
|
||||
|
||||
# new expansions added after bash-2.05b
|
||||
x[0]=zero
|
||||
x[1]=one
|
||||
x[4]=four
|
||||
x[10]=ten
|
||||
|
||||
recho ${!x[@]}
|
||||
recho "${!x[@]}"
|
||||
recho ${!x[*]}
|
||||
recho "${!x[*]}"
|
||||
|
||||
# sparse array tests for code fixed in bash-3.0
|
||||
unset av
|
||||
av[1]='one'
|
||||
av[2]=''
|
||||
|
||||
av[3]=three
|
||||
av[5]=five
|
||||
av[7]=seven
|
||||
|
||||
echo include null element -- expect one
|
||||
echo ${av[@]:1:2} # what happens when we include a null element?
|
||||
echo include unset element -- expect three five
|
||||
echo ${av[@]:3:2} # what happens when we include an unset element?
|
||||
echo start at unset element -- expect five seven
|
||||
echo ${av[@]:4:2} # what happens when we start at an unset element?
|
||||
|
||||
echo too many elements -- expect three five seven
|
||||
echo ${av[@]:3:5} # how about too many elements?
|
||||
|
||||
echo positive offset - expect five seven
|
||||
echo ${av[@]:5:2}
|
||||
echo negative offset to unset element - expect seven
|
||||
echo ${av[@]: -2:2}
|
||||
|
||||
echo positive offset 2 - expect seven
|
||||
echo ${av[@]: 6:2}
|
||||
echo negative offset 2 - expect seven
|
||||
echo ${av[@]: -1:2}
|
||||
|
||||
echo out-of-range offset
|
||||
echo ${av[@]:12}
|
||||
|
||||
# parsing problems and other inconsistencies not fixed until post bash-3.0
|
||||
unset x
|
||||
declare -a x=(')' $$)
|
||||
[ ${x[1]} -eq $$ ] || echo bad
|
||||
|
||||
unset x
|
||||
declare -a x=(a b c d e)
|
||||
echo ${x[4]}
|
||||
|
||||
z=([1]=one [4]=four [7]=seven [10]=ten)
|
||||
|
||||
echo ${#z[@]}
|
||||
|
||||
echo ${!z[@]}
|
||||
|
||||
unset x
|
||||
declare -a x=(a \'b c\')
|
||||
|
||||
echo "${x[1]}"
|
||||
|
||||
unset x
|
||||
declare -a x=(a 'b c')
|
||||
|
||||
echo "${x[1]}"
|
||||
|
||||
unset x
|
||||
declare -a x=($0)
|
||||
[ "${x[@]}" = $0 ] || echo double expansion of \$0
|
||||
declare -a x=(\$0)
|
||||
echo "${x[@]}"
|
||||
|
||||
# tests for bash-3.1 problems
|
||||
${THIS_SH} ./array5.sub
|
||||
|
||||
# tests for post-bash-3.2 problems, most fixed in bash-3.2 patches
|
||||
${THIS_SH} ./array6.sub
|
||||
${THIS_SH} ./array7.sub
|
||||
|
||||
${THIS_SH} ./array8.sub
|
||||
|
||||
${THIS_SH} ./array9.sub
|
||||
|
||||
${THIS_SH} ./array10.sub
|
||||
|
||||
${THIS_SH} ./array11.sub
|
||||
@@ -0,0 +1,21 @@
|
||||
# problems with fix for posix interp 217 introduced in bash-4.2
|
||||
|
||||
declare -ax array
|
||||
array[$(( $( echo -n 1001 ) - 1001 ))]=1
|
||||
|
||||
echo ${array[0]}
|
||||
echo ${array[@]}
|
||||
|
||||
unset 'array[0]'
|
||||
array[$( echo -n 1001 ) - 1001 ]=1
|
||||
echo ${array[0]}
|
||||
|
||||
unset 'array[0]'
|
||||
array[$(( 1001 - $( echo -n 1001 ) ))]=1
|
||||
echo ${array[0]}
|
||||
array[$(( 1001 - $( echo -n 1001 ) ))]=1
|
||||
echo ${array[0]}
|
||||
|
||||
unset 'array[0]'
|
||||
array[1001 - $( echo -n 1001 )]=1
|
||||
echo ${array[0]}
|
||||
+1
-1
@@ -5,7 +5,7 @@ trap 'rm /tmp/newhistory' 0
|
||||
file=bax
|
||||
histchars='!^#' # make sure history comment char is set correctly
|
||||
|
||||
unset HISTFILESIZE
|
||||
unset HISTFILESIZE HISTTIMEFORMAT
|
||||
|
||||
history -c
|
||||
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
LC_ALL=C
|
||||
LANG=C
|
||||
trap 'rm /tmp/newhistory' 0
|
||||
|
||||
file=bax
|
||||
histchars='!^#' # make sure history comment char is set correctly
|
||||
|
||||
unset HISTFILESIZE
|
||||
|
||||
history -c
|
||||
|
||||
HISTFILE=history.list
|
||||
HISTCONTROL=ignoreboth
|
||||
HISTIGNORE='&:#*:history*:fc*'
|
||||
# we will end up exercising the history stifling code as a result
|
||||
HISTSIZE=32
|
||||
|
||||
shopt -s cmdhist
|
||||
set -o history
|
||||
|
||||
history -p '!!'
|
||||
|
||||
# this should result in a failed history expansion error
|
||||
history -p '!!:z'
|
||||
|
||||
history
|
||||
|
||||
HISTFILE=/tmp/newhistory
|
||||
history -a
|
||||
|
||||
history -w
|
||||
|
||||
history -s "echo line 2 for history"
|
||||
history
|
||||
history -p '!e'
|
||||
history -p '!!'
|
||||
|
||||
set -H
|
||||
!!
|
||||
!e
|
||||
|
||||
history
|
||||
|
||||
echo a b c d e
|
||||
!?ch?
|
||||
!-2
|
||||
^2^8
|
||||
|
||||
!2
|
||||
|
||||
# we're selecting /bin/sh -c ...; we want `sh'
|
||||
echo !-1:0:t
|
||||
# we're selecting /bin/sh -c ...; we want `/bin'
|
||||
echo !-2:0:h
|
||||
# we're selecting `echo a b c d e'; we want `e'
|
||||
echo !?d?:5
|
||||
|
||||
echo a b c d e
|
||||
echo !-1:2-$
|
||||
echo !-2:2-4
|
||||
echo !-2:3*
|
||||
echo !!:*
|
||||
|
||||
echo !?a?:2-
|
||||
|
||||
echo file.c
|
||||
echo !!:$:r
|
||||
echo !-2:$:e
|
||||
echo !-3:$:r:q
|
||||
|
||||
echo $file.c
|
||||
echo !!:$:r
|
||||
echo !-2:^:e
|
||||
echo !-3:$:r:q
|
||||
|
||||
echo a b c d e
|
||||
echo !!:1-$:x
|
||||
echo !-2:1-$:q
|
||||
|
||||
echo foo.c foo.o foo.html foo.h
|
||||
!!:s/foo/bar/
|
||||
!-2:gs/foo/bar/
|
||||
!!:gs/bar/x&/
|
||||
!-2:g&
|
||||
|
||||
# make sure we can use any delimiter in the substitution, not just `/'
|
||||
!!:gs+bar+whix+
|
||||
|
||||
!!:p
|
||||
|
||||
# wow
|
||||
echo !?.o?:%:r:q
|
||||
|
||||
!!:0 !?.h?:%:q
|
||||
!!:-$
|
||||
!:-$
|
||||
|
||||
history
|
||||
|
||||
# make sure single quotes inhibit history expansion
|
||||
echo '!!'
|
||||
|
||||
# make sure backslashes can quote the history expansion character
|
||||
echo \!\!
|
||||
|
||||
# but other expansions on the line should still be processed
|
||||
|
||||
echo '!!' !!:*
|
||||
history -c
|
||||
unset HISTFILE
|
||||
|
||||
# make sure that the special bash cases are not history expanded
|
||||
case p in
|
||||
[!A-Z]) echo ok 1;;
|
||||
esac
|
||||
|
||||
var1='ok 2'
|
||||
var2=var1
|
||||
|
||||
echo ${!var2}
|
||||
|
||||
# Bash-2.01[.1] fails this test -- it attempts history expansion after the
|
||||
# history_comment_char
|
||||
echo ok 3 # !1200
|
||||
Reference in New Issue
Block a user