Print this page
3731 Update nawk to version 20121220


   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++;


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 }





























   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 /*
  27  * Copyright (C) Lucent Technologies 1997
  28  * All Rights Reserved
  29  *
  30  * Permission to use, copy, modify, and distribute this software and
  31  * its documentation for any purpose and without fee is hereby
  32  * granted, provided that the above copyright notice appear in all
  33  * copies and that both that the copyright notice and this
  34  * permission notice and warranty disclaimer appear in supporting
  35  * documentation, and that the name Lucent Technologies or any of
  36  * its entities not be used in advertising or publicity pertaining
  37  * to distribution of the software without specific, written prior
  38  * permission.
  39  *
  40  * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  41  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  42  * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
  43  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  44  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  45  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  46  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
  47  * THIS SOFTWARE.
  48  */
  49 
  50 #define tempfree(x)     if (istemp(x)) tfree(x);


  51 
  52 #define DEBUG





  53 #include <setjmp.h>
  54 #include <math.h>
  55 #include <time.h>
  56 #include "awk.h"
  57 #include "y.tab.h"
  58 
  59 static  Cell    *execute(Node *);
  60 static  Cell    *gettemp(void);
  61 static  Cell    *copycell(Cell *);
  62 static  FILE    *openfile(int, const uchar *);
  63 static  FILE    *redirect(int, Node *);
  64 static  const char *filename(FILE *);
  65 static  void    flush_all(void);
  66 
  67 static jmp_buf env;
  68 extern  Awkfloat        srand_seed;
  69 
  70 Node    *winner = NULL; /* root of parse tree */







  71 
  72 static Cell     *tmps;  /* free temporary cells for execution */
  73 static Cell     truecell        = { OBOOL, BTRUE, 0, 0, 1.0, NUM };
  74 Cell    *True   = &truecell;
  75 static Cell     falsecell       = { OBOOL, BFALSE, 0, 0, 0.0, NUM };
  76 Cell    *False  = &falsecell;
  77 static Cell     breakcell       = { OJUMP, JBREAK, 0, 0, 0.0, NUM };
  78 Cell    *jbreak = &breakcell;
  79 static Cell     contcell        = { OJUMP, JCONT, 0, 0, 0.0, NUM };
  80 Cell    *jcont  = &contcell;
  81 static Cell     nextcell        = { OJUMP, JNEXT, 0, 0, 0.0, NUM };
  82 Cell    *jnext  = &nextcell;
  83 static Cell     nextfilecell    = { OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
  84 Cell    *jnextfile      = &nextfilecell;
  85 static Cell     exitcell        = { OJUMP, JEXIT, 0, 0, 0.0, NUM };
  86 Cell    *jexit  = &exitcell;
  87 static Cell     retcell         = { OJUMP, JRET, 0, 0, 0.0, NUM };
  88 Cell    *jret   = &retcell;
  89 static Cell     tempcell        = { OCELL, CTEMP, 0, (uchar *)"", 0.0, NUM|
  90     STR|DONTFREE};
  91 
  92 Node    *curnode = NULL;        /* the node being executed, for debugging */
  93 
  94 static  void    tfree(Cell *);
  95 static  void    closeall(void);
  96 static  double  ipow(double, int);
  97 static  void    stdinit(void);
  98 
  99 /*
 100  * buffer memory management
 101  *
 102  * pbuf:    address of pointer to buffer being managed
 103  * psiz:    address of buffer size variable
 104  * minlen:  minimum length of buffer needed
 105  * quantum: buffer size quantum
 106  * pbptr:   address of movable pointer into buffer, or 0 if none
 107  * whatrtn: name of the calling routine if failure should cause fatal error
 108  *
 109  * return   0 for realloc failure, !=0 for success
 110  */
 111 int adjbuf(uchar **pbuf, size_t *psiz, int minlen, int quantum, uchar **pbptr,
 112     const char *whatrtn)
 113 {
 114         if (minlen > *psiz) {
 115                 uchar *tbuf;
 116                 int rminlen = quantum ? minlen % quantum : 0;
 117                 int boff = pbptr ? *pbptr - *pbuf : 0;
 118                 /* round up to next multiple of quantum */
 119                 if (rminlen)
 120                         minlen += quantum - rminlen;
 121                 tbuf = (uchar *)realloc(*pbuf, minlen);
 122                 dprintf(("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn,
 123                     *psiz, minlen, (void *)*pbuf, (void *)tbuf));
 124                 if (tbuf == NULL) {
 125                         if (whatrtn)
 126                                 FATAL("out of memory in %s", whatrtn);
 127                         return (0);
 128                 }
 129                 *pbuf = (uchar *)tbuf;
 130                 *psiz = minlen;
 131                 if (pbptr)
 132                         *pbptr = tbuf + boff;
 133         }
 134         return (1);
 135 }
 136 
 137 void
 138 run(Node *a)            /* execution of parse tree starts here */
 139 {
 140         stdinit();
 141         (void) execute(a);
 142         closeall();
 143 }
 144 
 145 static Cell *
 146 execute(Node *u)        /* execute a node of the parse tree */
 147 {
 148         Cell *(*proc)(Node **, int);
 149         Cell *x;
 150         Node *a;
 151 
 152         if (u == NULL)
 153                 return (True);
 154         for (a = u; ; a = a->nnext) {
 155                 curnode = a;
 156                 if (isvalue(a)) {
 157                         x = (Cell *)(a->narg[0]);
 158                         if (isfld(x) && !donefld)
 159                                 fldbld();
 160                         else if (isrec(x) && !donerec)
 161                                 recbld();
 162                         return (x);
 163                 }
 164                 /* probably a Cell* but too risky to print */
 165                 if (notlegal(a->nobj))
 166                         FATAL("illegal statement");
 167                 proc = proctab[a->nobj-FIRSTTOKEN];
 168                 x = (*proc)(a->narg, a->nobj);
 169                 if (isfld(x) && !donefld)
 170                         fldbld();
 171                 else if (isrec(x) && !donerec)
 172                         recbld();
 173                 if (isexpr(a))
 174                         return (x);

 175                 if (isjump(x))
 176                         return (x);
 177                 if (a->nnext == (Node *)NULL)
 178                         return (x);
 179                 tempfree(x);
 180         }
 181 }
 182 
 183 /*ARGSUSED*/
 184 Cell *
 185 program(Node **a, int n)        /* execute an awk program */
 186 {                               /* a[0] = BEGIN, a[1] = body, a[2] = END */
 187         Cell *x;
 188 
 189         if (setjmp(env) != 0)
 190                 goto ex;
 191         if (a[0]) {             /* BEGIN */
 192                 x = execute(a[0]);
 193                 if (isexit(x))
 194                         return (True);
 195                 if (isjump(x)) {
 196                         FATAL(
 197                 "illegal break, continue, next or nextfile from BEGIN");
 198                 }
 199                 tempfree(x);
 200         }
 201 
 202         if (a[1] || a[2]) {
 203                 while (getrec(&record, &record_size, 1) > 0) {
 204                         x = execute(a[1]);
 205                         if (isexit(x))
 206                                 break;
 207                         tempfree(x);
 208                 }
 209         }
 210 ex:
 211         if (setjmp(env) != 0)   /* handles exit within END */
 212                 goto ex1;
 213         if (a[2]) {             /* END */
 214                 x = execute(a[2]);
 215                 if (isbreak(x) || isnext(x) || iscont(x))
 216                         FATAL(
 217                 "illegal break, continue, next or nextfile from END");
 218                 tempfree(x);

 219         }
 220 ex1:
 221         return (True);
 222 }
 223 
 224 struct Frame {  /* stack frame for awk function calls */
 225         int nargs;      /* number of arguments in this call */
 226         Cell *fcncell;  /* pointer to Cell for function */
 227         Cell **args;    /* pointer to array of arguments after execute */
 228         Cell *retval;   /* return value */
 229 };
 230 
 231 #define NARGS   50      /* max args in a call */
 232 
 233 struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
 234 int     nframe = 0;             /* number of frames allocated */
 235 struct Frame *fp = NULL;        /* frame pointer. bottom level unused */
 236 
 237 /*ARGSUSED*/
 238 Cell *
 239 call(Node **a, int n)   /* function call.  very kludgy and fragile */
 240 {
 241         static Cell newcopycell =
 242             { OCELL, CCOPY, 0, (uchar *) "", 0.0, NUM|STR|DONTFREE };
 243         int i, ncall, ndef;
 244         /* handles potential double freeing when fcn & param share a tempcell */
 245         int freed = 0;
 246         Node *x;
 247         Cell *args[NARGS], *oargs[NARGS];       /* BUG: fixed size arrays */
 248         Cell *y, *z, *fcn;
 249         uchar *s;
 250 
 251         fcn = execute(a[0]);    /* the function itself */
 252         s = fcn->nval;
 253         if (!isfcn(fcn))
 254                 FATAL("calling undefined function %s", s);
 255         if (frame == NULL) {
 256                 fp = frame = (struct Frame *)calloc(nframe += 100,
 257                     sizeof (struct Frame));
 258                 if (frame == NULL) {
 259                         FATAL("out of space for stack frames calling %s", s);

 260                 }
 261         }
 262         for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
 263                 ncall++;
 264         ndef = (int)fcn->fval;                       /* args in defn */
 265         dprintf(("calling %s, %d args (%d in defn), fp=%d\n",
 266             s, ncall, ndef, (int)(fp-frame)));
 267 
 268         if (ncall > ndef) {
 269                 WARNING("function %s called with %d args, uses only %d",
 270                     s, ncall, ndef);
 271         }
 272         if (ncall + ndef > NARGS) {
 273                 FATAL("function %s has %d arguments, limit %d",
 274                     s, ncall + ndef, NARGS);
 275         }
 276         for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {
 277                 /* get call args */
 278                 dprintf(("evaluate args[%d], fp=%d:\n", i, (int)(fp-frame)));
 279                 y = execute(x);
 280                 oargs[i] = y;
 281                 dprintf(("args[%d]: %s %f <%s>, t=%o\n",
 282                     i, y->nval, y->fval,
 283                     isarr(y) ? "(array)" : (char *)y->sval, y->tval));
 284                 if (isfcn(y)) {
 285                         FATAL("can't use function %s as argument in %s",
 286                             y->nval, s);
 287                 }
 288                 if (isarr(y))
 289                         args[i] = y;    /* arrays by ref */
 290                 else
 291                         args[i] = copycell(y);
 292                 tempfree(y);
 293         }
 294         for (; i < ndef; i++) { /* add null args for ones not provided */
 295                 args[i] = gettemp();
 296                 *args[i] = newcopycell;
 297         }
 298         fp++;   /* now ok to up frame */
 299         if (fp >= frame + nframe) {
 300                 int dfp = fp - frame;   /* old index */
 301                 frame = (struct Frame *)
 302                     realloc(frame, (nframe += 100) * sizeof (struct Frame));
 303                 if (frame == NULL)
 304                         FATAL("out of space for stack frames in %s", s);
 305                 fp = frame + dfp;
 306         }
 307         fp->fcncell = fcn;
 308         fp->args = args;
 309         fp->nargs = ndef;    /* number defined with (excess are locals) */
 310         fp->retval = gettemp();
 311 
 312         dprintf(("start exec of %s, fp=%d\n", s, (int)(fp-frame)));
 313         /*LINTED align*/
 314         y = execute((Node *)(fcn->sval));    /* execute body */
 315         dprintf(("finished exec of %s, fp=%d\n", s, (int)(fp-frame)));
 316 
 317         for (i = 0; i < ndef; i++) {
 318                 Cell *t = fp->args[i];
 319                 if (isarr(t)) {
 320                         if (t->csub == CCOPY) {
 321                                 if (i >= ncall) {
 322                                         freesymtab(t);
 323                                         t->csub = CTEMP;
 324                                         tempfree(t);
 325                                 } else {
 326                                         oargs[i]->tval = t->tval;
 327                                         oargs[i]->tval &= ~(STR|NUM|DONTFREE);
 328                                         oargs[i]->sval = t->sval;
 329                                         tempfree(t);
 330                                 }
 331                         }
 332                 } else if (t != y) {    /* kludge to prevent freeing twice */
 333                         t->csub = CTEMP;
 334                         tempfree(t);
 335                 } else if (t == y && t->csub == CCOPY) {
 336                         t->csub = CTEMP;
 337                         tempfree(t);
 338                         freed = 1;
 339                 }
 340         }
 341         tempfree(fcn);
 342         if (isexit(y) || isnext(y))
 343                 return (y);
 344         if (freed == 0) {
 345                 tempfree(y);    /* don't free twice! */
 346         }
 347         z = fp->retval;                      /* return value */
 348         dprintf(("%s returns %g |%s| %o\n",
 349             s, getfval(z), getsval(z), z->tval));
 350         fp--;
 351         return (z);
 352 }
 353 
 354 static Cell *
 355 copycell(Cell *x)       /* make a copy of a cell in a temp */
 356 {
 357         Cell *y;
 358 
 359         y = gettemp();
 360         y->csub = CCOPY;     /* prevents freeing until call is over */
 361         y->nval = x->nval;        /* BUG? */
 362         if (isstr(x))
 363                 y->sval = tostring(x->sval);
 364         y->fval = x->fval;
 365         /* copy is not constant or field is DONTFREE right? */
 366         y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);
 367         return (y);
 368 }
 369 

 370 Cell *
 371 arg(Node **a, int n)            /* nth argument of a function */
 372 {

 373 
 374         n = ptoi(a[0]); /* argument number, counting from 0 */
 375         dprintf(("arg(%d), fp->nargs=%d\n", n, fp->nargs));
 376         if (n + 1 > fp->nargs) {
 377                 FATAL("argument #%d of function %s was not supplied",
 378                     n + 1, fp->fcncell->nval);
 379         }
 380         return (fp->args[n]);
 381 }
 382 
 383 Cell *
 384 jump(Node **a, int n)   /* break, continue, next, nextfile, return */
 385 {
 386         Cell *y;
 387 
 388         switch (n) {
 389         case EXIT:
 390                 if (a[0] != NULL) {
 391                         y = execute(a[0]);
 392                         errorflag = (int)getfval(y);
 393                         tempfree(y);
 394                 }
 395                 longjmp(env, 1);
 396                 /*NOTREACHED*/
 397         case RETURN:
 398                 if (a[0] != NULL) {
 399                         y = execute(a[0]);
 400                         if ((y->tval & (STR|NUM)) == (STR|NUM)) {
 401                                 (void) setsval(fp->retval, getsval(y));
 402                                 fp->retval->fval = getfval(y);
 403                                 fp->retval->tval |= NUM;
 404                         } else if (y->tval & STR)
 405                                 (void) setsval(fp->retval, getsval(y));
 406                         else if (y->tval & NUM)
 407                                 (void) setfval(fp->retval, getfval(y));
 408                         else            /* can't happen */
 409                                 FATAL("bad type variable %d", y->tval);
 410                         tempfree(y);
 411                 }
 412                 return (jret);
 413         case NEXT:
 414                 return (jnext);
 415         case NEXTFILE:
 416                 nextfile();
 417                 return (jnextfile);
 418         case BREAK:
 419                 return (jbreak);
 420         case CONTINUE:
 421                 return (jcont);
 422         default:        /* can't happen */
 423                 FATAL("illegal jump type %d", n);
 424         }
 425         /*NOTREACHED*/
 426         return (NULL);
 427 }
 428 
 429 /*
 430  * get next line from specific input
 431  *
 432  * a[0] is variable, a[1] is operator, a[2] is filename
 433  */
 434 Cell *
 435 awkgetline(Node **a, int n)
 436 {
 437         Cell *r, *x;
 438         extern Cell **fldtab;

 439         FILE *fp;
 440         uchar *buf;
 441         size_t bufsize = record_size;
 442         int mode;
 443 
 444         if ((buf = (uchar *)malloc(bufsize)) == NULL)
 445                 FATAL("out of memory in getline");
 446 
 447         (void) fflush(stdout);  /* in case someone is waiting for a prompt */
 448         r = gettemp();
 449         if (a[1] != NULL) {             /* getline < file */
 450                 x = execute(a[2]);              /* filename */
 451                 mode = ptoi(a[1]);
 452                 if (mode == '|')        /* input pipe */
 453                         mode = LE;      /* arbitrary flag */
 454                 fp = openfile(mode, getsval(x));
 455                 tempfree(x);
 456                 if (fp == NULL)
 457                         n = -1;
 458                 else
 459                         n = readrec(&buf, &bufsize, fp);

 460                 if (a[0] != NULL) {     /* getline var <file */
 461                         x = execute(a[0]);
 462                         (void) setsval(x, buf);
 463                         tempfree(x);
 464                 } else {                        /* getline <file */
 465                         (void) setsval(fldtab[0], buf);
 466                         if (is_number(fldtab[0]->sval)) {
 467                                 fldtab[0]->fval = atof((char *)fldtab[0]->sval);
 468                                 fldtab[0]->tval |= NUM;




 469                         }
 470                 }


 471         } else {                        /* bare getline; use current input */
 472                 if (a[0] == NULL)       /* getline */
 473                         n = getrec(&record, &record_size, 1);
 474                 else {                  /* getline var */
 475                         n = getrec(&buf, &bufsize, 0);
 476                         x = execute(a[0]);
 477                         (void) setsval(x, buf);
 478                         tempfree(x);
 479                 }
 480         }
 481         (void) setfval(r, (Awkfloat)n);
 482         free(buf);
 483         return (r);
 484 }
 485 
 486 /*ARGSUSED*/
 487 Cell *
 488 getnf(Node **a, int n)          /* get NF */
 489 {
 490         if (donefld == 0)
 491                 fldbld();
 492         return ((Cell *)a[0]);
 493 }
 494 
 495 /*ARGSUSED*/
 496 Cell *
 497 array(Node **a, int n)  /* a[0] is symtab, a[1] is list of subscripts */
 498 {
 499         Cell *x, *y, *z;
 500         uchar *s;
 501         Node *np;
 502         uchar *buf;
 503         size_t bufsz = record_size;
 504         size_t nsub = strlen((char *)*SUBSEP);
 505 
 506         if ((buf = (uchar *)malloc(bufsz)) == NULL)
 507                 FATAL("out of memory in array");
 508 
 509         x = execute(a[0]);      /* Cell* for symbol table */

 510         buf[0] = '\0';


 511         for (np = a[1]; np; np = np->nnext) {
 512                 y = execute(np);        /* subscript */
 513                 s = getsval(y);
 514                 if (!adjbuf(&buf, &bufsz, strlen((char *)buf) +
 515                     strlen((char *)s) + nsub + 1, record_size, 0, "array"))
 516                         FATAL("out of memory for %s[%s...]", x->nval, buf);
 517                 (void) strcat((char *)buf, (char *)s);
 518                 if (np->nnext)
 519                         (void) strcat((char *)buf, (char *)*SUBSEP);
 520                 tempfree(y);



 521         }
 522         if (!isarr(x)) {
 523                 dprintf(("making %s into an array\n", x->nval));
 524                 if (freeable(x))
 525                         xfree(x->sval);
 526                 x->tval &= ~(STR|NUM|DONTFREE);
 527                 x->tval |= ARR;
 528                 x->sval = (uchar *)makesymtab(NSYMTAB);
 529         }
 530         /*LINTED align*/
 531         z = setsymtab(buf, (uchar *)"", 0.0, STR|NUM, (Array *)x->sval);
 532         z->ctype = OCELL;
 533         z->csub = CVAR;
 534         tempfree(x);
 535         free(buf);
 536         return (z);
 537 }
 538 
 539 /*ARGSUSED*/
 540 Cell *
 541 awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
 542 {
 543         Cell *x, *y;
 544         Node *np;
 545         uchar *s;
 546         size_t nsub = strlen((char *)*SUBSEP);
 547 
 548         x = execute(a[0]);      /* Cell* for symbol table */
 549         if (!isarr(x))
 550                 return (True);
 551         if (a[1] == 0) {        /* delete the elements, not the table */
 552                 freesymtab(x);
 553                 x->tval &= ~STR;
 554                 x->tval |= ARR;
 555                 x->sval = (uchar *)makesymtab(NSYMTAB);
 556         } else {
 557                 size_t bufsz = record_size;
 558                 uchar *buf;
 559                 if ((buf = (uchar *)malloc(bufsz)) == NULL)
 560                         FATAL("out of memory in delete");
 561                 buf[0] = '\0';


 562                 for (np = a[1]; np; np = np->nnext) {
 563                         y = execute(np);        /* subscript */
 564                         s = getsval(y);
 565                         if (!adjbuf(&buf, &bufsz, strlen((char *)buf) +
 566                             strlen((char *)s) + nsub + 1, record_size, 0,
 567                             "awkdelete")) {
 568                                 FATAL("out of memory deleting %s[%s...]",
 569                                     x->nval, buf);
 570                         }
 571                         (void) strcat((char *)buf, (char *)s);
 572                         if (np->nnext)
 573                                 (void) strcat((char *)buf, (char *)*SUBSEP);
 574                         tempfree(y);
 575                 }
 576                 freeelem(x, buf);

 577                 free(buf);
 578         }
 579         tempfree(x);
 580         return (True);
 581 }
 582 
 583 /*ARGSUSED*/
 584 Cell *
 585 intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
 586 {
 587         Cell *x, *ap, *k;
 588         Node *p;
 589         uchar *buf;
 590         uchar *s;
 591         size_t bufsz = record_size;
 592         size_t nsub = strlen((char *)*SUBSEP);
 593 
 594         ap = execute(a[1]);     /* array name */
 595         if (!isarr(ap)) {
 596                 dprintf(("making %s into an array\n", ap->nval));
 597                 if (freeable(ap))
 598                         xfree(ap->sval);
 599                 ap->tval &= ~(STR|NUM|DONTFREE);
 600                 ap->tval |= ARR;
 601                 ap->sval = (uchar *)makesymtab(NSYMTAB);
 602         }
 603         if ((buf = (uchar *)malloc(bufsz)) == NULL) {
 604                 FATAL("out of memory in intest");
 605         }
 606         buf[0] = 0;


 607         for (p = a[0]; p; p = p->nnext) {
 608                 x = execute(p); /* expr */
 609                 s = getsval(x);
 610                 if (!adjbuf(&buf, &bufsz, strlen((char *)buf) +
 611                     strlen((char *)s) + nsub + 1, record_size, 0, "intest"))
 612                         FATAL("out of memory deleting %s[%s...]", x->nval, buf);
 613                 (void) strcat((char *)buf, (char *)s);
 614                 tempfree(x);
 615                 if (p->nnext)
 616                         (void) strcat((char *)buf, (char *)*SUBSEP);



 617         }
 618         /*LINTED align*/
 619         k = lookup(buf, (Array *)ap->sval);
 620         tempfree(ap);
 621         free(buf);
 622         if (k == NULL)
 623                 return (False);
 624         else
 625                 return (True);
 626 }
 627 

 628 Cell *
 629 matchop(Node **a, int n)        /* ~ and match() */
 630 {
 631         Cell *x, *y;
 632         uchar *s, *t;
 633         int i;
 634         fa *pfa;
 635         int (*mf)(fa *, const uchar *) = match, mode = 0;
 636 
 637         if (n == MATCHFCN) {
 638                 mf = pmatch;
 639                 mode = 1;
 640         }
 641         x = execute(a[1]);      /* a[1] = target text */
 642         s = getsval(x);
 643         if (a[0] == 0)          /* a[1] == 0: already-compiled reg expr */
 644                 i = (*mf)((fa *)a[2], s);
 645         else {
 646                 y = execute(a[2]);      /* a[2] = regular expr */
 647                 t = getsval(y);
 648                 pfa = makedfa(t, mode);
 649                 i = (*mf)(pfa, s);
 650                 tempfree(y);
 651         }
 652         tempfree(x);
 653         if (n == MATCHFCN) {
 654                 int start = patbeg - s + 1;
 655                 if (patlen < 0)
 656                         start = 0;
 657                 (void) setfval(rstartloc, (Awkfloat)start);
 658                 (void) setfval(rlengthloc, (Awkfloat)patlen);
 659                 x = gettemp();
 660                 x->tval = NUM;
 661                 x->fval = start;
 662                 return (x);
 663         } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
 664                 return (True);
 665         else
 666                 return (False);
 667 }
 668 

 669 Cell *
 670 boolop(Node **a, int n)         /* a[0] || a[1], a[0] && a[1], !a[0] */
 671 {
 672         Cell *x, *y;
 673         int i;
 674 
 675         x = execute(a[0]);
 676         i = istrue(x);
 677         tempfree(x);
 678         switch (n) {
 679         case BOR:
 680                 if (i)
 681                         return (True);
 682                 y = execute(a[1]);
 683                 i = istrue(y);
 684                 tempfree(y);
 685                 return (i ? True : False);
 686         case AND:
 687                 if (!i)
 688                         return (False);
 689                 y = execute(a[1]);
 690                 i = istrue(y);
 691                 tempfree(y);
 692                 return (i ? True : False);
 693         case NOT:
 694                 return (i ? False : True);
 695         default:        /* can't happen */
 696                 FATAL("unknown boolean operator %d", n);
 697         }
 698         /*NOTREACHED*/
 699         return (NULL);
 700 }
 701 
 702 Cell *
 703 relop(Node **a, int n)          /* a[0 < a[1], etc. */
 704 {
 705         int i;
 706         Cell *x, *y;
 707         Awkfloat j;
 708 
 709         x = execute(a[0]);
 710         y = execute(a[1]);
 711         if (x->tval & NUM && y->tval & NUM) {
 712                 j = x->fval - y->fval;
 713                 i = j < 0 ? -1: (j > 0 ? 1: 0);
 714         } else {
 715                 i = strcmp((char *)getsval(x), (char *)getsval(y));
 716         }
 717         tempfree(x);
 718         tempfree(y);
 719         switch (n) {
 720         case LT:        return (i < 0 ? True : False);
 721         case LE:        return (i <= 0 ? True : False);
 722         case NE:        return (i != 0 ? True : False);
 723         case EQ:        return (i == 0 ? True : False);
 724         case GE:        return (i >= 0 ? True : False);
 725         case GT:        return (i > 0 ? True : False);
 726         default:        /* can't happen */
 727                 FATAL("unknown relational operator %d", n);
 728         }
 729         /*NOTREACHED*/
 730         return (False);
 731 }
 732 
 733 static void
 734 tfree(Cell *a)          /* free a tempcell */
 735 {
 736         if (freeable(a)) {
 737                 dprintf(("freeing %s %s %o\n", (char *)a->nval,
 738                     (char *)a->sval, a->tval));


 739                 xfree(a->sval);
 740         }
 741         if (a == tmps)
 742                 FATAL("tempcell list is curdled");
 743         a->cnext = tmps;
 744         tmps = a;
 745 }
 746 
 747 static Cell *
 748 gettemp(void)           /* get a tempcell */
 749 {
 750         int i;
 751         Cell *x;
 752 
 753         if (!tmps) {
 754                 tmps = (Cell *)calloc(100, sizeof (Cell));
 755                 if (!tmps)
 756                         FATAL("out of space for temporaries");
 757                 for (i = 1; i < 100; i++)
 758                         tmps[i - 1].cnext = &tmps[i];
 759                 tmps[i - 1].cnext = 0;
 760         }
 761         x = tmps;
 762         tmps = x->cnext;
 763         *x = tempcell;


 764         return (x);
 765 }
 766 
 767 /*ARGSUSED*/
 768 Cell *
 769 indirect(Node **a, int n)       /* $( a[0] ) */
 770 {
 771         Awkfloat val;
 772         Cell *x;
 773         int m;
 774         uchar *s;
 775 
 776         x = execute(a[0]);
 777         /* freebsd: defend against super large field numbers */
 778         val = getfval(x);
 779         if ((Awkfloat)INT_MAX < val)
 780                 FATAL("trying to access out of range field %s", x->nval);
 781         m = (int)val;
 782         if (m == 0 && !is_number(s = getsval(x)))       /* suspicion! */
 783                 FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
 784                 /* BUG: can x->nval ever be null??? */
 785         tempfree(x);
 786         x = fieldadr(m);
 787         x->ctype = OCELL;    /* BUG?  why are these needed? */
 788         x->csub = CFLD;
 789         return (x);
 790 }
 791 
 792 /*ARGSUSED*/
 793 Cell *
 794 substr(Node **a, int nnn)       /* substr(a[0], a[1], a[2]) */
 795 {
 796         int k, m, n;
 797         uchar *s;
 798         int temp;
 799         Cell *x, *y, *z = 0;
 800 
 801         x = execute(a[0]);
 802         y = execute(a[1]);
 803         if (a[2] != 0)
 804                 z = execute(a[2]);
 805         s = getsval(x);
 806         k = strlen((char *)s) + 1;
 807         if (k <= 1) {
 808                 tempfree(x);
 809                 tempfree(y);
 810                 if (a[2] != 0) {
 811                         tempfree(z);
 812                 }
 813                 x = gettemp();
 814                 (void) setsval(x, (uchar *)"");
 815                 return (x);
 816         }
 817         m = (int)getfval(y);
 818         if (m <= 0)
 819                 m = 1;
 820         else if (m > k)
 821                 m = k;
 822         tempfree(y);
 823         if (a[2] != 0) {
 824                 n = (int)getfval(z);
 825                 tempfree(z);
 826         } else
 827                 n = k - 1;
 828         if (n < 0)
 829                 n = 0;
 830         else if (n > k - m)
 831                 n = k - m;
 832         dprintf(("substr: m=%d, n=%d, s=%s\n", m, n, s));
 833         y = gettemp();
 834         temp = s[n + m - 1];    /* with thanks to John Linderman */
 835         s[n + m - 1] = '\0';
 836         (void) setsval(y, s + m - 1);
 837         s[n + m - 1] = temp;
 838         tempfree(x);
 839         return (y);
 840 }
 841 
 842 /*ARGSUSED*/
 843 Cell *
 844 sindex(Node **a, int nnn)       /* index(a[0], a[1]) */
 845 {
 846         Cell *x, *y, *z;
 847         uchar *s1, *s2, *p1, *p2, *q;
 848         Awkfloat v = 0.0;
 849 
 850         x = execute(a[0]);
 851         s1 = getsval(x);
 852         y = execute(a[1]);
 853         s2 = getsval(y);
 854 
 855         z = gettemp();
 856         for (p1 = s1; *p1 != '\0'; p1++) {
 857                 for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++)
 858                         ;
 859                 if (*p2 == '\0') {
 860                         v = (Awkfloat)(p1 - s1 + 1);    /* origin 1 */
 861                         break;
 862                 }
 863         }
 864         tempfree(x);
 865         tempfree(y);
 866         (void) setfval(z, v);
 867         return (z);
 868 }
 869 
 870 #define MAXNUMSIZE      50
 871 
 872 /*
 873  * printf-like conversions
 874  */
 875 int
 876 format(uchar **bufp, size_t *pbufsize, const uchar *s, Node *a)
 877 {
 878         uchar *fmt;
 879         uchar *p, *t;
 880         const uchar *os;
 881         Cell *x;
 882         int flag = 0, n;
 883         int fmtwd; /* format width */
 884         size_t fmtsz = record_size;
 885         uchar_t *buf = *bufp;
 886         size_t bufsize = *pbufsize;
 887 


 888         os = s;
 889         p = buf;
 890         if ((fmt = (uchar *)malloc(fmtsz)) == NULL)
 891                 FATAL("out of memory in format()");
 892         while (*s) {
 893                 (void) adjbuf(&buf, &bufsize, MAXNUMSIZE + 1 + p - buf,
 894                     record_size, &p, "format1");
 895                 if (*s != '%') {
 896                         *p++ = *s++;

 897                         continue;
 898                 }
 899                 if (*(s+1) == '%') {
 900                         *p++ = '%';

 901                         s += 2;
 902                         continue;
 903                 }
 904                 /*
 905                  * have to be real careful in case this is a huge number,
 906                  * eg, %100000d
 907                  */
 908                 fmtwd = atoi((char *)s + 1);
 909                 if (fmtwd < 0)
 910                         fmtwd = -fmtwd;
 911                 (void) adjbuf(&buf, &bufsize, fmtwd + 1 + p - buf,
 912                     record_size, &p, "format2");
 913                 for (t = fmt; (*t++ = *s) != '\0'; s++) {
 914                         if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE + 1 + t - fmt,
 915                             record_size, &t, "format3"))
 916                                 FATAL(
 917                         "format item %.30s... ran format() out of memory", os);
 918                         if (isalpha((uchar)*s) && *s != 'l' && *s != 'h' &&
 919                             *s != 'L')
 920                                 break;  /* the ansi panoply */
 921                         if (*s == '*') {




 922                                 x = execute(a);
 923                                 a = a->nnext;
 924                                 (void) sprintf((char *)t - 1, "%d",
 925                                     fmtwd = (int)getfval(x));
 926                                 if (fmtwd < 0)
 927                                         fmtwd = -fmtwd;
 928                                 (void) adjbuf(&buf, &bufsize, fmtwd + 1 + p -
 929                                     buf, record_size, &p, "format");
 930                                 t = fmt + strlen((char *)fmt);
 931                                 tempfree(x);
 932                         }
 933                 }
 934                 *t = '\0';
 935                 if (fmtwd < 0)
 936                         fmtwd = -fmtwd;
 937                 (void) adjbuf(&buf, &bufsize, fmtwd + 1 + p - buf,
 938                     record_size, &p, "format4");
 939 
 940                 switch (*s) {
 941                 case 'f': case 'e': case 'g': case 'E': case 'G':
 942                         flag = 'f';
 943                         break;
 944                 case 'd': case 'i':
 945                         flag = 'd';
 946                         if (*(s-1) == 'l')
 947                                 break;
 948                         *(t-1) = 'l';
 949                         *t = 'd';
 950                         *++t = '\0';

 951                         break;
 952                 case 'o': case 'x': case 'X': case 'u':
 953                         flag = *(s-1) == 'l' ? 'd' : 'u';
 954                         break;
 955                 case 's':
 956                         flag = 's';
 957                         break;
 958                 case 'c':
 959                         flag = 'c';
 960                         break;
 961                 default:
 962                         WARNING("weird printf conversion %s", fmt);
 963                         flag = '?';
 964                         break;
 965                 }








 966                 if (a == NULL) {
 967                         FATAL(
 968         "not enough args in printf(%s)", os);
 969                 }
 970                 x = execute(a);
 971                 a = a->nnext;
 972                 n = MAXNUMSIZE;
 973                 if (fmtwd > n)
 974                         n = fmtwd;
 975                 (void) adjbuf(&buf, &bufsize, 1 + n + p - buf, record_size,
 976                     &p, "format5");
 977 
 978                 switch (flag) {
 979                 case '?':
 980                         /* unknown, so dump it too */
 981                         /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
 982                         (void) sprintf((char *)p, "%s", (char *)fmt);
 983                         t = getsval(x);
 984                         n = strlen((char *)t);
 985                         if (fmtwd > n)
 986                                 n = fmtwd;
 987                         (void) adjbuf(&buf, &bufsize, 1 + strlen((char *)p) +
 988                             n + p - buf, record_size, &p, "format6");
 989                         p += strlen((char *)p);
 990                         /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */
 991                         (void) sprintf((char *)p, "%s", t);
 992                         break;
 993                 case 'f':
 994                         /* LINTED E_SEC_PRINTF_VAR_FMT */
 995                         (void) sprintf((char *)p, (char *)fmt, getfval(x));
 996                         break;
 997                 case 'd':
 998                         /* LINTED E_SEC_PRINTF_VAR_FMT */
 999                         (void) sprintf((char *)p, (char *)fmt,
1000                             (long) getfval(x));
1001                         break;
1002                 case 'u':
1003                         /* LINTED E_SEC_PRINTF_VAR_FMT */
1004                         (void) sprintf((char *)p, (char *)fmt,
1005                             (int) getfval(x));
1006                         break;
1007                 case 's':
1008                         t = getsval(x);
1009                         n = strlen((char *)t);
1010                         if (fmtwd > n)
1011                                 n = fmtwd;
1012                         if (!adjbuf(&buf, &bufsize, 1+n+p-buf, record_size,
1013                             &p, "format7"))
1014                                 FATAL(
1015                 "huge string/format (%d chars) in printf %.30s... "
1016                 "ran format() out of memory", n, t);
1017                         /* LINTED E_SEC_PRINTF_VAR_FMT */
1018                         (void) sprintf((char *)p, (char *)fmt, t);
1019                         break;
1020                 case 'c':
1021                         if (isnum(x)) {
1022                                 if (getfval(x))
1023                                         /* LINTED E_SEC_PRINTF_VAR_FMT */
1024                                         (void) sprintf((char *)p, (char *)fmt,
1025                                             (int) getfval(x));
1026                                 else {
1027                                         *p++ = '\0'; /* explicit null byte */
1028                                         /* next output will start here */
1029                                         *p = '\0';
1030                                 }
1031                         } else {
1032                                 /* LINTED E_SEC_PRINTF_VAR_FMT */
1033                                 (void) sprintf((char *)p, (char *)fmt,
1034                                     getsval(x)[0]);
1035                         }
1036                         break;
1037                 default:
1038                         FATAL("can't happen: bad conversion %c in format()",
1039                             flag);
1040                 }
1041                 tempfree(x);
1042                 p += strlen((char *)p);




