File:  [local] / rpl / rplawk / run.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Sep 7 12:53:06 2010 UTC (13 years, 8 months ago) by bertrand
Branches: MAIN
CVS tags: rpl-4_1_9, rpl-4_1_8, rpl-4_1_7, rpl-4_1_6, rpl-4_1_5, rpl-4_1_4, rpl-4_1_3, rpl-4_1_2, rpl-4_1_13, rpl-4_1_12, rpl-4_1_11, rpl-4_1_10, rpl-4_1_1, rpl-4_1_0, rpl-4_0_24, rpl-4_0_22, rpl-4_0_21, rpl-4_0_20, rpl-4_0_19, rpl-4_0, HEAD
Ajout d'un AWK interne pour éviter des problèmes sur les OS non Unix.

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

CVSweb interface <joel.bertrand@systella.fr>