aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2003-08-06 11:20:52 +0000
committerEric Andersen <andersen@codepoet.org>2003-08-06 11:20:52 +0000
commit9089844382a87290143ec414cfea703bcc31e9d8 (patch)
treedd507d9dfc45625d953748ffc7c361bd1f025ca6
parentdc19af4179161bdc80ea4d382a116e916a43ac9d (diff)
downloadbusybox-w32-9089844382a87290143ec414cfea703bcc31e9d8.tar.gz
busybox-w32-9089844382a87290143ec414cfea703bcc31e9d8.tar.bz2
busybox-w32-9089844382a87290143ec414cfea703bcc31e9d8.zip
Latest dash update from vodz
-rw-r--r--libbb/Makefile.in2
-rw-r--r--libbb/arith.c375
-rw-r--r--shell/ash.c1061
3 files changed, 910 insertions, 528 deletions
diff --git a/libbb/Makefile.in b/libbb/Makefile.in
index b60adc959..0d7103ef0 100644
--- a/libbb/Makefile.in
+++ b/libbb/Makefile.in
@@ -24,7 +24,7 @@ LIBBB_DIR:=$(TOPDIR)libbb/
24endif 24endif
25 25
26LIBBB_SRC:= \ 26LIBBB_SRC:= \
27 arith.c bb_asprintf.c ask_confirmation.c change_identity.c chomp.c \ 27 bb_asprintf.c ask_confirmation.c change_identity.c chomp.c \
28 compare_string_array.c concat_path_file.c copy_file.c \ 28 compare_string_array.c concat_path_file.c copy_file.c \
29 copyfd.c correct_password.c create_icmp_socket.c \ 29 copyfd.c correct_password.c create_icmp_socket.c \
30 create_icmp6_socket.c device_open.c dump.c error_msg.c \ 30 create_icmp6_socket.c device_open.c dump.c error_msg.c \
diff --git a/libbb/arith.c b/libbb/arith.c
deleted file mode 100644
index 3e107126a..000000000
--- a/libbb/arith.c
+++ /dev/null
@@ -1,375 +0,0 @@
1/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
2
3 Permission is hereby granted, free of charge, to any person obtaining
4 a copy of this software and associated documentation files (the
5 "Software"), to deal in the Software without restriction, including
6 without limitation the rights to use, copy, modify, merge, publish,
7 distribute, sublicense, and/or sell copies of the Software, and to
8 permit persons to whom the Software is furnished to do so, subject to
9 the following conditions:
10
11 The above copyright notice and this permission notice shall be
12 included in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21*/
22
23/* This is my infix parser/evaluator. It is optimized for size, intended
24 * as a replacement for yacc-based parsers. However, it may well be faster
25 * than a comparable parser writen in yacc. The supported operators are
26 * listed in #defines below. Parens, order of operations, and error handling
27 * are supported. This code is threadsafe. The exact expression format should
28 * be that which POSIX specifies for shells. */
29
30/* The code uses a simple two-stack algorithm. See
31 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
32 * for a detailed explaination of the infix-to-postfix algorithm on which
33 * this is based (this code differs in that it applies operators immediately
34 * to the stack instead of adding them to a queue to end up with an
35 * expression). */
36
37/* To use the routine, call it with an expression string and error return
38 * pointer */
39
40/*
41 * Aug 24, 2001 Manuel Novoa III
42 *
43 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
44 *
45 * 1) In arith_apply():
46 * a) Cached values of *numptr and &(numptr[-1]).
47 * b) Removed redundant test for zero denominator.
48 *
49 * 2) In arith():
50 * a) Eliminated redundant code for processing operator tokens by moving
51 * to a table-based implementation. Also folded handling of parens
52 * into the table.
53 * b) Combined all 3 loops which called arith_apply to reduce generated
54 * code size at the cost of speed.
55 *
56 * 3) The following expressions were treated as valid by the original code:
57 * 1() , 0! , 1 ( *3 ) .
58 * These bugs have been fixed by internally enclosing the expression in
59 * parens and then checking that all binary ops and right parens are
60 * preceded by a valid expression (NUM_TOKEN).
61 *
62 * Note: It may be desireable to replace Aaron's test for whitespace with
63 * ctype's isspace() if it is used by another busybox applet or if additional
64 * whitespace chars should be considered. Look below the "#include"s for a
65 * precompiler test.
66 */
67
68/*
69 * Aug 26, 2001 Manuel Novoa III
70 *
71 * Return 0 for null expressions. Pointed out by vodz.
72 *
73 * Merge in Aaron's comments previously posted to the busybox list,
74 * modified slightly to take account of my changes to the code.
75 *
76 * TODO: May want to allow access to variables in the arith code.
77 * This would:
78 * 1) allow us to evaluate $A as 0 if A isn't set (although this
79 * would require changes to ash.c too).
80 * 2) allow us to write expressions as $(( A + 2 )).
81 * This could be done using a callback function passed to the
82 * arith() function of by requiring such a function with fixed
83 * name as an extern.
84 */
85
86#include <stdlib.h>
87#include <string.h>
88#include <ctype.h>
89#include "libbb.h"
90
91/*
92 * Use "#if 1" below for Aaron's original test for whitespace.
93 * Use "#if 0" for ctype's isspace().
94 * */
95#if 1
96#undef isspace
97#define isspace(arithval) \
98 (arithval == ' ' || arithval == '\n' || arithval == '\t')
99#endif
100
101typedef char operator;
102
103/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
104 * precedence, and high 3 are an ID unique accross operators of that
105 * precedence. The ID portion is so that multiple operators can have the
106 * same precedence, ensuring that the leftmost one is evaluated first.
107 * Consider * and /. */
108
109#define tok_decl(prec,id) (((id)<<5)|(prec))
110#define PREC(op) ((op)&0x1F)
111
112#define TOK_LPAREN tok_decl(0,0)
113
114#define TOK_OR tok_decl(1,0)
115
116#define TOK_AND tok_decl(2,0)
117
118#define TOK_BOR tok_decl(3,0)
119
120#define TOK_BXOR tok_decl(4,0)
121
122#define TOK_BAND tok_decl(5,0)
123
124#define TOK_EQ tok_decl(6,0)
125#define TOK_NE tok_decl(6,1)
126
127#define TOK_LT tok_decl(7,0)
128#define TOK_GT tok_decl(7,1)
129#define TOK_GE tok_decl(7,2)
130#define TOK_LE tok_decl(7,3)
131
132#define TOK_LSHIFT tok_decl(8,0)
133#define TOK_RSHIFT tok_decl(8,1)
134
135#define TOK_ADD tok_decl(9,0)
136#define TOK_SUB tok_decl(9,1)
137
138#define TOK_MUL tok_decl(10,0)
139#define TOK_DIV tok_decl(10,1)
140#define TOK_REM tok_decl(10,2)
141
142/* For now all unary operators have the same precedence, and that's used to
143 * identify them as unary operators */
144#define UNARYPREC 14
145#define TOK_BNOT tok_decl(UNARYPREC,0)
146#define TOK_NOT tok_decl(UNARYPREC,1)
147#define TOK_UMINUS tok_decl(UNARYPREC,2)
148#define TOK_UPLUS tok_decl(UNARYPREC,3)
149
150#define TOK_NUM tok_decl(15,0)
151#define TOK_RPAREN tok_decl(15,1)
152#define TOK_ERROR tok_decl(15,2) /* just a place-holder really */
153
154#define ARITH_APPLY(op) arith_apply(op, numstack, &numstackptr)
155#define NUMPTR (*numstackptr)
156
157/* "applying" a token means performing it on the top elements on the integer
158 * stack. For a unary operator it will only change the top element, but a
159 * binary operator will pop two arguments and push a result */
160static short arith_apply(operator op, long *numstack, long **numstackptr)
161{
162 long numptr_val;
163 long *NUMPTR_M1;
164
165 if (NUMPTR == numstack) goto err; /* There is no operator that can work
166 without arguments */
167 NUMPTR_M1 = NUMPTR - 1;
168 if (op == TOK_UMINUS)
169 *NUMPTR_M1 *= -1;
170 else if (op == TOK_NOT)
171 *NUMPTR_M1 = !(*NUMPTR_M1);
172 else if (op == TOK_BNOT)
173 *NUMPTR_M1 = ~(*NUMPTR_M1);
174 else if (op != TOK_UPLUS) {
175 /* Binary operators */
176 if (NUMPTR_M1 == numstack) goto err; /* ... and binary operators need two
177 arguments */
178 numptr_val = *--NUMPTR; /* ... and they pop one */
179 NUMPTR_M1 = NUMPTR - 1;
180 if (op == TOK_BOR)
181 *NUMPTR_M1 |= numptr_val;
182 else if (op == TOK_OR)
183 *NUMPTR_M1 = numptr_val || *NUMPTR_M1;
184 else if (op == TOK_BAND)
185 *NUMPTR_M1 &= numptr_val;
186 else if (op == TOK_AND)
187 *NUMPTR_M1 = *NUMPTR_M1 && numptr_val;
188 else if (op == TOK_EQ)
189 *NUMPTR_M1 = (*NUMPTR_M1 == numptr_val);
190 else if (op == TOK_NE)
191 *NUMPTR_M1 = (*NUMPTR_M1 != numptr_val);
192 else if (op == TOK_GE)
193 *NUMPTR_M1 = (*NUMPTR_M1 >= numptr_val);
194 else if (op == TOK_RSHIFT)
195 *NUMPTR_M1 >>= numptr_val;
196 else if (op == TOK_LSHIFT)
197 *NUMPTR_M1 <<= numptr_val;
198 else if (op == TOK_GT)
199 *NUMPTR_M1 = (*NUMPTR_M1 > numptr_val);
200 else if (op == TOK_LT)
201 *NUMPTR_M1 = (*NUMPTR_M1 < numptr_val);
202 else if (op == TOK_LE)
203 *NUMPTR_M1 = (*NUMPTR_M1 <= numptr_val);
204 else if (op == TOK_MUL)
205 *NUMPTR_M1 *= numptr_val;
206 else if (op == TOK_ADD)
207 *NUMPTR_M1 += numptr_val;
208 else if (op == TOK_SUB)
209 *NUMPTR_M1 -= numptr_val;
210 else if(numptr_val==0) /* zero divisor check */
211 return -2;
212 else if (op == TOK_DIV)
213 *NUMPTR_M1 /= numptr_val;
214 else if (op == TOK_REM)
215 *NUMPTR_M1 %= numptr_val;
216 /* WARNING!!! WARNING!!! WARNING!!! */
217 /* Any new operators should be added BEFORE the zero divisor check! */
218 }
219 return 0;
220err: return(-1);
221}
222
223static const char endexpression[] = ")";
224
225/* + and - (in that order) must be last */
226static const char op_char[] = "!<>=|&*/%~()+-";
227static const char op_token[] = {
228 /* paired with equal */
229 TOK_NE, TOK_LE, TOK_GE,
230 /* paired with self -- note: ! is special-cased below*/
231 TOK_ERROR, TOK_LSHIFT, TOK_RSHIFT, TOK_EQ, TOK_OR, TOK_AND,
232 /* singles */
233 TOK_NOT, TOK_LT, TOK_GT, TOK_ERROR, TOK_BOR, TOK_BAND,
234 TOK_MUL, TOK_DIV, TOK_REM, TOK_BNOT, TOK_LPAREN, TOK_RPAREN,
235 TOK_ADD, TOK_SUB, TOK_UPLUS, TOK_UMINUS
236};
237
238#define NUM_PAIR_EQUAL 3
239#define NUM_PAIR_SAME 6
240
241extern long arith (const char *expr, int *errcode)
242{
243 register char arithval; /* Current character under analysis */
244 operator lasttok, op;
245 unsigned char prec;
246
247 const char *p = endexpression;
248
249 size_t datasizes = strlen(expr) + 2;
250
251 /* Stack of integers */
252 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
253 * in any given correct or incorrect expression is left as an excersize to
254 * the reader. */
255 long *numstack = alloca(((datasizes)/2)*sizeof(long)),
256 *numstackptr = numstack;
257 /* Stack of operator tokens */
258 operator *stack = alloca((datasizes) * sizeof(operator)),
259 *stackptr = stack;
260
261 *numstack = 0;
262 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
263
264 loop:
265 if ((arithval = *expr) == 0) {
266 if (p == endexpression) { /* Null expression. */
267 *errcode = 0;
268 return *numstack;
269 }
270
271 /* This is only reached after all tokens have been extracted from the
272 * input stream. If there are still tokens on the operator stack, they
273 * are to be applied in order. At the end, there should be a final
274 * result on the integer stack */
275
276 if (expr != endexpression + 1) { /* If we haven't done so already, */
277 expr = endexpression; /* append a closing right paren */
278 goto loop; /* and let the loop process it. */
279 }
280 /* At this point, we're done with the expression. */
281 if (numstackptr != numstack+1) {/* ... but if there isn't, it's bad */
282 err:
283 return (*errcode = -1);
284 /* NOTREACHED */
285 }
286 return *numstack;
287 } else {
288 /* Continue processing the expression. */
289 if (isspace(arithval)) {
290 goto prologue; /* Skip whitespace */
291 }
292 if ((unsigned)arithval-'0' <= 9) /* isdigit */ {
293 *numstackptr++ = strtol(expr, (char **) &expr, 10);
294 lasttok = TOK_NUM;
295 goto loop;
296 }
297#if 1
298 if ((p = strchr(op_char, arithval)) == NULL) {
299 goto err;
300 }
301#else
302 for ( p=op_char ; *p != arithval ; p++ ) {
303 if (!*p) {
304 goto err;
305 }
306 }
307#endif
308 p = op_token + (int)(p - op_char);
309 ++expr;
310 if ((p >= op_token + NUM_PAIR_EQUAL) || (*expr != '=')) {
311 p += NUM_PAIR_EQUAL;
312 if ((p >= op_token + NUM_PAIR_SAME + NUM_PAIR_EQUAL)
313 || (*expr != arithval) || (arithval == '!')) {
314 --expr;
315 if (arithval == '=') { /* single = */
316 goto err;
317 }
318 p += NUM_PAIR_SAME;
319 /* Plus and minus are binary (not unary) _only_ if the last
320 * token was as number, or a right paren (which pretends to be
321 * a number, since it evaluates to one). Think about it.
322 * It makes sense. */
323 if ((lasttok != TOK_NUM)
324 && (p >= op_token + NUM_PAIR_SAME + NUM_PAIR_EQUAL
325 + sizeof(op_char) - 2)) {
326 p += 2; /* Unary plus or minus */
327 }
328 }
329 }
330 op = *p;
331
332 /* We don't want a unary operator to cause recursive descent on the
333 * stack, because there can be many in a row and it could cause an
334 * operator to be evaluated before its argument is pushed onto the
335 * integer stack. */
336 /* But for binary operators, "apply" everything on the operator
337 * stack until we find an operator with a lesser priority than the
338 * one we have just extracted. */
339 /* Left paren is given the lowest priority so it will never be
340 * "applied" in this way */
341 prec = PREC(op);
342 if ((prec > 0) && (prec != UNARYPREC)) { /* not left paren or unary */
343 if (lasttok != TOK_NUM) { /* binary op must be preceded by a num */
344 goto err;
345 }
346 while (stackptr != stack) {
347 if (op == TOK_RPAREN) {
348 /* The algorithm employed here is simple: while we don't
349 * hit an open paren nor the bottom of the stack, pop
350 * tokens and apply them */
351 if (stackptr[-1] == TOK_LPAREN) {
352 --stackptr;
353 lasttok = TOK_NUM; /* Any operator directly after a */
354 /* close paren should consider itself binary */
355 goto prologue;
356 }
357 } else if (PREC(stackptr[-1]) < prec) {
358 break;
359 }
360 *errcode = ARITH_APPLY(*--stackptr);
361 if(*errcode) return *errcode;
362 }
363 if (op == TOK_RPAREN) {
364 goto err;
365 }
366 }
367
368 /* Push this operator to the stack and remember it. */
369 *stackptr++ = lasttok = op;
370
371 prologue:
372 ++expr;
373 goto loop;
374 }
375}
diff --git a/shell/ash.c b/shell/ash.c
index 2b99a3254..74c33381a 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -26,13 +26,20 @@
26 * along with this program; if not, write to the Free Software 26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * 28 *
29 * Original BSD copyright notice is retained at the end of this file.
30 */
31
32/*
33 * rewrite arith.y to micro stack based cryptic algorithm by
34 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
29 * 35 *
30 * Modified by Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox 36 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2003 to be
31 * 37 * used in busybox and size optimizations,
38 * support locale, rewrited arith (see notes to this)
32 * 39 *
33 * Original BSD copyright notice is retained at the end of this file.
34 */ 40 */
35 41
42
36/* 43/*
37 * The follow should be set to reflect the type of system you have: 44 * The follow should be set to reflect the type of system you have:
38 * JOBS -> 1 if you have Berkeley job control, 0 otherwise. 45 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
@@ -83,8 +90,6 @@
83#include <sysexits.h> 90#include <sysexits.h>
84 91
85#include <fnmatch.h> 92#include <fnmatch.h>
86#include <glob.h>
87
88 93
89 94
90#include "busybox.h" 95#include "busybox.h"
@@ -544,7 +549,7 @@ static int parsenleft; /* copy of parsefile->nleft */
544static int parselleft; /* copy of parsefile->lleft */ 549static int parselleft; /* copy of parsefile->lleft */
545 550
546/* next character in input buffer */ 551/* next character in input buffer */
547static char *parsenextc; /* copy of parsefile->nextc */ 552static char *parsenextc; /* copy of parsefile->nextc */
548static struct parsefile basepf; /* top level input file */ 553static struct parsefile basepf; /* top level input file */
549static char basebuf[IBUFSIZ]; /* buffer for top level input file */ 554static char basebuf[IBUFSIZ]; /* buffer for top level input file */
550static struct parsefile *parsefile = &basepf; /* current input file */ 555static struct parsefile *parsefile = &basepf; /* current input file */
@@ -588,16 +593,12 @@ static const char homestr[] = "HOME";
588#define TRACEV(param) 593#define TRACEV(param)
589#endif 594#endif
590 595
591#if defined(__GNUC__) && __GNUC__ < 3
592#define va_copy __va_copy
593#endif
594
595#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) 596#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
596#define __builtin_expect(x, expected_value) (x) 597#define __builtin_expect(x, expected_value) (x)
597#endif 598#endif
598 599
599#define likely(x) __builtin_expect((x),1) 600#define likely(x) __builtin_expect((x),1)
600#define unlikely(x) __builtin_expect((x),0) 601
601 602
602#define TEOF 0 603#define TEOF 0
603#define TNL 1 604#define TNL 1
@@ -1223,9 +1224,6 @@ static int dotcmd(int, char **);
1223static int evalcmd(int, char **); 1224static int evalcmd(int, char **);
1224static int execcmd(int, char **); 1225static int execcmd(int, char **);
1225static int exitcmd(int, char **); 1226static int exitcmd(int, char **);
1226#ifdef CONFIG_ASH_MATH_SUPPORT
1227static int expcmd(int, char **);
1228#endif
1229static int exportcmd(int, char **); 1227static int exportcmd(int, char **);
1230static int falsecmd(int, char **); 1228static int falsecmd(int, char **);
1231#ifdef JOBS 1229#ifdef JOBS
@@ -1241,6 +1239,9 @@ static int helpcmd(int argc, char **argv);
1241#ifdef JOBS 1239#ifdef JOBS
1242static int jobscmd(int, char **); 1240static int jobscmd(int, char **);
1243#endif 1241#endif
1242#ifdef CONFIG_ASH_MATH_SUPPORT
1243static int letcmd(int, char **);
1244#endif
1244static int localcmd(int, char **); 1245static int localcmd(int, char **);
1245static int pwdcmd(int, char **); 1246static int pwdcmd(int, char **);
1246static int readcmd(int, char **); 1247static int readcmd(int, char **);
@@ -1345,9 +1346,6 @@ static const struct builtincmd builtincmd[] = {
1345 { BUILTIN_SPEC_REG "eval", evalcmd }, 1346 { BUILTIN_SPEC_REG "eval", evalcmd },
1346 { BUILTIN_SPEC_REG "exec", execcmd }, 1347 { BUILTIN_SPEC_REG "exec", execcmd },
1347 { BUILTIN_SPEC_REG "exit", exitcmd }, 1348 { BUILTIN_SPEC_REG "exit", exitcmd },
1348#ifdef CONFIG_ASH_MATH_SUPPORT
1349 { BUILTIN_NOSPEC "exp", expcmd },
1350#endif
1351 { BUILTIN_SPEC_REG_ASSG "export", exportcmd }, 1349 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1352 { BUILTIN_REGULAR "false", falsecmd }, 1350 { BUILTIN_REGULAR "false", falsecmd },
1353#ifdef JOBS 1351#ifdef JOBS
@@ -1365,7 +1363,7 @@ static const struct builtincmd builtincmd[] = {
1365 { BUILTIN_REGULAR "kill", killcmd }, 1363 { BUILTIN_REGULAR "kill", killcmd },
1366#endif 1364#endif
1367#ifdef CONFIG_ASH_MATH_SUPPORT 1365#ifdef CONFIG_ASH_MATH_SUPPORT
1368 { BUILTIN_NOSPEC "let", expcmd }, 1366 { BUILTIN_NOSPEC "let", letcmd },
1369#endif 1367#endif
1370 { BUILTIN_ASSIGN "local", localcmd }, 1368 { BUILTIN_ASSIGN "local", localcmd },
1371 { BUILTIN_NOSPEC "pwd", pwdcmd }, 1369 { BUILTIN_NOSPEC "pwd", pwdcmd },
@@ -1421,7 +1419,6 @@ static void defun(char *, union node *);
1421static void unsetfunc(const char *); 1419static void unsetfunc(const char *);
1422 1420
1423#ifdef CONFIG_ASH_MATH_SUPPORT 1421#ifdef CONFIG_ASH_MATH_SUPPORT
1424/* From arith.y */
1425static int dash_arith(const char *); 1422static int dash_arith(const char *);
1426#endif 1423#endif
1427 1424
@@ -1482,8 +1479,7 @@ static void change_lc_ctype(const char *value);
1482 1479
1483#define VTABSIZE 39 1480#define VTABSIZE 39
1484 1481
1485static const char defpathvar[] = 1482static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1486 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1487#ifdef IFS_BROKEN 1483#ifdef IFS_BROKEN
1488static const char defifsvar[] = "IFS= \t\n"; 1484static const char defifsvar[] = "IFS= \t\n";
1489#define defifs (defifsvar + 4) 1485#define defifs (defifsvar + 4)
@@ -4522,8 +4518,6 @@ static void removerecordregions(int);
4522static void ifsbreakup(char *, struct arglist *); 4518static void ifsbreakup(char *, struct arglist *);
4523static void ifsfree(void); 4519static void ifsfree(void);
4524static void expandmeta(struct strlist *, int); 4520static void expandmeta(struct strlist *, int);
4525static void addglob(const glob_t *);
4526static void addfname(char *);
4527static int patmatch(char *, const char *); 4521static int patmatch(char *, const char *);
4528 4522
4529static int cvtnum(long); 4523static int cvtnum(long);
@@ -4536,7 +4530,7 @@ static void varunset(const char *, const char *, const char *, int)
4536 4530
4537#define pmatch(a, b) !fnmatch((a), (b), 0) 4531#define pmatch(a, b) !fnmatch((a), (b), 0)
4538/* 4532/*
4539 * Prepare a pattern for a glob(3) call. 4533 * Prepare a pattern for a expmeta (internal glob(3)) call.
4540 * 4534 *
4541 * Returns an stalloced string. 4535 * Returns an stalloced string.
4542 */ 4536 */
@@ -4625,7 +4619,6 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
4625} 4619}
4626 4620
4627 4621
4628
4629/* 4622/*
4630 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC 4623 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4631 * characters to allow for further processing. Otherwise treat 4624 * characters to allow for further processing. Otherwise treat
@@ -4987,10 +4980,9 @@ read:
4987 4980
4988 4981
4989static char * 4982static char *
4990scanleft( 4983scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4991 char *startp, char *rmesc, char *rmescend, char *str, int quotes, 4984 int zero)
4992 int zero 4985{
4993) {
4994 char *loc; 4986 char *loc;
4995 char *loc2; 4987 char *loc2;
4996 char c; 4988 char c;
@@ -5019,10 +5011,9 @@ scanleft(
5019 5011
5020 5012
5021static char * 5013static char *
5022scanright( 5014scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5023 char *startp, char *rmesc, char *rmescend, char *str, int quotes, 5015 int zero)
5024 int zero 5016{
5025) {
5026 int esc = 0; 5017 int esc = 0;
5027 char *loc; 5018 char *loc;
5028 char *loc2; 5019 char *loc2;
@@ -5330,7 +5321,6 @@ varisset(char *name, int nulok)
5330} 5321}
5331 5322
5332 5323
5333
5334/* 5324/*
5335 * Put a string on the stack. 5325 * Put a string on the stack.
5336 */ 5326 */
@@ -5361,7 +5351,6 @@ strtodest(const char *p, int syntax, int quotes)
5361} 5351}
5362 5352
5363 5353
5364
5365/* 5354/*
5366 * Add the value of a specialized variable to the stack string. 5355 * Add the value of a specialized variable to the stack string.
5367 */ 5356 */
@@ -5437,7 +5426,6 @@ param:
5437} 5426}
5438 5427
5439 5428
5440
5441/* 5429/*
5442 * Record the fact that we have to scan this region of the 5430 * Record the fact that we have to scan this region of the
5443 * string for IFS characters. 5431 * string for IFS characters.
@@ -5464,7 +5452,6 @@ recordregion(int start, int end, int nulonly)
5464} 5452}
5465 5453
5466 5454
5467
5468/* 5455/*
5469 * Break the argument string into pieces based upon IFS and add the 5456 * Break the argument string into pieces based upon IFS and add the
5470 * strings to the argument list. The regions of the string to be 5457 * strings to the argument list. The regions of the string to be
@@ -5573,86 +5560,254 @@ ifsfree(void)
5573 INTON; 5560 INTON;
5574} 5561}
5575 5562
5563static void expmeta(char *, char *);
5564static struct strlist *expsort(struct strlist *);
5565static struct strlist *msort(struct strlist *, int);
5576 5566
5567static char *expdir;
5577 5568
5578/*
5579 * Expand shell metacharacters. At this point, the only control characters
5580 * should be escapes. The results are stored in the list exparg.
5581 */
5582 5569
5583static void 5570static void
5584expandmeta(str, flag) 5571expandmeta(struct strlist *str, int flag)
5585 struct strlist *str;
5586 int flag;
5587{ 5572{
5573 static const char metachars[] = {
5574 '*', '?', '[', 0
5575 };
5588 /* TODO - EXP_REDIR */ 5576 /* TODO - EXP_REDIR */
5589 5577
5590 while (str) { 5578 while (str) {
5591 const char *p; 5579 struct strlist **savelastp;
5592 glob_t pglob; 5580 struct strlist *sp;
5593 int i; 5581 char *p;
5594 5582
5595 if (fflag) 5583 if (fflag)
5596 goto nometa; 5584 goto nometa;
5585 if (!strpbrk(str->text, metachars))
5586 goto nometa;
5587 savelastp = exparg.lastp;
5588
5597 INTOFF; 5589 INTOFF;
5598 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); 5590 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5599 i = glob(p, GLOB_NOMAGIC, 0, &pglob); 5591 {
5592 int i = strlen(str->text);
5593 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5594 }
5595
5596 expmeta(expdir, p);
5597 ckfree(expdir);
5600 if (p != str->text) 5598 if (p != str->text)
5601 ckfree(p); 5599 ckfree(p);
5602 switch (i) { 5600 INTON;
5603 case 0: 5601 if (exparg.lastp == savelastp) {
5604 if (!(pglob.gl_flags & GLOB_MAGCHAR)) 5602 /*
5605 goto nometa2; 5603 * no matches
5606 addglob(&pglob); 5604 */
5607 globfree(&pglob);
5608 INTON;
5609 break;
5610 case GLOB_NOMATCH:
5611nometa2:
5612 globfree(&pglob);
5613 INTON;
5614nometa: 5605nometa:
5615 *exparg.lastp = str; 5606 *exparg.lastp = str;
5616 rmescapes(str->text); 5607 rmescapes(str->text);
5617 exparg.lastp = &str->next; 5608 exparg.lastp = &str->next;
5618 break; 5609 } else {
5619 default: /* GLOB_NOSPACE */ 5610 *exparg.lastp = NULL;
5620 error(bb_msg_memory_exhausted); 5611 *savelastp = sp = expsort(*savelastp);
5612 while (sp->next != NULL)
5613 sp = sp->next;
5614 exparg.lastp = &sp->next;
5621 } 5615 }
5622 str = str->next; 5616 str = str->next;
5623 } 5617 }
5624} 5618}
5625 5619
5626
5627/* 5620/*
5628 * Add the result of glob(3) to the list. 5621 * Add a file name to the list.
5629 */ 5622 */
5630 5623
5631static void 5624static void
5632addglob(pglob) 5625addfname(const char *name)
5633 const glob_t *pglob;
5634{ 5626{
5635 char **p = pglob->gl_pathv; 5627 struct strlist *sp;
5636 5628
5637 do { 5629 sp = (struct strlist *)stalloc(sizeof *sp);
5638 addfname(*p); 5630 sp->text = sstrdup(name);
5639 } while (*++p); 5631 *exparg.lastp = sp;
5632 exparg.lastp = &sp->next;
5640} 5633}
5641 5634
5642 5635
5643/* 5636/*
5644 * Add a file name to the list. 5637 * Do metacharacter (i.e. *, ?, [...]) expansion.
5645 */ 5638 */
5646 5639
5647static void 5640static void
5648addfname(char *name) 5641expmeta(char *enddir, char *name)
5649{ 5642{
5643 char *p;
5644 const char *cp;
5645 char *start;
5646 char *endname;
5647 int metaflag;
5648 struct stat64 statb;
5649 DIR *dirp;
5650 struct dirent *dp;
5651 int atend;
5652 int matchdot;
5653
5654 metaflag = 0;
5655 start = name;
5656 for (p = name; *p; p++) {
5657 if (*p == '*' || *p == '?')
5658 metaflag = 1;
5659 else if (*p == '[') {
5660 char *q = p + 1;
5661 if (*q == '!')
5662 q++;
5663 for (;;) {
5664 if (*q == '\\')
5665 q++;
5666 if (*q == '/' || *q == '\0')
5667 break;
5668 if (*++q == ']') {
5669 metaflag = 1;
5670 break;
5671 }
5672 }
5673 } else if (*p == '\\')
5674 p++;
5675 else if (*p == '/') {
5676 if (metaflag)
5677 goto out;
5678 start = p + 1;
5679 }
5680 }
5681out:
5682 if (metaflag == 0) { /* we've reached the end of the file name */
5683 if (enddir != expdir)
5684 metaflag++;
5685 p = name;
5686 do {
5687 if (*p == '\\')
5688 p++;
5689 *enddir++ = *p;
5690 } while (*p++);
5691 if (metaflag == 0 || lstat64(expdir, &statb) >= 0)
5692 addfname(expdir);
5693 return;
5694 }
5695 endname = p;
5696 if (name < start) {
5697 p = name;
5698 do {
5699 if (*p == '\\')
5700 p++;
5701 *enddir++ = *p++;
5702 } while (p < start);
5703 }
5704 if (enddir == expdir) {
5705 cp = ".";
5706 } else if (enddir == expdir + 1 && *expdir == '/') {
5707 cp = "/";
5708 } else {
5709 cp = expdir;
5710 enddir[-1] = '\0';
5711 }
5712 if ((dirp = opendir(cp)) == NULL)
5713 return;
5714 if (enddir != expdir)
5715 enddir[-1] = '/';
5716 if (*endname == 0) {
5717 atend = 1;
5718 } else {
5719 atend = 0;
5720 *endname++ = '\0';
5721 }
5722 matchdot = 0;
5723 p = start;
5724 if (*p == '\\')
5725 p++;
5726 if (*p == '.')
5727 matchdot++;
5728 while (! intpending && (dp = readdir(dirp)) != NULL) {
5729 if (dp->d_name[0] == '.' && ! matchdot)
5730 continue;
5731 if (pmatch(start, dp->d_name)) {
5732 if (atend) {
5733 scopy(dp->d_name, enddir);
5734 addfname(expdir);
5735 } else {
5736 for (p = enddir, cp = dp->d_name;
5737 (*p++ = *cp++) != '\0';)
5738 continue;
5739 p[-1] = '/';
5740 expmeta(p, endname);
5741 }
5742 }
5743 }
5744 closedir(dirp);
5745 if (! atend)
5746 endname[-1] = '/';
5747}
5748
5749/*
5750 * Sort the results of file name expansion. It calculates the number of
5751 * strings to sort and then calls msort (short for merge sort) to do the
5752 * work.
5753 */
5754
5755static struct strlist *
5756expsort(struct strlist *str)
5757{
5758 int len;
5650 struct strlist *sp; 5759 struct strlist *sp;
5651 5760
5652 sp = (struct strlist *)stalloc(sizeof *sp); 5761 len = 0;
5653 sp->text = sstrdup(name); 5762 for (sp = str ; sp ; sp = sp->next)
5654 *exparg.lastp = sp; 5763 len++;
5655 exparg.lastp = &sp->next; 5764 return msort(str, len);
5765}
5766
5767
5768static struct strlist *
5769msort(struct strlist *list, int len)
5770{
5771 struct strlist *p, *q = NULL;
5772 struct strlist **lpp;
5773 int half;
5774 int n;
5775
5776 if (len <= 1)
5777 return list;
5778 half = len >> 1;
5779 p = list;
5780 for (n = half ; --n >= 0 ; ) {
5781 q = p;
5782 p = p->next;
5783 }
5784 q->next = NULL; /* terminate first half of list */
5785 q = msort(list, half); /* sort first half of list */
5786 p = msort(p, len - half); /* sort second half */
5787 lpp = &list;
5788 for (;;) {
5789#ifdef CONFIG_LOCALE_SUPPORT
5790 if (strcoll(p->text, q->text) < 0)
5791#else
5792 if (strcmp(p->text, q->text) < 0)
5793#endif
5794 {
5795 *lpp = p;
5796 lpp = &p->next;
5797 if ((p = *lpp) == NULL) {
5798 *lpp = q;
5799 break;
5800 }
5801 } else {
5802 *lpp = q;
5803 lpp = &q->next;
5804 if ((q = *lpp) == NULL) {
5805 *lpp = p;
5806 break;
5807 }
5808 }
5809 }
5810 return list;
5656} 5811}
5657 5812
5658 5813
@@ -5736,7 +5891,6 @@ copy:
5736} 5891}
5737 5892
5738 5893
5739
5740/* 5894/*
5741 * See if a pattern matches in a case statement. 5895 * See if a pattern matches in a case statement.
5742 */ 5896 */
@@ -5790,12 +5944,12 @@ varunset(const char *end, const char *var, const char *umsg, int varflags)
5790 } 5944 }
5791 error("%.*s: %s%s", end - var - 1, var, msg, tail); 5945 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5792} 5946}
5793/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5794 5947
5795 5948
5949/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5796 5950
5797/* 5951/*
5798 * This file implements the input routines used by the parser. 5952 * This implements the input routines used by the parser.
5799 */ 5953 */
5800 5954
5801#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 5955#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
@@ -6147,7 +6301,6 @@ setinputstring(char *string)
6147} 6301}
6148 6302
6149 6303
6150
6151/* 6304/*
6152 * To handle the "." command, a stack of input files is used. Pushfile 6305 * To handle the "." command, a stack of input files is used. Pushfile
6153 * adds a new entry to the stack and popfile restores the previous level. 6306 * adds a new entry to the stack and popfile restores the previous level.
@@ -6205,7 +6358,6 @@ popallfiles(void)
6205} 6358}
6206 6359
6207 6360
6208
6209/* 6361/*
6210 * Close the file(s) that the shell is reading commands from. Called 6362 * Close the file(s) that the shell is reading commands from. Called
6211 * after a fork is done. 6363 * after a fork is done.
@@ -6220,8 +6372,8 @@ closescript(void)
6220 parsefile->fd = 0; 6372 parsefile->fd = 0;
6221 } 6373 }
6222} 6374}
6223/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6224 6375
6376/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6225 6377
6226/* mode flags for set_curjob */ 6378/* mode flags for set_curjob */
6227#define CUR_DELETE 2 6379#define CUR_DELETE 2
@@ -6382,9 +6534,7 @@ close:
6382} 6534}
6383 6535
6384static int 6536static int
6385killcmd(argc, argv) 6537killcmd(int argc, char **argv)
6386 int argc;
6387 char **argv;
6388{ 6538{
6389 int signo = -1; 6539 int signo = -1;
6390 int list = 0; 6540 int list = 0;
@@ -6625,8 +6775,7 @@ showjob(FILE *out, struct job *jp, int mode)
6625 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3; 6775 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6626 6776
6627start: 6777start:
6628 fprintf( 6778 fprintf(out, "%s%*c%s",
6629 out, "%s%*c%s",
6630 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd 6779 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6631 ); 6780 );
6632 if (!(mode & SHOW_PID)) { 6781 if (!(mode & SHOW_PID)) {
@@ -6781,7 +6930,6 @@ out:
6781} 6930}
6782 6931
6783 6932
6784
6785/* 6933/*
6786 * Convert a job name to a job structure. 6934 * Convert a job name to a job structure.
6787 */ 6935 */
@@ -6866,7 +7014,6 @@ err:
6866} 7014}
6867 7015
6868 7016
6869
6870/* 7017/*
6871 * Return a new job structure. 7018 * Return a new job structure.
6872 * Called with interrupts off. 7019 * Called with interrupts off.
@@ -7260,10 +7407,10 @@ out:
7260} 7407}
7261 7408
7262 7409
7263
7264/* 7410/*
7265 * return 1 if there are stopped jobs, otherwise 0 7411 * return 1 if there are stopped jobs, otherwise 0
7266 */ 7412 */
7413
7267int 7414int
7268stoppedjobs(void) 7415stoppedjobs(void)
7269{ 7416{
@@ -7468,7 +7615,6 @@ cmdlist(union node *np, int sep)
7468 } 7615 }
7469} 7616}
7470 7617
7471
7472static void 7618static void
7473cmdputs(const char *s) 7619cmdputs(const char *s)
7474{ 7620{
@@ -7749,7 +7895,7 @@ ash_main(int argc, char **argv)
7749 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell) 7895 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7750 exitshell(); 7896 exitshell();
7751 7897
7752 if (e == EXINT ) { 7898 if (e == EXINT) {
7753 outcslow('\n', stderr); 7899 outcslow('\n', stderr);
7754 } 7900 }
7755 popstackmark(&smark); 7901 popstackmark(&smark);
@@ -7814,7 +7960,6 @@ state3:
7814 evalstring(minusc, 0); 7960 evalstring(minusc, 0);
7815 7961
7816 if (sflag || minusc == NULL) { 7962 if (sflag || minusc == NULL) {
7817state4: /* XXX ??? - why isn't this before the "if" statement */
7818#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 7963#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7819 if ( iflag ) { 7964 if ( iflag ) {
7820 const char *hp = lookupvar("HISTFILE"); 7965 const char *hp = lookupvar("HISTFILE");
@@ -7823,6 +7968,7 @@ state4: /* XXX ??? - why isn't this before the "if" statement */
7823 load_history ( hp ); 7968 load_history ( hp );
7824 } 7969 }
7825#endif 7970#endif
7971state4: /* XXX ??? - why isn't this before the "if" statement */
7826 cmdloop(1); 7972 cmdloop(1);
7827 } 7973 }
7828#if PROFILE 7974#if PROFILE
@@ -7895,7 +8041,6 @@ cmdloop(int top)
7895} 8041}
7896 8042
7897 8043
7898
7899/* 8044/*
7900 * Read /etc/profile or .profile. Return on error. 8045 * Read /etc/profile or .profile. Return on error.
7901 */ 8046 */
@@ -7931,7 +8076,6 @@ read_profile(const char *name)
7931} 8076}
7932 8077
7933 8078
7934
7935/* 8079/*
7936 * Read a file containing shell functions. 8080 * Read a file containing shell functions.
7937 */ 8081 */
@@ -8019,35 +8163,24 @@ exitcmd(int argc, char **argv)
8019/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */ 8163/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8020 8164
8021/* 8165/*
8022 * Like malloc, but returns an error when out of space. 8166 * Same for malloc, realloc, but returns an error when out of space.
8023 */ 8167 */
8024 8168
8025static pointer 8169static pointer
8026ckmalloc(size_t nbytes) 8170ckrealloc(pointer p, size_t nbytes)
8027{ 8171{
8028 pointer p; 8172 p = realloc(p, nbytes);
8029
8030 p = malloc(nbytes);
8031 if (p == NULL) 8173 if (p == NULL)
8032 error(bb_msg_memory_exhausted); 8174 error(bb_msg_memory_exhausted);
8033 return p; 8175 return p;
8034} 8176}
8035 8177
8036
8037/*
8038 * Same for realloc.
8039 */
8040
8041static pointer 8178static pointer
8042ckrealloc(pointer p, size_t nbytes) 8179ckmalloc(size_t nbytes)
8043{ 8180{
8044 p = realloc(p, nbytes); 8181 return ckrealloc(NULL, nbytes);
8045 if (p == NULL)
8046 error(bb_msg_memory_exhausted);
8047 return p;
8048} 8182}
8049 8183
8050
8051/* 8184/*
8052 * Make a copy of a string in safe storage. 8185 * Make a copy of a string in safe storage.
8053 */ 8186 */
@@ -8120,7 +8253,6 @@ stunalloc(pointer p)
8120} 8253}
8121 8254
8122 8255
8123
8124void 8256void
8125setstackmark(struct stackmark *mark) 8257setstackmark(struct stackmark *mark)
8126{ 8258{
@@ -8327,7 +8459,6 @@ number(const char *s)
8327} 8459}
8328 8460
8329 8461
8330
8331/* 8462/*
8332 * Check for a valid number. This should be elsewhere. 8463 * Check for a valid number. This should be elsewhere.
8333 */ 8464 */
@@ -8479,7 +8610,6 @@ calcsize(union node *n)
8479} 8610}
8480 8611
8481 8612
8482
8483static void 8613static void
8484sizenodelist(struct nodelist *lp) 8614sizenodelist(struct nodelist *lp)
8485{ 8615{
@@ -8491,7 +8621,6 @@ sizenodelist(struct nodelist *lp)
8491} 8621}
8492 8622
8493 8623
8494
8495static union node * 8624static union node *
8496copynode(union node *n) 8625copynode(union node *n)
8497{ 8626{
@@ -8601,7 +8730,6 @@ copynodelist(struct nodelist *lp)
8601} 8730}
8602 8731
8603 8732
8604
8605static char * 8733static char *
8606nodesavestr(char *s) 8734nodesavestr(char *s)
8607{ 8735{
@@ -8612,7 +8740,6 @@ nodesavestr(char *s)
8612} 8740}
8613 8741
8614 8742
8615
8616/* 8743/*
8617 * Free a parse tree. 8744 * Free a parse tree.
8618 */ 8745 */
@@ -8775,7 +8902,6 @@ options(int cmdline)
8775} 8902}
8776 8903
8777 8904
8778
8779static void 8905static void
8780setoption(int flag, int val) 8906setoption(int flag, int val)
8781{ 8907{
@@ -10669,7 +10795,7 @@ noexpand(char *text)
10669 10795
10670char * 10796char *
10671endofname(const char *name) 10797endofname(const char *name)
10672 { 10798{
10673 char *p; 10799 char *p;
10674 10800
10675 p = (char *) name; 10801 p = (char *) name;
@@ -10735,7 +10861,7 @@ static void setprompt(int whichprompt)
10735static const char *const *findkwd(const char *s) 10861static const char *const *findkwd(const char *s)
10736{ 10862{
10737 return bsearch(s, tokname_array + KWDOFFSET, 10863 return bsearch(s, tokname_array + KWDOFFSET,
10738 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET, 10864 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10739 sizeof(const char *), pstrcmp); 10865 sizeof(const char *), pstrcmp);
10740} 10866}
10741 10867
@@ -12122,7 +12248,6 @@ localcmd(int argc, char **argv)
12122} 12248}
12123 12249
12124 12250
12125
12126/* 12251/*
12127 * Called after a function returns. 12252 * Called after a function returns.
12128 * Interrupts must be off. 12253 * Interrupts must be off.
@@ -12320,14 +12445,18 @@ int timescmd(int ac, char **av) {
12320static int 12445static int
12321dash_arith(const char *s) 12446dash_arith(const char *s)
12322{ 12447{
12323 long result = 0; 12448 long result;
12324 int errcode = 0; 12449 int errcode = 0;
12325 12450
12326 INTOFF; 12451 INTOFF;
12327 result = arith(s, &errcode); 12452 result = arith(s, &errcode);
12328 if (errcode < 0) { 12453 if (errcode < 0) {
12329 if (errcode == -2) 12454 if (errcode == -3)
12455 error("exponent less than 0");
12456 else if (errcode == -2)
12330 error("divide by zero"); 12457 error("divide by zero");
12458 else if (errcode == -5)
12459 error("expression recursion loop detected");
12331 else 12460 else
12332 synerror(s); 12461 synerror(s);
12333 } 12462 }
@@ -12338,41 +12467,26 @@ dash_arith(const char *s)
12338 12467
12339 12468
12340/* 12469/*
12341 * The exp(1) builtin. 12470 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12471 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12472 *
12473 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12342 */ 12474 */
12475
12343static int 12476static int
12344expcmd(int argc, char **argv) 12477letcmd(int argc, char **argv)
12345{ 12478{
12346 const char *p;
12347 char *concat;
12348 char **ap; 12479 char **ap;
12349 long i; 12480 long i;
12350 12481
12351 if (argc > 1) { 12482 ap = argv + 1;
12352 p = argv[1]; 12483 if(!*ap)
12353 if (argc > 2) { 12484 error("expression expected");
12354 /* 12485 for (ap = argv + 1; *ap; ap++) {
12355 * concatenate arguments 12486 i = dash_arith(*ap);
12356 */ 12487 }
12357 STARTSTACKSTR(concat);
12358 ap = argv + 2;
12359 for (;;) {
12360 while (*p)
12361 STPUTC(*p++, concat);
12362 if ((p = *ap++) == NULL)
12363 break;
12364 STPUTC(' ', concat);
12365 }
12366 STPUTC('\0', concat);
12367 p = grabstackstr(concat);
12368 }
12369 } else
12370 p = nullstr;
12371
12372 i = dash_arith(p);
12373 12488
12374 out1fmt("%ld\n", i); 12489 return (!i);
12375 return (! i);
12376} 12490}
12377#endif /* CONFIG_ASH_MATH_SUPPORT */ 12491#endif /* CONFIG_ASH_MATH_SUPPORT */
12378 12492
@@ -12697,6 +12811,649 @@ ulimitcmd(int argc, char **argv)
12697 return 0; 12811 return 0;
12698} 12812}
12699 12813
12814
12815#ifdef CONFIG_ASH_MATH_SUPPORT
12816
12817/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12818
12819 Permission is hereby granted, free of charge, to any person obtaining
12820 a copy of this software and associated documentation files (the
12821 "Software"), to deal in the Software without restriction, including
12822 without limitation the rights to use, copy, modify, merge, publish,
12823 distribute, sublicense, and/or sell copies of the Software, and to
12824 permit persons to whom the Software is furnished to do so, subject to
12825 the following conditions:
12826
12827 The above copyright notice and this permission notice shall be
12828 included in all copies or substantial portions of the Software.
12829
12830 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12831 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12832 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12833 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12834 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12835 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12836 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12837*/
12838
12839/* This is my infix parser/evaluator. It is optimized for size, intended
12840 * as a replacement for yacc-based parsers. However, it may well be faster
12841 * than a comparable parser writen in yacc. The supported operators are
12842 * listed in #defines below. Parens, order of operations, and error handling
12843 * are supported. This code is threadsafe. The exact expression format should
12844 * be that which POSIX specifies for shells. */
12845
12846/* The code uses a simple two-stack algorithm. See
12847 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12848 * for a detailed explaination of the infix-to-postfix algorithm on which
12849 * this is based (this code differs in that it applies operators immediately
12850 * to the stack instead of adding them to a queue to end up with an
12851 * expression). */
12852
12853/* To use the routine, call it with an expression string and error return
12854 * pointer */
12855
12856/*
12857 * Aug 24, 2001 Manuel Novoa III
12858 *
12859 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12860 *
12861 * 1) In arith_apply():
12862 * a) Cached values of *numptr and &(numptr[-1]).
12863 * b) Removed redundant test for zero denominator.
12864 *
12865 * 2) In arith():
12866 * a) Eliminated redundant code for processing operator tokens by moving
12867 * to a table-based implementation. Also folded handling of parens
12868 * into the table.
12869 * b) Combined all 3 loops which called arith_apply to reduce generated
12870 * code size at the cost of speed.
12871 *
12872 * 3) The following expressions were treated as valid by the original code:
12873 * 1() , 0! , 1 ( *3 ) .
12874 * These bugs have been fixed by internally enclosing the expression in
12875 * parens and then checking that all binary ops and right parens are
12876 * preceded by a valid expression (NUM_TOKEN).
12877 *
12878 * Note: It may be desireable to replace Aaron's test for whitespace with
12879 * ctype's isspace() if it is used by another busybox applet or if additional
12880 * whitespace chars should be considered. Look below the "#include"s for a
12881 * precompiler test.
12882 */
12883
12884/*
12885 * Aug 26, 2001 Manuel Novoa III
12886 *
12887 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12888 *
12889 * Merge in Aaron's comments previously posted to the busybox list,
12890 * modified slightly to take account of my changes to the code.
12891 *
12892 */
12893
12894/*
12895 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12896 *
12897 * - allow access to variable,
12898 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12899 * - realize assign syntax (VAR=expr, +=, *= etc)
12900 * - realize exponentiation (** operator)
12901 * - realize comma separated - expr, expr
12902 * - realise ++expr --expr expr++ expr--
12903 * - realise expr ? expr : expr (but, second expr calculate always)
12904 * - allow hexdecimal and octal numbers
12905 * - was restored loses XOR operator
12906 * - remove one goto label, added three ;-)
12907 * - protect $((num num)) as true zero expr (Manuel`s error)
12908 * - always use special isspace(), see comment from bash ;-)
12909 */
12910
12911
12912#define arith_isspace(arithval) \
12913 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12914
12915
12916typedef unsigned char operator;
12917
12918/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12919 * precedence, and 3 high bits are an ID unique accross operators of that
12920 * precedence. The ID portion is so that multiple operators can have the
12921 * same precedence, ensuring that the leftmost one is evaluated first.
12922 * Consider * and /. */
12923
12924#define tok_decl(prec,id) (((id)<<5)|(prec))
12925#define PREC(op) ((op) & 0x1F)
12926
12927#define TOK_LPAREN tok_decl(0,0)
12928
12929#define TOK_COMMA tok_decl(1,0)
12930
12931#define TOK_ASSIGN tok_decl(2,0)
12932#define TOK_AND_ASSIGN tok_decl(2,1)
12933#define TOK_OR_ASSIGN tok_decl(2,2)
12934#define TOK_XOR_ASSIGN tok_decl(2,3)
12935#define TOK_PLUS_ASSIGN tok_decl(2,4)
12936#define TOK_MINUS_ASSIGN tok_decl(2,5)
12937#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12938#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12939
12940#define TOK_MUL_ASSIGN tok_decl(3,0)
12941#define TOK_DIV_ASSIGN tok_decl(3,1)
12942#define TOK_REM_ASSIGN tok_decl(3,2)
12943
12944/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12945#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
12946
12947/* conditional is right associativity too */
12948#define TOK_CONDITIONAL tok_decl(4,0)
12949#define TOK_CONDITIONAL_SEP tok_decl(4,1)
12950
12951#define TOK_OR tok_decl(5,0)
12952
12953#define TOK_AND tok_decl(6,0)
12954
12955#define TOK_BOR tok_decl(7,0)
12956
12957#define TOK_BXOR tok_decl(8,0)
12958
12959#define TOK_BAND tok_decl(9,0)
12960
12961#define TOK_EQ tok_decl(10,0)
12962#define TOK_NE tok_decl(10,1)
12963
12964#define TOK_LT tok_decl(11,0)
12965#define TOK_GT tok_decl(11,1)
12966#define TOK_GE tok_decl(11,2)
12967#define TOK_LE tok_decl(11,3)
12968
12969#define TOK_LSHIFT tok_decl(12,0)
12970#define TOK_RSHIFT tok_decl(12,1)
12971
12972#define TOK_ADD tok_decl(13,0)
12973#define TOK_SUB tok_decl(13,1)
12974
12975#define TOK_MUL tok_decl(14,0)
12976#define TOK_DIV tok_decl(14,1)
12977#define TOK_REM tok_decl(14,2)
12978
12979/* exponent is right associativity */
12980#define TOK_EXPONENT tok_decl(15,1)
12981
12982/* For now unary operators. */
12983#define UNARYPREC 16
12984#define TOK_BNOT tok_decl(UNARYPREC,0)
12985#define TOK_NOT tok_decl(UNARYPREC,1)
12986
12987#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12988#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12989
12990#define PREC_PRE (UNARYPREC+2)
12991
12992#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12993#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12994
12995#define PREC_POST (UNARYPREC+3)
12996
12997#define TOK_POST_INC tok_decl(PREC_POST, 0)
12998#define TOK_POST_DEC tok_decl(PREC_POST, 1)
12999
13000#define SPEC_PREC (UNARYPREC+4)
13001
13002#define TOK_NUM tok_decl(SPEC_PREC, 0)
13003#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13004
13005#define NUMPTR (*numstackptr)
13006
13007static inline int tok_have_assign(operator op)
13008{
13009 operator prec = PREC(op);
13010
13011 convert_prec_is_assing(prec);
13012 return (prec == PREC(TOK_ASSIGN) ||
13013 prec == PREC_PRE || prec == PREC_POST);
13014}
13015
13016static inline int is_right_associativity(operator prec)
13017{
13018 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13019 prec == PREC(TOK_CONDITIONAL));
13020}
13021
13022
13023typedef struct ARITCH_VAR_NUM {
13024 long val;
13025 long contidional_second_val;
13026 char contidional_second_val_initialized;
13027 char *var; /* if NULL then is regular number,
13028 else is varable name */
13029} v_n_t;
13030
13031
13032typedef struct CHK_VAR_RECURSIVE_LOOPED {
13033 const char *var;
13034 struct CHK_VAR_RECURSIVE_LOOPED *next;
13035} chk_var_recursive_looped_t;
13036
13037static chk_var_recursive_looped_t *prev_chk_var_recursive;
13038
13039
13040static int arith_lookup_val(v_n_t *t)
13041{
13042 if(t->var) {
13043 const char * p = lookupvar(t->var);
13044
13045 if(p) {
13046 int errcode;
13047
13048 /* recursive try as expression */
13049 chk_var_recursive_looped_t *cur;
13050 chk_var_recursive_looped_t cur_save;
13051
13052 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13053 if(strcmp(cur->var, t->var) == 0) {
13054 /* expression recursion loop detected */
13055 return -5;
13056 }
13057 }
13058 /* save current lookuped var name */
13059 cur = prev_chk_var_recursive;
13060 cur_save.var = t->var;
13061 cur_save.next = cur;
13062 prev_chk_var_recursive = &cur_save;
13063
13064 t->val = arith (p, &errcode);
13065 /* restore previous ptr after recursiving */
13066 prev_chk_var_recursive = cur;
13067 return errcode;
13068 } else {
13069 /* allow undefined var as 0 */
13070 t->val = 0;
13071 }
13072 }
13073 return 0;
13074}
13075
13076/* "applying" a token means performing it on the top elements on the integer
13077 * stack. For a unary operator it will only change the top element, but a
13078 * binary operator will pop two arguments and push a result */
13079static inline int
13080arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13081{
13082 long numptr_val;
13083 v_n_t *numptr_m1;
13084 long rez;
13085 int ret_arith_lookup_val;
13086
13087 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13088 without arguments */
13089 numptr_m1 = NUMPTR - 1;
13090
13091 /* check operand is var with noninteger value */
13092 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13093 if(ret_arith_lookup_val)
13094 return ret_arith_lookup_val;
13095
13096 rez = numptr_m1->val;
13097 if (op == TOK_UMINUS)
13098 rez *= -1;
13099 else if (op == TOK_NOT)
13100 rez = !rez;
13101 else if (op == TOK_BNOT)
13102 rez = ~rez;
13103 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13104 rez++;
13105 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13106 rez--;
13107 else if (op != TOK_UPLUS) {
13108 /* Binary operators */
13109
13110 /* check and binary operators need two arguments */
13111 if (numptr_m1 == numstack) goto err;
13112
13113 /* ... and they pop one */
13114 --NUMPTR;
13115 numptr_val = rez;
13116 if (op == TOK_CONDITIONAL) {
13117 if(! numptr_m1->contidional_second_val_initialized) {
13118 /* protect $((expr1 ? expr2)) without ": expr" */
13119 goto err;
13120 }
13121 rez = numptr_m1->contidional_second_val;
13122 } else if(numptr_m1->contidional_second_val_initialized) {
13123 /* protect $((expr1 : expr2)) without "expr ? " */
13124 goto err;
13125 }
13126 numptr_m1 = NUMPTR - 1;
13127 if(op != TOK_ASSIGN) {
13128 /* check operand is var with noninteger value for not '=' */
13129 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13130 if(ret_arith_lookup_val)
13131 return ret_arith_lookup_val;
13132 }
13133 if (op == TOK_CONDITIONAL) {
13134 numptr_m1->contidional_second_val = rez;
13135 }
13136 rez = numptr_m1->val;
13137 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13138 rez |= numptr_val;
13139 else if (op == TOK_OR)
13140 rez = numptr_val || rez;
13141 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13142 rez &= numptr_val;
13143 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13144 rez ^= numptr_val;
13145 else if (op == TOK_AND)
13146 rez = rez && numptr_val;
13147 else if (op == TOK_EQ)
13148 rez = (rez == numptr_val);
13149 else if (op == TOK_NE)
13150 rez = (rez != numptr_val);
13151 else if (op == TOK_GE)
13152 rez = (rez >= numptr_val);
13153 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13154 rez >>= numptr_val;
13155 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13156 rez <<= numptr_val;
13157 else if (op == TOK_GT)
13158 rez = (rez > numptr_val);
13159 else if (op == TOK_LT)
13160 rez = (rez < numptr_val);
13161 else if (op == TOK_LE)
13162 rez = (rez <= numptr_val);
13163 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13164 rez *= numptr_val;
13165 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13166 rez += numptr_val;
13167 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13168 rez -= numptr_val;
13169 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13170 rez = numptr_val;
13171 else if (op == TOK_CONDITIONAL_SEP) {
13172 if (numptr_m1 == numstack) {
13173 /* protect $((expr : expr)) without "expr ? " */
13174 goto err;
13175 }
13176 numptr_m1->contidional_second_val_initialized = op;
13177 numptr_m1->contidional_second_val = numptr_val;
13178 }
13179 else if (op == TOK_CONDITIONAL) {
13180 rez = rez ?
13181 numptr_val : numptr_m1->contidional_second_val;
13182 }
13183 else if(op == TOK_EXPONENT) {
13184 if(numptr_val < 0)
13185 return -3; /* exponent less than 0 */
13186 else {
13187 long c = 1;
13188
13189 if(numptr_val)
13190 while(numptr_val--)
13191 c *= rez;
13192 rez = c;
13193 }
13194 }
13195 else if(numptr_val==0) /* zero divisor check */
13196 return -2;
13197 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13198 rez /= numptr_val;
13199 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13200 rez %= numptr_val;
13201 }
13202 if(tok_have_assign(op)) {
13203 char buf[32];
13204
13205 if(numptr_m1->var == NULL) {
13206 /* Hmm, 1=2 ? */
13207 goto err;
13208 }
13209 /* save to shell variable */
13210 sprintf(buf, "%ld", rez);
13211 setvar(numptr_m1->var, buf, 0);
13212 /* after saving, make previous value for v++ or v-- */
13213 if(op == TOK_POST_INC)
13214 rez--;
13215 else if(op == TOK_POST_DEC)
13216 rez++;
13217 }
13218 numptr_m1->val = rez;
13219 /* protect geting var value, is number now */
13220 numptr_m1->var = NULL;
13221 return 0;
13222err: return(-1);
13223}
13224
13225/* longest must first */
13226static const char op_tokens[] = {
13227 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13228 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13229 '<','<', 0, TOK_LSHIFT,
13230 '>','>', 0, TOK_RSHIFT,
13231 '|','|', 0, TOK_OR,
13232 '&','&', 0, TOK_AND,
13233 '!','=', 0, TOK_NE,
13234 '<','=', 0, TOK_LE,
13235 '>','=', 0, TOK_GE,
13236 '=','=', 0, TOK_EQ,
13237 '|','=', 0, TOK_OR_ASSIGN,
13238 '&','=', 0, TOK_AND_ASSIGN,
13239 '*','=', 0, TOK_MUL_ASSIGN,
13240 '/','=', 0, TOK_DIV_ASSIGN,
13241 '%','=', 0, TOK_REM_ASSIGN,
13242 '+','=', 0, TOK_PLUS_ASSIGN,
13243 '-','=', 0, TOK_MINUS_ASSIGN,
13244 '-','-', 0, TOK_POST_DEC,
13245 '^','=', 0, TOK_XOR_ASSIGN,
13246 '+','+', 0, TOK_POST_INC,
13247 '*','*', 0, TOK_EXPONENT,
13248 '!', 0, TOK_NOT,
13249 '<', 0, TOK_LT,
13250 '>', 0, TOK_GT,
13251 '=', 0, TOK_ASSIGN,
13252 '|', 0, TOK_BOR,
13253 '&', 0, TOK_BAND,
13254 '*', 0, TOK_MUL,
13255 '/', 0, TOK_DIV,
13256 '%', 0, TOK_REM,
13257 '+', 0, TOK_ADD,
13258 '-', 0, TOK_SUB,
13259 '^', 0, TOK_BXOR,
13260 /* uniq */
13261 '~', 0, TOK_BNOT,
13262 ',', 0, TOK_COMMA,
13263 '?', 0, TOK_CONDITIONAL,
13264 ':', 0, TOK_CONDITIONAL_SEP,
13265 ')', 0, TOK_RPAREN,
13266 '(', 0, TOK_LPAREN,
13267 0
13268};
13269/* ptr to ")" */
13270#define endexpression &op_tokens[sizeof(op_tokens)-7]
13271
13272
13273extern long arith (const char *expr, int *perrcode)
13274{
13275 register char arithval; /* Current character under analysis */
13276 operator lasttok, op;
13277 operator prec;
13278
13279 const char *p = endexpression;
13280 int errcode;
13281
13282 size_t datasizes = strlen(expr) + 2;
13283
13284 /* Stack of integers */
13285 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13286 * in any given correct or incorrect expression is left as an excersize to
13287 * the reader. */
13288 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13289 *numstackptr = numstack;
13290 /* Stack of operator tokens */
13291 operator *stack = alloca((datasizes) * sizeof(operator)),
13292 *stackptr = stack;
13293
13294 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13295 *perrcode = errcode = 0;
13296
13297 while(1) {
13298 if ((arithval = *expr) == 0) {
13299 if (p == endexpression) {
13300 /* Null expression. */
13301 return 0;
13302 }
13303
13304 /* This is only reached after all tokens have been extracted from the
13305 * input stream. If there are still tokens on the operator stack, they
13306 * are to be applied in order. At the end, there should be a final
13307 * result on the integer stack */
13308
13309 if (expr != endexpression + 1) {
13310 /* If we haven't done so already, */
13311 /* append a closing right paren */
13312 expr = endexpression;
13313 /* and let the loop process it. */
13314 continue;
13315 }
13316 /* At this point, we're done with the expression. */
13317 if (numstackptr != numstack+1) {
13318 /* ... but if there isn't, it's bad */
13319 err:
13320 return (*perrcode = -1);
13321 }
13322 if(numstack->var) {
13323 /* expression is $((var)) only, lookup now */
13324 errcode = arith_lookup_val(numstack);
13325 }
13326 ret:
13327 *perrcode = errcode;
13328 return numstack->val;
13329 } else {
13330 /* Continue processing the expression. */
13331 if (arith_isspace(arithval)) {
13332 /* Skip whitespace */
13333 goto prologue;
13334 }
13335 if((p = endofname(expr)) != expr) {
13336 int var_name_size = (p-expr) + 1; /* trailing zero */
13337
13338 numstackptr->var = alloca(var_name_size);
13339 safe_strncpy(numstackptr->var, expr, var_name_size);
13340 expr = p;
13341 num:
13342 numstackptr->contidional_second_val_initialized = 0;
13343 numstackptr++;
13344 lasttok = TOK_NUM;
13345 continue;
13346 } else if (is_digit(arithval)) {
13347 numstackptr->var = NULL;
13348 numstackptr->val = strtol(expr, (char **) &expr, 0);
13349 goto num;
13350 }
13351 for(p = op_tokens; ; p++) {
13352 const char *o;
13353
13354 if(*p == 0) {
13355 /* strange operator not found */
13356 goto err;
13357 }
13358 for(o = expr; *p && *o == *p; p++)
13359 o++;
13360 if(! *p) {
13361 /* found */
13362 expr = o - 1;
13363 break;
13364 }
13365 /* skip tail uncompared token */
13366 while(*p)
13367 p++;
13368 /* skip zero delim */
13369 p++;
13370 }
13371 op = p[1];
13372
13373 /* post grammar: a++ reduce to num */
13374 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13375 lasttok = TOK_NUM;
13376
13377 /* Plus and minus are binary (not unary) _only_ if the last
13378 * token was as number, or a right paren (which pretends to be
13379 * a number, since it evaluates to one). Think about it.
13380 * It makes sense. */
13381 if (lasttok != TOK_NUM) {
13382 switch(op) {
13383 case TOK_ADD:
13384 op = TOK_UPLUS;
13385 break;
13386 case TOK_SUB:
13387 op = TOK_UMINUS;
13388 break;
13389 case TOK_POST_INC:
13390 op = TOK_PRE_INC;
13391 break;
13392 case TOK_POST_DEC:
13393 op = TOK_PRE_DEC;
13394 break;
13395 }
13396 }
13397 /* We don't want a unary operator to cause recursive descent on the
13398 * stack, because there can be many in a row and it could cause an
13399 * operator to be evaluated before its argument is pushed onto the
13400 * integer stack. */
13401 /* But for binary operators, "apply" everything on the operator
13402 * stack until we find an operator with a lesser priority than the
13403 * one we have just extracted. */
13404 /* Left paren is given the lowest priority so it will never be
13405 * "applied" in this way.
13406 * if associativity is right and priority eq, applied also skip
13407 */
13408 prec = PREC(op);
13409 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13410 /* not left paren or unary */
13411 if (lasttok != TOK_NUM) {
13412 /* binary op must be preceded by a num */
13413 goto err;
13414 }
13415 while (stackptr != stack) {
13416 if (op == TOK_RPAREN) {
13417 /* The algorithm employed here is simple: while we don't
13418 * hit an open paren nor the bottom of the stack, pop
13419 * tokens and apply them */
13420 if (stackptr[-1] == TOK_LPAREN) {
13421 --stackptr;
13422 /* Any operator directly after a */
13423 lasttok = TOK_NUM;
13424 /* close paren should consider itself binary */
13425 goto prologue;
13426 }
13427 } else {
13428 operator prev_prec = PREC(stackptr[-1]);
13429
13430 convert_prec_is_assing(prec);
13431 convert_prec_is_assing(prev_prec);
13432 if (prev_prec < prec)
13433 break;
13434 /* check right assoc */
13435 if(prev_prec == prec && is_right_associativity(prec))
13436 break;
13437 }
13438 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13439 if(errcode) goto ret;
13440 }
13441 if (op == TOK_RPAREN) {
13442 goto err;
13443 }
13444 }
13445
13446 /* Push this operator to the stack and remember it. */
13447 *stackptr++ = lasttok = op;
13448
13449 prologue:
13450 ++expr;
13451 }
13452 }
13453}
13454#endif /* CONFIG_ASH_MATH_SUPPORT */
13455
13456
12700#ifdef DEBUG 13457#ifdef DEBUG
12701const char *bb_applet_name = "debug stuff usage"; 13458const char *bb_applet_name = "debug stuff usage";
12702int main(int argc, char **argv) 13459int main(int argc, char **argv)