commit bash-20110622 snapshot

This commit is contained in:
Chet Ramey
2011-12-29 13:09:50 -05:00
parent 3443670e48
commit 51f7ea3672
47 changed files with 5974 additions and 144 deletions
+80
View File
@@ -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>
+87
View File
@@ -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
+1
View File
@@ -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
+12
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+47 -14
View File
@@ -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
View File
@@ -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;
}
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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; \
+501
View File
@@ -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_ */
+2
View File
@@ -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 */
+5
View File
@@ -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
View File
@@ -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(']'))
+772
View File
@@ -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
View File
@@ -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)
+409
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+7
View File
@@ -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;
+568
View File
@@ -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 -1
View File
@@ -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);
}
+12 -6
View File
@@ -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);
}
+47
View File
@@ -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 ();
}
/************************************************
+88
View File
@@ -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
View File
@@ -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 ();
}
+85 -33
View File
@@ -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 ();
}
/************************************************
+15
View File
@@ -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 *));
+30
View File
@@ -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 *));
+39
View File
@@ -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 *));
+181
View File
@@ -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 *));
+6 -2
View File
@@ -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);
+20 -4
View File
@@ -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
View File
@@ -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
+6
View File
@@ -349,3 +349,9 @@ version[agent] foo[bar]
version.agent bowl
foobar] foo foo[bar]
bleh bbb bleh
1
1
1
1
1
1
+351
View File
@@ -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
+2
View File
@@ -390,3 +390,5 @@ ${THIS_SH} ./array9.sub
${THIS_SH} ./array10.sub
${THIS_SH} ./array11.sub
${THIS_SH} ./array12.sub
+392
View File
@@ -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
+21
View File
@@ -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
View File
@@ -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
+124
View File
@@ -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