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