[BACK]Return to run.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / awk

Diff for /src/usr.bin/awk/run.c between version 1.12 and 1.13

version 1.12, 1997/04/07 15:59:56 version 1.13, 1997/08/25 16:17:14
Line 1 
Line 1 
 /*      $OpenBSD$       */  /*      $OpenBSD$       */
 /****************************************************************  /****************************************************************
 Copyright (C) AT&T and Lucent Technologies 1996  Copyright (C) Lucent Technologies 1997
 All Rights Reserved  All Rights Reserved
   
 Permission to use, copy, modify, and distribute this software and  Permission to use, copy, modify, and distribute this software and
Line 8 
Line 8 
 granted, provided that the above copyright notice appear in all  granted, provided that the above copyright notice appear in all
 copies and that both that the copyright notice and this  copies and that both that the copyright notice and this
 permission notice and warranty disclaimer appear in supporting  permission notice and warranty disclaimer appear in supporting
 documentation, and that the names of AT&T or Lucent Technologies  documentation, and that the name Lucent Technologies or any of
 or any of their entities not be used in advertising or publicity  its entities not be used in advertising or publicity pertaining
 pertaining to distribution of the software without specific,  to distribution of the software without specific, written prior
 written prior permission.  permission.
   
 AT&T AND LUCENT DISCLAIM ALL WARRANTIES WITH REGARD TO THIS  LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
 FITNESS. IN NO EVENT SHALL AT&T OR LUCENT OR ANY OF THEIR  IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
 ENTITIES BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR  IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 USE OR PERFORMANCE OF THIS SOFTWARE.  THIS SOFTWARE.
 ****************************************************************/  ****************************************************************/
   
 #define DEBUG  #define DEBUG
Line 32 
Line 32 
 #include <stdlib.h>  #include <stdlib.h>
 #include <time.h>  #include <time.h>
 #include "awk.h"  #include "awk.h"
 #include "awkgram.h"  #include "ytab.h"
   
 #define tempfree(x)     if (istemp(x)) tfree(x); else  #define tempfree(x)     if (istemp(x)) tfree(x); else
   
Line 64 
Line 64 
 #endif  #endif
   
 jmp_buf env;  jmp_buf env;
   extern  int     pairstack[];
   
 #define PA2NUM  29      /* max number of pat,pat patterns allowed */  
 int     paircnt;                /* number of them in use */  
 int     pairstack[PA2NUM];      /* state of each pat,pat */  
   
 Node    *winner = NULL; /* root of parse tree */  Node    *winner = NULL; /* root of parse tree */
 Cell    *tmps;          /* free temporary cells for execution */  Cell    *tmps;          /* free temporary cells for execution */
   
Line 88 
Line 85 
 Cell    *jexit  = &exitcell;  Cell    *jexit  = &exitcell;
 static Cell     retcell         ={ OJUMP, JRET, 0, 0, 0.0, NUM };  static Cell     retcell         ={ OJUMP, JRET, 0, 0, 0.0, NUM };
 Cell    *jret   = &retcell;  Cell    *jret   = &retcell;
 static Cell     tempcell        ={ OCELL, CTEMP, 0, 0, 0.0, NUM };  static Cell     tempcell        ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
   
 Node    *curnode = NULL;        /* the node being executed, for debugging */  Node    *curnode = NULL;        /* the node being executed, for debugging */
   
   /* buffer memory management */
   int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
           char *whatrtn)
   /* pbuf:    address of pointer to buffer being managed
    * psiz:    address of buffer size variable
    * minlen:  minimum length of buffer needed
    * quantum: buffer size quantum
    * pbptr:   address of movable pointer into buffer, or 0 if none
    * whatrtn: name of the calling routine if failure should cause fatal error
    *
    * return   0 for realloc failure, !=0 for success
    */
   {
           if (minlen > *psiz) {
                   char *tbuf;
                   int rminlen = quantum ? minlen % quantum : 0;
                   int boff = pbptr ? *pbptr - *pbuf : 0;
                   /* round up to next multiple of quantum */
                   if (rminlen)
                           minlen += quantum - rminlen;
                   tbuf = realloc(*pbuf, minlen);
                   if (tbuf == NULL) {
                           if (whatrtn)
                                   ERROR "out of memory in %s", whatrtn FATAL;
                           return 0;
                   }
                   *pbuf = tbuf;
                   *psiz = minlen;
                   if (pbptr)
                           *pbptr = tbuf + boff;
           }
           return 1;
   }
   
 void run(Node *a)       /* execution of parse tree starts here */  void run(Node *a)       /* execution of parse tree starts here */
 {  {
         execute(a);          execute(a);
Line 110 
Line 141 
                 curnode = a;                  curnode = a;
                 if (isvalue(a)) {                  if (isvalue(a)) {
                         x = (Cell *) (a->narg[0]);                          x = (Cell *) (a->narg[0]);
                         if ((x->tval & FLD) && !donefld)                          if (isfld(x) && !donefld)
                                 fldbld();                                  fldbld();
                         else if ((x->tval & REC) && !donerec)                          else if (isrec(x) && !donerec)
                                 recbld();                                  recbld();
                         return(x);                          return(x);
                 }                  }
Line 120 
Line 151 
                         ERROR "illegal statement" FATAL;                          ERROR "illegal statement" FATAL;
                 proc = proctab[a->nobj-FIRSTTOKEN];                  proc = proctab[a->nobj-FIRSTTOKEN];
                 x = (*proc)(a->narg, a->nobj);                  x = (*proc)(a->narg, a->nobj);
                 if ((x->tval & FLD) && !donefld)                  if (isfld(x) && !donefld)
                         fldbld();                          fldbld();
                 else if ((x->tval & REC) && !donerec)                  else if (isrec(x) && !donerec)
                         recbld();                          recbld();
                 if (isexpr(a))                  if (isexpr(a))
                         return(x);                          return(x);
Line 150 
Line 181 
                 tempfree(x);                  tempfree(x);
         }          }
         if (a[1] || a[2])          if (a[1] || a[2])
                 while (getrec(record) > 0) {                  while (getrec(&record, &recsize, 1) > 0) {
                         x = execute(a[1]);                          x = execute(a[1]);
                         if (isexit(x))                          if (isexit(x))
                                 break;                                  break;
Line 184 
Line 215 
   
 Cell *call(Node **a, int n)     /* function call.  very kludgy and fragile */  Cell *call(Node **a, int n)     /* function call.  very kludgy and fragile */
 {  {
         static Cell newcopycell = { OCELL, CCOPY, 0, (char *) "", 0.0, NUM|STR|DONTFREE };          static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
         int i, ncall, ndef;          int i, ncall, ndef;
         Node *x;          Node *x;
         Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn;          Cell *args[NARGS], *oargs[NARGS];       /* BUG: fixed size arrays */
           Cell *y, *z, *fcn;
         char *s;          char *s;
   
         fcn = execute(a[0]);    /* the function itself */          fcn = execute(a[0]);    /* the function itself */
         s = fcn->nval;          s = fcn->nval;
         if (!isfunc(fcn))          if (!isfcn(fcn))
                 ERROR "calling undefined function %s", s FATAL;                  ERROR "calling undefined function %s", s FATAL;
         if (frame == NULL) {          if (frame == NULL) {
                 fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));                  fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
Line 202 
Line 234 
         for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)      /* args in call */          for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)      /* args in call */
                 ncall++;                  ncall++;
         ndef = (int) fcn->fval;                 /* args in defn */          ndef = (int) fcn->fval;                 /* args in defn */
         dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, fp-frame) );             dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, fp-frame) );
         if (ncall > ndef)          if (ncall > ndef)
                 ERROR "function %s called with %d args, uses only %d",                  ERROR "function %s called with %d args, uses only %d",
                         s, ncall, ndef WARNING;                          s, ncall, ndef WARNING;
         if (ncall + ndef > NARGS)          if (ncall + ndef > NARGS)
                 ERROR "function %s has %d arguments, limit %d", s, ncall+ndef, NARGS FATAL;                  ERROR "function %s has %d arguments, limit %d", s, ncall+ndef, NARGS FATAL;
         for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {   /* get call args */          for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {   /* get call args */
                 dprintf( ("evaluate args[%d], fp=%d:\n", i, fp-frame) );                     dprintf( ("evaluate args[%d], fp=%d:\n", i, fp-frame) );
                 y = execute(x);                  y = execute(x);
                 oargs[i] = y;                  oargs[i] = y;
                 dprintf( ("args[%d]: %s %f <%s>, t=%o\n",                     dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
                            i, y->nval, y->fval, isarr(y) ? "(array)" : (char*) y->sval, y->tval) );                             i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) );
                 if (isfunc(y))                  if (isfcn(y))
                         ERROR "can't use function %s as argument in %s", y->nval, s FATAL;                          ERROR "can't use function %s as argument in %s", y->nval, s FATAL;
                 if (isarr(y))                  if (isarr(y))
                         args[i] = y;    /* arrays by ref */                          args[i] = y;    /* arrays by ref */
