1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
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
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
23 ****************************************************************/
37 #define tempfree(x) if (istemp(x)) tfree(x); else
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);
52 /* do we really need these? */
54 /* #ifndef FOPEN_MAX */
55 /* #define FOPEN_MAX _NFILE */
59 /* #ifndef FOPEN_MAX */
60 /* #define FOPEN_MAX 40 */ /* max number of open files */
63 /* #ifndef RAND_MAX */
64 /* #define RAND_MAX 32767 */ /* all that ansi guarantees */
68 extern int pairstack
[];
69 extern Awkfloat srand_seed
;
71 Node
*winner
= NULL
; /* root of parse tree */
72 Cell
*tmps
; /* free temporary cells for execution */
74 static Cell truecell
={ OBOOL
, BTRUE
, 0, 0, 1.0, NUM
};
75 Cell
*True
= &truecell
;
76 static Cell falsecell
={ OBOOL
, BFALSE
, 0, 0, 0.0, NUM
};
77 Cell
*False
= &falsecell
;
78 static Cell breakcell
={ OJUMP
, JBREAK
, 0, 0, 0.0, NUM
};
79 Cell
*jbreak
= &breakcell
;
80 static Cell contcell
={ OJUMP
, JCONT
, 0, 0, 0.0, NUM
};
81 Cell
*jcont
= &contcell
;
82 static Cell nextcell
={ OJUMP
, JNEXT
, 0, 0, 0.0, NUM
};
83 Cell
*jnext
= &nextcell
;
84 static Cell nextfilecell
={ OJUMP
, JNEXTFILE
, 0, 0, 0.0, NUM
};
85 Cell
*jnextfile
= &nextfilecell
;
86 static Cell exitcell
={ OJUMP
, JEXIT
, 0, 0, 0.0, NUM
};
87 Cell
*jexit
= &exitcell
;
88 static Cell retcell
={ OJUMP
, JRET
, 0, 0, 0.0, NUM
};
89 Cell
*jret
= &retcell
;
90 static Cell tempcell
={ OCELL
, CTEMP
, 0, "", 0.0, NUM
|STR
|DONTFREE
};
92 Node
*curnode
= NULL
; /* the node being executed, for debugging */
94 /* buffer memory management */
95 int adjbuf(char **pbuf
, int *psiz
, int minlen
, int quantum
, char **pbptr
,
97 /* pbuf: address of pointer to buffer being managed
98 * psiz: address of buffer size variable
99 * minlen: minimum length of buffer needed
100 * quantum: buffer size quantum
101 * pbptr: address of movable pointer into buffer, or 0 if none
102 * whatrtn: name of the calling routine if failure should cause fatal error
104 * return 0 for realloc failure, !=0 for success
107 if (minlen
> *psiz
) {
109 int rminlen
= quantum
? minlen
% quantum
: 0;
110 int boff
= pbptr
? *pbptr
- *pbuf
: 0;
111 /* round up to next multiple of quantum */
113 minlen
+= quantum
- rminlen
;
114 tbuf
= (char *) realloc(*pbuf
, minlen
);
115 dprintf( ("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn
, *psiz
, minlen
, *pbuf
, tbuf
) );
118 FATAL("out of memory in %s", whatrtn
);
124 *pbptr
= tbuf
+ boff
;
129 void run(Node
*a
) /* execution of parse tree starts here */
131 extern void stdinit(void);
138 Cell
*execute(Node
*u
) /* execute a node of the parse tree */
140 Cell
*(*proc
)(Node
**, int);
146 for (a
= u
; ; a
= a
->nnext
) {
149 x
= (Cell
*) (a
->narg
[0]);
150 if (isfld(x
) && !donefld
)
152 else if (isrec(x
) && !donerec
)
156 if (notlegal(a
->nobj
)) /* probably a Cell* but too risky to print */
157 FATAL("illegal statement");
158 proc
= proctab
[a
->nobj
-FIRSTTOKEN
];
159 x
= (*proc
)(a
->narg
, a
->nobj
);
160 if (isfld(x
) && !donefld
)
162 else if (isrec(x
) && !donerec
)
168 if (a
->nnext
== NULL
)
175 Cell
*program(Node
**a
, int n
) /* execute an awk program */
176 { /* a[0] = BEGIN, a[1] = body, a[2] = END */
179 if (setjmp(env
) != 0)
181 if (a
[0]) { /* BEGIN */
186 FATAL("illegal break, continue, next or nextfile from BEGIN");
190 while (getrec(&record
, &recsize
, 1) > 0) {
197 if (setjmp(env
) != 0) /* handles exit within END */
199 if (a
[2]) { /* END */
201 if (isbreak(x
) || isnext(x
) || iscont(x
))
202 FATAL("illegal break, continue, next or nextfile from END");
209 struct Frame
{ /* stack frame for awk function calls */
210 int nargs
; /* number of arguments in this call */
211 Cell
*fcncell
; /* pointer to Cell for function */
212 Cell
**args
; /* pointer to array of arguments after execute */
213 Cell
*retval
; /* return value */
216 #define NARGS 50 /* max args in a call */
218 struct Frame
*frame
= NULL
; /* base of stack frames; dynamically allocated */
219 int nframe
= 0; /* number of frames allocated */
220 struct Frame
*fp
= NULL
; /* frame pointer. bottom level unused */
222 Cell
*call(Node
**a
, int n
) /* function call. very kludgy and fragile */
224 static Cell newcopycell
= { OCELL
, CCOPY
, 0, "", 0.0, NUM
|STR
|DONTFREE
};
226 int freed
= 0; /* handles potential double freeing when fcn & param share a tempcell */
228 Cell
*args
[NARGS
], *oargs
[NARGS
]; /* BUG: fixed size arrays */
232 fcn
= execute(a
[0]); /* the function itself */
235 FATAL("calling undefined function %s", s
);
237 fp
= frame
= (struct Frame
*) calloc(nframe
+= 100, sizeof(struct Frame
));
239 FATAL("out of space for stack frames calling %s", s
);
241 for (ncall
= 0, x
= a
[1]; x
!= NULL
; x
= x
->nnext
) /* args in call */
243 ndef
= (int) fcn
->fval
; /* args in defn */
244 dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s
, ncall
, ndef
, (int) (fp
-frame
)) );
246 WARNING("function %s called with %d args, uses only %d",
248 if (ncall
+ ndef
> NARGS
)
249 FATAL("function %s has %d arguments, limit %d", s
, ncall
+ndef
, NARGS
);
250 for (i
= 0, x
= a
[1]; x
!= NULL
; i
++, x
= x
->nnext
) { /* get call args */
251 dprintf( ("evaluate args[%d], fp=%d:\n", i
, (int) (fp
-frame
)) );
254 dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
255 i
, NN(y
->nval
), y
->fval
, isarr(y
) ? "(array)" : NN(y
->sval
), y
->tval
) );
257 FATAL("can't use function %s as argument in %s", y
->nval
, s
);
259 args
[i
] = y
; /* arrays by ref */
261 args
[i
] = copycell(y
);
264 for ( ; i
< ndef
; i
++) { /* add null args for ones not provided */
266 *args
[i
] = newcopycell
;
268 fp
++; /* now ok to up frame */
269 if (fp
>= frame
+ nframe
) {
270 int dfp
= fp
- frame
; /* old index */
271 frame
= (struct Frame
*)
272 realloc((char *) frame
, (nframe
+= 100) * sizeof(struct Frame
));
274 FATAL("out of space for stack frames in %s", s
);
279 fp
->nargs
= ndef
; /* number defined with (excess are locals) */
280 fp
->retval
= gettemp();
282 dprintf( ("start exec of %s, fp=%d\n", s
, (int) (fp
-frame
)) );
283 y
= execute((Node
*)(fcn
->sval
)); /* execute body */
284 dprintf( ("finished exec of %s, fp=%d\n", s
, (int) (fp
-frame
)) );
286 for (i
= 0; i
< ndef
; i
++) {
287 Cell
*t
= fp
->args
[i
];
289 if (t
->csub
== CCOPY
) {
295 oargs
[i
]->tval
= t
->tval
;
296 oargs
[i
]->tval
&= ~(STR
|NUM
|DONTFREE
);
297 oargs
[i
]->sval
= t
->sval
;
301 } else if (t
!= y
) { /* kludge to prevent freeing twice */
304 } else if (t
== y
&& t
->csub
== CCOPY
) {
311 if (isexit(y
) || isnext(y
))
314 tempfree(y
); /* don't free twice! */
316 z
= fp
->retval
; /* return value */
317 dprintf( ("%s returns %g |%s| %o\n", s
, getfval(z
), getsval(z
), z
->tval
) );
322 Cell
*copycell(Cell
*x
) /* make a copy of a cell in a temp */
327 y
->csub
= CCOPY
; /* prevents freeing until call is over */
328 y
->nval
= x
->nval
; /* BUG? */
330 y
->sval
= tostring(x
->sval
);
332 y
->tval
= x
->tval
& ~(CON
|FLD
|REC
|DONTFREE
); /* copy is not constant or field */
333 /* is DONTFREE right? */
337 Cell
*arg(Node
**a
, int n
) /* nth argument of a function */
340 n
= ptoi(a
[0]); /* argument number, counting from 0 */
341 dprintf( ("arg(%d), fp->nargs=%d\n", n
, fp
->nargs
) );
343 FATAL("argument #%d of function %s was not supplied",
344 n
+1, fp
->fcncell
->nval
);
348 Cell
*jump(Node
**a
, int n
) /* break, continue, next, nextfile, return */
356 errorflag
= (int) getfval(y
);
363 if ((y
->tval
& (STR
|NUM
)) == (STR
|NUM
)) {
364 setsval(fp
->retval
, getsval(y
));
365 fp
->retval
->fval
= getfval(y
);
366 fp
->retval
->tval
|= NUM
;
368 else if (y
->tval
& STR
)
369 setsval(fp
->retval
, getsval(y
));
370 else if (y
->tval
& NUM
)
371 setfval(fp
->retval
, getfval(y
));
372 else /* can't happen */
373 FATAL("bad type variable %d", y
->tval
);
386 default: /* can't happen */
387 FATAL("illegal jump type %d", n
);
389 return 0; /* not reached */
392 Cell
*awkgetline(Node
**a
, int n
) /* get next line from specific input */
393 { /* a[0] is variable, a[1] is operator, a[2] is filename */
395 extern Cell
**fldtab
;
398 int bufsize
= recsize
;
401 if ((buf
= (char *) malloc(bufsize
)) == NULL
)
402 FATAL("out of memory in getline");
404 fflush(stdout
); /* in case someone is waiting for a prompt */
406 if (a
[1] != NULL
) { /* getline < file */
407 x
= execute(a
[2]); /* filename */
409 if (mode
== '|') /* input pipe */
410 mode
= LE
; /* arbitrary flag */
411 fp
= openfile(mode
, getsval(x
));
416 n
= readrec(&buf
, &bufsize
, fp
);
419 } else if (a
[0] != NULL
) { /* getline var <file */
423 } else { /* getline <file */
424 setsval(fldtab
[0], buf
);
425 if (is_number(fldtab
[0]->sval
)) {
426 fldtab
[0]->fval
= atof(fldtab
[0]->sval
);
427 fldtab
[0]->tval
|= NUM
;
430 } else { /* bare getline; use current input */
431 if (a
[0] == NULL
) /* getline */
432 n
= getrec(&record
, &recsize
, 1);
433 else { /* getline var */
434 n
= getrec(&buf
, &bufsize
, 0);
440 setfval(r
, (Awkfloat
) n
);
445 Cell
*getnf(Node
**a
, int n
) /* get NF */
449 return (Cell
*) a
[0];
452 Cell
*array(Node
**a
, int n
) /* a[0] is symtab, a[1] is list of subscripts */
459 int nsub
= strlen(*SUBSEP
);
461 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
462 FATAL("out of memory in array");
464 x
= execute(a
[0]); /* Cell* for symbol table */
466 for (np
= a
[1]; np
; np
= np
->nnext
) {
467 y
= execute(np
); /* subscript */
469 if (!adjbuf(&buf
, &bufsz
, strlen(buf
)+strlen(s
)+nsub
+1, recsize
, 0, "array"))
470 FATAL("out of memory for %s[%s...]", x
->nval
, buf
);
473 strcat(buf
, *SUBSEP
);
477 dprintf( ("making %s into an array\n", NN(x
->nval
)) );
480 x
->tval
&= ~(STR
|NUM
|DONTFREE
);
482 x
->sval
= (char *) makesymtab(NSYMTAB
);
484 z
= setsymtab(buf
, "", 0.0, STR
|NUM
, (Array
*) x
->sval
);
492 Cell
*awkdelete(Node
**a
, int n
) /* a[0] is symtab, a[1] is list of subscripts */
497 int nsub
= strlen(*SUBSEP
);
499 x
= execute(a
[0]); /* Cell* for symbol table */
502 if (a
[1] == 0) { /* delete the elements, not the table */
506 x
->sval
= (char *) makesymtab(NSYMTAB
);
510 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
511 FATAL("out of memory in adelete");
513 for (np
= a
[1]; np
; np
= np
->nnext
) {
514 y
= execute(np
); /* subscript */
516 if (!adjbuf(&buf
, &bufsz
, strlen(buf
)+strlen(s
)+nsub
+1, recsize
, 0, "awkdelete"))
517 FATAL("out of memory deleting %s[%s...]", x
->nval
, buf
);
520 strcat(buf
, *SUBSEP
);
530 Cell
*intest(Node
**a
, int n
) /* a[0] is index (list), a[1] is symtab */
537 int nsub
= strlen(*SUBSEP
);
539 ap
= execute(a
[1]); /* array name */
541 dprintf( ("making %s into an array\n", ap
->nval
) );
544 ap
->tval
&= ~(STR
|NUM
|DONTFREE
);
546 ap
->sval
= (char *) makesymtab(NSYMTAB
);
548 if ((buf
= (char *) malloc(bufsz
)) == NULL
) {
549 FATAL("out of memory in intest");
552 for (p
= a
[0]; p
; p
= p
->nnext
) {
553 x
= execute(p
); /* expr */
555 if (!adjbuf(&buf
, &bufsz
, strlen(buf
)+strlen(s
)+nsub
+1, recsize
, 0, "intest"))
556 FATAL("out of memory deleting %s[%s...]", x
->nval
, buf
);
560 strcat(buf
, *SUBSEP
);
562 k
= lookup(buf
, (Array
*) ap
->sval
);
572 Cell
*matchop(Node
**a
, int n
) /* ~ and match() */
578 int (*mf
)(fa
*, const char *) = match
, mode
= 0;
584 x
= execute(a
[1]); /* a[1] = target text */
586 if (a
[0] == 0) /* a[1] == 0: already-compiled reg expr */
587 i
= (*mf
)((fa
*) a
[2], s
);
589 y
= execute(a
[2]); /* a[2] = regular expr */
591 pfa
= makedfa(t
, mode
);
597 int start
= patbeg
- s
+ 1;
600 setfval(rstartloc
, (Awkfloat
) start
);
601 setfval(rlengthloc
, (Awkfloat
) patlen
);
606 } else if ((n
== MATCH
&& i
== 1) || (n
== NOTMATCH
&& i
== 0))
613 Cell
*boolop(Node
**a
, int n
) /* a[0] || a[1], a[0] && a[1], !a[0] */
630 if ( !i
) return(False
);
637 if (i
) return(False
);
639 default: /* can't happen */
640 FATAL("unknown boolean operator %d", n
);
642 return 0; /*NOTREACHED*/
645 Cell
*relop(Node
**a
, int n
) /* a[0 < a[1], etc. */
653 if (x
->tval
&NUM
&& y
->tval
&NUM
) {
654 j
= x
->fval
- y
->fval
;
655 i
= j
<0? -1: (j
>0? 1: 0);
657 i
= strcmp(getsval(x
), getsval(y
));
662 case LT
: if (i
<0) return(True
);
664 case LE
: if (i
<=0) return(True
);
666 case NE
: if (i
!=0) return(True
);
668 case EQ
: if (i
== 0) return(True
);
670 case GE
: if (i
>=0) return(True
);
672 case GT
: if (i
>0) return(True
);
674 default: /* can't happen */
675 FATAL("unknown relational operator %d", n
);
677 return 0; /*NOTREACHED*/
680 void tfree(Cell
*a
) /* free a tempcell */
683 dprintf( ("freeing %s %s %o\n", NN(a
->nval
), NN(a
->sval
), a
->tval
) );
687 FATAL("tempcell list is curdled");
692 Cell
*gettemp(void) /* get a tempcell */
697 tmps
= (Cell
*) calloc(100, sizeof(Cell
));
699 FATAL("out of space for temporaries");
700 for(i
= 1; i
< 100; i
++)
701 tmps
[i
-1].cnext
= &tmps
[i
];
710 Cell
*indirect(Node
**a
, int n
) /* $( a[0] ) */
718 val
= getfval(x
); /* freebsd: defend against super large field numbers */
719 if ((Awkfloat
)INT_MAX
< val
)
720 FATAL("trying to access out of range field %s", x
->nval
);
722 if (m
== 0 && !is_number(s
= getsval(x
))) /* suspicion! */
723 FATAL("illegal field $(%s), name \"%s\"", s
, x
->nval
);
724 /* BUG: can x->nval ever be null??? */
727 x
->ctype
= OCELL
; /* BUG? why are these needed? */
732 Cell
*substr(Node
**a
, int nnn
) /* substr(a[0], a[1], a[2]) */
755 m
= (int) getfval(y
);
762 n
= (int) getfval(z
);
770 dprintf( ("substr: m=%d, n=%d, s=%s\n", m
, n
, s
) );
772 temp
= s
[n
+m
-1]; /* with thanks to John Linderman */
774 setsval(y
, s
+ m
- 1);
780 Cell
*sindex(Node
**a
, int nnn
) /* index(a[0], a[1]) */
783 char *s1
, *s2
, *p1
, *p2
, *q
;
792 for (p1
= s1
; *p1
!= '\0'; p1
++) {
793 for (q
=p1
, p2
=s2
; *p2
!= '\0' && *q
== *p2
; q
++, p2
++)
796 v
= (Awkfloat
) (p1
- s1
+ 1); /* origin 1 */
806 #define MAXNUMSIZE 50
808 int format(char **pbuf
, int *pbufsize
, const char *s
, Node
*a
) /* printf-like conversions */
815 int fmtwd
; /* format width */
818 int bufsize
= *pbufsize
;
822 if ((fmt
= (char *) malloc(fmtsz
)) == NULL
)
823 FATAL("out of memory in format()");
825 adjbuf(&buf
, &bufsize
, MAXNUMSIZE
+1+p
-buf
, recsize
, &p
, "format1");
835 /* have to be real careful in case this is a huge number, eg, %100000d */
839 adjbuf(&buf
, &bufsize
, fmtwd
+1+p
-buf
, recsize
, &p
, "format2");
840 for (t
= fmt
; (*t
++ = *s
) != '\0'; s
++) {
841 if (!adjbuf(&fmt
, &fmtsz
, MAXNUMSIZE
+1+t
-fmt
, recsize
, &t
, "format3"))
842 FATAL("format item %.30s... ran format() out of memory", os
);
843 if (isalpha((uschar
)*s
) && *s
!= 'l' && *s
!= 'h' && *s
!= 'L')
844 break; /* the ansi panoply */
848 sprintf(t
-1, "%d", fmtwd
=(int) getfval(x
));
851 adjbuf(&buf
, &bufsize
, fmtwd
+1+p
-buf
, recsize
, &p
, "format");
852 t
= fmt
+ strlen(fmt
);
859 adjbuf(&buf
, &bufsize
, fmtwd
+1+p
-buf
, recsize
, &p
, "format4");
862 case 'f': case 'e': case 'g': case 'E': case 'G':
867 if(*(s
-1) == 'l') break;
872 case 'o': case 'x': case 'X': case 'u':
873 flag
= *(s
-1) == 'l' ? 'd' : 'u';
882 WARNING("weird printf conversion %s", fmt
);
887 FATAL("not enough args in printf(%s)", os
);
893 adjbuf(&buf
, &bufsize
, 1+n
+p
-buf
, recsize
, &p
, "format5");
895 case '?': sprintf(p
, "%s", fmt
); /* unknown, so dump it too */
900 adjbuf(&buf
, &bufsize
, 1+strlen(p
)+n
+p
-buf
, recsize
, &p
, "format6");
904 case 'f': sprintf(p
, fmt
, getfval(x
)); break;
905 case 'd': sprintf(p
, fmt
, (long) getfval(x
)); break;
906 case 'u': sprintf(p
, fmt
, (int) getfval(x
)); break;
912 if (!adjbuf(&buf
, &bufsize
, 1+n
+p
-buf
, recsize
, &p
, "format7"))
913 FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n
, t
);
919 sprintf(p
, fmt
, (int) getfval(x
));
921 *p
++ = '\0'; /* explicit null byte */
922 *p
= '\0'; /* next output will start here */
925 sprintf(p
, fmt
, getsval(x
)[0]);
928 FATAL("can't happen: bad conversion %c in format()", flag
);
936 for ( ; a
; a
= a
->nnext
) /* evaluate any remaining args */
943 Cell
*awksprintf(Node
**a
, int n
) /* sprintf(a[0]) */
950 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
951 FATAL("out of memory in awksprintf");
954 if (format(&buf
, &bufsz
, getsval(x
), y
) == -1)
955 FATAL("sprintf string %.30s... too long. can't happen.", buf
);
963 Cell
*awkprintf(Node
**a
, int n
) /* printf */
964 { /* a[0] is list of args, starting with format string */
965 /* a[1] is redirection operator, a[2] is redirection file */
973 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
974 FATAL("out of memory in awkprintf");
977 if ((len
= format(&buf
, &bufsz
, getsval(x
), y
)) == -1)
978 FATAL("printf string %.30s... too long. can't happen.", buf
);
981 /* fputs(buf, stdout); */
982 fwrite(buf
, len
, 1, stdout
);
984 FATAL("write error on stdout");
986 fp
= redirect(ptoi(a
[1]), a
[2]);
987 /* fputs(buf, fp); */
988 fwrite(buf
, len
, 1, fp
);
991 FATAL("write error on %s", filename(fp
));
997 Cell
*arith(Node
**a
, int n
) /* a[0] + a[1], etc. also -a[0] */
1024 FATAL("division by zero");
1029 FATAL("division by zero in mod");
1037 if (j
>= 0 && modf(j
, &v
) == 0.0) /* pos integer exponent */
1038 i
= ipow(i
, (int) j
);
1040 i
= errcheck(pow(i
, j
), "pow");
1042 default: /* can't happen */
1043 FATAL("illegal arithmetic operator %d", n
);
1049 double ipow(double x
, int n
) /* x**n. ought to be done by pow, but isn't always */
1062 Cell
*incrdecr(Node
**a
, int n
) /* a[0]++, etc. */
1070 k
= (n
== PREINCR
|| n
== POSTINCR
) ? 1 : -1;
1071 if (n
== PREINCR
|| n
== PREDECR
) {
1082 Cell
*assign(Node
**a
, int n
) /* a[0] = a[1], a[0] += a[1], etc. */
1083 { /* this is subtle; don't muck with it. */
1090 if (n
== ASSIGN
) { /* ordinary assignment */
1091 if (x
== y
&& !(x
->tval
& (FLD
|REC
))) /* self-assignment: */
1092 ; /* leave alone unless it's a field */
1093 else if ((y
->tval
& (STR
|NUM
)) == (STR
|NUM
)) {
1094 setsval(x
, getsval(y
));
1095 x
->fval
= getfval(y
);
1099 setsval(x
, getsval(y
));
1101 setfval(x
, getfval(y
));
1103 funnyvar(y
, "read value of");
1121 FATAL("division by zero in /=");
1126 FATAL("division by zero in %%=");
1131 if (yf
>= 0 && modf(yf
, &v
) == 0.0) /* pos integer exponent */
1132 xf
= ipow(xf
, (int) yf
);
1134 xf
= errcheck(pow(xf
, yf
), "pow");
1137 FATAL("illegal assignment operator %d", n
);
1145 Cell
*cat(Node
**a
, int q
) /* a[0] cat a[1] */
1155 n1
= strlen(x
->sval
);
1156 n2
= strlen(y
->sval
) + 1;
1157 s
= (char *) malloc(n1
+ n2
);
1159 FATAL("out of space concatenating %.15s... and %.15s...",
1161 memmove(s
, x
->sval
, n1
);
1162 memmove(s
+n1
, y
->sval
, n2
);
1171 Cell
*pastat(Node
**a
, int n
) /* a[0] { a[1] } */
1187 Cell
*dopa2(Node
**a
, int n
) /* a[0], a[1] { a[2] } */
1193 if (pairstack
[pair
] == 0) {
1196 pairstack
[pair
] = 1;
1199 if (pairstack
[pair
] == 1) {
1202 pairstack
[pair
] = 0;
1210 Cell
*split(Node
**a
, int nnn
) /* split(a[0], a[1], a[2]); a[3] is type */
1212 Cell
*x
= 0, *y
, *ap
;
1215 char *t
, temp
, num
[50], *fs
= 0;
1216 int n
, tempstat
, arg3type
;
1218 y
= execute(a
[0]); /* source string */
1219 origs
= s
= strdup(getsval(y
));
1220 arg3type
= ptoi(a
[3]);
1221 if (a
[2] == 0) /* fs string */
1223 else if (arg3type
== STRING
) { /* split(str,arr,"string") */
1226 } else if (arg3type
== REGEXPR
)
1227 fs
= "(regexpr)"; /* split(str,arr,/regexpr/) */
1229 FATAL("illegal type of split");
1231 ap
= execute(a
[1]); /* array name */
1233 dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s
, NN(ap
->nval
), fs
) );
1236 ap
->sval
= (char *) makesymtab(NSYMTAB
);
1239 if (arg3type
== REGEXPR
&& strlen((char*)((fa
*)a
[2])->restr
) == 0) {
1240 /* split(s, a, //); have to arrange that it looks like empty sep */
1245 if (*s
!= '\0' && (strlen(fs
) > 1 || arg3type
== REGEXPR
)) { /* reg expr */
1247 if (arg3type
== REGEXPR
) { /* it's ready already */
1250 pfa
= makedfa(fs
, 1);
1252 if (nematch(pfa
,s
)) {
1253 tempstat
= pfa
->initstat
;
1257 sprintf(num
, "%d", n
);
1261 setsymtab(num
, s
, atof(s
), STR
|NUM
, (Array
*) ap
->sval
);
1263 setsymtab(num
, s
, 0.0, STR
, (Array
*) ap
->sval
);
1265 s
= patbeg
+ patlen
;
1266 if (*(patbeg
+patlen
-1) == 0 || *s
== 0) {
1268 sprintf(num
, "%d", n
);
1269 setsymtab(num
, "", 0.0, STR
, (Array
*) ap
->sval
);
1270 pfa
->initstat
= tempstat
;
1273 } while (nematch(pfa
,s
));
1274 pfa
->initstat
= tempstat
; /* bwk: has to be here to reset */
1275 /* cf gsub and refldbld */
1278 sprintf(num
, "%d", n
);
1280 setsymtab(num
, s
, atof(s
), STR
|NUM
, (Array
*) ap
->sval
);
1282 setsymtab(num
, s
, 0.0, STR
, (Array
*) ap
->sval
);
1285 } else if (sep
== ' ') {
1287 while (*s
== ' ' || *s
== '\t' || *s
== '\n')
1295 while (*s
!=' ' && *s
!='\t' && *s
!='\n' && *s
!='\0');
1298 sprintf(num
, "%d", n
);
1300 setsymtab(num
, t
, atof(t
), STR
|NUM
, (Array
*) ap
->sval
);
1302 setsymtab(num
, t
, 0.0, STR
, (Array
*) ap
->sval
);
1307 } else if (sep
== 0) { /* new: split(s, a, "") => 1 char/elem */
1308 for (n
= 0; *s
!= 0; s
++) {
1311 sprintf(num
, "%d", n
);
1314 if (isdigit((uschar
)buf
[0]))
1315 setsymtab(num
, buf
, atof(buf
), STR
|NUM
, (Array
*) ap
->sval
);
1317 setsymtab(num
, buf
, 0.0, STR
, (Array
*) ap
->sval
);
1319 } else if (*s
!= 0) {
1323 while (*s
!= sep
&& *s
!= '\n' && *s
!= '\0')
1327 sprintf(num
, "%d", n
);
1329 setsymtab(num
, t
, atof(t
), STR
|NUM
, (Array
*) ap
->sval
);
1331 setsymtab(num
, t
, 0.0, STR
, (Array
*) ap
->sval
);
1340 if (a
[2] != 0 && arg3type
== STRING
) {
1349 Cell
*condexpr(Node
**a
, int n
) /* a[0] ? a[1] : a[2] */
1364 Cell
*ifstat(Node
**a
, int n
) /* if (a[0]) a[1]; else a[2] */
1372 } else if (a
[2] != 0) {
1379 Cell
*whilestat(Node
**a
, int n
) /* while (a[0]) a[1] */
1393 if (isnext(x
) || isexit(x
) || isret(x
))
1399 Cell
*dostat(Node
**a
, int n
) /* do a[0]; while(a[1]) */
1407 if (isnext(x
) || isexit(x
) || isret(x
))
1417 Cell
*forstat(Node
**a
, int n
) /* for (a[0]; a[1]; a[2]) a[3] */
1426 if (!istrue(x
)) return(x
);
1430 if (isbreak(x
)) /* turn off break */
1432 if (isnext(x
) || isexit(x
) || isret(x
))
1440 Cell
*instat(Node
**a
, int n
) /* for (a[0] in a[1]) a[2] */
1442 Cell
*x
, *vp
, *arrayp
, *cp
, *ncp
;
1447 arrayp
= execute(a
[1]);
1448 if (!isarr(arrayp
)) {
1451 tp
= (Array
*) arrayp
->sval
;
1453 for (i
= 0; i
< tp
->size
; i
++) { /* this routine knows too much */
1454 for (cp
= tp
->tab
[i
]; cp
!= NULL
; cp
= ncp
) {
1455 setsval(vp
, cp
->nval
);
1462 if (isnext(x
) || isexit(x
) || isret(x
)) {
1472 Cell
*bltin(Node
**a
, int n
) /* builtin functions. a[0] is type, a[1] is arg list */
1481 void flush_all(void);
1485 nextarg
= a
[1]->nnext
;
1489 u
= ((Array
*) x
->sval
)->nelem
; /* GROT. should be function*/
1491 u
= strlen(getsval(x
));
1494 u
= errcheck(log(getfval(x
)), "log"); break;
1496 modf(getfval(x
), &u
); break;
1498 u
= errcheck(exp(getfval(x
)), "exp"); break;
1500 u
= errcheck(sqrt(getfval(x
)), "sqrt"); break;
1502 u
= sin(getfval(x
)); break;
1504 u
= cos(getfval(x
)); break;
1507 WARNING("atan2 requires two arguments; returning 1.0");
1510 y
= execute(a
[1]->nnext
);
1511 u
= atan2(getfval(x
), getfval(y
));
1513 nextarg
= nextarg
->nnext
;
1517 fflush(stdout
); /* in case something is buffered already */
1518 u
= (Awkfloat
) system(getsval(x
)) / 256; /* 256 is unix-dep */
1521 /* in principle, rand() returns something in 0..RAND_MAX */
1522 u
= (Awkfloat
) (rand() % RAND_MAX
) / RAND_MAX
;
1525 if (isrec(x
)) /* no argument provided */
1526 u
= time((time_t *)0);
1530 srand((unsigned int) u
);
1536 buf
= tostring(getsval(x
));
1537 if (t
== FTOUPPER
) {
1538 for (p
= buf
; *p
; p
++)
1539 if (islower((uschar
) *p
))
1540 *p
= toupper((uschar
)*p
);
1542 for (p
= buf
; *p
; p
++)
1543 if (isupper((uschar
) *p
))
1544 *p
= tolower((uschar
)*p
);
1552 if (isrec(x
) || strlen(getsval(x
)) == 0) {
1553 flush_all(); /* fflush() or fflush("") -> all */
1555 } else if ((fp
= openfile(FFLUSH
, getsval(x
))) == NULL
)
1560 default: /* can't happen */
1561 FATAL("illegal function type %d", t
);
1568 WARNING("warning: function has too many arguments");
1569 for ( ; nextarg
; nextarg
= nextarg
->nnext
)
1575 Cell
*printstat(Node
**a
, int n
) /* print a[0] */
1581 if (a
[1] == 0) /* a[1] is redirection operator, a[2] is file */
1584 fp
= redirect(ptoi(a
[1]), a
[2]);
1585 for (x
= a
[0]; x
!= NULL
; x
= x
->nnext
) {
1587 fputs(getpssval(y
), fp
);
1589 if (x
->nnext
== NULL
)
1597 FATAL("write error on %s", filename(fp
));
1601 Cell
*nullproc(Node
**a
, int n
)
1609 FILE *redirect(int a
, Node
*b
) /* set up all i/o redirections */
1617 fp
= openfile(a
, fname
);
1619 FATAL("can't open file %s", fname
);
1627 int mode
; /* '|', 'a', 'w' => LE/LT, GT */
1632 void stdinit(void) /* in case stdin, etc., are not constants */
1635 files
= calloc(nfiles
, sizeof(*files
));
1637 FATAL("can't allocate file memory for %u files", nfiles
);
1638 files
[0].fp
= stdin
;
1639 files
[0].fname
= "/dev/stdin";
1641 files
[1].fp
= stdout
;
1642 files
[1].fname
= "/dev/stdout";
1644 files
[2].fp
= stderr
;
1645 files
[2].fname
= "/dev/stderr";
1649 FILE *openfile(int a
, const char *us
)
1656 FATAL("null file name in print or getline");
1657 for (i
=0; i
< nfiles
; i
++)
1658 if (files
[i
].fname
&& strcmp(s
, files
[i
].fname
) == 0) {
1659 if (a
== files
[i
].mode
|| (a
==APPEND
&& files
[i
].mode
==GT
))
1664 if (a
== FFLUSH
) /* didn't find it, so don't create it! */
1667 for (i
=0; i
< nfiles
; i
++)
1668 if (files
[i
].fp
== 0)
1672 int nnf
= nfiles
+ FOPEN_MAX
;
1673 nf
= realloc(files
, nnf
* sizeof(*nf
));
1675 FATAL("cannot grow files for %s and %d files", s
, nnf
);
1676 memset(&nf
[nfiles
], 0, FOPEN_MAX
* sizeof(*nf
));
1680 fflush(stdout
); /* force a semblance of order */
1684 } else if (a
== APPEND
) {
1686 m
= GT
; /* so can mix > and >> */
1687 } else if (a
== '|') { /* output pipe */
1689 } else if (a
== LE
) { /* input pipe */
1691 } else if (a
== LT
) { /* getline <file */
1692 fp
= strcmp(s
, "-") == 0 ? stdin
: fopen(s
, "r"); /* "-" is stdin */
1693 } else /* can't happen */
1694 FATAL("illegal redirection %d", a
);
1696 files
[i
].fname
= tostring(s
);
1703 const char *filename(FILE *fp
)
1707 for (i
= 0; i
< nfiles
; i
++)
1708 if (fp
== files
[i
].fp
)
1709 return files
[i
].fname
;
1713 Cell
*closefile(Node
**a
, int n
)
1722 for (i
= 0; i
< nfiles
; i
++) {
1723 if (files
[i
].fname
&& strcmp(x
->sval
, files
[i
].fname
) == 0) {
1724 if (ferror(files
[i
].fp
))
1725 WARNING( "i/o error occurred on %s", files
[i
].fname
);
1726 if (files
[i
].mode
== '|' || files
[i
].mode
== LE
)
1727 stat
= pclose(files
[i
].fp
);
1729 stat
= fclose(files
[i
].fp
);
1731 WARNING( "i/o error occurred closing %s", files
[i
].fname
);
1732 if (i
> 2) /* don't do /dev/std... */
1733 xfree(files
[i
].fname
);
1734 files
[i
].fname
= NULL
; /* watch out for ref thru this */
1740 setfval(x
, (Awkfloat
) stat
);
1748 for (i
= 0; i
< FOPEN_MAX
; i
++) {
1750 if (ferror(files
[i
].fp
))
1751 WARNING( "i/o error occurred on %s", files
[i
].fname
);
1752 if (files
[i
].mode
== '|' || files
[i
].mode
== LE
)
1753 stat
= pclose(files
[i
].fp
);
1755 stat
= fclose(files
[i
].fp
);
1757 WARNING( "i/o error occurred while closing %s", files
[i
].fname
);
1762 void flush_all(void)
1766 for (i
= 0; i
< nfiles
; i
++)
1768 fflush(files
[i
].fp
);
1771 void backsub(char **pb_ptr
, char **sptr_ptr
);
1773 Cell
*sub(Node
**a
, int nnn
) /* substitute command */
1775 char *sptr
, *pb
, *q
;
1776 Cell
*x
, *y
, *result
;
1779 int bufsz
= recsize
;
1781 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
1782 FATAL("out of memory in sub");
1783 x
= execute(a
[3]); /* target string */
1785 if (a
[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1786 pfa
= (fa
*) a
[1]; /* regular expression */
1789 pfa
= makedfa(getsval(y
), 1);
1792 y
= execute(a
[2]); /* replacement string */
1794 if (pmatch(pfa
, t
)) {
1796 adjbuf(&buf
, &bufsz
, 1+patbeg
-sptr
, recsize
, 0, "sub");
1798 while (sptr
< patbeg
)
1801 while (*sptr
!= 0) {
1802 adjbuf(&buf
, &bufsz
, 5+pb
-buf
, recsize
, &pb
, "sub");
1803 if (*sptr
== '\\') {
1804 backsub(&pb
, &sptr
);
1805 } else if (*sptr
== '&') {
1807 adjbuf(&buf
, &bufsz
, 1+patlen
+pb
-buf
, recsize
, &pb
, "sub");
1808 for (q
= patbeg
; q
< patbeg
+patlen
; )
1814 if (pb
> buf
+ bufsz
)
1815 FATAL("sub result1 %.30s too big; can't happen", buf
);
1816 sptr
= patbeg
+ patlen
;
1817 if ((patlen
== 0 && *patbeg
) || (patlen
&& *(sptr
-1))) {
1818 adjbuf(&buf
, &bufsz
, 1+strlen(sptr
)+pb
-buf
, 0, &pb
, "sub");
1819 while ((*pb
++ = *sptr
++) != 0)
1822 if (pb
> buf
+ bufsz
)
1823 FATAL("sub result2 %.30s too big; can't happen", buf
);
1824 setsval(x
, buf
); /* BUG: should be able to avoid copy */
1833 Cell
*gsub(Node
**a
, int nnn
) /* global substitute */
1836 char *rptr
, *sptr
, *t
, *pb
, *q
;
1839 int mflag
, tempstat
, num
;
1840 int bufsz
= recsize
;
1842 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
1843 FATAL("out of memory in gsub");
1844 mflag
= 0; /* if mflag == 0, can replace empty string */
1846 x
= execute(a
[3]); /* target string */
1848 if (a
[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1849 pfa
= (fa
*) a
[1]; /* regular expression */
1852 pfa
= makedfa(getsval(y
), 1);
1855 y
= execute(a
[2]); /* replacement string */
1856 if (pmatch(pfa
, t
)) {
1857 tempstat
= pfa
->initstat
;
1862 if (patlen
== 0 && *patbeg
!= 0) { /* matched empty string */
1863 if (mflag
== 0) { /* can replace empty */
1866 while (*sptr
!= 0) {
1867 adjbuf(&buf
, &bufsz
, 5+pb
-buf
, recsize
, &pb
, "gsub");
1868 if (*sptr
== '\\') {
1869 backsub(&pb
, &sptr
);
1870 } else if (*sptr
== '&') {
1872 adjbuf(&buf
, &bufsz
, 1+patlen
+pb
-buf
, recsize
, &pb
, "gsub");
1873 for (q
= patbeg
; q
< patbeg
+patlen
; )
1879 if (*t
== 0) /* at end */
1881 adjbuf(&buf
, &bufsz
, 2+pb
-buf
, recsize
, &pb
, "gsub");
1883 if (pb
> buf
+ bufsz
) /* BUG: not sure of this test */
1884 FATAL("gsub result0 %.30s too big; can't happen", buf
);
1887 else { /* matched nonempty string */
1890 adjbuf(&buf
, &bufsz
, 1+(patbeg
-sptr
)+pb
-buf
, recsize
, &pb
, "gsub");
1891 while (sptr
< patbeg
)
1894 while (*sptr
!= 0) {
1895 adjbuf(&buf
, &bufsz
, 5+pb
-buf
, recsize
, &pb
, "gsub");
1896 if (*sptr
== '\\') {
1897 backsub(&pb
, &sptr
);
1898 } else if (*sptr
== '&') {
1900 adjbuf(&buf
, &bufsz
, 1+patlen
+pb
-buf
, recsize
, &pb
, "gsub");
1901 for (q
= patbeg
; q
< patbeg
+patlen
; )
1906 t
= patbeg
+ patlen
;
1907 if (patlen
== 0 || *t
== 0 || *(t
-1) == 0)
1909 if (pb
> buf
+ bufsz
)
1910 FATAL("gsub result1 %.30s too big; can't happen", buf
);
1913 } while (pmatch(pfa
,t
));
1915 adjbuf(&buf
, &bufsz
, 1+strlen(sptr
)+pb
-buf
, 0, &pb
, "gsub");
1916 while ((*pb
++ = *sptr
++) != 0)
1918 done
: if (pb
< buf
+ bufsz
)
1920 else if (*(pb
-1) != '\0')
1921 FATAL("gsub result2 %.30s truncated; can't happen", buf
);
1922 setsval(x
, buf
); /* BUG: should be able to avoid copy + free */
1923 pfa
->initstat
= tempstat
;
1934 void backsub(char **pb_ptr
, char **sptr_ptr
) /* handle \\& variations */
1935 { /* sptr[0] == '\\' */
1936 char *pb
= *pb_ptr
, *sptr
= *sptr_ptr
;
1938 if (sptr
[1] == '\\') {
1939 if (sptr
[2] == '\\' && sptr
[3] == '&') { /* \\\& -> \& */
1943 } else if (sptr
[2] == '&') { /* \\& -> \ + matched */
1946 } else { /* \\x -> \\x */
1950 } else if (sptr
[1] == '&') { /* literal & */
1953 } else /* literal \ */