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