Line 240 
Line 272 
         fp->nargs = ndef;       /* number defined with (excess are locals) */          fp->nargs = ndef;       /* number defined with (excess are locals) */
         fp->retval = gettemp();          fp->retval = gettemp();
   
         dprintf( ("start exec of %s, fp=%d\n", s, fp-frame) );             dprintf( ("start exec of %s, fp=%d\n", s, fp-frame) );
         y = execute((Node *)(fcn->sval));       /* execute body */          y = execute((Node *)(fcn->sval));       /* execute body */
         dprintf( ("finished exec of %s, fp=%d\n", s, fp-frame) );             dprintf( ("finished exec of %s, fp=%d\n", s, fp-frame) );
   
         for (i = 0; i < ndef; i++) {          for (i = 0; i < ndef; i++) {
                 Cell *t = fp->args[i];                  Cell *t = fp->args[i];
Line 268 
Line 300 
                 return y;                  return y;
         tempfree(y);            /* this can free twice! */          tempfree(y);            /* this can free twice! */
         z = fp->retval;                 /* return value */          z = fp->retval;                 /* return value */
         dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );             dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
         fp--;          fp--;
         return(z);          return(z);
 }  }
Line 279 
Line 311 
   
         y = gettemp();          y = gettemp();
         y->csub = CCOPY;        /* prevents freeing until call is over */          y->csub = CCOPY;        /* prevents freeing until call is over */
         y->nval = x->nval;          y->nval = x->nval;      /* BUG? */
         y->sval = x->sval ? tostring(x->sval) : NULL;          y->sval = x->sval ? tostring(x->sval) : NULL;
         y->fval = x->fval;          y->fval = x->fval;
         y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);    /* copy is not constant or field */          y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);    /* copy is not constant or field */
