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