diff options
author | Eric Andersen <andersen@codepoet.org> | 2003-08-06 11:20:52 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2003-08-06 11:20:52 +0000 |
commit | 9089844382a87290143ec414cfea703bcc31e9d8 (patch) | |
tree | dd507d9dfc45625d953748ffc7c361bd1f025ca6 | |
parent | dc19af4179161bdc80ea4d382a116e916a43ac9d (diff) | |
download | busybox-w32-9089844382a87290143ec414cfea703bcc31e9d8.tar.gz busybox-w32-9089844382a87290143ec414cfea703bcc31e9d8.tar.bz2 busybox-w32-9089844382a87290143ec414cfea703bcc31e9d8.zip |
Latest dash update from vodz
-rw-r--r-- | libbb/Makefile.in | 2 | ||||
-rw-r--r-- | libbb/arith.c | 375 | ||||
-rw-r--r-- | shell/ash.c | 1061 |
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/ | |||
24 | endif | 24 | endif |
25 | 25 | ||
26 | LIBBB_SRC:= \ | 26 | LIBBB_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 | |||
101 | typedef 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 */ | ||
160 | static 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; | ||
220 | err: return(-1); | ||
221 | } | ||
222 | |||
223 | static const char endexpression[] = ")"; | ||
224 | |||
225 | /* + and - (in that order) must be last */ | ||
226 | static const char op_char[] = "!<>=|&*/%~()+-"; | ||
227 | static 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 | |||
241 | extern 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 */ | |||
544 | static int parselleft; /* copy of parsefile->lleft */ | 549 | static int parselleft; /* copy of parsefile->lleft */ |
545 | 550 | ||
546 | /* next character in input buffer */ | 551 | /* next character in input buffer */ |
547 | static char *parsenextc; /* copy of parsefile->nextc */ | 552 | static char *parsenextc; /* copy of parsefile->nextc */ |
548 | static struct parsefile basepf; /* top level input file */ | 553 | static struct parsefile basepf; /* top level input file */ |
549 | static char basebuf[IBUFSIZ]; /* buffer for top level input file */ | 554 | static char basebuf[IBUFSIZ]; /* buffer for top level input file */ |
550 | static struct parsefile *parsefile = &basepf; /* current input file */ | 555 | static 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 **); | |||
1223 | static int evalcmd(int, char **); | 1224 | static int evalcmd(int, char **); |
1224 | static int execcmd(int, char **); | 1225 | static int execcmd(int, char **); |
1225 | static int exitcmd(int, char **); | 1226 | static int exitcmd(int, char **); |
1226 | #ifdef CONFIG_ASH_MATH_SUPPORT | ||
1227 | static int expcmd(int, char **); | ||
1228 | #endif | ||
1229 | static int exportcmd(int, char **); | 1227 | static int exportcmd(int, char **); |
1230 | static int falsecmd(int, char **); | 1228 | static 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 |
1242 | static int jobscmd(int, char **); | 1240 | static int jobscmd(int, char **); |
1243 | #endif | 1241 | #endif |
1242 | #ifdef CONFIG_ASH_MATH_SUPPORT | ||
1243 | static int letcmd(int, char **); | ||
1244 | #endif | ||
1244 | static int localcmd(int, char **); | 1245 | static int localcmd(int, char **); |
1245 | static int pwdcmd(int, char **); | 1246 | static int pwdcmd(int, char **); |
1246 | static int readcmd(int, char **); | 1247 | static 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 *); | |||
1421 | static void unsetfunc(const char *); | 1419 | static void unsetfunc(const char *); |
1422 | 1420 | ||
1423 | #ifdef CONFIG_ASH_MATH_SUPPORT | 1421 | #ifdef CONFIG_ASH_MATH_SUPPORT |
1424 | /* From arith.y */ | ||
1425 | static int dash_arith(const char *); | 1422 | static 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 | ||
1485 | static const char defpathvar[] = | 1482 | static 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 |
1488 | static const char defifsvar[] = "IFS= \t\n"; | 1484 | static const char defifsvar[] = "IFS= \t\n"; |
1489 | #define defifs (defifsvar + 4) | 1485 | #define defifs (defifsvar + 4) |
@@ -4522,8 +4518,6 @@ static void removerecordregions(int); | |||
4522 | static void ifsbreakup(char *, struct arglist *); | 4518 | static void ifsbreakup(char *, struct arglist *); |
4523 | static void ifsfree(void); | 4519 | static void ifsfree(void); |
4524 | static void expandmeta(struct strlist *, int); | 4520 | static void expandmeta(struct strlist *, int); |
4525 | static void addglob(const glob_t *); | ||
4526 | static void addfname(char *); | ||
4527 | static int patmatch(char *, const char *); | 4521 | static int patmatch(char *, const char *); |
4528 | 4522 | ||
4529 | static int cvtnum(long); | 4523 | static 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 | ||
4989 | static char * | 4982 | static char * |
4990 | scanleft( | 4983 | scanleft(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 | ||
5021 | static char * | 5013 | static char * |
5022 | scanright( | 5014 | scanright(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 | ||
5563 | static void expmeta(char *, char *); | ||
5564 | static struct strlist *expsort(struct strlist *); | ||
5565 | static struct strlist *msort(struct strlist *, int); | ||
5576 | 5566 | ||
5567 | static 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 | ||
5583 | static void | 5570 | static void |
5584 | expandmeta(str, flag) | 5571 | expandmeta(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: | ||
5611 | nometa2: | ||
5612 | globfree(&pglob); | ||
5613 | INTON; | ||
5614 | nometa: | 5605 | nometa: |
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 | ||
5631 | static void | 5624 | static void |
5632 | addglob(pglob) | 5625 | addfname(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 | ||
5647 | static void | 5640 | static void |
5648 | addfname(char *name) | 5641 | expmeta(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 | } | ||
5681 | out: | ||
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 | |||
5755 | static struct strlist * | ||
5756 | expsort(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 | |||
5768 | static struct strlist * | ||
5769 | msort(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 | ||
6384 | static int | 6536 | static int |
6385 | killcmd(argc, argv) | 6537 | killcmd(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 | ||
6627 | start: | 6777 | start: |
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 | |||
7267 | int | 7414 | int |
7268 | stoppedjobs(void) | 7415 | stoppedjobs(void) |
7269 | { | 7416 | { |
@@ -7468,7 +7615,6 @@ cmdlist(union node *np, int sep) | |||
7468 | } | 7615 | } |
7469 | } | 7616 | } |
7470 | 7617 | ||
7471 | |||
7472 | static void | 7618 | static void |
7473 | cmdputs(const char *s) | 7619 | cmdputs(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) { |
7817 | state4: /* 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 |
7971 | state4: /* 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 | ||
8025 | static pointer | 8169 | static pointer |
8026 | ckmalloc(size_t nbytes) | 8170 | ckrealloc(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 | |||
8041 | static pointer | 8178 | static pointer |
8042 | ckrealloc(pointer p, size_t nbytes) | 8179 | ckmalloc(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 | |||
8124 | void | 8256 | void |
8125 | setstackmark(struct stackmark *mark) | 8257 | setstackmark(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 | |||
8483 | static void | 8613 | static void |
8484 | sizenodelist(struct nodelist *lp) | 8614 | sizenodelist(struct nodelist *lp) |
8485 | { | 8615 | { |
@@ -8491,7 +8621,6 @@ sizenodelist(struct nodelist *lp) | |||
8491 | } | 8621 | } |
8492 | 8622 | ||
8493 | 8623 | ||
8494 | |||
8495 | static union node * | 8624 | static union node * |
8496 | copynode(union node *n) | 8625 | copynode(union node *n) |
8497 | { | 8626 | { |
@@ -8601,7 +8730,6 @@ copynodelist(struct nodelist *lp) | |||
8601 | } | 8730 | } |
8602 | 8731 | ||
8603 | 8732 | ||
8604 | |||
8605 | static char * | 8733 | static char * |
8606 | nodesavestr(char *s) | 8734 | nodesavestr(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 | |||
8779 | static void | 8905 | static void |
8780 | setoption(int flag, int val) | 8906 | setoption(int flag, int val) |
8781 | { | 8907 | { |
@@ -10669,7 +10795,7 @@ noexpand(char *text) | |||
10669 | 10795 | ||
10670 | char * | 10796 | char * |
10671 | endofname(const char *name) | 10797 | endofname(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) | |||
10735 | static const char *const *findkwd(const char *s) | 10861 | static 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) { | |||
12320 | static int | 12445 | static int |
12321 | dash_arith(const char *s) | 12446 | dash_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 | |||
12343 | static int | 12476 | static int |
12344 | expcmd(int argc, char **argv) | 12477 | letcmd(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 | |||
12916 | typedef 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 | |||
13007 | static 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 | |||
13016 | static 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 | |||
13023 | typedef 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 | |||
13032 | typedef struct CHK_VAR_RECURSIVE_LOOPED { | ||
13033 | const char *var; | ||
13034 | struct CHK_VAR_RECURSIVE_LOOPED *next; | ||
13035 | } chk_var_recursive_looped_t; | ||
13036 | |||
13037 | static chk_var_recursive_looped_t *prev_chk_var_recursive; | ||
13038 | |||
13039 | |||
13040 | static 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 */ | ||
13079 | static inline int | ||
13080 | arith_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; | ||
13222 | err: return(-1); | ||
13223 | } | ||
13224 | |||
13225 | /* longest must first */ | ||
13226 | static 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 | |||
13273 | extern 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 |
12701 | const char *bb_applet_name = "debug stuff usage"; | 13458 | const char *bb_applet_name = "debug stuff usage"; |
12702 | int main(int argc, char **argv) | 13459 | int main(int argc, char **argv) |