Line 291 
Line 323 
 {  {
   
         n = (int) a[0]; /* argument number, counting from 0 */          n = (int) a[0]; /* argument number, counting from 0 */
         dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );             dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
         if (n+1 > fp->nargs)          if (n+1 > fp->nargs)
                 ERROR "argument #%d of function %s was not supplied",                  ERROR "argument #%d of function %s was not supplied",
                         n+1, fp->fcncell->nval FATAL;                          n+1, fp->fcncell->nval FATAL;
Line 345 
Line 377 
 Cell *getline(Node **a, int n)  /* get next line from specific input */  Cell *getline(Node **a, int n)  /* get next line from specific input */
 {               /* a[0] is variable, a[1] is operator, a[2] is filename */  {               /* a[0] is variable, a[1] is operator, a[2] is filename */
         Cell *r, *x;          Cell *r, *x;
         char buf[RECSIZE];          extern Cell **fldtab;
         FILE *fp;          FILE *fp;
           char *buf;
           int bufsize = recsize;
   
           if ((buf = (char *) malloc(bufsize)) == NULL)
                   ERROR "out of memory in getline" FATAL;
   
         fflush(stdout); /* in case someone is waiting for a prompt */          fflush(stdout); /* in case someone is waiting for a prompt */
         r = gettemp();          r = gettemp();
         if (a[1] != NULL) {             /* getline < file */          if (a[1] != NULL) {             /* getline < file */
                 x = execute(a[2]);              /* filename */                  x = execute(a[2]);              /* filename */
                 if ((int) a[1] == '|')  /* input pipe */                  if ((int) a[1] == '|')          /* input pipe */
                         a[1] = (Node *) LE;     /* arbitrary flag */                          a[1] = (Node *) LE;     /* arbitrary flag */
                 fp = openfile((int) a[1], getsval(x));                  fp = openfile((int) a[1], getsval(x));
                 tempfree(x);                  tempfree(x);
                 if (fp == NULL)                  if (fp == NULL)
                         n = -1;                          n = -1;
                 else                  else
                         n = readrec(buf, sizeof(buf), fp);                          n = readrec(&buf, &bufsize, fp);
                 if (n <= 0) {                  if (n <= 0) {
                         ;                          ;
                 } else if (a[0] != NULL) {      /* getline var <file */                  } else if (a[0] != NULL) {      /* getline var <file */
                         setsval(execute(a[0]), buf);                          x = execute(a[0]);
                           setsval(x, buf);
                           tempfree(x);
                 } else {                        /* getline <file */                  } else {                        /* getline <file */
                         if (!(recloc->tval & DONTFREE))                          setsval(fldtab[0], buf);
                                 xfree(recloc->sval);                          if (isnumber(fldtab[0]->sval)) {
                         strcpy(record, buf);                                  fldtab[0]->fval = atof(fldtab[0]->sval);
                         recloc->sval = record;                                  fldtab[0]->tval |= NUM;
                         recloc->tval = REC | STR | DONTFREE;  
                         if (isnumber(recloc->sval)) {  
                                 recloc->fval = atof(recloc->sval);  
                                 recloc->tval |= NUM;  
                         }                          }
                         donerec = 1; donefld = 0;  
                 }                  }
         } else {                        /* bare getline; use current input */          } else {                        /* bare getline; use current input */
                 if (a[0] == NULL)       /* getline */                  if (a[0] == NULL)       /* getline */
                         n = getrec(record);                          n = getrec(&record, &recsize, 1);
                 else {                  /* getline var */                  else {                  /* getline var */
                         n = getrec(buf);                          n = getrec(&buf, &bufsize, 0);
                         setsval(execute(a[0]), buf);                          x = execute(a[0]);
                           setsval(x, buf);
                           tempfree(x);
                 }                  }
         }          }
         setfval(r, (Awkfloat) n);          setfval(r, (Awkfloat) n);
           free(buf);
         return r;          return r;
 }  }
   
Line 400 
Line 437 
         Cell *x, *y, *z;          Cell *x, *y, *z;
         char *s;          char *s;
         Node *np;          Node *np;
         char buf[RECSIZE];          char *buf;
           int bufsz = recsize;
           int nsub = strlen(*SUBSEP);
   
           if ((buf = malloc(bufsz)) == NULL)
                   ERROR "out of memory in array" FATAL;
   
         x = execute(a[0]);      /* Cell* for symbol table */          x = execute(a[0]);      /* Cell* for symbol table */
         buf[0] = 0;          buf[0] = 0;
         for (np = a[1]; np; np = np->nnext) {          for (np = a[1]; np; np = np->nnext) {
                 y = execute(np);        /* subscript */                  y = execute(np);        /* subscript */
                 s = getsval(y);                  s = getsval(y);
                 strcat(buf, s);         /* BUG: unchecked! */                  if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
                           ERROR "out of memory for %s[%s...]", x->nval, buf FATAL;
                   strcat(buf, s);
                 if (np->nnext)                  if (np->nnext)
                         strcat(buf, *SUBSEP);                          strcat(buf, *SUBSEP);
                 tempfree(y);                  tempfree(y);
         }          }
         if (!isarr(x)) {          if (!isarr(x)) {
                 dprintf( ("making %s into an array\n", x->nval) );                     dprintf( ("making %s into an array\n", x->nval) );
                 if (freeable(x))                  if (freeable(x))
                         xfree(x->sval);                          xfree(x->sval);
                 x->tval &= ~(STR|NUM|DONTFREE);                  x->tval &= ~(STR|NUM|DONTFREE);
Line 424 
Line 468 
         z->ctype = OCELL;          z->ctype = OCELL;
         z->csub = CVAR;          z->csub = CVAR;
         tempfree(x);          tempfree(x);
           free(buf);
         return(z);          return(z);
 }  }
   
Line 431 
Line 476 
 {  {
         Cell *x, *y;          Cell *x, *y;
         Node *np;          Node *np;
         char buf[RECSIZE], *s;          char *s;
           int nsub = strlen(*SUBSEP);
   
         x = execute(a[0]);      /* Cell* for symbol table */          x = execute(a[0]);      /* Cell* for symbol table */
         if (!isarr(x))          if (!isarr(x))
Line 442 
Line 488 
                 x->tval |= ARR;                  x->tval |= ARR;
                 x->sval = (char *) makesymtab(NSYMTAB);                  x->sval = (char *) makesymtab(NSYMTAB);
         } else {          } else {
                   int bufsz = recsize;
                   char *buf;
                   if ((buf = malloc(bufsz)) == NULL)
                           ERROR "out of memory in adelete" FATAL;
                 buf[0] = 0;                  buf[0] = 0;
                 for (np = a[1]; np; np = np->nnext) {                  for (np = a[1]; np; np = np->nnext) {
                         y = execute(np);        /* subscript */                          y = execute(np);        /* subscript */
                         s = getsval(y);                          s = getsval(y);
                         strcat(buf, s);                          if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
                                   ERROR "out of memory deleting %s[%s...]", x->nval, buf FATAL;
                           strcat(buf, s);
                         if (np->nnext)                          if (np->nnext)
                                 strcat(buf, *SUBSEP);                                  strcat(buf, *SUBSEP);
                         tempfree(y);                          tempfree(y);
                 }                  }
                 freeelem(x, buf);                  freeelem(x, buf);
                   free(buf);
         }          }
         tempfree(x);          tempfree(x);
         return true;          return true;
Line 461 
Line 514 
 {  {
         Cell *x, *ap, *k;          Cell *x, *ap, *k;
         Node *p;          Node *p;
         char buf[RECSIZE];          char *buf;
         char *s;          char *s;
           int bufsz = recsize;
           int nsub = strlen(*SUBSEP);
   
         ap = execute(a[1]);     /* array name */          ap = execute(a[1]);     /* array name */
         if (!isarr(ap)) {          if (!isarr(ap)) {
                 dprintf( ("making %s into an array\n", ap->nval) );                     dprintf( ("making %s into an array\n", ap->nval) );
                 if (freeable(ap))                  if (freeable(ap))
                         xfree(ap->sval);                          xfree(ap->sval);
                 ap->tval &= ~(STR|NUM|DONTFREE);                  ap->tval &= ~(STR|NUM|DONTFREE);
                 ap->tval |= ARR;                  ap->tval |= ARR;
                 ap->sval = (char *) makesymtab(NSYMTAB);                  ap->sval = (char *) makesymtab(NSYMTAB);
         }          }
           if ((buf = malloc(bufsz)) == NULL) {
                   ERROR "out of memory in intest" FATAL;
           }
         buf[0] = 0;          buf[0] = 0;
         for (p = a[0]; p; p = p->nnext) {          for (p = a[0]; p; p = p->nnext) {
                 x = execute(p); /* expr */                  x = execute(p); /* expr */
                 s = getsval(x);                  s = getsval(x);
                   if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
                           ERROR "out of memory deleting %s[%s...]", x->nval, buf FATAL;
                 strcat(buf, s);                  strcat(buf, s);
                 tempfree(x);                  tempfree(x);
                 if (p->nnext)                  if (p->nnext)
Line 484 
Line 544 
         }          }
         k = lookup(buf, (Array *) ap->sval);          k = lookup(buf, (Array *) ap->sval);
         tempfree(ap);          tempfree(ap);
           free(buf);
         if (k == NULL)          if (k == NULL)
                 return(false);                  return(false);
         else          else
Line 601 
Line 662 
   
 void tfree(Cell *a)     /* free a tempcell */  void tfree(Cell *a)     /* free a tempcell */
 {  {
         if (freeable(a))          if (freeable(a)) {
                      dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) );
                 xfree(a->sval);                  xfree(a->sval);
           }
         if (a == tmps)          if (a == tmps)
                 ERROR "tempcell list is curdled" FATAL;                  ERROR "tempcell list is curdled" FATAL;
         a->cnext = tmps;          a->cnext = tmps;
Line 637 
Line 700 
         m = getfval(x);          m = getfval(x);
         if (m == 0 && !isnumber(s = getsval(x)))        /* suspicion! */          if (m == 0 && !isnumber(s = getsval(x)))        /* suspicion! */
                 ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL;                  ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL;
   /* can x->nval ever be null??? */                  /* BUG: can x->nval ever be null??? */
                 /* ERROR "illegal field $(%s)", s FATAL; */  
         tempfree(x);          tempfree(x);
         x = fieldadr(m);          x = fieldadr(m);
         x->ctype = OCELL;          x->ctype = OCELL;       /* BUG?  why are these needed? */
         x->csub = CFLD;          x->csub = CFLD;
         return(x);          return(x);
 }  }
Line 683 
Line 745 
                 n = 0;                  n = 0;
         else if (n > k - m)          else if (n > k - m)
                 n = k - m;                  n = k - m;
         dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );             dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
         y = gettemp();          y = gettemp();
         temp = s[n+m-1];        /* with thanks to John Linderman */          temp = s[n+m-1];        /* with thanks to John Linderman */
         s[n+m-1] = '\0';          s[n+m-1] = '\0';
