8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / awk / run.c
blob3cc8341d84fb3a61d9fe22bc8035fdd63ccc711b
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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)
33 #define DEBUG
34 #include "awk.h"
35 #include <math.h>
36 #include "y.tab.h"
37 #include <stdio.h>
38 #include <ctype.h>
39 #include <setjmp.h>
40 #include <time.h>
42 #ifndef FOPEN_MAX
43 #define FOPEN_MAX 15 /* max number of open files, from ANSI std. */
44 #endif
47 static jmp_buf env;
49 static Cell *r_execute(Node *);
50 static Cell *gettemp(char *), *copycell(Cell *);
51 static FILE *openfile(int, uchar *), *redirect(int, Node *);
53 int paircnt;
54 Node *winner = NULL;
56 static Cell *tmps;
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);
80 void
81 run(Node *a)
83 (void) execute(a);
84 closeall();
87 static Cell *
88 r_execute(Node *u)
90 register Cell *(*proc)();
91 register Cell *x;
92 register Node *a;
94 if (u == NULL)
95 return (true);
96 for (a = u; ; a = a->nnext) {
97 curnode = a;
98 if (isvalue(a)) {
99 x = (Cell *) (a->narg[0]);
100 if ((x->tval & FLD) && !donefld)
101 fldbld();
102 else if ((x->tval & REC) && !donerec)
103 recbld();
104 return (x);
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)
112 fldbld();
113 else if ((x->tval & REC) && !donerec)
114 recbld();
115 if (isexpr(a))
116 return (x);
117 /* a statement, goto next statement */
118 if (isjump(x))
119 return (x);
120 if (a->nnext == (Node *)NULL)
121 return (x);
122 tempfree(x, "execute");
126 /*ARGSUSED*/
127 Cell *
128 program(Node **a, int n)
130 register Cell *x;
132 if (setjmp(env) != 0)
133 goto ex;
134 if (a[0]) { /* BEGIN */
135 x = execute(a[0]);
136 if (isexit(x))
137 return (true);
138 if (isjump(x)) {
139 ERROR "illegal break, continue or next from BEGIN"
140 FATAL;
142 tempfree(x, "");
144 loop:
145 if (a[1] || a[2])
146 while (getrec(&record, &record_size) > 0) {
147 x = execute(a[1]);
148 if (isexit(x))
149 break;
150 tempfree(x, "");
153 if (setjmp(env) != 0)
154 goto ex1;
155 if (a[2]) { /* END */
156 x = execute(a[2]);
157 if (iscont(x)) /* read some more */
158 goto loop;
159 if (isbreak(x) || isnext(x))
160 ERROR "illegal break or next from END" FATAL;
161 tempfree(x, "");
163 ex1:
164 return (true);
167 struct Frame {
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 */
174 #define NARGS 30
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 */
180 /*ARGSUSED*/
181 Cell *
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;
187 Node *x;
188 Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn;
189 uchar *s;
191 fcn = execute(a[0]); /* the function itself */
192 s = fcn->nval;
193 if (!isfunc(fcn))
194 ERROR "calling undefined function %s", s FATAL;
195 if (frame == NULL) {
196 fp = frame = (struct Frame *)calloc(nframe += 100,
197 sizeof (struct Frame));
198 if (frame == NULL) {
199 ERROR "out of space for stack frames calling %s",
200 s FATAL;
203 for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
204 ncall++;
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));
208 if (ncall > ndef) {
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) {
217 /* get call args */
218 dprintf(("evaluate args[%d], fp=%d:\n", i, fp-frame));
219 y = execute(x);
220 oargs[i] = y;
221 dprintf(("args[%d]: %s %f <%s>, t=%o\n",
222 i, y->nval, y->fval,
223 isarr(y) ? "(array)" : (char *)y->sval, y->tval));
224 if (isfunc(y)) {
225 ERROR "can't use function %s as argument in %s",
226 y->nval, s FATAL;
228 if (isarr(y))
229 args[i] = y; /* arrays by ref */
230 else
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));
243 if (frame == NULL)
244 ERROR "out of space for stack frames in %s", s FATAL;
245 fp = frame + dfp;
247 fp->fcncell = fcn;
248 fp->args = args;
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));
253 /*LINTED align*/
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];
259 if (isarr(t)) {
260 if (t->csub == CCOPY) {
261 if (i >= ncall) {
262 freesymtab(t);
263 t->csub = CTEMP;
264 } else {
265 oargs[i]->tval = t->tval;
266 oargs[i]->tval &= ~(STR|NUM|DONTFREE);
267 oargs[i]->sval = t->sval;
268 tempfree(t, "oargsarr");
271 } else {
272 t->csub = CTEMP;
273 tempfree(t, "fp->args");
274 if (t == y) freed = 1;
277 tempfree(fcn, "call.fcn");
278 if (isexit(y) || isnext(y))
279 return (y);
280 if (!freed)
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));
285 fp--;
286 return (z);
289 static Cell *
290 copycell(Cell *x) /* make a copy of a cell in a temp */
292 Cell *y;
294 y = gettemp("copycell");
295 y->csub = CCOPY; /* prevents freeing until call is over */
296 y->nval = x->nval;
297 y->sval = x->sval ? tostring(x->sval) : NULL;
298 y->fval = x->fval;
299 /* copy is not constant or field is DONTFREE right? */
300 y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);
301 return (y);
304 /*ARGSUSED*/
305 Cell *
306 arg(Node **a, int nnn)
308 int n;
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]);
319 Cell *
320 jump(Node **a, int n)
322 register Cell *y;
324 switch (n) {
325 case EXIT:
326 if (a[0] != NULL) {
327 y = execute(a[0]);
328 errorflag = (int)getfval(y);
329 tempfree(y, "");
331 longjmp(env, 1);
332 /*NOTREACHED*/
333 case RETURN:
334 if (a[0] != NULL) {
335 y = execute(a[0]);
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));
344 tempfree(y, "");
346 return (jret);
347 case NEXT:
348 return (jnext);
349 case BREAK:
350 return (jbreak);
351 case CONTINUE:
352 return (jcont);
353 default: /* can't happen */
354 ERROR "illegal jump type %d", n FATAL;
356 /*NOTREACHED*/
357 return (NULL);
360 Cell *
361 getaline(Node **a, int n)
363 /* a[0] is variable, a[1] is operator, a[2] is filename */
364 register Cell *r, *x;
365 uchar *buf;
366 FILE *fp;
367 size_t len;
369 (void) fflush(stdout); /* in case someone is waiting for a prompt */
370 r = gettemp("");
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));
376 tempfree(x, "");
377 buf = NULL;
378 if (fp == NULL)
379 n = -1;
380 else
381 n = readrec(&buf, &len, fp);
382 if (n > 0) {
383 if (a[0] != NULL) { /* getline var <file */
384 (void) setsval(execute(a[0]), buf);
385 } else { /* getline <file */
386 if (!(recloc->tval & DONTFREE))
387 xfree(recloc->sval);
388 expand_buf(&record, &record_size, len);
389 (void) memcpy(record, buf, len);
390 record[len] = '\0';
391 recloc->sval = record;
392 recloc->tval = REC | STR | DONTFREE;
393 donerec = 1; donefld = 0;
396 if (buf != NULL)
397 free(buf);
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);
405 free(buf);
408 (void) setfval(r, (Awkfloat)n);
409 return (r);
412 /*ARGSUSED*/
413 Cell *
414 getnf(Node **a, int n)
416 if (donefld == 0)
417 fldbld();
418 return ((Cell *)a[0]);
421 /*ARGSUSED*/
422 Cell *
423 array(Node **a, int n)
425 register Cell *x, *y, *z;
426 register uchar *s;
427 register Node *np;
428 uchar *buf;
429 size_t bsize, tlen, len, slen;
431 x = execute(a[0]); /* Cell* for symbol table */
432 init_buf(&buf, &bsize, LINE_INCR);
433 buf[0] = '\0';
434 tlen = 0;
435 slen = strlen((char *)*SUBSEP);
436 for (np = a[1]; np; np = np->nnext) {
437 y = execute(np); /* subscript */
438 s = getsval(y);
439 len = strlen((char *)s);
440 expand_buf(&buf, &bsize, tlen + len + slen);
441 (void) memcpy(&buf[tlen], s, len);
442 tlen += len;
443 if (np->nnext) {
444 (void) memcpy(&buf[tlen], *SUBSEP, slen);
445 tlen += slen;
447 buf[tlen] = '\0';
448 tempfree(y, "");
450 if (!isarr(x)) {
451 dprintf(("making %s into an array\n", x->nval));
452 if (freeable(x))
453 xfree(x->sval);
454 x->tval &= ~(STR|NUM|DONTFREE);
455 x->tval |= ARR;
456 x->sval = (uchar *) makesymtab(NSYMTAB);
458 /*LINTED align*/
459 z = setsymtab(buf, (uchar *)"", 0.0, STR|NUM, (Array *)x->sval);
460 z->ctype = OCELL;
461 z->csub = CVAR;
462 tempfree(x, "");
463 free(buf);
464 return (z);
467 /*ARGSUSED*/
468 Cell *
469 delete(Node **a, int n)
471 Cell *x, *y;
472 Node *np;
473 uchar *buf, *s;
474 size_t bsize, tlen, slen, len;
476 x = execute(a[0]); /* Cell* for symbol table */
477 if (!isarr(x))
478 return (true);
479 init_buf(&buf, &bsize, LINE_INCR);
480 buf[0] = '\0';
481 tlen = 0;
482 slen = strlen((char *)*SUBSEP);
483 for (np = a[1]; np; np = np->nnext) {
484 y = execute(np); /* subscript */
485 s = getsval(y);
486 len = strlen((char *)s);
487 expand_buf(&buf, &bsize, tlen + len + slen);
488 (void) memcpy(&buf[tlen], s, len);
489 tlen += len;
490 if (np->nnext) {
491 (void) memcpy(&buf[tlen], *SUBSEP, slen);
492 tlen += slen;
494 buf[tlen] = '\0';
495 tempfree(y, "");
497 freeelem(x, buf);
498 tempfree(x, "");
499 free(buf);
500 return (true);
503 /*ARGSUSED*/
504 Cell *
505 intest(Node **a, int n)
507 register Cell *x, *ap, *k;
508 Node *p;
509 uchar *buf;
510 uchar *s;
511 size_t bsize, tlen, slen, len;
513 ap = execute(a[1]); /* array name */
514 if (!isarr(ap))
515 ERROR "%s is not an array", ap->nval FATAL;
516 init_buf(&buf, &bsize, LINE_INCR);
517 buf[0] = 0;
518 tlen = 0;
519 slen = strlen((char *)*SUBSEP);
520 for (p = a[0]; p; p = p->nnext) {
521 x = execute(p); /* expr */
522 s = getsval(x);
523 len = strlen((char *)s);
524 expand_buf(&buf, &bsize, tlen + len + slen);
525 (void) memcpy(&buf[tlen], s, len);
526 tlen += len;
527 tempfree(x, "");
528 if (p->nnext) {
529 (void) memcpy(&buf[tlen], *SUBSEP, slen);
530 tlen += slen;
532 buf[tlen] = '\0';
534 /*LINTED align*/
535 k = lookup(buf, (Array *)ap->sval);
536 tempfree(ap, "");
537 free(buf);
538 if (k == NULL)
539 return (false);
540 else
541 return (true);
545 Cell *
546 matchop(Node **a, int n)
548 register Cell *x, *y;
549 register uchar *s, *t;
550 register int i;
551 fa *pfa;
552 int (*mf)() = match, mode = 0;
554 if (n == MATCHFCN) {
555 mf = pmatch;
556 mode = 1;
558 x = execute(a[1]);
559 s = getsval(x);
560 if (a[0] == 0)
561 i = (*mf)(a[2], s);
562 else {
563 y = execute(a[2]);
564 t = getsval(y);
565 pfa = makedfa(t, mode);
566 i = (*mf)(pfa, s);
567 tempfree(y, "");
569 tempfree(x, "");
570 if (n == MATCHFCN) {
571 int start = patbeg - s + 1;
572 if (patlen < 0)
573 start = 0;
574 (void) setfval(rstartloc, (Awkfloat)start);
575 (void) setfval(rlengthloc, (Awkfloat)patlen);
576 x = gettemp("");
577 x->tval = NUM;
578 x->fval = start;
579 return (x);
580 } else if (n == MATCH && i == 1 || n == NOTMATCH && i == 0)
581 return (true);
582 else
583 return (false);
587 Cell *
588 boolop(Node **a, int n)
590 register Cell *x, *y;
591 register int i;
593 x = execute(a[0]);
594 i = istrue(x);
595 tempfree(x, "");
596 switch (n) {
597 case BOR:
598 if (i)
599 return (true);
600 y = execute(a[1]);
601 i = istrue(y);
602 tempfree(y, "");
603 return (i ? true : false);
604 case AND:
605 if (!i)
606 return (false);
607 y = execute(a[1]);
608 i = istrue(y);
609 tempfree(y, "");
610 return (i ? true : false);
611 case NOT:
612 return (i ? false : true);
613 default: /* can't happen */
614 ERROR "unknown boolean operator %d", n FATAL;
616 /*NOTREACHED*/
617 return (NULL);
620 Cell *
621 relop(Node **a, int n)
623 register int i;
624 register Cell *x, *y;
625 Awkfloat j;
627 x = execute(a[0]);
628 y = execute(a[1]);
629 if (x->tval&NUM && y->tval&NUM) {
630 j = x->fval - y->fval;
631 i = j < 0 ? -1: (j > 0 ? 1: 0);
632 } else {
633 i = strcmp((char *)getsval(x), (char *)getsval(y));
635 tempfree(x, "");
636 tempfree(y, "");
637 switch (n) {
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;
647 /*NOTREACHED*/
648 return (false);
651 static void
652 tfree(Cell *a, char *s)
654 if (dbg > 1) {
655 (void) printf("## tfree %.8s %06lo %s\n",
656 s, (ulong_t)a, a->sval ? a->sval : (uchar *)"");
658 if (freeable(a))
659 xfree(a->sval);
660 if (a == tmps)
661 ERROR "tempcell list is curdled" FATAL;
662 a->cnext = tmps;
663 tmps = a;
666 static Cell *
667 gettemp(char *s)
669 int i;
670 register Cell *x;
672 if (!tmps) {
673 tmps = (Cell *)calloc(100, sizeof (Cell));
674 if (!tmps)
675 ERROR "no space for temporaries" FATAL;
676 for (i = 1; i < 100; i++)
677 tmps[i-1].cnext = &tmps[i];
678 tmps[i-1].cnext = 0;
680 x = tmps;
681 tmps = x->cnext;
682 *x = tempcell;
683 if (dbg > 1)
684 (void) printf("## gtemp %.8s %06lo\n", s, (ulong_t)x);
685 return (x);
688 /*ARGSUSED*/
689 Cell *
690 indirect(Node **a, int n)
692 register Cell *x;
693 register int m;
694 register uchar *s;
696 x = execute(a[0]);
697 m = (int)getfval(x);
698 if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */
699 ERROR "illegal field $(%s)", s FATAL;
700 tempfree(x, "");
701 x = fieldadr(m);
702 x->ctype = OCELL;
703 x->csub = CFLD;
704 return (x);
707 /*ARGSUSED*/
708 Cell *
709 substr(Node **a, int nnn)
711 register int k, m, n;
712 register uchar *s;
713 int temp;
714 register Cell *x, *y, *z;
716 x = execute(a[0]);
717 y = execute(a[1]);
718 if (a[2] != 0)
719 z = execute(a[2]);
720 s = getsval(x);
721 k = strlen((char *)s) + 1;
722 if (k <= 1) {
723 tempfree(x, "");
724 tempfree(y, "");
725 if (a[2] != 0)
726 tempfree(z, "");
727 x = gettemp("");
728 (void) setsval(x, (uchar *)"");
729 return (x);
731 m = (int)getfval(y);
732 if (m <= 0)
733 m = 1;
734 else if (m > k)
735 m = k;
736 tempfree(y, "");
737 if (a[2] != 0) {
738 n = (int)getfval(z);
739 tempfree(z, "");
740 } else
741 n = k - 1;
742 if (n < 0)
743 n = 0;
744 else if (n > k - m)
745 n = k - m;
746 dprintf(("substr: m=%d, n=%d, s=%s\n", m, n, s));
747 y = gettemp("");
748 temp = s[n + m - 1]; /* with thanks to John Linderman */
749 s[n + m - 1] = '\0';
750 (void) setsval(y, s + m - 1);
751 s[n + m - 1] = temp;
752 tempfree(x, "");
753 return (y);
756 /*ARGSUSED*/
757 Cell *
758 sindex(Node **a, int nnn)
760 register Cell *x, *y, *z;
761 register uchar *s1, *s2, *p1, *p2, *q;
762 Awkfloat v = 0.0;
764 x = execute(a[0]);
765 s1 = getsval(x);
766 y = execute(a[1]);
767 s2 = getsval(y);
769 z = gettemp("");
770 for (p1 = s1; *p1 != '\0'; p1++) {
771 for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++)
773 if (*p2 == '\0') {
774 v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
775 break;
778 tempfree(x, "");
779 tempfree(y, "");
780 (void) setfval(z, v);
781 return (z);
784 void
785 format(uchar **bufp, uchar *s, Node *a)
787 uchar *fmt;
788 register uchar *os;
789 register Cell *x;
790 int flag = 0, len;
791 uchar_t *buf;
792 size_t bufsize, fmtsize, cnt, tcnt, ret;
794 init_buf(&buf, &bufsize, LINE_INCR);
795 init_buf(&fmt, &fmtsize, LINE_INCR);
796 os = s;
797 cnt = 0;
798 while (*s) {
799 if (*s != '%') {
800 expand_buf(&buf, &bufsize, cnt);
801 buf[cnt++] = *s++;
802 continue;
804 if (*(s+1) == '%') {
805 expand_buf(&buf, &bufsize, cnt);
806 buf[cnt++] = '%';
807 s += 2;
808 continue;
810 for (tcnt = 0; ; s++) {
811 expand_buf(&fmt, &fmtsize, tcnt);
812 fmt[tcnt++] = *s;
813 if (*s == '\0')
814 break;
815 if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
816 break; /* the ansi panoply */
817 if (*s == '*') {
818 if (a == NULL) {
819 ERROR
820 "not enough args in printf(%s) or sprintf(%s)", os, os FATAL;
822 x = execute(a);
823 a = a->nnext;
824 tcnt--;
825 expand_buf(&fmt, &fmtsize, tcnt + 12);
826 ret = sprintf((char *)&fmt[tcnt], "%d",
827 (int)getfval(x));
828 tcnt += ret;
829 tempfree(x, "");
832 fmt[tcnt] = '\0';
834 switch (*s) {
835 case 'f': case 'e': case 'g': case 'E': case 'G':
836 flag = 1;
837 break;
838 case 'd': case 'i':
839 flag = 2;
840 if (*(s-1) == 'l')
841 break;
842 fmt[tcnt - 1] = 'l';
843 expand_buf(&fmt, &fmtsize, tcnt);
844 fmt[tcnt++] = 'd';
845 fmt[tcnt] = '\0';
846 break;
847 case 'o': case 'x': case 'X': case 'u':
848 flag = *(s-1) == 'l' ? 2 : 3;
849 break;
850 case 's':
851 flag = 4;
852 break;
853 case 'c':
854 flag = 5;
855 break;
856 default:
857 flag = 0;
858 break;
860 if (flag == 0) {
861 len = strlen((char *)fmt);
862 expand_buf(&buf, &bufsize, cnt + len);
863 (void) memcpy(&buf[cnt], fmt, len);
864 cnt += len;
865 buf[cnt] = '\0';
866 continue;
868 if (a == NULL) {
869 ERROR
870 "not enough args in printf(%s) or sprintf(%s)", os, os FATAL;
872 x = execute(a);
873 a = a->nnext;
874 for (;;) {
875 /* make sure we have at least 1 byte space */
876 expand_buf(&buf, &bufsize, cnt + 1);
877 len = bufsize - cnt;
878 switch (flag) {
879 case 1:
880 /*LINTED*/
881 ret = snprintf((char *)&buf[cnt], len,
882 (char *)fmt, getfval(x));
883 break;
884 case 2:
885 /*LINTED*/
886 ret = snprintf((char *)&buf[cnt], len,
887 (char *)fmt, (long)getfval(x));
888 break;
889 case 3:
890 /*LINTED*/
891 ret = snprintf((char *)&buf[cnt], len,
892 (char *)fmt, (int)getfval(x));
893 break;
894 case 4:
895 /*LINTED*/
896 ret = snprintf((char *)&buf[cnt], len,
897 (char *)fmt, getsval(x));
898 break;
899 case 5:
900 if (isnum(x)) {
901 /*LINTED*/
902 ret = snprintf((char *)&buf[cnt], len,
903 (char *)fmt, (int)getfval(x));
904 } else {
905 /*LINTED*/
906 ret = snprintf((char *)&buf[cnt], len,
907 (char *)fmt, getsval(x)[0]);
909 break;
910 default:
911 ret = 0;
913 if (ret < len)
914 break;
915 expand_buf(&buf, &bufsize, cnt + ret);
917 tempfree(x, "");
918 cnt += ret;
919 s++;
921 buf[cnt] = '\0';
922 for (; a; a = a->nnext) /* evaluate any remaining args */
923 (void) execute(a);
924 *bufp = tostring(buf);
925 free(buf);
926 free(fmt);
929 /*ARGSUSED*/
930 Cell *
931 a_sprintf(Node **a, int n)
933 register Cell *x;
934 register Node *y;
935 uchar *buf;
937 y = a[0]->nnext;
938 x = execute(a[0]);
939 format(&buf, getsval(x), y);
940 tempfree(x, "");
941 x = gettemp("");
942 x->sval = buf;
943 x->tval = STR;
944 return (x);
947 /*ARGSUSED*/
948 Cell *
949 aprintf(Node **a, int n)
951 FILE *fp;
952 register Cell *x;
953 register Node *y;
954 uchar *buf;
956 y = a[0]->nnext;
957 x = execute(a[0]);
958 format(&buf, getsval(x), y);
959 tempfree(x, "");
960 if (a[1] == NULL)
961 (void) fputs((char *)buf, stdout);
962 else {
963 fp = redirect((int)a[1], a[2]);
964 (void) fputs((char *)buf, fp);
965 (void) fflush(fp);
967 free(buf);
968 return (true);
971 Cell *
972 arith(Node **a, int n)
974 Awkfloat i, j;
975 double v;
976 register Cell *x, *y, *z;
978 x = execute(a[0]);
979 i = getfval(x);
980 tempfree(x, "");
981 if (n != UMINUS) {
982 y = execute(a[1]);
983 j = getfval(y);
984 tempfree(y, "");
986 z = gettemp("");
987 switch (n) {
988 case ADD:
989 i += j;
990 break;
991 case MINUS:
992 i -= j;
993 break;
994 case MULT:
995 i *= j;
996 break;
997 case DIVIDE:
998 if (j == 0)
999 ERROR "division by zero" FATAL;
1000 i /= j;
1001 break;
1002 case MOD:
1003 if (j == 0)
1004 ERROR "division by zero in mod" FATAL;
1005 (void) modf(i/j, &v);
1006 i = i - j * v;
1007 break;
1008 case UMINUS:
1009 i = -i;
1010 break;
1011 case POWER:
1012 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1013 i = ipow(i, (int)j);
1014 else
1015 i = errcheck(pow(i, j), "pow");
1016 break;
1017 default: /* can't happen */
1018 ERROR "illegal arithmetic operator %d", n FATAL;
1020 (void) setfval(z, i);
1021 return (z);
1024 static double
1025 ipow(double x, int n)
1027 double v;
1029 if (n <= 0)
1030 return (1.0);
1031 v = ipow(x, n/2);
1032 if (n % 2 == 0)
1033 return (v * v);
1034 else
1035 return (x * v * v);
1038 Cell *
1039 incrdecr(Node **a, int n)
1041 register Cell *x, *z;
1042 register int k;
1043 Awkfloat xf;
1045 x = execute(a[0]);
1046 xf = getfval(x);
1047 k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1048 if (n == PREINCR || n == PREDECR) {
1049 (void) setfval(x, xf + k);
1050 return (x);
1052 z = gettemp("");
1053 (void) setfval(z, xf);
1054 (void) setfval(x, xf + k);
1055 tempfree(x, "");
1056 return (z);
1059 Cell *
1060 assign(Node **a, int n)
1062 register Cell *x, *y;
1063 Awkfloat xf, yf;
1064 double v;
1066 y = execute(a[1]);
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);
1072 x->tval |= NUM;
1073 } else if (y->tval & STR)
1074 (void) setsval(x, getsval(y));
1075 else if (y->tval & NUM)
1076 (void) setfval(x, getfval(y));
1077 else
1078 funnyvar(y, "read value of");
1079 tempfree(y, "");
1080 return (x);
1082 xf = getfval(x);
1083 yf = getfval(y);
1084 switch (n) {
1085 case ADDEQ:
1086 xf += yf;
1087 break;
1088 case SUBEQ:
1089 xf -= yf;
1090 break;
1091 case MULTEQ:
1092 xf *= yf;
1093 break;
1094 case DIVEQ:
1095 if (yf == 0)
1096 ERROR "division by zero in /=" FATAL;
1097 xf /= yf;
1098 break;
1099 case MODEQ:
1100 if (yf == 0)
1101 ERROR "division by zero in %%=" FATAL;
1102 (void) modf(xf/yf, &v);
1103 xf = xf - yf * v;
1104 break;
1105 case POWEQ:
1106 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1107 xf = ipow(xf, (int)yf);
1108 else
1109 xf = errcheck(pow(xf, yf), "pow");
1110 break;
1111 default:
1112 ERROR "illegal assignment operator %d", n FATAL;
1113 break;
1115 tempfree(y, "");
1116 (void) setfval(x, xf);
1117 return (x);
1120 /*ARGSUSED*/
1121 Cell *
1122 cat(Node **a, int q)
1124 register Cell *x, *y, *z;
1125 register int n1, n2;
1126 register uchar *s;
1128 x = execute(a[0]);
1129 y = execute(a[1]);
1130 (void) getsval(x);
1131 (void) getsval(y);
1132 n1 = strlen((char *)x->sval);
1133 n2 = strlen((char *)y->sval);
1134 s = (uchar *)malloc(n1 + n2 + 1);
1135 if (s == NULL) {
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);
1141 tempfree(y, "");
1142 z = gettemp("");
1143 z->sval = s;
1144 z->tval = STR;
1145 tempfree(x, "");
1146 return (z);
1149 /*ARGSUSED*/
1150 Cell *
1151 pastat(Node **a, int n)
1153 register Cell *x;
1155 if (a[0] == 0)
1156 x = execute(a[1]);
1157 else {
1158 x = execute(a[0]);
1159 if (istrue(x)) {
1160 tempfree(x, "");
1161 x = execute(a[1]);
1164 return (x);
1167 /*ARGSUSED*/
1168 Cell *
1169 dopa2(Node **a, int n)
1171 Cell *x;
1172 int pair;
1173 static int *pairstack = NULL;
1175 if (!pairstack) {
1176 /* first time */
1177 dprintf(("paircnt: %d\n", paircnt));
1178 pairstack = (int *)malloc(sizeof (int) * paircnt);
1179 if (!pairstack)
1180 ERROR "out of space in dopa2" FATAL;
1181 (void) memset(pairstack, 0, sizeof (int) * paircnt);
1184 pair = (int)a[3];
1185 if (pairstack[pair] == 0) {
1186 x = execute(a[0]);
1187 if (istrue(x))
1188 pairstack[pair] = 1;
1189 tempfree(x, "");
1191 if (pairstack[pair] == 1) {
1192 x = execute(a[1]);
1193 if (istrue(x))
1194 pairstack[pair] = 0;
1195 tempfree(x, "");
1196 x = execute(a[2]);
1197 return (x);
1199 return (false);
1202 /*ARGSUSED*/
1203 Cell *
1204 split(Node **a, int nnn)
1206 Cell *x, *y, *ap;
1207 register uchar *s;
1208 register int sep;
1209 uchar *t, temp, num[11], *fs;
1210 int n, tempstat;
1212 y = execute(a[0]); /* source string */
1213 s = getsval(y);
1214 if (a[2] == 0) /* fs string */
1215 fs = *FS;
1216 else if ((int)a[3] == STRING) { /* split(str,arr,"string") */
1217 x = execute(a[2]);
1218 fs = getsval(x);
1219 } else if ((int)a[3] == REGEXPR)
1220 fs = (uchar *)"(regexpr)"; /* split(str,arr,/regexpr/) */
1221 else
1222 ERROR "illegal type of split()" FATAL;
1223 sep = *fs;
1224 ap = execute(a[1]); /* array name */
1225 freesymtab(ap);
1226 dprintf(("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs));
1227 ap->tval &= ~STR;
1228 ap->tval |= ARR;
1229 ap->sval = (uchar *)makesymtab(NSYMTAB);
1231 n = 0;
1232 if (*s != '\0' && strlen((char *)fs) > 1 || (int)a[3] == REGEXPR) {
1233 /* reg expr */
1234 fa *pfa;
1235 if ((int)a[3] == REGEXPR) { /* it's ready already */
1236 pfa = (fa *)a[2];
1237 } else {
1238 pfa = makedfa(fs, 1);
1240 if (nematch(pfa, s)) {
1241 tempstat = pfa->initstat;
1242 pfa->initstat = 2;
1243 do {
1244 n++;
1245 (void) sprintf((char *)num, "%d", n);
1246 temp = *patbeg;
1247 *patbeg = '\0';
1248 if (is_number(s)) {
1249 (void) setsymtab(num, s,
1250 atof((char *)s),
1251 /*LINTED align*/
1252 STR|NUM, (Array *)ap->sval);
1253 } else {
1254 (void) setsymtab(num, s, 0.0,
1255 /*LINTED align*/
1256 STR, (Array *)ap->sval);
1258 *patbeg = temp;
1259 s = patbeg + patlen;
1260 if (*(patbeg+patlen-1) == 0 || *s == 0) {
1261 n++;
1262 (void) sprintf((char *)num, "%d", n);
1263 (void) setsymtab(num, (uchar *)"", 0.0,
1264 /*LINTED align*/
1265 STR, (Array *)ap->sval);
1266 pfa->initstat = tempstat;
1267 goto spdone;
1269 } while (nematch(pfa, s));
1271 n++;
1272 (void) sprintf((char *)num, "%d", n);
1273 if (is_number(s)) {
1274 (void) setsymtab(num, s, atof((char *)s),
1275 /*LINTED align*/
1276 STR|NUM, (Array *)ap->sval);
1277 } else {
1278 /*LINTED align*/
1279 (void) setsymtab(num, s, 0.0, STR, (Array *)ap->sval);
1281 spdone:
1282 pfa = NULL;
1283 } else if (sep == ' ') {
1284 for (n = 0; ; ) {
1285 while (*s == ' ' || *s == '\t' || *s == '\n')
1286 s++;
1287 if (*s == 0)
1288 break;
1289 n++;
1290 t = s;
1292 s++;
1293 while (*s != ' ' && *s != '\t' &&
1294 *s != '\n' && *s != '\0')
1296 temp = *s;
1297 *s = '\0';
1298 (void) sprintf((char *)num, "%d", n);
1299 if (is_number(t)) {
1300 (void) setsymtab(num, t, atof((char *)t),
1301 /*LINTED align*/
1302 STR|NUM, (Array *)ap->sval);
1303 } else {
1304 (void) setsymtab(num, t, 0.0,
1305 /*LINTED align*/
1306 STR, (Array *)ap->sval);
1308 *s = temp;
1309 if (*s != 0)
1310 s++;
1312 } else if (*s != 0) {
1313 for (;;) {
1314 n++;
1315 t = s;
1316 while (*s != sep && *s != '\n' && *s != '\0')
1317 s++;
1318 temp = *s;
1319 *s = '\0';
1320 (void) sprintf((char *)num, "%d", n);
1321 if (is_number(t)) {
1322 (void) setsymtab(num, t, atof((char *)t),
1323 /*LINTED align*/
1324 STR|NUM, (Array *)ap->sval);
1325 } else {
1326 (void) setsymtab(num, t, 0.0,
1327 /*LINTED align*/
1328 STR, (Array *)ap->sval);
1330 *s = temp;
1331 if (*s++ == 0)
1332 break;
1335 tempfree(ap, "");
1336 tempfree(y, "");
1337 if (a[2] != 0 && (int)a[3] == STRING)
1338 tempfree(x, "");
1339 x = gettemp("");
1340 x->tval = NUM;
1341 x->fval = n;
1342 return (x);
1345 /*ARGSUSED*/
1346 Cell *
1347 condexpr(Node **a, int n)
1349 register Cell *x;
1351 x = execute(a[0]);
1352 if (istrue(x)) {
1353 tempfree(x, "");
1354 x = execute(a[1]);
1355 } else {
1356 tempfree(x, "");
1357 x = execute(a[2]);
1359 return (x);
1362 /*ARGSUSED*/
1363 Cell *
1364 ifstat(Node **a, int n)
1366 register Cell *x;
1368 x = execute(a[0]);
1369 if (istrue(x)) {
1370 tempfree(x, "");
1371 x = execute(a[1]);
1372 } else if (a[2] != 0) {
1373 tempfree(x, "");
1374 x = execute(a[2]);
1376 return (x);
1379 /*ARGSUSED*/
1380 Cell *
1381 whilestat(Node **a, int n)
1383 register Cell *x;
1385 for (;;) {
1386 x = execute(a[0]);
1387 if (!istrue(x))
1388 return (x);
1389 tempfree(x, "");
1390 x = execute(a[1]);
1391 if (isbreak(x)) {
1392 x = true;
1393 return (x);
1395 if (isnext(x) || isexit(x) || isret(x))
1396 return (x);
1397 tempfree(x, "");
1401 /*ARGSUSED*/
1402 Cell *
1403 dostat(Node **a, int n)
1405 register Cell *x;
1407 for (;;) {
1408 x = execute(a[0]);
1409 if (isbreak(x))
1410 return (true);
1411 if (isnext(x) || isexit(x) || isret(x))
1412 return (x);
1413 tempfree(x, "");
1414 x = execute(a[1]);
1415 if (!istrue(x))
1416 return (x);
1417 tempfree(x, "");
1421 /*ARGSUSED*/
1422 Cell *
1423 forstat(Node **a, int n)
1425 register Cell *x;
1427 x = execute(a[0]);
1428 tempfree(x, "");
1429 for (;;) {
1430 if (a[1] != 0) {
1431 x = execute(a[1]);
1432 if (!istrue(x))
1433 return (x);
1434 else
1435 tempfree(x, "");
1437 x = execute(a[3]);
1438 if (isbreak(x)) /* turn off break */
1439 return (true);
1440 if (isnext(x) || isexit(x) || isret(x))
1441 return (x);
1442 tempfree(x, "");
1443 x = execute(a[2]);
1444 tempfree(x, "");
1448 /*ARGSUSED*/
1449 Cell *
1450 instat(Node **a, int n)
1452 register Cell *x, *vp, *arrayp, *cp, *ncp;
1453 Array *tp;
1454 int i;
1456 vp = execute(a[0]);
1457 arrayp = execute(a[1]);
1458 if (!isarr(arrayp))
1459 ERROR "%s is not an array", arrayp->nval FATAL;
1460 /*LINTED align*/
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);
1466 ncp = cp->cnext;
1467 x = execute(a[2]);
1468 if (isbreak(x)) {
1469 tempfree(vp, "");
1470 return (true);
1472 if (isnext(x) || isexit(x) || isret(x)) {
1473 tempfree(vp, "");
1474 return (x);
1476 tempfree(x, "");
1479 return (true);
1482 /*ARGSUSED*/
1483 Cell *
1484 bltin(Node **a, int n)
1486 register Cell *x, *y;
1487 Awkfloat u;
1488 register int t;
1489 uchar *p, *buf;
1490 Node *nextarg;
1492 t = (int)a[0];
1493 x = execute(a[1]);
1494 nextarg = a[1]->nnext;
1495 switch (t) {
1496 case FLENGTH:
1497 u = (Awkfloat)strlen((char *)getsval(x)); break;
1498 case FLOG:
1499 u = errcheck(log(getfval(x)), "log"); break;
1500 case FINT:
1501 (void) modf(getfval(x), &u); break;
1502 case FEXP:
1503 u = errcheck(exp(getfval(x)), "exp"); break;
1504 case FSQRT:
1505 u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1506 case FSIN:
1507 u = sin(getfval(x)); break;
1508 case FCOS:
1509 u = cos(getfval(x)); break;
1510 case FATAN:
1511 if (nextarg == 0) {
1512 ERROR "atan2 requires two arguments; returning 1.0"
1513 WARNING;
1514 u = 1.0;
1515 } else {
1516 y = execute(a[1]->nnext);
1517 u = atan2(getfval(x), getfval(y));
1518 tempfree(y, "");
1519 nextarg = nextarg->nnext;
1521 break;
1522 case FSYSTEM:
1523 /* in case something is buffered already */
1524 (void) fflush(stdout);
1525 /* 256 is unix-dep */
1526 u = (Awkfloat)system((char *)getsval(x)) / 256;
1527 break;
1528 case FRAND:
1529 u = (Awkfloat)(rand() % 32767) / 32767.0;
1530 break;
1531 case FSRAND:
1532 if (x->tval & REC) /* no argument provided */
1533 u = time((time_t *)0);
1534 else
1535 u = getfval(x);
1536 srand((int)u); u = (int)u;
1537 break;
1538 case FTOUPPER:
1539 case FTOLOWER:
1540 buf = tostring(getsval(x));
1541 if (t == FTOUPPER) {
1542 for (p = buf; *p; p++)
1543 if (islower(*p))
1544 *p = toupper(*p);
1545 } else {
1546 for (p = buf; *p; p++)
1547 if (isupper(*p))
1548 *p = tolower(*p);
1550 tempfree(x, "");
1551 x = gettemp("");
1552 (void) setsval(x, buf);
1553 free(buf);
1554 return (x);
1555 default: /* can't happen */
1556 ERROR "illegal function type %d", t FATAL;
1557 break;
1559 tempfree(x, "");
1560 x = gettemp("");
1561 (void) setfval(x, u);
1562 if (nextarg != 0) {
1563 ERROR "warning: function has too many arguments" WARNING;
1564 for (; nextarg; nextarg = nextarg->nnext)
1565 (void) execute(nextarg);
1567 return (x);
1570 /*ARGSUSED*/
1571 Cell *
1572 print(Node **a, int n)
1574 register Node *x;
1575 register Cell *y;
1576 FILE *fp;
1578 if (a[1] == 0)
1579 fp = stdout;
1580 else
1581 fp = redirect((int)a[1], a[2]);
1582 for (x = a[0]; x != NULL; x = x->nnext) {
1583 y = execute(x);
1584 (void) fputs((char *)getsval(y), fp);
1585 tempfree(y, "");
1586 if (x->nnext == NULL)
1587 (void) fputs((char *)*ORS, fp);
1588 else
1589 (void) fputs((char *)*OFS, fp);
1591 if (a[1] != 0)
1592 (void) fflush(fp);
1593 return (true);
1596 /*ARGSUSED*/
1597 Cell *
1598 nullproc(Node **a, int n)
1600 return (0);
1603 struct {
1604 FILE *fp;
1605 uchar *fname;
1606 int mode; /* '|', 'a', 'w' */
1607 } files[FOPEN_MAX];
1609 static FILE *
1610 redirect(int a, Node *b)
1612 FILE *fp;
1613 Cell *x;
1614 uchar *fname;
1616 x = execute(b);
1617 fname = getsval(x);
1618 fp = openfile(a, fname);
1619 if (fp == NULL)
1620 ERROR "can't open file %s", fname FATAL;
1621 tempfree(x, "");
1622 return (fp);
1625 static FILE *
1626 openfile(int a, uchar *s)
1628 register int i, m;
1629 register FILE *fp;
1631 if (*s == '\0')
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)
1644 break;
1646 if (i >= FOPEN_MAX)
1647 ERROR "%s makes too many open files", s FATAL;
1648 (void) fflush(stdout); /* force a semblance of order */
1649 m = a;
1650 if (a == GT) {
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;
1664 if (fp != NULL) {
1665 files[i].fname = tostring(s);
1666 files[i].fp = fp;
1667 files[i].mode = m;
1669 return (fp);
1672 /*ARGSUSED*/
1673 Cell *
1674 closefile(Node **a, int n)
1676 register Cell *x;
1677 int i, stat;
1679 x = execute(a[0]);
1680 (void) getsval(x);
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);
1690 else
1691 stat = fclose(files[i].fp);
1692 if (stat == EOF) {
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;
1699 files[i].fp = NULL;
1702 tempfree(x, "close");
1703 return (true);
1706 static void
1707 closeall(void)
1709 int i, stat;
1711 for (i = 0; i < FOPEN_MAX; i++) {
1712 if (files[i].fp) {
1713 if (ferror(files[i].fp)) {
1714 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);
1719 else
1720 stat = fclose(files[i].fp);
1721 if (stat == EOF) {
1722 ERROR "i/o error occurred while closing %s",
1723 files[i].fname WARNING;
1729 /*ARGSUSED*/
1730 Cell *
1731 sub(Node **a, int nnn)
1733 register uchar *sptr;
1734 register Cell *x, *y, *result;
1735 uchar *buf, *t;
1736 fa *pfa;
1737 size_t bsize, cnt, len;
1739 x = execute(a[3]); /* target string */
1740 t = getsval(x);
1741 if (a[0] == 0)
1742 pfa = (fa *)a[1]; /* regular expression */
1743 else {
1744 y = execute(a[1]);
1745 pfa = makedfa(getsval(y), 1);
1746 tempfree(y, "");
1748 y = execute(a[2]); /* replacement string */
1749 result = false;
1750 if (pmatch(pfa, t)) {
1751 init_buf(&buf, &bsize, LINE_INCR);
1752 cnt = 0;
1753 sptr = t;
1754 len = patbeg - sptr;
1755 if (len > 0) {
1756 expand_buf(&buf, &bsize, cnt + len);
1757 (void) memcpy(buf, sptr, len);
1758 cnt += len;
1760 sptr = getsval(y);
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);
1769 sptr++;
1770 (void) memcpy(&buf[cnt], patbeg, patlen);
1771 cnt += patlen;
1772 } else {
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);
1781 cnt += len;
1783 buf[cnt] = '\0';
1784 (void) setsval(x, buf);
1785 free(buf);
1786 result = true;
1788 tempfree(x, "");
1789 tempfree(y, "");
1790 return (result);
1793 /*ARGSUSED*/
1794 Cell *
1795 gsub(Node **a, int nnn)
1797 register Cell *x, *y;
1798 register uchar *rptr, *sptr, *t;
1799 uchar *buf;
1800 register fa *pfa;
1801 int mflag, tempstat, num;
1802 size_t bsize, cnt, len;
1804 mflag = 0; /* if mflag == 0, can replace empty string */
1805 num = 0;
1806 x = execute(a[3]); /* target string */
1807 t = getsval(x);
1808 if (a[0] == 0)
1809 pfa = (fa *) a[1]; /* regular expression */
1810 else {
1811 y = execute(a[1]);
1812 pfa = makedfa(getsval(y), 1);
1813 tempfree(y, "");
1815 y = execute(a[2]); /* replacement string */
1816 if (pmatch(pfa, t)) {
1817 tempstat = pfa->initstat;
1818 pfa->initstat = 2;
1819 init_buf(&buf, &bsize, LINE_INCR);
1820 rptr = getsval(y);
1821 cnt = 0;
1822 do {
1823 if (patlen == 0 && *patbeg != 0) {
1824 /* matched empty string */
1825 if (mflag == 0) { /* can replace empty */
1826 num++;
1827 sptr = rptr;
1828 while (*sptr != 0) {
1829 expand_buf(&buf, &bsize, cnt);
1830 if (*sptr == '\\' &&
1831 (*(sptr+1) == '&' ||
1832 *(sptr+1) == '\\')) {
1833 sptr++;
1834 buf[cnt++] = *sptr++;
1835 } else if (*sptr == '&') {
1836 expand_buf(&buf,
1837 &bsize,
1838 cnt + patlen);
1839 sptr++;
1840 (void) memcpy(&buf[cnt],
1841 patbeg, patlen);
1842 cnt += patlen;
1843 } else {
1844 buf[cnt++] = *sptr++;
1848 if (*t == 0) /* at end */
1849 goto done;
1850 expand_buf(&buf, &bsize, cnt);
1851 buf[cnt++] = *t++;
1852 mflag = 0;
1853 } else { /* matched nonempty string */
1854 num++;
1855 sptr = t;
1856 len = patbeg - sptr;
1857 if (len > 0) {
1858 expand_buf(&buf, &bsize, cnt + len);
1859 (void) memcpy(&buf[cnt], sptr, len);
1860 cnt += len;
1862 sptr = rptr;
1863 while (*sptr != 0) {
1864 expand_buf(&buf, &bsize, cnt);
1865 if (*sptr == '\\' &&
1866 (*(sptr+1) == '&' ||
1867 *(sptr+1) == '\\')) {
1868 sptr++;
1869 buf[cnt++] = *sptr++;
1870 } else if (*sptr == '&') {
1871 expand_buf(&buf, &bsize,
1872 cnt + patlen);
1873 sptr++;
1874 (void) memcpy(&buf[cnt],
1875 patbeg, patlen);
1876 cnt += patlen;
1877 } else {
1878 buf[cnt++] = *sptr++;
1881 t = patbeg + patlen;
1882 if ((*(t-1) == 0) || (*t == 0))
1883 goto done;
1884 mflag = 1;
1886 } while (pmatch(pfa, t));
1887 sptr = t;
1888 len = strlen((char *)sptr);
1889 expand_buf(&buf, &bsize, len + cnt);
1890 (void) memcpy(&buf[cnt], sptr, len);
1891 cnt += len;
1892 done:
1893 buf[cnt] = '\0';
1894 (void) setsval(x, buf);
1895 free(buf);
1896 pfa->initstat = tempstat;
1898 tempfree(x, "");
1899 tempfree(y, "");
1900 x = gettemp("");
1901 x->tval = NUM;
1902 x->fval = num;
1903 return (x);