1 /**************************************************************** 2 Copyright (C) Lucent Technologies 1997 3 All Rights Reserved 4 5 Permission to use, copy, modify, and distribute this software and 6 its documentation for any purpose and without fee is hereby 7 granted, provided that the above copyright notice appear in all 8 copies and that both that the copyright notice and this 9 permission notice and warranty disclaimer appear in supporting 10 documentation, and that the name Lucent Technologies or any of 11 its entities not be used in advertising or publicity pertaining 12 to distribution of the software without specific, written prior 13 permission. 14 15 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 17 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 18 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 20 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 22 THIS SOFTWARE. 23 ****************************************************************/ 24 25 #define DEBUG 26 #include <stdio.h> 27 #include <ctype.h> 28 #include <setjmp.h> 29 #include <math.h> 30 #include <string.h> 31 #include <stdlib.h> 32 #include <time.h> 33 #include "awk.h" 34 #include "y.tab.h" 35 36 #define tempfree(x) if (istemp(x)) tfree(x); else 37 38 /* 39 #undef tempfree 40 41 void tempfree(Cell *p) { 42 if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) { 43 WARNING("bad csub %d in Cell %d %s", 44 p->csub, p->ctype, p->sval); 45 } 46 if (istemp(p)) 47 tfree(p); 48 } 49 */ 50 51 #ifdef _NFILE 52 #ifndef FOPEN_MAX 53 #define FOPEN_MAX _NFILE 54 #endif 55 #endif 56 57 #ifndef FOPEN_MAX 58 #define FOPEN_MAX 40 /* max number of open files */ 59 #endif 60 61 #ifndef RAND_MAX 62 #define RAND_MAX 32767 /* all that ansi guarantees */ 63 #endif 64 65 jmp_buf env; 66 extern int pairstack[]; 67 68 Node *winner = NULL; /* root of parse tree */ 69 Cell *tmps; /* free temporary cells for execution */ 70 71 static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM }; 72 Cell *True = &truecell; 73 static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM }; 74 Cell *False = &falsecell; 75 static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM }; 76 Cell *jbreak = &breakcell; 77 static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM }; 78 Cell *jcont = &contcell; 79 static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM }; 80 Cell *jnext = &nextcell; 81 static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM }; 82 Cell *jnextfile = &nextfilecell; 83 static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM }; 84 Cell *jexit = &exitcell; 85 static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM }; 86 Cell *jret = &retcell; 87 static Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE }; 88 89 Node *curnode = NULL; /* the node being executed, for debugging */ 90 91 /* buffer memory management */ 92 int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr, 93 char *whatrtn) 94 /* pbuf: address of pointer to buffer being managed 95 * psiz: address of buffer size variable 96 * minlen: minimum length of buffer needed 97 * quantum: buffer size quantum 98 * pbptr: address of movable pointer into buffer, or 0 if none 99 * whatrtn: name of the calling routine if failure should cause fatal error 100 * 101 * return 0 for realloc failure, !=0 for success 102 */ 103 { 104 if (minlen > *psiz) { 105 char *tbuf; 106 int rminlen = quantum ? minlen % quantum : 0; 107 int boff = pbptr ? *pbptr - *pbuf : 0; 108 /* round up to next multiple of quantum */ 109 if (rminlen) 110 minlen += quantum - rminlen; 111 tbuf = (char *) realloc(*pbuf, minlen); 112 if (tbuf == NULL) { 113 if (whatrtn) 114 FATAL("out of memory in %s", whatrtn); 115 return 0; 116 } 117 *pbuf = tbuf; 118 *psiz = minlen; 119 if (pbptr) 120 *pbptr = tbuf + boff; 121 } 122 return 1; 123 } 124 125 void run(Node *a) /* execution of parse tree starts here */ 126 { 127 extern void stdinit(void); 128 129 stdinit(); 130 execute(a); 131 closeall(); 132 } 133 134 Cell *execute(Node *u) /* execute a node of the parse tree */ 135 { 136 Cell *(*proc)(Node **, int); 137 Cell *x; 138 Node *a; 139 140 if (u == NULL) 141 return(True); 142 for (a = u; ; a = a->nnext) { 143 curnode = a; 144 if (isvalue(a)) { 145 x = (Cell *) (a->narg[0]); 146 if (isfld(x) && !donefld) 147 fldbld(); 148 else if (isrec(x) && !donerec) 149 recbld(); 150 return(x); 151 } 152 if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */ 153 FATAL("illegal statement"); 154 proc = proctab[a->nobj-FIRSTTOKEN]; 155 x = (*proc)(a->narg, a->nobj); 156 if (isfld(x) && !donefld) 157 fldbld(); 158 else if (isrec(x) && !donerec) 159 recbld(); 160 if (isexpr(a)) 161 return(x); 162 if (isjump(x)) 163 return(x); 164 if (a->nnext == NULL) 165 return(x); 166 tempfree(x); 167 } 168 } 169 170 171 Cell *program(Node **a, int n) /* execute an awk program */ 172 { /* a[0] = BEGIN, a[1] = body, a[2] = END */ 173 Cell *x; 174 175 if (setjmp(env) != 0) 176 goto ex; 177 if (a[0]) { /* BEGIN */ 178 x = execute(a[0]); 179 if (isexit(x)) 180 return(True); 181 if (isjump(x)) 182 FATAL("illegal break, continue, next or nextfile from BEGIN"); 183 tempfree(x); 184 } 185 if (a[1] || a[2]) 186 while (getrec(&record, &recsize, 1) > 0) { 187 x = execute(a[1]); 188 if (isexit(x)) 189 break; 190 tempfree(x); 191 } 192 ex: 193 if (setjmp(env) != 0) /* handles exit within END */ 194 goto ex1; 195 if (a[2]) { /* END */ 196 x = execute(a[2]); 197 if (isbreak(x) || isnext(x) || iscont(x)) 198 FATAL("illegal break, continue, next or nextfile from END"); 199 tempfree(x); 200 } 201 ex1: 202 return(True); 203 } 204 205 struct Frame { /* stack frame for awk function calls */ 206 int nargs; /* number of arguments in this call */ 207 Cell *fcncell; /* pointer to Cell for function */ 208 Cell **args; /* pointer to array of arguments after execute */ 209 Cell *retval; /* return value */ 210 }; 211 212 #define NARGS 50 /* max args in a call */ 213 214 struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */ 215 int nframe = 0; /* number of frames allocated */ 216 struct Frame *fp = NULL; /* frame pointer. bottom level unused */ 217 218 Cell *call(Node **a, int n) /* function call. very kludgy and fragile */ 219 { 220 static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE }; 221 int i, ncall, ndef; 222 Node *x; 223 Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */ 224 Cell *y, *z, *fcn; 225 char *s; 226 227 fcn = execute(a[0]); /* the function itself */ 228 s = fcn->nval; 229 if (!isfcn(fcn)) 230 FATAL("calling undefined function %s", s); 231 if (frame == NULL) { 232 fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame)); 233 if (frame == NULL) 234 FATAL("out of space for stack frames calling %s", s); 235 } 236 for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */ 237 ncall++; 238 ndef = (int) fcn->fval; /* args in defn */ 239 dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) ); 240 if (ncall > ndef) 241 WARNING("function %s called with %d args, uses only %d", 242 s, ncall, ndef); 243 if (ncall + ndef > NARGS) 244 FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS); 245 for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */ 246 dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) ); 247 y = execute(x); 248 oargs[i] = y; 249 dprintf( ("args[%d]: %s %f <%s>, t=%o\n", 250 i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) ); 251 if (isfcn(y)) 252 FATAL("can't use function %s as argument in %s", y->nval, s); 253 if (isarr(y)) 254 args[i] = y; /* arrays by ref */ 255 else 256 args[i] = copycell(y); 257 tempfree(y); 258 } 259 for ( ; i < ndef; i++) { /* add null args for ones not provided */ 260 args[i] = gettemp(); 261 *args[i] = newcopycell; 262 } 263 fp++; /* now ok to up frame */ 264 if (fp >= frame + nframe) { 265 int dfp = fp - frame; /* old index */ 266 frame = (struct Frame *) 267 realloc((char *) frame, (nframe += 100) * sizeof(struct Frame)); 268 if (frame == NULL) 269 FATAL("out of space for stack frames in %s", s); 270 fp = frame + dfp; 271 } 272 fp->fcncell = fcn; 273 fp->args = args; 274 fp->nargs = ndef; /* number defined with (excess are locals) */ 275 fp->retval = gettemp(); 276 277 dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) ); 278 y = execute((Node *)(fcn->sval)); /* execute body */ 279 dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) ); 280 281 for (i = 0; i < ndef; i++) { 282 Cell *t = fp->args[i]; 283 if (isarr(t)) { 284 if (t->csub == CCOPY) { 285 if (i >= ncall) { 286 freesymtab(t); 287 t->csub = CTEMP; 288 tempfree(t); 289 } else { 290 oargs[i]->tval = t->tval; 291 oargs[i]->tval &= ~(STR|NUM|DONTFREE); 292 oargs[i]->sval = t->sval; 293 tempfree(t); 294 } 295 } 296 } else if (t != y) { /* kludge to prevent freeing twice */ 297 t->csub = CTEMP; 298 tempfree(t); 299 } 300 } 301 tempfree(fcn); 302 if (isexit(y) || isnext(y) || isnextfile(y)) 303 return y; 304 tempfree(y); /* this can free twice! */ 305 z = fp->retval; /* return value */ 306 dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) ); 307 fp--; 308 return(z); 309 } 310 311 Cell *copycell(Cell *x) /* make a copy of a cell in a temp */ 312 { 313 Cell *y; 314 315 y = gettemp(); 316 y->csub = CCOPY; /* prevents freeing until call is over */ 317 y->nval = x->nval; /* BUG? */ 318 y->sval = x->sval ? tostring(x->sval) : NULL; 319 y->fval = x->fval; 320 y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */ 321 /* is DONTFREE right? */ 322 return y; 323 } 324 325 Cell *arg(Node **a, int n) /* nth argument of a function */ 326 { 327 328 n = ptoi(a[0]); /* argument number, counting from 0 */ 329 dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) ); 330 if (n+1 > fp->nargs) 331 FATAL("argument #%d of function %s was not supplied", 332 n+1, fp->fcncell->nval); 333 return fp->args[n]; 334 } 335 336 Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */ 337 { 338 Cell *y; 339 340 switch (n) { 341 case EXIT: 342 if (a[0] != NULL) { 343 y = execute(a[0]); 344 errorflag = (int) getfval(y); 345 tempfree(y); 346 } 347 longjmp(env, 1); 348 case RETURN: 349 if (a[0] != NULL) { 350 y = execute(a[0]); 351 if ((y->tval & (STR|NUM)) == (STR|NUM)) { 352 setsval(fp->retval, getsval(y)); 353 fp->retval->fval = getfval(y); 354 fp->retval->tval |= NUM; 355 } 356 else if (y->tval & STR) 357 setsval(fp->retval, getsval(y)); 358 else if (y->tval & NUM) 359 setfval(fp->retval, getfval(y)); 360 else /* can't happen */ 361 FATAL("bad type variable %d", y->tval); 362 tempfree(y); 363 } 364 return(jret); 365 case NEXT: 366 return(jnext); 367 case NEXTFILE: 368 nextfile(); 369 return(jnextfile); 370 case BREAK: 371 return(jbreak); 372 case CONTINUE: 373 return(jcont); 374 default: /* can't happen */ 375 FATAL("illegal jump type %d", n); 376 } 377 return 0; /* not reached */ 378 } 379 380 Cell *getline(Node **a, int n) /* get next line from specific input */ 381 { /* a[0] is variable, a[1] is operator, a[2] is filename */ 382 Cell *r, *x; 383 extern Cell **fldtab; 384 FILE *fp; 385 char *buf; 386 int bufsize = recsize; 387 int mode; 388 389 if ((buf = (char *) malloc(bufsize)) == NULL) 390 FATAL("out of memory in getline"); 391 392 fflush(stdout); /* in case someone is waiting for a prompt */ 393 r = gettemp(); 394 if (a[1] != NULL) { /* getline < file */ 395 x = execute(a[2]); /* filename */ 396 mode = ptoi(a[1]); 397 if (mode == '|') /* input pipe */ 398 mode = LE; /* arbitrary flag */ 399 fp = openfile(mode, getsval(x)); 400 tempfree(x); 401 if (fp == NULL) 402 n = -1; 403 else 404 n = readrec(&buf, &bufsize, fp); 405 if (n <= 0) { 406 ; 407 } else if (a[0] != NULL) { /* getline var <file */ 408 x = execute(a[0]); 409 setsval(x, buf); 410 tempfree(x); 411 } else { /* getline <file */ 412 setsval(fldtab[0], buf); 413 if (is_number(fldtab[0]->sval)) { 414 fldtab[0]->fval = atof(fldtab[0]->sval); 415 fldtab[0]->tval |= NUM; 416 } 417 } 418 } else { /* bare getline; use current input */ 419 if (a[0] == NULL) /* getline */ 420 n = getrec(&record, &recsize, 1); 421 else { /* getline var */ 422 n = getrec(&buf, &bufsize, 0); 423 x = execute(a[0]); 424 setsval(x, buf); 425 tempfree(x); 426 } 427 } 428 setfval(r, (Awkfloat) n); 429 free(buf); 430 return r; 431 } 432 433 Cell *getnf(Node **a, int n) /* get NF */ 434 { 435 if (donefld == 0) 436 fldbld(); 437 return (Cell *) a[0]; 438 } 439 440 Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ 441 { 442 Cell *x, *y, *z; 443 char *s; 444 Node *np; 445 char *buf; 446 int bufsz = recsize; 447 int nsub = strlen(*SUBSEP); 448 449 if ((buf = (char *) malloc(bufsz)) == NULL) 450 FATAL("out of memory in array"); 451 452 x = execute(a[0]); /* Cell* for symbol table */ 453 buf[0] = 0; 454 for (np = a[1]; np; np = np->nnext) { 455 y = execute(np); /* subscript */ 456 s = getsval(y); 457 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0)) 458 FATAL("out of memory for %s[%s...]", x->nval, buf); 459 strcat(buf, s); 460 if (np->nnext) 461 strcat(buf, *SUBSEP); 462 tempfree(y); 463 } 464 if (!isarr(x)) { 465 dprintf( ("making %s into an array\n", x->nval) ); 466 if (freeable(x)) 467 xfree(x->sval); 468 x->tval &= ~(STR|NUM|DONTFREE); 469 x->tval |= ARR; 470 x->sval = (char *) makesymtab(NSYMTAB); 471 } 472 z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval); 473 z->ctype = OCELL; 474 z->csub = CVAR; 475 tempfree(x); 476 free(buf); 477 return(z); 478 } 479 480 Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ 481 { 482 Cell *x, *y; 483 Node *np; 484 char *s; 485 int nsub = strlen(*SUBSEP); 486 487 x = execute(a[0]); /* Cell* for symbol table */ 488 if (!isarr(x)) 489 return True; 490 if (a[1] == 0) { /* delete the elements, not the table */ 491 freesymtab(x); 492 x->tval &= ~STR; 493 x->tval |= ARR; 494 x->sval = (char *) makesymtab(NSYMTAB); 495 } else { 496 int bufsz = recsize; 497 char *buf; 498 if ((buf = (char *) malloc(bufsz)) == NULL) 499 FATAL("out of memory in adelete"); 500 buf[0] = 0; 501 for (np = a[1]; np; np = np->nnext) { 502 y = execute(np); /* subscript */ 503 s = getsval(y); 504 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0)) 505 FATAL("out of memory deleting %s[%s...]", x->nval, buf); 506 strcat(buf, s); 507 if (np->nnext) 508 strcat(buf, *SUBSEP); 509 tempfree(y); 510 } 511 freeelem(x, buf); 512 free(buf); 513 } 514 tempfree(x); 515 return True; 516 } 517 518 Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */ 519 { 520 Cell *x, *ap, *k; 521 Node *p; 522 char *buf; 523 char *s; 524 int bufsz = recsize; 525 int nsub = strlen(*SUBSEP); 526 527 ap = execute(a[1]); /* array name */ 528 if (!isarr(ap)) { 529 dprintf( ("making %s into an array\n", ap->nval) ); 530 if (freeable(ap)) 531 xfree(ap->sval); 532 ap->tval &= ~(STR|NUM|DONTFREE); 533 ap->tval |= ARR; 534 ap->sval = (char *) makesymtab(NSYMTAB); 535 } 536 if ((buf = (char *) malloc(bufsz)) == NULL) { 537 FATAL("out of memory in intest"); 538 } 539 buf[0] = 0; 540 for (p = a[0]; p; p = p->nnext) { 541 x = execute(p); /* expr */ 542 s = getsval(x); 543 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0)) 544 FATAL("out of memory deleting %s[%s...]", x->nval, buf); 545 strcat(buf, s); 546 tempfree(x); 547 if (p->nnext) 548 strcat(buf, *SUBSEP); 549 } 550 k = lookup(buf, (Array *) ap->sval); 551 tempfree(ap); 552 free(buf); 553 if (k == NULL) 554 return(False); 555 else 556 return(True); 557 } 558 559 560 Cell *matchop(Node **a, int n) /* ~ and match() */ 561 { 562 Cell *x, *y; 563 char *s, *t; 564 int i; 565 void *p; 566 567 x = execute(a[1]); /* a[1] = target text */ 568 s = getsval(x); 569 if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */ 570 p = (void *) a[2]; 571 else { 572 y = execute(a[2]); /* a[2] = regular expr */ 573 t = getsval(y); 574 p = compre(t); 575 tempfree(y); 576 } 577 if (n == MATCHFCN) 578 i = pmatch(p, s, s); 579 else 580 i = match(p, s, s); 581 tempfree(x); 582 if (n == MATCHFCN) { 583 int start = countposn(s, patbeg-s)+1; 584 if (patlen < 0) 585 start = 0; 586 setfval(rstartloc, (Awkfloat) start); 587 setfval(rlengthloc, (Awkfloat) countposn(patbeg, patlen)); 588 x = gettemp(); 589 x->tval = NUM; 590 x->fval = start; 591 return x; 592 } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0)) 593 return(True); 594 else 595 return(False); 596 } 597 598 599 Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */ 600 { 601 Cell *x, *y; 602 int i; 603 604 x = execute(a[0]); 605 i = istrue(x); 606 tempfree(x); 607 switch (n) { 608 case BOR: 609 if (i) return(True); 610 y = execute(a[1]); 611 i = istrue(y); 612 tempfree(y); 613 if (i) return(True); 614 else return(False); 615 case AND: 616 if ( !i ) return(False); 617 y = execute(a[1]); 618 i = istrue(y); 619 tempfree(y); 620 if (i) return(True); 621 else return(False); 622 case NOT: 623 if (i) return(False); 624 else return(True); 625 default: /* can't happen */ 626 FATAL("unknown boolean operator %d", n); 627 } 628 return 0; /*NOTREACHED*/ 629 } 630 631 Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */ 632 { 633 int i; 634 Cell *x, *y; 635 Awkfloat j; 636 637 x = execute(a[0]); 638 y = execute(a[1]); 639 if (x->tval&NUM && y->tval&NUM) { 640 j = x->fval - y->fval; 641 i = j<0? -1: (j>0? 1: 0); 642 } else { 643 i = strcmp(getsval(x), getsval(y)); 644 } 645 tempfree(x); 646 tempfree(y); 647 switch (n) { 648 case LT: if (i<0) return(True); 649 else return(False); 650 case LE: if (i<=0) return(True); 651 else return(False); 652 case NE: if (i!=0) return(True); 653 else return(False); 654 case EQ: if (i == 0) return(True); 655 else return(False); 656 case GE: if (i>=0) return(True); 657 else return(False); 658 case GT: if (i>0) return(True); 659 else return(False); 660 default: /* can't happen */ 661 FATAL("unknown relational operator %d", n); 662 } 663 return 0; /*NOTREACHED*/ 664 } 665 666 void tfree(Cell *a) /* free a tempcell */ 667 { 668 if (freeable(a)) { 669 dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) ); 670 xfree(a->sval); 671 } 672 if (a == tmps) 673 FATAL("tempcell list is curdled"); 674 a->cnext = tmps; 675 tmps = a; 676 } 677 678 Cell *gettemp(void) /* get a tempcell */ 679 { int i; 680 Cell *x; 681 682 if (!tmps) { 683 tmps = (Cell *) calloc(100, sizeof(Cell)); 684 if (!tmps) 685 FATAL("out of space for temporaries"); 686 for(i = 1; i < 100; i++) 687 tmps[i-1].cnext = &tmps[i]; 688 tmps[i-1].cnext = 0; 689 } 690 x = tmps; 691 tmps = x->cnext; 692 *x = tempcell; 693 return(x); 694 } 695 696 Cell *indirect(Node **a, int n) /* $( a[0] ) */ 697 { 698 Cell *x; 699 int m; 700 char *s; 701 702 x = execute(a[0]); 703 m = (int) getfval(x); 704 if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */ 705 FATAL("illegal field $(%s), name \"%s\"", s, x->nval); 706 /* BUG: can x->nval ever be null??? */ 707 tempfree(x); 708 x = fieldadr(m); 709 x->ctype = OCELL; /* BUG? why are these needed? */ 710 x->csub = CFLD; 711 return(x); 712 } 713 714 Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */ 715 { 716 int k, m, n; 717 char *s, *p; 718 int temp; 719 Cell *x, *y, *z = 0; 720 721 x = execute(a[0]); 722 y = execute(a[1]); 723 if (a[2] != 0) 724 z = execute(a[2]); 725 s = getsval(x); 726 k = countposn(s, strlen(s)) + 1; 727 if (k <= 1) { 728 tempfree(x); 729 tempfree(y); 730 if (a[2] != 0) 731 tempfree(z); 732 x = gettemp(); 733 setsval(x, ""); 734 return(x); 735 } 736 m = (int) getfval(y); 737 if (m <= 0) 738 m = 1; 739 else if (m > k) 740 m = k; 741 tempfree(y); 742 if (a[2] != 0) { 743 n = (int) getfval(z); 744 tempfree(z); 745 } else 746 n = k - 1; 747 if (n < 0) 748 n = 0; 749 else if (n > k - m) 750 n = k - m; 751 dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) ); 752 y = gettemp(); 753 while (*s && --m) 754 s += mblen(s, k); 755 for (p = s; *p && n--; p += mblen(p, k)) 756 ; 757 temp = *p; /* with thanks to John Linderman */ 758 *p = '\0'; 759 setsval(y, s); 760 *p = temp; 761 tempfree(x); 762 return(y); 763 } 764 765 Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */ 766 { 767 Cell *x, *y, *z; 768 char *s1, *s2, *p1, *p2, *q; 769 Awkfloat v = 0.0; 770 771 x = execute(a[0]); 772 s1 = getsval(x); 773 y = execute(a[1]); 774 s2 = getsval(y); 775 776 z = gettemp(); 777 for (p1 = s1; *p1 != '\0'; p1++) { 778 for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++) 779 ; 780 if (*p2 == '\0') { 781 v = (Awkfloat) countposn(s1, p1-s1) + 1; /* origin 1 */ 782 break; 783 } 784 } 785 tempfree(x); 786 tempfree(y); 787 setfval(z, v); 788 return(z); 789 } 790 791 #define MAXNUMSIZE 50 792 793 int format(char **pbuf, int *pbufsize, char *s, Node *a) /* printf-like conversions */ 794 { 795 char *fmt; 796 char *p, *t, *os; 797 Cell *x; 798 int flag = 0, n; 799 int fmtwd; /* format width */ 800 int fmtsz = recsize; 801 char *buf = *pbuf; 802 int bufsize = *pbufsize; 803 804 os = s; 805 p = buf; 806 if ((fmt = (char *) malloc(fmtsz)) == NULL) 807 FATAL("out of memory in format()"); 808 while (*s) { 809 adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format"); 810 if (*s != '%') { 811 *p++ = *s++; 812 continue; 813 } 814 if (*(s+1) == '%') { 815 *p++ = '%'; 816 s += 2; 817 continue; 818 } 819 /* have to be real careful in case this is a huge number, eg, %100000d */ 820 fmtwd = atoi(s+1); 821 if (fmtwd < 0) 822 fmtwd = -fmtwd; 823 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); 824 for (t = fmt; (*t++ = *s) != '\0'; s++) { 825 if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0)) 826 FATAL("format item %.30s... ran format() out of memory", os); 827 if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L') 828 break; /* the ansi panoply */ 829 if (*s == '*') { 830 x = execute(a); 831 a = a->nnext; 832 sprintf(t-1, "%d", fmtwd=(int) getfval(x)); 833 if (fmtwd < 0) 834 fmtwd = -fmtwd; 835 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); 836 t = fmt + strlen(fmt); 837 tempfree(x); 838 } 839 } 840 *t = '\0'; 841 if (fmtwd < 0) 842 fmtwd = -fmtwd; 843 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); 844 845 switch (*s) { 846 case 'f': case 'e': case 'g': case 'E': case 'G': 847 flag = 1; 848 break; 849 case 'd': case 'i': 850 flag = 2; 851 if(*(s-1) == 'l') break; 852 *(t-1) = 'l'; 853 *t = 'd'; 854 *++t = '\0'; 855 break; 856 case 'o': case 'x': case 'X': case 'u': 857 flag = *(s-1) == 'l' ? 2 : 3; 858 break; 859 case 's': 860 flag = 4; 861 break; 862 case 'c': 863 flag = 5; 864 break; 865 default: 866 WARNING("weird printf conversion %s", fmt); 867 flag = 0; 868 break; 869 } 870 if (a == NULL) 871 FATAL("not enough args in printf(%s)", os); 872 x = execute(a); 873 a = a->nnext; 874 n = MAXNUMSIZE; 875 if (fmtwd > n) 876 n = fmtwd; 877 adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format"); 878 switch (flag) { 879 case 0: sprintf(p, "%s", fmt); /* unknown, so dump it too */ 880 t = getsval(x); 881 n = strlen(t); 882 if (fmtwd > n) 883 n = fmtwd; 884 adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format"); 885 p += strlen(p); 886 sprintf(p, "%s", t); 887 break; 888 case 1: sprintf(p, fmt, getfval(x)); break; 889 case 2: sprintf(p, fmt, (long) getfval(x)); break; 890 case 3: sprintf(p, fmt, (int) getfval(x)); break; 891 case 4: 892 t = getsval(x); 893 n = strlen(t); 894 if (fmtwd > n) 895 n = fmtwd; 896 if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0)) 897 FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t); 898 sprintf(p, fmt, t); 899 break; 900 case 5: 901 if (isnum(x)) { 902 if (getfval(x)) 903 sprintf(p, fmt, (int) getfval(x)); 904 else 905 *p++ = '\0'; 906 } else 907 sprintf(p, fmt, getsval(x)[0]); 908 break; 909 } 910 tempfree(x); 911 p += strlen(p); 912 s++; 913 } 914 *p = '\0'; 915 free(fmt); 916 for ( ; a; a = a->nnext) /* evaluate any remaining args */ 917 execute(a); 918 *pbuf = buf; 919 *pbufsize = bufsize; 920 return p - buf; 921 } 922 923 Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */ 924 { 925 Cell *x; 926 Node *y; 927 char *buf; 928 int bufsz=3*recsize; 929 930 if ((buf = (char *) malloc(bufsz)) == NULL) 931 FATAL("out of memory in awksprintf"); 932 y = a[0]->nnext; 933 x = execute(a[0]); 934 if (format(&buf, &bufsz, getsval(x), y) == -1) 935 FATAL("sprintf string %.30s... too long. can't happen.", buf); 936 tempfree(x); 937 x = gettemp(); 938 x->sval = buf; 939 x->tval = STR; 940 return(x); 941 } 942 943 Cell *awkprintf(Node **a, int n) /* printf */ 944 { /* a[0] is list of args, starting with format string */ 945 /* a[1] is redirection operator, a[2] is redirection file */ 946 FILE *fp; 947 Cell *x; 948 Node *y; 949 char *buf; 950 int len; 951 int bufsz=3*recsize; 952 953 if ((buf = (char *) malloc(bufsz)) == NULL) 954 FATAL("out of memory in awkprintf"); 955 y = a[0]->nnext; 956 x = execute(a[0]); 957 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1) 958 FATAL("printf string %.30s... too long. can't happen.", buf); 959 tempfree(x); 960 if (a[1] == NULL) { 961 /* fputs(buf, stdout); */ 962 fwrite(buf, len, 1, stdout); 963 if (ferror(stdout)) 964 FATAL("write error on stdout"); 965 } else { 966 fp = redirect(ptoi(a[1]), a[2]); 967 /* fputs(buf, fp); */ 968 fwrite(buf, len, 1, fp); 969 fflush(fp); 970 if (ferror(fp)) 971 FATAL("write error on %s", filename(fp)); 972 } 973 free(buf); 974 return(True); 975 } 976 977 Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */ 978 { 979 Awkfloat i, j = 0; 980 double v; 981 Cell *x, *y, *z; 982 983 x = execute(a[0]); 984 i = getfval(x); 985 tempfree(x); 986 if (n != UMINUS) { 987 y = execute(a[1]); 988 j = getfval(y); 989 tempfree(y); 990 } 991 z = gettemp(); 992 switch (n) { 993 case ADD: 994 i += j; 995 break; 996 case MINUS: 997 i -= j; 998 break; 999 case MULT: 1000 i *= j; 1001 break; 1002 case DIVIDE: 1003 if (j == 0) 1004 FATAL("division by zero"); 1005 i /= j; 1006 break; 1007 case MOD: 1008 if (j == 0) 1009 FATAL("division by zero in mod"); 1010 modf(i/j, &v); 1011 i = i - j * v; 1012 break; 1013 case UMINUS: 1014 i = -i; 1015 break; 1016 case POWER: 1017 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */ 1018 i = ipow(i, (int) j); 1019 else 1020 i = errcheck(pow(i, j), "pow"); 1021 break; 1022 default: /* can't happen */ 1023 FATAL("illegal arithmetic operator %d", n); 1024 } 1025 setfval(z, i); 1026 return(z); 1027 } 1028 1029 double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */ 1030 { 1031 double v; 1032 1033 if (n <= 0) 1034 return 1; 1035 v = ipow(x, n/2); 1036 if (n % 2 == 0) 1037 return v * v; 1038 else 1039 return x * v * v; 1040 } 1041 1042 Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */ 1043 { 1044 Cell *x, *z; 1045 int k; 1046 Awkfloat xf; 1047 1048 x = execute(a[0]); 1049 xf = getfval(x); 1050 k = (n == PREINCR || n == POSTINCR) ? 1 : -1; 1051 if (n == PREINCR || n == PREDECR) { 1052 setfval(x, xf + k); 1053 return(x); 1054 } 1055 z = gettemp(); 1056 setfval(z, xf); 1057 setfval(x, xf + k); 1058 tempfree(x); 1059 return(z); 1060 } 1061 1062 Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */ 1063 { /* this is subtle; don't muck with it. */ 1064 Cell *x, *y; 1065 Awkfloat xf, yf; 1066 double v; 1067 1068 y = execute(a[1]); 1069 x = execute(a[0]); 1070 if (n == ASSIGN) { /* ordinary assignment */ 1071 if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */ 1072 ; /* leave alone unless it's a field */ 1073 else if ((y->tval & (STR|NUM)) == (STR|NUM)) { 1074 setsval(x, getsval(y)); 1075 x->fval = getfval(y); 1076 x->tval |= NUM; 1077 } 1078 else if (isstr(y)) 1079 setsval(x, getsval(y)); 1080 else if (isnum(y)) 1081 setfval(x, getfval(y)); 1082 else 1083 funnyvar(y, "read value of"); 1084 tempfree(y); 1085 return(x); 1086 } 1087 xf = getfval(x); 1088 yf = getfval(y); 1089 switch (n) { 1090 case ADDEQ: 1091 xf += yf; 1092 break; 1093 case SUBEQ: 1094 xf -= yf; 1095 break; 1096 case MULTEQ: 1097 xf *= yf; 1098 break; 1099 case DIVEQ: 1100 if (yf == 0) 1101 FATAL("division by zero in /="); 1102 xf /= yf; 1103 break; 1104 case MODEQ: 1105 if (yf == 0) 1106 FATAL("division by zero in %%="); 1107 modf(xf/yf, &v); 1108 xf = xf - yf * v; 1109 break; 1110 case POWEQ: 1111 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */ 1112 xf = ipow(xf, (int) yf); 1113 else 1114 xf = errcheck(pow(xf, yf), "pow"); 1115 break; 1116 default: 1117 FATAL("illegal assignment operator %d", n); 1118 break; 1119 } 1120 tempfree(y); 1121 setfval(x, xf); 1122 return(x); 1123 } 1124 1125 Cell *cat(Node **a, int q) /* a[0] cat a[1] */ 1126 { 1127 Cell *x, *y, *z; 1128 int n1, n2; 1129 char *s; 1130 1131 x = execute(a[0]); 1132 y = execute(a[1]); 1133 getsval(x); 1134 getsval(y); 1135 n1 = strlen(x->sval); 1136 n2 = strlen(y->sval); 1137 s = (char *) malloc(n1 + n2 + 1); 1138 if (s == NULL) 1139 FATAL("out of space concatenating %.15s... and %.15s...", 1140 x->sval, y->sval); 1141 strcpy(s, x->sval); 1142 strcpy(s+n1, y->sval); 1143 tempfree(y); 1144 z = gettemp(); 1145 z->sval = s; 1146 z->tval = STR; 1147 tempfree(x); 1148 return(z); 1149 } 1150 1151 Cell *pastat(Node **a, int n) /* a[0] { a[1] } */ 1152 { 1153 Cell *x; 1154 1155 if (a[0] == 0) 1156 x = execute(a[1]); 1157 else { 1158 x = execute(a[0]); 1159 if (istrue(x)) { 1160 tempfree(x); 1161 x = execute(a[1]); 1162 } 1163 } 1164 return x; 1165 } 1166 1167 Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */ 1168 { 1169 Cell *x; 1170 int pair; 1171 1172 pair = ptoi(a[3]); 1173 if (pairstack[pair] == 0) { 1174 x = execute(a[0]); 1175 if (istrue(x)) 1176 pairstack[pair] = 1; 1177 tempfree(x); 1178 } 1179 if (pairstack[pair] == 1) { 1180 x = execute(a[1]); 1181 if (istrue(x)) 1182 pairstack[pair] = 0; 1183 tempfree(x); 1184 x = execute(a[2]); 1185 return(x); 1186 } 1187 return(False); 1188 } 1189 1190 Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ 1191 { 1192 Cell *x = 0, *y, *ap; 1193 char *s; 1194 int sep; 1195 char *t, temp, num[50], *fs = 0; 1196 int n, tempstat, arg3type; 1197 1198 y = execute(a[0]); /* source string */ 1199 s = getsval(y); 1200 arg3type = ptoi(a[3]); 1201 if (a[2] == 0) /* fs string */ 1202 fs = *FS; 1203 else if (arg3type == STRING) { /* split(str,arr,"string") */ 1204 x = execute(a[2]); 1205 fs = getsval(x); 1206 } else if (arg3type == REGEXPR) 1207 fs = "(regexpr)"; /* split(str,arr,/regexpr/) */ 1208 else 1209 FATAL("illegal type of split"); 1210 sep = *fs; 1211 ap = execute(a[1]); /* array name */ 1212 freesymtab(ap); 1213 dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) ); 1214 ap->tval &= ~STR; 1215 ap->tval |= ARR; 1216 ap->sval = (char *) makesymtab(NSYMTAB); 1217 1218 n = 0; 1219 if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) { /* reg expr */ 1220 void *p; 1221 if (arg3type == REGEXPR) { /* it's ready already */ 1222 p = (void *) a[2]; 1223 } else { 1224 p = compre(fs); 1225 } 1226 t = s; 1227 if (nematch(p,s,t)) { 1228 do { 1229 n++; 1230 sprintf(num, "%d", n); 1231 temp = *patbeg; 1232 *patbeg = '\0'; 1233 if (is_number(t)) 1234 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); 1235 else 1236 setsymtab(num, t, 0.0, STR, (Array *) ap->sval); 1237 *patbeg = temp; 1238 t = patbeg + patlen; 1239 if (t[-1] == 0 || *t == 0) { 1240 n++; 1241 sprintf(num, "%d", n); 1242 setsymtab(num, "", 0.0, STR, (Array *) ap->sval); 1243 goto spdone; 1244 } 1245 } while (nematch(p,s,t)); 1246 } 1247 n++; 1248 sprintf(num, "%d", n); 1249 if (is_number(t)) 1250 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); 1251 else 1252 setsymtab(num, t, 0.0, STR, (Array *) ap->sval); 1253 spdone: 1254 p = NULL; 1255 } else if (sep == ' ') { 1256 for (n = 0; ; ) { 1257 while (*s == ' ' || *s == '\t' || *s == '\n') 1258 s++; 1259 if (*s == 0) 1260 break; 1261 n++; 1262 t = s; 1263 do 1264 s++; 1265 while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0'); 1266 temp = *s; 1267 *s = '\0'; 1268 sprintf(num, "%d", n); 1269 if (is_number(t)) 1270 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); 1271 else 1272 setsymtab(num, t, 0.0, STR, (Array *) ap->sval); 1273 *s = temp; 1274 if (*s != 0) 1275 s++; 1276 } 1277 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */ 1278 for (n = 0; *s != 0; s++) { 1279 char buf[2]; 1280 n++; 1281 sprintf(num, "%d", n); 1282 buf[0] = *s; 1283 buf[1] = 0; 1284 if (isdigit(buf[0])) 1285 setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval); 1286 else 1287 setsymtab(num, buf, 0.0, STR, (Array *) ap->sval); 1288 } 1289 } else if (*s != 0) { 1290 for (;;) { 1291 n++; 1292 t = s; 1293 while (*s != sep && *s != '\n' && *s != '\0') 1294 s++; 1295 temp = *s; 1296 *s = '\0'; 1297 sprintf(num, "%d", n); 1298 if (is_number(t)) 1299 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); 1300 else 1301 setsymtab(num, t, 0.0, STR, (Array *) ap->sval); 1302 *s = temp; 1303 if (*s++ == 0) 1304 break; 1305 } 1306 } 1307 tempfree(ap); 1308 tempfree(y); 1309 if (a[2] != 0 && arg3type == STRING) 1310 tempfree(x); 1311 x = gettemp(); 1312 x->tval = NUM; 1313 x->fval = n; 1314 return(x); 1315 } 1316 1317 Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */ 1318 { 1319 Cell *x; 1320 1321 x = execute(a[0]); 1322 if (istrue(x)) { 1323 tempfree(x); 1324 x = execute(a[1]); 1325 } else { 1326 tempfree(x); 1327 x = execute(a[2]); 1328 } 1329 return(x); 1330 } 1331 1332 Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */ 1333 { 1334 Cell *x; 1335 1336 x = execute(a[0]); 1337 if (istrue(x)) { 1338 tempfree(x); 1339 x = execute(a[1]); 1340 } else if (a[2] != 0) { 1341 tempfree(x); 1342 x = execute(a[2]); 1343 } 1344 return(x); 1345 } 1346 1347 Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */ 1348 { 1349 Cell *x; 1350 1351 for (;;) { 1352 x = execute(a[0]); 1353 if (!istrue(x)) 1354 return(x); 1355 tempfree(x); 1356 x = execute(a[1]); 1357 if (isbreak(x)) { 1358 x = True; 1359 return(x); 1360 } 1361 if (isnext(x) || isexit(x) || isret(x)) 1362 return(x); 1363 tempfree(x); 1364 } 1365 } 1366 1367 Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */ 1368 { 1369 Cell *x; 1370 1371 for (;;) { 1372 x = execute(a[0]); 1373 if (isbreak(x)) 1374 return True; 1375 if (isnext(x) || isnextfile(x) || isexit(x) || isret(x)) 1376 return(x); 1377 tempfree(x); 1378 x = execute(a[1]); 1379 if (!istrue(x)) 1380 return(x); 1381 tempfree(x); 1382 } 1383 } 1384 1385 Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */ 1386 { 1387 Cell *x; 1388 1389 x = execute(a[0]); 1390 tempfree(x); 1391 for (;;) { 1392 if (a[1]!=0) { 1393 x = execute(a[1]); 1394 if (!istrue(x)) return(x); 1395 else tempfree(x); 1396 } 1397 x = execute(a[3]); 1398 if (isbreak(x)) /* turn off break */ 1399 return True; 1400 if (isnext(x) || isexit(x) || isret(x)) 1401 return(x); 1402 tempfree(x); 1403 x = execute(a[2]); 1404 tempfree(x); 1405 } 1406 } 1407 1408 Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */ 1409 { 1410 Cell *x, *vp, *arrayp, *cp, *ncp; 1411 Array *tp; 1412 int i; 1413 1414 vp = execute(a[0]); 1415 arrayp = execute(a[1]); 1416 if (!isarr(arrayp)) { 1417 return True; 1418 } 1419 tp = (Array *) arrayp->sval; 1420 tempfree(arrayp); 1421 for (i = 0; i < tp->size; i++) { /* this routine knows too much */ 1422 for (cp = tp->tab[i]; cp != NULL; cp = ncp) { 1423 setsval(vp, cp->nval); 1424 ncp = cp->cnext; 1425 x = execute(a[2]); 1426 if (isbreak(x)) { 1427 tempfree(vp); 1428 return True; 1429 } 1430 if (isnext(x) || isexit(x) || isret(x)) { 1431 tempfree(vp); 1432 return(x); 1433 } 1434 tempfree(x); 1435 } 1436 } 1437 return True; 1438 } 1439 1440 Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ 1441 { 1442 Cell *x, *y; 1443 Awkfloat u; 1444 int t; 1445 wchar_t wc; 1446 char *p, *buf; 1447 char mbc[50]; 1448 Node *nextarg; 1449 FILE *fp; 1450 1451 t = ptoi(a[0]); 1452 x = execute(a[1]); 1453 nextarg = a[1]->nnext; 1454 switch (t) { 1455 case FLENGTH: 1456 p = getsval(x); 1457 u = (Awkfloat) countposn(p, strlen(p)); break; 1458 case FLOG: 1459 u = errcheck(log(getfval(x)), "log"); break; 1460 case FINT: 1461 modf(getfval(x), &u); break; 1462 case FEXP: 1463 u = errcheck(exp(getfval(x)), "exp"); break; 1464 case FSQRT: 1465 u = errcheck(sqrt(getfval(x)), "sqrt"); break; 1466 case FSIN: 1467 u = sin(getfval(x)); break; 1468 case FCOS: 1469 u = cos(getfval(x)); break; 1470 case FATAN: 1471 if (nextarg == 0) { 1472 WARNING("atan2 requires two arguments; returning 1.0"); 1473 u = 1.0; 1474 } else { 1475 y = execute(a[1]->nnext); 1476 u = atan2(getfval(x), getfval(y)); 1477 tempfree(y); 1478 nextarg = nextarg->nnext; 1479 } 1480 break; 1481 case FSYSTEM: 1482 fflush(stdout); /* in case something is buffered already */ 1483 u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */ 1484 break; 1485 case FRAND: 1486 /* in principle, rand() returns something in 0..RAND_MAX */ 1487 u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX; 1488 break; 1489 case FSRAND: 1490 if (isrec(x)) /* no argument provided */ 1491 u = time((time_t *)0); 1492 else 1493 u = getfval(x); 1494 srand((unsigned int) u); 1495 break; 1496 case FTOUPPER: 1497 case FTOLOWER: 1498 buf = tostring(getsval(x)); 1499 if (t == FTOUPPER) { 1500 for (p = buf; *p; p++) 1501 if (islower(*p)) 1502 *p = toupper(*p); 1503 } else { 1504 for (p = buf; *p; p++) 1505 if (isupper(*p)) 1506 *p = tolower(*p); 1507 } 1508 tempfree(x); 1509 x = gettemp(); 1510 setsval(x, buf); 1511 free(buf); 1512 return x; 1513 case FFLUSH: 1514 if ((fp = openfile(FFLUSH, getsval(x))) == NULL) 1515 u = EOF; 1516 else 1517 u = fflush(fp); 1518 break; 1519 case FUTF: 1520 wc = (int)getfval(x); 1521 mbc[wctomb(mbc, wc)] = 0; 1522 tempfree(x); 1523 x = gettemp(); 1524 setsval(x, mbc); 1525 return x; 1526 default: /* can't happen */ 1527 FATAL("illegal function type %d", t); 1528 break; 1529 } 1530 tempfree(x); 1531 x = gettemp(); 1532 setfval(x, u); 1533 if (nextarg != 0) { 1534 WARNING("warning: function has too many arguments"); 1535 for ( ; nextarg; nextarg = nextarg->nnext) 1536 execute(nextarg); 1537 } 1538 return(x); 1539 } 1540 1541 Cell *printstat(Node **a, int n) /* print a[0] */ 1542 { 1543 Node *x; 1544 Cell *y; 1545 FILE *fp; 1546 1547 if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */ 1548 fp = stdout; 1549 else 1550 fp = redirect(ptoi(a[1]), a[2]); 1551 for (x = a[0]; x != NULL; x = x->nnext) { 1552 y = execute(x); 1553 fputs(getsval(y), fp); 1554 tempfree(y); 1555 if (x->nnext == NULL) 1556 fputs(*ORS, fp); 1557 else 1558 fputs(*OFS, fp); 1559 } 1560 if (a[1] != 0) 1561 fflush(fp); 1562 if (ferror(fp)) 1563 FATAL("write error on %s", filename(fp)); 1564 return(True); 1565 } 1566 1567 Cell *nullproc(Node **a, int n) 1568 { 1569 n = n; 1570 a = a; 1571 return 0; 1572 } 1573 1574 1575 FILE *redirect(int a, Node *b) /* set up all i/o redirections */ 1576 { 1577 FILE *fp; 1578 Cell *x; 1579 char *fname; 1580 1581 x = execute(b); 1582 fname = getsval(x); 1583 fp = openfile(a, fname); 1584 if (fp == NULL) 1585 FATAL("can't open file %s", fname); 1586 tempfree(x); 1587 return fp; 1588 } 1589 1590 struct files { 1591 FILE *fp; 1592 char *fname; 1593 int mode; /* '|', 'a', 'w' => LE/LT, GT */ 1594 } files[FOPEN_MAX] ={ 1595 { NULL, "/dev/stdin", LT }, /* watch out: don't free this! */ 1596 { NULL, "/dev/stdout", GT }, 1597 { NULL, "/dev/stderr", GT } 1598 }; 1599 1600 void stdinit(void) /* in case stdin, etc., are not constants */ 1601 { 1602 files[0].fp = stdin; 1603 files[1].fp = stdout; 1604 files[2].fp = stderr; 1605 } 1606 1607 FILE *openfile(int a, char *us) 1608 { 1609 char *s = us; 1610 int i, m; 1611 FILE *fp = 0; 1612 1613 if (*s == '\0') 1614 FATAL("null file name in print or getline"); 1615 for (i=0; i < FOPEN_MAX; i++) 1616 if (files[i].fname && strcmp(s, files[i].fname) == 0) { 1617 if (a == files[i].mode || (a==APPEND && files[i].mode==GT)) 1618 return files[i].fp; 1619 if (a == FFLUSH) 1620 return files[i].fp; 1621 } 1622 if (a == FFLUSH) /* didn't find it, so don't create it! */ 1623 return NULL; 1624 1625 for (i=0; i < FOPEN_MAX; i++) 1626 if (files[i].fp == 0) 1627 break; 1628 if (i >= FOPEN_MAX) 1629 FATAL("%s makes too many open files", s); 1630 fflush(stdout); /* force a semblance of order */ 1631 m = a; 1632 if (a == GT) { 1633 fp = fopen(s, "w"); 1634 } else if (a == APPEND) { 1635 fp = fopen(s, "a"); 1636 m = GT; /* so can mix > and >> */ 1637 } else if (a == '|') { /* output pipe */ 1638 fp = popen(s, "w"); 1639 } else if (a == LE) { /* input pipe */ 1640 fp = popen(s, "r"); 1641 } else if (a == LT) { /* getline <file */ 1642 fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */ 1643 } else /* can't happen */ 1644 FATAL("illegal redirection %d", a); 1645 if (fp != NULL) { 1646 files[i].fname = tostring(s); 1647 files[i].fp = fp; 1648 files[i].mode = m; 1649 } 1650 return fp; 1651 } 1652 1653 char *filename(FILE *fp) 1654 { 1655 int i; 1656 1657 for (i = 0; i < FOPEN_MAX; i++) 1658 if (fp == files[i].fp) 1659 return files[i].fname; 1660 return "???"; 1661 } 1662 1663 Cell *closefile(Node **a, int n) 1664 { 1665 Cell *x; 1666 int i, stat; 1667 1668 n = n; 1669 x = execute(a[0]); 1670 getsval(x); 1671 for (i = 0; i < FOPEN_MAX; i++) 1672 if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) { 1673 if (ferror(files[i].fp)) 1674 WARNING( "i/o error occurred on %s", files[i].fname ); 1675 if (files[i].mode == '|' || files[i].mode == LE) 1676 stat = pclose(files[i].fp); 1677 else 1678 stat = fclose(files[i].fp); 1679 if (stat == EOF) 1680 WARNING( "i/o error occurred closing %s", files[i].fname ); 1681 if (i > 2) /* don't do /dev/std... */ 1682 xfree(files[i].fname); 1683 files[i].fname = NULL; /* watch out for ref thru this */ 1684 files[i].fp = NULL; 1685 } 1686 tempfree(x); 1687 return(True); 1688 } 1689 1690 void closeall(void) 1691 { 1692 int i, stat; 1693 1694 for (i = 0; i < FOPEN_MAX; i++) 1695 if (files[i].fp) { 1696 if (ferror(files[i].fp)) 1697 WARNING( "i/o error occurred on %s", files[i].fname ); 1698 if (files[i].mode == '|' || files[i].mode == LE) 1699 stat = pclose(files[i].fp); 1700 else 1701 stat = fclose(files[i].fp); 1702 if (stat == EOF) 1703 WARNING( "i/o error occurred while closing %s", files[i].fname ); 1704 } 1705 } 1706 1707 void backsub(char **pb_ptr, char **sptr_ptr); 1708 1709 Cell *sub(Node **a, int nnn) /* substitute command */ 1710 { 1711 char *sptr, *pb, *q; 1712 Cell *x, *y, *result; 1713 char *t, *buf; 1714 void *p; 1715 int bufsz = recsize; 1716 1717 if ((buf = (char *) malloc(bufsz)) == NULL) 1718 FATAL("out of memory in sub"); 1719 x = execute(a[3]); /* target string */ 1720 t = getsval(x); 1721 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ 1722 p = (void *) a[1]; /* regular expression */ 1723 else { 1724 y = execute(a[1]); 1725 p = compre(getsval(y)); 1726 tempfree(y); 1727 } 1728 y = execute(a[2]); /* replacement string */ 1729 result = False; 1730 if (pmatch(p, t, t)) { 1731 sptr = t; 1732 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub"); 1733 pb = buf; 1734 while (sptr < patbeg) 1735 *pb++ = *sptr++; 1736 sptr = getsval(y); 1737 while (*sptr != 0) { 1738 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub"); 1739 if (*sptr == '\\') { 1740 backsub(&pb, &sptr); 1741 } else if (*sptr == '&') { 1742 sptr++; 1743 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub"); 1744 for (q = patbeg; q < patbeg+patlen; ) 1745 *pb++ = *q++; 1746 } else 1747 *pb++ = *sptr++; 1748 } 1749 *pb = '\0'; 1750 if (pb > buf + bufsz) 1751 FATAL("sub result1 %.30s too big; can't happen", buf); 1752 sptr = patbeg + patlen; 1753 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) { 1754 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub"); 1755 while ((*pb++ = *sptr++) != 0) 1756 ; 1757 } 1758 if (pb > buf + bufsz) 1759 FATAL("sub result2 %.30s too big; can't happen", buf); 1760 setsval(x, buf); /* BUG: should be able to avoid copy */ 1761 result = True;; 1762 } 1763 tempfree(x); 1764 tempfree(y); 1765 free(buf); 1766 return result; 1767 } 1768 1769 Cell *gsub(Node **a, int nnn) /* global substitute */ 1770 { 1771 Cell *x, *y; 1772 char *rptr, *sptr, *t, *pb, *c; 1773 char *buf; 1774 void *p; 1775 int mflag, num; 1776 int bufsz = recsize; 1777 1778 if ((buf = (char *)malloc(bufsz)) == NULL) 1779 FATAL("out of memory in gsub"); 1780 mflag = 0; /* if mflag == 0, can replace empty string */ 1781 num = 0; 1782 x = execute(a[3]); /* target string */ 1783 c = t = getsval(x); 1784 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ 1785 p = (void *) a[1]; /* regular expression */ 1786 else { 1787 y = execute(a[1]); 1788 p = compre(getsval(y)); 1789 tempfree(y); 1790 } 1791 y = execute(a[2]); /* replacement string */ 1792 if (pmatch(p, t, c)) { 1793 pb = buf; 1794 rptr = getsval(y); 1795 do { 1796 if (patlen == 0 && *patbeg != 0) { /* matched empty string */ 1797 if (mflag == 0) { /* can replace empty */ 1798 num++; 1799 sptr = rptr; 1800 while (*sptr != 0) { 1801 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub"); 1802 if (*sptr == '\\') { 1803 backsub(&pb, &sptr); 1804 } else if (*sptr == '&') { 1805 char *q; 1806 sptr++; 1807 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub"); 1808 for (q = patbeg; q < patbeg+patlen; ) 1809 *pb++ = *q++; 1810 } else 1811 *pb++ = *sptr++; 1812 } 1813 } 1814 if (*c == 0) /* at end */ 1815 goto done; 1816 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub"); 1817 *pb++ = *c++; 1818 if (pb > buf + bufsz) /* BUG: not sure of this test */ 1819 FATAL("gsub result0 %.30s too big; can't happen", buf); 1820 mflag = 0; 1821 } 1822 else { /* matched nonempty string */ 1823 num++; 1824 sptr = c; 1825 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub"); 1826 while (sptr < patbeg) 1827 *pb++ = *sptr++; 1828 sptr = rptr; 1829 while (*sptr != 0) { 1830 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub"); 1831 if (*sptr == '\\') { 1832 backsub(&pb, &sptr); 1833 } else if (*sptr == '&') { 1834 char *q; 1835 sptr++; 1836 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub"); 1837 for (q = patbeg; q < patbeg+patlen; ) 1838 *pb++ = *q++; 1839 } else 1840 *pb++ = *sptr++; 1841 } 1842 c = patbeg + patlen; 1843 if ((c[-1] == 0) || (*c == 0)) 1844 goto done; 1845 if (pb > buf + bufsz) 1846 FATAL("gsub result1 %.30s too big; can't happen", buf); 1847 mflag = 1; 1848 } 1849 } while (pmatch(p, t, c)); 1850 sptr = c; 1851 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub"); 1852 while ((*pb++ = *sptr++) != 0) 1853 ; 1854 done: if (pb > buf + bufsz) 1855 FATAL("gsub result2 %.30s too big; can't happen", buf); 1856 *pb = '\0'; 1857 setsval(x, buf); /* BUG: should be able to avoid copy + free */ 1858 } 1859 tempfree(x); 1860 tempfree(y); 1861 x = gettemp(); 1862 x->tval = NUM; 1863 x->fval = num; 1864 free(buf); 1865 return(x); 1866 } 1867 1868 void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */ 1869 { /* sptr[0] == '\\' */ 1870 char *pb = *pb_ptr, *sptr = *sptr_ptr; 1871 1872 if (sptr[1] == '\\') { 1873 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */ 1874 *pb++ = '\\'; 1875 *pb++ = '&'; 1876 sptr += 4; 1877 } else if (sptr[2] == '&') { /* \\& -> \ + matched */ 1878 *pb++ = '\\'; 1879 sptr += 2; 1880 } else { /* \\x -> \\x */ 1881 *pb++ = *sptr++; 1882 *pb++ = *sptr++; 1883 } 1884 } else if (sptr[1] == '&') { /* literal & */ 1885 sptr++; 1886 *pb++ = *sptr++; 1887 } else /* literal \ */ 1888 *pb++ = *sptr++; 1889 1890 *pb_ptr = pb; 1891 *sptr_ptr = sptr; 1892 } 1893