Line 719 
Line 781 
         return(z);          return(z);
 }  }
   
 /*  #define MAXNUMSIZE      50
  * printf-like conversions  
  *   returns len of buf or -1 on error  int format(char **pbuf, int *pbufsize, char *s, Node *a)        /* printf-like conversions */
  */  
 int format(char *buf, int bufsize, char *s, Node *a)  
 {  {
         char fmt[RECSIZE];          char *fmt;
         char *p, *t, *os;          char *p, *t, *os;
         Cell *x;          Cell *x;
         int flag = 0, n;          int flag = 0, n;
           int fmtwd; /* format width */
           int fmtsz = recsize;
           char *buf = *pbuf;
           int bufsize = *pbufsize;
   
         os = s;          os = s;
         p = buf;          p = buf;
           if ((fmt = malloc(fmtsz)) == NULL)
                   ERROR "out of memory in format()" FATAL;
         while (*s) {          while (*s) {
                 if (p - buf >= bufsize)                  adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
                         return -1;  
                 if (*s != '%') {                  if (*s != '%') {
                         *p++ = *s++;                          *p++ = *s++;
                         continue;                          continue;
Line 744 
Line 809 
                         s += 2;                          s += 2;
                         continue;                          continue;
                 }                  }
                 for (t=fmt; (*t++ = *s) != '\0'; s++) {                  /* have to be real careful in case this is a huge number, eg, %100000d */
                   fmtwd = atoi(s+1);
                   if (fmtwd < 0)
                           fmtwd = -fmtwd;
                   adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
                   for (t = fmt; (*t++ = *s) != '\0'; s++) {
                           if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
                                   ERROR "format item %.30s... ran format() out of memory", os FATAL;
                         if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')                          if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
                                 break;  /* the ansi panoply */                                  break;  /* the ansi panoply */
                         if (*s == '*') {                          if (*s == '*') {
                                 x = execute(a);                                  x = execute(a);
                                 a = a->nnext;                                  a = a->nnext;
                                 sprintf((char *)t-1, "%d", (int) getfval(x));                                  sprintf(t-1, "%d", fmtwd=(int) getfval(x));
                                   if (fmtwd < 0)
                                           fmtwd = -fmtwd;
                                   adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
                                 t = fmt + strlen(fmt);                                  t = fmt + strlen(fmt);
                                 tempfree(x);                                  tempfree(x);
                         }                          }
                 }                  }
                 *t = '\0';                  *t = '\0';
                 if (t >= fmt + sizeof(fmt))                  if (fmtwd < 0)
                         ERROR "format item %.30s... too long", os FATAL;                          fmtwd = -fmtwd;
                   adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
   
                 switch (*s) {                  switch (*s) {
                 case 'f': case 'e': case 'g': case 'E': case 'G':                  case 'f': case 'e': case 'g': case 'E': case 'G':
                         flag = 1;                          flag = 1;
Line 787 
Line 864 
                         ERROR "not enough args in printf(%s)", os FATAL;                          ERROR "not enough args in printf(%s)", os FATAL;
                 x = execute(a);                  x = execute(a);
                 a = a->nnext;                  a = a->nnext;
                   n = MAXNUMSIZE;
                   if (fmtwd > n)
                           n = fmtwd;
                   adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
                 switch (flag) {                  switch (flag) {
                 case 0: sprintf((char *)p, "%s", fmt);  /* unknown, so dump it too */                  case 0: sprintf(p, "%s", fmt);  /* unknown, so dump it too */
                           t = getsval(x);
                           n = strlen(t);
                           if (fmtwd > n)
                                   n = fmtwd;
                           adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
                         p += strlen(p);                          p += strlen(p);
                         sprintf((char *)p, "%s", getsval(x));                          sprintf(p, "%s", t);
                         break;                          break;
                 case 1: sprintf((char *)p, (char *)fmt, getfval(x)); break;                  case 1: sprintf(p, fmt, getfval(x)); break;
                 case 2: sprintf((char *)p, (char *)fmt, (long) getfval(x)); break;                  case 2: sprintf(p, fmt, (long) getfval(x)); break;
                 case 3: sprintf((char *)p, (char *)fmt, (int) getfval(x)); break;                  case 3: sprintf(p, fmt, (int) getfval(x)); break;
                 case 4:                  case 4:
                         t = getsval(x);                          t = getsval(x);
                         n = strlen(t);                          n = strlen(t);
                         if (n >= bufsize)                          if (fmtwd > n)
                                 ERROR "huge string (%d chars) in printf %.30s...",                                  n = fmtwd;
                                         n, t FATAL;                          if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
                         sprintf((char *)p, (char *)fmt, t);                                  ERROR "huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t FATAL;
                           sprintf(p, fmt, t);
                         break;                          break;
                 case 5:                  case 5:
                         isnum(x) ?                          if (isnum(x)) {
                           (getfval(x) ?                                  if (getfval(x))
                             sprintf((char *)p, (char *)fmt, (int) getfval(x))                                          sprintf(p, fmt, (int) getfval(x));
                                       : (*p++ = '\0'))                                  else
                                  : sprintf((char *)p, (char *)fmt, getsval(x)[0]);                                          *p++ = '\0';
                           } else
                                   sprintf(p, fmt, getsval(x)[0]);
                         break;                          break;
                 }                  }
                 tempfree(x);                  tempfree(x);
Line 816 
Line 905 
                 s++;                  s++;
         }          }
         *p = '\0';          *p = '\0';
           free(fmt);
         for ( ; a; a = a->nnext)                /* evaluate any remaining args */          for ( ; a; a = a->nnext)                /* evaluate any remaining args */
                 execute(a);                  execute(a);
         return ((int)(p - buf));          *pbuf = buf;
           *pbufsize = bufsize;
           return p - buf;
 }  }
   
 Cell *awksprintf(Node **a, int n)               /* sprintf(a[0]) */  Cell *awksprintf(Node **a, int n)               /* sprintf(a[0]) */
 {  {
         Cell *x;          Cell *x;
         Node *y;          Node *y;
         char buf[3*RECSIZE];          char *buf;
           int bufsz=3*recsize;
   
           if ((buf=malloc(bufsz)) == NULL)
                   ERROR "out of memory in awksprintf" FATAL;
         y = a[0]->nnext;          y = a[0]->nnext;
         x = execute(a[0]);          x = execute(a[0]);
         if (format(buf, sizeof buf, getsval(x), y) == -1)          if (format(&buf, &bufsz, getsval(x), y) == -1)
                 ERROR "sprintf string %.30s... too long", buf FATAL;                  ERROR "sprintf string %.30s... too long.  can't happen.", buf FATAL;
         tempfree(x);          tempfree(x);
         x = gettemp();          x = gettemp();
         x->sval = tostring(buf);          x->sval = buf;
         x->tval = STR;          x->tval = STR;
         return(x);          return(x);
 }  }
Line 844 
Line 939 
         FILE *fp;          FILE *fp;
         Cell *x;          Cell *x;
         Node *y;          Node *y;
         char buf[3*RECSIZE];          char *buf;
         int len;          int len;
           int bufsz=3*recsize;
   
           if ((buf=malloc(bufsz)) == NULL)
                   ERROR "out of memory in awkprintf" FATAL;
         y = a[0]->nnext;          y = a[0]->nnext;
         x = execute(a[0]);          x = execute(a[0]);
         if ((len = format(buf, sizeof buf, getsval(x), y)) == -1)          if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
                 ERROR "printf string %.30s... too long", buf FATAL;                  ERROR "printf string %.30s... too long.  can't happen.", buf FATAL;
         tempfree(x);          tempfree(x);
         if (a[1] == NULL) {          if (a[1] == NULL) {
                   /* fputs(buf, stdout); */
                 fwrite(buf, len, 1, stdout);                  fwrite(buf, len, 1, stdout);
                 if (ferror(stdout))                  if (ferror(stdout))
                         ERROR "write error on stdout" FATAL;                          ERROR "write error on stdout" FATAL;
         } else {          } else {
                 fp = redirect((int)a[1], a[2]);                  fp = redirect((int)a[1], a[2]);
                   /* fputs(buf, fp); */
                 fwrite(buf, len, 1, fp);                  fwrite(buf, len, 1, fp);
                 fflush(fp);                  fflush(fp);
                 if (ferror(fp))                  if (ferror(fp))
                         ERROR "write error on %s", filename(fp) FATAL;                          ERROR "write error on %s", filename(fp) FATAL;
         }          }
           free(buf);
         return(true);          return(true);
 }  }
   
