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