Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/coreutils/expr.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/coreutils/expr.c
r821 r1770 12 12 * - 64 math support 13 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 2 of the License, or 17 * (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 * General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, write to the Free Software 26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 27 * 14 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 28 15 */ 29 16 … … 39 26 /* no getopt needed */ 40 27 41 #include <stdio.h> 42 #include <string.h> 43 #include <stdlib.h> 44 #include <regex.h> 45 #include <sys/types.h> 46 #include <errno.h> 47 #include "busybox.h" 48 28 #include "libbb.h" 29 #include "xregex.h" 49 30 50 31 /* The kinds of value we can have. */ … … 57 38 #if ENABLE_EXPR_MATH_SUPPORT_64 58 39 typedef int64_t arith_t; 40 59 41 #define PF_REZ "ll" 60 42 #define PF_REZ_TYPE (long long) … … 62 44 #else 63 45 typedef long arith_t; 46 64 47 #define PF_REZ "l" 65 48 #define PF_REZ_TYPE (long) … … 67 50 #endif 68 51 52 /* TODO: use bb_strtol[l]? It's easier to check for errors... */ 53 69 54 /* A value is.... */ 70 55 struct valinfo { 71 TYPE type; 72 union { 56 TYPE type; /* Which kind. */ 57 union { /* The value itself. */ 73 58 arith_t i; 74 59 char *s; … … 78 63 79 64 /* The arguments given to the program, minus the program name. */ 80 static char **args; 81 82 static VALUE *docolon (VALUE *sv, VALUE *pv); 83 static VALUE *eval (void); 84 static VALUE *int_value (arith_t i); 85 static VALUE *str_value (char *s); 86 static int nextarg (char *str); 87 static int null (VALUE *v); 88 static int toarith (VALUE *v); 89 static void freev (VALUE *v); 90 static void tostring (VALUE *v); 91 92 int expr_main (int argc, char **argv) 65 struct globals { 66 char **args; 67 }; 68 #define G (*(struct globals*)&bb_common_bufsiz1) 69 70 /* forward declarations */ 71 static VALUE *eval(void); 72 73 74 /* Return a VALUE for I. */ 75 76 static VALUE *int_value(arith_t i) 93 77 { 94 78 VALUE *v; 95 79 96 if (argc == 1) { 97 bb_error_msg_and_die("too few arguments"); 98 } 99 100 args = argv + 1; 101 102 v = eval (); 103 if (*args) 104 bb_error_msg_and_die ("syntax error"); 105 106 if (v->type == integer) 107 printf ("%" PF_REZ "d\n", PF_REZ_TYPE v->u.i); 108 else 109 puts (v->u.s); 110 111 exit (null (v)); 112 } 113 114 /* Return a VALUE for I. */ 115 116 static VALUE *int_value (arith_t i) 117 { 118 VALUE *v; 119 120 v = xmalloc (sizeof(VALUE)); 80 v = xmalloc(sizeof(VALUE)); 121 81 v->type = integer; 122 82 v->u.i = i; … … 126 86 /* Return a VALUE for S. */ 127 87 128 static VALUE *str_value (char *s)88 static VALUE *str_value(const char *s) 129 89 { 130 90 VALUE *v; 131 91 132 v = xmalloc 92 v = xmalloc(sizeof(VALUE)); 133 93 v->type = string; 134 v->u.s = bb_xstrdup(s);94 v->u.s = xstrdup(s); 135 95 return v; 136 96 } … … 138 98 /* Free VALUE V, including structure components. */ 139 99 140 static void freev (VALUE *v)100 static void freev(VALUE * v) 141 101 { 142 102 if (v->type == string) 143 free 144 free 103 free(v->u.s); 104 free(v); 145 105 } 146 106 147 107 /* Return nonzero if V is a null-string or zero-number. */ 148 108 149 static int null (VALUE *v) 150 { 151 switch (v->type) { 152 case integer: 153 return v->u.i == 0; 154 default: /* string: */ 155 return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0; 156 } 109 static int null(VALUE * v) 110 { 111 if (v->type == integer) 112 return v->u.i == 0; 113 /* string: */ 114 return v->u.s[0] == '\0' || LONE_CHAR(v->u.s, '0'); 157 115 } 158 116 159 117 /* Coerce V to a string value (can't fail). */ 160 118 161 static void tostring (VALUE *v)119 static void tostring(VALUE * v) 162 120 { 163 121 if (v->type == integer) { 164 v->u.s = bb_xasprintf("%" PF_REZ "d", PF_REZ_TYPE v->u.i);122 v->u.s = xasprintf("%" PF_REZ "d", PF_REZ_TYPE v->u.i); 165 123 v->type = string; 166 124 } … … 169 127 /* Coerce V to an integer value. Return 1 on success, 0 on failure. */ 170 128 171 static int toarith (VALUE *v)172 { 173 if (v->type == string) {129 static bool toarith(VALUE * v) 130 { 131 if (v->type == string) { 174 132 arith_t i; 175 133 char *e; … … 180 138 if ((v->u.s == e) || *e) 181 139 return 0; 182 free 140 free(v->u.s); 183 141 v->u.i = i; 184 142 v->type = integer; … … 190 148 STR must not be NULL. */ 191 149 192 static int 193 nextarg (char *str) 194 { 195 if (*args == NULL) 150 static bool nextarg(const char *str) 151 { 152 if (*G.args == NULL) 196 153 return 0; 197 return strcmp (*args, str) == 0;154 return strcmp(*G.args, str) == 0; 198 155 } 199 156 200 157 /* The comparison operator handling functions. */ 201 158 202 static int cmp_common (VALUE *l, VALUE *r, int op)159 static int cmp_common(VALUE * l, VALUE * r, int op) 203 160 { 204 161 int cmpval; 205 162 206 163 if (l->type == string || r->type == string) { 207 tostring (l); 208 tostring (r); 209 cmpval = strcmp (l->u.s, r->u.s); 210 } 164 tostring(l); 165 tostring(r); 166 cmpval = strcmp(l->u.s, r->u.s); 167 } else 168 cmpval = l->u.i - r->u.i; 169 if (op == '<') 170 return cmpval < 0; 171 if (op == ('L' + 'E')) 172 return cmpval <= 0; 173 if (op == '=') 174 return cmpval == 0; 175 if (op == '!') 176 return cmpval != 0; 177 if (op == '>') 178 return cmpval > 0; 179 /* >= */ 180 return cmpval >= 0; 181 } 182 183 /* The arithmetic operator handling functions. */ 184 185 static arith_t arithmetic_common(VALUE * l, VALUE * r, int op) 186 { 187 arith_t li, ri; 188 189 if (!toarith(l) || !toarith(r)) 190 bb_error_msg_and_die("non-numeric argument"); 191 li = l->u.i; 192 ri = r->u.i; 193 if ((op == '/' || op == '%') && ri == 0) 194 bb_error_msg_and_die("division by zero"); 195 if (op == '+') 196 return li + ri; 197 else if (op == '-') 198 return li - ri; 199 else if (op == '*') 200 return li * ri; 201 else if (op == '/') 202 return li / ri; 211 203 else 212 cmpval = l->u.i - r->u.i;213 switch(op) {214 case '<':215 return cmpval < 0;216 case ('L'+'E'):217 return cmpval <= 0;218 case '=':219 return cmpval == 0;220 case '!':221 return cmpval != 0;222 case '>':223 return cmpval > 0;224 default: /* >= */225 return cmpval >= 0;226 }227 }228 229 /* The arithmetic operator handling functions. */230 231 static arith_t arithmetic_common (VALUE *l, VALUE *r, int op)232 {233 arith_t li, ri;234 235 if (!toarith (l) || !toarith (r))236 bb_error_msg_and_die ("non-numeric argument");237 li = l->u.i;238 ri = r->u.i;239 if((op == '/' || op == '%') && ri == 0)240 bb_error_msg_and_die ( "division by zero");241 switch(op) {242 case '+':243 return li + ri;244 case '-':245 return li - ri;246 case '*':247 return li * ri;248 case '/':249 return li / ri;250 default:251 204 return li % ri; 252 }253 205 } 254 206 … … 257 209 PV is the VALUE for the rhs (the pattern). */ 258 210 259 static VALUE *docolon (VALUE *sv, VALUE *pv)211 static VALUE *docolon(VALUE * sv, VALUE * pv) 260 212 { 261 213 VALUE *v; … … 264 216 regmatch_t re_regs[NMATCH]; 265 217 266 tostring 267 tostring 218 tostring(sv); 219 tostring(pv); 268 220 269 221 if (pv->u.s[0] == '^') { 270 fprintf (stderr,"\222 bb_error_msg("\ 271 223 warning: unportable BRE: `%s': using `^' as the first character\n\ 272 of a basic regular expression is not portable; it is being ignored", 273 pv->u.s); 274 } 275 276 memset (&re_buffer, 0, sizeof (re_buffer)); 277 memset (re_regs, 0, sizeof (*re_regs)); 278 if( regcomp (&re_buffer, pv->u.s, 0) != 0 ) 279 bb_error_msg_and_die("Invalid regular expression"); 224 of a basic regular expression is not portable; it is being ignored", pv->u.s); 225 } 226 227 memset(&re_buffer, 0, sizeof(re_buffer)); 228 memset(re_regs, 0, sizeof(*re_regs)); 229 xregcomp(&re_buffer, pv->u.s, 0); 280 230 281 231 /* expr uses an anchored pattern match, so check that there was a 282 232 * match and that the match starts at offset 0. */ 283 if (regexec 284 233 if (regexec(&re_buffer, sv->u.s, NMATCH, re_regs, 0) != REG_NOMATCH && 234 re_regs[0].rm_so == 0) { 285 235 /* Were \(...\) used? */ 286 236 if (re_buffer.re_nsub > 0) { 287 237 sv->u.s[re_regs[1].rm_eo] = '\0'; 288 v = str_value (sv->u.s + re_regs[1].rm_so); 289 } 290 else 291 v = int_value (re_regs[0].rm_eo); 292 } 293 else { 238 v = str_value(sv->u.s + re_regs[1].rm_so); 239 } else 240 v = int_value(re_regs[0].rm_eo); 241 } else { 294 242 /* Match failed -- return the right kind of null. */ 295 243 if (re_buffer.re_nsub > 0) 296 v = str_value 244 v = str_value(""); 297 245 else 298 v = int_value (0); 299 } 246 v = int_value(0); 247 } 248 //FIXME: sounds like here is a bit missing: regfree(&re_buffer); 300 249 return v; 301 250 } … … 303 252 /* Handle bare operands and ( expr ) syntax. */ 304 253 305 static VALUE *eval7 254 static VALUE *eval7(void) 306 255 { 307 256 VALUE *v; 308 257 309 if (!*args) 310 bb_error_msg_and_die ( "syntax error"); 311 312 if (nextarg ("(")) { 313 args++; 314 v = eval (); 315 if (!nextarg (")")) 316 bb_error_msg_and_die ( "syntax error"); 317 args++; 318 return v; 258 if (!*G.args) 259 bb_error_msg_and_die("syntax error"); 260 261 if (nextarg("(")) { 262 G.args++; 263 v = eval(); 264 if (!nextarg(")")) 265 bb_error_msg_and_die("syntax error"); 266 G.args++; 267 return v; 268 } 269 270 if (nextarg(")")) 271 bb_error_msg_and_die("syntax error"); 272 273 return str_value(*G.args++); 274 } 275 276 /* Handle match, substr, index, length, and quote keywords. */ 277 278 static VALUE *eval6(void) 279 { 280 static const char keywords[] ALIGN1 = 281 "quote\0""length\0""match\0""index\0""substr\0"; 282 283 VALUE *r, *i1, *i2; 284 VALUE *l = l; /* silence gcc */ 285 VALUE *v = v; /* silence gcc */ 286 int key = *G.args ? index_in_strings(keywords, *G.args) + 1 : 0; 287 288 if (key == 0) /* not a keyword */ 289 return eval7(); 290 G.args++; /* We have a valid token, so get the next argument. */ 291 if (key == 1) { /* quote */ 292 if (!*G.args) 293 bb_error_msg_and_die("syntax error"); 294 return str_value(*G.args++); 295 } 296 if (key == 2) { /* length */ 297 r = eval6(); 298 tostring(r); 299 v = int_value(strlen(r->u.s)); 300 freev(r); 301 } else 302 l = eval6(); 303 304 if (key == 3) { /* match */ 305 r = eval6(); 306 v = docolon(l, r); 307 freev(l); 308 freev(r); 309 } 310 if (key == 4) { /* index */ 311 r = eval6(); 312 tostring(l); 313 tostring(r); 314 v = int_value(strcspn(l->u.s, r->u.s) + 1); 315 if (v->u.i == (arith_t) strlen(l->u.s) + 1) 316 v->u.i = 0; 317 freev(l); 318 freev(r); 319 } 320 if (key == 5) { /* substr */ 321 i1 = eval6(); 322 i2 = eval6(); 323 tostring(l); 324 if (!toarith(i1) || !toarith(i2) 325 || i1->u.i > (arith_t) strlen(l->u.s) 326 || i1->u.i <= 0 || i2->u.i <= 0) 327 v = str_value(""); 328 else { 329 v = xmalloc(sizeof(VALUE)); 330 v->type = string; 331 v->u.s = xstrndup(l->u.s + i1->u.i - 1, i2->u.i); 319 332 } 320 321 if (nextarg (")")) 322 bb_error_msg_and_die ( "syntax error"); 323 324 return str_value (*args++); 325 } 326 327 /* Handle match, substr, index, length, and quote keywords. */ 328 329 static VALUE *eval6 (void) 330 { 331 VALUE *l, *r, *v, *i1, *i2; 332 333 if (nextarg ("quote")) { 334 args++; 335 if (!*args) 336 bb_error_msg_and_die ( "syntax error"); 337 return str_value (*args++); 338 } 339 else if (nextarg ("length")) { 340 args++; 341 r = eval6 (); 342 tostring (r); 343 v = int_value (strlen (r->u.s)); 344 freev (r); 345 return v; 346 } 347 else if (nextarg ("match")) { 348 args++; 349 l = eval6 (); 350 r = eval6 (); 351 v = docolon (l, r); 352 freev (l); 353 freev (r); 354 return v; 355 } 356 else if (nextarg ("index")) { 357 args++; 358 l = eval6 (); 359 r = eval6 (); 360 tostring (l); 361 tostring (r); 362 v = int_value (strcspn (l->u.s, r->u.s) + 1); 363 if (v->u.i == (arith_t) strlen (l->u.s) + 1) 364 v->u.i = 0; 365 freev (l); 366 freev (r); 367 return v; 368 } 369 else if (nextarg ("substr")) { 370 args++; 371 l = eval6 (); 372 i1 = eval6 (); 373 i2 = eval6 (); 374 tostring (l); 375 if (!toarith (i1) || !toarith (i2) 376 || i1->u.i > (arith_t) strlen (l->u.s) 377 || i1->u.i <= 0 || i2->u.i <= 0) 378 v = str_value (""); 379 else { 380 v = xmalloc (sizeof(VALUE)); 381 v->type = string; 382 v->u.s = bb_xstrndup(l->u.s + i1->u.i - 1, i2->u.i); 383 } 384 freev (l); 385 freev (i1); 386 freev (i2); 387 return v; 388 } 389 else 390 return eval7 (); 333 freev(l); 334 freev(i1); 335 freev(i2); 336 } 337 return v; 338 391 339 } 392 340 … … 394 342 Calls docolon to do the real work. */ 395 343 396 static VALUE *eval5 344 static VALUE *eval5(void) 397 345 { 398 346 VALUE *l, *r, *v; 399 347 400 l = eval6 401 while (nextarg 402 args++;403 r = eval6 404 v = docolon 405 freev 406 freev 348 l = eval6(); 349 while (nextarg(":")) { 350 G.args++; 351 r = eval6(); 352 v = docolon(l, r); 353 freev(l); 354 freev(r); 407 355 l = v; 408 356 } … … 412 360 /* Handle *, /, % operators. */ 413 361 414 static VALUE *eval4 362 static VALUE *eval4(void) 415 363 { 416 364 VALUE *l, *r; … … 418 366 arith_t val; 419 367 420 l = eval5 368 l = eval5(); 421 369 while (1) { 422 if (nextarg 370 if (nextarg("*")) 423 371 op = '*'; 424 else if (nextarg 372 else if (nextarg("/")) 425 373 op = '/'; 426 else if (nextarg 374 else if (nextarg("%")) 427 375 op = '%'; 428 376 else 429 377 return l; 430 args++;431 r = eval5 432 val = arithmetic_common 433 freev 434 freev 435 l = int_value 378 G.args++; 379 r = eval5(); 380 val = arithmetic_common(l, r, op); 381 freev(l); 382 freev(r); 383 l = int_value(val); 436 384 } 437 385 } … … 439 387 /* Handle +, - operators. */ 440 388 441 static VALUE *eval3 389 static VALUE *eval3(void) 442 390 { 443 391 VALUE *l, *r; … … 445 393 arith_t val; 446 394 447 l = eval4 395 l = eval4(); 448 396 while (1) { 449 if (nextarg 397 if (nextarg("+")) 450 398 op = '+'; 451 else if (nextarg 399 else if (nextarg("-")) 452 400 op = '-'; 453 401 else 454 402 return l; 455 args++;456 r = eval4 457 val = arithmetic_common 458 freev 459 freev 460 l = int_value 403 G.args++; 404 r = eval4(); 405 val = arithmetic_common(l, r, op); 406 freev(l); 407 freev(r); 408 l = int_value(val); 461 409 } 462 410 } … … 464 412 /* Handle comparisons. */ 465 413 466 static VALUE *eval2 414 static VALUE *eval2(void) 467 415 { 468 416 VALUE *l, *r; … … 470 418 arith_t val; 471 419 472 l = eval3 420 l = eval3(); 473 421 while (1) { 474 if (nextarg 422 if (nextarg("<")) 475 423 op = '<'; 476 else if (nextarg 477 op = 'L' +'E';478 else if (nextarg ("=") || nextarg("=="))424 else if (nextarg("<=")) 425 op = 'L' + 'E'; 426 else if (nextarg("=") || nextarg("==")) 479 427 op = '='; 480 else if (nextarg 428 else if (nextarg("!=")) 481 429 op = '!'; 482 else if (nextarg 483 op = 'G' +'E';484 else if (nextarg 430 else if (nextarg(">=")) 431 op = 'G' + 'E'; 432 else if (nextarg(">")) 485 433 op = '>'; 486 434 else 487 435 return l; 488 args++;489 r = eval3 490 toarith 491 toarith 492 val = cmp_common 493 freev 494 freev 495 l = int_value 436 G.args++; 437 r = eval3(); 438 toarith(l); 439 toarith(r); 440 val = cmp_common(l, r, op); 441 freev(l); 442 freev(r); 443 l = int_value(val); 496 444 } 497 445 } … … 499 447 /* Handle &. */ 500 448 501 static VALUE *eval1 449 static VALUE *eval1(void) 502 450 { 503 451 VALUE *l, *r; 504 452 505 l = eval2 (); 506 while (nextarg ("&")) { 507 args++; 508 r = eval2 (); 509 if (null (l) || null (r)) { 510 freev (l); 511 freev (r); 512 l = int_value (0); 513 } 514 else 515 freev (r); 453 l = eval2(); 454 while (nextarg("&")) { 455 G.args++; 456 r = eval2(); 457 if (null(l) || null(r)) { 458 freev(l); 459 freev(r); 460 l = int_value(0); 461 } else 462 freev(r); 516 463 } 517 464 return l; … … 520 467 /* Handle |. */ 521 468 522 static VALUE *eval 469 static VALUE *eval(void) 523 470 { 524 471 VALUE *l, *r; 525 472 526 l = eval1 527 while (nextarg 528 args++;529 r = eval1 530 if (null 531 freev 473 l = eval1(); 474 while (nextarg("|")) { 475 G.args++; 476 r = eval1(); 477 if (null(l)) { 478 freev(l); 532 479 l = r; 533 } 534 else 535 freev (r); 480 } else 481 freev(r); 536 482 } 537 483 return l; 538 484 } 485 486 int expr_main(int argc, char **argv); 487 int expr_main(int argc, char **argv) 488 { 489 VALUE *v; 490 491 if (argc == 1) { 492 bb_error_msg_and_die("too few arguments"); 493 } 494 495 G.args = argv + 1; 496 497 v = eval(); 498 if (*G.args) 499 bb_error_msg_and_die("syntax error"); 500 501 if (v->type == integer) 502 printf("%" PF_REZ "d\n", PF_REZ_TYPE v->u.i); 503 else 504 puts(v->u.s); 505 506 fflush_stdout_and_exit(null(v)); 507 }
Note:
See TracChangeset
for help on using the changeset viewer.