Line 967 
Line 1068 
                         x->fval = getfval(y);                          x->fval = getfval(y);
                         x->tval |= NUM;                          x->tval |= NUM;
                 }                  }
                 else if (y->tval & STR)                  else if (isstr(y))
                         setsval(x, getsval(y));                          setsval(x, getsval(y));
                 else if (y->tval & NUM)                  else if (isnum(y))
                         setfval(x, getfval(y));                          setfval(x, getfval(y));
                 else                  else
                         funnyvar(y, "read value of");                          funnyvar(y, "read value of");
Line 1084 
Line 1185 
         Cell *x = 0, *y, *ap;          Cell *x = 0, *y, *ap;
         char *s;          char *s;
         int sep;          int sep;
         char *t, temp, num[10], *fs = 0;          char *t, temp, num[50], *fs = 0;
         int n, tempstat;          int n, tempstat;
   
         y = execute(a[0]);      /* source string */          y = execute(a[0]);      /* source string */
Line 1095 
Line 1196 
                 x = execute(a[2]);                  x = execute(a[2]);
                 fs = getsval(x);                  fs = getsval(x);
         } else if ((int) a[3] == REGEXPR)          } else if ((int) a[3] == REGEXPR)
                 fs = (char*) "(regexpr)";       /* split(str,arr,/regexpr/) */                  fs = "(regexpr)";       /* split(str,arr,/regexpr/) */
         else          else
                 ERROR "illegal type of split()" FATAL;                  ERROR "illegal type of split" FATAL;
         sep = *fs;          sep = *fs;
         ap = execute(a[1]);     /* array name */          ap = execute(a[1]);     /* array name */
         freesymtab(ap);          freesymtab(ap);
         dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );             dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
         ap->tval &= ~STR;          ap->tval &= ~STR;
         ap->tval |= ARR;          ap->tval |= ARR;
         ap->sval = (char *) makesymtab(NSYMTAB);          ap->sval = (char *) makesymtab(NSYMTAB);
