16262b84eSJilles Tjoelker /*-
26262b84eSJilles Tjoelker * Copyright (c) 1993
36262b84eSJilles Tjoelker * The Regents of the University of California. All rights reserved.
46262b84eSJilles Tjoelker * Copyright (c) 2007
56262b84eSJilles Tjoelker * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
66262b84eSJilles Tjoelker *
76262b84eSJilles Tjoelker * This code is derived from software contributed to Berkeley by
86262b84eSJilles Tjoelker * Kenneth Almquist.
96262b84eSJilles Tjoelker *
106262b84eSJilles Tjoelker * Redistribution and use in source and binary forms, with or without
116262b84eSJilles Tjoelker * modification, are permitted provided that the following conditions
126262b84eSJilles Tjoelker * are met:
136262b84eSJilles Tjoelker * 1. Redistributions of source code must retain the above copyright
146262b84eSJilles Tjoelker * notice, this list of conditions and the following disclaimer.
156262b84eSJilles Tjoelker * 2. Redistributions in binary form must reproduce the above copyright
166262b84eSJilles Tjoelker * notice, this list of conditions and the following disclaimer in the
176262b84eSJilles Tjoelker * documentation and/or other materials provided with the distribution.
186262b84eSJilles Tjoelker * 3. Neither the name of the University nor the names of its contributors
196262b84eSJilles Tjoelker * may be used to endorse or promote products derived from this software
206262b84eSJilles Tjoelker * without specific prior written permission.
216262b84eSJilles Tjoelker *
226262b84eSJilles Tjoelker * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
236262b84eSJilles Tjoelker * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
246262b84eSJilles Tjoelker * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
256262b84eSJilles Tjoelker * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
266262b84eSJilles Tjoelker * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
276262b84eSJilles Tjoelker * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
286262b84eSJilles Tjoelker * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
296262b84eSJilles Tjoelker * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
306262b84eSJilles Tjoelker * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
316262b84eSJilles Tjoelker * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
326262b84eSJilles Tjoelker * SUCH DAMAGE.
336262b84eSJilles Tjoelker */
346262b84eSJilles Tjoelker
356262b84eSJilles Tjoelker #include <sys/cdefs.h>
364004e05eSJilles Tjoelker #include <limits.h>
376262b84eSJilles Tjoelker #include <errno.h>
386262b84eSJilles Tjoelker #include <inttypes.h>
396262b84eSJilles Tjoelker #include <stdlib.h>
406262b84eSJilles Tjoelker #include <stdio.h>
416262b84eSJilles Tjoelker #include "arith.h"
426262b84eSJilles Tjoelker #include "arith_yacc.h"
436262b84eSJilles Tjoelker #include "expand.h"
446262b84eSJilles Tjoelker #include "shell.h"
456262b84eSJilles Tjoelker #include "error.h"
466262b84eSJilles Tjoelker #include "memalloc.h"
476262b84eSJilles Tjoelker #include "output.h"
486262b84eSJilles Tjoelker #include "options.h"
496262b84eSJilles Tjoelker #include "var.h"
506262b84eSJilles Tjoelker
516262b84eSJilles Tjoelker #if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
526262b84eSJilles Tjoelker #error Arithmetic tokens are out of order.
536262b84eSJilles Tjoelker #endif
546262b84eSJilles Tjoelker
556262b84eSJilles Tjoelker static const char *arith_startbuf;
566262b84eSJilles Tjoelker
576262b84eSJilles Tjoelker const char *arith_buf;
586262b84eSJilles Tjoelker union yystype yylval;
596262b84eSJilles Tjoelker
606262b84eSJilles Tjoelker static int last_token;
616262b84eSJilles Tjoelker
626262b84eSJilles Tjoelker #define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
636262b84eSJilles Tjoelker
646262b84eSJilles Tjoelker static const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
656262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_MUL, 0),
666262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_DIV, 0),
676262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_REM, 0),
686262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_ADD, 1),
696262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_SUB, 1),
706262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_LSHIFT, 2),
716262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_RSHIFT, 2),
726262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_LT, 3),
736262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_LE, 3),
746262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_GT, 3),
756262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_GE, 3),
766262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_EQ, 4),
776262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_NE, 4),
786262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_BAND, 5),
796262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_BXOR, 6),
806262b84eSJilles Tjoelker ARITH_PRECEDENCE(ARITH_BOR, 7),
816262b84eSJilles Tjoelker };
826262b84eSJilles Tjoelker
836262b84eSJilles Tjoelker #define ARITH_MAX_PREC 8
846262b84eSJilles Tjoelker
852fae4c3dSPhilippe Charnier int letcmd(int, char **);
862fae4c3dSPhilippe Charnier
yyerror(const char * s)876262b84eSJilles Tjoelker static __dead2 void yyerror(const char *s)
886262b84eSJilles Tjoelker {
896262b84eSJilles Tjoelker error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
906262b84eSJilles Tjoelker /* NOTREACHED */
916262b84eSJilles Tjoelker }
926262b84eSJilles Tjoelker
arith_lookupvarint(char * varname)936262b84eSJilles Tjoelker static arith_t arith_lookupvarint(char *varname)
946262b84eSJilles Tjoelker {
956262b84eSJilles Tjoelker const char *str;
966262b84eSJilles Tjoelker char *p;
976262b84eSJilles Tjoelker arith_t result;
986262b84eSJilles Tjoelker
996262b84eSJilles Tjoelker str = lookupvar(varname);
1003937fc9cSJilles Tjoelker if (uflag && str == NULL)
1013937fc9cSJilles Tjoelker yyerror("variable not set");
1026262b84eSJilles Tjoelker if (str == NULL || *str == '\0')
1036262b84eSJilles Tjoelker str = "0";
1046262b84eSJilles Tjoelker errno = 0;
105*aac5464bSJilles Tjoelker result = strtoarith_t(str, &p);
1066262b84eSJilles Tjoelker if (errno != 0 || *p != '\0')
1076262b84eSJilles Tjoelker yyerror("variable conversion error");
1086262b84eSJilles Tjoelker return result;
1096262b84eSJilles Tjoelker }
1106262b84eSJilles Tjoelker
arith_prec(int op)1116262b84eSJilles Tjoelker static inline int arith_prec(int op)
1126262b84eSJilles Tjoelker {
1136262b84eSJilles Tjoelker return prec[op - ARITH_BINOP_MIN];
1146262b84eSJilles Tjoelker }
1156262b84eSJilles Tjoelker
higher_prec(int op1,int op2)1166262b84eSJilles Tjoelker static inline int higher_prec(int op1, int op2)
1176262b84eSJilles Tjoelker {
1186262b84eSJilles Tjoelker return arith_prec(op1) < arith_prec(op2);
1196262b84eSJilles Tjoelker }
1206262b84eSJilles Tjoelker
do_binop(int op,arith_t a,arith_t b)1216262b84eSJilles Tjoelker static arith_t do_binop(int op, arith_t a, arith_t b)
1226262b84eSJilles Tjoelker {
1236262b84eSJilles Tjoelker
1246262b84eSJilles Tjoelker switch (op) {
1256262b84eSJilles Tjoelker default:
1266262b84eSJilles Tjoelker case ARITH_REM:
1276262b84eSJilles Tjoelker case ARITH_DIV:
1286262b84eSJilles Tjoelker if (!b)
1296262b84eSJilles Tjoelker yyerror("division by zero");
130e9749129SJilles Tjoelker if (a == ARITH_MIN && b == -1)
131e9749129SJilles Tjoelker yyerror("divide error");
1326262b84eSJilles Tjoelker return op == ARITH_REM ? a % b : a / b;
1336262b84eSJilles Tjoelker case ARITH_MUL:
134876f9b78SJilles Tjoelker return (uintmax_t)a * (uintmax_t)b;
1356262b84eSJilles Tjoelker case ARITH_ADD:
136876f9b78SJilles Tjoelker return (uintmax_t)a + (uintmax_t)b;
1376262b84eSJilles Tjoelker case ARITH_SUB:
138876f9b78SJilles Tjoelker return (uintmax_t)a - (uintmax_t)b;
1396262b84eSJilles Tjoelker case ARITH_LSHIFT:
140dd6d480aSJilles Tjoelker return (uintmax_t)a << (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
1416262b84eSJilles Tjoelker case ARITH_RSHIFT:
142dd6d480aSJilles Tjoelker return a >> (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
1436262b84eSJilles Tjoelker case ARITH_LT:
1446262b84eSJilles Tjoelker return a < b;
1456262b84eSJilles Tjoelker case ARITH_LE:
1466262b84eSJilles Tjoelker return a <= b;
1476262b84eSJilles Tjoelker case ARITH_GT:
1486262b84eSJilles Tjoelker return a > b;
1496262b84eSJilles Tjoelker case ARITH_GE:
1506262b84eSJilles Tjoelker return a >= b;
1516262b84eSJilles Tjoelker case ARITH_EQ:
1526262b84eSJilles Tjoelker return a == b;
1536262b84eSJilles Tjoelker case ARITH_NE:
1546262b84eSJilles Tjoelker return a != b;
1556262b84eSJilles Tjoelker case ARITH_BAND:
1566262b84eSJilles Tjoelker return a & b;
1576262b84eSJilles Tjoelker case ARITH_BXOR:
1586262b84eSJilles Tjoelker return a ^ b;
1596262b84eSJilles Tjoelker case ARITH_BOR:
1606262b84eSJilles Tjoelker return a | b;
1616262b84eSJilles Tjoelker }
1626262b84eSJilles Tjoelker }
1636262b84eSJilles Tjoelker
1646262b84eSJilles Tjoelker static arith_t assignment(int var, int noeval);
1656262b84eSJilles Tjoelker
primary(int token,union yystype * val,int op,int noeval)1666262b84eSJilles Tjoelker static arith_t primary(int token, union yystype *val, int op, int noeval)
1676262b84eSJilles Tjoelker {
1686262b84eSJilles Tjoelker arith_t result;
1696262b84eSJilles Tjoelker
1706262b84eSJilles Tjoelker again:
1716262b84eSJilles Tjoelker switch (token) {
1726262b84eSJilles Tjoelker case ARITH_LPAREN:
1736262b84eSJilles Tjoelker result = assignment(op, noeval);
1746262b84eSJilles Tjoelker if (last_token != ARITH_RPAREN)
1756262b84eSJilles Tjoelker yyerror("expecting ')'");
1766262b84eSJilles Tjoelker last_token = yylex();
1776262b84eSJilles Tjoelker return result;
1786262b84eSJilles Tjoelker case ARITH_NUM:
1796262b84eSJilles Tjoelker last_token = op;
1806262b84eSJilles Tjoelker return val->val;
1816262b84eSJilles Tjoelker case ARITH_VAR:
1826262b84eSJilles Tjoelker last_token = op;
1836262b84eSJilles Tjoelker return noeval ? val->val : arith_lookupvarint(val->name);
1846262b84eSJilles Tjoelker case ARITH_ADD:
1856262b84eSJilles Tjoelker token = op;
1866262b84eSJilles Tjoelker *val = yylval;
1876262b84eSJilles Tjoelker op = yylex();
1886262b84eSJilles Tjoelker goto again;
1896262b84eSJilles Tjoelker case ARITH_SUB:
1906262b84eSJilles Tjoelker *val = yylval;
1916262b84eSJilles Tjoelker return -primary(op, val, yylex(), noeval);
1926262b84eSJilles Tjoelker case ARITH_NOT:
1936262b84eSJilles Tjoelker *val = yylval;
1946262b84eSJilles Tjoelker return !primary(op, val, yylex(), noeval);
1956262b84eSJilles Tjoelker case ARITH_BNOT:
1966262b84eSJilles Tjoelker *val = yylval;
1976262b84eSJilles Tjoelker return ~primary(op, val, yylex(), noeval);
1986262b84eSJilles Tjoelker default:
1996262b84eSJilles Tjoelker yyerror("expecting primary");
2006262b84eSJilles Tjoelker }
2016262b84eSJilles Tjoelker }
2026262b84eSJilles Tjoelker
binop2(arith_t a,int op,int precedence,int noeval)203976018d2SJilles Tjoelker static arith_t binop2(arith_t a, int op, int precedence, int noeval)
2046262b84eSJilles Tjoelker {
2056262b84eSJilles Tjoelker for (;;) {
2066262b84eSJilles Tjoelker union yystype val;
2076262b84eSJilles Tjoelker arith_t b;
2086262b84eSJilles Tjoelker int op2;
2096262b84eSJilles Tjoelker int token;
2106262b84eSJilles Tjoelker
2116262b84eSJilles Tjoelker token = yylex();
2126262b84eSJilles Tjoelker val = yylval;
2136262b84eSJilles Tjoelker
2146262b84eSJilles Tjoelker b = primary(token, &val, yylex(), noeval);
2156262b84eSJilles Tjoelker
2166262b84eSJilles Tjoelker op2 = last_token;
2176262b84eSJilles Tjoelker if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX &&
2186262b84eSJilles Tjoelker higher_prec(op2, op)) {
2196262b84eSJilles Tjoelker b = binop2(b, op2, arith_prec(op), noeval);
2206262b84eSJilles Tjoelker op2 = last_token;
2216262b84eSJilles Tjoelker }
2226262b84eSJilles Tjoelker
2236262b84eSJilles Tjoelker a = noeval ? b : do_binop(op, a, b);
2246262b84eSJilles Tjoelker
2256262b84eSJilles Tjoelker if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX ||
226976018d2SJilles Tjoelker arith_prec(op2) >= precedence)
2276262b84eSJilles Tjoelker return a;
2286262b84eSJilles Tjoelker
2296262b84eSJilles Tjoelker op = op2;
2306262b84eSJilles Tjoelker }
2316262b84eSJilles Tjoelker }
2326262b84eSJilles Tjoelker
binop(int token,union yystype * val,int op,int noeval)2336262b84eSJilles Tjoelker static arith_t binop(int token, union yystype *val, int op, int noeval)
2346262b84eSJilles Tjoelker {
2356262b84eSJilles Tjoelker arith_t a = primary(token, val, op, noeval);
2366262b84eSJilles Tjoelker
2376262b84eSJilles Tjoelker op = last_token;
2386262b84eSJilles Tjoelker if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX)
2396262b84eSJilles Tjoelker return a;
2406262b84eSJilles Tjoelker
2416262b84eSJilles Tjoelker return binop2(a, op, ARITH_MAX_PREC, noeval);
2426262b84eSJilles Tjoelker }
2436262b84eSJilles Tjoelker
and(int token,union yystype * val,int op,int noeval)2446262b84eSJilles Tjoelker static arith_t and(int token, union yystype *val, int op, int noeval)
2456262b84eSJilles Tjoelker {
2466262b84eSJilles Tjoelker arith_t a = binop(token, val, op, noeval);
2476262b84eSJilles Tjoelker arith_t b;
2486262b84eSJilles Tjoelker
2496262b84eSJilles Tjoelker op = last_token;
2506262b84eSJilles Tjoelker if (op != ARITH_AND)
2516262b84eSJilles Tjoelker return a;
2526262b84eSJilles Tjoelker
2536262b84eSJilles Tjoelker token = yylex();
2546262b84eSJilles Tjoelker *val = yylval;
2556262b84eSJilles Tjoelker
2566262b84eSJilles Tjoelker b = and(token, val, yylex(), noeval | !a);
2576262b84eSJilles Tjoelker
2586262b84eSJilles Tjoelker return a && b;
2596262b84eSJilles Tjoelker }
2606262b84eSJilles Tjoelker
or(int token,union yystype * val,int op,int noeval)2616262b84eSJilles Tjoelker static arith_t or(int token, union yystype *val, int op, int noeval)
2626262b84eSJilles Tjoelker {
2636262b84eSJilles Tjoelker arith_t a = and(token, val, op, noeval);
2646262b84eSJilles Tjoelker arith_t b;
2656262b84eSJilles Tjoelker
2666262b84eSJilles Tjoelker op = last_token;
2676262b84eSJilles Tjoelker if (op != ARITH_OR)
2686262b84eSJilles Tjoelker return a;
2696262b84eSJilles Tjoelker
2706262b84eSJilles Tjoelker token = yylex();
2716262b84eSJilles Tjoelker *val = yylval;
2726262b84eSJilles Tjoelker
2736262b84eSJilles Tjoelker b = or(token, val, yylex(), noeval | !!a);
2746262b84eSJilles Tjoelker
2756262b84eSJilles Tjoelker return a || b;
2766262b84eSJilles Tjoelker }
2776262b84eSJilles Tjoelker
cond(int token,union yystype * val,int op,int noeval)2786262b84eSJilles Tjoelker static arith_t cond(int token, union yystype *val, int op, int noeval)
2796262b84eSJilles Tjoelker {
2806262b84eSJilles Tjoelker arith_t a = or(token, val, op, noeval);
2816262b84eSJilles Tjoelker arith_t b;
2826262b84eSJilles Tjoelker arith_t c;
2836262b84eSJilles Tjoelker
2846262b84eSJilles Tjoelker if (last_token != ARITH_QMARK)
2856262b84eSJilles Tjoelker return a;
2866262b84eSJilles Tjoelker
2876262b84eSJilles Tjoelker b = assignment(yylex(), noeval | !a);
2886262b84eSJilles Tjoelker
2896262b84eSJilles Tjoelker if (last_token != ARITH_COLON)
2906262b84eSJilles Tjoelker yyerror("expecting ':'");
2916262b84eSJilles Tjoelker
2926262b84eSJilles Tjoelker token = yylex();
2936262b84eSJilles Tjoelker *val = yylval;
2946262b84eSJilles Tjoelker
2956262b84eSJilles Tjoelker c = cond(token, val, yylex(), noeval | !!a);
2966262b84eSJilles Tjoelker
2976262b84eSJilles Tjoelker return a ? b : c;
2986262b84eSJilles Tjoelker }
2996262b84eSJilles Tjoelker
assignment(int var,int noeval)3006262b84eSJilles Tjoelker static arith_t assignment(int var, int noeval)
3016262b84eSJilles Tjoelker {
3026262b84eSJilles Tjoelker union yystype val = yylval;
3036262b84eSJilles Tjoelker int op = yylex();
3046262b84eSJilles Tjoelker arith_t result;
3056262b84eSJilles Tjoelker char sresult[DIGITS(result) + 1];
3066262b84eSJilles Tjoelker
3076262b84eSJilles Tjoelker if (var != ARITH_VAR)
3086262b84eSJilles Tjoelker return cond(var, &val, op, noeval);
3096262b84eSJilles Tjoelker
3106262b84eSJilles Tjoelker if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX))
3116262b84eSJilles Tjoelker return cond(var, &val, op, noeval);
3126262b84eSJilles Tjoelker
3136262b84eSJilles Tjoelker result = assignment(yylex(), noeval);
3146262b84eSJilles Tjoelker if (noeval)
3156262b84eSJilles Tjoelker return result;
3166262b84eSJilles Tjoelker
3176262b84eSJilles Tjoelker if (op != ARITH_ASS)
3186262b84eSJilles Tjoelker result = do_binop(op - 11, arith_lookupvarint(val.name), result);
3196262b84eSJilles Tjoelker snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result);
3206262b84eSJilles Tjoelker setvar(val.name, sresult, 0);
3216262b84eSJilles Tjoelker return result;
3226262b84eSJilles Tjoelker }
3236262b84eSJilles Tjoelker
arith(const char * s)3246262b84eSJilles Tjoelker arith_t arith(const char *s)
3256262b84eSJilles Tjoelker {
3266262b84eSJilles Tjoelker struct stackmark smark;
3276262b84eSJilles Tjoelker arith_t result;
3286262b84eSJilles Tjoelker
3296262b84eSJilles Tjoelker setstackmark(&smark);
3306262b84eSJilles Tjoelker
3316262b84eSJilles Tjoelker arith_buf = arith_startbuf = s;
3326262b84eSJilles Tjoelker
3336262b84eSJilles Tjoelker result = assignment(yylex(), 0);
3346262b84eSJilles Tjoelker
3356262b84eSJilles Tjoelker if (last_token)
3366262b84eSJilles Tjoelker yyerror("expecting EOF");
3376262b84eSJilles Tjoelker
3386262b84eSJilles Tjoelker popstackmark(&smark);
3396262b84eSJilles Tjoelker
3406262b84eSJilles Tjoelker return result;
3416262b84eSJilles Tjoelker }
3426262b84eSJilles Tjoelker
3436262b84eSJilles Tjoelker /*
3446262b84eSJilles Tjoelker * The exp(1) builtin.
3456262b84eSJilles Tjoelker */
3466262b84eSJilles Tjoelker int
letcmd(int argc,char ** argv)3478d5a1430SJilles Tjoelker letcmd(int argc, char **argv)
3486262b84eSJilles Tjoelker {
3496262b84eSJilles Tjoelker const char *p;
3506262b84eSJilles Tjoelker char *concat;
3516262b84eSJilles Tjoelker char **ap;
3526262b84eSJilles Tjoelker arith_t i;
3536262b84eSJilles Tjoelker
3546262b84eSJilles Tjoelker if (argc > 1) {
3556262b84eSJilles Tjoelker p = argv[1];
3566262b84eSJilles Tjoelker if (argc > 2) {
3576262b84eSJilles Tjoelker /*
3586262b84eSJilles Tjoelker * Concatenate arguments.
3596262b84eSJilles Tjoelker */
3606262b84eSJilles Tjoelker STARTSTACKSTR(concat);
3616262b84eSJilles Tjoelker ap = argv + 2;
3626262b84eSJilles Tjoelker for (;;) {
3636262b84eSJilles Tjoelker while (*p)
3646262b84eSJilles Tjoelker STPUTC(*p++, concat);
3656262b84eSJilles Tjoelker if ((p = *ap++) == NULL)
3666262b84eSJilles Tjoelker break;
3676262b84eSJilles Tjoelker STPUTC(' ', concat);
3686262b84eSJilles Tjoelker }
3696262b84eSJilles Tjoelker STPUTC('\0', concat);
3706262b84eSJilles Tjoelker p = grabstackstr(concat);
3716262b84eSJilles Tjoelker }
3726262b84eSJilles Tjoelker } else
3736262b84eSJilles Tjoelker p = "";
3746262b84eSJilles Tjoelker
3756262b84eSJilles Tjoelker i = arith(p);
3766262b84eSJilles Tjoelker
3776262b84eSJilles Tjoelker out1fmt(ARITH_FORMAT_STR "\n", i);
3786262b84eSJilles Tjoelker return !i;
3796262b84eSJilles Tjoelker }
380