freebsd-dev/bin/sh/arith_yylex.c
Jilles Tjoelker aac5464b61 sh: Restore $((x)) error checking after fix for $((-9223372036854775808))
SVN r342880 was designed to fix $((-9223372036854775808)) and things like
$((0x8000000000000000)) but also broke error detection for values of
variables without dollar sign ($((x))).

For compatibility, overflow in plain literals continues to be ignored and
the value is clamped to the boundary (except 9223372036854775808 which is
changed to -9223372036854775808).

Reviewed by:	se (although he would like error checking to be removed)
MFC after:	2 weeks
X-MFC-with:	r342880
Differential Revision:	https://reviews.freebsd.org/D18926
2019-02-10 22:23:05 +00:00

277 lines
5.5 KiB
C

/*-
* Copyright (c) 2002
* Herbert Xu.
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "shell.h"
#include "arith_yacc.h"
#include "expand.h"
#include "error.h"
#include "memalloc.h"
#include "parser.h"
#include "syntax.h"
#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
#error Arithmetic tokens are out of order.
#endif
arith_t
strtoarith_t(const char *restrict nptr, char **restrict endptr)
{
arith_t val;
while (isspace((unsigned char)*nptr))
nptr++;
switch (*nptr) {
case '-':
return strtoimax(nptr, endptr, 0);
case '0':
return (arith_t)strtoumax(nptr, endptr, 0);
default:
val = (arith_t)strtoumax(nptr, endptr, 0);
if (val >= 0)
return val;
else if (val == ARITH_MIN) {
errno = ERANGE;
return ARITH_MIN;
} else {
errno = ERANGE;
return ARITH_MAX;
}
}
}
int
yylex(void)
{
int value;
const char *buf = arith_buf;
char *end;
const char *p;
for (;;) {
value = *buf;
switch (value) {
case ' ':
case '\t':
case '\n':
buf++;
continue;
default:
return ARITH_BAD;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
yylval.val = strtoarith_t(buf, &end);
arith_buf = end;
return ARITH_NUM;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case '_':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
p = buf;
while (buf++, is_in_name(*buf))
;
yylval.name = stalloc(buf - p + 1);
memcpy(yylval.name, p, buf - p);
yylval.name[buf - p] = '\0';
value = ARITH_VAR;
goto out;
case '=':
value += ARITH_ASS - '=';
checkeq:
buf++;
checkeqcur:
if (*buf != '=')
goto out;
value += 11;
break;
case '>':
switch (*++buf) {
case '=':
value += ARITH_GE - '>';
break;
case '>':
value += ARITH_RSHIFT - '>';
goto checkeq;
default:
value += ARITH_GT - '>';
goto out;
}
break;
case '<':
switch (*++buf) {
case '=':
value += ARITH_LE - '<';
break;
case '<':
value += ARITH_LSHIFT - '<';
goto checkeq;
default:
value += ARITH_LT - '<';
goto out;
}
break;
case '|':
if (*++buf != '|') {
value += ARITH_BOR - '|';
goto checkeqcur;
}
value += ARITH_OR - '|';
break;
case '&':
if (*++buf != '&') {
value += ARITH_BAND - '&';
goto checkeqcur;
}
value += ARITH_AND - '&';
break;
case '!':
if (*++buf != '=') {
value += ARITH_NOT - '!';
goto out;
}
value += ARITH_NE - '!';
break;
case 0:
goto out;
case '(':
value += ARITH_LPAREN - '(';
break;
case ')':
value += ARITH_RPAREN - ')';
break;
case '*':
value += ARITH_MUL - '*';
goto checkeq;
case '/':
value += ARITH_DIV - '/';
goto checkeq;
case '%':
value += ARITH_REM - '%';
goto checkeq;
case '+':
if (buf[1] == '+')
return ARITH_BAD;
value += ARITH_ADD - '+';
goto checkeq;
case '-':
if (buf[1] == '-')
return ARITH_BAD;
value += ARITH_SUB - '-';
goto checkeq;
case '~':
value += ARITH_BNOT - '~';
break;
case '^':
value += ARITH_BXOR - '^';
goto checkeq;
case '?':
value += ARITH_QMARK - '?';
break;
case ':':
value += ARITH_COLON - ':';
break;
}
break;
}
buf++;
out:
arith_buf = buf;
return value;
}