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