diff options
| author | andersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2003-08-06 11:20:52 +0000 |
|---|---|---|
| committer | andersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2003-08-06 11:20:52 +0000 |
| commit | 8a1d6b28d2773e9ce4cb650fc2ad7b85dd7af9ac (patch) | |
| tree | dd507d9dfc45625d953748ffc7c361bd1f025ca6 | |
| parent | 11789a1691b9deb8eff4ceefb986d0ae0f6559d4 (diff) | |
| download | busybox-w32-8a1d6b28d2773e9ce4cb650fc2ad7b85dd7af9ac.tar.gz busybox-w32-8a1d6b28d2773e9ce4cb650fc2ad7b85dd7af9ac.tar.bz2 busybox-w32-8a1d6b28d2773e9ce4cb650fc2ad7b85dd7af9ac.zip | |
Latest dash update from vodz
git-svn-id: svn://busybox.net/trunk/busybox@7177 69ca8d6d-28ef-0310-b511-8ec308f3f277
| -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) |
