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
[];
70 Node
*winner
= NULL
; /* root of parse tree */
71 Cell
*tmps
; /* free temporary cells for execution */
73 static Cell truecell
={ OBOOL
, BTRUE
, 0, 0, 1.0, NUM
};
74 Cell
*True
= &truecell
;
75 static Cell falsecell
={ OBOOL
, BFALSE
, 0, 0, 0.0, NUM
};
76 Cell
*False
= &falsecell
;
77 static Cell breakcell
={ OJUMP
, JBREAK
, 0, 0, 0.0, NUM
};
78 Cell
*jbreak
= &breakcell
;
79 static Cell contcell
={ OJUMP
, JCONT
, 0, 0, 0.0, NUM
};
80 Cell
*jcont
= &contcell
;
81 static Cell nextcell
={ OJUMP
, JNEXT
, 0, 0, 0.0, NUM
};
82 Cell
*jnext
= &nextcell
;
83 static Cell nextfilecell
={ OJUMP
, JNEXTFILE
, 0, 0, 0.0, NUM
};
84 Cell
*jnextfile
= &nextfilecell
;
85 static Cell exitcell
={ OJUMP
, JEXIT
, 0, 0, 0.0, NUM
};
86 Cell
*jexit
= &exitcell
;
87 static Cell retcell
={ OJUMP
, JRET
, 0, 0, 0.0, NUM
};
88 Cell
*jret
= &retcell
;
89 static Cell tempcell
={ OCELL
, CTEMP
, 0, "", 0.0, NUM
|STR
|DONTFREE
};
91 Node
*curnode
= NULL
; /* the node being executed, for debugging */
93 /* buffer memory management */
94 int adjbuf(char **pbuf
, int *psiz
, int minlen
, int quantum
, char **pbptr
,
96 /* pbuf: address of pointer to buffer being managed
97 * psiz: address of buffer size variable
98 * minlen: minimum length of buffer needed
99 * quantum: buffer size quantum
100 * pbptr: address of movable pointer into buffer, or 0 if none
101 * whatrtn: name of the calling routine if failure should cause fatal error
103 * return 0 for realloc failure, !=0 for success
106 if (minlen
> *psiz
) {
108 int rminlen
= quantum
? minlen
% quantum
: 0;
109 int boff
= pbptr
? *pbptr
- *pbuf
: 0;
110 /* round up to next multiple of quantum */
112 minlen
+= quantum
- rminlen
;
113 tbuf
= (char *) realloc(*pbuf
, minlen
);
114 dprintf( ("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn
, *psiz
, minlen
, *pbuf
, tbuf
) );
117 FATAL("out of memory in %s", whatrtn
);
123 *pbptr
= tbuf
+ boff
;
128 void run(Node
*a
) /* execution of parse tree starts here */
130 extern void stdinit(void);
137 Cell
*execute(Node
*u
) /* execute a node of the parse tree */
139 Cell
*(*proc
)(Node
**, int);
145 for (a
= u
; ; a
= a
->nnext
) {
148 x
= (Cell
*) (a
->narg
[0]);
149 if (isfld(x
) && !donefld
)
151 else if (isrec(x
) && !donerec
)
155 if (notlegal(a
->nobj
)) /* probably a Cell* but too risky to print */
156 FATAL("illegal statement");
157 proc
= proctab
[a
->nobj
-FIRSTTOKEN
];
158 x
= (*proc
)(a
->narg
, a
->nobj
);
159 if (isfld(x
) && !donefld
)
161 else if (isrec(x
) && !donerec
)
167 if (a
->nnext
== NULL
)
174 Cell
*program(Node
**a
, int n
) /* execute an awk program */
175 { /* a[0] = BEGIN, a[1] = body, a[2] = END */
178 if (setjmp(env
) != 0)
180 if (a
[0]) { /* BEGIN */
185 FATAL("illegal break, continue, next or nextfile from BEGIN");
189 while (getrec(&record
, &recsize
, 1) > 0) {
196 if (setjmp(env
) != 0) /* handles exit within END */
198 if (a
[2]) { /* END */
200 if (isbreak(x
) || isnext(x
) || iscont(x
))
201 FATAL("illegal break, continue, next or nextfile from END");
208 struct Frame
{ /* stack frame for awk function calls */
209 int nargs
; /* number of arguments in this call */
210 Cell
*fcncell
; /* pointer to Cell for function */
211 Cell
**args
; /* pointer to array of arguments after execute */
212 Cell
*retval
; /* return value */
215 #define NARGS 50 /* max args in a call */
217 struct Frame
*frame
= NULL
; /* base of stack frames; dynamically allocated */
218 int nframe
= 0; /* number of frames allocated */
219 struct Frame
*fp
= NULL
; /* frame pointer. bottom level unused */
221 Cell
*call(Node
**a
, int n
) /* function call. very kludgy and fragile */
223 static Cell newcopycell
= { OCELL
, CCOPY
, 0, "", 0.0, NUM
|STR
|DONTFREE
};
225 int freed
= 0; /* handles potential double freeing when fcn & param share a tempcell */
227 Cell
*args
[NARGS
], *oargs
[NARGS
]; /* BUG: fixed size arrays */
231 fcn
= execute(a
[0]); /* the function itself */
234 FATAL("calling undefined function %s", s
);
236 fp
= frame
= (struct Frame
*) calloc(nframe
+= 100, sizeof(struct Frame
));
238 FATAL("out of space for stack frames calling %s", s
);
240 for (ncall
= 0, x
= a
[1]; x
!= NULL
; x
= x
->nnext
) /* args in call */
242 ndef
= (int) fcn
->fval
; /* args in defn */
243 dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s
, ncall
, ndef
, (int) (fp
-frame
)) );
245 WARNING("function %s called with %d args, uses only %d",
247 if (ncall
+ ndef
> NARGS
)
248 FATAL("function %s has %d arguments, limit %d", s
, ncall
+ndef
, NARGS
);
249 for (i
= 0, x
= a
[1]; x
!= NULL
; i
++, x
= x
->nnext
) { /* get call args */
250 dprintf( ("evaluate args[%d], fp=%d:\n", i
, (int) (fp
-frame
)) );
253 dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
254 i
, NN(y
->nval
), y
->fval
, isarr(y
) ? "(array)" : NN(y
->sval
), y
->tval
) );
256 FATAL("can't use function %s as argument in %s", y
->nval
, s
);
258 args
[i
] = y
; /* arrays by ref */
260 args
[i
] = copycell(y
);
263 for ( ; i
< ndef
; i
++) { /* add null args for ones not provided */
265 *args
[i
] = newcopycell
;
267 fp
++; /* now ok to up frame */
268 if (fp
>= frame
+ nframe
) {
269 int dfp
= fp
- frame
; /* old index */
270 frame
= (struct Frame
*)
271 realloc((char *) frame
, (nframe
+= 100) * sizeof(struct Frame
));
273 FATAL("out of space for stack frames in %s", s
);
278 fp
->nargs
= ndef
; /* number defined with (excess are locals) */
279 fp
->retval
= gettemp();
281 dprintf( ("start exec of %s, fp=%d\n", s
, (int) (fp
-frame
)) );
282 y
= execute((Node
*)(fcn
->sval
)); /* execute body */
283 dprintf( ("finished exec of %s, fp=%d\n", s
, (int) (fp
-frame
)) );
285 for (i
= 0; i
< ndef
; i
++) {
286 Cell
*t
= fp
->args
[i
];
288 if (t
->csub
== CCOPY
) {
294 oargs
[i
]->tval
= t
->tval
;
295 oargs
[i
]->tval
&= ~(STR
|NUM
|DONTFREE
);
296 oargs
[i
]->sval
= t
->sval
;
300 } else if (t
!= y
) { /* kludge to prevent freeing twice */
303 } else if (t
== y
&& t
->csub
== CCOPY
) {
310 if (isexit(y
) || isnext(y
))
313 tempfree(y
); /* don't free twice! */
315 z
= fp
->retval
; /* return value */
316 dprintf( ("%s returns %g |%s| %o\n", s
, getfval(z
), getsval(z
), z
->tval
) );
321 Cell
*copycell(Cell
*x
) /* make a copy of a cell in a temp */
326 y
->csub
= CCOPY
; /* prevents freeing until call is over */
327 y
->nval
= x
->nval
; /* BUG? */
329 y
->sval
= tostring(x
->sval
);
331 y
->tval
= x
->tval
& ~(CON
|FLD
|REC
|DONTFREE
); /* copy is not constant or field */
332 /* is DONTFREE right? */
336 Cell
*arg(Node
**a
, int n
) /* nth argument of a function */
339 n
= ptoi(a
[0]); /* argument number, counting from 0 */
340 dprintf( ("arg(%d), fp->nargs=%d\n", n
, fp
->nargs
) );
342 FATAL("argument #%d of function %s was not supplied",
343 n
+1, fp
->fcncell
->nval
);
347 Cell
*jump(Node
**a
, int n
) /* break, continue, next, nextfile, return */
355 errorflag
= (int) getfval(y
);
362 if ((y
->tval
& (STR
|NUM
)) == (STR
|NUM
)) {
363 setsval(fp
->retval
, getsval(y
));
364 fp
->retval
->fval
= getfval(y
);
365 fp
->retval
->tval
|= NUM
;
367 else if (y
->tval
& STR
)
368 setsval(fp
->retval
, getsval(y
));
369 else if (y
->tval
& NUM
)
370 setfval(fp
->retval
, getfval(y
));
371 else /* can't happen */
372 FATAL("bad type variable %d", y
->tval
);
385 default: /* can't happen */
386 FATAL("illegal jump type %d", n
);
388 return 0; /* not reached */
391 Cell
*awkgetline(Node
**a
, int n
) /* get next line from specific input */
392 { /* a[0] is variable, a[1] is operator, a[2] is filename */
394 extern Cell
**fldtab
;
397 int bufsize
= recsize
;
400 if ((buf
= (char *) malloc(bufsize
)) == NULL
)
401 FATAL("out of memory in getline");
403 fflush(stdout
); /* in case someone is waiting for a prompt */
405 if (a
[1] != NULL
) { /* getline < file */
406 x
= execute(a
[2]); /* filename */
408 if (mode
== '|') /* input pipe */
409 mode
= LE
; /* arbitrary flag */
410 fp
= openfile(mode
, getsval(x
));
415 n
= readrec(&buf
, &bufsize
, fp
);
418 } else if (a
[0] != NULL
) { /* getline var <file */
422 } else { /* getline <file */
423 setsval(fldtab
[0], buf
);
424 if (is_number(fldtab
[0]->sval
)) {
425 fldtab
[0]->fval
= atof(fldtab
[0]->sval
);
426 fldtab
[0]->tval
|= NUM
;
429 } else { /* bare getline; use current input */
430 if (a
[0] == NULL
) /* getline */
431 n
= getrec(&record
, &recsize
, 1);
432 else { /* getline var */
433 n
= getrec(&buf
, &bufsize
, 0);
439 setfval(r
, (Awkfloat
) n
);
444 Cell
*getnf(Node
**a
, int n
) /* get NF */
448 return (Cell
*) a
[0];
451 Cell
*array(Node
**a
, int n
) /* a[0] is symtab, a[1] is list of subscripts */
458 int nsub
= strlen(*SUBSEP
);
460 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
461 FATAL("out of memory in array");
463 x
= execute(a
[0]); /* Cell* for symbol table */
465 for (np
= a
[1]; np
; np
= np
->nnext
) {
466 y
= execute(np
); /* subscript */
468 if (!adjbuf(&buf
, &bufsz
, strlen(buf
)+strlen(s
)+nsub
+1, recsize
, 0, "array"))
469 FATAL("out of memory for %s[%s...]", x
->nval
, buf
);
472 strcat(buf
, *SUBSEP
);
476 dprintf( ("making %s into an array\n", NN(x
->nval
)) );
479 x
->tval
&= ~(STR
|NUM
|DONTFREE
);
481 x
->sval
= (char *) makesymtab(NSYMTAB
);
483 z
= setsymtab(buf
, "", 0.0, STR
|NUM
, (Array
*) x
->sval
);
491 Cell
*awkdelete(Node
**a
, int n
) /* a[0] is symtab, a[1] is list of subscripts */
496 int nsub
= strlen(*SUBSEP
);
498 x
= execute(a
[0]); /* Cell* for symbol table */
501 if (a
[1] == 0) { /* delete the elements, not the table */
505 x
->sval
= (char *) makesymtab(NSYMTAB
);
509 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
510 FATAL("out of memory in adelete");
512 for (np
= a
[1]; np
; np
= np
->nnext
) {
513 y
= execute(np
); /* subscript */
515 if (!adjbuf(&buf
, &bufsz
, strlen(buf
)+strlen(s
)+nsub
+1, recsize
, 0, "awkdelete"))
516 FATAL("out of memory deleting %s[%s...]", x
->nval
, buf
);
519 strcat(buf
, *SUBSEP
);
529 Cell
*intest(Node
**a
, int n
) /* a[0] is index (list), a[1] is symtab */
536 int nsub
= strlen(*SUBSEP
);
538 ap
= execute(a
[1]); /* array name */
540 dprintf( ("making %s into an array\n", ap
->nval
) );
543 ap
->tval
&= ~(STR
|NUM
|DONTFREE
);
545 ap
->sval
= (char *) makesymtab(NSYMTAB
);
547 if ((buf
= (char *) malloc(bufsz
)) == NULL
) {
548 FATAL("out of memory in intest");
551 for (p
= a
[0]; p
; p
= p
->nnext
) {
552 x
= execute(p
); /* expr */
554 if (!adjbuf(&buf
, &bufsz
, strlen(buf
)+strlen(s
)+nsub
+1, recsize
, 0, "intest"))
555 FATAL("out of memory deleting %s[%s...]", x
->nval
, buf
);
559 strcat(buf
, *SUBSEP
);
561 k
= lookup(buf
, (Array
*) ap
->sval
);
571 Cell
*matchop(Node
**a
, int n
) /* ~ and match() */
577 int (*mf
)(fa
*, const char *) = match
, mode
= 0;
583 x
= execute(a
[1]); /* a[1] = target text */
585 if (a
[0] == 0) /* a[1] == 0: already-compiled reg expr */
586 i
= (*mf
)((fa
*) a
[2], s
);
588 y
= execute(a
[2]); /* a[2] = regular expr */
590 pfa
= makedfa(t
, mode
);
596 int start
= patbeg
- s
+ 1;
599 setfval(rstartloc
, (Awkfloat
) start
);
600 setfval(rlengthloc
, (Awkfloat
) patlen
);
605 } else if ((n
== MATCH
&& i
== 1) || (n
== NOTMATCH
&& i
== 0))
612 Cell
*boolop(Node
**a
, int n
) /* a[0] || a[1], a[0] && a[1], !a[0] */
629 if ( !i
) return(False
);
636 if (i
) return(False
);
638 default: /* can't happen */
639 FATAL("unknown boolean operator %d", n
);
641 return 0; /*NOTREACHED*/
644 Cell
*relop(Node
**a
, int n
) /* a[0 < a[1], etc. */
652 if (x
->tval
&NUM
&& y
->tval
&NUM
) {
653 j
= x
->fval
- y
->fval
;
654 i
= j
<0? -1: (j
>0? 1: 0);
656 i
= strcmp(getsval(x
), getsval(y
));
661 case LT
: if (i
<0) return(True
);
663 case LE
: if (i
<=0) return(True
);
665 case NE
: if (i
!=0) return(True
);
667 case EQ
: if (i
== 0) return(True
);
669 case GE
: if (i
>=0) return(True
);
671 case GT
: if (i
>0) return(True
);
673 default: /* can't happen */
674 FATAL("unknown relational operator %d", n
);
676 return 0; /*NOTREACHED*/
679 void tfree(Cell
*a
) /* free a tempcell */
682 dprintf( ("freeing %s %s %o\n", NN(a
->nval
), NN(a
->sval
), a
->tval
) );
686 FATAL("tempcell list is curdled");
691 Cell
*gettemp(void) /* get a tempcell */
696 tmps
= (Cell
*) calloc(100, sizeof(Cell
));
698 FATAL("out of space for temporaries");
699 for(i
= 1; i
< 100; i
++)
700 tmps
[i
-1].cnext
= &tmps
[i
];
709 Cell
*indirect(Node
**a
, int n
) /* $( a[0] ) */
717 val
= getfval(x
); /* freebsd: defend against super large field numbers */
718 if ((Awkfloat
)INT_MAX
< val
)
719 FATAL("trying to access out of range field %s", x
->nval
);
721 if (m
== 0 && !is_number(s
= getsval(x
))) /* suspicion! */
722 FATAL("illegal field $(%s), name \"%s\"", s
, x
->nval
);
723 /* BUG: can x->nval ever be null??? */
726 x
->ctype
= OCELL
; /* BUG? why are these needed? */
731 Cell
*substr(Node
**a
, int nnn
) /* substr(a[0], a[1], a[2]) */
754 m
= (int) getfval(y
);
761 n
= (int) getfval(z
);
769 dprintf( ("substr: m=%d, n=%d, s=%s\n", m
, n
, s
) );
771 temp
= s
[n
+m
-1]; /* with thanks to John Linderman */
773 setsval(y
, s
+ m
- 1);
779 Cell
*sindex(Node
**a
, int nnn
) /* index(a[0], a[1]) */
782 char *s1
, *s2
, *p1
, *p2
, *q
;
791 for (p1
= s1
; *p1
!= '\0'; p1
++) {
792 for (q
=p1
, p2
=s2
; *p2
!= '\0' && *q
== *p2
; q
++, p2
++)
795 v
= (Awkfloat
) (p1
- s1
+ 1); /* origin 1 */
805 #define MAXNUMSIZE 50
807 int format(char **pbuf
, int *pbufsize
, const char *s
, Node
*a
) /* printf-like conversions */
814 int fmtwd
; /* format width */
817 int bufsize
= *pbufsize
;
821 if ((fmt
= (char *) malloc(fmtsz
)) == NULL
)
822 FATAL("out of memory in format()");
824 adjbuf(&buf
, &bufsize
, MAXNUMSIZE
+1+p
-buf
, recsize
, &p
, "format1");
834 /* have to be real careful in case this is a huge number, eg, %100000d */
838 adjbuf(&buf
, &bufsize
, fmtwd
+1+p
-buf
, recsize
, &p
, "format2");
839 for (t
= fmt
; (*t
++ = *s
) != '\0'; s
++) {
840 if (!adjbuf(&fmt
, &fmtsz
, MAXNUMSIZE
+1+t
-fmt
, recsize
, &t
, "format3"))
841 FATAL("format item %.30s... ran format() out of memory", os
);
842 if (isalpha((uschar
)*s
) && *s
!= 'l' && *s
!= 'h' && *s
!= 'L')
843 break; /* the ansi panoply */
847 sprintf(t
-1, "%d", fmtwd
=(int) getfval(x
));
850 adjbuf(&buf
, &bufsize
, fmtwd
+1+p
-buf
, recsize
, &p
, "format");
851 t
= fmt
+ strlen(fmt
);
858 adjbuf(&buf
, &bufsize
, fmtwd
+1+p
-buf
, recsize
, &p
, "format4");
861 case 'f': case 'e': case 'g': case 'E': case 'G':
866 if(*(s
-1) == 'l') break;
871 case 'o': case 'x': case 'X': case 'u':
872 flag
= *(s
-1) == 'l' ? 'd' : 'u';
881 WARNING("weird printf conversion %s", fmt
);
886 FATAL("not enough args in printf(%s)", os
);
892 adjbuf(&buf
, &bufsize
, 1+n
+p
-buf
, recsize
, &p
, "format5");
894 case '?': sprintf(p
, "%s", fmt
); /* unknown, so dump it too */
899 adjbuf(&buf
, &bufsize
, 1+strlen(p
)+n
+p
-buf
, recsize
, &p
, "format6");
903 case 'f': sprintf(p
, fmt
, getfval(x
)); break;
904 case 'd': sprintf(p
, fmt
, (long) getfval(x
)); break;
905 case 'u': sprintf(p
, fmt
, (int) getfval(x
)); break;
911 if (!adjbuf(&buf
, &bufsize
, 1+n
+p
-buf
, recsize
, &p
, "format7"))
912 FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n
, t
);
918 sprintf(p
, fmt
, (int) getfval(x
));
920 *p
++ = '\0'; /* explicit null byte */
921 *p
= '\0'; /* next output will start here */
924 sprintf(p
, fmt
, getsval(x
)[0]);
927 FATAL("can't happen: bad conversion %c in format()", flag
);
935 for ( ; a
; a
= a
->nnext
) /* evaluate any remaining args */
942 Cell
*awksprintf(Node
**a
, int n
) /* sprintf(a[0]) */
949 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
950 FATAL("out of memory in awksprintf");
953 if (format(&buf
, &bufsz
, getsval(x
), y
) == -1)
954 FATAL("sprintf string %.30s... too long. can't happen.", buf
);
962 Cell
*awkprintf(Node
**a
, int n
) /* printf */
963 { /* a[0] is list of args, starting with format string */
964 /* a[1] is redirection operator, a[2] is redirection file */
972 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
973 FATAL("out of memory in awkprintf");
976 if ((len
= format(&buf
, &bufsz
, getsval(x
), y
)) == -1)
977 FATAL("printf string %.30s... too long. can't happen.", buf
);
980 /* fputs(buf, stdout); */
981 fwrite(buf
, len
, 1, stdout
);
983 FATAL("write error on stdout");
985 fp
= redirect(ptoi(a
[1]), a
[2]);
986 /* fputs(buf, fp); */
987 fwrite(buf
, len
, 1, fp
);
990 FATAL("write error on %s", filename(fp
));
996 Cell
*arith(Node
**a
, int n
) /* a[0] + a[1], etc. also -a[0] */
1023 FATAL("division by zero");
1028 FATAL("division by zero in mod");
1036 if (j
>= 0 && modf(j
, &v
) == 0.0) /* pos integer exponent */
1037 i
= ipow(i
, (int) j
);
1039 i
= errcheck(pow(i
, j
), "pow");
1041 default: /* can't happen */
1042 FATAL("illegal arithmetic operator %d", n
);
1048 double ipow(double x
, int n
) /* x**n. ought to be done by pow, but isn't always */
1061 Cell
*incrdecr(Node
**a
, int n
) /* a[0]++, etc. */
1069 k
= (n
== PREINCR
|| n
== POSTINCR
) ? 1 : -1;
1070 if (n
== PREINCR
|| n
== PREDECR
) {
1081 Cell
*assign(Node
**a
, int n
) /* a[0] = a[1], a[0] += a[1], etc. */
1082 { /* this is subtle; don't muck with it. */
1089 if (n
== ASSIGN
) { /* ordinary assignment */
1090 if (x
== y
&& !(x
->tval
& (FLD
|REC
))) /* self-assignment: */
1091 ; /* leave alone unless it's a field */
1092 else if ((y
->tval
& (STR
|NUM
)) == (STR
|NUM
)) {
1093 setsval(x
, getsval(y
));
1094 x
->fval
= getfval(y
);
1098 setsval(x
, getsval(y
));
1100 setfval(x
, getfval(y
));
1102 funnyvar(y
, "read value of");
1120 FATAL("division by zero in /=");
1125 FATAL("division by zero in %%=");
1130 if (yf
>= 0 && modf(yf
, &v
) == 0.0) /* pos integer exponent */
1131 xf
= ipow(xf
, (int) yf
);
1133 xf
= errcheck(pow(xf
, yf
), "pow");
1136 FATAL("illegal assignment operator %d", n
);
1144 Cell
*cat(Node
**a
, int q
) /* a[0] cat a[1] */
1154 n1
= strlen(x
->sval
);
1155 n2
= strlen(y
->sval
);
1156 s
= (char *) malloc(n1
+ n2
+ 1);
1158 FATAL("out of space concatenating %.15s... and %.15s...",
1161 strcpy(s
+n1
, y
->sval
);
1170 Cell
*pastat(Node
**a
, int n
) /* a[0] { a[1] } */
1186 Cell
*dopa2(Node
**a
, int n
) /* a[0], a[1] { a[2] } */
1192 if (pairstack
[pair
] == 0) {
1195 pairstack
[pair
] = 1;
1198 if (pairstack
[pair
] == 1) {
1201 pairstack
[pair
] = 0;
1209 Cell
*split(Node
**a
, int nnn
) /* split(a[0], a[1], a[2]); a[3] is type */
1211 Cell
*x
= 0, *y
, *ap
;
1214 char *t
, temp
, num
[50], *fs
= 0;
1215 int n
, tempstat
, arg3type
;
1217 y
= execute(a
[0]); /* source string */
1219 arg3type
= ptoi(a
[3]);
1220 if (a
[2] == 0) /* fs string */
1222 else if (arg3type
== STRING
) { /* split(str,arr,"string") */
1225 } else if (arg3type
== REGEXPR
)
1226 fs
= "(regexpr)"; /* split(str,arr,/regexpr/) */
1228 FATAL("illegal type of split");
1230 ap
= execute(a
[1]); /* array name */
1232 dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s
, NN(ap
->nval
), fs
) );
1235 ap
->sval
= (char *) makesymtab(NSYMTAB
);
1238 if (*s
!= '\0' && (strlen(fs
) > 1 || arg3type
== REGEXPR
)) { /* reg expr */
1240 if (arg3type
== REGEXPR
) { /* it's ready already */
1243 pfa
= makedfa(fs
, 1);
1245 if (nematch(pfa
,s
)) {
1246 tempstat
= pfa
->initstat
;
1250 sprintf(num
, "%d", n
);
1254 setsymtab(num
, s
, atof(s
), STR
|NUM
, (Array
*) ap
->sval
);
1256 setsymtab(num
, s
, 0.0, STR
, (Array
*) ap
->sval
);
1258 s
= patbeg
+ patlen
;
1259 if (*(patbeg
+patlen
-1) == 0 || *s
== 0) {
1261 sprintf(num
, "%d", n
);
1262 setsymtab(num
, "", 0.0, STR
, (Array
*) ap
->sval
);
1263 pfa
->initstat
= tempstat
;
1266 } while (nematch(pfa
,s
));
1267 pfa
->initstat
= tempstat
; /* bwk: has to be here to reset */
1268 /* cf gsub and refldbld */
1271 sprintf(num
, "%d", n
);
1273 setsymtab(num
, s
, atof(s
), STR
|NUM
, (Array
*) ap
->sval
);
1275 setsymtab(num
, s
, 0.0, STR
, (Array
*) ap
->sval
);
1278 } else if (sep
== ' ') {
1280 while (*s
== ' ' || *s
== '\t' || *s
== '\n')
1288 while (*s
!=' ' && *s
!='\t' && *s
!='\n' && *s
!='\0');
1291 sprintf(num
, "%d", n
);
1293 setsymtab(num
, t
, atof(t
), STR
|NUM
, (Array
*) ap
->sval
);
1295 setsymtab(num
, t
, 0.0, STR
, (Array
*) ap
->sval
);
1300 } else if (sep
== 0) { /* new: split(s, a, "") => 1 char/elem */
1301 for (n
= 0; *s
!= 0; s
++) {
1304 sprintf(num
, "%d", n
);
1307 if (isdigit((uschar
)buf
[0]))
1308 setsymtab(num
, buf
, atof(buf
), STR
|NUM
, (Array
*) ap
->sval
);
1310 setsymtab(num
, buf
, 0.0, STR
, (Array
*) ap
->sval
);
1312 } else if (*s
!= 0) {
1316 while (*s
!= sep
&& *s
!= '\n' && *s
!= '\0')
1320 sprintf(num
, "%d", n
);
1322 setsymtab(num
, t
, atof(t
), STR
|NUM
, (Array
*) ap
->sval
);
1324 setsymtab(num
, t
, 0.0, STR
, (Array
*) ap
->sval
);
1332 if (a
[2] != 0 && arg3type
== STRING
) {
1341 Cell
*condexpr(Node
**a
, int n
) /* a[0] ? a[1] : a[2] */
1356 Cell
*ifstat(Node
**a
, int n
) /* if (a[0]) a[1]; else a[2] */
1364 } else if (a
[2] != 0) {
1371 Cell
*whilestat(Node
**a
, int n
) /* while (a[0]) a[1] */
1385 if (isnext(x
) || isexit(x
) || isret(x
))
1391 Cell
*dostat(Node
**a
, int n
) /* do a[0]; while(a[1]) */
1399 if (isnext(x
) || isexit(x
) || isret(x
))
1409 Cell
*forstat(Node
**a
, int n
) /* for (a[0]; a[1]; a[2]) a[3] */
1418 if (!istrue(x
)) return(x
);
1422 if (isbreak(x
)) /* turn off break */
1424 if (isnext(x
) || isexit(x
) || isret(x
))
1432 Cell
*instat(Node
**a
, int n
) /* for (a[0] in a[1]) a[2] */
1434 Cell
*x
, *vp
, *arrayp
, *cp
, *ncp
;
1439 arrayp
= execute(a
[1]);
1440 if (!isarr(arrayp
)) {
1443 tp
= (Array
*) arrayp
->sval
;
1445 for (i
= 0; i
< tp
->size
; i
++) { /* this routine knows too much */
1446 for (cp
= tp
->tab
[i
]; cp
!= NULL
; cp
= ncp
) {
1447 setsval(vp
, cp
->nval
);
1454 if (isnext(x
) || isexit(x
) || isret(x
)) {
1464 Cell
*bltin(Node
**a
, int n
) /* builtin functions. a[0] is type, a[1] is arg list */
1472 void flush_all(void);
1476 nextarg
= a
[1]->nnext
;
1480 u
= ((Array
*) x
->sval
)->nelem
; /* GROT. should be function*/
1482 u
= strlen(getsval(x
));
1485 u
= errcheck(log(getfval(x
)), "log"); break;
1487 modf(getfval(x
), &u
); break;
1489 u
= errcheck(exp(getfval(x
)), "exp"); break;
1491 u
= errcheck(sqrt(getfval(x
)), "sqrt"); break;
1493 u
= sin(getfval(x
)); break;
1495 u
= cos(getfval(x
)); break;
1498 WARNING("atan2 requires two arguments; returning 1.0");
1501 y
= execute(a
[1]->nnext
);
1502 u
= atan2(getfval(x
), getfval(y
));
1504 nextarg
= nextarg
->nnext
;
1508 fflush(stdout
); /* in case something is buffered already */
1509 u
= (Awkfloat
) system(getsval(x
)) / 256; /* 256 is unix-dep */
1512 /* in principle, rand() returns something in 0..RAND_MAX */
1513 u
= (Awkfloat
) (rand() % RAND_MAX
) / RAND_MAX
;
1516 if (isrec(x
)) /* no argument provided */
1517 u
= time((time_t *)0);
1520 srand((unsigned int) u
);
1524 buf
= tostring(getsval(x
));
1525 if (t
== FTOUPPER
) {
1526 for (p
= buf
; *p
; p
++)
1527 if (islower((uschar
) *p
))
1528 *p
= toupper((uschar
)*p
);
1530 for (p
= buf
; *p
; p
++)
1531 if (isupper((uschar
) *p
))
1532 *p
= tolower((uschar
)*p
);
1540 if (isrec(x
) || strlen(getsval(x
)) == 0) {
1541 flush_all(); /* fflush() or fflush("") -> all */
1543 } else if ((fp
= openfile(FFLUSH
, getsval(x
))) == NULL
)
1548 default: /* can't happen */
1549 FATAL("illegal function type %d", t
);
1556 WARNING("warning: function has too many arguments");
1557 for ( ; nextarg
; nextarg
= nextarg
->nnext
)
1563 Cell
*printstat(Node
**a
, int n
) /* print a[0] */
1569 if (a
[1] == 0) /* a[1] is redirection operator, a[2] is file */
1572 fp
= redirect(ptoi(a
[1]), a
[2]);
1573 for (x
= a
[0]; x
!= NULL
; x
= x
->nnext
) {
1575 fputs(getpssval(y
), fp
);
1577 if (x
->nnext
== NULL
)
1585 FATAL("write error on %s", filename(fp
));
1589 Cell
*nullproc(Node
**a
, int n
)
1597 FILE *redirect(int a
, Node
*b
) /* set up all i/o redirections */
1605 fp
= openfile(a
, fname
);
1607 FATAL("can't open file %s", fname
);
1615 int mode
; /* '|', 'a', 'w' => LE/LT, GT */
1616 } files
[FOPEN_MAX
] ={
1617 { NULL
, "/dev/stdin", LT
}, /* watch out: don't free this! */
1618 { NULL
, "/dev/stdout", GT
},
1619 { NULL
, "/dev/stderr", GT
}
1622 void stdinit(void) /* in case stdin, etc., are not constants */
1624 files
[0].fp
= stdin
;
1625 files
[1].fp
= stdout
;
1626 files
[2].fp
= stderr
;
1629 FILE *openfile(int a
, const char *us
)
1636 FATAL("null file name in print or getline");
1637 for (i
=0; i
< FOPEN_MAX
; i
++)
1638 if (files
[i
].fname
&& strcmp(s
, files
[i
].fname
) == 0) {
1639 if (a
== files
[i
].mode
|| (a
==APPEND
&& files
[i
].mode
==GT
))
1644 if (a
== FFLUSH
) /* didn't find it, so don't create it! */
1647 for (i
=0; i
< FOPEN_MAX
; i
++)
1648 if (files
[i
].fp
== 0)
1651 FATAL("%s makes too many open files", s
);
1652 fflush(stdout
); /* force a semblance of order */
1656 } else if (a
== APPEND
) {
1658 m
= GT
; /* so can mix > and >> */
1659 } else if (a
== '|') { /* output pipe */
1661 } else if (a
== LE
) { /* input pipe */
1663 } else if (a
== LT
) { /* getline <file */
1664 fp
= strcmp(s
, "-") == 0 ? stdin
: fopen(s
, "r"); /* "-" is stdin */
1665 } else /* can't happen */
1666 FATAL("illegal redirection %d", a
);
1668 files
[i
].fname
= tostring(s
);
1675 const char *filename(FILE *fp
)
1679 for (i
= 0; i
< FOPEN_MAX
; i
++)
1680 if (fp
== files
[i
].fp
)
1681 return files
[i
].fname
;
1685 Cell
*closefile(Node
**a
, int n
)
1694 for (i
= 0; i
< FOPEN_MAX
; i
++) {
1695 if (files
[i
].fname
&& strcmp(x
->sval
, files
[i
].fname
) == 0) {
1696 if (ferror(files
[i
].fp
))
1697 WARNING( "i/o error occurred on %s", files
[i
].fname
);
1698 if (files
[i
].mode
== '|' || files
[i
].mode
== LE
)
1699 stat
= pclose(files
[i
].fp
);
1701 stat
= fclose(files
[i
].fp
);
1703 WARNING( "i/o error occurred closing %s", files
[i
].fname
);
1704 if (i
> 2) /* don't do /dev/std... */
1705 xfree(files
[i
].fname
);
1706 files
[i
].fname
= NULL
; /* watch out for ref thru this */
1712 setfval(x
, (Awkfloat
) stat
);
1720 for (i
= 0; i
< FOPEN_MAX
; i
++) {
1722 if (ferror(files
[i
].fp
))
1723 WARNING( "i/o error occurred on %s", files
[i
].fname
);
1724 if (files
[i
].mode
== '|' || files
[i
].mode
== LE
)
1725 stat
= pclose(files
[i
].fp
);
1727 stat
= fclose(files
[i
].fp
);
1729 WARNING( "i/o error occurred while closing %s", files
[i
].fname
);
1734 void flush_all(void)
1738 for (i
= 0; i
< FOPEN_MAX
; i
++)
1740 fflush(files
[i
].fp
);
1743 void backsub(char **pb_ptr
, char **sptr_ptr
);
1745 Cell
*sub(Node
**a
, int nnn
) /* substitute command */
1747 char *sptr
, *pb
, *q
;
1748 Cell
*x
, *y
, *result
;
1751 int bufsz
= recsize
;
1753 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
1754 FATAL("out of memory in sub");
1755 x
= execute(a
[3]); /* target string */
1757 if (a
[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1758 pfa
= (fa
*) a
[1]; /* regular expression */
1761 pfa
= makedfa(getsval(y
), 1);
1764 y
= execute(a
[2]); /* replacement string */
1766 if (pmatch(pfa
, t
)) {
1768 adjbuf(&buf
, &bufsz
, 1+patbeg
-sptr
, recsize
, 0, "sub");
1770 while (sptr
< patbeg
)
1773 while (*sptr
!= 0) {
1774 adjbuf(&buf
, &bufsz
, 5+pb
-buf
, recsize
, &pb
, "sub");
1775 if (*sptr
== '\\') {
1776 backsub(&pb
, &sptr
);
1777 } else if (*sptr
== '&') {
1779 adjbuf(&buf
, &bufsz
, 1+patlen
+pb
-buf
, recsize
, &pb
, "sub");
1780 for (q
= patbeg
; q
< patbeg
+patlen
; )
1786 if (pb
> buf
+ bufsz
)
1787 FATAL("sub result1 %.30s too big; can't happen", buf
);
1788 sptr
= patbeg
+ patlen
;
1789 if ((patlen
== 0 && *patbeg
) || (patlen
&& *(sptr
-1))) {
1790 adjbuf(&buf
, &bufsz
, 1+strlen(sptr
)+pb
-buf
, 0, &pb
, "sub");
1791 while ((*pb
++ = *sptr
++) != 0)
1794 if (pb
> buf
+ bufsz
)
1795 FATAL("sub result2 %.30s too big; can't happen", buf
);
1796 setsval(x
, buf
); /* BUG: should be able to avoid copy */
1805 Cell
*gsub(Node
**a
, int nnn
) /* global substitute */
1808 char *rptr
, *sptr
, *t
, *pb
, *q
;
1811 int mflag
, tempstat
, num
;
1812 int bufsz
= recsize
;
1814 if ((buf
= (char *) malloc(bufsz
)) == NULL
)
1815 FATAL("out of memory in gsub");
1816 mflag
= 0; /* if mflag == 0, can replace empty string */
1818 x
= execute(a
[3]); /* target string */
1820 if (a
[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1821 pfa
= (fa
*) a
[1]; /* regular expression */
1824 pfa
= makedfa(getsval(y
), 1);
1827 y
= execute(a
[2]); /* replacement string */
1828 if (pmatch(pfa
, t
)) {
1829 tempstat
= pfa
->initstat
;
1834 if (patlen
== 0 && *patbeg
!= 0) { /* matched empty string */
1835 if (mflag
== 0) { /* can replace empty */
1838 while (*sptr
!= 0) {
1839 adjbuf(&buf
, &bufsz
, 5+pb
-buf
, recsize
, &pb
, "gsub");
1840 if (*sptr
== '\\') {
1841 backsub(&pb
, &sptr
);
1842 } else if (*sptr
== '&') {
1844 adjbuf(&buf
, &bufsz
, 1+patlen
+pb
-buf
, recsize
, &pb
, "gsub");
1845 for (q
= patbeg
; q
< patbeg
+patlen
; )
1851 if (*t
== 0) /* at end */
1853 adjbuf(&buf
, &bufsz
, 2+pb
-buf
, recsize
, &pb
, "gsub");
1855 if (pb
> buf
+ bufsz
) /* BUG: not sure of this test */
1856 FATAL("gsub result0 %.30s too big; can't happen", buf
);
1859 else { /* matched nonempty string */
1862 adjbuf(&buf
, &bufsz
, 1+(patbeg
-sptr
)+pb
-buf
, recsize
, &pb
, "gsub");
1863 while (sptr
< patbeg
)
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
; )
1878 t
= patbeg
+ patlen
;
1879 if (patlen
== 0 || *t
== 0 || *(t
-1) == 0)
1881 if (pb
> buf
+ bufsz
)
1882 FATAL("gsub result1 %.30s too big; can't happen", buf
);
1885 } while (pmatch(pfa
,t
));
1887 adjbuf(&buf
, &bufsz
, 1+strlen(sptr
)+pb
-buf
, 0, &pb
, "gsub");
1888 while ((*pb
++ = *sptr
++) != 0)
1890 done
: if (pb
> buf
+ bufsz
)
1891 FATAL("gsub result2 %.30s too big; can't happen", buf
);
1893 setsval(x
, buf
); /* BUG: should be able to avoid copy + free */
1894 pfa
->initstat
= tempstat
;
1905 void backsub(char **pb_ptr
, char **sptr_ptr
) /* handle \\& variations */
1906 { /* sptr[0] == '\\' */
1907 char *pb
= *pb_ptr
, *sptr
= *sptr_ptr
;
1909 if (sptr
[1] == '\\') {
1910 if (sptr
[2] == '\\' && sptr
[3] == '&') { /* \\\& -> \& */
1914 } else if (sptr
[2] == '&') { /* \\& -> \ + matched */
1917 } else { /* \\x -> \\x */
1921 } else if (sptr
[1] == '&') { /* literal & */
1924 } else /* literal \ */