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