File:  [local] / rpl / rplawk / run.c
Revision 1.2: download - view: text, annotated - select for diffs - revision graph
Wed Jun 12 09:47:52 2013 UTC (10 years, 10 months ago) by bertrand
Branches: MAIN
CVS tags: rpl-4_1_35, rpl-4_1_34, rpl-4_1_33, rpl-4_1_32, rpl-4_1_31, rpl-4_1_30, rpl-4_1_29, rpl-4_1_28, rpl-4_1_27, rpl-4_1_26, rpl-4_1_25, rpl-4_1_24, rpl-4_1_23, rpl-4_1_22, rpl-4_1_21, rpl-4_1_20, rpl-4_1_19, rpl-4_1_18, rpl-4_1_17, rpl-4_1_16, rpl-4_1_15, rpl-4_1_14, HEAD
Quelques patches pour rplawk et ncurses.

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

CVSweb interface <joel.bertrand@systella.fr>