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);
54 #define FOPEN_MAX _NFILE
59 #define FOPEN_MAX 40 /* max number of open files */
63 #define RAND_MAX 32767 /* all that ansi guarantees */
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
,
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
) {
107 int rminlen
= quantum
? minlen
% quantum
: 0;
108 int boff
= pbptr
? *pbptr
- *pbuf
: 0;
109 /* round up to next multiple of quantum */
111 minlen
+= quantum
- rminlen
;
112 tbuf
= (char *) realloc(*pbuf
, minlen
);
115 FATAL("out of memory in %s", whatrtn
);
121 *pbptr
= tbuf
+ boff
;
126 void run(Node
*a
) /* execution of parse tree starts here */
128 extern void stdinit(void);
135 Cell
*execute(Node
*u
) /* execute a node of the parse tree */
137 Cell
*(*proc
)(Node
**, int);
143 for (a
= u
; ; a
= a
->nnext
) {
146 x
= (Cell
*) (a
->narg
[0]);
147 if (isfld(x
) && !donefld
)
149 else if (isrec(x
) && !donerec
)
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
)
159 else if (isrec(x
) && !donerec
)
165 if (a
->nnext
== NULL
)
172 Cell
*program(Node
**a
, int n
) /* execute an awk program */
173 { /* a[0] = BEGIN, a[1] = body, a[2] = END */
176 if (setjmp(env
) != 0)
178 if (a
[0]) { /* BEGIN */
183 FATAL("illegal break, continue, next or nextfile from BEGIN");
187 while (getrec(&record
, &recsize
, 1) > 0) {
194 if (setjmp(env
) != 0) /* handles exit within END */
196 if (a
[2]) { /* END */
198 if (isbreak(x
) || isnext(x
) || iscont(x
))
199 FATAL("illegal break, continue, next or nextfile from END");
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
};
223 int freed
= 0; /* handles potential double freeing when fcn & param share a tempcell */
225 Cell
*args
[NARGS
], *oargs
[NARGS
]; /* BUG: fixed size arrays */
229 fcn
= execute(a
[0]); /* the function itself */
232 FATAL("calling undefined function %s", s
);
234 fp
= frame
= (struct Frame
*) calloc(nframe
+= 100, sizeof(struct Frame
));
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 */
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
)) );
243 WARNING("function %s called with %d args, uses only %d",
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
)) );
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
) );
254 FATAL("can't use function %s as argument in %s", y
->nval
, s
);
256 args
[i
] = y
; /* arrays by ref */
258 args
[i
] = copycell(y
);
261 for ( ; i
< ndef
; i
++) { /* add null args for ones not provided */
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
));
271 FATAL("out of space for stack frames in %s", s
);
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
];
286 if (t
->csub
== CCOPY
) {
292 oargs
[i
]->tval
= t
->tval
;
293 oargs
[i
]->tval
&= ~(STR
|NUM
|DONTFREE
);
294 oargs
[i
]->sval
= t
->sval
;
298 } else if (t
!= y
) { /* kludge to prevent freeing twice */
301 } else if (t
== y
&& t
->csub
== CCOPY
) {
308 if (isexit(y
) || isnext(y
))
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
) );
319 Cell
*copycell(Cell
*x
) /* make a copy of a cell in a temp */
324 y
->csub
= CCOPY
; /* prevents freeing until call is over */
325 y
->nval
= x
->nval
; /* BUG? */
327 y
->sval
= tostring(x
->sval
);
329 y
->tval
= x
->tval
& ~(CON
|FLD
|REC
|DONTFREE
); /* copy is not constant or field */
330 /* is DONTFREE right? */
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
) );
340 FATAL("argument #%d of function %s was not supplied",
341 n
+1, fp
->fcncell
->nval
);
345 Cell
*jump(Node
**a
, int n
) /* break, continue, next, nextfile, return */
353 errorflag
= (int) getfval(y
);
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
);
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 */
392 extern Cell
**fldtab
;
395 int bufsize
= recsize
;
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 */
403 if (a
[1] != NULL
) { /* getline < file */
404 x
= execute(a
[2]); /* filename */
406 if (mode
== '|') /* input pipe */
407 mode
= LE
; /* arbitrary flag */
408 fp
= openfile(mode
, getsval(x
));
413 n
= readrec(&buf
, &bufsize
, fp
);
416 } else if (a
[0] != NULL
) { /* getline var <file */
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);
437 setfval(r
, (Awkfloat
) n
);
442 Cell
*getnf(Node
**a
, int n
) /* get NF */
446 return (Cell
*) a
[0];
449 Cell
*array(Node
**a
, int n
) /* a[0] is symtab, a[1] is list of subscripts */
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 */
463 for (np
= a
[1]; np
; np
= np
->nnext
) {
464 y
= execute(np
); /* subscript */
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
);
470 strcat(buf
, *SUBSEP
);
474 dprintf( ("making %s into an array\n", NN(x
->nval
)) );
477 x
->tval
&= ~(STR
|NUM
|DONTFREE
);
479 x
->sval
= (char *) makesymtab(NSYMTAB
);
481 z
= setsymtab(buf
, "", 0.0, STR
|NUM
, (Array
*) x
->sval
);
489 Cell
*awkdelete(Node
**a
, int n
) /* a[0] is symtab, a[1] is list of subscripts */
494 int nsub
= strlen(*SUBSEP
);
496 x
= execute(a
[0]); /* Cell* for symbol table */
499 if (a
[1] == 0) { /* delete the elements, not the table */
503 x
->sval
= (char *) makesymtab(NSYMTAB
);
507 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
508 FATAL("out of memory in adelete");
510 for (np
= a
[1]; np
; np
= np
->nnext
) {
511 y
= execute(np
); /* subscript */
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
);
517 strcat(buf
, *SUBSEP
);
527 Cell
*intest(Node
**a
, int n
) /* a[0] is index (list), a[1] is symtab */
534 int nsub
= strlen(*SUBSEP
);
536 ap
= execute(a
[1]); /* array name */
538 dprintf( ("making %s into an array\n", ap
->nval
) );
541 ap
->tval
&= ~(STR
|NUM
|DONTFREE
);
543 ap
->sval
= (char *) makesymtab(NSYMTAB
);
545 if ((buf
= (char *) malloc(bufsz
)) == NULL
) {
546 FATAL("out of memory in intest");
549 for (p
= a
[0]; p
; p
= p
->nnext
) {
550 x
= execute(p
); /* expr */
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
);
557 strcat(buf
, *SUBSEP
);
559 k
= lookup(buf
, (Array
*) ap
->sval
);
569 Cell
*matchop(Node
**a
, int n
) /* ~ and match() */
575 int (*mf
)(fa
*, const char *) = match
, mode
= 0;
581 x
= execute(a
[1]); /* a[1] = target text */
583 if (a
[0] == 0) /* a[1] == 0: already-compiled reg expr */
584 i
= (*mf
)((fa
*) a
[2], s
);
586 y
= execute(a
[2]); /* a[2] = regular expr */
588 pfa
= makedfa(t
, mode
);
594 int start
= patbeg
- s
+ 1;
597 setfval(rstartloc
, (Awkfloat
) start
);
598 setfval(rlengthloc
, (Awkfloat
) patlen
);
603 } else if ((n
== MATCH
&& i
== 1) || (n
== NOTMATCH
&& i
== 0))
610 Cell
*boolop(Node
**a
, int n
) /* a[0] || a[1], a[0] && a[1], !a[0] */
627 if ( !i
) return(False
);
634 if (i
) return(False
);
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. */
650 if (x
->tval
&NUM
&& y
->tval
&NUM
) {
651 j
= x
->fval
- y
->fval
;
652 i
= j
<0? -1: (j
>0? 1: 0);
654 i
= strcmp(getsval(x
), getsval(y
));
659 case LT
: if (i
<0) return(True
);
661 case LE
: if (i
<=0) return(True
);
663 case NE
: if (i
!=0) return(True
);
665 case EQ
: if (i
== 0) return(True
);
667 case GE
: if (i
>=0) return(True
);
669 case GT
: if (i
>0) return(True
);
671 default: /* can't happen */
672 FATAL("unknown relational operator %d", n
);
674 return 0; /*NOTREACHED*/
677 void tfree(Cell
*a
) /* free a tempcell */
680 dprintf( ("freeing %s %s %o\n", NN(a
->nval
), NN(a
->sval
), a
->tval
) );
684 FATAL("tempcell list is curdled");
689 Cell
*gettemp(void) /* get a tempcell */
694 tmps
= (Cell
*) calloc(100, sizeof(Cell
));
696 FATAL("out of space for temporaries");
697 for(i
= 1; i
< 100; i
++)
698 tmps
[i
-1].cnext
= &tmps
[i
];
707 Cell
*indirect(Node
**a
, int n
) /* $( 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
);
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??? */
724 x
->ctype
= OCELL
; /* BUG? why are these needed? */
729 Cell
*substr(Node
**a
, int nnn
) /* substr(a[0], a[1], a[2]) */
752 m
= (int) getfval(y
);
759 n
= (int) getfval(z
);
767 dprintf( ("substr: m=%d, n=%d, s=%s\n", m
, n
, s
) );
769 temp
= s
[n
+m
-1]; /* with thanks to John Linderman */
771 setsval(y
, s
+ m
- 1);
777 Cell
*sindex(Node
**a
, int nnn
) /* index(a[0], a[1]) */
780 char *s1
, *s2
, *p1
, *p2
, *q
;
789 for (p1
= s1
; *p1
!= '\0'; p1
++) {
790 for (q
=p1
, p2
=s2
; *p2
!= '\0' && *q
== *p2
; q
++, p2
++)
793 v
= (Awkfloat
) (p1
- s1
+ 1); /* origin 1 */
803 #define MAXNUMSIZE 50
805 int format(char **pbuf
, int *pbufsize
, const char *s
, Node
*a
) /* printf-like conversions */
812 int fmtwd
; /* format width */
815 int bufsize
= *pbufsize
;
819 if ((fmt
= (char *) malloc(fmtsz
)) == NULL
)
820 FATAL("out of memory in format()");
822 adjbuf(&buf
, &bufsize
, MAXNUMSIZE
+1+p
-buf
, recsize
, &p
, "format");
832 /* have to be real careful in case this is a huge number, eg, %100000d */
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 */
845 sprintf(t
-1, "%d", fmtwd
=(int) getfval(x
));
848 adjbuf(&buf
, &bufsize
, fmtwd
+1+p
-buf
, recsize
, &p
, "format");
849 t
= fmt
+ strlen(fmt
);
856 adjbuf(&buf
, &bufsize
, fmtwd
+1+p
-buf
, recsize
, &p
, "format");
859 case 'f': case 'e': case 'g': case 'E': case 'G':
864 if(*(s
-1) == 'l') break;
869 case 'o': case 'x': case 'X': case 'u':
870 flag
= *(s
-1) == 'l' ? 'd' : 'u';
879 WARNING("weird printf conversion %s", fmt
);
884 FATAL("not enough args in printf(%s)", os
);
890 adjbuf(&buf
, &bufsize
, 1+n
+p
-buf
, recsize
, &p
, "format");
892 case '?': sprintf(p
, "%s", fmt
); /* unknown, so dump it too */
897 adjbuf(&buf
, &bufsize
, 1+strlen(p
)+n
+p
-buf
, recsize
, &p
, "format");
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;
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
);
916 sprintf(p
, fmt
, (int) getfval(x
));
918 *p
++ = '\0'; /* explicit null byte */
919 *p
= '\0'; /* next output will start here */
922 sprintf(p
, fmt
, getsval(x
)[0]);
925 FATAL("can't happen: bad conversion %c in format()", flag
);
933 for ( ; a
; a
= a
->nnext
) /* evaluate any remaining args */
940 Cell
*awksprintf(Node
**a
, int n
) /* sprintf(a[0]) */
947 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
948 FATAL("out of memory in awksprintf");
951 if (format(&buf
, &bufsz
, getsval(x
), y
) == -1)
952 FATAL("sprintf string %.30s... too long. can't happen.", buf
);
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 */
970 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
971 FATAL("out of memory in awkprintf");
974 if ((len
= format(&buf
, &bufsz
, getsval(x
), y
)) == -1)
975 FATAL("printf string %.30s... too long. can't happen.", buf
);
978 /* fputs(buf, stdout); */
979 fwrite(buf
, len
, 1, stdout
);
981 FATAL("write error on stdout");
983 fp
= redirect(ptoi(a
[1]), a
[2]);
984 /* fputs(buf, fp); */
985 fwrite(buf
, len
, 1, fp
);
988 FATAL("write error on %s", filename(fp
));
994 Cell
*arith(Node
**a
, int n
) /* a[0] + a[1], etc. also -a[0] */
1021 FATAL("division by zero");
1026 FATAL("division by zero in mod");
1034 if (j
>= 0 && modf(j
, &v
) == 0.0) /* pos integer exponent */
1035 i
= ipow(i
, (int) j
);
1037 i
= errcheck(pow(i
, j
), "pow");
1039 default: /* can't happen */
1040 FATAL("illegal arithmetic operator %d", n
);
1046 double ipow(double x
, int n
) /* x**n. ought to be done by pow, but isn't always */
1059 Cell
*incrdecr(Node
**a
, int n
) /* a[0]++, etc. */
1067 k
= (n
== PREINCR
|| n
== POSTINCR
) ? 1 : -1;
1068 if (n
== PREINCR
|| n
== PREDECR
) {
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. */
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
);
1096 setsval(x
, getsval(y
));
1098 setfval(x
, getfval(y
));
1100 funnyvar(y
, "read value of");
1118 FATAL("division by zero in /=");
1123 FATAL("division by zero in %%=");
1128 if (yf
>= 0 && modf(yf
, &v
) == 0.0) /* pos integer exponent */
1129 xf
= ipow(xf
, (int) yf
);
1131 xf
= errcheck(pow(xf
, yf
), "pow");
1134 FATAL("illegal assignment operator %d", n
);
1142 Cell
*cat(Node
**a
, int q
) /* a[0] cat a[1] */
1152 n1
= strlen(x
->sval
);
1153 n2
= strlen(y
->sval
);
1154 s
= (char *) malloc(n1
+ n2
+ 1);
1156 FATAL("out of space concatenating %.15s... and %.15s...",
1159 strcpy(s
+n1
, y
->sval
);
1168 Cell
*pastat(Node
**a
, int n
) /* a[0] { a[1] } */
1184 Cell
*dopa2(Node
**a
, int n
) /* a[0], a[1] { a[2] } */
1190 if (pairstack
[pair
] == 0) {
1193 pairstack
[pair
] = 1;
1196 if (pairstack
[pair
] == 1) {
1199 pairstack
[pair
] = 0;
1207 Cell
*split(Node
**a
, int nnn
) /* split(a[0], a[1], a[2]); a[3] is type */
1209 Cell
*x
= 0, *y
, *ap
;
1212 char *t
, temp
, num
[50], *fs
= 0;
1213 int n
, tempstat
, arg3type
;
1215 y
= execute(a
[0]); /* source string */
1217 arg3type
= ptoi(a
[3]);
1218 if (a
[2] == 0) /* fs string */
1220 else if (arg3type
== STRING
) { /* split(str,arr,"string") */
1223 } else if (arg3type
== REGEXPR
)
1224 fs
= "(regexpr)"; /* split(str,arr,/regexpr/) */
1226 FATAL("illegal type of split");
1228 ap
= execute(a
[1]); /* array name */
1230 dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s
, NN(ap
->nval
), fs
) );
1233 ap
->sval
= (char *) makesymtab(NSYMTAB
);
1236 if (*s
!= '\0' && (strlen(fs
) > 1 || arg3type
== REGEXPR
)) { /* reg expr */
1238 if (arg3type
== REGEXPR
) { /* it's ready already */
1241 pfa
= makedfa(fs
, 1);
1243 if (nematch(pfa
,s
)) {
1244 tempstat
= pfa
->initstat
;
1248 sprintf(num
, "%d", n
);
1252 setsymtab(num
, s
, atof(s
), STR
|NUM
, (Array
*) ap
->sval
);
1254 setsymtab(num
, s
, 0.0, STR
, (Array
*) ap
->sval
);
1256 s
= patbeg
+ patlen
;
1257 if (*(patbeg
+patlen
-1) == 0 || *s
== 0) {
1259 sprintf(num
, "%d", n
);
1260 setsymtab(num
, "", 0.0, STR
, (Array
*) ap
->sval
);
1261 pfa
->initstat
= tempstat
;
1264 } while (nematch(pfa
,s
));
1265 pfa
->initstat
= tempstat
; /* bwk: has to be here to reset */
1266 /* cf gsub and refldbld */
1269 sprintf(num
, "%d", n
);
1271 setsymtab(num
, s
, atof(s
), STR
|NUM
, (Array
*) ap
->sval
);
1273 setsymtab(num
, s
, 0.0, STR
, (Array
*) ap
->sval
);
1276 } else if (sep
== ' ') {
1278 while (*s
== ' ' || *s
== '\t' || *s
== '\n')
1286 while (*s
!=' ' && *s
!='\t' && *s
!='\n' && *s
!='\0');
1289 sprintf(num
, "%d", n
);
1291 setsymtab(num
, t
, atof(t
), STR
|NUM
, (Array
*) ap
->sval
);
1293 setsymtab(num
, t
, 0.0, STR
, (Array
*) ap
->sval
);
1298 } else if (sep
== 0) { /* new: split(s, a, "") => 1 char/elem */
1299 for (n
= 0; *s
!= 0; s
++) {
1302 sprintf(num
, "%d", n
);
1305 if (isdigit((uschar
)buf
[0]))
1306 setsymtab(num
, buf
, atof(buf
), STR
|NUM
, (Array
*) ap
->sval
);
1308 setsymtab(num
, buf
, 0.0, STR
, (Array
*) ap
->sval
);
1310 } else if (*s
!= 0) {
1314 while (*s
!= sep
&& *s
!= '\n' && *s
!= '\0')
1318 sprintf(num
, "%d", n
);
1320 setsymtab(num
, t
, atof(t
), STR
|NUM
, (Array
*) ap
->sval
);
1322 setsymtab(num
, t
, 0.0, STR
, (Array
*) ap
->sval
);
1330 if (a
[2] != 0 && arg3type
== STRING
) {
1339 Cell
*condexpr(Node
**a
, int n
) /* a[0] ? a[1] : a[2] */
1354 Cell
*ifstat(Node
**a
, int n
) /* if (a[0]) a[1]; else a[2] */
1362 } else if (a
[2] != 0) {
1369 Cell
*whilestat(Node
**a
, int n
) /* while (a[0]) a[1] */
1383 if (isnext(x
) || isexit(x
) || isret(x
))
1389 Cell
*dostat(Node
**a
, int n
) /* do a[0]; while(a[1]) */
1397 if (isnext(x
) || isexit(x
) || isret(x
))
1407 Cell
*forstat(Node
**a
, int n
) /* for (a[0]; a[1]; a[2]) a[3] */
1416 if (!istrue(x
)) return(x
);
1420 if (isbreak(x
)) /* turn off break */
1422 if (isnext(x
) || isexit(x
) || isret(x
))
1430 Cell
*instat(Node
**a
, int n
) /* for (a[0] in a[1]) a[2] */
1432 Cell
*x
, *vp
, *arrayp
, *cp
, *ncp
;
1437 arrayp
= execute(a
[1]);
1438 if (!isarr(arrayp
)) {
1441 tp
= (Array
*) arrayp
->sval
;
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
);
1452 if (isnext(x
) || isexit(x
) || isret(x
)) {
1462 Cell
*bltin(Node
**a
, int n
) /* builtin functions. a[0] is type, a[1] is arg list */
1470 void flush_all(void);
1474 nextarg
= a
[1]->nnext
;
1478 u
= ((Array
*) x
->sval
)->nelem
; /* GROT. should be function*/
1480 u
= strlen(getsval(x
));
1483 u
= errcheck(log(getfval(x
)), "log"); break;
1485 modf(getfval(x
), &u
); break;
1487 u
= errcheck(exp(getfval(x
)), "exp"); break;
1489 u
= errcheck(sqrt(getfval(x
)), "sqrt"); break;
1491 u
= sin(getfval(x
)); break;
1493 u
= cos(getfval(x
)); break;
1496 WARNING("atan2 requires two arguments; returning 1.0");
1499 y
= execute(a
[1]->nnext
);
1500 u
= atan2(getfval(x
), getfval(y
));
1502 nextarg
= nextarg
->nnext
;
1506 fflush(stdout
); /* in case something is buffered already */
1507 u
= (Awkfloat
) system(getsval(x
)) / 256; /* 256 is unix-dep */
1510 /* in principle, rand() returns something in 0..RAND_MAX */
1511 u
= (Awkfloat
) (rand() % RAND_MAX
) / RAND_MAX
;
1514 if (isrec(x
)) /* no argument provided */
1515 u
= time((time_t *)0);
1518 srand((unsigned int) u
);
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
);
1528 for (p
= buf
; *p
; p
++)
1529 if (isupper((uschar
) *p
))
1530 *p
= tolower((uschar
)*p
);
1538 if (isrec(x
) || strlen(getsval(x
)) == 0) {
1539 flush_all(); /* fflush() or fflush("") -> all */
1541 } else if ((fp
= openfile(FFLUSH
, getsval(x
))) == NULL
)
1546 default: /* can't happen */
1547 FATAL("illegal function type %d", t
);
1554 WARNING("warning: function has too many arguments");
1555 for ( ; nextarg
; nextarg
= nextarg
->nnext
)
1561 Cell
*printstat(Node
**a
, int n
) /* print a[0] */
1567 if (a
[1] == 0) /* a[1] is redirection operator, a[2] is file */
1570 fp
= redirect(ptoi(a
[1]), a
[2]);
1571 for (x
= a
[0]; x
!= NULL
; x
= x
->nnext
) {
1573 fputs(getpssval(y
), fp
);
1575 if (x
->nnext
== NULL
)
1583 FATAL("write error on %s", filename(fp
));
1587 Cell
*nullproc(Node
**a
, int n
)
1595 FILE *redirect(int a
, Node
*b
) /* set up all i/o redirections */
1603 fp
= openfile(a
, fname
);
1605 FATAL("can't open file %s", 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
)
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
))
1642 if (a
== FFLUSH
) /* didn't find it, so don't create it! */
1645 for (i
=0; i
< FOPEN_MAX
; i
++)
1646 if (files
[i
].fp
== 0)
1649 FATAL("%s makes too many open files", s
);
1650 fflush(stdout
); /* force a semblance of order */
1654 } else if (a
== APPEND
) {
1656 m
= GT
; /* so can mix > and >> */
1657 } else if (a
== '|') { /* output pipe */
1659 } else if (a
== LE
) { /* input pipe */
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
);
1666 files
[i
].fname
= tostring(s
);
1673 const char *filename(FILE *fp
)
1677 for (i
= 0; i
< FOPEN_MAX
; i
++)
1678 if (fp
== files
[i
].fp
)
1679 return files
[i
].fname
;
1683 Cell
*closefile(Node
**a
, int n
)
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
);
1699 stat
= fclose(files
[i
].fp
);
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 */
1710 setfval(x
, (Awkfloat
) stat
);
1718 for (i
= 0; i
< FOPEN_MAX
; i
++) {
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
);
1725 stat
= fclose(files
[i
].fp
);
1727 WARNING( "i/o error occurred while closing %s", files
[i
].fname
);
1732 void flush_all(void)
1736 for (i
= 0; i
< FOPEN_MAX
; i
++)
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
;
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 */
1755 if (a
[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1756 pfa
= (fa
*) a
[1]; /* regular expression */
1759 pfa
= makedfa(getsval(y
), 1);
1762 y
= execute(a
[2]); /* replacement string */
1764 if (pmatch(pfa
, t
)) {
1766 adjbuf(&buf
, &bufsz
, 1+patbeg
-sptr
, recsize
, 0, "sub");
1768 while (sptr
< patbeg
)
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
== '&') {
1777 adjbuf(&buf
, &bufsz
, 1+patlen
+pb
-buf
, recsize
, &pb
, "sub");
1778 for (q
= patbeg
; q
< patbeg
+patlen
; )
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 */
1803 Cell
*gsub(Node
**a
, int nnn
) /* global substitute */
1806 char *rptr
, *sptr
, *t
, *pb
, *q
;
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 */
1816 x
= execute(a
[3]); /* target string */
1818 if (a
[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1819 pfa
= (fa
*) a
[1]; /* regular expression */
1822 pfa
= makedfa(getsval(y
), 1);
1825 y
= execute(a
[2]); /* replacement string */
1826 if (pmatch(pfa
, t
)) {
1827 tempstat
= pfa
->initstat
;
1832 if (patlen
== 0 && *patbeg
!= 0) { /* matched empty string */
1833 if (mflag
== 0) { /* can replace empty */
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
== '&') {
1842 adjbuf(&buf
, &bufsz
, 1+patlen
+pb
-buf
, recsize
, &pb
, "gsub");
1843 for (q
= patbeg
; q
< patbeg
+patlen
; )
1849 if (*t
== 0) /* at end */
1851 adjbuf(&buf
, &bufsz
, 2+pb
-buf
, recsize
, &pb
, "gsub");
1853 if (pb
> buf
+ bufsz
) /* BUG: not sure of this test */
1854 FATAL("gsub result0 %.30s too big; can't happen", buf
);
1857 else { /* matched nonempty string */
1860 adjbuf(&buf
, &bufsz
, 1+(patbeg
-sptr
)+pb
-buf
, recsize
, &pb
, "gsub");
1861 while (sptr
< patbeg
)
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
== '&') {
1870 adjbuf(&buf
, &bufsz
, 1+patlen
+pb
-buf
, recsize
, &pb
, "gsub");
1871 for (q
= patbeg
; q
< patbeg
+patlen
; )
1876 t
= patbeg
+ patlen
;
1877 if (patlen
== 0 || *t
== 0 || *(t
-1) == 0)
1879 if (pb
> buf
+ bufsz
)
1880 FATAL("gsub result1 %.30s too big; can't happen", buf
);
1883 } while (pmatch(pfa
,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
);
1891 setsval(x
, buf
); /* BUG: should be able to avoid copy + free */
1892 pfa
->initstat
= tempstat
;
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] == '&') { /* \\\& -> \& */
1912 } else if (sptr
[2] == '&') { /* \\& -> \ + matched */
1915 } else { /* \\x -> \\x */
1919 } else if (sptr
[1] == '&') { /* literal & */
1922 } else /* literal \ */