commit bash-20070405 snapshot

This commit is contained in:
Chet Ramey
2011-12-07 09:06:13 -05:00
parent d3ad40dee6
commit e6598ba488
36 changed files with 20242 additions and 362 deletions
+42
View File
@@ -14458,3 +14458,45 @@ mailcheck.h
shell.c
- call init_mail_dates instead of remember_mail_dates
4/4
---
builtins/read.def
- changes to print $PS2 when a line is continued with a backslash in
an interactive shell. This is as POSIX requires
4/5
---
subst.c
- make sure quote_escapes is only ever called when the word to be
escaped is not marked as double-quoted -- cleaner, and allows us
to make certain assumptions
4/6
---
subst.c
- change all EX_* defines to begin with SX_
- new flag, SX_NOCTLESC, obeyed by string_extract_verbatim, tells it
to not obey CTLESC quoting
- change quote_escapes to not quote CTLESC with CTLESC if one of the
chars in $IFS is CTLESC, since the return value from quote_string
will be passed to word splitting and filename generation
- change read_comsub to do the same thing for unquoted command
substitutions
- change list_string to pass SX_NOCTLESC if CTLESC is one of the
chars in $IFS, so it will split on CTLESC instead of using it as a
quote character
4/7
---
subst.c
- slight change to string_extract_verbatim to allow CTLESC to quote
CTLNUL even if SX_NOCTLESC is set in the flags passed, to protect
the CTLNULs from future calls to remove_quoted_nulls. Only
matters when $IFS contains CTLESC
- changes to cope with $IFS containing CTLNUL in the same way as the
CTLESC changes
builtins/read.def
- changes to cope with $IFS containing CTLNUL in the same way as the
CTLESC changes
+39 -2
View File
@@ -14444,8 +14444,9 @@ doc/Makefile.in
mailcheck.c
- new function, init_mail_dates, calls remember_mail_dates only if
there are no mailboxes in `mailfiles'
- new function, init_mail_file, just calls RESET_MAIL_FILE (placeholder
for later expansion)
- new function, init_mail_file, initializes a FILEINFO, using the
last time mail was checked as the mtime and atime (or the time the
shell was started if last_time_mail_checked is uninitialized)
- call init_mail_file instead of update_mail_file in add_mail_file,
called from remember_mail_dates (which is supposed to initialize
the list of mail files)
@@ -14457,3 +14458,39 @@ mailcheck.h
shell.c
- call init_mail_dates instead of remember_mail_dates
4/4
---
builtins/read.def
- changes to print $PS2 when a line is continued with a backslash in
an interactive shell. This is as POSIX requires
4/5
---
subst.c
- make sure quote_escapes is only ever called when the word to be
escaped is not marked as double-quoted -- cleaner, and allows us
to make certain assumptions
4/6
---
subst.c
- change all EX_* defines to begin with SX_
- new flag, SX_NOCTLESC, obeyed by string_extract_verbatim, tells it
to not obey CTLESC quoting
- change quote_escapes to not quote CTLESC with CTLESC if one of the
chars in $IFS is CTLESC, since the return value from quote_string
will be passed to word splitting and filename generation
- change read_comsub to do the same thing for unquoted command
substitutions
- change list_string to pass SX_NOCTLESC if CTLESC is one of the
chars in $IFS, so it will split on CTLESC instead of using it as a
quote character
4/7
---
subst.c
- slight change to string_extract_verbatim to allow CTLESC to quote
CTLNUL even if SX_NOCTLESC is set in the flags passed, to protect
the CTLNULs from future calls to remove_quoted_nulls. Only
matters when $IFS contains CTLESC
+7 -1
View File
@@ -702,6 +702,8 @@ tests/array1.sub f
tests/array2.sub f
tests/array3.sub f
tests/array4.sub f
tests/array5.sub f
tests/array6.sub f
tests/array-at-star f
tests/array2.right f
tests/braces.tests f
@@ -749,8 +751,9 @@ tests/exec4.sub f
tests/exec5.sub f
tests/exec6.sub f
tests/exec7.sub f
tests/exp-tests f
tests/exp.tests f
tests/exp.right f
tests/exp1.sub f
tests/extglob.tests f
tests/extglob.right f
tests/extglob1.sub f
@@ -823,6 +826,8 @@ tests/nquote3.tests f
tests/nquote3.right f
tests/nquote4.tests f
tests/nquote4.right f
tests/nquote5.tests f
tests/nquote5.right f
tests/posix2.tests f
tests/posix2.right f
tests/posixpat.tests f
@@ -900,6 +905,7 @@ tests/run-nquote1 f
tests/run-nquote2 f
tests/run-nquote3 f
tests/run-nquote4 f
tests/run-nquote5 f
tests/run-posix2 f
tests/run-posixpat f
tests/run-precedence f
+1006
View File
File diff suppressed because it is too large Load Diff
+31 -9
View File
@@ -1,7 +1,7 @@
This file is read.def, from which is created read.c.
It implements the builtin "read" in Bash.
Copyright (C) 1987-2005 Free Software Foundation, Inc.
Copyright (C) 1987-2007 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -127,14 +127,14 @@ read_builtin (list)
WORD_LIST *list;
{
register char *varname;
int size, i, nr, pass_next, saw_escape, eof, opt, retval, code;
int input_is_tty, input_is_pipe, unbuffered_read;
int size, i, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2;
int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc, skip_ctlnul;
int raw, edit, nchars, silent, have_timeout, fd;
unsigned int tmout;
intmax_t intval;
char c;
char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
char *e, *t, *t1;
char *e, *t, *t1, *ps2;
struct stat tsb;
SHELL_VAR *var;
#if defined (ARRAY_VARS)
@@ -148,6 +148,7 @@ read_builtin (list)
USE_VAR(size);
USE_VAR(i);
USE_VAR(pass_next);
USE_VAR(print_ps2);
USE_VAR(saw_escape);
USE_VAR(input_is_pipe);
/* USE_VAR(raw); */
@@ -163,6 +164,7 @@ read_builtin (list)
USE_VAR(rlind);
#endif
USE_VAR(list);
USE_VAR(ps2);
i = 0; /* Index into the string that we are reading. */
raw = edit = 0; /* Not reading raw input by default. */
@@ -261,6 +263,8 @@ read_builtin (list)
ifs_chars = getifs ();
if (ifs_chars == 0) /* XXX - shouldn't happen */
ifs_chars = "";
for (skip_ctlesc = skip_ctlnul = 0, e = ifs_chars; *e; e++)
skip_ctlesc |= *e == CTLESC, skip_ctlnul |= *e == CTLNUL;
input_string = (char *)xmalloc (size = 112); /* XXX was 128 */
@@ -386,7 +390,8 @@ read_builtin (list)
setmode (0, O_TEXT);
#endif
for (eof = retval = 0;;)
ps2 = 0;
for (print_ps2 = eof = retval = 0;;)
{
#if defined (READLINE)
if (edit)
@@ -412,6 +417,15 @@ read_builtin (list)
{
#endif
if (print_ps2)
{
if (ps2 == 0)
ps2 = get_string_value ("PS2");
fprintf (stderr, "%s", ps2 ? ps2 : "");
fflush (stderr);
print_ps2 = 0;
}
if (unbuffered_read)
retval = zread (fd, &c, 1);
else
@@ -440,24 +454,32 @@ read_builtin (list)
{
pass_next = 0;
if (c == '\n')
i--; /* back up over the CTLESC */
{
i--; /* back up over the CTLESC */
if (interactive && raw == 0)
print_ps2 = 1;
}
else
goto add_char;
continue;
}
/* This may cause problems if IFS contains CTLESC */
if (c == '\\' && raw == 0)
{
pass_next++;
saw_escape++;
input_string[i++] = CTLESC;
if (skip_ctlesc == 0)
{
saw_escape++;
input_string[i++] = CTLESC;
}
continue;
}
if ((unsigned char)c == delim)
break;
if (c == CTLESC || c == CTLNUL)
if ((skip_ctlesc == 0 && c == CTLESC) || (skip_ctlnul == 0 && c == CTLNUL))
{
saw_escape++;
input_string[i++] = CTLESC;
+806
View File
@@ -0,0 +1,806 @@
This file is read.def, from which is created read.c.
It implements the builtin "read" in Bash.
Copyright (C) 1987-2007 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 2, 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; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
$PRODUCES read.c
$BUILTIN read
$FUNCTION read_builtin
$SHORT_DOC read [-ers] [-a array] [-d delim] [-n nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
One line is read from the standard input, or from file descriptor FD if the
-u option is supplied, and the first word is assigned to the first NAME,
the second word to the second NAME, and so on, with leftover words assigned
to the last NAME. Only the characters found in $IFS are recognized as word
delimiters. If no NAMEs are supplied, the line read is stored in the REPLY
variable. If the -r option is given, this signifies `raw' input, and
backslash escaping is disabled. The -d option causes read to continue
until the first character of DELIM is read, rather than newline. If the -p
option is supplied, the string PROMPT is output without a trailing newline
before attempting to read. If -a is supplied, the words read are assigned
to sequential indices of ARRAY, starting at zero. If -e is supplied and
the shell is interactive, readline is used to obtain the line. If -n is
supplied with a non-zero NCHARS argument, read returns after NCHARS
characters have been read. The -s option causes input coming from a
terminal to not be echoed.
The -t option causes read to time out and return failure if a complete line
of input is not read within TIMEOUT seconds. If the TMOUT variable is set,
its value is the default timeout. The return code is zero, unless end-of-file
is encountered, read times out, or an invalid file descriptor is supplied as
the argument to -u.
$END
#include <config.h>
#include "bashtypes.h"
#include "posixstat.h"
#include <stdio.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <signal.h>
#include <errno.h>
#ifdef __CYGWIN__
# include <fcntl.h>
# include <io.h>
#endif
#include "../bashintl.h"
#include "../shell.h"
#include "common.h"
#include "bashgetopt.h"
#include <shtty.h>
#if defined (READLINE)
#include "../bashline.h"
#include <readline/readline.h>
#endif
#if defined (BUFFERED_INPUT)
# include "input.h"
#endif
#if !defined(errno)
extern int errno;
#endif
#if defined (READLINE)
static void reset_attempted_completion_function __P((char *));
static char *edit_line __P((char *));
static void set_eol_delim __P((int));
static void reset_eol_delim __P((char *));
#endif
static SHELL_VAR *bind_read_variable __P((char *, char *));
static sighandler sigalrm __P((int));
static void reset_alarm __P((void));
static procenv_t alrmbuf;
static SigHandler *old_alrm;
static unsigned char delim;
static sighandler
sigalrm (s)
int s;
{
longjmp (alrmbuf, 1);
}
static void
reset_alarm ()
{
set_signal_handler (SIGALRM, old_alrm);
alarm (0);
}
/* Read the value of the shell variables whose names follow.
The reading is done from the current input stream, whatever
that may be. Successive words of the input line are assigned
to the variables mentioned in LIST. The last variable in LIST
gets the remainder of the words on the line. If no variables
are mentioned in LIST, then the default variable is $REPLY. */
int
read_builtin (list)
WORD_LIST *list;
{
register char *varname;
int size, i, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2;
int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc;
int raw, edit, nchars, silent, have_timeout, fd;
unsigned int tmout;
intmax_t intval;
char c;
char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
char *e, *t, *t1, *ps2;
struct stat tsb;
SHELL_VAR *var;
#if defined (ARRAY_VARS)
WORD_LIST *alist;
#endif
#if defined (READLINE)
char *rlbuf;
int rlind;
#endif
USE_VAR(size);
USE_VAR(i);
USE_VAR(pass_next);
USE_VAR(print_ps2);
USE_VAR(saw_escape);
USE_VAR(input_is_pipe);
/* USE_VAR(raw); */
USE_VAR(edit);
USE_VAR(tmout);
USE_VAR(nchars);
USE_VAR(silent);
USE_VAR(ifs_chars);
USE_VAR(prompt);
USE_VAR(arrayname);
#if defined (READLINE)
USE_VAR(rlbuf);
USE_VAR(rlind);
#endif
USE_VAR(list);
USE_VAR(ps2);
i = 0; /* Index into the string that we are reading. */
raw = edit = 0; /* Not reading raw input by default. */
silent = 0;
arrayname = prompt = (char *)NULL;
fd = 0; /* file descriptor to read from */
#if defined (READLINE)
rlbuf = (char *)0;
rlind = 0;
#endif
tmout = 0; /* no timeout */
nr = nchars = input_is_tty = input_is_pipe = unbuffered_read = have_timeout = 0;
delim = '\n'; /* read until newline */
reset_internal_getopt ();
while ((opt = internal_getopt (list, "ersa:d:n:p:t:u:")) != -1)
{
switch (opt)
{
case 'r':
raw = 1;
break;
case 'p':
prompt = list_optarg;
break;
case 's':
silent = 1;
break;
case 'e':
#if defined (READLINE)
edit = 1;
#endif
break;
#if defined (ARRAY_VARS)
case 'a':
arrayname = list_optarg;
break;
#endif
case 't':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (unsigned int)intval)
{
builtin_error (_("%s: invalid timeout specification"), list_optarg);
return (EXECUTION_FAILURE);
}
else
{
have_timeout = 1;
tmout = intval;
}
break;
case 'n':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (int)intval)
{
sh_invalidnum (list_optarg);
return (EXECUTION_FAILURE);
}
else
nchars = intval;
break;
case 'u':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (int)intval)
{
builtin_error (_("%s: invalid file descriptor specification"), list_optarg);
return (EXECUTION_FAILURE);
}
else
fd = intval;
if (sh_validfd (fd) == 0)
{
builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno));
return (EXECUTION_FAILURE);
}
break;
case 'd':
delim = *list_optarg;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
/* `read -t 0 var' returns failure immediately. XXX - should it test
whether input is available with select/FIONREAD, and fail if those
are unavailable? */
if (have_timeout && tmout == 0)
return (EXECUTION_FAILURE);
/* IF IFS is unset, we use the default of " \t\n". */
ifs_chars = getifs ();
if (ifs_chars == 0) /* XXX - shouldn't happen */
ifs_chars = "";
for (skip_ctlesc = 0, e = ifs_chars; *e; e++)
skip_ctlesc |= *e == CTLESC;
input_string = (char *)xmalloc (size = 112); /* XXX was 128 */
/* $TMOUT, if set, is the default timeout for read. */
if (have_timeout == 0 && (e = get_string_value ("TMOUT")))
{
code = legal_number (e, &intval);
if (code == 0 || intval < 0 || intval != (unsigned int)intval)
tmout = 0;
else
tmout = intval;
}
begin_unwind_frame ("read_builtin");
#if defined (BUFFERED_INPUT)
if (interactive == 0 && default_buffered_input >= 0 && fd_is_bash_input (fd))
sync_buffered_stream (default_buffered_input);
#endif
input_is_tty = isatty (fd);
if (input_is_tty == 0)
#ifndef __CYGWIN__
input_is_pipe = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
#else
input_is_pipe = 1;
#endif
/* If the -p, -e or -s flags were given, but input is not coming from the
terminal, turn them off. */
if ((prompt || edit || silent) && input_is_tty == 0)
{
prompt = (char *)NULL;
edit = silent = 0;
}
#if defined (READLINE)
if (edit)
add_unwind_protect (xfree, rlbuf);
#endif
if (prompt && edit == 0)
{
fprintf (stderr, "%s", prompt);
fflush (stderr);
}
pass_next = 0; /* Non-zero signifies last char was backslash. */
saw_escape = 0; /* Non-zero signifies that we saw an escape char */
if (tmout > 0)
{
/* Turn off the timeout if stdin is a regular file (e.g. from
input redirection). */
if ((fstat (fd, &tsb) < 0) || S_ISREG (tsb.st_mode))
tmout = 0;
}
if (tmout > 0)
{
code = setjmp (alrmbuf);
if (code)
{
run_unwind_frame ("read_builtin");
return (EXECUTION_FAILURE);
}
old_alrm = set_signal_handler (SIGALRM, sigalrm);
add_unwind_protect (reset_alarm, (char *)NULL);
#if defined (READLINE)
if (edit)
add_unwind_protect (reset_attempted_completion_function, (char *)NULL);
#endif
alarm (tmout);
}
/* If we've been asked to read only NCHARS chars, or we're using some
character other than newline to terminate the line, do the right
thing to readline or the tty. */
if (nchars > 0 || delim != '\n')
{
#if defined (READLINE)
if (edit)
{
if (nchars > 0)
{
unwind_protect_int (rl_num_chars_to_read);
rl_num_chars_to_read = nchars;
}
if (delim != '\n')
{
set_eol_delim (delim);
add_unwind_protect (reset_eol_delim, (char *)NULL);
}
}
else
#endif
if (input_is_tty)
{
ttsave ();
if (silent)
ttcbreak ();
else
ttonechar ();
add_unwind_protect ((Function *)ttrestore, (char *)NULL);
}
}
else if (silent) /* turn off echo but leave term in canonical mode */
{
ttsave ();
ttnoecho ();
add_unwind_protect ((Function *)ttrestore, (char *)NULL);
}
/* This *must* be the top unwind-protect on the stack, so the manipulation
of the unwind-protect stack after the realloc() works right. */
add_unwind_protect (xfree, input_string);
interrupt_immediately++;
terminate_immediately = 1;
unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe;
#if defined (__CYGWIN__) && defined (O_TEXT)
setmode (0, O_TEXT);
#endif
ps2 = 0;
for (print_ps2 = eof = retval = 0;;)
{
#if defined (READLINE)
if (edit)
{
if (rlbuf && rlbuf[rlind] == '\0')
{
xfree (rlbuf);
rlbuf = (char *)0;
}
if (rlbuf == 0)
{
rlbuf = edit_line (prompt ? prompt : "");
rlind = 0;
}
if (rlbuf == 0)
{
eof = 1;
break;
}
c = rlbuf[rlind++];
}
else
{
#endif
if (print_ps2)
{
if (ps2 == 0)
ps2 = get_string_value ("PS2");
fprintf (stderr, "%s", ps2 ? ps2 : "");
fflush (stderr);
print_ps2 = 0;
}
if (unbuffered_read)
retval = zread (fd, &c, 1);
else
retval = zreadc (fd, &c);
if (retval <= 0)
{
eof = 1;
break;
}
#if defined (READLINE)
}
#endif
if (i + 2 >= size)
{
input_string = (char *)xrealloc (input_string, size += 128);
remove_unwind_protect ();
add_unwind_protect (xfree, input_string);
}
/* If the next character is to be accepted verbatim, a backslash
newline pair still disappears from the input. */
if (pass_next)
{
pass_next = 0;
if (c == '\n')
{
i--; /* back up over the CTLESC */
if (interactive && raw == 0)
print_ps2 = 1;
}
else
goto add_char;
continue;
}
/* This may cause problems if IFS contains CTLESC */
if (c == '\\' && raw == 0)
{
pass_next++;
if (skip_ctlesc == 0)
{
saw_escape++;
input_string[i++] = CTLESC;
}
continue;
}
if ((unsigned char)c == delim)
break;
if ((skip_ctlesc == 0 && c == CTLESC) || c == CTLNUL)
{
saw_escape++;
input_string[i++] = CTLESC;
}
add_char:
input_string[i++] = c;
nr++;
if (nchars > 0 && nr >= nchars)
break;
}
input_string[i] = '\0';
#if 1
if (retval < 0)
{
builtin_error (_("read error: %d: %s"), fd, strerror (errno));
run_unwind_frame ("read_builtin");
return (EXECUTION_FAILURE);
}
#endif
if (tmout > 0)
reset_alarm ();
if (nchars > 0 || delim != '\n')
{
#if defined (READLINE)
if (edit)
{
if (nchars > 0)
rl_num_chars_to_read = 0;
if (delim != '\n')
reset_eol_delim ((char *)NULL);
}
else
#endif
if (input_is_tty)
ttrestore ();
}
else if (silent)
ttrestore ();
if (unbuffered_read == 0)
zsyncfd (fd);
interrupt_immediately--;
terminate_immediately = 0;
discard_unwind_frame ("read_builtin");
retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
#if defined (ARRAY_VARS)
/* If -a was given, take the string read, break it into a list of words,
an assign them to `arrayname' in turn. */
if (arrayname)
{
if (legal_identifier (arrayname) == 0)
{
sh_invalidid (arrayname);
xfree (input_string);
return (EXECUTION_FAILURE);
}
var = find_or_make_array_variable (arrayname, 1);
if (var == 0)
{
xfree (input_string);
return EXECUTION_FAILURE; /* readonly or noassign */
}
array_flush (array_cell (var));
alist = list_string (input_string, ifs_chars, 0);
if (alist)
{
if (saw_escape)
dequote_list (alist);
else
word_list_remove_quoted_nulls (alist);
assign_array_var_from_word_list (var, alist, 0);
dispose_words (alist);
}
xfree (input_string);
return (retval);
}
#endif /* ARRAY_VARS */
/* If there are no variables, save the text of the line read to the
variable $REPLY. ksh93 strips leading and trailing IFS whitespace,
so that `read x ; echo "$x"' and `read ; echo "$REPLY"' behave the
same way, but I believe that the difference in behaviors is useful
enough to not do it. Without the bash behavior, there is no way
to read a line completely without interpretation or modification
unless you mess with $IFS (e.g., setting it to the empty string).
If you disagree, change the occurrences of `#if 0' to `#if 1' below. */
if (list == 0)
{
#if 0
orig_input_string = input_string;
for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++)
;
input_string = t;
input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape);
#endif
if (saw_escape)
{
t = dequote_string (input_string);
var = bind_variable ("REPLY", t, 0);
free (t);
}
else
var = bind_variable ("REPLY", input_string, 0);
VUNSETATTR (var, att_invisible);
free (input_string);
return (retval);
}
/* This code implements the Posix.2 spec for splitting the words
read and assigning them to variables. */
orig_input_string = input_string;
/* Remove IFS white space at the beginning of the input string. If
$IFS is null, no field splitting is performed. */
for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++)
;
input_string = t;
for (; list->next; list = list->next)
{
varname = list->word->word;
#if defined (ARRAY_VARS)
if (legal_identifier (varname) == 0 && valid_array_reference (varname) == 0)
#else
if (legal_identifier (varname) == 0)
#endif
{
sh_invalidid (varname);
xfree (orig_input_string);
return (EXECUTION_FAILURE);
}
/* If there are more variables than words read from the input,
the remaining variables are set to the empty string. */
if (*input_string)
{
/* This call updates INPUT_STRING. */
t = get_word_from_string (&input_string, ifs_chars, &e);
if (t)
*e = '\0';
/* Don't bother to remove the CTLESC unless we added one
somewhere while reading the string. */
if (t && saw_escape)
{
t1 = dequote_string (t);
var = bind_read_variable (varname, t1);
xfree (t1);
}
else
var = bind_read_variable (varname, t);
}
else
{
t = (char *)0;
var = bind_read_variable (varname, "");
}
FREE (t);
if (var == 0)
{
xfree (orig_input_string);
return (EXECUTION_FAILURE);
}
stupidly_hack_special_variables (varname);
VUNSETATTR (var, att_invisible);
}
/* Now assign the rest of the line to the last variable argument. */
#if defined (ARRAY_VARS)
if (legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word) == 0)
#else
if (legal_identifier (list->word->word) == 0)
#endif
{
sh_invalidid (list->word->word);
xfree (orig_input_string);
return (EXECUTION_FAILURE);
}
#if 0
/* This has to be done this way rather than using string_list
and list_string because Posix.2 says that the last variable gets the
remaining words and their intervening separators. */
input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape);
#else
/* Check whether or not the number of fields is exactly the same as the
number of variables. */
if (*input_string)
{
t1 = input_string;
t = get_word_from_string (&input_string, ifs_chars, &e);
if (*input_string == 0)
input_string = t;
else
input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape);
}
#endif
if (saw_escape)
{
t = dequote_string (input_string);
var = bind_read_variable (list->word->word, t);
xfree (t);
}
else
var = bind_read_variable (list->word->word, input_string);
stupidly_hack_special_variables (list->word->word);
if (var)
VUNSETATTR (var, att_invisible);
xfree (orig_input_string);
return (retval);
}
static SHELL_VAR *
bind_read_variable (name, value)
char *name, *value;
{
#if defined (ARRAY_VARS)
if (valid_array_reference (name) == 0)
return (bind_variable (name, value, 0));
else
return (assign_array_element (name, value, 0));
#else /* !ARRAY_VARS */
return bind_variable (name, value, 0);
#endif /* !ARRAY_VARS */
}
#if defined (READLINE)
static rl_completion_func_t *old_attempted_completion_function = 0;
static void
reset_attempted_completion_function (cp)
char *cp;
{
if (rl_attempted_completion_function == 0 && old_attempted_completion_function)
rl_attempted_completion_function = old_attempted_completion_function;
}
static char *
edit_line (p)
char *p;
{
char *ret;
int len;
if (bash_readline_initialized == 0)
initialize_readline ();
old_attempted_completion_function = rl_attempted_completion_function;
rl_attempted_completion_function = (rl_completion_func_t *)NULL;
ret = readline (p);
rl_attempted_completion_function = old_attempted_completion_function;
old_attempted_completion_function = (rl_completion_func_t *)NULL;
if (ret == 0)
return ret;
len = strlen (ret);
ret = (char *)xrealloc (ret, len + 2);
ret[len++] = delim;
ret[len] = '\0';
return ret;
}
static int old_delim_ctype;
static rl_command_func_t *old_delim_func;
static int old_newline_ctype;
static rl_command_func_t *old_newline_func;
static unsigned char delim_char;
static void
set_eol_delim (c)
int c;
{
Keymap cmap;
if (bash_readline_initialized == 0)
initialize_readline ();
cmap = rl_get_keymap ();
/* Change newline to self-insert */
old_newline_ctype = cmap[RETURN].type;
old_newline_func = cmap[RETURN].function;
cmap[RETURN].type = ISFUNC;
cmap[RETURN].function = rl_insert;
/* Bind the delimiter character to accept-line. */
old_delim_ctype = cmap[c].type;
old_delim_func = cmap[c].function;
cmap[c].type = ISFUNC;
cmap[c].function = rl_newline;
delim_char = c;
}
static void
reset_eol_delim (cp)
char *cp;
{
Keymap cmap;
cmap = rl_get_keymap ();
cmap[RETURN].type = old_newline_ctype;
cmap[RETURN].function = old_newline_func;
cmap[delim_char].type = old_delim_ctype;
cmap[delim_char].function = old_delim_func;
}
#endif
+32 -10
View File
@@ -1,7 +1,7 @@
This file is read.def, from which is created read.c.
It implements the builtin "read" in Bash.
Copyright (C) 1987-2005 Free Software Foundation, Inc.
Copyright (C) 1987-2007 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -23,7 +23,7 @@ $PRODUCES read.c
$BUILTIN read
$FUNCTION read_builtin
$SHORT_DOC read [-ers] [-u fd] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...]
$SHORT_DOC read [-ers] [-a array] [-d delim] [-n nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
One line is read from the standard input, or from file descriptor FD if the
-u option is supplied, and the first word is assigned to the first NAME,
the second word to the second NAME, and so on, with leftover words assigned
@@ -127,14 +127,14 @@ read_builtin (list)
WORD_LIST *list;
{
register char *varname;
int size, i, nr, pass_next, saw_escape, eof, opt, retval, code;
int input_is_tty, input_is_pipe, unbuffered_read;
int size, i, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2;
int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc;
int raw, edit, nchars, silent, have_timeout, fd;
unsigned int tmout;
intmax_t intval;
char c;
char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
char *e, *t, *t1;
char *e, *t, *t1, *ps2;
struct stat tsb;
SHELL_VAR *var;
#if defined (ARRAY_VARS)
@@ -148,6 +148,7 @@ read_builtin (list)
USE_VAR(size);
USE_VAR(i);
USE_VAR(pass_next);
USE_VAR(print_ps2);
USE_VAR(saw_escape);
USE_VAR(input_is_pipe);
/* USE_VAR(raw); */
@@ -163,6 +164,7 @@ read_builtin (list)
USE_VAR(rlind);
#endif
USE_VAR(list);
USE_VAR(ps2);
i = 0; /* Index into the string that we are reading. */
raw = edit = 0; /* Not reading raw input by default. */
@@ -261,6 +263,8 @@ read_builtin (list)
ifs_chars = getifs ();
if (ifs_chars == 0) /* XXX - shouldn't happen */
ifs_chars = "";
for (skip_ctlesc = 0, e = ifs_chars; *e; e++)
skip_ctlesc |= *e == CTLESC;
input_string = (char *)xmalloc (size = 112); /* XXX was 128 */
@@ -386,7 +390,8 @@ read_builtin (list)
setmode (0, O_TEXT);
#endif
for (eof = retval = 0;;)
ps2 = 0;
for (print_ps2 = eof = retval = 0;;)
{
#if defined (READLINE)
if (edit)
@@ -412,6 +417,15 @@ read_builtin (list)
{
#endif
if (print_ps2)
{
if (ps2 == 0)
ps2 = get_string_value ("PS2");
fprintf (stderr, "%s", ps2 ? ps2 : "");
fflush (stderr);
print_ps2 = 0;
}
if (unbuffered_read)
retval = zread (fd, &c, 1);
else
@@ -440,24 +454,32 @@ read_builtin (list)
{
pass_next = 0;
if (c == '\n')
i--; /* back up over the CTLESC */
{
i--; /* back up over the CTLESC */
if (interactive && raw == 0)
print_ps2 = 1;
}
else
goto add_char;
continue;
}
/* This may cause problems if IFS contains CTLESC */
if (c == '\\' && raw == 0)
{
pass_next++;
saw_escape++;
input_string[i++] = CTLESC;
if (skip_ctlesc == 0)
{
saw_escape++;
input_string[i++] = CTLESC;
}
continue;
}
if ((unsigned char)c == delim)
break;
if (c == CTLESC || c == CTLNUL)
if ((skip_ctlesc == 0 && c == CTLESC) || c == CTLNUL)
{
saw_escape++;
input_string[i++] = CTLESC;
+1 -2
View File
@@ -2,7 +2,6 @@
.\" MAN PAGE COMMENTS to
.\"
.\" Chet Ramey
.\" Information Network Services
.\" Case Western Reserve University
.\" chet@po.cwru.edu
.\"
@@ -2570,7 +2569,7 @@ The \fIpattern\fP is expanded to produce a pattern just as in
pathname expansion.
\fIParameter\fP is expanded and the longest match of \fIpattern\fP
against its value is replaced with \fIstring\fP.
If \Ipattern\fP begins with \fB/\fP, all matches of \fIpattern\fP are
If \fIpattern\fP begins with \fB/\fP, all matches of \fIpattern\fP are
replaced with \fIstring\fP. Normally only the first match is replaced.
If \fIpattern\fP begins with \fB#\fP, it must match at the beginning
of the expanded value of \fIparameter\fP.
+33 -49
View File
@@ -1,66 +1,50 @@
BASHBUG(1) BASHBUG(1)
BASHBUG(1) BASHBUG(1)
NNAAMMEE
bashbug - report a bug in bash
SSYYNNOOPPSSIISS
bbaasshhbbuugg [_a_d_d_r_e_s_s]
bbaasshhbbuugg [_-_-_v_e_r_s_i_o_n] [_-_-_h_e_l_p] [_e_m_a_i_l_-_a_d_d_r_e_s_s]
DDEESSCCRRIIPPTTIIOONN
bbaasshhbbuugg is a shell script to help the user compose and
mail bug reports concerning bash in a standard format.
bbaasshhbbuugg invokes the editor specified by the environment
variable EEDDIITTOORR on a temporary copy of the bug report for-
mat outline. The user must fill in the appropriate fields
and exit the editor. bbaasshhbbuugg then mails the completed
report to _b_u_g_-_b_a_s_h_@_g_n_u_._o_r_g, or _a_d_d_r_e_s_s. If the report
cannot be mailed, it is saved in the file _d_e_a_d_._b_a_s_h_b_u_g in
the invoking user's home directory.
bbaasshhbbuugg is a shell script to help the user compose and mail bug reports
concerning bash in a standard format. bbaasshhbbuugg invokes the editor spec-
ified by the environment variable EEDDIITTOORR on a temporary copy of the bug
report format outline. The user must fill in the appropriate fields and
exit the editor. bbaasshhbbuugg then mails the completed report to _b_u_g_-
_b_a_s_h_@_g_n_u_._o_r_g, or _e_m_a_i_l_-_a_d_d_r_e_s_s. If the report cannot be mailed, it is
saved in the file _d_e_a_d_._b_a_s_h_b_u_g in the invoking user's home directory.
The bug report format outline consists of several sec-
tions. The first section provides information about the
machine, operating system, the bash version, and the com-
pilation environment. The second section should be filled
in with a description of the bug. The third section
should be a description of how to reproduce the bug. The
optional fourth section is for a proposed fix. Fixes are
encouraged.
The bug report format outline consists of several sections. The first
section provides information about the machine, operating system, the
bash version, and the compilation environment. The second section
should be filled in with a description of the bug. The third section
should be a description of how to reproduce the bug. The optional
fourth section is for a proposed fix. Fixes are encouraged.
EENNVVIIRROONNMMEENNTT
bbaasshhbbuugg will utilize the following environment variables
if they exist:
bbaasshhbbuugg will utilize the following environment variables if they exist:
EEDDIITTOORR Specifies the preferred editor. If EEDDIITTOORR is not
set, bbaasshhbbuugg defaults to eemmaaccss.
EEDDIITTOORR Specifies the preferred editor. If EEDDIITTOORR is not set, bbaasshhbbuugg
defaults to eemmaaccss.
HHOOMMEE Directory in which the failed bug report is saved
if the mail fails.
HHOOMMEE Directory in which the failed bug report is saved if the mail
fails.
TTMMPPDDIIRR Directory in which to create temporary files and directories.
SSEEEE AALLSSOO
_b_a_s_h(1)
AAUUTTHHOORRSS
Brian Fox, Free Software Foundation
bfox@gnu.org
Chet Ramey, Case Western Reserve University
chet@po.cwru.edu
GNU 1998 July 30 1
GNU Bash-3.2 1998 July 30 BASHBUG(1)
+26 -3
View File
@@ -1,8 +1,17 @@
.TH BASHBUG 1 "1998 July 30" GNU
.\"
.\" MAN PAGE COMMENTS to
.\"
.\" Chet Ramey
.\" Case Western Reserve University
.\" chet@po.cwru.edu
.\"
.\" Last Change: Tue Apr 3 15:46:30 EDT 2007
.\"
.TH BASHBUG 1 "1998 July 30" "GNU Bash-3.2"
.SH NAME
bashbug \- report a bug in bash
.SH SYNOPSIS
\fBbashbug\fP [\fIaddress\fP]
\fBbashbug\fP [\fI--version\fP] [\fI--help\fP] [\fIemail-address\fP]
.SH DESCRIPTION
.B bashbug
is a shell script to help the user compose and mail bug reports
@@ -15,7 +24,7 @@ on a temporary copy of the bug report format outline. The user must
fill in the appropriate fields and exit the editor.
.B bashbug
then mails the completed report to \fIbug-bash@gnu.org\fP, or
\fIaddress\fP. If the report cannot be mailed, it is saved in the
\fIemail-address\fP. If the report cannot be mailed, it is saved in the
file \fIdead.bashbug\fP in the invoking user's home directory.
.PP
The bug report format outline consists of several sections. The first
@@ -39,3 +48,17 @@ defaults to
.TP
.B HOME
Directory in which the failed bug report is saved if the mail fails.
.TP
.B TMPDIR
Directory in which to create temporary files and directories.
.SH "SEE ALSO"
.TP
\fIbash\fP(1)
.SH AUTHORS
Brian Fox, Free Software Foundation
.br
bfox@gnu.org
.PP
Chet Ramey, Case Western Reserve University
.br
chet@po.cwru.edu
+65 -31
View File
@@ -1,16 +1,21 @@
%!PS-Adobe-3.0
%%Creator: groff version 1.10
%%CreationDate: Wed Sep 30 13:53:50 1998
%%Creator: groff version 1.19.1
%%CreationDate: Tue Apr 3 15:54:18 2007
%%DocumentNeededResources: font Times-Roman
%%+ font Times-Bold
%%+ font Times-Italic
%%DocumentSuppliedResources: procset grops 1.10 0
%%DocumentSuppliedResources: procset grops 1.19 1
%%Pages: 1
%%PageOrder: Ascend
%%DocumentMedia: Default 595 842 0 () ()
%%Orientation: Portrait
%%EndComments
%%BeginDefaults
%%PageMedia: Default
%%EndDefaults
%%BeginProlog
%%BeginResource: procset grops 1.10 0
%%BeginResource: procset grops 1.19 1
%!PS-Adobe-3.0 Resource-ProcSet
/setpacking where{
pop
currentpacking
@@ -108,11 +113,26 @@ TM setmatrix
/ST/stroke load def
/MT/moveto load def
/CL/closepath load def
/FL{
currentgray exch setgray fill setgray
/Fr{
setrgbcolor fill
}bind def
/BL/fill load def
/setcmykcolor where{
pop
/Fk{
setcmykcolor fill
}bind def
}if
/Fg{
setgray fill
}bind def
/FL/fill load def
/LW/setlinewidth load def
/Cr/setrgbcolor load def
/setcmykcolor where{
pop
/Ck/setcmykcolor load def
}if
/Cg/setgray load def
/RE{
findfont
dup maxlength 1 index/FontName known not{1 add}if dict begin
@@ -154,6 +174,7 @@ newpath
/CNT countdictstack def
userdict begin
/showpage{}def
/setpagedevice{}def
}bind def
/PEND{
clear
@@ -166,15 +187,20 @@ pop
setpacking
}if
%%EndResource
%%EndProlog
%%BeginSetup
%%BeginFeature: *PageSize Default
<< /PageSize [ 595 842 ] /ImagingBBox null >> setpagedevice
%%EndFeature
%%IncludeResource: font Times-Roman
%%IncludeResource: font Times-Bold
%%IncludeResource: font Times-Italic
grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72
def/PL 792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron
/scaron/zcaron/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef
def/PL 841.89 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron
/Zcaron/scaron/zcaron/Ydieresis/trademark/quotesingle/Euro/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent
/.notdef/.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent
/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen
/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon
/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O
@@ -199,32 +225,33 @@ def/PL 792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron
/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def
/Times-Italic@0 ENC0/Times-Italic RE/Times-Bold@0 ENC0/Times-Bold RE
/Times-Roman@0 ENC0/Times-Roman RE
%%EndProlog
%%EndSetup
%%Page: 1 1
%%BeginPageSetup
BP
%%EndPageSetup
/F0 10/Times-Roman@0 SF -.35(BA)72 48 S(SHB).35 E 347.52(UG\(1\) B)-.1 F
(ASHB)-.35 E(UG\(1\))-.1 E/F1 9/Times-Bold@0 SF -.18(NA)72 84 S(ME).18 E
F0(bashb)108 96 Q(ug \255 report a b)-.2 E(ug in bash)-.2 E F1(SYNOPSIS)
72 112.8 Q/F2 10/Times-Bold@0 SF(bashb)108 124.8 Q(ug)-.2 E F0([)2.5 E
/F3 10/Times-Italic@0 SF(addr)A(ess)-.37 E F0(])A F1(DESCRIPTION)72
141.6 Q F2(bashb)108 153.6 Q(ug)-.2 E F0 .446
(ASHB)-.35 E(UG\(1\))-.1 E/F1 10.95/Times-Bold@0 SF -.219(NA)72 84 S(ME)
.219 E F0(bashb)108 96 Q(ug \255 report a b)-.2 E(ug in bash)-.2 E F1
(SYNOPSIS)72 112.8 Q/F2 10/Times-Bold@0 SF(bashb)108 124.8 Q(ug)-.2 E F0
([)2.5 E/F3 10/Times-Italic@0 SF(--ver)A(sion)-.1 E F0 2.5(][)C F3
(--help)-2.5 E F0 2.5(][)C F3(email-addr)-2.5 E(ess)-.37 E F0(])A F1
(DESCRIPTION)72 141.6 Q F2(bashb)108 153.6 Q(ug)-.2 E F0 .446
(is a shell script to help the user compose and mail b)2.947 F .446
(ug reports concerning bash in a standard for)-.2 F(-)-.2 E(mat.)108
165.6 Q F2(bashb)5.961 E(ug)-.2 E F0(in)3.461 E -.2(vo)-.4 G -.1(ke).2 G
3.461(st).1 G .962(he editor speci\214ed by the en)-3.461 F .962
(vironment v)-.4 F(ariable)-.25 E F1(EDIT)3.462 E(OR)-.162 E F0 .962
(on a temporary cop)3.212 F 3.462(yo)-.1 G(f)-3.462 E .374(the b)108
177.6 R .374(ug report format outline. The user must \214ll in the appr\
opriate \214elds and e)-.2 F .374(xit the editor)-.15 F(.)-.55 E F2
(bashb)5.373 E(ug)-.2 E F0(then)2.873 E .439
(mails the completed report to)108 189.6 R F3 -.2(bu)2.939 G
(g-bash@gnu.or).2 E(g)-.37 E F0 2.939(,o)C(r)-2.939 E F3(addr)2.939 E
(ess)-.37 E F0 5.439(.I)C 2.939(ft)-5.439 G .44
(he report cannot be mailed, it is sa)-2.939 F -.15(ve)-.2 G 2.94(di).15
G(n)-2.94 E(the \214le)108 201.6 Q F3(dead.bashb)2.5 E(ug)-.2 E F0
(in the in)2.5 E -.2(vo)-.4 G(king user').2 E 2.5(sh)-.55 G
(vironment v)-.4 F(ariable)-.25 E/F4 9/Times-Bold@0 SF(EDIT)3.462 E(OR)
-.162 E F0 .962(on a temporary cop)3.212 F 3.462(yo)-.1 G(f)-3.462 E
.374(the b)108 177.6 R .374(ug report format outline. The user must \
\214ll in the appropriate \214elds and e)-.2 F .374(xit the editor)-.15
F(.)-.55 E F2(bashb)5.373 E(ug)-.2 E F0(then)2.873 E 1.141
(mails the completed report to)108 189.6 R F3 -.2(bu)3.641 G
(g-bash@gnu.or).2 E(g)-.37 E F0 3.641(,o)C(r)-3.641 E F3(email-addr)
3.641 E(ess)-.37 E F0 6.141(.I)C 3.641(ft)-6.141 G 1.142
(he report cannot be mailed, it is)-3.641 F(sa)108 201.6 Q -.15(ve)-.2 G
2.5(di).15 G 2.5(nt)-2.5 G(he \214le)-2.5 E F3(dead.bashb)2.5 E(ug)-.2 E
F0(in the in)2.5 E -.2(vo)-.4 G(king user').2 E 2.5(sh)-.55 G
(ome directory)-2.5 E(.)-.65 E .354(The b)108 218.4 R .354
(ug report format outline consists of se)-.2 F -.15(ve)-.25 G .353
(ral sections.).15 F .353(The \214rst section pro)5.353 F .353
@@ -236,16 +263,23 @@ G(n)-2.94 E(the \214le)108 201.6 Q F3(dead.bashb)2.5 E(ug)-.2 E F0
-.2 F .208(third section should be a description of ho)2.709 F 2.708(wt)
-.25 G 2.708(or)-2.708 G .208(eproduce the)-2.708 F -.2(bu)108 254.4 S
2.5(g. The).2 F(optional fourth section is for a proposed \214x.)2.5 E
(Fix)5 E(es are encouraged.)-.15 E F1(ENVIR)72 271.2 Q(ONMENT)-.27 E F2
(Fix)5 E(es are encouraged.)-.15 E F1(ENVIR)72 271.2 Q(ONMENT)-.329 E F2
(bashb)108 283.2 Q(ug)-.2 E F0(will utilize the follo)2.5 E(wing en)-.25
E(vironment v)-.4 E(ariables if the)-.25 E 2.5(ye)-.15 G(xist:)-2.65 E
F2(EDIT)108 300 Q(OR)-.18 E F0(Speci\214es the preferred editor)144 312
Q 2.5(.I)-.55 G(f)-2.5 E F1(EDIT)2.5 E(OR)-.162 E F0(is not set,)2.25 E
Q 2.5(.I)-.55 G(f)-2.5 E F4(EDIT)2.5 E(OR)-.162 E F0(is not set,)2.25 E
F2(bashb)2.5 E(ug)-.2 E F0(def)2.5 E(aults to)-.1 E F2(emacs)2.5 E F0(.)
A F2(HOME)108 328.8 Q F0(Directory in which the f)144 340.8 Q(ailed b)
-.1 E(ug report is sa)-.2 E -.15(ve)-.2 G 2.5(di).15 G 2.5(ft)-2.5 G
(he mail f)-2.5 E(ails.)-.1 E 184.005(GNU 1998)72 768 R(July 30)2.5 E(1)
203.165 E EP
(he mail f)-2.5 E(ails.)-.1 E F2(TMPDIR)108 357.6 Q F0
(Directory in which to create temporary \214les and directories.)144
369.6 Q F1(SEE ALSO)72 386.4 Q F3(bash)108 398.4 Q F0(\(1\))A F1 -.548
(AU)72 415.2 S(THORS).548 E F0(Brian F)108 427.2 Q(ox, Free Softw)-.15 E
(are F)-.1 E(oundation)-.15 E(bfox@gnu.or)108 439.2 Q(g)-.18 E
(Chet Rame)108 456 Q 1.3 -.65(y, C)-.15 H(ase W).65 E(estern Reserv)-.8
E 2.5(eU)-.15 G(ni)-2.5 E -.15(ve)-.25 G(rsity).15 E(chet@po.cwru.edu)
108 468 Q(GNU Bash-3.2)72 768 Q(1998 July 30)148.175 E(1)203.165 E 0 Cg
EP
%%Trailer
end
%%EOF
+86 -72
View File
@@ -79,10 +79,12 @@ extern int errno;
#define ST_DQUOTE 0x08 /* unused yet */
/* Flags for the string extraction functions. */
#define EX_NOALLOC 0x01 /* just skip; don't return substring */
#define EX_VARNAME 0x02 /* variable name; for string_extract () */
#define EX_REQMATCH 0x04 /* closing/matching delimiter required */
#define EX_COMMAND 0x08 /* extracting a shell script/command */
#define SX_NOALLOC 0x01 /* just skip; don't return substring */
#define SX_VARNAME 0x02 /* variable name; for string_extract () */
#define SX_REQMATCH 0x04 /* closing/matching delimiter required */
#define SX_COMMAND 0x08 /* extracting a shell script/command */
#define SX_NOCTLESC 0x10 /* don't honor CTLESC quoting */
#define SX_NOESCCTLNUL 0x20 /* don't let CTLESC quote CTLNUL */
/* Flags for the `pflags' argument to param_expand() */
#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */
@@ -543,11 +545,11 @@ sub_append_number (number, target, indx, size)
/* Extract a substring from STRING, starting at SINDEX and ending with
one of the characters in CHARLIST. Don't make the ending character
part of the string. Leave SINDEX pointing at the ending character.
Understand about backslashes in the string. If (flags & EX_VARNAME)
Understand about backslashes in the string. If (flags & SX_VARNAME)
is non-zero, and array variables have been compiled into the shell,
everything between a `[' and a corresponding `]' is skipped over.
If (flags & EX_NOALLOC) is non-zero, don't return the substring, just
update SINDEX. If (flags & EX_REQMATCH) is non-zero, the string must
If (flags & SX_NOALLOC) is non-zero, don't return the substring, just
update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must
contain a closing character from CHARLIST. */
static char *
string_extract (string, sindex, charlist, flags)
@@ -575,7 +577,7 @@ string_extract (string, sindex, charlist, flags)
break;
}
#if defined (ARRAY_VARS)
else if ((flags & EX_VARNAME) && c == '[')
else if ((flags & SX_VARNAME) && c == '[')
{
int ni;
/* If this is an array subscript, skip over it and continue. */
@@ -595,13 +597,13 @@ string_extract (string, sindex, charlist, flags)
/* If we had to have a matching delimiter and didn't find one, return an
error and let the caller deal with it. */
if ((flags & EX_REQMATCH) && found == 0)
if ((flags & SX_REQMATCH) && found == 0)
{
*sindex = i;
return (&extract_string_error);
}
temp = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
*sindex = i;
return (temp);
@@ -712,7 +714,7 @@ add_one_character:
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_COMMAND); /*)*/
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_COMMAND); /*)*/
else
ret = extract_dollar_brace_string (string, &si, 1, 0);
@@ -814,9 +816,9 @@ skip_double_quoted (string, slen, sind)
{
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC|EX_COMMAND); /* ) */
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
else
ret = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC);
ret = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
i = si + 1;
continue;
@@ -924,12 +926,19 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
#if defined (HANDLE_MULTIBYTE)
size_t mblength;
#endif
if (c == CTLESC)
if ((flags & SX_NOCTLESC) == 0 && c == CTLESC)
{
i += 2;
continue;
}
/* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL
through, to protect the CTLNULs from later calls to
remove_quoted_nulls. */
else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL)
{
i += 2;
continue;
}
#if defined (HANDLE_MULTIBYTE)
mblength = MBLEN (string + i, slen - i);
if (mblength > 1)
@@ -983,7 +992,7 @@ extract_command_subst (string, sindex)
char *string;
int *sindex;
{
return (extract_delimited_string (string, sindex, "$(", "(", ")", EX_COMMAND)); /*)*/
return (extract_delimited_string (string, sindex, "$(", "(", ")", SX_COMMAND)); /*)*/
}
/* Extract the $[ construct in STRING, and return a new string. (])
@@ -1090,7 +1099,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
/* Not exactly right yet; should handle shell metacharacters and
multibyte characters, too. */
if ((flags & EX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || whitespace (string[i - 1])))
if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || whitespace (string[i - 1])))
{
in_comment = 1;
ADVANCE_CHAR (string, slen, i);
@@ -1108,7 +1117,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
if (STREQN (string + i, opener, len_opener))
{
si = i + len_opener;
t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|EX_NOALLOC);
t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1117,7 +1126,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
{
si = i + len_alt_opener;
t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|EX_NOALLOC);
t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1136,7 +1145,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
if (c == '`')
{
si = i + 1;
t = string_extract (string, &si, "`", flags|EX_NOALLOC);
t = string_extract (string, &si, "`", flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1170,7 +1179,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
}
si = i - *sindex - len_closer + 1;
if (flags & EX_NOALLOC)
if (flags & SX_NOALLOC)
result = (char *)NULL;
else
{
@@ -1245,7 +1254,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
if (c == '`')
{
si = i + 1;
t = string_extract (string, &si, "`", flags|EX_NOALLOC);
t = string_extract (string, &si, "`", flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1255,7 +1264,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
if (string[i] == '$' && string[i+1] == LPAREN)
{
si = i + 2;
t = extract_delimited_string (string, &si, "$(", "(", ")", flags|EX_NOALLOC|EX_COMMAND); /*)*/
t = extract_delimited_string (string, &si, "$(", "(", ")", flags|SX_NOALLOC|SX_COMMAND); /*)*/
i = si + 1;
continue;
}
@@ -1290,7 +1299,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
}
}
result = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
*sindex = i;
return (result);
@@ -1518,9 +1527,9 @@ skip_to_delim (string, start, delims)
CQ_RETURN(si);
if (string[i+1] == LPAREN)
temp = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC|EX_COMMAND); /* ) */
temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
else
temp = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC);
temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
i = si;
if (string[i] == '\0') /* don't increment i past EOS in loop */
break;
@@ -1945,7 +1954,7 @@ list_string (string, separators, quoted)
WORD_LIST *result;
WORD_DESC *t;
char *current_word, *s;
int sindex, sh_style_split, whitesep;
int sindex, sh_style_split, whitesep, xflags;
size_t slen;
if (!string || !*string)
@@ -1955,6 +1964,11 @@ list_string (string, separators, quoted)
separators[1] == '\t' &&
separators[2] == '\n' &&
separators[3] == '\0';
for (xflags = 0, s = ifs_value; s && *s; s++)
{
if (*s == CTLESC) xflags |= SX_NOCTLESC;
else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
}
slen = 0;
/* Remove sequences of whitespace at the beginning of STRING, as
@@ -1980,7 +1994,7 @@ list_string (string, separators, quoted)
{
/* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
unless multibyte chars are possible. */
current_word = string_extract_verbatim (string, slen, &sindex, separators, 0);
current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags);
if (current_word == 0)
break;
@@ -2062,19 +2076,23 @@ get_word_from_string (stringp, separators, endptr)
{
register char *s;
char *current_word;
int sindex, sh_style_split, whitesep;
int sindex, sh_style_split, whitesep, xflags;
size_t slen;
if (!stringp || !*stringp || !**stringp)
return ((char *)NULL);
s = *stringp;
sh_style_split = separators && separators[0] == ' ' &&
separators[1] == '\t' &&
separators[2] == '\n' &&
separators[3] == '\0';
for (xflags = 0, s = ifs_value; s && *s; s++)
{
if (*s == CTLESC) xflags |= SX_NOCTLESC;
if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
}
s = *stringp;
slen = 0;
/* Remove sequences of whitespace at the beginning of STRING, as
@@ -2103,7 +2121,7 @@ get_word_from_string (stringp, separators, endptr)
/* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
unless multibyte chars are possible. */
slen = (MB_CUR_MAX > 1) ? strlen (s) : 1;
current_word = string_extract_verbatim (s, slen, &sindex, separators, 0);
current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags);
/* Set ENDPTR to the first character after the end of the word. */
if (endptr)
@@ -2934,12 +2952,14 @@ expand_string (string, quoted)
/* Quote escape characters in string s, but no other characters. This is
used to protect CTLESC and CTLNUL in variable values from the rest of
the word expansion process after the variable is expanded. If IFS is
null, we quote spaces as well, just in case we split on spaces later
(in the case of unquoted $@, we will eventually attempt to split the
entire word on spaces). Corresponding code exists in dequote_escapes.
Even if we don't end up splitting on spaces, quoting spaces is not a
problem. */
the word expansion process after the variable is expanded (word splitting
and filename generation). If IFS is null, we quote spaces as well, just
in case we split on spaces later (in the case of unquoted $@, we will
eventually attempt to split the entire word on spaces). Corresponding
code exists in dequote_escapes. Even if we don't end up splitting on
spaces, quoting spaces is not a problem. This should never be called on
a string that is quoted with single or double quotes or part of a here
document (effectively double-quoted). */
char *
quote_escapes (string)
char *string;
@@ -2947,19 +2967,23 @@ quote_escapes (string)
register char *s, *t;
size_t slen;
char *result, *send;
int quote_spaces;
int quote_spaces, skip_ctlesc, skip_ctlnul;
DECLARE_MBSTATE;
slen = strlen (string);
send = string + slen;
quote_spaces = (ifs_value && *ifs_value == 0);
for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
t = result = (char *)xmalloc ((slen * 2) + 1);
s = string;
while (*s)
{
if (*s == CTLESC || *s == CTLNUL || (quote_spaces && *s == ' '))
if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
*t++ = CTLESC;
COPY_CHAR_P (t, s, send);
}
@@ -2998,7 +3022,7 @@ static char *
dequote_escapes (string)
char *string;
{
register char *s, *t;
register char *s, *t, *s1;
size_t slen;
char *result, *send;
int quote_spaces;
@@ -3011,12 +3035,13 @@ dequote_escapes (string)
send = string + slen;
t = result = (char *)xmalloc (slen + 1);
s = string;
if (strchr (string, CTLESC) == 0)
return (strcpy (result, s));
return (strcpy (result, string));
quote_spaces = (ifs_value && *ifs_value == 0);
s = string;
while (*s)
{
if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
@@ -3993,7 +4018,9 @@ parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted)
FREE (val);
if (temp1)
{
val = quote_escapes (temp1);
val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
? quote_string (temp1)
: quote_escapes (temp1);
free (temp1);
temp1 = val;
}
@@ -4460,13 +4487,16 @@ read_comsub (fd, quoted, rflag)
int fd, quoted;
int *rflag;
{
char *istring, buf[128], *bufp;
int istring_index, istring_size, c, tflag;
char *istring, buf[128], *bufp, *s;
int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul;
ssize_t bufn;
istring = (char *)NULL;
istring_index = istring_size = bufn = tflag = 0;
for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
#ifdef __CYGWIN__
setmode (fd, O_TEXT); /* we don't want CR/LF, we want Unix-style */
#endif
@@ -4503,12 +4533,12 @@ read_comsub (fd, quoted, rflag)
/* Escape CTLESC and CTLNUL in the output to protect those characters
from the rest of the word expansions (word splitting and globbing.)
This is essentially quote_escapes inline. */
else if (c == CTLESC)
else if (skip_ctlesc == 0 && c == CTLESC)
{
tflag |= W_HASCTLESC;
istring[istring_index++] = CTLESC;
}
else if (c == CTLNUL || (c == ' ' && (ifs_value && *ifs_value == 0)))
else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
istring[istring_index++] = CTLESC;
istring[istring_index++] = c;
@@ -5608,18 +5638,9 @@ parameter_brace_substring (varname, value, substr, quoted)
/* We want E2 to be the number of elements desired (arrays can be sparse,
so verify_substring_values just returns the numbers specified and we
rely on array_subrange to understand how to deal with them). */
tt = array_subrange (array_cell (v), e1, e2, starsub, quoted);
#if 0
temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
/* array_subrange now calls array_quote_escapes as appropriate, so the
caller no longer needs to. */
if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
{
temp = tt ? quote_escapes (tt) : (char *)NULL;
FREE (tt);
}
else
#endif
temp = tt;
break;
#endif
default:
@@ -5852,7 +5873,7 @@ parameter_brace_patsub (varname, value, patsub, quoted)
FREE (val);
if (temp)
{
tt = quote_escapes (temp);
tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
free (temp);
temp = tt;
}
@@ -5869,16 +5890,9 @@ parameter_brace_patsub (varname, value, patsub, quoted)
#if defined (ARRAY_VARS)
case VT_ARRAYVAR:
temp = array_patsub (array_cell (v), p, rep, mflags);
#if 0
/* Don't need to do this anymore; array_patsub calls array_quote_escapes
as appropriate before adding the space separators. */
if (temp && (mflags & MATCH_QUOTED) == 0)
{
tt = quote_escapes (temp);
free (temp);
temp = tt;
}
#endif
/* Don't call quote_escapes anymore; array_patsub calls
array_quote_escapes as appropriate before adding the
space separators. */
break;
#endif
}
@@ -5968,9 +5982,9 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
t_index = ++sindex;
/* ${#var} doesn't have any of the other parameter expansions on it. */
if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
name = string_extract (string, &t_index, "}", EX_VARNAME);
name = string_extract (string, &t_index, "}", SX_VARNAME);
else
name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME);
name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME);
ret = 0;
tflag = 0;
@@ -7027,7 +7041,7 @@ add_string:
{
t_index = sindex++;
temp = string_extract (string, &sindex, "`", EX_REQMATCH);
temp = string_extract (string, &sindex, "`", SX_REQMATCH);
/* The test of sindex against t_index is to allow bare instances of
` to pass through, for backwards compatibility. */
if (temp == &extract_string_error || temp == &extract_string_fatal)
+8207
View File
File diff suppressed because it is too large Load Diff
+100 -69
View File
@@ -4,7 +4,7 @@
/* ``Have a little faith, there's magic in the night. You ain't a
beauty, but, hey, you're alright.'' */
/* Copyright (C) 1987-2006 Free Software Foundation, Inc.
/* Copyright (C) 1987-2007 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -79,10 +79,11 @@ extern int errno;
#define ST_DQUOTE 0x08 /* unused yet */
/* Flags for the string extraction functions. */
#define EX_NOALLOC 0x01 /* just skip; don't return substring */
#define EX_VARNAME 0x02 /* variable name; for string_extract () */
#define EX_REQMATCH 0x04 /* closing/matching delimiter required */
#define EX_COMMAND 0x08 /* extracting a shell script/command */
#define SX_NOALLOC 0x01 /* just skip; don't return substring */
#define SX_VARNAME 0x02 /* variable name; for string_extract () */
#define SX_REQMATCH 0x04 /* closing/matching delimiter required */
#define SX_COMMAND 0x08 /* extracting a shell script/command */
#define SX_NOCTLESC 0x10 /* don't honor CTLESC quoting */
/* Flags for the `pflags' argument to param_expand() */
#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */
@@ -543,11 +544,11 @@ sub_append_number (number, target, indx, size)
/* Extract a substring from STRING, starting at SINDEX and ending with
one of the characters in CHARLIST. Don't make the ending character
part of the string. Leave SINDEX pointing at the ending character.
Understand about backslashes in the string. If (flags & EX_VARNAME)
Understand about backslashes in the string. If (flags & SX_VARNAME)
is non-zero, and array variables have been compiled into the shell,
everything between a `[' and a corresponding `]' is skipped over.
If (flags & EX_NOALLOC) is non-zero, don't return the substring, just
update SINDEX. If (flags & EX_REQMATCH) is non-zero, the string must
If (flags & SX_NOALLOC) is non-zero, don't return the substring, just
update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must
contain a closing character from CHARLIST. */
static char *
string_extract (string, sindex, charlist, flags)
@@ -575,7 +576,7 @@ string_extract (string, sindex, charlist, flags)
break;
}
#if defined (ARRAY_VARS)
else if ((flags & EX_VARNAME) && c == '[')
else if ((flags & SX_VARNAME) && c == '[')
{
int ni;
/* If this is an array subscript, skip over it and continue. */
@@ -595,13 +596,13 @@ string_extract (string, sindex, charlist, flags)
/* If we had to have a matching delimiter and didn't find one, return an
error and let the caller deal with it. */
if ((flags & EX_REQMATCH) && found == 0)
if ((flags & SX_REQMATCH) && found == 0)
{
*sindex = i;
return (&extract_string_error);
}
temp = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
*sindex = i;
return (temp);
@@ -712,7 +713,7 @@ add_one_character:
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_COMMAND); /*)*/
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_COMMAND); /*)*/
else
ret = extract_dollar_brace_string (string, &si, 1, 0);
@@ -814,9 +815,9 @@ skip_double_quoted (string, slen, sind)
{
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC|EX_COMMAND); /* ) */
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
else
ret = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC);
ret = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
i = si + 1;
continue;
@@ -924,7 +925,7 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
#if defined (HANDLE_MULTIBYTE)
size_t mblength;
#endif
if (c == CTLESC)
if ((flags & SX_NOCTLESC) == 0 && c == CTLESC)
{
i += 2;
continue;
@@ -983,7 +984,7 @@ extract_command_subst (string, sindex)
char *string;
int *sindex;
{
return (extract_delimited_string (string, sindex, "$(", "(", ")", EX_COMMAND)); /*)*/
return (extract_delimited_string (string, sindex, "$(", "(", ")", SX_COMMAND)); /*)*/
}
/* Extract the $[ construct in STRING, and return a new string. (])
@@ -1090,7 +1091,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
/* Not exactly right yet; should handle shell metacharacters and
multibyte characters, too. */
if ((flags & EX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || whitespace (string[i - 1])))
if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || whitespace (string[i - 1])))
{
in_comment = 1;
ADVANCE_CHAR (string, slen, i);
@@ -1108,7 +1109,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
if (STREQN (string + i, opener, len_opener))
{
si = i + len_opener;
t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|EX_NOALLOC);
t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1117,7 +1118,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
{
si = i + len_alt_opener;
t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|EX_NOALLOC);
t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1136,7 +1137,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
if (c == '`')
{
si = i + 1;
t = string_extract (string, &si, "`", flags|EX_NOALLOC);
t = string_extract (string, &si, "`", flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1170,7 +1171,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
}
si = i - *sindex - len_closer + 1;
if (flags & EX_NOALLOC)
if (flags & SX_NOALLOC)
result = (char *)NULL;
else
{
@@ -1245,7 +1246,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
if (c == '`')
{
si = i + 1;
t = string_extract (string, &si, "`", flags|EX_NOALLOC);
t = string_extract (string, &si, "`", flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1255,7 +1256,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
if (string[i] == '$' && string[i+1] == LPAREN)
{
si = i + 2;
t = extract_delimited_string (string, &si, "$(", "(", ")", flags|EX_NOALLOC|EX_COMMAND); /*)*/
t = extract_delimited_string (string, &si, "$(", "(", ")", flags|SX_NOALLOC|SX_COMMAND); /*)*/
i = si + 1;
continue;
}
@@ -1290,7 +1291,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
}
}
result = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
*sindex = i;
return (result);
@@ -1518,9 +1519,9 @@ skip_to_delim (string, start, delims)
CQ_RETURN(si);
if (string[i+1] == LPAREN)
temp = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC|EX_COMMAND); /* ) */
temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
else
temp = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC);
temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
i = si;
if (string[i] == '\0') /* don't increment i past EOS in loop */
break;
@@ -1888,7 +1889,13 @@ string_list_dollar_at (list, quoted)
sep[1] = '\0';
#endif
/* XXX -- why call quote_list if ifs == 0? we can get away without doing
it now that quote_escapes quotes spaces */
#if 0
tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0))
#else
tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
#endif
? quote_list (list)
: list_quote_escapes (list);
@@ -1939,7 +1946,7 @@ list_string (string, separators, quoted)
WORD_LIST *result;
WORD_DESC *t;
char *current_word, *s;
int sindex, sh_style_split, whitesep;
int sindex, sh_style_split, whitesep, xflags;
size_t slen;
if (!string || !*string)
@@ -1949,6 +1956,8 @@ list_string (string, separators, quoted)
separators[1] == '\t' &&
separators[2] == '\n' &&
separators[3] == '\0';
for (xflags = 0, s = ifs_value; s && *s; s++)
if (*s == CTLESC) xflags |= SX_NOCTLESC;
slen = 0;
/* Remove sequences of whitespace at the beginning of STRING, as
@@ -1974,7 +1983,7 @@ list_string (string, separators, quoted)
{
/* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
unless multibyte chars are possible. */
current_word = string_extract_verbatim (string, slen, &sindex, separators, 0);
current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags);
if (current_word == 0)
break;
@@ -2056,19 +2065,20 @@ get_word_from_string (stringp, separators, endptr)
{
register char *s;
char *current_word;
int sindex, sh_style_split, whitesep;
int sindex, sh_style_split, whitesep, xflags;
size_t slen;
if (!stringp || !*stringp || !**stringp)
return ((char *)NULL);
s = *stringp;
sh_style_split = separators && separators[0] == ' ' &&
separators[1] == '\t' &&
separators[2] == '\n' &&
separators[3] == '\0';
for (xflags = 0, s = ifs_value; s && *s; s++)
if (*s == CTLESC) xflags |= SX_NOCTLESC;
s = *stringp;
slen = 0;
/* Remove sequences of whitespace at the beginning of STRING, as
@@ -2097,7 +2107,7 @@ get_word_from_string (stringp, separators, endptr)
/* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
unless multibyte chars are possible. */
slen = (MB_CUR_MAX > 1) ? strlen (s) : 1;
current_word = string_extract_verbatim (s, slen, &sindex, separators, 0);
current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags);
/* Set ENDPTR to the first character after the end of the word. */
if (endptr)
@@ -2653,11 +2663,12 @@ remove_backslashes (string)
/* This needs better error handling. */
/* Expand W for use as an argument to a unary or binary operator in a
[[...]] expression. If SPECIAL is nonzero, this is the rhs argument
[[...]] expression. If SPECIAL is 1, this is the rhs argument
to the != or == operator, and should be treated as a pattern. In
this case, we quote the string specially for the globbing code. The
caller is responsible for removing the backslashes if the unquoted
words is needed later. */
this case, we quote the string specially for the globbing code. If
SPECIAL is 2, this is an rhs argument for the =~ operator, and should
be quoted appropriately for regcomp/regexec. The caller is responsible
for removing the backslashes if the unquoted word is needed later. */
char *
cond_expand_word (w, special)
WORD_DESC *w;
@@ -2665,6 +2676,7 @@ cond_expand_word (w, special)
{
char *r, *p;
WORD_LIST *l;
int qflags;
if (w->word == 0 || w->word[0] == '\0')
return ((char *)NULL);
@@ -2679,8 +2691,11 @@ cond_expand_word (w, special)
}
else
{
qflags = QGLOB_CVTNULL;
if (special == 2)
qflags |= QGLOB_REGEXP;
p = string_list (l);
r = quote_string_for_globbing (p, QGLOB_CVTNULL);
r = quote_string_for_globbing (p, qflags);
free (p);
}
dispose_words (l);
@@ -2923,7 +2938,14 @@ expand_string (string, quoted)
/* Quote escape characters in string s, but no other characters. This is
used to protect CTLESC and CTLNUL in variable values from the rest of
the word expansion process after the variable is expanded. */
the word expansion process after the variable is expanded (word splitting
and filename generation). If IFS is null, we quote spaces as well, just
in case we split on spaces later (in the case of unquoted $@, we will
eventually attempt to split the entire word on spaces). Corresponding
code exists in dequote_escapes. Even if we don't end up splitting on
spaces, quoting spaces is not a problem. This should never be called on
a string that is quoted with single or double quotes or part of a here
document (effectively double-quoted). */
char *
quote_escapes (string)
char *string;
@@ -2931,17 +2953,23 @@ quote_escapes (string)
register char *s, *t;
size_t slen;
char *result, *send;
int quote_spaces, skip_ctlesc;
DECLARE_MBSTATE;
slen = strlen (string);
send = string + slen;
quote_spaces = (ifs_value && *ifs_value == 0);
for (skip_ctlesc = 0, s = ifs_value; s && *s; s++)
skip_ctlesc |= *s == CTLESC;
t = result = (char *)xmalloc ((slen * 2) + 1);
s = string;
while (*s)
{
if (*s == CTLESC || *s == CTLNUL)
if ((skip_ctlesc == 0 && *s == CTLESC) || *s == CTLNUL || (quote_spaces && *s == ' '))
*t++ = CTLESC;
COPY_CHAR_P (t, s, send);
}
@@ -2980,9 +3008,10 @@ static char *
dequote_escapes (string)
char *string;
{
register char *s, *t;
register char *s, *t, *s1;
size_t slen;
char *result, *send;
int quote_spaces;
DECLARE_MBSTATE;
if (string == 0)
@@ -2992,14 +3021,16 @@ dequote_escapes (string)
send = string + slen;
t = result = (char *)xmalloc (slen + 1);
s = string;
if (strchr (string, CTLESC) == 0)
return (strcpy (result, s));
return (strcpy (result, string));
quote_spaces = (ifs_value && *ifs_value == 0);
s = string;
while (*s)
{
if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL))
if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
{
s++;
if (*s == '\0')
@@ -3973,7 +4004,9 @@ parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted)
FREE (val);
if (temp1)
{
val = quote_escapes (temp1);
val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
? quote_string (temp1)
: quote_escapes (temp1);
free (temp1);
temp1 = val;
}
@@ -4317,7 +4350,7 @@ process_substitute (string, open_for_read_in_child)
/* Cancel traps, in trap.c. */
restore_original_signals ();
setup_async_signals ();
subshell_environment |= SUBSHELL_COMSUB;
subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB;
}
#if defined (JOB_CONTROL)
@@ -4440,18 +4473,22 @@ read_comsub (fd, quoted, rflag)
int fd, quoted;
int *rflag;
{
char *istring, buf[128], *bufp;
int istring_index, istring_size, c, tflag;
char *istring, buf[128], *bufp, *s;
int istring_index, istring_size, c, tflag, skip_ctlesc;
ssize_t bufn;
istring = (char *)NULL;
istring_index = istring_size = bufn = tflag = 0;
for (skip_ctlesc = 0, s = ifs_value; s && *s; s++)
skip_ctlesc |= *s == CTLESC;
#ifdef __CYGWIN__
setmode (fd, O_TEXT); /* we don't want CR/LF, we want Unix-style */
#endif
/* Read the output of the command through the pipe. */
/* Read the output of the command through the pipe. This may need to be
changed to understand multibyte characters in the future. */
while (1)
{
if (fd < 0)
@@ -4476,16 +4513,18 @@ read_comsub (fd, quoted, rflag)
/* Add the character to ISTRING, possibly after resizing it. */
RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE);
/* This is essentially quote_string inline */
if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
istring[istring_index++] = CTLESC;
/* Escape CTLESC and CTLNUL in the output to protect those characters
from the rest of the word expansions (word splitting and globbing.) */
else if (c == CTLESC)
from the rest of the word expansions (word splitting and globbing.)
This is essentially quote_escapes inline. */
else if (skip_ctlesc == 0 && c == CTLESC)
{
tflag |= W_HASCTLESC;
istring[istring_index++] = CTLESC;
}
else if (c == CTLNUL)
else if (c == CTLNUL || (c == ' ' && (ifs_value && *ifs_value == 0)))
istring[istring_index++] = CTLESC;
istring[istring_index++] = c;
@@ -5585,14 +5624,9 @@ parameter_brace_substring (varname, value, substr, quoted)
/* We want E2 to be the number of elements desired (arrays can be sparse,
so verify_substring_values just returns the numbers specified and we
rely on array_subrange to understand how to deal with them). */
tt = array_subrange (array_cell (v), e1, e2, starsub, quoted);
if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
{
temp = tt ? quote_escapes (tt) : (char *)NULL;
FREE (tt);
}
else
temp = tt;
temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
/* array_subrange now calls array_quote_escapes as appropriate, so the
caller no longer needs to. */
break;
#endif
default:
@@ -5825,7 +5859,7 @@ parameter_brace_patsub (varname, value, patsub, quoted)
FREE (val);
if (temp)
{
tt = quote_escapes (temp);
tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
free (temp);
temp = tt;
}
@@ -5842,12 +5876,9 @@ parameter_brace_patsub (varname, value, patsub, quoted)
#if defined (ARRAY_VARS)
case VT_ARRAYVAR:
temp = array_patsub (array_cell (v), p, rep, mflags);
if (temp && (mflags & MATCH_QUOTED) == 0)
{
tt = quote_escapes (temp);
free (temp);
temp = tt;
}
/* Don't call quote_escapes anymore; array_patsub calls
array_quote_escapes as appropriate before adding the
space separators. */
break;
#endif
}
@@ -5937,9 +5968,9 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
t_index = ++sindex;
/* ${#var} doesn't have any of the other parameter expansions on it. */
if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
name = string_extract (string, &t_index, "}", EX_VARNAME);
name = string_extract (string, &t_index, "}", SX_VARNAME);
else
name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME);
name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME);
ret = 0;
tflag = 0;
@@ -6996,7 +7027,7 @@ add_string:
{
t_index = sindex++;
temp = string_extract (string, &sindex, "`", EX_REQMATCH);
temp = string_extract (string, &sindex, "`", SX_REQMATCH);
/* The test of sindex against t_index is to allow bare instances of
` to pass through, for backwards compatibility. */
if (temp == &extract_string_error || temp == &extract_string_fatal)
+8224
View File
File diff suppressed because it is too large Load Diff
+103 -77
View File
@@ -4,7 +4,7 @@
/* ``Have a little faith, there's magic in the night. You ain't a
beauty, but, hey, you're alright.'' */
/* Copyright (C) 1987-2006 Free Software Foundation, Inc.
/* Copyright (C) 1987-2007 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -79,10 +79,12 @@ extern int errno;
#define ST_DQUOTE 0x08 /* unused yet */
/* Flags for the string extraction functions. */
#define EX_NOALLOC 0x01 /* just skip; don't return substring */
#define EX_VARNAME 0x02 /* variable name; for string_extract () */
#define EX_REQMATCH 0x04 /* closing/matching delimiter required */
#define EX_COMMAND 0x08 /* extracting a shell script/command */
#define SX_NOALLOC 0x01 /* just skip; don't return substring */
#define SX_VARNAME 0x02 /* variable name; for string_extract () */
#define SX_REQMATCH 0x04 /* closing/matching delimiter required */
#define SX_COMMAND 0x08 /* extracting a shell script/command */
#define SX_NOCTLESC 0x10 /* don't honor CTLESC quoting */
#define SX_NOESCCTLNUL 0x20 /* don't let CTLESC quote CTLNUL */
/* Flags for the `pflags' argument to param_expand() */
#define PF_NOCOMSUB 0x01 /* Do not perform command substitution */
@@ -543,11 +545,11 @@ sub_append_number (number, target, indx, size)
/* Extract a substring from STRING, starting at SINDEX and ending with
one of the characters in CHARLIST. Don't make the ending character
part of the string. Leave SINDEX pointing at the ending character.
Understand about backslashes in the string. If (flags & EX_VARNAME)
Understand about backslashes in the string. If (flags & SX_VARNAME)
is non-zero, and array variables have been compiled into the shell,
everything between a `[' and a corresponding `]' is skipped over.
If (flags & EX_NOALLOC) is non-zero, don't return the substring, just
update SINDEX. If (flags & EX_REQMATCH) is non-zero, the string must
If (flags & SX_NOALLOC) is non-zero, don't return the substring, just
update SINDEX. If (flags & SX_REQMATCH) is non-zero, the string must
contain a closing character from CHARLIST. */
static char *
string_extract (string, sindex, charlist, flags)
@@ -575,7 +577,7 @@ string_extract (string, sindex, charlist, flags)
break;
}
#if defined (ARRAY_VARS)
else if ((flags & EX_VARNAME) && c == '[')
else if ((flags & SX_VARNAME) && c == '[')
{
int ni;
/* If this is an array subscript, skip over it and continue. */
@@ -595,13 +597,13 @@ string_extract (string, sindex, charlist, flags)
/* If we had to have a matching delimiter and didn't find one, return an
error and let the caller deal with it. */
if ((flags & EX_REQMATCH) && found == 0)
if ((flags & SX_REQMATCH) && found == 0)
{
*sindex = i;
return (&extract_string_error);
}
temp = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
temp = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
*sindex = i;
return (temp);
@@ -712,7 +714,7 @@ add_one_character:
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_COMMAND); /*)*/
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_COMMAND); /*)*/
else
ret = extract_dollar_brace_string (string, &si, 1, 0);
@@ -814,9 +816,9 @@ skip_double_quoted (string, slen, sind)
{
si = i + 2;
if (string[i + 1] == LPAREN)
ret = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC|EX_COMMAND); /* ) */
ret = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
else
ret = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC);
ret = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
i = si + 1;
continue;
@@ -924,12 +926,19 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
#if defined (HANDLE_MULTIBYTE)
size_t mblength;
#endif
if (c == CTLESC)
if ((flags & SX_NOCTLESC) == 0 && c == CTLESC)
{
i += 2;
continue;
}
/* Even if flags contains SX_NOCTLESC, we let CTLESC quoting CTLNUL
through, to protect the CTLNULs from later calls to
remove_quoted_nulls. */
else if ((flags & SX_NOESCCTLNUL) == 0 && c == CTLESC && string[i+1] == CTLNUL)
{
i += 2;
continue;
}
#if defined (HANDLE_MULTIBYTE)
mblength = MBLEN (string + i, slen - i);
if (mblength > 1)
@@ -983,7 +992,7 @@ extract_command_subst (string, sindex)
char *string;
int *sindex;
{
return (extract_delimited_string (string, sindex, "$(", "(", ")", EX_COMMAND)); /*)*/
return (extract_delimited_string (string, sindex, "$(", "(", ")", SX_COMMAND)); /*)*/
}
/* Extract the $[ construct in STRING, and return a new string. (])
@@ -1090,7 +1099,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
/* Not exactly right yet; should handle shell metacharacters and
multibyte characters, too. */
if ((flags & EX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || whitespace (string[i - 1])))
if ((flags & SX_COMMAND) && c == '#' && (i == 0 || string[i - 1] == '\n' || whitespace (string[i - 1])))
{
in_comment = 1;
ADVANCE_CHAR (string, slen, i);
@@ -1108,7 +1117,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
if (STREQN (string + i, opener, len_opener))
{
si = i + len_opener;
t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|EX_NOALLOC);
t = extract_delimited_string (string, &si, opener, alt_opener, closer, flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1117,7 +1126,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
if (len_alt_opener && STREQN (string + i, alt_opener, len_alt_opener))
{
si = i + len_alt_opener;
t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|EX_NOALLOC);
t = extract_delimited_string (string, &si, alt_opener, alt_opener, closer, flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1136,7 +1145,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
if (c == '`')
{
si = i + 1;
t = string_extract (string, &si, "`", flags|EX_NOALLOC);
t = string_extract (string, &si, "`", flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1170,7 +1179,7 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
}
si = i - *sindex - len_closer + 1;
if (flags & EX_NOALLOC)
if (flags & SX_NOALLOC)
result = (char *)NULL;
else
{
@@ -1245,7 +1254,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
if (c == '`')
{
si = i + 1;
t = string_extract (string, &si, "`", flags|EX_NOALLOC);
t = string_extract (string, &si, "`", flags|SX_NOALLOC);
i = si + 1;
continue;
}
@@ -1255,7 +1264,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
if (string[i] == '$' && string[i+1] == LPAREN)
{
si = i + 2;
t = extract_delimited_string (string, &si, "$(", "(", ")", flags|EX_NOALLOC|EX_COMMAND); /*)*/
t = extract_delimited_string (string, &si, "$(", "(", ")", flags|SX_NOALLOC|SX_COMMAND); /*)*/
i = si + 1;
continue;
}
@@ -1290,7 +1299,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
}
}
result = (flags & EX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
result = (flags & SX_NOALLOC) ? (char *)NULL : substring (string, *sindex, i);
*sindex = i;
return (result);
@@ -1518,9 +1527,9 @@ skip_to_delim (string, start, delims)
CQ_RETURN(si);
if (string[i+1] == LPAREN)
temp = extract_delimited_string (string, &si, "$(", "(", ")", EX_NOALLOC|EX_COMMAND); /* ) */
temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
else
temp = extract_dollar_brace_string (string, &si, 0, EX_NOALLOC);
temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC);
i = si;
if (string[i] == '\0') /* don't increment i past EOS in loop */
break;
@@ -1945,7 +1954,7 @@ list_string (string, separators, quoted)
WORD_LIST *result;
WORD_DESC *t;
char *current_word, *s;
int sindex, sh_style_split, whitesep;
int sindex, sh_style_split, whitesep, xflags;
size_t slen;
if (!string || !*string)
@@ -1955,6 +1964,11 @@ list_string (string, separators, quoted)
separators[1] == '\t' &&
separators[2] == '\n' &&
separators[3] == '\0';
for (xflags = 0, s = ifs_value; s && *s; s++)
{
if (*s == CTLESC) xflags |= SX_NOCTLESC;
else if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
}
slen = 0;
/* Remove sequences of whitespace at the beginning of STRING, as
@@ -1980,7 +1994,7 @@ list_string (string, separators, quoted)
{
/* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
unless multibyte chars are possible. */
current_word = string_extract_verbatim (string, slen, &sindex, separators, 0);
current_word = string_extract_verbatim (string, slen, &sindex, separators, xflags);
if (current_word == 0)
break;
@@ -2062,19 +2076,23 @@ get_word_from_string (stringp, separators, endptr)
{
register char *s;
char *current_word;
int sindex, sh_style_split, whitesep;
int sindex, sh_style_split, whitesep, xflags;
size_t slen;
if (!stringp || !*stringp || !**stringp)
return ((char *)NULL);
s = *stringp;
sh_style_split = separators && separators[0] == ' ' &&
separators[1] == '\t' &&
separators[2] == '\n' &&
separators[3] == '\0';
for (xflags = 0, s = ifs_value; s && *s; s++)
{
if (*s == CTLESC) xflags |= SX_NOCTLESC;
if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL;
}
s = *stringp;
slen = 0;
/* Remove sequences of whitespace at the beginning of STRING, as
@@ -2103,7 +2121,7 @@ get_word_from_string (stringp, separators, endptr)
/* Don't need string length in ADVANCE_CHAR or string_extract_verbatim
unless multibyte chars are possible. */
slen = (MB_CUR_MAX > 1) ? strlen (s) : 1;
current_word = string_extract_verbatim (s, slen, &sindex, separators, 0);
current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags);
/* Set ENDPTR to the first character after the end of the word. */
if (endptr)
@@ -2659,11 +2677,12 @@ remove_backslashes (string)
/* This needs better error handling. */
/* Expand W for use as an argument to a unary or binary operator in a
[[...]] expression. If SPECIAL is nonzero, this is the rhs argument
[[...]] expression. If SPECIAL is 1, this is the rhs argument
to the != or == operator, and should be treated as a pattern. In
this case, we quote the string specially for the globbing code. The
caller is responsible for removing the backslashes if the unquoted
words is needed later. */
this case, we quote the string specially for the globbing code. If
SPECIAL is 2, this is an rhs argument for the =~ operator, and should
be quoted appropriately for regcomp/regexec. The caller is responsible
for removing the backslashes if the unquoted word is needed later. */
char *
cond_expand_word (w, special)
WORD_DESC *w;
@@ -2671,6 +2690,7 @@ cond_expand_word (w, special)
{
char *r, *p;
WORD_LIST *l;
int qflags;
if (w->word == 0 || w->word[0] == '\0')
return ((char *)NULL);
@@ -2685,8 +2705,11 @@ cond_expand_word (w, special)
}
else
{
qflags = QGLOB_CVTNULL;
if (special == 2)
qflags |= QGLOB_REGEXP;
p = string_list (l);
r = quote_string_for_globbing (p, QGLOB_CVTNULL);
r = quote_string_for_globbing (p, qflags);
free (p);
}
dispose_words (l);
@@ -2929,12 +2952,14 @@ expand_string (string, quoted)
/* Quote escape characters in string s, but no other characters. This is
used to protect CTLESC and CTLNUL in variable values from the rest of
the word expansion process after the variable is expanded. If IFS is
null, we quote spaces as well, just in case we split on spaces later
(in the case of unquoted $@, we will eventually attempt to split the
entire word on spaces). Corresponding code exists in dequote_escapes.
Even if we don't end up splitting on spaces, quoting spaces is not a
problem. */
the word expansion process after the variable is expanded (word splitting
and filename generation). If IFS is null, we quote spaces as well, just
in case we split on spaces later (in the case of unquoted $@, we will
eventually attempt to split the entire word on spaces). Corresponding
code exists in dequote_escapes. Even if we don't end up splitting on
spaces, quoting spaces is not a problem. This should never be called on
a string that is quoted with single or double quotes or part of a here
document (effectively double-quoted). */
char *
quote_escapes (string)
char *string;
@@ -2942,19 +2967,26 @@ quote_escapes (string)
register char *s, *t;
size_t slen;
char *result, *send;
int quote_spaces;
int quote_spaces, skip_ctlesc, skip_ctlnul;
DECLARE_MBSTATE;
slen = strlen (string);
send = string + slen;
quote_spaces = (ifs_value && *ifs_value == 0);
for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
{
skip_ctlesc |= *s == CTLESC;
skip_ctlnul |= *s == CTLNUL;
}
t = result = (char *)xmalloc ((slen * 2) + 1);
s = string;
while (*s)
{
if (*s == CTLESC || *s == CTLNUL || (quote_spaces && *s == ' '))
if ((skip_ctlesc == 0 && *s == CTLESC) || (skip_ctlnul == 0 && *s == CTLNUL) || (quote_spaces && *s == ' '))
*t++ = CTLESC;
COPY_CHAR_P (t, s, send);
}
@@ -2993,7 +3025,7 @@ static char *
dequote_escapes (string)
char *string;
{
register char *s, *t;
register char *s, *t, *s1;
size_t slen;
char *result, *send;
int quote_spaces;
@@ -3006,12 +3038,13 @@ dequote_escapes (string)
send = string + slen;
t = result = (char *)xmalloc (slen + 1);
s = string;
if (strchr (string, CTLESC) == 0)
return (strcpy (result, s));
return (strcpy (result, string));
quote_spaces = (ifs_value && *ifs_value == 0);
s = string;
while (*s)
{
if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
@@ -3988,7 +4021,9 @@ parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted)
FREE (val);
if (temp1)
{
val = quote_escapes (temp1);
val = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
? quote_string (temp1)
: quote_escapes (temp1);
free (temp1);
temp1 = val;
}
@@ -4332,7 +4367,7 @@ process_substitute (string, open_for_read_in_child)
/* Cancel traps, in trap.c. */
restore_original_signals ();
setup_async_signals ();
subshell_environment |= SUBSHELL_COMSUB;
subshell_environment |= SUBSHELL_COMSUB|SUBSHELL_PROCSUB;
}
#if defined (JOB_CONTROL)
@@ -4455,13 +4490,16 @@ read_comsub (fd, quoted, rflag)
int fd, quoted;
int *rflag;
{
char *istring, buf[128], *bufp;
int istring_index, istring_size, c, tflag;
char *istring, buf[128], *bufp, *s;
int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul;
ssize_t bufn;
istring = (char *)NULL;
istring_index = istring_size = bufn = tflag = 0;
for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
#ifdef __CYGWIN__
setmode (fd, O_TEXT); /* we don't want CR/LF, we want Unix-style */
#endif
@@ -4498,12 +4536,12 @@ read_comsub (fd, quoted, rflag)
/* Escape CTLESC and CTLNUL in the output to protect those characters
from the rest of the word expansions (word splitting and globbing.)
This is essentially quote_escapes inline. */
else if (c == CTLESC)
else if (skip_ctlesc == 0 && c == CTLESC)
{
tflag |= W_HASCTLESC;
istring[istring_index++] = CTLESC;
}
else if (c == CTLNUL || (c == ' ' && (ifs_value && *ifs_value == 0)))
else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0)))
istring[istring_index++] = CTLESC;
istring[istring_index++] = c;
@@ -5603,14 +5641,9 @@ parameter_brace_substring (varname, value, substr, quoted)
/* We want E2 to be the number of elements desired (arrays can be sparse,
so verify_substring_values just returns the numbers specified and we
rely on array_subrange to understand how to deal with them). */
tt = array_subrange (array_cell (v), e1, e2, starsub, quoted);
if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
{
temp = tt ? quote_escapes (tt) : (char *)NULL;
FREE (tt);
}
else
temp = tt;
temp = array_subrange (array_cell (v), e1, e2, starsub, quoted);
/* array_subrange now calls array_quote_escapes as appropriate, so the
caller no longer needs to. */
break;
#endif
default:
@@ -5843,7 +5876,7 @@ parameter_brace_patsub (varname, value, patsub, quoted)
FREE (val);
if (temp)
{
tt = quote_escapes (temp);
tt = (mflags & MATCH_QUOTED) ? quote_string (temp) : quote_escapes (temp);
free (temp);
temp = tt;
}
@@ -5860,16 +5893,9 @@ parameter_brace_patsub (varname, value, patsub, quoted)
#if defined (ARRAY_VARS)
case VT_ARRAYVAR:
temp = array_patsub (array_cell (v), p, rep, mflags);
#if 0
/* Don't need to do this anymore; array_patsub calls array_quote_escapes
as appropriate before adding the space separators. */
if (temp && (mflags & MATCH_QUOTED) == 0)
{
tt = quote_escapes (temp);
free (temp);
temp = tt;
}
#endif
/* Don't call quote_escapes anymore; array_patsub calls
array_quote_escapes as appropriate before adding the
space separators. */
break;
#endif
}
@@ -5959,9 +5985,9 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
t_index = ++sindex;
/* ${#var} doesn't have any of the other parameter expansions on it. */
if (string[t_index] == '#' && legal_variable_starter (string[t_index+1])) /* {{ */
name = string_extract (string, &t_index, "}", EX_VARNAME);
name = string_extract (string, &t_index, "}", SX_VARNAME);
else
name = string_extract (string, &t_index, "#%:-=?+/}", EX_VARNAME);
name = string_extract (string, &t_index, "#%:-=?+/}", SX_VARNAME);
ret = 0;
tflag = 0;
@@ -7018,7 +7044,7 @@ add_string:
{
t_index = sindex++;
temp = string_extract (string, &sindex, "`", EX_REQMATCH);
temp = string_extract (string, &sindex, "`", SX_REQMATCH);
/* The test of sindex against t_index is to allow bare instances of
` to pass through, for backwards compatibility. */
if (temp == &extract_string_error || temp == &extract_string_fatal)
+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
+64 -4
View File
@@ -152,10 +152,10 @@ for case if then else
12 14 16 18 20
4414758999202
aaa bbb
./array.tests: line 285: syntax error near unexpected token `<>'
./array.tests: line 285: `metas=( <> < > ! )'
./array.tests: line 286: syntax error near unexpected token `<>'
./array.tests: line 286: `metas=( [1]=<> [2]=< [3]=> [4]=! )'
./array.tests: line 287: syntax error near unexpected token `<>'
./array.tests: line 287: `metas=( <> < > ! )'
./array.tests: line 288: syntax error near unexpected token `<>'
./array.tests: line 288: `metas=( [1]=<> [2]=< [3]=> [4]=! )'
abc 3
case 4
abc case if then else 5
@@ -206,3 +206,63 @@ t
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>
+6 -30
View File
@@ -253,6 +253,8 @@ foo=([10]="bar")
echo ${foo[0]}
rm 1=bar
cd $OLDPWD
foo=(a b c d e f g)
echo ${foo[@]}
@@ -372,34 +374,8 @@ declare -a x=($0)
declare -a x=(\$0)
echo "${x[@]}"
: ${TMPDIR:=/tmp}
# tests for bash-3.1 problems
${THIS_SH} ./array5.sub
mkdir $TMPDIR/bash-test-$$
cd $TMPDIR/bash-test-$$
trap "cd / ; rm -rf $TMPDIR/bash-test-$$" 0 1 2 3 6 15
touch '[3]=abcde'
touch r s t u v
declare -a x=(*)
echo ${x[3]}
echo ${x[@]}
unset x
x=(a b c d e)
echo ${x[*]: -1}
unset x[4]
unset x[2]
x[9]='9'
echo ${x[*]: -1}
TOOLKIT=(1 2 3 4 5 6 7 8 9 10)
ARRAY="1"
echo ${TOOLKIT["$ARRAY"]}
# tests for post-bash-3.2 problems, most fixed in bash-3.2 patches
${THIS_SH} ./array6.sub
+34
View File
@@ -0,0 +1,34 @@
: ${TMPDIR:=/tmp}
mkdir $TMPDIR/bash-test-$$
cd $TMPDIR/bash-test-$$
trap "cd / ; rm -rf $TMPDIR/bash-test-$$" 0 1 2 3 6 15
touch '[3]=abcde'
touch r s t u v
declare -a x=(*)
echo ${x[3]}
echo ${x[@]}
unset x
x=(a b c d e)
echo ${x[*]: -1}
unset x[4]
unset x[2]
x[9]='9'
echo ${x[*]: -1}
TOOLKIT=(1 2 3 4 5 6 7 8 9 10)
ARRAY="1"
echo ${TOOLKIT["$ARRAY"]}
exit 0
+109
View File
@@ -0,0 +1,109 @@
# test cases for array quoting and escaping fixed post bash-3.2-release
oIFS="$IFS"
a=(a b c)
echo ${a[@]}
a2=("${a[@]/#/"-iname '"}")
recho "${a2[@]}"
echo "${dbg-"'hey'"}"
echo "${dbg-"hey"}"
echo "${dbg-'"'hey}"
echo "${dbg-'"hey'}"
unset a a2
IFS=
a2=(${a[@]/#/"-iname '"})
recho "${a2[@]}"
IFS="$oIFS"
unset a a2
a=('a b' 'c d' 'e f')
recho ${a[@]:1:2}
recho "${a[@]:1:2}"
IFS=
recho ${a[@]:1:2}
recho "${a[@]:1:2}"
IFS="$oIFS"
unset a a2
a=(abc def)
# Prevent word splitting
#IFS=
a2=("${a[@]/#/"-iname '"}")
recho "${a2[@]}"
eval a2=("${a[@]/#/"-iname '"}")
recho "${a2[@]}"
a2=("${a[@]/#/-iname \'}")
recho "${a2[@]}"
eval a2=("${a[@]/#/-iname \'}")
recho "${a2[@]}"
set -- abc def
a2=("${@/#/"-iname '"}")
recho "${a2[@]}"
eval a2=("${@/#/"-iname '"}")
recho "${a2[@]}"
unset a a2
IFS=
pat=('*.*')
case $(ls ${pat[@]} 2>/dev/null) in
'') echo '*.* BAD' ;;
*) echo '*.* OK' ;;
esac
IFS="$oIFS"
unset a a2 pat
IFS=
s='abc'
set - ${s/b/1 2 3}
echo $#
echo "$1"
IFS="$oIFS"
unset s
set -- ab cd ef
foo="var with spaces"
IFS=
recho $foo
recho "$foo"
recho ${foo}"$@"
recho ${foo}$@
array=(ab cd ef)
recho ${foo}"${array[@]}"
recho ${foo}${array[@]}
recho $(echo $foo)"$@"
recho $(echo $foo)$@
a=('word1 with spaces' 'word2 with spaces')
set - ${a[@]/word/element}
echo $#
recho "$@"
recho $@
IFS="$oIFS"
unset a a2 array foo
+123
View File
@@ -0,0 +1,123 @@
# test cases for array quoting and escaping fixed post bash-3.2-release
oIFS="$IFS"
a=(a b c)
echo ${a[@]}
a2=("${a[@]/#/"-iname '"}")
recho "${a2[@]}"
echo "${dbg-"'hey'"}"
echo "${dbg-"hey"}"
echo "${dbg-'"'hey}"
echo "${dbg-'"hey'}"
unset a a2
IFS=
a2=(${a[@]/#/"-iname '"})
recho "${a2[@]}"
IFS="$oIFS"
unset a a2
a=('a b' 'c d' 'e f')
recho ${a[@]:1:2}
recho "${a[@]:1:2}"
IFS=
recho ${a[@]:1:2}
recho "${a[@]:1:2}"
IFS="$oIFS"
unset a a2
a=(abc def)
# Prevent word splitting
#IFS=
a2=("${a[@]/#/"-iname '"}")
recho "${a2[@]}"
eval a2=("${a[@]/#/"-iname '"}")
recho "${a2[@]}"
a2=("${a[@]/#/-iname \'}")
recho "${a2[@]}"
eval a2=("${a[@]/#/-iname \'}")
recho "${a2[@]}"
set -- abc def
a2=("${@/#/"-iname '"}")
recho "${a2[@]}"
eval a2=("${@/#/"-iname '"}")
recho "${a2[@]}"
unset a a2
IFS=
pat=('*.*')
case $(ls ${pat[@]} 2>/dev/null) in
'') echo '*.* BAD' ;;
*) echo '*.* OK' ;;
esac
IFS="$oIFS"
unset a a2 pat
IFS=
s='abc'
set - ${s/b/1 2 3}
echo $#
echo "$1"
IFS="$oIFS"
unset s
set -- ab cd ef
foo="var with spaces"
IFS=
recho $foo
recho "$foo"
recho ${foo}"$@"
recho ${foo}$@
array=(ab cd ef)
recho ${foo}"${array[@]}"
recho ${foo}${array[@]}
recho $(echo $foo)"$@"
recho $(echo $foo)$@
a=('word1 with spaces' 'word2 with spaces')
set - ${a[@]/word/element}
echo $#
recho "$@"
recho $@
IFS="$oIFS"
unset a a2 array foo
a=$'ab\001cd\001ef'
recho $a
recho "$a"
recho $(echo $a)
recho $(echo "$a")
# XXX - this doesn't work right until post-bash-3.2
IFS=$'\001'
recho $a
IFS=$'\001' recho "$a"
+11
View File
@@ -145,3 +145,14 @@ argv[4] = <d>
argv[5] = <e>
a?b?c
a b c
argv[1] = <^?>
argv[1] = <^?>
argv[1] = <^?>
argv[1] = <^?>
argv[1] = <^?>
argv[1] = <^?>
argv[1] = <^A>
argv[2] = <^?>
argv[1] = <^A^?>
argv[1] = <^A^?^A^?>
argv[1] = <^A^A^?>
+382
View File
@@ -0,0 +1,382 @@
#
# A suite of tests for bash word expansions
#
# This tests parameter and variable expansion, with an empahsis on
# proper quoting behavior.
#
# Chet Ramey
#
# If you comment out the body of this function, you can do a diff against
# `expansion-tests.right' to see if the shell is behaving correctly
#
expect()
{
echo expect "$@"
}
# Test the substitution quoting characters (CTLESC and CTLNUL) in different
# combinations
expect "<^A>"
recho `echo ''`
expect "<^A>"
recho `echo ""`
expect "<^B>"
recho `echo ''`
expect "<^B>"
recho `echo ""`
expect "<^A>"
recho `echo `
expect "<^B>"
recho `echo `
# Test null strings without variable expansion
expect "<abcdefgh>"
recho abcd""efgh
expect "<abcdefgh>"
recho abcd''efgh
expect "<abcdefgh>"
recho ""abcdefgh
expect "<abcdefgh>"
recho ''abcdefgh
expect "<abcd>"
recho abcd""
expect "<abcd>"
recho abcd''
# Test the quirky behavior of $@ in ""
expect nothing
recho "$@"
expect "< >"
recho " $@"
expect "<-->"
recho "-${@}-"
# Test null strings with variable expansion that fails
expect '<>'
recho $xxx""
expect '<>'
recho ""$xxx
expect '<>'
recho $xxx''
expect '<>'
recho ''$xxx
expect '<>'
recho $xxx""$yyy
expect '<>'
recho $xxx''$yyy
# Test null strings with variable expansion that succeeds
xxx=abc
yyy=def
expect '<abc>'
recho $xxx""
expect '<abc>'
recho ""$xxx
expect '<abc>'
recho $xxx''
expect '<abc>'
recho ''$xxx
expect '<abcdef>'
recho $xxx""$yyy
expect '<abcdef>'
recho $xxx''$yyy
unset xxx yyy
# Test the unquoted special quoting characters
expect "<^A>"
recho 
expect "<^B>"
recho 
expect "<^A>"
recho ""
expect "<^B>"
recho ""
expect "<^A>"
recho ''
expect "<^B>"
recho ''
# Test expansion of a variable that is unset
expect nothing
recho $xxx
expect '<>'
recho "$xxx"
expect nothing
recho "$xxx${@}"
# Test empty string expansion
expect '<>'
recho ""
expect '<>'
recho ''
# Test command substitution with (disabled) history substitution
expect '<Hello World!>'
# set +H
recho "`echo \"Hello world!\"`"
# Test some shell special characters
expect '<`>'
recho "\`"
expect '<">'
recho "\""
expect '<\^A>'
recho "\"
expect '<\$>'
recho "\\$"
expect '<\\>'
recho "\\\\"
# This should give argv[1] = a argv[2] = b
expect '<a> <b>'
FOO=`echo 'a b' | tr ' ' '\012'`
recho $FOO
# This should give argv[1] = ^A argv[2] = ^B
expect '<^A> <^B>'
FOO=`echo ' ' | tr ' ' '\012'`
recho $FOO
# Test quoted and unquoted globbing characters
expect '<**>'
recho "*"*
expect '<\.\./*/>'
recho "\.\./*/"
# Test patterns that come up when the shell quotes funny character
# combinations
expect '<^A^B^A^B>'
recho ''
expect '<^A^A>'
recho ''
expect '<^A^B>'
recho ''
expect '<^A^A^B>'
recho ''
# More tests of "$@"
set abc def ghi jkl
expect '< abc> <def> <ghi> <jkl >'
recho " $@ "
expect '< abc> <def> <ghi> <jkl >'
recho "${1+ $@ }"
set abc def ghi jkl
expect '<--abc> <def> <ghi> <jkl-->'
recho "--$@--"
set "a b" cd ef gh
expect '<a b> <cd> <ef> <gh>'
recho ${1+"$@"}
expect '<a b> <cd> <ef> <gh>'
recho ${foo:-"$@"}
expect '<a b> <cd> <ef> <gh>'
recho "${@}"
expect '< >'
recho " "
expect '< - >'
recho " - "
# Test combinations of different types of quoting in a fully-quoted string
# (so the WHOLLY_QUOTED tests fail and it doesn't get set)
expect '</^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/>'
recho "/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/"
# Test the various Posix parameter expansions
expect '<foo bar>'
recho "${x:-$(echo "foo bar")}"
expect '<foo> <bar>'
recho ${x:-$(echo "foo bar")}
unset X
expect '<abc>'
recho ${X:=abc}
expect '<abc>'
recho $X
set a b c
expect '<posix>'
recho ${3:+posix}
POSIX=/usr/posix
expect '<10>'
recho ${#POSIX}
# remove shortest trailing match
x=file.c
expect '<file.o>'
recho ${x%.c}.o
# remove longest trailing match
x=posix/src/std
expect '<posix>'
recho ${x%%/*}
# remove shortest leading pattern
x=$HOME/src/cmd
expect '</src/cmd>'
recho ${x#$HOME}
# remove longest leading pattern
x=/one/two/three
expect '<three>'
recho ${x##*/}
# pattern removal of patterns that don't match
z=abcdef
expect '<abcdef>'
recho ${z#xyz}
expect '<abcdef>'
recho ${z##xyz}
expect '<abcdef>'
recho ${z%xyz}
expect '<abcdef>'
recho ${z%%xyz}
# Command substitution and the quirky differences between `` and $()
expect '<\$x>'
recho '\$x'
expect '<$x>'
recho `echo '\$x'`
expect '<\$x>'
recho $(echo '\$x')
# The difference between $* "$*" and "$@"
set "abc" "def ghi" "jkl"
expect '<abc> <def> <ghi> <jkl>'
recho $*
expect '<abc def ghi jkl>'
recho "$*"
OIFS="$IFS"
IFS=":$IFS"
# The special behavior of "$*", using the first character of $IFS as separator
expect '<abc:def ghi:jkl>'
recho "$*"
IFS="$OIFS"
expect '<abc> <def ghi> <jkl>'
recho "$@"
expect '<xxabc> <def ghi> <jklyy>'
recho "xx$@yy"
expect '<abc> <def ghi> <jklabc> <def ghi> <jkl>'
recho "$@$@"
foo=abc
bar=def
expect '<abcdef>'
recho "$foo""$bar"
unset foo
set $foo bar '' xyz "$foo" abc
expect '<bar> <> <xyz> <> <abc>'
recho "$@"
# More tests of quoting and deferred evaluation
foo=10 x=foo
y='$'$x
expect '<$foo>'
recho $y
eval y='$'$x
expect '<10>'
recho $y
# case statements
NL='
'
x='ab
cd'
expect '<newline expected>'
case "$x" in
*$NL*) recho "newline expected" ;;
esac
expect '<got it>'
case \? in
*"?"*) recho "got it" ;;
esac
expect '<got it>'
case \? in
*\?*) recho "got it" ;;
esac
set one two three four five
expect '<one> <three> <five>'
recho $1 $3 ${5} $8 ${9}
# length tests on positional parameters and some special parameters
expect '<5> <5>'
recho $# ${#}
expect '<3>'
recho ${#1}
expect '<1>'
recho ${##}
expect '<1>'
recho ${#?}
expect '<5>'
recho ${#@}
expect '<5>'
recho ${#*}
expect '<5>'
recho "${#@}"
expect '<5>'
recho "${#*}"
expect '<42>'
recho $((28 + 14))
expect '<26>'
recho $[ 13 * 2 ]
expect '<\>'
recho `echo \\\\`
expect '<~>'
recho '~'
expect nothing
recho $!
expect nothing
recho ${!}
# test word splitting of assignment statements not preceding a command
a="a b c d e"
declare b=$a
expect '<a> <b> <c> <d> <e>'
recho $b
a="a?b?c"
echo ${a//\\?/ }
echo ${a//\?/ }
${THIS_SH} ./exp1.sub
+380
View File
@@ -0,0 +1,380 @@
#
# A suite of tests for bash word expansions
#
# This tests parameter and variable expansion, with an empahsis on
# proper quoting behavior.
#
# Chet Ramey
#
# If you comment out the body of this function, you can do a diff against
# `expansion-tests.right' to see if the shell is behaving correctly
#
expect()
{
echo expect "$@"
}
# Test the substitution quoting characters (CTLESC and CTLNUL) in different
# combinations
expect "<^A>"
recho `echo ''`
expect "<^A>"
recho `echo ""`
expect "<^B>"
recho `echo ''`
expect "<^B>"
recho `echo ""`
expect "<^A>"
recho `echo `
expect "<^B>"
recho `echo `
# Test null strings without variable expansion
expect "<abcdefgh>"
recho abcd""efgh
expect "<abcdefgh>"
recho abcd''efgh
expect "<abcdefgh>"
recho ""abcdefgh
expect "<abcdefgh>"
recho ''abcdefgh
expect "<abcd>"
recho abcd""
expect "<abcd>"
recho abcd''
# Test the quirky behavior of $@ in ""
expect nothing
recho "$@"
expect "< >"
recho " $@"
expect "<-->"
recho "-${@}-"
# Test null strings with variable expansion that fails
expect '<>'
recho $xxx""
expect '<>'
recho ""$xxx
expect '<>'
recho $xxx''
expect '<>'
recho ''$xxx
expect '<>'
recho $xxx""$yyy
expect '<>'
recho $xxx''$yyy
# Test null strings with variable expansion that succeeds
xxx=abc
yyy=def
expect '<abc>'
recho $xxx""
expect '<abc>'
recho ""$xxx
expect '<abc>'
recho $xxx''
expect '<abc>'
recho ''$xxx
expect '<abcdef>'
recho $xxx""$yyy
expect '<abcdef>'
recho $xxx''$yyy
unset xxx yyy
# Test the unquoted special quoting characters
expect "<^A>"
recho 
expect "<^B>"
recho 
expect "<^A>"
recho ""
expect "<^B>"
recho ""
expect "<^A>"
recho ''
expect "<^B>"
recho ''
# Test expansion of a variable that is unset
expect nothing
recho $xxx
expect '<>'
recho "$xxx"
expect nothing
recho "$xxx${@}"
# Test empty string expansion
expect '<>'
recho ""
expect '<>'
recho ''
# Test command substitution with (disabled) history substitution
expect '<Hello World!>'
# set +H
recho "`echo \"Hello world!\"`"
# Test some shell special characters
expect '<`>'
recho "\`"
expect '<">'
recho "\""
expect '<\^A>'
recho "\"
expect '<\$>'
recho "\\$"
expect '<\\>'
recho "\\\\"
# This should give argv[1] = a argv[2] = b
expect '<a> <b>'
FOO=`echo 'a b' | tr ' ' '\012'`
recho $FOO
# This should give argv[1] = ^A argv[2] = ^B
expect '<^A> <^B>'
FOO=`echo ' ' | tr ' ' '\012'`
recho $FOO
# Test quoted and unquoted globbing characters
expect '<**>'
recho "*"*
expect '<\.\./*/>'
recho "\.\./*/"
# Test patterns that come up when the shell quotes funny character
# combinations
expect '<^A^B^A^B>'
recho ''
expect '<^A^A>'
recho ''
expect '<^A^B>'
recho ''
expect '<^A^A^B>'
recho ''
# More tests of "$@"
set abc def ghi jkl
expect '< abc> <def> <ghi> <jkl >'
recho " $@ "
expect '< abc> <def> <ghi> <jkl >'
recho "${1+ $@ }"
set abc def ghi jkl
expect '<--abc> <def> <ghi> <jkl-->'
recho "--$@--"
set "a b" cd ef gh
expect '<a b> <cd> <ef> <gh>'
recho ${1+"$@"}
expect '<a b> <cd> <ef> <gh>'
recho ${foo:-"$@"}
expect '<a b> <cd> <ef> <gh>'
recho "${@}"
expect '< >'
recho " "
expect '< - >'
recho " - "
# Test combinations of different types of quoting in a fully-quoted string
# (so the WHOLLY_QUOTED tests fail and it doesn't get set)
expect '</^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/>'
recho "/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/"
# Test the various Posix parameter expansions
expect '<foo bar>'
recho "${x:-$(echo "foo bar")}"
expect '<foo> <bar>'
recho ${x:-$(echo "foo bar")}
unset X
expect '<abc>'
recho ${X:=abc}
expect '<abc>'
recho $X
set a b c
expect '<posix>'
recho ${3:+posix}
POSIX=/usr/posix
expect '<10>'
recho ${#POSIX}
# remove shortest trailing match
x=file.c
expect '<file.o>'
recho ${x%.c}.o
# remove longest trailing match
x=posix/src/std
expect '<posix>'
recho ${x%%/*}
# remove shortest leading pattern
x=$HOME/src/cmd
expect '</src/cmd>'
recho ${x#$HOME}
# remove longest leading pattern
x=/one/two/three
expect '<three>'
recho ${x##*/}
# pattern removal of patterns that don't match
z=abcdef
expect '<abcdef>'
recho ${z#xyz}
expect '<abcdef>'
recho ${z##xyz}
expect '<abcdef>'
recho ${z%xyz}
expect '<abcdef>'
recho ${z%%xyz}
# Command substitution and the quirky differences between `` and $()
expect '<\$x>'
recho '\$x'
expect '<$x>'
recho `echo '\$x'`
expect '<\$x>'
recho $(echo '\$x')
# The difference between $* "$*" and "$@"
set "abc" "def ghi" "jkl"
expect '<abc> <def> <ghi> <jkl>'
recho $*
expect '<abc def ghi jkl>'
recho "$*"
OIFS="$IFS"
IFS=":$IFS"
# The special behavior of "$*", using the first character of $IFS as separator
expect '<abc:def ghi:jkl>'
recho "$*"
IFS="$OIFS"
expect '<abc> <def ghi> <jkl>'
recho "$@"
expect '<xxabc> <def ghi> <jklyy>'
recho "xx$@yy"
expect '<abc> <def ghi> <jklabc> <def ghi> <jkl>'
recho "$@$@"
foo=abc
bar=def
expect '<abcdef>'
recho "$foo""$bar"
unset foo
set $foo bar '' xyz "$foo" abc
expect '<bar> <> <xyz> <> <abc>'
recho "$@"
# More tests of quoting and deferred evaluation
foo=10 x=foo
y='$'$x
expect '<$foo>'
recho $y
eval y='$'$x
expect '<10>'
recho $y
# case statements
NL='
'
x='ab
cd'
expect '<newline expected>'
case "$x" in
*$NL*) recho "newline expected" ;;
esac
expect '<got it>'
case \? in
*"?"*) recho "got it" ;;
esac
expect '<got it>'
case \? in
*\?*) recho "got it" ;;
esac
set one two three four five
expect '<one> <three> <five>'
recho $1 $3 ${5} $8 ${9}
# length tests on positional parameters and some special parameters
expect '<5> <5>'
recho $# ${#}
expect '<3>'
recho ${#1}
expect '<1>'
recho ${##}
expect '<1>'
recho ${#?}
expect '<5>'
recho ${#@}
expect '<5>'
recho ${#*}
expect '<5>'
recho "${#@}"
expect '<5>'
recho "${#*}"
expect '<42>'
recho $((28 + 14))
expect '<26>'
recho $[ 13 * 2 ]
expect '<\>'
recho `echo \\\\`
expect '<~>'
recho '~'
expect nothing
recho $!
expect nothing
recho ${!}
# test word splitting of assignment statements not preceding a command
a="a b c d e"
declare b=$a
expect '<a> <b> <c> <d> <e>'
recho $b
a="a?b?c"
echo ${a//\\?/ }
echo ${a//\?/ }
+21
View File
@@ -0,0 +1,21 @@
# Test the substitution quoting characters (CTLESC and CTLNUL) in different
# combinations
recho `echo ''`
recho `echo ""`
recho `echo `
# Test the unquoted special quoting characters
recho 
recho ""
recho ''
# This should give argv[1] = ^A argv[2] = ^?
FOO=`echo ' ' | tr ' ' '\012'`
recho $FOO
# Test patterns that come up when the shell quotes funny character
# combinations
recho ''
recho ''
recho ''
+94
View File
@@ -0,0 +1,94 @@
a=$'a\001b'
set $a
b=$a
c=$1
d="$1"
e=$'uv\001\001wx'
f=$'uv\001w\001xy'
set $e $e
recho ${e%%??}
recho "${e%%??}"
recho ${e%%???}
recho "${e%%???}"
recho ${a#?}
recho "${a#?}"
# simple variables
recho ${f##*$'\001'}
recho "${f##*$'\001'}"
recho ${f##*''} # literal ^A
recho "${f##*'^A'}" # two characters, `^' and `A'
recho ${e%$'\001'*}
recho "${e%$'\001'*}"
recho ${e#*$'\001'}
recho "${e#*$'\001'}"
# array members
arr[0]=$e
arr[1]=$f
recho ${arr[1]##*$'\001'}
recho "${arr[1]##*$'\001'}"
recho ${arr[1]##*''} # literal ^A
recho "${arr[1]##*'^A'}" # two characters, `^' and `A'
recho ${arr[0]%$'\001'*}
recho "${arr[0]%$'\001'*}"
recho ${arr[0]#*$'\001'}
recho "${arr[0]#*$'\001'}"
recho ${arr%$'\001'*}
recho "${arr%$'\001'*}"
recho ${arr#*$'\001'}
recho "${arr#*$'\001'}"
# positional parameters
set $e $f
recho ${2##*$'\001'}
recho "${2##*$'\001'}"
recho ${2##*''} # literal ^A
recho "${2##*''}" # literal ^A
recho ${2##*'^A'} # two characters, `^' and `A'
recho "${2##*'^A'}" # two characters, `^' and `A'
recho ${1%$'\001'*}
recho "${1%$'\001'*}"
recho ${1#*$'\001'}
recho "${1#*$'\001'}"
recho ${@%$'\001'*}
recho "${@%$'\001'*}"
recho ${@#*$'\001'}
recho "${@#*$'\001'}"
recho ${@##*''} # literal ^A
recho "${@##*'^A'}" # two characters, `^' and `A'
# arrays treated as a whole
recho ${arr[@]%$'\001'*}
recho "${arr[@]%$'\001'*}"
recho ${arr[@]#*$'\001'}
recho "${arr[@]#*$'\001'}"
recho ${arr[@]##*''} # literal ^A
recho "${arr[@]##*'^A'}" # two characters, `^' and `A'
# make sure command substitution works with CTLESC as well
a=$'ab\001cd\001ef'
recho $a
recho "$a"
recho $(echo $a)
recho $(echo "$a")
+86
View File
@@ -0,0 +1,86 @@
argv[1] = <ab>
argv[2] = <cd>
argv[3] = <ef>
argv[1] = <ab>
argv[2] = <cd>
argv[3] = <ef>
argv[1] = <xxab>
argv[2] = <cd>
argv[3] = <efyy>
argv[1] = <ab^Acd^Aef>
argv[1] = <ab cd ef>
argv[1] = <ab>
argv[2] = <cd>
argv[3] = <ef>
argv[1] = <ab>
argv[2] = <cd>
argv[1] = <ab^Acd^A>
argv[1] = <ab>
argv[2] = <cd>
argv[3] = <e>
argv[1] = <ab^Acd^Ae>
argv[1] = <ab>
argv[2] = <cd>
argv[3] = <ef>
argv[1] = <ab>
argv[2] = <cd>
argv[3] = <ef>
argv[1] = <>
argv[2] = <c>
argv[1] = <ab>
argv[2] = <-->
argv[3] = <cd>
argv[4] = <-->
argv[5] = <ef>
argv[1] = <ab>
argv[2] = <cd>
argv[3] = <ef>
argv[1] = <ab>
argv[2] = <cd>
argv[3] = <ef>
argv[1] = <ab>
argv[2] = <-->
argv[3] = <cd>
argv[4] = <-->
argv[5] = <ef>
argv[1] = <uv^?wx^?yz>
argv[1] = <abyab^Acd^Aefz>
argv[1] = <abyab>
argv[2] = <cd>
argv[3] = <efz>
argv[1] = <abuv^?wx^?yzyab^Acd^Aefz>
argv[1] = <abuv^?wx^?yzyab>
argv[2] = <cd>
argv[3] = <efz>
argv[1] = <abuv^?wx^?yzyab>
argv[2] = <-->
argv[3] = <cd>
argv[4] = <-->
argv[5] = <efz>
argv[6] = <-->
argv[1] = <ab^Acd^Aef>
argv[1] = <uv>
argv[2] = <wx>
argv[3] = <yz>
argv[1] = <abyuv^?wx^?yzz>
argv[1] = <abyuv>
argv[2] = <wx>
argv[3] = <yzz>
argv[1] = <abuv^?wx^?yzyab^Acd^Aefz>
argv[1] = <abuv>
argv[2] = <wx>
argv[3] = <yzyab^Acd^Aefz>
argv[1] = <abuv^?wx^?yzyab>
argv[2] = <-->
argv[3] = <cd>
argv[4] = <-->
argv[5] = <efz>
argv[6] = <-->
argv[7] = <>
argv[1] = <abuv>
argv[2] = <-->
argv[3] = <wx>
argv[4] = <-->
argv[5] = <yzyab^Acd^Aefz>
argv[6] = <-->
argv[7] = <>
+63
View File
@@ -0,0 +1,63 @@
a=$'ab\001cd\001ef'
IFS=$'\001'
recho $a
recho ${a}
recho xx${a}yy
recho "$a"
recho $(echo $a)
recho $(echo "$a")
recho ${a%%??}
recho "${a%%??}"
recho ${a/f/}
recho "${a/f/}"
a1=("$a")
recho ${a1[0]}
recho ${a1}
recho ${a:2:2}
set -- $a
recho $1 -- $2 -- $3
set -- "$a"
recho $1
recho ${1}
echo "$a" | { IFS=$'\001' read x y z; recho $x -- $y -- $z ; }
unset x y z
b=$'uv\177wx\177yz'
recho $b
recho "ab${x}y${a}z"
recho ab${x}y${a}z
recho "ab${b}y${a}z"
recho ab${b}y${a}z
echo "ab${b}y${a}z" | { IFS=$'\001' read l m n o ; recho $l -- $m -- $n -- $o; }
unset l m n o
a=$'ab\001cd\001ef'
b=$'uv\177wx\177yz'
IFS=$'\177'
recho $a
recho $b
recho "ab${x}y${b}z"
recho ab${x}y${b}z
recho "ab${b}y${a}z"
recho ab${b}y${a}z
echo "ab${b}y${a}z" | { IFS=$'\001' read l m n o ; recho "$l" -- "$m" -- "$n" -- "$o"; }
unset l m n o
echo "ab${b}y${a}z" | { IFS=$'\177' read l m n o ; recho "$l" -- "$m" -- "$n" -- "$o"; }
unset l m n o
+43
View File
@@ -0,0 +1,43 @@
a=$'ab\001cd\001ef'
IFS=$'\001'
recho $a
recho ${a}
recho xx${a}yy
recho "$a"
recho $(echo $a)
recho $(echo "$a")
recho ${a%%??}
recho "${a%%??}"
recho ${a/f/}
recho "${a/f/}"
a1=("$a")
recho ${a1[0]}
recho ${a1}
recho ${a:2:2}
set -- $a
recho $1 -- $2 -- $3
set -- "$a"
recho $1
recho ${1}
echo "$a" | { IFS=$'\001' read x y z; recho $x -- $y -- $z ; }
unset x y z
b=$'uv\177wx\177yz'
recho $b
recho "ab${x}y${a}z"
recho ab${x}y${a}z
recho "ab${b}y${a}z"
recho ab${b}y${a}z
echo "ab${b}y${a}z" | { IFS=$'\001' read l m n o ; recho $l -- $m -- $n -- $o; }
+2 -1
View File
@@ -1,5 +1,6 @@
echo "warning: some of these tests may fail if process substitution has not" >&2
echo "warning: been compiled into the shell" >&2
echo "warning: been compiled into the shell or if the OS does not provide" >&2
echo "warning: /dev/fd." >&2
${THIS_SH} ./builtins.tests > /tmp/xx 2>&1
diff /tmp/xx builtins.right && rm -f /tmp/xx
+6
View File
@@ -0,0 +1,6 @@
echo "warning: some of these tests may fail if process substitution has not" >&2
echo "warning: been compiled into the shell or if the OS does not provide" >&2
ecoh "warning: /dev/fd." >&2
${THIS_SH} ./builtins.tests > /tmp/xx 2>&1
diff /tmp/xx builtins.right && rm -f /tmp/xx
+1 -1
View File
@@ -1,2 +1,2 @@
${THIS_SH} ./exp-tests | grep -v '^expect' > /tmp/xx
${THIS_SH} ./exp.tests | grep -v '^expect' > /tmp/xx
diff /tmp/xx exp.right && rm -f /tmp/xx
+2
View File
@@ -0,0 +1,2 @@
${THIS_SH} ./exp-tests | grep -v '^expect' > /tmp/xx
diff /tmp/xx exp.right && rm -f /tmp/xx
+2
View File
@@ -0,0 +1,2 @@
${THIS_SH} ./nquote5.tests 2>&1 | grep -v '^expect' > /tmp/xx
diff /tmp/xx nquote5.right && rm -f /tmp/xx
+4
View File
@@ -0,0 +1,4 @@
echo warning: some of these tests will fail if you do not have UTF-8 >&2
echo warning: locales installed on your system
${THIS_SH} ./nquote4.tests 2>&1 | grep -v '^expect' > /tmp/xx
diff /tmp/xx nquote4.right && rm -f /tmp/xx