Bash-4.3 distribution sources and documentation
This commit is contained in:
parent
4539d736f1
commit
ac50fbac37
497 changed files with 129395 additions and 87598 deletions
202
braces.c
202
braces.c
|
|
@ -1,6 +1,6 @@
|
|||
/* braces.c -- code for doing word expansion in curly braces. */
|
||||
|
||||
/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2012 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
|
@ -31,22 +31,32 @@
|
|||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#if defined (SHELL)
|
||||
# include "shell.h"
|
||||
#endif /* SHELL */
|
||||
|
||||
#include "typemax.h" /* INTMAX_MIN, INTMAX_MAX */
|
||||
#include "general.h"
|
||||
#include "shmbutil.h"
|
||||
#include "chartypes.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
|
||||
|
||||
#define BRACE_SEQ_SPECIFIER ".."
|
||||
|
||||
extern int asprintf __P((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
|
||||
|
||||
extern int last_command_exit_value;
|
||||
|
||||
/* Basic idea:
|
||||
|
||||
Segregate the text into 3 sections: preamble (stuff before an open brace),
|
||||
|
|
@ -63,7 +73,7 @@ static const int brace_arg_separator = ',';
|
|||
static int brace_gobbler __P((char *, size_t, int *, int));
|
||||
static char **expand_amble __P((char *, size_t, int));
|
||||
static char **expand_seqterm __P((char *, size_t));
|
||||
static char **mkseq __P((intmax_t, intmax_t, int, int, int));
|
||||
static char **mkseq __P((intmax_t, intmax_t, intmax_t, int, int));
|
||||
static char **array_concat __P((char **, char **));
|
||||
#else
|
||||
static int brace_gobbler ();
|
||||
|
|
@ -136,7 +146,8 @@ brace_expand (text)
|
|||
#endif /* !CSH_BRACE_COMPAT */
|
||||
|
||||
preamble = (char *)xmalloc (i + 1);
|
||||
strncpy (preamble, text, i);
|
||||
if (i > 0)
|
||||
strncpy (preamble, text, i);
|
||||
preamble[i] = '\0';
|
||||
|
||||
result = (char **)xmalloc (2 * sizeof (char *));
|
||||
|
|
@ -171,6 +182,7 @@ brace_expand (text)
|
|||
if (text[j] == brace_arg_separator)
|
||||
{ /* { */
|
||||
strvec_dispose (result);
|
||||
last_command_exit_value = 1;
|
||||
report_error ("no closing `%c' in %s", '}', text);
|
||||
throw_to_top_level ();
|
||||
}
|
||||
|
|
@ -218,6 +230,19 @@ brace_expand (text)
|
|||
tack = expand_seqterm (amble, alen);
|
||||
if (tack)
|
||||
goto add_tack;
|
||||
else if (text[i + 1])
|
||||
{
|
||||
/* If the sequence expansion fails (e.g., because the integers
|
||||
overflow), but there is more in the string, try and process
|
||||
the rest of the string, which may contain additional brace
|
||||
expansions. Treat the unexpanded sequence term as a simple
|
||||
string (including the braces). */
|
||||
tack = strvec_create (2);
|
||||
tack[0] = savestring (text+start-1);
|
||||
tack[0][i-start+2] = '\0';
|
||||
tack[1] = (char *)0;
|
||||
goto add_tack;
|
||||
}
|
||||
else
|
||||
{
|
||||
free (amble);
|
||||
|
|
@ -232,13 +257,18 @@ brace_expand (text)
|
|||
add_tack:
|
||||
result = array_concat (result, tack);
|
||||
free (amble);
|
||||
strvec_dispose (tack);
|
||||
if (tack != result)
|
||||
strvec_dispose (tack);
|
||||
|
||||
postamble = text + i + 1;
|
||||
|
||||
tack = brace_expand (postamble);
|
||||
result = array_concat (result, tack);
|
||||
strvec_dispose (tack);
|
||||
if (postamble && *postamble)
|
||||
{
|
||||
tack = brace_expand (postamble);
|
||||
result = array_concat (result, tack);
|
||||
if (tack != result)
|
||||
strvec_dispose (tack);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
|
@ -253,7 +283,7 @@ expand_amble (text, tlen, flags)
|
|||
size_t tlen;
|
||||
int flags;
|
||||
{
|
||||
char **result, **partial;
|
||||
char **result, **partial, **tresult;
|
||||
char *tem;
|
||||
int start, i, c;
|
||||
|
||||
|
|
@ -285,7 +315,16 @@ expand_amble (text, tlen, flags)
|
|||
lr = strvec_len (result);
|
||||
lp = strvec_len (partial);
|
||||
|
||||
result = strvec_resize (result, lp + lr + 1);
|
||||
tresult = strvec_mresize (result, lp + lr + 1);
|
||||
if (tresult == 0)
|
||||
{
|
||||
internal_error (_("brace expansion: cannot allocate memory for %s"), tem);
|
||||
strvec_dispose (result);
|
||||
result = (char **)NULL;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
result = tresult;
|
||||
|
||||
for (j = 0; j < lp; j++)
|
||||
result[lr + j] = partial[j];
|
||||
|
|
@ -305,25 +344,75 @@ expand_amble (text, tlen, flags)
|
|||
#define ST_CHAR 2
|
||||
#define ST_ZINT 3
|
||||
|
||||
#ifndef sh_imaxabs
|
||||
# define sh_imaxabs(x) (((x) >= 0) ? (x) : -(x))
|
||||
#endif
|
||||
|
||||
/* Handle signed arithmetic overflow and underflow. Have to do it this way
|
||||
to avoid compilers optimizing out simpler overflow checks. */
|
||||
|
||||
/* Make sure that a+b does not exceed MAXV or is smaller than MINV (if b < 0).
|
||||
Assumes that b > 0 if a > 0 and b < 0 if a < 0 */
|
||||
#define ADDOVERFLOW(a,b,minv,maxv) \
|
||||
((((a) > 0) && ((b) > ((maxv) - (a)))) || \
|
||||
(((a) < 0) && ((b) < ((minv) - (a)))))
|
||||
|
||||
/* Make sure that a-b is not smaller than MINV or exceeds MAXV (if b < 0).
|
||||
Assumes that b > 0 if a > 0 and b < 0 if a < 0 */
|
||||
#define SUBOVERFLOW(a,b,minv,maxv) \
|
||||
((((b) > 0) && ((a) < ((minv) + (b)))) || \
|
||||
(((b) < 0) && ((a) > ((maxv) + (b)))))
|
||||
|
||||
static char **
|
||||
mkseq (start, end, incr, type, width)
|
||||
intmax_t start, end;
|
||||
int incr, type, width;
|
||||
intmax_t start, end, incr;
|
||||
int type, width;
|
||||
{
|
||||
intmax_t n;
|
||||
int i;
|
||||
intmax_t n, prevn;
|
||||
int i, j, nelem;
|
||||
char **result, *t;
|
||||
|
||||
i = abs (end - start) + 1;
|
||||
result = strvec_create (i + 1);
|
||||
|
||||
if (incr == 0)
|
||||
incr = 1;
|
||||
|
||||
|
||||
if (start > end && incr > 0)
|
||||
incr = -incr;
|
||||
else if (start < end && incr < 0)
|
||||
incr = -incr;
|
||||
{
|
||||
if (incr == INTMAX_MIN) /* Don't use -INTMAX_MIN */
|
||||
return ((char **)NULL);
|
||||
incr = -incr;
|
||||
}
|
||||
|
||||
/* Check that end-start will not overflow INTMAX_MIN, INTMAX_MAX. The +3
|
||||
and -2, not strictly necessary, are there because of the way the number
|
||||
of elements and value passed to strvec_create() are calculated below. */
|
||||
if (SUBOVERFLOW (end, start, INTMAX_MIN+3, INTMAX_MAX-2))
|
||||
return ((char **)NULL);
|
||||
|
||||
prevn = sh_imaxabs (end - start);
|
||||
/* Need to check this way in case INT_MAX == INTMAX_MAX */
|
||||
if (INT_MAX == INTMAX_MAX && (ADDOVERFLOW (prevn, 2, INT_MIN, INT_MAX)))
|
||||
return ((char **)NULL);
|
||||
/* Make sure the assignment to nelem below doesn't end up <= 0 due to
|
||||
intmax_t overflow */
|
||||
else if (ADDOVERFLOW ((prevn/sh_imaxabs(incr)), 1, INTMAX_MIN, INTMAX_MAX))
|
||||
return ((char **)NULL);
|
||||
|
||||
/* XXX - TOFIX: potentially allocating a lot of extra memory if
|
||||
imaxabs(incr) != 1 */
|
||||
/* Instead of a simple nelem = prevn + 1, something like:
|
||||
nelem = (prevn / imaxabs(incr)) + 1;
|
||||
would work */
|
||||
nelem = (prevn / sh_imaxabs(incr)) + 1;
|
||||
if (nelem > INT_MAX - 2) /* Don't overflow int */
|
||||
return ((char **)NULL);
|
||||
result = strvec_mcreate (nelem + 1);
|
||||
if (result == 0)
|
||||
{
|
||||
internal_error (_("brace expansion: failed to allocate memory for %d elements"), nelem);
|
||||
return ((char **)NULL);
|
||||
}
|
||||
|
||||
/* Make sure we go through the loop at least once, so {3..3} prints `3' */
|
||||
i = 0;
|
||||
|
|
@ -334,7 +423,7 @@ mkseq (start, end, incr, type, width)
|
|||
QUIT; /* XXX - memory leak here */
|
||||
#endif
|
||||
if (type == ST_INT)
|
||||
result[i++] = itos (n);
|
||||
result[i++] = t = itos (n);
|
||||
else if (type == ST_ZINT)
|
||||
{
|
||||
int len, arg;
|
||||
|
|
@ -344,12 +433,33 @@ mkseq (start, end, incr, type, width)
|
|||
}
|
||||
else
|
||||
{
|
||||
t = (char *)xmalloc (2);
|
||||
t[0] = n;
|
||||
t[1] = '\0';
|
||||
if (t = (char *)malloc (2))
|
||||
{
|
||||
t[0] = n;
|
||||
t[1] = '\0';
|
||||
}
|
||||
result[i++] = t;
|
||||
}
|
||||
|
||||
/* We failed to allocate memory for this number, so we bail. */
|
||||
if (t == 0)
|
||||
{
|
||||
char *p, lbuf[INT_STRLEN_BOUND(intmax_t) + 1];
|
||||
|
||||
/* Easier to do this than mess around with various intmax_t printf
|
||||
formats (%ld? %lld? %jd?) and PRIdMAX. */
|
||||
p = inttostr (n, lbuf, sizeof (lbuf));
|
||||
internal_error (_("brace expansion: failed to allocate memory for `%s'"), p);
|
||||
strvec_dispose (result);
|
||||
return ((char **)NULL);
|
||||
}
|
||||
|
||||
/* Handle overflow and underflow of n+incr */
|
||||
if (ADDOVERFLOW (n, incr, INTMAX_MIN, INTMAX_MAX))
|
||||
break;
|
||||
|
||||
n += incr;
|
||||
|
||||
if ((incr < 0 && n < end) || (incr > 0 && n > end))
|
||||
break;
|
||||
}
|
||||
|
|
@ -365,8 +475,8 @@ expand_seqterm (text, tlen)
|
|||
size_t tlen;
|
||||
{
|
||||
char *t, *lhs, *rhs;
|
||||
int i, lhs_t, rhs_t, incr, lhs_l, rhs_l, width;
|
||||
intmax_t lhs_v, rhs_v;
|
||||
int i, lhs_t, rhs_t, lhs_l, rhs_l, width;
|
||||
intmax_t lhs_v, rhs_v, incr;
|
||||
intmax_t tl, tr;
|
||||
char **result, *ep, *oep;
|
||||
|
||||
|
|
@ -396,8 +506,9 @@ expand_seqterm (text, tlen)
|
|||
if (ISDIGIT (rhs[0]) || ((rhs[0] == '+' || rhs[0] == '-') && ISDIGIT (rhs[1])))
|
||||
{
|
||||
rhs_t = ST_INT;
|
||||
errno = 0;
|
||||
tr = strtoimax (rhs, &ep, 10);
|
||||
if (ep && *ep != 0 && *ep != '.')
|
||||
if (errno == ERANGE || (ep && *ep != 0 && *ep != '.'))
|
||||
rhs_t = ST_BAD; /* invalid */
|
||||
}
|
||||
else if (ISALPHA (rhs[0]) && (rhs[1] == 0 || rhs[1] == '.'))
|
||||
|
|
@ -415,10 +526,11 @@ expand_seqterm (text, tlen)
|
|||
if (rhs_t != ST_BAD)
|
||||
{
|
||||
oep = ep;
|
||||
errno = 0;
|
||||
if (ep && *ep == '.' && ep[1] == '.' && ep[2])
|
||||
incr = strtoimax (ep + 2, &ep, 10);
|
||||
if (*ep != 0)
|
||||
rhs_t = ST_BAD; /* invalid incr */
|
||||
if (*ep != 0 || errno == ERANGE)
|
||||
rhs_t = ST_BAD; /* invalid incr or overflow */
|
||||
tlen -= ep - oep;
|
||||
}
|
||||
|
||||
|
|
@ -535,6 +647,11 @@ brace_gobbler (text, tlen, indx, satisfy)
|
|||
{
|
||||
if (c == quoted)
|
||||
quoted = 0;
|
||||
#if defined (SHELL)
|
||||
/* The shell allows quoted command substitutions */
|
||||
if (quoted == '"' && c == '$' && text[i+1] == '(') /*)*/
|
||||
goto comsub;
|
||||
#endif
|
||||
ADVANCE_CHAR (text, tlen, i);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -550,6 +667,7 @@ brace_gobbler (text, tlen, indx, satisfy)
|
|||
/* Pass new-style command and process substitutions through unchanged. */
|
||||
if ((c == '$' || c == '<' || c == '>') && text[i+1] == '(') /* ) */
|
||||
{
|
||||
comsub:
|
||||
si = i + 2;
|
||||
t = extract_command_subst (text, &si, 0);
|
||||
i = si;
|
||||
|
|
@ -594,6 +712,20 @@ brace_gobbler (text, tlen, indx, satisfy)
|
|||
return (c);
|
||||
}
|
||||
|
||||
/* Return 1 if ARR has any non-empty-string members. Used to short-circuit
|
||||
in array_concat() below. */
|
||||
static int
|
||||
degenerate_array (arr)
|
||||
char **arr;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; arr[i]; i++)
|
||||
if (arr[i][0] != '\0')
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return a new array of strings which is the result of appending each
|
||||
string in ARR2 to each string in ARR1. The resultant array is
|
||||
len (arr1) * len (arr2) long. For convenience, ARR1 (and its contents)
|
||||
|
|
@ -607,10 +739,22 @@ array_concat (arr1, arr2)
|
|||
register char **result;
|
||||
|
||||
if (arr1 == 0)
|
||||
return (strvec_copy (arr2));
|
||||
return (arr2); /* XXX - see if we can get away without copying? */
|
||||
|
||||
if (arr2 == 0)
|
||||
return (strvec_copy (arr1));
|
||||
return (arr1); /* XXX - caller expects us to free arr1 */
|
||||
|
||||
/* We can only short-circuit if the array consists of a single null element;
|
||||
otherwise we need to replicate the contents of the other array and
|
||||
prefix (or append, below) an empty element to each one. */
|
||||
if (arr1[0] && arr1[0][0] == 0 && arr1[1] == 0)
|
||||
{
|
||||
strvec_dispose (arr1);
|
||||
return (arr2); /* XXX - use flags to see if we can avoid copying here */
|
||||
}
|
||||
|
||||
if (arr2[0] && arr2[0][0] == 0 && arr2[1] == 0)
|
||||
return (arr1); /* XXX - rather than copying and freeing it */
|
||||
|
||||
len1 = strvec_len (arr1);
|
||||
len2 = strvec_len (arr2);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue