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 }