1043                 s++;
1044         }
1045         *p = '\0';
1046         free(fmt);
1047         for (; a; a = a->nnext)      /* evaluate any remaining args */
1048                 (void) execute(a);
1049         *bufp = buf;
1050         *pbufsize = bufsize;
1051         return (p - buf);
1052 }
1053 
1054 /*ARGSUSED*/
1055 Cell *
1056 awksprintf(Node **a, int n)     /* sprintf(a[0]) */
1057 {
1058         Cell *x;
1059         Node *y;
1060         uchar *buf;
1061         size_t bufsz = 3 * record_size;
1062 
1063         if ((buf = (uchar *)malloc(bufsz)) == NULL)
1064                 FATAL("out of memory in awksprintf");
1065         y = a[0]->nnext;
1066         x = execute(a[0]);
1067         if (format(&buf, &bufsz, getsval(x), y) == -1)
1068                 FATAL("sprintf string %.30s... too long.  can't happen.", buf);
1069         tempfree(x);
1070         x = gettemp();
1071         x->sval = buf;
1072         x->tval = STR;
1073         return (x);
1074 }
1075 
1076 /*ARGSUSED*/
1077 Cell *
1078 awkprintf(Node **a, int n)      /* printf */
1079 {       /* a[0] is list of args, starting with format string */
1080         /* a[1] is redirection operator, a[2] is redirection file */
1081         FILE *fp;
1082         Cell *x;
1083         Node *y;
1084         uchar *buf;
1085         int len;
1086         size_t bufsz = 3 * record_size;
1087 
1088         if ((buf = (uchar *)malloc(bufsz)) == NULL)
1089                 FATAL("out of memory in awkprintf");
1090         y = a[0]->nnext;
1091         x = execute(a[0]);
1092         if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
1093                 FATAL("printf string %.30s... too long.  can't happen.", buf);
1094         tempfree(x);
1095         if (a[1] == NULL) {
1096                 /* fputs(buf, stdout); */
1097                 (void) fwrite((char *)buf, len, 1, stdout);
1098                 if (ferror(stdout))
1099                         FATAL("write error on stdout");
1100         } else {
1101                 fp = redirect(ptoi(a[1]), a[2]);
1102                 /* fputs(buf, fp); */
1103                 (void) fwrite(buf, len, 1, fp);
1104                 (void) fflush(fp);
1105                 if (ferror(fp))
1106                         FATAL("write error on %s", filename(fp));
1107         }
1108         free(buf);
1109         return (True);
1110 }
1111 
1112 Cell *
1113 arith(Node **a, int n)  /* a[0] + a[1], etc.  also -a[0] */
1114 {
1115         Awkfloat i, j = 0;
1116         double v;
1117         Cell *x, *y, *z;
1118 
1119         x = execute(a[0]);
1120         i = getfval(x);
1121         tempfree(x);
1122         if (n != UMINUS) {
1123                 y = execute(a[1]);
1124                 j = getfval(y);
1125                 tempfree(y);
1126         }
1127         z = gettemp();
1128         switch (n) {
1129         case ADD:
1130                 i += j;
1131                 break;
1132         case MINUS:
1133                 i -= j;
1134                 break;
1135         case MULT:
1136                 i *= j;
1137                 break;
1138         case DIVIDE:
1139                 if (j == 0)
1140                         FATAL("division by zero");
1141                 i /= j;
1142                 break;
1143         case MOD:
1144                 if (j == 0)
1145                         FATAL("division by zero in mod");
1146                 (void) modf(i/j, &v);
1147                 i = i - j * v;
1148                 break;
1149         case UMINUS:
1150                 i = -i;
1151                 break;
1152         case POWER:
1153                 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1154                         i = ipow(i, (int)j);
1155                 else
1156                         i = errcheck(pow(i, j), "pow");
1157                 break;
1158         default:        /* can't happen */
1159                 FATAL("illegal arithmetic operator %d", n);
1160         }
1161         (void) setfval(z, i);
1162         return (z);
1163 }
1164 
1165 static double
1166 ipow(double x, int n)   /* x**n.  ought to be done by pow, but isn't always */
1167 {
1168         double v;
1169 
1170         if (n <= 0)
1171                 return (1.0);
1172         v = ipow(x, n / 2);
1173         if (n % 2 == 0)
1174                 return (v * v);
1175         else
1176                 return (x * v * v);
1177 }
1178 
1179 Cell *
1180 incrdecr(Node **a, int n)       /* a[0]++, etc. */
1181 {
1182         Cell *x, *z;
1183         int k;
1184         Awkfloat xf;
1185 
1186         x = execute(a[0]);
1187         xf = getfval(x);
1188         k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1189         if (n == PREINCR || n == PREDECR) {
1190                 (void) setfval(x, xf + k);
1191                 return (x);
1192         }
1193         z = gettemp();
1194         (void) setfval(z, xf);
1195         (void) setfval(x, xf + k);
1196         tempfree(x);
1197         return (z);
1198 }
1199 
1200 Cell *
1201 assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
1202 {                       /* this is subtle; don't muck with it. */
1203         Cell *x, *y;
1204         Awkfloat xf, yf;
1205         double v;
1206 
1207         y = execute(a[1]);
1208         x = execute(a[0]);
1209         if (n == ASSIGN) {      /* ordinary assignment */
1210                 /* self-assignment: */
1211                 /* LINTED E_NOP_IF_STMT */
1212                 if (x == y && !(x->tval & (FLD|REC)))
1213                         /* leave alone unless it's a field */
1214                         ;
1215                 else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1216                         (void) setsval(x, getsval(y));
1217                         x->fval = getfval(y);
1218                         x->tval |= NUM;
1219                 } else if (isstr(y))
1220                         (void) setsval(x, getsval(y));
1221                 else if (isnum(y))
1222                         (void) setfval(x, getfval(y));
1223                 else
1224                         funnyvar(y, "read value of");
1225                 tempfree(y);
1226                 return (x);
1227         }
1228         xf = getfval(x);
1229         yf = getfval(y);
1230         switch (n) {
1231         case ADDEQ:
1232                 xf += yf;
1233                 break;
1234         case SUBEQ:
1235                 xf -= yf;
1236                 break;
1237         case MULTEQ:
1238                 xf *= yf;
1239                 break;
1240         case DIVEQ:
1241                 if (yf == 0)
1242                         FATAL("division by zero in /=");
1243                 xf /= yf;
1244                 break;
1245         case MODEQ:
1246                 if (yf == 0)
1247                         FATAL("division by zero in %%=");
1248                 (void) modf(xf/yf, &v);
1249                 xf = xf - yf * v;
1250                 break;
1251         case POWEQ:
1252                 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1253                         xf = ipow(xf, (int)yf);
1254                 else
1255                         xf = errcheck(pow(xf, yf), "pow");
1256                 break;
1257         default:
1258                 FATAL("illegal assignment operator %d", n);
1259                 break;
1260         }
1261         tempfree(y);
1262         (void) setfval(x, xf);
1263         return (x);
1264 }
1265 
1266 /*ARGSUSED*/
1267 Cell *
1268 cat(Node **a, int q)            /* a[0] cat a[1] */
1269 {
1270         Cell *x, *y, *z;
1271         int n1, n2;
1272         uchar *s;
1273 
1274         x = execute(a[0]);
1275         y = execute(a[1]);
1276         (void) getsval(x);
1277         (void) getsval(y);
1278         n1 = strlen((char *)x->sval);
1279         n2 = strlen((char *)y->sval);
1280         s = (uchar *)malloc(n1 + n2 + 1);
1281         if (s == NULL) {
1282                 FATAL("out of space concatenating %.15s... and %.15s...",
1283                     x->sval, y->sval);
1284         }
1285         (void) strcpy((char *)s, (char *)x->sval);
1286         (void) strcpy((char *)s + n1, (char *)y->sval);
1287         tempfree(x);
1288         tempfree(y);
1289         z = gettemp();
1290         z->sval = s;
1291         z->tval = STR;

1292         return (z);
1293 }
1294 
1295 /*ARGSUSED*/
1296 Cell *
1297 pastat(Node **a, int n)         /* a[0] { a[1] } */
1298 {
1299         Cell *x;
1300 
1301         if (a[0] == 0)
1302                 x = execute(a[1]);
1303         else {
1304                 x = execute(a[0]);
1305                 if (istrue(x)) {
1306                         tempfree(x);
1307                         x = execute(a[1]);
1308                 }
1309         }
1310         return (x);
1311 }
1312 
1313 /*ARGSUSED*/
1314 Cell *
1315 dopa2(Node **a, int n)          /* a[0], a[1] { a[2] } */
1316 {
1317         Cell *x;
1318         int pair;










1319 
1320         pair = ptoi(a[3]);
1321         if (pairstack[pair] == 0) {
1322                 x = execute(a[0]);
1323                 if (istrue(x))
1324                         pairstack[pair] = 1;
1325                 tempfree(x);
1326         }
1327         if (pairstack[pair] == 1) {
1328                 x = execute(a[1]);
1329                 if (istrue(x))
1330                         pairstack[pair] = 0;
1331                 tempfree(x);
1332                 x = execute(a[2]);
1333                 return (x);
1334         }
1335         return (False);
1336 }
1337 
1338 /*ARGSUSED*/
1339 Cell *
1340 split(Node **a, int nnn)        /* split(a[0], a[1], a[2]); a[3] is type */
1341 {
1342         Cell *x = 0, *y, *ap;
1343         uchar *s, *origs;
1344         int sep;
1345         uchar *t, temp, num[50], *fs = 0;
1346         int n, tempstat, arg3type;
1347 
1348         y = execute(a[0]);      /* source string */
1349         origs = s = (uchar *)strdup((char *)getsval(y));
1350         arg3type = ptoi(a[3]);
1351         if (a[2] == 0)          /* fs string */
1352                 fs = *FS;
1353         else if (arg3type == STRING) {  /* split(str,arr,"string") */
1354                 x = execute(a[2]);
1355                 fs = getsval(x);
1356         } else if (arg3type == REGEXPR)
1357                 fs = (uchar *)"(regexpr)";      /* split(str,arr,/regexpr/) */
1358         else
1359                 FATAL("illegal type of split");
1360         sep = *fs;
1361         ap = execute(a[1]);     /* array name */
1362         freesymtab(ap);
1363         dprintf(("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs));
1364         ap->tval &= ~STR;
1365         ap->tval |= ARR;
1366         ap->sval = (uchar *)makesymtab(NSYMTAB);
1367 
1368         n = 0;
1369         if (arg3type == REGEXPR && strlen((char *)((fa *)a[2])->restr) == 0) {
1370                 arg3type = 0;
1371                 fs = (uchar *)"";
1372                 sep = 0;
1373         }
1374         if (*s != '\0' && (strlen((char *)fs) > 1 || arg3type == REGEXPR)) {
1375                 /* reg expr */
1376                 fa *pfa;
1377                 if (arg3type == REGEXPR) {      /* it's ready already */
1378                         pfa = (fa *)a[2];
1379                 } else {
1380                         pfa = makedfa(fs, 1);
1381                 }
1382                 if (nematch(pfa, s)) {
1383                         tempstat = pfa->initstat;
1384                         pfa->initstat = 2;
1385                         do {
1386                                 n++;
1387                                 (void) sprintf((char *)num, "%d", n);
1388                                 temp = *patbeg;
1389                                 *patbeg = '\0';
1390                                 if (is_number(s)) {
1391                                         (void) setsymtab(num, s,
1392                                             atof((char *)s),
1393                                             /*LINTED align*/
1394                                             STR|NUM, (Array *)ap->sval);
1395                                 } else {
1396                                         (void) setsymtab(num, s, 0.0,
1397                                             /*LINTED align*/
1398                                             STR, (Array *)ap->sval);
1399                                 }
1400                                 *patbeg = temp;
1401                                 s = patbeg + patlen;
1402                                 if (*(patbeg+patlen-1) == 0 || *s == 0) {
1403                                         n++;
1404                                         (void) sprintf((char *)num, "%d", n);
1405                                         (void) setsymtab(num, (uchar *)"", 0.0,
1406                                             /*LINTED align*/
1407                                             STR, (Array *)ap->sval);
1408                                         pfa->initstat = tempstat;
1409                                         goto spdone;
1410                                 }
1411                         } while (nematch(pfa, s));
1412                         /* bwk: has to be here to reset */
1413                         pfa->initstat = tempstat;
1414                         /* cf gsub and refldbld */
1415                 }
1416                 n++;
1417                 (void) sprintf((char *)num, "%d", n);
1418                 if (is_number(s)) {
1419                         (void) setsymtab(num, s, atof((char *)s),
1420                             /*LINTED align*/
1421                             STR|NUM, (Array *)ap->sval);
1422                 } else {
1423                         /*LINTED align*/
1424                         (void) setsymtab(num, s, 0.0, STR, (Array *)ap->sval);
1425                 }
1426 spdone:
1427                 pfa = NULL;
1428         } else if (sep == ' ') {
1429                 for (n = 0; ; ) {
1430                         while (*s == ' ' || *s == '\t' || *s == '\n')
1431                                 s++;
1432                         if (*s == 0)
1433                                 break;
1434                         n++;


1437                                 s++;
1438                         while (*s != ' ' && *s != '\t' &&
1439                             *s != '\n' && *s != '\0')
1440                                 ;
1441                         temp = *s;
1442                         *s = '\0';
1443                         (void) sprintf((char *)num, "%d", n);
1444                         if (is_number(t)) {
1445                                 (void) setsymtab(num, t, atof((char *)t),
1446                                     /*LINTED align*/
1447                                     STR|NUM, (Array *)ap->sval);
1448                         } else {
1449                                 (void) setsymtab(num, t, 0.0,
1450                                     /*LINTED align*/
1451                                     STR, (Array *)ap->sval);
1452                         }
1453                         *s = temp;
1454                         if (*s != 0)
1455                                 s++;
1456                 }
1457         } else if (sep == 0) {  /* new: split(s, a, "") => 1 char/elem */
1458                 for (n = 0; *s != 0; s++) {
1459                         uchar buf[2];
1460                         n++;
1461                         (void) sprintf((char *)num, "%d", n);
1462                         buf[0] = *s;
1463                         buf[1] = 0;
1464                         if (isdigit(buf[0])) {
1465                                 (void) setsymtab(num, buf, atof((char *)buf),
1466                                     /* LINTED align */
1467                                     STR | NUM, (Array *)ap->sval);
1468                         } else {
1469                                 (void) setsymtab(num, buf, 0.0,
1470                                     /* LINTED align */
1471                                     STR, (Array *)ap->sval);
1472                         }
1473                 }
1474         } else if (*s != 0) {
1475                 for (;;) {
1476                         n++;
1477                         t = s;
1478                         while (*s != sep && *s != '\n' && *s != '\0')
1479                                 s++;
1480                         temp = *s;
1481                         *s = '\0';
1482                         (void) sprintf((char *)num, "%d", n);
1483                         if (is_number(t)) {
1484                                 (void) setsymtab(num, t, atof((char *)t),
1485                                     /*LINTED align*/
1486                                     STR|NUM, (Array *)ap->sval);
1487                         } else {
1488                                 (void) setsymtab(num, t, 0.0,
1489                                     /*LINTED align*/
1490                                     STR, (Array *)ap->sval);
1491                         }
1492                         *s = temp;
1493                         if (*s++ == 0)
1494                                 break;
1495                 }
1496         }
1497         tempfree(ap);
1498         tempfree(y);
1499         free(origs);
1500         if (a[2] != 0 && arg3type == STRING) {
1501                 tempfree(x);
1502         }
1503         x = gettemp();
1504         x->tval = NUM;
1505         x->fval = n;
1506         return (x);
1507 }
1508 
1509 /*ARGSUSED*/
1510 Cell *
1511 condexpr(Node **a, int n)       /* a[0] ? a[1] : a[2] */
1512 {
1513         Cell *x;
1514 
1515         x = execute(a[0]);
1516         if (istrue(x)) {
1517                 tempfree(x);
1518                 x = execute(a[1]);
1519         } else {
1520                 tempfree(x);
1521                 x = execute(a[2]);
1522         }
1523         return (x);
1524 }
1525 
1526 /*ARGSUSED*/
1527 Cell *
1528 ifstat(Node **a, int n)         /* if (a[0]) a[1]; else a[2] */
1529 {
1530         Cell *x;
1531 
1532         x = execute(a[0]);
1533         if (istrue(x)) {
1534                 tempfree(x);
1535                 x = execute(a[1]);
1536         } else if (a[2] != 0) {
1537                 tempfree(x);
1538                 x = execute(a[2]);
1539         }
1540         return (x);
1541 }
1542 
1543 /*ARGSUSED*/
1544 Cell *
1545 whilestat(Node **a, int n)      /* while (a[0]) a[1] */
1546 {
1547         Cell *x;
1548 
1549         for (;;) {
1550                 x = execute(a[0]);
1551                 if (!istrue(x))
1552                         return (x);
1553                 tempfree(x);
1554                 x = execute(a[1]);
1555                 if (isbreak(x)) {
1556                         x = True;
1557                         return (x);
1558                 }
1559                 if (isnext(x) || isexit(x) || isret(x))
1560                         return (x);
1561                 tempfree(x);
1562         }
1563 }
1564 
1565 /*ARGSUSED*/
1566 Cell *
1567 dostat(Node **a, int n)         /* do a[0]; while(a[1]) */
1568 {
1569         Cell *x;
1570 
1571         for (;;) {
1572                 x = execute(a[0]);
1573                 if (isbreak(x))
1574                         return (True);
1575                 if (isnext(x) || isexit(x) || isret(x))
1576                         return (x);
1577                 tempfree(x);
1578                 x = execute(a[1]);
1579                 if (!istrue(x))
1580                         return (x);
1581                 tempfree(x);
1582         }
1583 }
1584 
1585 /*ARGSUSED*/
1586 Cell *
1587 forstat(Node **a, int n)        /* for (a[0]; a[1]; a[2]) a[3] */
1588 {
1589         Cell *x;
1590 
1591         x = execute(a[0]);
1592         tempfree(x);
1593         for (;;) {
1594                 if (a[1] != 0) {
1595                         x = execute(a[1]);
1596                         if (!istrue(x))
1597                                 return (x);
1598                         else
1599                                 tempfree(x);
1600                 }
1601                 x = execute(a[3]);
1602                 if (isbreak(x))         /* turn off break */
1603                         return (True);
1604                 if (isnext(x) || isexit(x) || isret(x))
1605                         return (x);
1606                 tempfree(x);
1607                 x = execute(a[2]);
1608                 tempfree(x);
1609         }
1610 }
1611 
1612 /*ARGSUSED*/
1613 Cell *
1614 instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1615 {
1616         Cell *x, *vp, *arrayp, *cp, *ncp;
1617         Array *tp;
1618         int i;
1619 
1620         vp = execute(a[0]);
1621         arrayp = execute(a[1]);
1622         if (!isarr(arrayp)) {
1623                 return (True);
1624         }
1625         /*LINTED align*/
1626         tp = (Array *)arrayp->sval;
1627         tempfree(arrayp);
1628         for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1629                 for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1630                         (void) setsval(vp, cp->nval);
1631                         ncp = cp->cnext;
1632                         x = execute(a[2]);
1633                         if (isbreak(x)) {
1634                                 tempfree(vp);
1635                                 return (True);
1636                         }
1637                         if (isnext(x) || isexit(x) || isret(x)) {
1638                                 tempfree(vp);
1639                                 return (x);
1640                         }
1641                         tempfree(x);
1642                 }
1643         }
1644         return (True);
1645 }
1646 
1647 /*
1648  * builtin functions. a[0] is type, a[1] is arg list
1649  */
1650 /*ARGSUSED*/
1651 Cell *
1652 bltin(Node **a, int n)
1653 {
1654         Cell *x, *y;
1655         Awkfloat u;
1656         int t;
1657         Awkfloat tmp;
1658         uchar *p, *buf;
1659         Node *nextarg;
1660         FILE *fp;
1661 
1662         t = ptoi(a[0]);
1663         x = execute(a[1]);
1664         nextarg = a[1]->nnext;
1665         switch (t) {
1666         case FLENGTH:
1667                 if (isarr(x)) {
1668                         /* GROT.  should be function */
1669                         /* LINTED align */
1670                         u = (Awkfloat)((Array *)x->sval)->nelem;
1671                 } else {
1672                         u = (Awkfloat)strlen((char *)getsval(x));
1673                 }
1674                 break;
1675         case FLOG:
1676                 u = errcheck(log(getfval(x)), "log"); break;
1677         case FINT:
1678                 (void) modf(getfval(x), &u); break;
1679         case FEXP:
1680                 u = errcheck(exp(getfval(x)), "exp"); break;
1681         case FSQRT:
1682                 u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1683         case FSIN:
1684                 u = sin(getfval(x)); break;
1685         case FCOS:
1686                 u = cos(getfval(x)); break;
1687         case FATAN:
1688                 if (nextarg == 0) {
1689                         WARNING("atan2 requires two arguments; returning 1.0");

1690                         u = 1.0;
1691                 } else {
1692                         y = execute(a[1]->nnext);
1693                         u = atan2(getfval(x), getfval(y));
1694                         tempfree(y);
1695                         nextarg = nextarg->nnext;
1696                 }
1697                 break;
1698         case FSYSTEM:
1699                 /* in case something is buffered already */
1700                 (void) fflush(stdout);
1701                 /* 256 is unix-dep */
1702                 u = (Awkfloat)system((char *)getsval(x)) / 256;
1703                 break;
1704         case FRAND:
1705                 /* in principle, rand() returns something in 0..RAND_MAX */
1706                 u = (Awkfloat)(rand() % RAND_MAX) / RAND_MAX;
1707                 break;
1708         case FSRAND:
1709                 if (isrec(x))   /* no argument provided */
1710                         u = time((time_t *)0);
1711                 else
1712                         u = getfval(x);
1713                 tmp = u;
1714                 srand((unsigned int)u);
1715                 u = srand_seed;
1716                 srand_seed = tmp;
1717                 break;
1718         case FTOUPPER:
1719         case FTOLOWER:
1720                 buf = tostring(getsval(x));
1721                 if (t == FTOUPPER) {
1722                         for (p = buf; *p; p++)
1723                                 if (islower(*p))
1724                                         *p = toupper(*p);
1725                 } else {
1726                         for (p = buf; *p; p++)
1727                                 if (isupper(*p))
1728                                         *p = tolower(*p);
1729                 }
1730                 tempfree(x);
1731                 x = gettemp();
1732                 (void) setsval(x, buf);
1733                 free(buf);
1734                 return (x);
1735         case FFLUSH:
1736                 if (isrec(x) || strlen((char *)getsval(x)) == 0) {
1737                         /* fflush() or fflush("") -> all */
1738                         flush_all();
1739                         u = 0;
1740                 } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1741                         u = EOF;
1742                 else
1743                         u = fflush(fp);
1744                 break;
1745         default:        /* can't happen */
1746                 FATAL("illegal function type %d", t);
1747                 break;
1748         }
1749         tempfree(x);
1750         x = gettemp();
1751         (void) setfval(x, u);
1752         if (nextarg != 0) {
1753                 WARNING("warning: function has too many arguments");
1754                 for (; nextarg; nextarg = nextarg->nnext)
1755                         (void) execute(nextarg);
1756         }
1757         return (x);
1758 }
1759 
1760 /*ARGSUSED*/
1761 Cell *
1762 printstat(Node **a, int n)              /* print a[0] */
1763 {
1764         Node *x;
1765         Cell *y;
1766         FILE *fp;
1767 
1768         if (a[1] == 0)  /* a[1] is redirection operator, a[2] is file */
1769                 fp = stdout;
1770         else
1771                 fp = redirect(ptoi(a[1]), a[2]);
1772         for (x = a[0]; x != NULL; x = x->nnext) {
1773                 y = execute(x);
1774                 (void) fputs((char *)getsval(y), fp);
1775                 tempfree(y);
1776                 if (x->nnext == NULL)
1777                         (void) fputs((char *)*ORS, fp);
1778                 else
1779                         (void) fputs((char *)*OFS, fp);
1780         }
1781         if (a[1] != 0)
1782                 (void) fflush(fp);
1783         if (ferror(fp))
1784                 FATAL("write error on %s", filename(fp));
1785         return (True);
1786 }
1787 
1788 /*ARGSUSED*/
1789 Cell *
1790 nullproc(Node **a, int n)
1791 {
1792         return (0);
1793 }
1794 






