1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  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++;
1435                         t = s;
1436                         do
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 }