Print this page
3731 Update nawk to version 20121220

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