1795 static FILE *
1796 redirect(int a, Node *b)        /* set up all i/o redirections */
1797 {
1798         FILE *fp;
1799         Cell *x;
1800         uchar *fname;
1801 
1802         x = execute(b);
1803         fname = getsval(x);
1804         fp = openfile(a, fname);
1805         if (fp == NULL)
1806                 FATAL("can't open file %s", fname);
1807         tempfree(x);
1808         return (fp);
1809 }
1810 
1811 struct files {
1812         FILE    *fp;
1813         const uchar     *fname;
1814         int     mode;   /* '|', 'a', 'w' => LE/LT, GT */
1815 } *files;
1816 
1817 int nfiles;
1818 
1819 static void
1820 stdinit(void)   /* in case stdin, etc., are not constants */
1821 {
1822         nfiles = FOPEN_MAX;
1823         files = calloc(nfiles, sizeof (*files));
1824         if (files == NULL)
1825                 FATAL("can't allocate file memory for %u files", nfiles);
1826         files[0].fp = stdin;
1827         files[0].fname = (uchar *)"/dev/stdin";
1828         files[0].mode = LT;
1829         files[1].fp = stdout;
1830         files[1].fname = (uchar *)"/dev/stdout";
1831         files[1].mode = GT;
1832         files[2].fp = stderr;
1833         files[2].fname = (uchar *)"/dev/stderr";
1834         files[2].mode = GT;
1835 }
1836 
1837 static FILE *
1838 openfile(int a, const uchar *us)
1839 {
1840         const uchar *s = us;
1841         int i, m;
1842         FILE *fp = 0;
1843 
1844         if (*s == '\0')
1845                 FATAL("null file name in print or getline");
1846         for (i = 0; i < nfiles; i++) {
1847                 if (files[i].fname &&
1848                     (strcmp((char *)s, (char *)files[i].fname) == 0)) {
1849                         if (a == files[i].mode ||
1850                             (a == APPEND && files[i].mode == GT)) {
1851                                 return (files[i].fp);
1852                         }
1853                         if (a == FFLUSH)
1854                                 return (files[i].fp);
1855                 }
1856         }
1857         if (a == FFLUSH)        /* didn't find it, so don't create it! */
1858                 return (NULL);
1859 
1860         for (i = 0; i < nfiles; i++) {
1861                 if (files[i].fp == 0)
1862                         break;
1863         }
1864         if (i >= nfiles) {
1865                 struct files *nf;
1866                 int nnf = nfiles + FOPEN_MAX;
1867                 nf = realloc(files, nnf * sizeof (*nf));
1868                 if (nf == NULL)
1869                         FATAL("cannot grow files for %s and %d files", s, nnf);
1870                 (void) memset(&nf[nfiles], 0, FOPEN_MAX * sizeof (*nf));
1871                 nfiles = nnf;
1872                 files = nf;
1873         }
1874         (void) fflush(stdout);  /* force a semblance of order */
1875         m = a;
1876         if (a == GT) {
1877                 fp = fopen((char *)s, "w");
1878         } else if (a == APPEND) {
1879                 fp = fopen((char *)s, "a");
1880                 m = GT; /* so can mix > and >> */
1881         } else if (a == '|') {  /* output pipe */
1882                 fp = popen((char *)s, "w");
1883         } else if (a == LE) {   /* input pipe */
1884                 fp = popen((char *)s, "r");
1885         } else if (a == LT) {   /* getline <file */
1886                 fp = strcmp((char *)s, "-") == 0 ?
1887                     stdin : fopen((char *)s, "r");      /* "-" is stdin */
1888         } else  /* can't happen */
1889                 FATAL("illegal redirection %d", a);
1890         if (fp != NULL) {
1891                 files[i].fname = tostring(s);
1892                 files[i].fp = fp;
1893                 files[i].mode = m;
1894         }
1895         return (fp);
1896 }
1897 
1898 static const char *
1899 filename(FILE *fp)
1900 {
1901         int i;
1902 
1903         for (i = 0; i < nfiles; i++) {
1904                 if (fp == files[i].fp)
1905                         return ((char *)files[i].fname);
1906         }
1907 
1908         return ("???");
1909 }
1910 
1911 /*ARGSUSED*/
1912 Cell *
1913 closefile(Node **a, int n)
1914 {
1915         Cell *x;
1916         int i, stat;
1917 
1918         x = execute(a[0]);
1919         (void) getsval(x);
1920         stat = -1;
1921         for (i = 0; i < nfiles; i++) {
1922                 if (files[i].fname &&
1923                     strcmp((char *)x->sval, (char *)files[i].fname) == 0) {
1924                         if (ferror(files[i].fp)) {
1925                                 WARNING("i/o error occurred on %s",
1926                                     files[i].fname);
1927                         }
1928                         if (files[i].mode == '|' || files[i].mode == LE)
1929                                 stat = pclose(files[i].fp);
1930                         else
1931                                 stat = fclose(files[i].fp);
1932                         if (stat == EOF) {
1933                                 WARNING("i/o error occurred closing %s",
1934                                     files[i].fname);
1935                         }
1936                         if (i > 2)   /* don't do /dev/std... */
1937                                 xfree(files[i].fname);
1938                         /* watch out for ref thru this */
1939                         files[i].fname = NULL;
1940                         files[i].fp = NULL;
1941                 }
1942         }
1943         tempfree(x);
1944         x = gettemp();
1945         (void) setfval(x, (Awkfloat)stat);
1946         return (x);
1947 }
1948 
1949 static void
1950 closeall(void)
1951 {
1952         int i, stat;
1953 
1954         for (i = 0; i < FOPEN_MAX; i++) {
1955                 if (files[i].fp) {
1956                         if (ferror(files[i].fp)) {
1957                                 WARNING("i/o error occurred on %s",
1958                                     files[i].fname);
1959                         }
1960                         if (files[i].mode == '|' || files[i].mode == LE)
1961                                 stat = pclose(files[i].fp);
1962                         else
1963                                 stat = fclose(files[i].fp);
1964                         if (stat == EOF) {
1965                                 WARNING("i/o error occurred while closing %s",
1966                                     files[i].fname);
1967                         }
1968                 }
1969         }
1970 }
1971 
1972 static void
1973 flush_all(void)
1974 {
1975         int i;
1976 
1977         for (i = 0; i < nfiles; i++)
1978                 if (files[i].fp)
1979                         (void) fflush(files[i].fp);
1980 }
1981 
1982 void backsub(uchar **pb_ptr, uchar **sptr_ptr);
1983 
1984 /*ARGSUSED*/
1985 Cell *
1986 sub(Node **a, int nnn)  /* substitute command */
1987 {
1988         uchar *sptr, *pb, *q;
1989         Cell *x, *y, *result;
1990         uchar *t, *buf;
1991         fa *pfa;
1992         size_t  bufsz = record_size;
1993 
1994         if ((buf = (uchar *)malloc(bufsz)) == NULL)
1995                 FATAL("out of memory in sub");
1996         x = execute(a[3]);      /* target string */
1997         t = getsval(x);
1998         if (a[0] == 0)          /* 0 => a[1] is already-compiled regexpr */
1999                 pfa = (fa *)a[1];       /* regular expression */
2000         else {
2001                 y = execute(a[1]);
2002                 pfa = makedfa(getsval(y), 1);
2003                 tempfree(y);
2004         }
2005         y = execute(a[2]);      /* replacement string */
2006         result = False;
2007         if (pmatch(pfa, t)) {


2008                 sptr = t;
2009                 (void) adjbuf(&buf, &bufsz, 1+patbeg-sptr, record_size,
2010                     0, "sub");
2011                 pb = buf;
2012                 while (sptr < patbeg)
2013                         *pb++ = *sptr++;

2014                 sptr = getsval(y);
2015                 while (*sptr != 0) {
2016                         (void) adjbuf(&buf, &bufsz, 5 + pb - buf, record_size,
2017                             &pb, "sub");
2018                         if (*sptr == '\\') {
2019                                 backsub(&pb, &sptr);

2020                         } else if (*sptr == '&') {

2021                                 sptr++;
2022                                 (void) adjbuf(&buf, &bufsz, 1+patlen+pb-buf,
2023                                     record_size, &pb, "sub");
2024                                 for (q = patbeg; q < patbeg + patlen; )
2025                                         *pb++ = *q++;
2026                         } else {
2027                                 *pb++ = *sptr++;
2028                         }
2029                 }
2030                 *pb = '\0';
2031                 if (pb > buf + bufsz)
2032                         FATAL("sub result1 %.30s too big; can't happen", buf);
2033                 sptr = patbeg + patlen;
2034                 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
2035                         (void) adjbuf(&buf, &bufsz, 1 + strlen((char *)sptr) +
2036                             pb - buf, 0, &pb, "sub");
2037                         while ((*pb++ = *sptr++) != 0)
2038                                 ;
2039                 }
2040                 if (pb > buf + bufsz)
2041                         FATAL("sub result2 %.30s too big; can't happen", buf);
2042                 /* BUG: should be able to avoid copy */
2043                 (void) setsval(x, buf);
2044                 result = True;

2045         }
2046         tempfree(x);
2047         tempfree(y);
2048         free(buf);
2049         return (result);
2050 }
2051 
2052 /*ARGSUSED*/
2053 Cell *
2054 gsub(Node **a, int nnn)         /* global substitute */
2055 {
2056         Cell *x, *y;
2057         uchar *rptr, *sptr, *t, *pb, *q;
2058         uchar *buf;
2059         fa *pfa;
2060         int mflag, tempstat, num;
2061         size_t bufsz = record_size;
2062 
2063         if ((buf = (uchar *)malloc(bufsz)) == NULL)
2064                 FATAL("out of memory in gsub");
2065         mflag = 0;      /* if mflag == 0, can replace empty string */
2066         num = 0;
2067         x = execute(a[3]);      /* target string */
2068         t = getsval(x);
2069         if (a[0] == 0)          /* 0 => a[1] is already-compiled regexpr */
2070                 pfa = (fa *)a[1];       /* regular expression */
2071         else {
2072                 y = execute(a[1]);
2073                 pfa = makedfa(getsval(y), 1);
2074                 tempfree(y);
2075         }
2076         y = execute(a[2]);      /* replacement string */
2077         if (pmatch(pfa, t)) {
2078                 tempstat = pfa->initstat;
2079                 pfa->initstat = 2;
2080                 pb = buf;
2081                 rptr = getsval(y);

2082                 do {
2083                         if (patlen == 0 && *patbeg != 0) {
2084                                 /* matched empty string */
2085                                 if (mflag == 0) {       /* can replace empty */
2086                                         num++;
2087                                         sptr = rptr;
2088                                         while (*sptr != 0) {
2089                                         (void) adjbuf(&buf, &bufsz, 5+pb-buf,
2090                                             record_size, &pb, "gsub");
2091                                         if (*sptr == '\\') {
2092                                                 backsub(&pb, &sptr);


2093                                         } else if (*sptr == '&') {



2094                                                 sptr++;
2095                                                 (void) adjbuf(&buf, &bufsz, 1 +
2096                                                     patlen+pb-buf, record_size,
2097                                                     &pb, "gsub");
2098                                         for (q = patbeg; q < patbeg+patlen; )
2099                                                 *pb++ = *q++;
2100                                         } else {
2101                                                 *pb++ = *sptr++;
2102                                         }
2103                                         }
2104                                 }
2105                                 if (*t == 0)    /* at end */
2106                                         goto done;
2107                                 (void) adjbuf(&buf, &bufsz, 2 + pb - buf,
2108                                     record_size, &pb, "gsub");
2109                                 *pb++ = *t++;
2110                                 /* BUG: not sure of this test */
2111                                 if (pb > buf + bufsz)
2112                                         FATAL(
2113                         "gsub result0 %.30s too big; can't happen", buf);
2114                                 mflag = 0;
2115                         } else {        /* matched nonempty string */
2116                                 num++;
2117                                 sptr = t;
2118                                 (void) adjbuf(&buf, &bufsz, 1 +
2119                                     (patbeg - sptr) + pb - buf, record_size,
2120                                     &pb, "gsub");
2121                                 while (sptr < patbeg)
2122                                         *pb++ = *sptr++;

2123                                 sptr = rptr;
2124                                 while (*sptr != 0) {
2125                                         (void) adjbuf(&buf, &bufsz, 5 + pb -
2126                                             buf, record_size, &pb, "gsub");
2127                                         if (*sptr == '\\') {
2128                                                 backsub(&pb, &sptr);


2129                                         } else if (*sptr == '&') {


2130                                                 sptr++;
2131                                         (void) adjbuf(&buf, &bufsz, 1 +
2132                                             patlen + pb - buf, record_size,
2133                                             &pb, "gsub");
2134                                 for (q = patbeg; q < patbeg + patlen; )
2135                                                         *pb++ = *q++;
2136                                         } else {
2137                                                 *pb++ = *sptr++;
2138                                         }
2139                                 }
2140                                 t = patbeg + patlen;
2141                                 if (patlen == 0 || *t == 0 || *(t - 1) == 0)
2142                                         goto done;
2143                                 if (pb > buf + bufsz)
2144                                         FATAL(
2145                         "gsub result1 %.30s too big; can't happen", buf);
2146                                 mflag = 1;
2147                         }
2148                 } while (pmatch(pfa, t));
2149                 sptr = t;
2150                 (void) adjbuf(&buf, &bufsz, 1 + strlen((char *)sptr) + pb -
2151                     buf, 0, &pb, "gsub");
2152                 while ((*pb++ = *sptr++) != 0)
2153                         ;
2154         done:   if (pb < buf + bufsz)
2155                         *pb = '\0';
2156                 else if (*(pb-1) != '\0')
2157                         FATAL("gsub result2 %.30s truncated; can't happen",
2158                             buf);
2159                 /* BUG: should be able to avoid copy + free */
2160                 (void) setsval(x, buf);

2161                 pfa->initstat = tempstat;
2162         }
2163         tempfree(x);
2164         tempfree(y);
2165         x = gettemp();
2166         x->tval = NUM;
2167         x->fval = num;
2168         free(buf);
2169         return (x);
2170 }
2171 
2172 void
2173 backsub(uchar **pb_ptr, uchar **sptr_ptr)       /* handle \\& variations */
2174 {                                       /* sptr[0] == '\\' */
2175         uchar *pb = *pb_ptr, *sptr = *sptr_ptr;
2176 
2177         if (sptr[1] == '\\') {
2178                 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
2179                         *pb++ = '\\';
2180                         *pb++ = '&';
2181                         sptr += 4;
2182                 } else if (sptr[2] == '&') {        /* \\& -> \ + matched */
2183                         *pb++ = '\\';
2184                         sptr += 2;
2185                 } else {                        /* \\x -> \\x */
2186                         *pb++ = *sptr++;
2187                         *pb++ = *sptr++;
2188                 }
2189         } else if (sptr[1] == '&') {        /* literal & */
2190                 sptr++;
2191                 *pb++ = *sptr++;
2192         } else                          /* literal \ */
2193                 *pb++ = *sptr++;
2194 
2195         *pb_ptr = pb;
2196         *sptr_ptr = sptr;
2197 }