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