Line 1119 
Line 1220 
                         pfa->initstat = 2;                          pfa->initstat = 2;
                         do {                          do {
                                 n++;                                  n++;
                                 sprintf((char *)num, "%d", n);                                  sprintf(num, "%d", n);
                                 temp = *patbeg;                                  temp = *patbeg;
                                 *patbeg = '\0';                                  *patbeg = '\0';
                                 if (isnumber(s))                                  if (isnumber(s))
                                         setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);                                          setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
                                 else                                  else
                                         setsymtab(num, s, 0.0, STR, (Array *) ap->sval);                                          setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
                                 *patbeg = temp;                                  *patbeg = temp;
                                 s = patbeg + patlen;                                  s = patbeg + patlen;
                                 if (*(patbeg+patlen-1) == 0 || *s == 0) {                                  if (*(patbeg+patlen-1) == 0 || *s == 0) {
                                         n++;                                          n++;
                                         sprintf((char *)num, "%d", n);                                          sprintf(num, "%d", n);
                                         setsymtab(num, "", 0.0, STR, (Array *) ap->sval);                                          setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
                                         pfa->initstat = tempstat;                                          pfa->initstat = tempstat;
                                         goto spdone;                                          goto spdone;
Line 1138 
Line 1239 
                         } while (nematch(pfa,s));                          } while (nematch(pfa,s));
                 }                  }
                 n++;                  n++;
                 sprintf((char *)num, "%d", n);                  sprintf(num, "%d", n);
                 if (isnumber(s))                  if (isnumber(s))
                         setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);                          setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
                 else                  else
                         setsymtab(num, s, 0.0, STR, (Array *) ap->sval);                          setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
   spdone:    spdone:
Line 1158 
Line 1259 
                         while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');                          while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
                         temp = *s;                          temp = *s;
                         *s = '\0';                          *s = '\0';
                         sprintf((char *)num, "%d", n);                          sprintf(num, "%d", n);
                         if (isnumber(t))                          if (isnumber(t))
                                 setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);                                  setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
                         else                          else
                                 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);                                  setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
                         *s = temp;                          *s = temp;
Line 1171 
Line 1272 
                 for (n = 0; *s != 0; s++) {                  for (n = 0; *s != 0; s++) {
                         char buf[2];                          char buf[2];
                         n++;                          n++;
                         sprintf((char *)num, "%d", n);                          sprintf(num, "%d", n);
                         buf[0] = *s;                          buf[0] = *s;
                         buf[1] = 0;                          buf[1] = 0;
                         if (isdigit(buf[0]))                          if (isdigit(buf[0]))
Line 1187 
Line 1288 
                                 s++;                                  s++;
                         temp = *s;                          temp = *s;
                         *s = '\0';                          *s = '\0';
                         sprintf((char *)num, "%d", n);                          sprintf(num, "%d", n);
                         if (isnumber(t))                          if (isnumber(t))
                                 setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);                                  setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
                         else                          else
                                 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);                                  setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
                         *s = temp;                          *s = temp;
