Bash-4.3 distribution sources and documentation

This commit is contained in:
Chet Ramey 2014-02-26 09:36:43 -05:00
commit ac50fbac37
497 changed files with 129395 additions and 87598 deletions

127
expr.c
View file

@ -1,6 +1,6 @@
/* expr.c -- arithmetic expression evaluation. */
/* Copyright (C) 1990-2010 Free Software Foundation, Inc.
/* Copyright (C) 1990-2013 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@ -63,7 +63,7 @@
Implementation is a recursive-descent parser.
Chet Ramey
chet@ins.CWRU.Edu
chet@po.cwru.edu
*/
#include "config.h"
@ -82,12 +82,13 @@
#include "bashintl.h"
#include "shell.h"
#include "typemax.h" /* INTMAX_MAX, INTMAX_MIN */
/* Because of the $((...)) construct, expressions may include newlines.
Here is a macro which accepts newlines, tabs and spaces as whitespace. */
#define cr_whitespace(c) (whitespace(c) || ((c) == '\n'))
/* Size be which the expression stack grows when neccessary. */
/* Size be which the expression stack grows when necessary. */
#define EXPR_STACK_GROW_SIZE 10
/* Maximum amount of recursion allowed. This prevents a non-integer
@ -188,7 +189,9 @@ static void pushexp __P((void));
static void popexp __P((void));
static void expr_unwind __P((void));
static void expr_bind_variable __P((char *, char *));
#if defined (ARRAY_VARS)
static void expr_bind_array_element __P((char *, arrayind_t, char *));
#endif
static intmax_t subexpr __P((char *));
@ -309,10 +312,15 @@ static void
expr_bind_variable (lhs, rhs)
char *lhs, *rhs;
{
(void)bind_int_variable (lhs, rhs);
SHELL_VAR *v;
v = bind_int_variable (lhs, rhs);
if (v && (readonly_p (v) || noassign_p (v)))
longjmp (evalbuf, 1); /* variable assignment error */
stupidly_hack_special_variables (lhs);
}
#if defined (ARRAY_VARS)
/* Rewrite tok, which is of the form vname[expression], to vname[ind], where
IND is the already-calculated value of expression. */
static void
@ -333,11 +341,12 @@ expr_bind_array_element (tok, ind, rhs)
sprintf (lhs, "%s[%s]", vname, istr); /* XXX */
expr_bind_variable (lhs, rhs);
/*itrace("expr_bind_array_element: %s=%s", lhs, rhs);*/
expr_bind_variable (lhs, rhs);
free (vname);
free (lhs);
}
#endif /* ARRAY_VARS */
/* Evaluate EXPR, and return the arithmetic result. If VALIDP is
non-null, a zero is stored into the location to which it points
@ -366,7 +375,7 @@ evalexp (expr, validp)
FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf));
c = setjmp (evalbuf);
c = setjmp_nosigs (evalbuf);
if (c)
{
@ -450,6 +459,9 @@ expassign ()
register intmax_t value;
char *lhs, *rhs;
arrayind_t lind;
#if defined (HAVE_IMAXDIV)
imaxdiv_t idiv;
#endif
value = expcond ();
if (curtok == EQ || curtok == OP_ASSIGN)
@ -468,6 +480,7 @@ expassign ()
lvalue = value;
}
/* XXX - watch out for pointer aliasing issues here */
lhs = savestring (tokstr);
/* save ind in case rhs is string var and evaluation overwrites it */
lind = curlval.ind;
@ -490,10 +503,18 @@ expassign ()
lvalue *= value;
break;
case DIV:
lvalue /= value;
break;
case MOD:
lvalue %= value;
if (lvalue == INTMAX_MIN && value == -1)
lvalue = (op == DIV) ? INTMAX_MIN : 0;
else
#if HAVE_IMAXDIV
{
idiv = imaxdiv (lvalue, value);
lvalue = (op == DIV) ? idiv.quot : idiv.rem;
}
#else
lvalue = (op == DIV) ? lvalue / value : lvalue % value;
#endif
break;
case PLUS:
lvalue += value;
@ -527,16 +548,22 @@ expassign ()
rhs = itos (value);
if (noeval == 0)
{
#if defined (ARRAY_VARS)
if (lind != -1)
expr_bind_array_element (lhs, lind, rhs);
else
#endif
expr_bind_variable (lhs, rhs);
}
if (curlval.tokstr && curlval.tokstr == tokstr)
init_lvalue (&curlval);
free (rhs);
free (lhs);
FREE (tokstr);
tokstr = (char *)NULL; /* For freeing on errors. */
}
return (value);
}
@ -654,6 +681,7 @@ expbor ()
readtok ();
val2 = expbxor ();
val1 = val1 | val2;
lasttok = NUM;
}
return (val1);
@ -672,6 +700,7 @@ expbxor ()
readtok ();
val2 = expband ();
val1 = val1 ^ val2;
lasttok = NUM;
}
return (val1);
@ -690,6 +719,7 @@ expband ()
readtok ();
val2 = exp5 ();
val1 = val1 & val2;
lasttok = NUM;
}
return (val1);
@ -712,6 +742,7 @@ exp5 ()
val1 = (val1 == val2);
else if (op == NEQ)
val1 = (val1 != val2);
lasttok = NUM;
}
return (val1);
}
@ -740,6 +771,7 @@ exp4 ()
val1 = val1 < val2;
else /* (op == GT) */
val1 = val1 > val2;
lasttok = NUM;
}
return (val1);
}
@ -763,6 +795,7 @@ expshift ()
val1 = val1 << val2;
else
val1 = val1 >> val2;
lasttok = NUM;
}
return (val1);
@ -786,6 +819,7 @@ exp3 ()
val1 += val2;
else if (op == MINUS)
val1 -= val2;
lasttok = NUM;
}
return (val1);
}
@ -794,6 +828,9 @@ static intmax_t
exp2 ()
{
register intmax_t val1, val2;
#if defined (HAVE_IMAXDIV)
imaxdiv_t idiv;
#endif
val1 = exppower ();
@ -802,29 +839,69 @@ exp2 ()
(curtok == MOD))
{
int op = curtok;
char *stp, *sltp;
stp = tp;
readtok ();
val2 = exppower ();
/* Handle division by 0 and twos-complement arithmetic overflow */
if (((op == DIV) || (op == MOD)) && (val2 == 0))
{
if (noeval == 0)
evalerror (_("division by 0"));
{
sltp = lasttp;
lasttp = stp;
while (lasttp && *lasttp && whitespace (*lasttp))
lasttp++;
evalerror (_("division by 0"));
lasttp = sltp;
}
else
val2 = 1;
}
else if (op == MOD && val1 == INTMAX_MIN && val2 == -1)
{
val1 = 0;
continue;
}
else if (op == DIV && val1 == INTMAX_MIN && val2 == -1)
val2 = 1;
if (op == MUL)
val1 *= val2;
else if (op == DIV)
val1 /= val2;
else if (op == MOD)
val1 %= val2;
else if (op == DIV || op == MOD)
#if defined (HAVE_IMAXDIV)
{
idiv = imaxdiv (val1, val2);
val1 = (op == DIV) ? idiv.quot : idiv.rem;
}
#else
val1 = (op == DIV) ? val1 / val2 : val1 % val2;
#endif
lasttok = NUM;
}
return (val1);
}
static intmax_t
ipow (base, exp)
intmax_t base, exp;
{
intmax_t result;
result = 1;
while (exp)
{
if (exp & 1)
result *= base;
exp >>= 1;
base *= base;
}
return result;
}
static intmax_t
exppower ()
{
@ -835,13 +912,12 @@ exppower ()
{
readtok ();
val2 = exppower (); /* exponentiation is right-associative */
lasttok = NUM;
if (val2 == 0)
return (1);
if (val2 < 0)
evalerror (_("exponent less than 0"));
for (c = 1; val2--; c *= val1)
;
val1 = c;
val1 = ipow (val1, val2);
}
return (val1);
}
@ -855,21 +931,25 @@ exp1 ()
{
readtok ();
val = !exp1 ();
lasttok = NUM;
}
else if (curtok == BNOT)
{
readtok ();
val = ~exp1 ();
lasttok = NUM;
}
else if (curtok == MINUS)
{
readtok ();
val = - exp1 ();
lasttok = NUM;
}
else if (curtok == PLUS)
{
readtok ();
val = exp1 ();
lasttok = NUM;
}
else
val = exp0 ();
@ -899,9 +979,11 @@ exp0 ()
vincdec = itos (v2);
if (noeval == 0)
{
#if defined (ARRAY_VARS)
if (curlval.ind != -1)
expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec);
else
#endif
expr_bind_variable (tokstr, vincdec);
}
free (vincdec);
@ -912,6 +994,7 @@ exp0 ()
}
else if (curtok == LPAR)
{
/* XXX - save curlval here? Or entire expression context? */
readtok ();
val = EXP_HIGHEST ();
@ -945,9 +1028,11 @@ exp0 ()
vincdec = itos (v2);
if (noeval == 0)
{
#if defined (ARRAY_VARS)
if (curlval.ind != -1)
expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec);
else
#endif
expr_bind_variable (tokstr, vincdec);
}
free (vincdec);
@ -955,11 +1040,11 @@ exp0 ()
}
else
{
/* XXX - watch out for pointer aliasing issues here */
if (stok == STR) /* free new tokstr before old one is restored */
FREE (tokstr);
RESTORETOK (&ec);
}
}
readtok ();
@ -1048,8 +1133,8 @@ expr_streval (tok, e, lvalue)
jump_to_top_level (FORCE_EOF);
}
ind = -1;
#if defined (ARRAY_VARS)
ind = -1;
/* Second argument of 0 to get_array_value means that we don't allow
references like array[@]. In this case, get_array_value is just
like get_variable_value in that it does not return newly-allocated
@ -1066,7 +1151,11 @@ expr_streval (tok, e, lvalue)
lvalue->tokstr = tok; /* XXX */
lvalue->tokval = tval;
lvalue->tokvar = v; /* XXX */
#if defined (ARRAY_VARS)
lvalue->ind = ind;
#else
lvalue->ind = -1;
#endif
}
return (tval);