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