Line 1330 
Line 1431 
         return true;          return true;
 }  }
   
 #if 0  
         /* if someone ever wants to run over the arrays in sorted order, */  
         /* here it is.  but it will likely run slower, not faster. */  
   
         int qstrcmp(p, q)  
                 char **p, **q;  
         {  
                 return strcmp(*p, *q);  
         }  
   
         Cell *instat(Node **a, int n)   /* for (a[0] in a[1]) a[2] */  
         {  
                 Cell *x, *vp, *arrayp, *cp, *ncp, *ret;  
                 Array *tp;  
                 int i, ne;  
         #define BIGENOUGH 1000  
                 char *elems[BIGENOUGH], **ep;  
   
                 vp = execute(a[0]);  
                 arrayp = execute(a[1]);  
                 if (!isarr(arrayp))  
                         ERROR "%s is not an array", arrayp->nval FATAL;  
                 tp = (Array *) arrayp->sval;  
                 tempfree(arrayp);  
                 ep = elems;  
                 ret = true;  
                 if (tp->nelem >= BIGENOUGH)  
                         ep = (char **) malloc(tp->nelem * sizeof(char *));  
   
                 for (i = ne = 0; i < tp->size; i++)  
                         for (cp = tp->tab[i]; cp != NULL; cp = cp->cnext)  
                                 ep[ne++] = cp->nval;  
                 if (ne != tp->nelem)  
                         ERROR "can't happen: lost elems %d vs. %d", ne, tp->nelem FATAL;  
                 qsort(ep, ne, sizeof(char *), qstrcmp);  
                 for (i = 0; i < ne; i++) {  
                         setsval(vp, ep[i]);  
                         x = execute(a[2]);  
                         if (isbreak(x)) {  
                                 tempfree(vp);  
                                 break;  
                         }  
                         if (isnext(x) || isnextfile(x) || isexit(x) || isret(x)) {  
                                 tempfree(vp);  
                                 ret = x;  
                                 break;  
                         }  
                         tempfree(x);  
                 }  
                 if (ep != elems)  
                         free(ep);  
                 return ret;  
         }  
 #endif  
   
   
 Cell *bltin(Node **a, int n)    /* builtin functions. a[0] is type, a[1] is arg list */  Cell *bltin(Node **a, int n)    /* builtin functions. a[0] is type, a[1] is arg list */
 {  {
         Cell *x, *y;          Cell *x, *y;
         Awkfloat u;          Awkfloat u;
         int t;          int t;
         char *p, buf[RECSIZE];          char *p, *buf;
         Node *nextarg;          Node *nextarg;
         FILE *fp;          FILE *fp;
   
Line 1426 
Line 1471 
                 break;                  break;
         case FSYSTEM:          case FSYSTEM:
                 fflush(stdout);         /* in case something is buffered already */                  fflush(stdout);         /* in case something is buffered already */
                 u = (Awkfloat) system((char *)getsval(x)) / 256;   /* 256 is unix-dep */                  u = (Awkfloat) system(getsval(x)) / 256;   /* 256 is unix-dep */
                 break;                  break;
         case FRAND:          case FRAND:
                 /* in principle, rand() returns something in 0..RAND_MAX */                  /* in principle, rand() returns something in 0..RAND_MAX */
                 u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;                  u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
                 break;                  break;
         case FSRAND:          case FSRAND:
                 if (x->tval & REC)      /* no argument provided */                  if (isrec(x))   /* no argument provided */
                         u = time((time_t *)0);                          u = time((time_t *)0);
                 else                  else
                         u = getfval(x);                          u = getfval(x);
Line 1441 
Line 1486 
                 break;                  break;
         case FTOUPPER:          case FTOUPPER:
         case FTOLOWER:          case FTOLOWER:
                 strcpy(buf, getsval(x));                  buf = tostring(getsval(x));
                 if (t == FTOUPPER) {                  if (t == FTOUPPER) {
                         for (p = buf; *p; p++)                          for (p = buf; *p; p++)
                                 if (islower(*p))                                  if (islower(*p))
Line 1454 
Line 1499 
                 tempfree(x);                  tempfree(x);
                 x = gettemp();                  x = gettemp();
                 setsval(x, buf);                  setsval(x, buf);
                   free(buf);
                 return x;                  return x;
         case FFLUSH:          case FFLUSH:
                 if ((fp = openfile(GT, getsval(x))) == NULL)                  if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
                         u = EOF;                          u = EOF;
                 else                  else
                         u = fflush(fp);                          u = fflush(fp);
Line 1488 
Line 1534 
                 fp = redirect((int)a[1], a[2]);                  fp = redirect((int)a[1], a[2]);
         for (x = a[0]; x != NULL; x = x->nnext) {          for (x = a[0]; x != NULL; x = x->nnext) {
                 y = execute(x);                  y = execute(x);
                 fputs((char *)getsval(y), fp);                  fputs(getsval(y), fp);
                 tempfree(y);                  tempfree(y);
                 if (x->nnext == NULL)                  if (x->nnext == NULL)
                         fputs((char *)*ORS, fp);                          fputs(*ORS, fp);
                 else                  else
                         fputs((char *)*OFS, fp);                          fputs(*OFS, fp);
         }          }
         if (a[1] != 0)          if (a[1] != 0)
                 fflush(fp);                  fflush(fp);
Line 1544 
Line 1590 
         if (*s == '\0')          if (*s == '\0')
                 ERROR "null file name in print or getline" FATAL;                  ERROR "null file name in print or getline" FATAL;
         for (i=0; i < FOPEN_MAX; i++)          for (i=0; i < FOPEN_MAX; i++)
                 if (files[i].fname && strcmp(s, files[i].fname) == 0)                  if (files[i].fname && strcmp(s, files[i].fname) == 0) {
                         if (a == files[i].mode || (a==APPEND && files[i].mode==GT))                          if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
                                 return files[i].fp;                                  return files[i].fp;
                           if (a == FFLUSH)
                                   return files[i].fp;
                   }
           if (a == FFLUSH)        /* didn't find it, so don't create it! */
                   return NULL;
   
         for (i=0; i < FOPEN_MAX; i++)          for (i=0; i < FOPEN_MAX; i++)
                 if (files[i].fp == 0)                  if (files[i].fp == 0)
                         break;                          break;
Line 1629 
Line 1681 
                 }                  }
 }  }
   
 #define SUBSIZE (20 * RECSIZE)  void backsub(char **pb_ptr, char **sptr_ptr);
   
 Cell *sub(Node **a, int nnn)    /* substitute command */  Cell *sub(Node **a, int nnn)    /* substitute command */
 {  {
         char *sptr, *pb, *q;          char *sptr, *pb, *q;
         Cell *x, *y, *result;          Cell *x, *y, *result;
         char buf[SUBSIZE], *t;          char *t, *buf;
         fa *pfa;          fa *pfa;
           int bufsz = recsize;
   
           if ((buf=malloc(bufsz)) == NULL)
                   ERROR "out of memory in sub" FATAL;
         x = execute(a[3]);      /* target string */          x = execute(a[3]);      /* target string */
         t = getsval(x);          t = getsval(x);
         if (a[0] == 0)          /* 0 => a[1] is already-compiled regexpr */          if (a[0] == 0)          /* 0 => a[1] is already-compiled regexpr */
Line 1650 
Line 1705 
         y = execute(a[2]);      /* replacement string */          y = execute(a[2]);      /* replacement string */
         result = false;          result = false;
         if (pmatch(pfa, t)) {          if (pmatch(pfa, t)) {
                 pb = buf;  
                 sptr = t;                  sptr = t;
                   adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
                   pb = buf;
                 while (sptr < patbeg)                  while (sptr < patbeg)
                         *pb++ = *sptr++;                          *pb++ = *sptr++;
                 sptr = getsval(y);                  sptr = getsval(y);
                 while (*sptr != 0 && pb < buf + SUBSIZE - 1)                  while (*sptr != 0) {
                         if (*sptr == '\\' && *(sptr+1) == '&') {                          adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
                                 sptr++;         /* skip \, */                          if (*sptr == '\\') {
                                 *pb++ = *sptr++; /* add & */                                  backsub(&pb, &sptr);
                         } else if (*sptr == '&') {                          } else if (*sptr == '&') {
                                 sptr++;                                  sptr++;
                                   adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
                                 for (q = patbeg; q < patbeg+patlen; )                                  for (q = patbeg; q < patbeg+patlen; )
                                         *pb++ = *q++;                                          *pb++ = *q++;
                         } else                          } else
                                 *pb++ = *sptr++;                                  *pb++ = *sptr++;
                   }
                 *pb = '\0';                  *pb = '\0';
                 if (pb >= buf + SUBSIZE)                  if (pb > buf + bufsz)
                         ERROR "sub() result %.30s too big", buf FATAL;                          ERROR "sub result1 %.30s too big; can't happen", buf FATAL;
                 sptr = patbeg + patlen;                  sptr = patbeg + patlen;
                 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1)))                  if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
                           adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
                         while ((*pb++ = *sptr++) != 0)                          while ((*pb++ = *sptr++) != 0)
                                 ;                                  ;
                 if (pb >= buf + SUBSIZE)                  }
                         ERROR "sub() result %.30s too big", buf FATAL;                  if (pb > buf + bufsz)
                 setsval(x, buf);                          ERROR "sub result2 %.30s too big; can't happen", buf FATAL;
                   setsval(x, buf);        /* BUG: should be able to avoid copy */
                 result = true;;                  result = true;;
         }          }
         tempfree(x);          tempfree(x);
         tempfree(y);          tempfree(y);
           free(buf);
         return result;          return result;
 }  }
   
 Cell *gsub(Node **a, int nnn)   /* global substitute */  Cell *gsub(Node **a, int nnn)   /* global substitute */
 {  {
         Cell *x, *y;          Cell *x, *y;
         char *rptr, *sptr, *t, *pb;          char *rptr, *sptr, *t, *pb, *q;
         char buf[SUBSIZE];          char *buf;
         fa *pfa;          fa *pfa;
         int mflag, tempstat, num;          int mflag, tempstat, num;
           int bufsz = recsize;
   
           if ((buf=malloc(bufsz)) == NULL)
                   ERROR "out of memory in gsub" FATAL;
         mflag = 0;      /* if mflag == 0, can replace empty string */          mflag = 0;      /* if mflag == 0, can replace empty string */
         num = 0;          num = 0;
         x = execute(a[3]);      /* target string */          x = execute(a[3]);      /* target string */
Line 1708 
Line 1772 
                 pb = buf;                  pb = buf;
                 rptr = getsval(y);                  rptr = getsval(y);
                 do {                  do {
                         /*  
                         char *p;  
                         int i;  
                         printf("target string: %s, *patbeg = %o, patlen = %d\n",  
                                 t, *patbeg, patlen);  
                         printf("        match found: ");  
                         p=patbeg;  
                         for (i=0; i<patlen; i++)  
                                 printf("%c", *p++);  
                         printf("\n");  
                         */  
                         if (patlen == 0 && *patbeg != 0) {      /* matched empty string */                          if (patlen == 0 && *patbeg != 0) {      /* matched empty string */
                                 if (mflag == 0) {       /* can replace empty */                                  if (mflag == 0) {       /* can replace empty */
                                         num++;                                          num++;
                                         sptr = rptr;                                          sptr = rptr;
                                         while (*sptr != 0 && pb < buf + SUBSIZE-1)                                          while (*sptr != 0) {
                                                 if (*sptr == '\\' && *(sptr+1) == '&') {                                                  adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
                                                         sptr++;                                                  if (*sptr == '\\') {
                                                         *pb++ = *sptr++;                                                          backsub(&pb, &sptr);
                                                 } else if (*sptr == '&') {                                                  } else if (*sptr == '&') {
                                                         char *q;  
                                                         sptr++;                                                          sptr++;
                                                           adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
                                                         for (q = patbeg; q < patbeg+patlen; )                                                          for (q = patbeg; q < patbeg+patlen; )
                                                                 *pb++ = *q++;                                                                  *pb++ = *q++;
                                                 } else                                                  } else
                                                         *pb++ = *sptr++;                                                          *pb++ = *sptr++;
                                           }
                                 }                                  }
                                 if (*t == 0)    /* at end */                                  if (*t == 0)    /* at end */
                                         goto done;                                          goto done;
                                   adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
                                 *pb++ = *t++;                                  *pb++ = *t++;
                                 if (pb >= buf + SUBSIZE-1)                                  if (pb > buf + bufsz)   /* BUG: not sure of this test */
                                         ERROR "gsub() result %.30s too big", buf FATAL;                                          ERROR "gsub result0 %.30s too big; can't happen", buf FATAL;
                                 mflag = 0;                                  mflag = 0;
                         }                          }
                         else {  /* matched nonempty string */                          else {  /* matched nonempty string */
                                 num++;                                  num++;
                                 /* if (patlen <= 0)  
                                         ERROR "4: buf=%s, patlen %d, t=%s, patbeg=%s", buf, patlen, t, patbeg WARNING; */  
                                 sptr = t;                                  sptr = t;
                                 while (sptr < patbeg && pb < buf + SUBSIZE-1)                                  adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
                                   while (sptr < patbeg)
                                         *pb++ = *sptr++;                                          *pb++ = *sptr++;
                                 sptr = rptr;                                  sptr = rptr;
                                 while (*sptr != 0 && pb < buf + SUBSIZE-1)                                  while (*sptr != 0) {
                                         if (*sptr == '\\' && *(sptr+1) == '&') {                                          adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
                                                 sptr++;                                          if (*sptr == '\\') {
                                                 *pb++ = *sptr++;                                                  backsub(&pb, &sptr);
                                         } else if (*sptr == '&') {                                          } else if (*sptr == '&') {
                                                 char *q;  
                                                 sptr++;                                                  sptr++;
                                                   adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
                                                 for (q = patbeg; q < patbeg+patlen; )                                                  for (q = patbeg; q < patbeg+patlen; )
                                                         *pb++ = *q++;                                                          *pb++ = *q++;
                                         } else                                          } else
                                                 *pb++ = *sptr++;                                                  *pb++ = *sptr++;
                                   }
                                 t = patbeg + patlen;                                  t = patbeg + patlen;
                                 if (patlen == 0 || *t == 0 || *(t-1) == 0)                                  if (patlen == 0 || *t == 0 || *(t-1) == 0)
                                         goto done;                                          goto done;
                                 if (pb >= buf + SUBSIZE-1)                                  if (pb > buf + bufsz)
                                         ERROR "gsub() result %.30s too big", buf FATAL;                                          ERROR "gsub result1 %.30s too big; can't happen", buf FATAL;
                                 mflag = 1;                                  mflag = 1;
                         }                          }
                 } while (pmatch(pfa,t));                  } while (pmatch(pfa,t));
                 sptr = t;                  sptr = t;
                   adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
                 while ((*pb++ = *sptr++) != 0)                  while ((*pb++ = *sptr++) != 0)
                         ;                          ;
         done:   if (pb >= buf + SUBSIZE-1)          done:   if (pb > buf + bufsz)
                         ERROR "gsub() result %.30s too big", buf FATAL;                          ERROR "gsub result2 %.30s too big; can't happen", buf FATAL;
                 *pb = '\0';                  *pb = '\0';
                 setsval(x, buf);                  setsval(x, buf);        /* BUG: should be able to avoid copy + free */
                 pfa->initstat = tempstat;                  pfa->initstat = tempstat;
         }          }
         tempfree(x);          tempfree(x);
Line 1783 
Line 1839 
         x = gettemp();          x = gettemp();
         x->tval = NUM;          x->tval = NUM;
         x->fval = num;          x->fval = num;
           free(buf);
         return(x);          return(x);
   }
   
   void backsub(char **pb_ptr, char **sptr_ptr)    /* handle \\& variations */
   {                                               /* sptr[0] == '\\' */
           char *pb = *pb_ptr, *sptr = *sptr_ptr;
   
           if (sptr[1] == '\\') {
                   if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
                           *pb++ = '\\';
                           *pb++ = '&';
                           sptr += 4;
                   } else if (sptr[2] == '&') {    /* \\& -> \ + matched */
                           *pb++ = '\\';
                           sptr += 2;
                   } else {                        /* \\x -> \\x */
                           *pb++ = *sptr++;
                           *pb++ = *sptr++;
                   }
           } else if (sptr[1] == '&') {    /* literal & */
                   sptr++;
                   *pb++ = *sptr++;
           } else                          /* literal \ */
                   *pb++ = *sptr++;
   
           *pb_ptr = pb;
           *sptr_ptr = sptr;
 }  }

Legend:
Removed from v.1.12  
changed lines
  Added in v.1.13