Add our READMEs.
[dragonfly/port-amd64.git] / contrib / awk20050424 / run.c
blob5f29a643013ffa0be817b55c60d94857864e81bb
1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
3 All Rights Reserved
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.
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 ****************************************************************/
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"
37 #define tempfree(x) if (istemp(x)) tfree(x); else
40 #undef tempfree
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);
47 if (istemp(p))
48 tfree(p);
52 #ifdef _NFILE
53 #ifndef FOPEN_MAX
54 #define FOPEN_MAX _NFILE
55 #endif
56 #endif
58 #ifndef FOPEN_MAX
59 #define FOPEN_MAX 40 /* max number of open files */
60 #endif
62 #ifndef RAND_MAX
63 #define RAND_MAX 32767 /* all that ansi guarantees */
64 #endif
66 jmp_buf env;
67 extern int pairstack[];
69 Node *winner = NULL; /* root of parse tree */
70 Cell *tmps; /* free temporary cells for execution */
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 };
90 Node *curnode = NULL; /* the node being executed, for debugging */
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
102 * return 0 for realloc failure, !=0 for success
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;
118 *pbuf = tbuf;
119 *psiz = minlen;
120 if (pbptr)
121 *pbptr = tbuf + boff;
123 return 1;
126 void run(Node *a) /* execution of parse tree starts here */
128 extern void stdinit(void);
130 stdinit();
131 execute(a);
132 closeall();
135 Cell *execute(Node *u) /* execute a node of the parse tree */
137 Cell *(*proc)(Node **, int);
138 Cell *x;
139 Node *a;
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);
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);
172 Cell *program(Node **a, int n) /* execute an awk program */
173 { /* a[0] = BEGIN, a[1] = body, a[2] = END */
174 Cell *x;
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);
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);
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);
202 ex1:
203 return(True);
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 */
213 #define NARGS 50 /* max args in a call */
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 */
219 Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
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;
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);
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);
261 for ( ; i < ndef; i++) { /* add null args for ones not provided */
262 args[i] = gettemp();
263 *args[i] = newcopycell;
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;
274 fp->fcncell = fcn;
275 fp->args = args;
276 fp->nargs = ndef; /* number defined with (excess are locals) */
277 fp->retval = gettemp();
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)) );
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);
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;
307 tempfree(fcn);
308 if (isexit(y) || isnext(y))
309 return y;
310 if (freed == 0) {
311 tempfree(y); /* don't free twice! */
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);
319 Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
321 Cell *y;
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;
334 Cell *arg(Node **a, int n) /* nth argument of a function */
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];
345 Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
347 Cell *y;
349 switch (n) {
350 case EXIT:
351 if (a[0] != NULL) {
352 y = execute(a[0]);
353 errorflag = (int) getfval(y);
354 tempfree(y);
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;
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);
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);
386 return 0; /* not reached */
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;
398 if ((buf = (char *) malloc(bufsize)) == NULL)
399 FATAL("out of memory in getline");
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) {
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;
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);
437 setfval(r, (Awkfloat) n);
438 free(buf);
439 return r;
442 Cell *getnf(Node **a, int n) /* get NF */
444 if (donefld == 0)
445 fldbld();
446 return (Cell *) a[0];
449 Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
451 Cell *x, *y, *z;
452 char *s;
453 Node *np;
454 char *buf;
455 int bufsz = recsize;
456 int nsub = strlen(*SUBSEP);
458 if ((buf = (char *) malloc(bufsz)) == NULL)
459 FATAL("out of memory in array");
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);
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);
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);
489 Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
491 Cell *x, *y;
492 Node *np;
493 char *s;
494 int nsub = strlen(*SUBSEP);
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);
520 freeelem(x, buf);
521 free(buf);
523 tempfree(x);
524 return True;
527 Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
529 Cell *x, *ap, *k;
530 Node *p;
531 char *buf;
532 char *s;
533 int bufsz = recsize;
534 int nsub = strlen(*SUBSEP);
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);
545 if ((buf = (char *) malloc(bufsz)) == NULL) {
546 FATAL("out of memory in intest");
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);
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);
569 Cell *matchop(Node **a, int n) /* ~ and match() */
571 Cell *x, *y;
572 char *s, *t;
573 int i;
574 fa *pfa;
575 int (*mf)(fa *, const char *) = match, mode = 0;
577 if (n == MATCHFCN) {
578 mf = pmatch;
579 mode = 1;
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);
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);
610 Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
612 Cell *x, *y;
613 int i;
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);
639 return 0; /*NOTREACHED*/
642 Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
644 int i;
645 Cell *x, *y;
646 Awkfloat j;
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));
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);
674 return 0; /*NOTREACHED*/
677 void tfree(Cell *a) /* free a tempcell */
679 if (freeable(a)) {
680 dprintf( ("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval) );
681 xfree(a->sval);
683 if (a == tmps)
684 FATAL("tempcell list is curdled");
685 a->cnext = tmps;
686 tmps = a;
689 Cell *gettemp(void) /* get a tempcell */
690 { int i;
691 Cell *x;
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;
701 x = tmps;
702 tmps = x->cnext;
703 *x = tempcell;
704 return(x);
707 Cell *indirect(Node **a, int n) /* $( a[0] ) */
709 Awkfloat val;
710 Cell *x;
711 int m;
712 char *s;
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);
729 Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
731 int k, m, n;
732 char *s;
733 int temp;
734 Cell *x, *y, *z = 0;
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);
748 x = gettemp();
749 setsval(x, "");
750 return(x);
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);
777 Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
779 Cell *x, *y, *z;
780 char *s1, *s2, *p1, *p2, *q;
781 Awkfloat v = 0.0;
783 x = execute(a[0]);
784 s1 = getsval(x);
785 y = execute(a[1]);
786 s2 = getsval(y);
788 z = gettemp();
789 for (p1 = s1; *p1 != '\0'; p1++) {
790 for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
792 if (*p2 == '\0') {
793 v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
794 break;
797 tempfree(x);
798 tempfree(y);
799 setfval(z, v);
800 return(z);
803 #define MAXNUMSIZE 50
805 int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */
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;
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;
827 if (*(s+1) == '%') {
828 *p++ = '%';
829 s += 2;
830 continue;
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);
853 *t = '\0';
854 if (fmtwd < 0)
855 fmtwd = -fmtwd;
856 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
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;
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 */
921 } else
922 sprintf(p, fmt, getsval(x)[0]);
923 break;
924 default:
925 FATAL("can't happen: bad conversion %c in format()", flag);
927 tempfree(x);
928 p += strlen(p);
929 s++;
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;
940 Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
942 Cell *x;
943 Node *y;
944 char *buf;
945 int bufsz=3*recsize;
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);
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;
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));
990 free(buf);
991 return(True);
994 Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
996 Awkfloat i, j = 0;
997 double v;
998 Cell *x, *y, *z;
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);
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);
1042 setfval(z, i);
1043 return(z);
1046 double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
1048 double v;
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;
1059 Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
1061 Cell *x, *z;
1062 int k;
1063 Awkfloat xf;
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);
1072 z = gettemp();
1073 setfval(z, xf);
1074 setfval(x, xf + k);
1075 tempfree(x);
1076 return(z);
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;
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;
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);
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;
1137 tempfree(y);
1138 setfval(x, xf);
1139 return(x);
1142 Cell *cat(Node **a, int q) /* a[0] cat a[1] */
1144 Cell *x, *y, *z;
1145 int n1, n2;
1146 char *s;
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);
1168 Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
1170 Cell *x;
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]);
1181 return x;
1184 Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
1186 Cell *x;
1187 int pair;
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);
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);
1204 return(False);
1207 Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
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;
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);
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);
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;
1264 } while (nematch(pfa,s));
1265 pfa->initstat = tempstat; /* bwk: has to be here to reset */
1266 /* cf gsub and refldbld */
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;
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++;
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);
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;
1328 tempfree(ap);
1329 tempfree(y);
1330 if (a[2] != 0 && arg3type == STRING) {
1331 tempfree(x);
1333 x = gettemp();
1334 x->tval = NUM;
1335 x->fval = n;
1336 return(x);
1339 Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1341 Cell *x;
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]);
1351 return(x);
1354 Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1356 Cell *x;
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]);
1366 return(x);
1369 Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
1371 Cell *x;
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);
1383 if (isnext(x) || isexit(x) || isret(x))
1384 return(x);
1385 tempfree(x);
1389 Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
1391 Cell *x;
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);
1407 Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
1409 Cell *x;
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);
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);
1430 Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1432 Cell *x, *vp, *arrayp, *cp, *ncp;
1433 Array *tp;
1434 int i;
1436 vp = execute(a[0]);
1437 arrayp = execute(a[1]);
1438 if (!isarr(arrayp)) {
1439 return True;
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;
1452 if (isnext(x) || isexit(x) || isret(x)) {
1453 tempfree(vp);
1454 return(x);
1456 tempfree(x);
1459 return True;
1462 Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
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);
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;
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);
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;
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);
1558 return(x);
1561 Cell *printstat(Node **a, int n) /* print a[0] */
1563 Node *x;
1564 Cell *y;
1565 FILE *fp;
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);
1580 if (a[1] != 0)
1581 fflush(fp);
1582 if (ferror(fp))
1583 FATAL("write error on %s", filename(fp));
1584 return(True);
1587 Cell *nullproc(Node **a, int n)
1589 n = n;
1590 a = a;
1591 return 0;
1595 FILE *redirect(int a, Node *b) /* set up all i/o redirections */
1597 FILE *fp;
1598 Cell *x;
1599 char *fname;
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;
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 }
1620 void stdinit(void) /* in case stdin, etc., are not constants */
1622 files[0].fp = stdin;
1623 files[1].fp = stdout;
1624 files[2].fp = stderr;
1627 FILE *openfile(int a, const char *us)
1629 const char *s = us;
1630 int i, m;
1631 FILE *fp = 0;
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;
1642 if (a == FFLUSH) /* didn't find it, so don't create it! */
1643 return NULL;
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;
1670 return fp;
1673 const char *filename(FILE *fp)
1675 int i;
1677 for (i = 0; i < FOPEN_MAX; i++)
1678 if (fp == files[i].fp)
1679 return files[i].fname;
1680 return "???";
1683 Cell *closefile(Node **a, int n)
1685 Cell *x;
1686 int i, stat;
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;
1708 tempfree(x);
1709 x = gettemp();
1710 setfval(x, (Awkfloat) stat);
1711 return(x);
1714 void closeall(void)
1716 int i, stat;
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 );
1732 void flush_all(void)
1734 int i;
1736 for (i = 0; i < FOPEN_MAX; i++)
1737 if (files[i].fp)
1738 fflush(files[i].fp);
1741 void backsub(char **pb_ptr, char **sptr_ptr);
1743 Cell *sub(Node **a, int nnn) /* substitute command */
1745 char *sptr, *pb, *q;
1746 Cell *x, *y, *result;
1747 char *t, *buf;
1748 fa *pfa;
1749 int bufsz = recsize;
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);
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++;
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)
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;;
1797 tempfree(x);
1798 tempfree(y);
1799 free(buf);
1800 return result;
1803 Cell *gsub(Node **a, int nnn) /* global substitute */
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;
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);
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++;
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;
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++;
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;
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)
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;
1894 tempfree(x);
1895 tempfree(y);
1896 x = gettemp();
1897 x->tval = NUM;
1898 x->fval = num;
1899 free(buf);
1900 return(x);
1903 void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
1904 { /* sptr[0] == '\\' */
1905 char *pb = *pb_ptr, *sptr = *sptr_ptr;
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++;
1919 } else if (sptr[1] == '&') { /* literal & */
1920 sptr++;
1921 *pb++ = *sptr++;
1922 } else /* literal \ */
1923 *pb++ = *sptr++;
1925 *pb_ptr = pb;
1926 *sptr_ptr = sptr;