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