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