4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
29 #define tempfree(x, s) if (istemp(x)) tfree(x, s)
31 #define execute(p) r_execute(p)
43 #define FOPEN_MAX 15 /* max number of open files, from ANSI std. */
49 static Cell
*r_execute(Node
*);
50 static Cell
*gettemp(char *), *copycell(Cell
*);
51 static FILE *openfile(int, uchar
*), *redirect(int, Node
*);
58 static Cell truecell
= { OBOOL
, BTRUE
, 0, 0, 1.0, NUM
};
59 Cell
*true = &truecell
;
60 static Cell falsecell
= { OBOOL
, BFALSE
, 0, 0, 0.0, NUM
};
61 Cell
*false = &falsecell
;
62 static Cell breakcell
= { OJUMP
, JBREAK
, 0, 0, 0.0, NUM
};
63 Cell
*jbreak
= &breakcell
;
64 static Cell contcell
= { OJUMP
, JCONT
, 0, 0, 0.0, NUM
};
65 Cell
*jcont
= &contcell
;
66 static Cell nextcell
= { OJUMP
, JNEXT
, 0, 0, 0.0, NUM
};
67 Cell
*jnext
= &nextcell
;
68 static Cell exitcell
= { OJUMP
, JEXIT
, 0, 0, 0.0, NUM
};
69 Cell
*jexit
= &exitcell
;
70 static Cell retcell
= { OJUMP
, JRET
, 0, 0, 0.0, NUM
};
71 Cell
*jret
= &retcell
;
72 static Cell tempcell
= { OCELL
, CTEMP
, 0, 0, 0.0, NUM
};
74 Node
*curnode
= NULL
; /* the node being executed, for debugging */
76 static void tfree(Cell
*, char *);
77 static void closeall(void);
78 static double ipow(double, int);
90 register Cell
*(*proc
)();
96 for (a
= u
; ; a
= a
->nnext
) {
99 x
= (Cell
*) (a
->narg
[0]);
100 if ((x
->tval
& FLD
) && !donefld
)
102 else if ((x
->tval
& REC
) && !donerec
)
106 /* probably a Cell* but too risky to print */
107 if (notlegal(a
->nobj
))
108 ERROR
"illegal statement" FATAL
;
109 proc
= proctab
[a
->nobj
-FIRSTTOKEN
];
110 x
= (*proc
)(a
->narg
, a
->nobj
);
111 if ((x
->tval
& FLD
) && !donefld
)
113 else if ((x
->tval
& REC
) && !donerec
)
117 /* a statement, goto next statement */
120 if (a
->nnext
== (Node
*)NULL
)
122 tempfree(x
, "execute");
128 program(Node
**a
, int n
)
132 if (setjmp(env
) != 0)
134 if (a
[0]) { /* BEGIN */
139 ERROR
"illegal break, continue or next from BEGIN"
146 while (getrec(&record
, &record_size
) > 0) {
153 if (setjmp(env
) != 0)
155 if (a
[2]) { /* END */
157 if (iscont(x
)) /* read some more */
159 if (isbreak(x
) || isnext(x
))
160 ERROR
"illegal break or next from END" FATAL
;
168 int nargs
; /* number of arguments in this call */
169 Cell
*fcncell
; /* pointer to Cell for function */
170 Cell
**args
; /* pointer to array of arguments after execute */
171 Cell
*retval
; /* return value */
176 struct Frame
*frame
= NULL
; /* base of stack frames; dynamically allocated */
177 int nframe
= 0; /* number of frames allocated */
178 struct Frame
*fp
= NULL
; /* frame pointer. bottom level unused */
182 call(Node
**a
, int n
)
184 static Cell newcopycell
=
185 { OCELL
, CCOPY
, 0, (uchar
*) "", 0.0, NUM
|STR
|DONTFREE
};
186 int i
, ncall
, ndef
, freed
= 0;
188 Cell
*args
[NARGS
], *oargs
[NARGS
], *y
, *z
, *fcn
;
191 fcn
= execute(a
[0]); /* the function itself */
194 ERROR
"calling undefined function %s", s FATAL
;
196 fp
= frame
= (struct Frame
*)calloc(nframe
+= 100,
197 sizeof (struct Frame
));
199 ERROR
"out of space for stack frames calling %s",
203 for (ncall
= 0, x
= a
[1]; x
!= NULL
; x
= x
->nnext
) /* args in call */
205 ndef
= (int)fcn
->fval
; /* args in defn */
206 dprintf(("calling %s, %d args (%d in defn), fp=%d\n",
207 s
, ncall
, ndef
, fp
-frame
));
209 ERROR
"function %s called with %d args, uses only %d",
210 s
, ncall
, ndef WARNING
;
212 if (ncall
+ ndef
> NARGS
) {
213 ERROR
"function %s has %d arguments, limit %d",
214 s
, ncall
+ndef
, NARGS FATAL
;
216 for (i
= 0, x
= a
[1]; x
!= NULL
; i
++, x
= x
->nnext
) {
218 dprintf(("evaluate args[%d], fp=%d:\n", i
, fp
-frame
));
221 dprintf(("args[%d]: %s %f <%s>, t=%o\n",
223 isarr(y
) ? "(array)" : (char *)y
->sval
, y
->tval
));
225 ERROR
"can't use function %s as argument in %s",
229 args
[i
] = y
; /* arrays by ref */
231 args
[i
] = copycell(y
);
232 tempfree(y
, "callargs");
234 for (; i
< ndef
; i
++) { /* add null args for ones not provided */
235 args
[i
] = gettemp("nullargs");
236 *args
[i
] = newcopycell
;
238 fp
++; /* now ok to up frame */
239 if (fp
>= frame
+ nframe
) {
240 int dfp
= fp
- frame
; /* old index */
241 frame
= (struct Frame
*)
242 realloc(frame
, (nframe
+= 100) * sizeof (struct Frame
));
244 ERROR
"out of space for stack frames in %s", s FATAL
;
249 fp
->nargs
= ndef
; /* number defined with (excess are locals) */
250 fp
->retval
= gettemp("retval");
252 dprintf(("start exec of %s, fp=%d\n", s
, fp
-frame
));
254 y
= execute((Node
*)(fcn
->sval
)); /* execute body */
255 dprintf(("finished exec of %s, fp=%d\n", s
, fp
-frame
));
257 for (i
= 0; i
< ndef
; i
++) {
258 Cell
*t
= fp
->args
[i
];
260 if (t
->csub
== CCOPY
) {
265 oargs
[i
]->tval
= t
->tval
;
266 oargs
[i
]->tval
&= ~(STR
|NUM
|DONTFREE
);
267 oargs
[i
]->sval
= t
->sval
;
268 tempfree(t
, "oargsarr");
273 tempfree(t
, "fp->args");
274 if (t
== y
) freed
= 1;
277 tempfree(fcn
, "call.fcn");
278 if (isexit(y
) || isnext(y
))
281 tempfree(y
, "fcn ret"); /* this can free twice! */
282 z
= fp
->retval
; /* return value */
283 dprintf(("%s returns %g |%s| %o\n",
284 s
, getfval(z
), getsval(z
), z
->tval
));
290 copycell(Cell
*x
) /* make a copy of a cell in a temp */
294 y
= gettemp("copycell");
295 y
->csub
= CCOPY
; /* prevents freeing until call is over */
297 y
->sval
= x
->sval
? tostring(x
->sval
) : NULL
;
299 /* copy is not constant or field is DONTFREE right? */
300 y
->tval
= x
->tval
& ~(CON
|FLD
|REC
|DONTFREE
);
306 arg(Node
**a
, int nnn
)
310 n
= (int)a
[0]; /* argument number, counting from 0 */
311 dprintf(("arg(%d), fp->nargs=%d\n", n
, fp
->nargs
));
312 if (n
+1 > fp
->nargs
) {
313 ERROR
"argument #%d of function %s was not supplied",
314 n
+1, fp
->fcncell
->nval FATAL
;
316 return (fp
->args
[n
]);
320 jump(Node
**a
, int n
)
328 errorflag
= (int)getfval(y
);
336 if ((y
->tval
& (STR
|NUM
)) == (STR
|NUM
)) {
337 (void) setsval(fp
->retval
, getsval(y
));
338 fp
->retval
->fval
= getfval(y
);
339 fp
->retval
->tval
|= NUM
;
340 } else if (y
->tval
& STR
)
341 (void) setsval(fp
->retval
, getsval(y
));
342 else if (y
->tval
& NUM
)
343 (void) setfval(fp
->retval
, getfval(y
));
353 default: /* can't happen */
354 ERROR
"illegal jump type %d", n FATAL
;
361 getaline(Node
**a
, int n
)
363 /* a[0] is variable, a[1] is operator, a[2] is filename */
364 register Cell
*r
, *x
;
369 (void) fflush(stdout
); /* in case someone is waiting for a prompt */
371 if (a
[1] != NULL
) { /* getline < file */
372 x
= execute(a
[2]); /* filename */
373 if ((int)a
[1] == '|') /* input pipe */
374 a
[1] = (Node
*)LE
; /* arbitrary flag */
375 fp
= openfile((int)a
[1], getsval(x
));
381 n
= readrec(&buf
, &len
, fp
);
383 if (a
[0] != NULL
) { /* getline var <file */
384 (void) setsval(execute(a
[0]), buf
);
385 } else { /* getline <file */
386 if (!(recloc
->tval
& DONTFREE
))
388 expand_buf(&record
, &record_size
, len
);
389 (void) memcpy(record
, buf
, len
);
391 recloc
->sval
= record
;
392 recloc
->tval
= REC
| STR
| DONTFREE
;
393 donerec
= 1; donefld
= 0;
398 } else { /* bare getline; use current input */
399 if (a
[0] == NULL
) /* getline */
400 n
= getrec(&record
, &record_size
);
401 else { /* getline var */
402 init_buf(&buf
, &len
, LINE_INCR
);
403 n
= getrec(&buf
, &len
);
404 (void) setsval(execute(a
[0]), buf
);
408 (void) setfval(r
, (Awkfloat
)n
);
414 getnf(Node
**a
, int n
)
418 return ((Cell
*)a
[0]);
423 array(Node
**a
, int n
)
425 register Cell
*x
, *y
, *z
;
429 size_t bsize
, tlen
, len
, slen
;
431 x
= execute(a
[0]); /* Cell* for symbol table */
432 init_buf(&buf
, &bsize
, LINE_INCR
);
435 slen
= strlen((char *)*SUBSEP
);
436 for (np
= a
[1]; np
; np
= np
->nnext
) {
437 y
= execute(np
); /* subscript */
439 len
= strlen((char *)s
);
440 expand_buf(&buf
, &bsize
, tlen
+ len
+ slen
);
441 (void) memcpy(&buf
[tlen
], s
, len
);
444 (void) memcpy(&buf
[tlen
], *SUBSEP
, slen
);
451 dprintf(("making %s into an array\n", x
->nval
));
454 x
->tval
&= ~(STR
|NUM
|DONTFREE
);
456 x
->sval
= (uchar
*) makesymtab(NSYMTAB
);
459 z
= setsymtab(buf
, (uchar
*)"", 0.0, STR
|NUM
, (Array
*)x
->sval
);
469 delete(Node
**a
, int n
)
474 size_t bsize
, tlen
, slen
, len
;
476 x
= execute(a
[0]); /* Cell* for symbol table */
479 init_buf(&buf
, &bsize
, LINE_INCR
);
482 slen
= strlen((char *)*SUBSEP
);
483 for (np
= a
[1]; np
; np
= np
->nnext
) {
484 y
= execute(np
); /* subscript */
486 len
= strlen((char *)s
);
487 expand_buf(&buf
, &bsize
, tlen
+ len
+ slen
);
488 (void) memcpy(&buf
[tlen
], s
, len
);
491 (void) memcpy(&buf
[tlen
], *SUBSEP
, slen
);
505 intest(Node
**a
, int n
)
507 register Cell
*x
, *ap
, *k
;
511 size_t bsize
, tlen
, slen
, len
;
513 ap
= execute(a
[1]); /* array name */
515 ERROR
"%s is not an array", ap
->nval FATAL
;
516 init_buf(&buf
, &bsize
, LINE_INCR
);
519 slen
= strlen((char *)*SUBSEP
);
520 for (p
= a
[0]; p
; p
= p
->nnext
) {
521 x
= execute(p
); /* expr */
523 len
= strlen((char *)s
);
524 expand_buf(&buf
, &bsize
, tlen
+ len
+ slen
);
525 (void) memcpy(&buf
[tlen
], s
, len
);
529 (void) memcpy(&buf
[tlen
], *SUBSEP
, slen
);
535 k
= lookup(buf
, (Array
*)ap
->sval
);
546 matchop(Node
**a
, int n
)
548 register Cell
*x
, *y
;
549 register uchar
*s
, *t
;
552 int (*mf
)() = match
, mode
= 0;
565 pfa
= makedfa(t
, mode
);
571 int start
= patbeg
- s
+ 1;
574 (void) setfval(rstartloc
, (Awkfloat
)start
);
575 (void) setfval(rlengthloc
, (Awkfloat
)patlen
);
580 } else if (n
== MATCH
&& i
== 1 || n
== NOTMATCH
&& i
== 0)
588 boolop(Node
**a
, int n
)
590 register Cell
*x
, *y
;
603 return (i
? true : false);
610 return (i
? true : false);
612 return (i
? false : true);
613 default: /* can't happen */
614 ERROR
"unknown boolean operator %d", n FATAL
;
621 relop(Node
**a
, int n
)
624 register Cell
*x
, *y
;
629 if (x
->tval
&NUM
&& y
->tval
&NUM
) {
630 j
= x
->fval
- y
->fval
;
631 i
= j
< 0 ? -1: (j
> 0 ? 1: 0);
633 i
= strcmp((char *)getsval(x
), (char *)getsval(y
));
638 case LT
: return (i
< 0 ? true : false);
639 case LE
: return (i
<= 0 ? true : false);
640 case NE
: return (i
!= 0 ? true : false);
641 case EQ
: return (i
== 0 ? true : false);
642 case GE
: return (i
>= 0 ? true : false);
643 case GT
: return (i
> 0 ? true : false);
644 default: /* can't happen */
645 ERROR
"unknown relational operator %d", n FATAL
;
652 tfree(Cell
*a
, char *s
)
655 (void) printf("## tfree %.8s %06lo %s\n",
656 s
, (ulong_t
)a
, a
->sval
? a
->sval
: (uchar
*)"");
661 ERROR
"tempcell list is curdled" FATAL
;
673 tmps
= (Cell
*)calloc(100, sizeof (Cell
));
675 ERROR
"no space for temporaries" FATAL
;
676 for (i
= 1; i
< 100; i
++)
677 tmps
[i
-1].cnext
= &tmps
[i
];
684 (void) printf("## gtemp %.8s %06lo\n", s
, (ulong_t
)x
);
690 indirect(Node
**a
, int n
)
698 if (m
== 0 && !is_number(s
= getsval(x
))) /* suspicion! */
699 ERROR
"illegal field $(%s)", s FATAL
;
709 substr(Node
**a
, int nnn
)
711 register int k
, m
, n
;
714 register Cell
*x
, *y
, *z
;
721 k
= strlen((char *)s
) + 1;
728 (void) setsval(x
, (uchar
*)"");
746 dprintf(("substr: m=%d, n=%d, s=%s\n", m
, n
, s
));
748 temp
= s
[n
+ m
- 1]; /* with thanks to John Linderman */
750 (void) setsval(y
, s
+ m
- 1);
758 sindex(Node
**a
, int nnn
)
760 register Cell
*x
, *y
, *z
;
761 register uchar
*s1
, *s2
, *p1
, *p2
, *q
;
770 for (p1
= s1
; *p1
!= '\0'; p1
++) {
771 for (q
= p1
, p2
= s2
; *p2
!= '\0' && *q
== *p2
; q
++, p2
++)
774 v
= (Awkfloat
) (p1
- s1
+ 1); /* origin 1 */
780 (void) setfval(z
, v
);
785 format(uchar
**bufp
, uchar
*s
, Node
*a
)
792 size_t bufsize
, fmtsize
, cnt
, tcnt
, ret
;
794 init_buf(&buf
, &bufsize
, LINE_INCR
);
795 init_buf(&fmt
, &fmtsize
, LINE_INCR
);
800 expand_buf(&buf
, &bufsize
, cnt
);
805 expand_buf(&buf
, &bufsize
, cnt
);
810 for (tcnt
= 0; ; s
++) {
811 expand_buf(&fmt
, &fmtsize
, tcnt
);
815 if (isalpha(*s
) && *s
!= 'l' && *s
!= 'h' && *s
!= 'L')
816 break; /* the ansi panoply */
820 "not enough args in printf(%s) or sprintf(%s)", os
, os FATAL
;
825 expand_buf(&fmt
, &fmtsize
, tcnt
+ 12);
826 ret
= sprintf((char *)&fmt
[tcnt
], "%d",
835 case 'f': case 'e': case 'g': case 'E': case 'G':
843 expand_buf(&fmt
, &fmtsize
, tcnt
);
847 case 'o': case 'x': case 'X': case 'u':
848 flag
= *(s
-1) == 'l' ? 2 : 3;
861 len
= strlen((char *)fmt
);
862 expand_buf(&buf
, &bufsize
, cnt
+ len
);
863 (void) memcpy(&buf
[cnt
], fmt
, len
);
870 "not enough args in printf(%s) or sprintf(%s)", os
, os FATAL
;
875 /* make sure we have at least 1 byte space */
876 expand_buf(&buf
, &bufsize
, cnt
+ 1);
881 ret
= snprintf((char *)&buf
[cnt
], len
,
882 (char *)fmt
, getfval(x
));
886 ret
= snprintf((char *)&buf
[cnt
], len
,
887 (char *)fmt
, (long)getfval(x
));
891 ret
= snprintf((char *)&buf
[cnt
], len
,
892 (char *)fmt
, (int)getfval(x
));
896 ret
= snprintf((char *)&buf
[cnt
], len
,
897 (char *)fmt
, getsval(x
));
902 ret
= snprintf((char *)&buf
[cnt
], len
,
903 (char *)fmt
, (int)getfval(x
));
906 ret
= snprintf((char *)&buf
[cnt
], len
,
907 (char *)fmt
, getsval(x
)[0]);
915 expand_buf(&buf
, &bufsize
, cnt
+ ret
);
922 for (; a
; a
= a
->nnext
) /* evaluate any remaining args */
924 *bufp
= tostring(buf
);
931 a_sprintf(Node
**a
, int n
)
939 format(&buf
, getsval(x
), y
);
949 aprintf(Node
**a
, int n
)
958 format(&buf
, getsval(x
), y
);
961 (void) fputs((char *)buf
, stdout
);
963 fp
= redirect((int)a
[1], a
[2]);
964 (void) fputs((char *)buf
, fp
);
972 arith(Node
**a
, int n
)
976 register Cell
*x
, *y
, *z
;
999 ERROR
"division by zero" FATAL
;
1004 ERROR
"division by zero in mod" FATAL
;
1005 (void) modf(i
/j
, &v
);
1012 if (j
>= 0 && modf(j
, &v
) == 0.0) /* pos integer exponent */
1013 i
= ipow(i
, (int)j
);
1015 i
= errcheck(pow(i
, j
), "pow");
1017 default: /* can't happen */
1018 ERROR
"illegal arithmetic operator %d", n FATAL
;
1020 (void) setfval(z
, i
);
1025 ipow(double x
, int n
)
1039 incrdecr(Node
**a
, int n
)
1041 register Cell
*x
, *z
;
1047 k
= (n
== PREINCR
|| n
== POSTINCR
) ? 1 : -1;
1048 if (n
== PREINCR
|| n
== PREDECR
) {
1049 (void) setfval(x
, xf
+ k
);
1053 (void) setfval(z
, xf
);
1054 (void) setfval(x
, xf
+ k
);
1060 assign(Node
**a
, int n
)
1062 register Cell
*x
, *y
;
1067 x
= execute(a
[0]); /* order reversed from before... */
1068 if (n
== ASSIGN
) { /* ordinary assignment */
1069 if ((y
->tval
& (STR
|NUM
)) == (STR
|NUM
)) {
1070 (void) setsval(x
, getsval(y
));
1071 x
->fval
= getfval(y
);
1073 } else if (y
->tval
& STR
)
1074 (void) setsval(x
, getsval(y
));
1075 else if (y
->tval
& NUM
)
1076 (void) setfval(x
, getfval(y
));
1078 funnyvar(y
, "read value of");
1096 ERROR
"division by zero in /=" FATAL
;
1101 ERROR
"division by zero in %%=" FATAL
;
1102 (void) modf(xf
/yf
, &v
);
1106 if (yf
>= 0 && modf(yf
, &v
) == 0.0) /* pos integer exponent */
1107 xf
= ipow(xf
, (int)yf
);
1109 xf
= errcheck(pow(xf
, yf
), "pow");
1112 ERROR
"illegal assignment operator %d", n FATAL
;
1116 (void) setfval(x
, xf
);
1122 cat(Node
**a
, int q
)
1124 register Cell
*x
, *y
, *z
;
1125 register int n1
, n2
;
1132 n1
= strlen((char *)x
->sval
);
1133 n2
= strlen((char *)y
->sval
);
1134 s
= (uchar
*)malloc(n1
+ n2
+ 1);
1136 ERROR
"out of space concatenating %.15s and %.15s",
1137 x
->sval
, y
->sval FATAL
;
1139 (void) strcpy((char *)s
, (char *)x
->sval
);
1140 (void) strcpy((char *)s
+ n1
, (char *)y
->sval
);
1151 pastat(Node
**a
, int n
)
1169 dopa2(Node
**a
, int n
)
1173 static int *pairstack
= NULL
;
1177 dprintf(("paircnt: %d\n", paircnt
));
1178 pairstack
= (int *)malloc(sizeof (int) * paircnt
);
1180 ERROR
"out of space in dopa2" FATAL
;
1181 (void) memset(pairstack
, 0, sizeof (int) * paircnt
);
1185 if (pairstack
[pair
] == 0) {
1188 pairstack
[pair
] = 1;
1191 if (pairstack
[pair
] == 1) {
1194 pairstack
[pair
] = 0;
1204 split(Node
**a
, int nnn
)
1209 uchar
*t
, temp
, num
[11], *fs
;
1212 y
= execute(a
[0]); /* source string */
1214 if (a
[2] == 0) /* fs string */
1216 else if ((int)a
[3] == STRING
) { /* split(str,arr,"string") */
1219 } else if ((int)a
[3] == REGEXPR
)
1220 fs
= (uchar
*)"(regexpr)"; /* split(str,arr,/regexpr/) */
1222 ERROR
"illegal type of split()" FATAL
;
1224 ap
= execute(a
[1]); /* array name */
1226 dprintf(("split: s=|%s|, a=%s, sep=|%s|\n", s
, ap
->nval
, fs
));
1229 ap
->sval
= (uchar
*)makesymtab(NSYMTAB
);
1232 if (*s
!= '\0' && strlen((char *)fs
) > 1 || (int)a
[3] == REGEXPR
) {
1235 if ((int)a
[3] == REGEXPR
) { /* it's ready already */
1238 pfa
= makedfa(fs
, 1);
1240 if (nematch(pfa
, s
)) {
1241 tempstat
= pfa
->initstat
;
1245 (void) sprintf((char *)num
, "%d", n
);
1249 (void) setsymtab(num
, s
,
1252 STR
|NUM
, (Array
*)ap
->sval
);
1254 (void) setsymtab(num
, s
, 0.0,
1256 STR
, (Array
*)ap
->sval
);
1259 s
= patbeg
+ patlen
;
1260 if (*(patbeg
+patlen
-1) == 0 || *s
== 0) {
1262 (void) sprintf((char *)num
, "%d", n
);
1263 (void) setsymtab(num
, (uchar
*)"", 0.0,
1265 STR
, (Array
*)ap
->sval
);
1266 pfa
->initstat
= tempstat
;
1269 } while (nematch(pfa
, s
));
1272 (void) sprintf((char *)num
, "%d", n
);
1274 (void) setsymtab(num
, s
, atof((char *)s
),
1276 STR
|NUM
, (Array
*)ap
->sval
);
1279 (void) setsymtab(num
, s
, 0.0, STR
, (Array
*)ap
->sval
);
1283 } else if (sep
== ' ') {
1285 while (*s
== ' ' || *s
== '\t' || *s
== '\n')
1293 while (*s
!= ' ' && *s
!= '\t' &&
1294 *s
!= '\n' && *s
!= '\0')
1298 (void) sprintf((char *)num
, "%d", n
);
1300 (void) setsymtab(num
, t
, atof((char *)t
),
1302 STR
|NUM
, (Array
*)ap
->sval
);
1304 (void) setsymtab(num
, t
, 0.0,
1306 STR
, (Array
*)ap
->sval
);
1312 } else if (*s
!= 0) {
1316 while (*s
!= sep
&& *s
!= '\n' && *s
!= '\0')
1320 (void) sprintf((char *)num
, "%d", n
);
1322 (void) setsymtab(num
, t
, atof((char *)t
),
1324 STR
|NUM
, (Array
*)ap
->sval
);
1326 (void) setsymtab(num
, t
, 0.0,
1328 STR
, (Array
*)ap
->sval
);
1337 if (a
[2] != 0 && (int)a
[3] == STRING
)
1347 condexpr(Node
**a
, int n
)
1364 ifstat(Node
**a
, int n
)
1372 } else if (a
[2] != 0) {
1381 whilestat(Node
**a
, int n
)
1395 if (isnext(x
) || isexit(x
) || isret(x
))
1403 dostat(Node
**a
, int n
)
1411 if (isnext(x
) || isexit(x
) || isret(x
))
1423 forstat(Node
**a
, int n
)
1438 if (isbreak(x
)) /* turn off break */
1440 if (isnext(x
) || isexit(x
) || isret(x
))
1450 instat(Node
**a
, int n
)
1452 register Cell
*x
, *vp
, *arrayp
, *cp
, *ncp
;
1457 arrayp
= execute(a
[1]);
1459 ERROR
"%s is not an array", arrayp
->nval FATAL
;
1461 tp
= (Array
*)arrayp
->sval
;
1462 tempfree(arrayp
, "");
1463 for (i
= 0; i
< tp
->size
; i
++) { /* this routine knows too much */
1464 for (cp
= tp
->tab
[i
]; cp
!= NULL
; cp
= ncp
) {
1465 (void) setsval(vp
, cp
->nval
);
1472 if (isnext(x
) || isexit(x
) || isret(x
)) {
1484 bltin(Node
**a
, int n
)
1486 register Cell
*x
, *y
;
1494 nextarg
= a
[1]->nnext
;
1497 u
= (Awkfloat
)strlen((char *)getsval(x
)); break;
1499 u
= errcheck(log(getfval(x
)), "log"); break;
1501 (void) modf(getfval(x
), &u
); break;
1503 u
= errcheck(exp(getfval(x
)), "exp"); break;
1505 u
= errcheck(sqrt(getfval(x
)), "sqrt"); break;
1507 u
= sin(getfval(x
)); break;
1509 u
= cos(getfval(x
)); break;
1512 ERROR
"atan2 requires two arguments; returning 1.0"
1516 y
= execute(a
[1]->nnext
);
1517 u
= atan2(getfval(x
), getfval(y
));
1519 nextarg
= nextarg
->nnext
;
1523 /* in case something is buffered already */
1524 (void) fflush(stdout
);
1525 /* 256 is unix-dep */
1526 u
= (Awkfloat
)system((char *)getsval(x
)) / 256;
1529 u
= (Awkfloat
)(rand() % 32767) / 32767.0;
1532 if (x
->tval
& REC
) /* no argument provided */
1533 u
= time((time_t *)0);
1536 srand((int)u
); u
= (int)u
;
1540 buf
= tostring(getsval(x
));
1541 if (t
== FTOUPPER
) {
1542 for (p
= buf
; *p
; p
++)
1546 for (p
= buf
; *p
; p
++)
1552 (void) setsval(x
, buf
);
1555 default: /* can't happen */
1556 ERROR
"illegal function type %d", t FATAL
;
1561 (void) setfval(x
, u
);
1563 ERROR
"warning: function has too many arguments" WARNING
;
1564 for (; nextarg
; nextarg
= nextarg
->nnext
)
1565 (void) execute(nextarg
);
1572 print(Node
**a
, int n
)
1581 fp
= redirect((int)a
[1], a
[2]);
1582 for (x
= a
[0]; x
!= NULL
; x
= x
->nnext
) {
1584 (void) fputs((char *)getsval(y
), fp
);
1586 if (x
->nnext
== NULL
)
1587 (void) fputs((char *)*ORS
, fp
);
1589 (void) fputs((char *)*OFS
, fp
);
1598 nullproc(Node
**a
, int n
)
1606 int mode
; /* '|', 'a', 'w' */
1610 redirect(int a
, Node
*b
)
1618 fp
= openfile(a
, fname
);
1620 ERROR
"can't open file %s", fname FATAL
;
1626 openfile(int a
, uchar
*s
)
1632 ERROR
"null file name in print or getline" FATAL
;
1633 for (i
= 0; i
< FOPEN_MAX
; i
++) {
1634 if (files
[i
].fname
&&
1635 strcmp((char *)s
, (char *)files
[i
].fname
) == 0) {
1636 if (a
== files
[i
].mode
||
1637 a
== APPEND
&& files
[i
].mode
== GT
) {
1638 return (files
[i
].fp
);
1642 for (i
= 0; i
< FOPEN_MAX
; i
++) {
1643 if (files
[i
].fp
== 0)
1647 ERROR
"%s makes too many open files", s FATAL
;
1648 (void) fflush(stdout
); /* force a semblance of order */
1651 fp
= fopen((char *)s
, "w");
1652 } else if (a
== APPEND
) {
1653 fp
= fopen((char *)s
, "a");
1654 m
= GT
; /* so can mix > and >> */
1655 } else if (a
== '|') { /* output pipe */
1656 fp
= popen((char *)s
, "w");
1657 } else if (a
== LE
) { /* input pipe */
1658 fp
= popen((char *)s
, "r");
1659 } else if (a
== LT
) { /* getline <file */
1660 fp
= strcmp((char *)s
, "-") == 0 ?
1661 stdin
: fopen((char *)s
, "r"); /* "-" is stdin */
1662 } else /* can't happen */
1663 ERROR
"illegal redirection" FATAL
;
1665 files
[i
].fname
= tostring(s
);
1674 closefile(Node
**a
, int n
)
1681 for (i
= 0; i
< FOPEN_MAX
; i
++) {
1682 if (files
[i
].fname
&&
1683 strcmp((char *)x
->sval
, (char *)files
[i
].fname
) == 0) {
1684 if (ferror(files
[i
].fp
)) {
1685 ERROR
"i/o error occurred on %s",
1686 files
[i
].fname WARNING
;
1688 if (files
[i
].mode
== '|' || files
[i
].mode
== LE
)
1689 stat
= pclose(files
[i
].fp
);
1691 stat
= fclose(files
[i
].fp
);
1693 ERROR
"i/o error occurred closing %s",
1694 files
[i
].fname WARNING
;
1696 xfree(files
[i
].fname
);
1697 /* watch out for ref thru this */
1698 files
[i
].fname
= NULL
;
1702 tempfree(x
, "close");
1711 for (i
= 0; i
< FOPEN_MAX
; i
++) {
1713 if (ferror(files
[i
].fp
)) {
1714 ERROR
"i/o error occurred on %s",
1715 files
[i
].fname WARNING
;
1717 if (files
[i
].mode
== '|' || files
[i
].mode
== LE
)
1718 stat
= pclose(files
[i
].fp
);
1720 stat
= fclose(files
[i
].fp
);
1722 ERROR
"i/o error occurred while closing %s",
1723 files
[i
].fname WARNING
;
1731 sub(Node
**a
, int nnn
)
1733 register uchar
*sptr
;
1734 register Cell
*x
, *y
, *result
;
1737 size_t bsize
, cnt
, len
;
1739 x
= execute(a
[3]); /* target string */
1742 pfa
= (fa
*)a
[1]; /* regular expression */
1745 pfa
= makedfa(getsval(y
), 1);
1748 y
= execute(a
[2]); /* replacement string */
1750 if (pmatch(pfa
, t
)) {
1751 init_buf(&buf
, &bsize
, LINE_INCR
);
1754 len
= patbeg
- sptr
;
1756 expand_buf(&buf
, &bsize
, cnt
+ len
);
1757 (void) memcpy(buf
, sptr
, len
);
1761 while (*sptr
!= 0) {
1762 expand_buf(&buf
, &bsize
, cnt
);
1763 if (*sptr
== '\\' &&
1764 (*(sptr
+1) == '&' || *(sptr
+1) == '\\')) {
1765 sptr
++; /* skip \, */
1766 buf
[cnt
++] = *sptr
++; /* add & or \ */
1767 } else if (*sptr
== '&') {
1768 expand_buf(&buf
, &bsize
, cnt
+ patlen
);
1770 (void) memcpy(&buf
[cnt
], patbeg
, patlen
);
1773 buf
[cnt
++] = *sptr
++;
1776 sptr
= patbeg
+ patlen
;
1777 if ((patlen
== 0 && *patbeg
) || (patlen
&& *(sptr
-1))) {
1778 len
= strlen((char *)sptr
);
1779 expand_buf(&buf
, &bsize
, cnt
+ len
);
1780 (void) memcpy(&buf
[cnt
], sptr
, len
);
1784 (void) setsval(x
, buf
);
1795 gsub(Node
**a
, int nnn
)
1797 register Cell
*x
, *y
;
1798 register uchar
*rptr
, *sptr
, *t
;
1801 int mflag
, tempstat
, num
;
1802 size_t bsize
, cnt
, len
;
1804 mflag
= 0; /* if mflag == 0, can replace empty string */
1806 x
= execute(a
[3]); /* target string */
1809 pfa
= (fa
*) a
[1]; /* regular expression */
1812 pfa
= makedfa(getsval(y
), 1);
1815 y
= execute(a
[2]); /* replacement string */
1816 if (pmatch(pfa
, t
)) {
1817 tempstat
= pfa
->initstat
;
1819 init_buf(&buf
, &bsize
, LINE_INCR
);
1823 if (patlen
== 0 && *patbeg
!= 0) {
1824 /* matched empty string */
1825 if (mflag
== 0) { /* can replace empty */
1828 while (*sptr
!= 0) {
1829 expand_buf(&buf
, &bsize
, cnt
);
1830 if (*sptr
== '\\' &&
1831 (*(sptr
+1) == '&' ||
1832 *(sptr
+1) == '\\')) {
1834 buf
[cnt
++] = *sptr
++;
1835 } else if (*sptr
== '&') {
1840 (void) memcpy(&buf
[cnt
],
1844 buf
[cnt
++] = *sptr
++;
1848 if (*t
== 0) /* at end */
1850 expand_buf(&buf
, &bsize
, cnt
);
1853 } else { /* matched nonempty string */
1856 len
= patbeg
- sptr
;
1858 expand_buf(&buf
, &bsize
, cnt
+ len
);
1859 (void) memcpy(&buf
[cnt
], sptr
, len
);
1863 while (*sptr
!= 0) {
1864 expand_buf(&buf
, &bsize
, cnt
);
1865 if (*sptr
== '\\' &&
1866 (*(sptr
+1) == '&' ||
1867 *(sptr
+1) == '\\')) {
1869 buf
[cnt
++] = *sptr
++;
1870 } else if (*sptr
== '&') {
1871 expand_buf(&buf
, &bsize
,
1874 (void) memcpy(&buf
[cnt
],
1878 buf
[cnt
++] = *sptr
++;
1881 t
= patbeg
+ patlen
;
1882 if ((*(t
-1) == 0) || (*t
== 0))
1886 } while (pmatch(pfa
, t
));
1888 len
= strlen((char *)sptr
);
1889 expand_buf(&buf
, &bsize
, len
+ cnt
);
1890 (void) memcpy(&buf
[cnt
], sptr
, len
);
1894 (void) setsval(x
, buf
);
1896 pfa
->initstat
= tempstat
;