Annotation of src/usr.bin/awk/run.c, Revision 1.24
1.24 ! millert 1: /* $OpenBSD: run.c,v 1.23 2003/08/06 21:08:07 millert Exp $ */
1.1 tholo 2: /****************************************************************
1.13 kstailey 3: Copyright (C) Lucent Technologies 1997
1.1 tholo 4: All Rights Reserved
5:
6: Permission to use, copy, modify, and distribute this software and
7: its documentation for any purpose and without fee is hereby
8: granted, provided that the above copyright notice appear in all
9: copies and that both that the copyright notice and this
10: permission notice and warranty disclaimer appear in supporting
1.13 kstailey 11: documentation, and that the name Lucent Technologies or any of
12: its entities not be used in advertising or publicity pertaining
13: to distribution of the software without specific, written prior
14: permission.
15:
16: LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17: INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
18: IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
19: SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20: WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
21: IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
23: THIS SOFTWARE.
1.1 tholo 24: ****************************************************************/
25:
26: #define DEBUG
27: #include <stdio.h>
28: #include <ctype.h>
29: #include <setjmp.h>
30: #include <math.h>
31: #include <string.h>
32: #include <stdlib.h>
33: #include <time.h>
34: #include "awk.h"
1.13 kstailey 35: #include "ytab.h"
1.1 tholo 36:
37: #define tempfree(x) if (istemp(x)) tfree(x); else
38:
39: /*
40: #undef tempfree
41:
42: void tempfree(Cell *p) {
43: if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
1.16 millert 44: WARNING("bad csub %d in Cell %d %s",
45: p->csub, p->ctype, p->sval);
1.1 tholo 46: }
47: if (istemp(p))
48: tfree(p);
49: }
50: */
51:
52: #ifdef _NFILE
53: #ifndef FOPEN_MAX
54: #define FOPEN_MAX _NFILE
55: #endif
56: #endif
57:
58: #ifndef FOPEN_MAX
59: #define FOPEN_MAX 40 /* max number of open files */
60: #endif
61:
62: #ifndef RAND_MAX
63: #define RAND_MAX 32767 /* all that ansi guarantees */
64: #endif
65:
66: jmp_buf env;
1.24 ! millert 67: int use_arc4 = 1;
1.13 kstailey 68: extern int pairstack[];
1.1 tholo 69:
70: Node *winner = NULL; /* root of parse tree */
71: Cell *tmps; /* free temporary cells for execution */
72:
73: static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
1.15 millert 74: Cell *True = &truecell;
1.1 tholo 75: static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
1.15 millert 76: Cell *False = &falsecell;
1.1 tholo 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;
1.13 kstailey 89: static Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
1.1 tholo 90:
91: Node *curnode = NULL; /* the node being executed, for debugging */
1.22 deraadt 92:
93: void stdinit(void);
94: void flush_all(void);
95:
1.1 tholo 96:
1.13 kstailey 97: /* buffer memory management */
98: int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
1.18 millert 99: const char *whatrtn)
1.13 kstailey 100: /* pbuf: address of pointer to buffer being managed
101: * psiz: address of buffer size variable
102: * minlen: minimum length of buffer needed
103: * quantum: buffer size quantum
104: * pbptr: address of movable pointer into buffer, or 0 if none
105: * whatrtn: name of the calling routine if failure should cause fatal error
106: *
107: * return 0 for realloc failure, !=0 for success
108: */
109: {
110: if (minlen > *psiz) {
111: char *tbuf;
112: int rminlen = quantum ? minlen % quantum : 0;
113: int boff = pbptr ? *pbptr - *pbuf : 0;
114: /* round up to next multiple of quantum */
115: if (rminlen)
116: minlen += quantum - rminlen;
1.15 millert 117: tbuf = (char *) realloc(*pbuf, minlen);
1.13 kstailey 118: if (tbuf == NULL) {
119: if (whatrtn)
1.16 millert 120: FATAL("out of memory in %s", whatrtn);
1.13 kstailey 121: return 0;
122: }
123: *pbuf = tbuf;
124: *psiz = minlen;
125: if (pbptr)
126: *pbptr = tbuf + boff;
127: }
128: return 1;
129: }
130:
1.1 tholo 131: void run(Node *a) /* execution of parse tree starts here */
132: {
1.16 millert 133: extern void stdinit(void);
134:
135: stdinit();
1.1 tholo 136: execute(a);
137: closeall();
138: }
139:
140: Cell *execute(Node *u) /* execute a node of the parse tree */
141: {
142: Cell *(*proc)(Node **, int);
143: Cell *x;
144: Node *a;
145:
146: if (u == NULL)
1.15 millert 147: return(True);
1.1 tholo 148: for (a = u; ; a = a->nnext) {
149: curnode = a;
150: if (isvalue(a)) {
1.2 millert 151: x = (Cell *) (a->narg[0]);
1.13 kstailey 152: if (isfld(x) && !donefld)
1.1 tholo 153: fldbld();
1.13 kstailey 154: else if (isrec(x) && !donerec)
1.1 tholo 155: recbld();
156: return(x);
157: }
158: if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */
1.16 millert 159: FATAL("illegal statement");
1.1 tholo 160: proc = proctab[a->nobj-FIRSTTOKEN];
161: x = (*proc)(a->narg, a->nobj);
1.13 kstailey 162: if (isfld(x) && !donefld)
1.1 tholo 163: fldbld();
1.13 kstailey 164: else if (isrec(x) && !donerec)
1.1 tholo 165: recbld();
166: if (isexpr(a))
167: return(x);
168: if (isjump(x))
169: return(x);
170: if (a->nnext == NULL)
171: return(x);
172: tempfree(x);
173: }
174: }
175:
176:
177: Cell *program(Node **a, int n) /* execute an awk program */
178: { /* a[0] = BEGIN, a[1] = body, a[2] = END */
179: Cell *x;
180:
181: if (setjmp(env) != 0)
182: goto ex;
183: if (a[0]) { /* BEGIN */
184: x = execute(a[0]);
185: if (isexit(x))
1.15 millert 186: return(True);
1.1 tholo 187: if (isjump(x))
1.16 millert 188: FATAL("illegal break, continue, next or nextfile from BEGIN");
1.1 tholo 189: tempfree(x);
190: }
191: if (a[1] || a[2])
1.13 kstailey 192: while (getrec(&record, &recsize, 1) > 0) {
1.1 tholo 193: x = execute(a[1]);
194: if (isexit(x))
195: break;
196: tempfree(x);
197: }
198: ex:
199: if (setjmp(env) != 0) /* handles exit within END */
200: goto ex1;
201: if (a[2]) { /* END */
202: x = execute(a[2]);
203: if (isbreak(x) || isnext(x) || iscont(x))
1.16 millert 204: FATAL("illegal break, continue, next or nextfile from END");
1.1 tholo 205: tempfree(x);
206: }
207: ex1:
1.15 millert 208: return(True);
1.1 tholo 209: }
210:
211: struct Frame { /* stack frame for awk function calls */
212: int nargs; /* number of arguments in this call */
213: Cell *fcncell; /* pointer to Cell for function */
214: Cell **args; /* pointer to array of arguments after execute */
215: Cell *retval; /* return value */
216: };
217:
218: #define NARGS 50 /* max args in a call */
219:
220: struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
221: int nframe = 0; /* number of frames allocated */
222: struct Frame *fp = NULL; /* frame pointer. bottom level unused */
223:
224: Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
225: {
1.13 kstailey 226: static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
1.1 tholo 227: int i, ncall, ndef;
228: Node *x;
1.13 kstailey 229: Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */
230: Cell *y, *z, *fcn;
1.1 tholo 231: char *s;
232:
233: fcn = execute(a[0]); /* the function itself */
234: s = fcn->nval;
1.13 kstailey 235: if (!isfcn(fcn))
1.16 millert 236: FATAL("calling undefined function %s", s);
1.1 tholo 237: if (frame == NULL) {
238: fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
239: if (frame == NULL)
1.16 millert 240: FATAL("out of space for stack frames calling %s", s);
1.1 tholo 241: }
242: for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
243: ncall++;
1.12 millert 244: ndef = (int) fcn->fval; /* args in defn */
1.15 millert 245: dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
1.1 tholo 246: if (ncall > ndef)
1.16 millert 247: WARNING("function %s called with %d args, uses only %d",
248: s, ncall, ndef);
1.1 tholo 249: if (ncall + ndef > NARGS)
1.16 millert 250: FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
1.1 tholo 251: for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */
1.15 millert 252: dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
1.1 tholo 253: y = execute(x);
254: oargs[i] = y;
1.13 kstailey 255: dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
1.18 millert 256: i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval) );
1.13 kstailey 257: if (isfcn(y))
1.16 millert 258: FATAL("can't use function %s as argument in %s", y->nval, s);
1.1 tholo 259: if (isarr(y))
260: args[i] = y; /* arrays by ref */
261: else
262: args[i] = copycell(y);
263: tempfree(y);
264: }
265: for ( ; i < ndef; i++) { /* add null args for ones not provided */
266: args[i] = gettemp();
267: *args[i] = newcopycell;
268: }
269: fp++; /* now ok to up frame */
270: if (fp >= frame + nframe) {
271: int dfp = fp - frame; /* old index */
272: frame = (struct Frame *)
273: realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
274: if (frame == NULL)
1.16 millert 275: FATAL("out of space for stack frames in %s", s);
1.1 tholo 276: fp = frame + dfp;
277: }
278: fp->fcncell = fcn;
279: fp->args = args;
280: fp->nargs = ndef; /* number defined with (excess are locals) */
281: fp->retval = gettemp();
282:
1.15 millert 283: dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
1.1 tholo 284: y = execute((Node *)(fcn->sval)); /* execute body */
1.15 millert 285: dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
1.1 tholo 286:
287: for (i = 0; i < ndef; i++) {
288: Cell *t = fp->args[i];
289: if (isarr(t)) {
290: if (t->csub == CCOPY) {
291: if (i >= ncall) {
292: freesymtab(t);
293: t->csub = CTEMP;
1.14 millert 294: tempfree(t);
1.1 tholo 295: } else {
296: oargs[i]->tval = t->tval;
297: oargs[i]->tval &= ~(STR|NUM|DONTFREE);
298: oargs[i]->sval = t->sval;
299: tempfree(t);
300: }
301: }
302: } else if (t != y) { /* kludge to prevent freeing twice */
303: t->csub = CTEMP;
304: tempfree(t);
305: }
306: }
307: tempfree(fcn);
1.17 millert 308: if (isexit(y) || isnext(y))
1.1 tholo 309: return y;
310: tempfree(y); /* this can free twice! */
311: z = fp->retval; /* return value */
1.13 kstailey 312: dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
1.1 tholo 313: fp--;
314: return(z);
315: }
316:
317: Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
318: {
319: Cell *y;
320:
321: y = gettemp();
322: y->csub = CCOPY; /* prevents freeing until call is over */
1.13 kstailey 323: y->nval = x->nval; /* BUG? */
1.17 millert 324: if (isstr(x))
325: y->sval = tostring(x->sval);
1.1 tholo 326: y->fval = x->fval;
327: y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */
328: /* is DONTFREE right? */
329: return y;
330: }
331:
332: Cell *arg(Node **a, int n) /* nth argument of a function */
333: {
334:
1.15 millert 335: n = ptoi(a[0]); /* argument number, counting from 0 */
1.13 kstailey 336: dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
1.1 tholo 337: if (n+1 > fp->nargs)
1.16 millert 338: FATAL("argument #%d of function %s was not supplied",
339: n+1, fp->fcncell->nval);
1.1 tholo 340: return fp->args[n];
341: }
342:
343: Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
344: {
345: Cell *y;
346:
347: switch (n) {
348: case EXIT:
349: if (a[0] != NULL) {
350: y = execute(a[0]);
1.14 millert 351: errorflag = (int) getfval(y);
1.1 tholo 352: tempfree(y);
353: }
354: longjmp(env, 1);
355: case RETURN:
356: if (a[0] != NULL) {
357: y = execute(a[0]);
358: if ((y->tval & (STR|NUM)) == (STR|NUM)) {
359: setsval(fp->retval, getsval(y));
360: fp->retval->fval = getfval(y);
361: fp->retval->tval |= NUM;
362: }
363: else if (y->tval & STR)
364: setsval(fp->retval, getsval(y));
365: else if (y->tval & NUM)
366: setfval(fp->retval, getfval(y));
367: else /* can't happen */
1.16 millert 368: FATAL("bad type variable %d", y->tval);
1.1 tholo 369: tempfree(y);
370: }
371: return(jret);
372: case NEXT:
373: return(jnext);
374: case NEXTFILE:
375: nextfile();
376: return(jnextfile);
377: case BREAK:
378: return(jbreak);
379: case CONTINUE:
380: return(jcont);
381: default: /* can't happen */
1.16 millert 382: FATAL("illegal jump type %d", n);
1.1 tholo 383: }
384: return 0; /* not reached */
385: }
386:
387: Cell *getline(Node **a, int n) /* get next line from specific input */
388: { /* a[0] is variable, a[1] is operator, a[2] is filename */
389: Cell *r, *x;
1.13 kstailey 390: extern Cell **fldtab;
1.1 tholo 391: FILE *fp;
1.13 kstailey 392: char *buf;
393: int bufsize = recsize;
1.15 millert 394: int mode;
1.13 kstailey 395:
396: if ((buf = (char *) malloc(bufsize)) == NULL)
1.16 millert 397: FATAL("out of memory in getline");
1.1 tholo 398:
399: fflush(stdout); /* in case someone is waiting for a prompt */
400: r = gettemp();
401: if (a[1] != NULL) { /* getline < file */
402: x = execute(a[2]); /* filename */
1.15 millert 403: mode = ptoi(a[1]);
404: if (mode == '|') /* input pipe */
405: mode = LE; /* arbitrary flag */
406: fp = openfile(mode, getsval(x));
1.1 tholo 407: tempfree(x);
408: if (fp == NULL)
409: n = -1;
410: else
1.13 kstailey 411: n = readrec(&buf, &bufsize, fp);
1.1 tholo 412: if (n <= 0) {
413: ;
414: } else if (a[0] != NULL) { /* getline var <file */
1.13 kstailey 415: x = execute(a[0]);
416: setsval(x, buf);
417: tempfree(x);
1.1 tholo 418: } else { /* getline <file */
1.13 kstailey 419: setsval(fldtab[0], buf);
1.14 millert 420: if (is_number(fldtab[0]->sval)) {
1.13 kstailey 421: fldtab[0]->fval = atof(fldtab[0]->sval);
422: fldtab[0]->tval |= NUM;
1.1 tholo 423: }
424: }
425: } else { /* bare getline; use current input */
426: if (a[0] == NULL) /* getline */
1.13 kstailey 427: n = getrec(&record, &recsize, 1);
1.1 tholo 428: else { /* getline var */
1.13 kstailey 429: n = getrec(&buf, &bufsize, 0);
430: x = execute(a[0]);
431: setsval(x, buf);
432: tempfree(x);
1.1 tholo 433: }
434: }
435: setfval(r, (Awkfloat) n);
1.13 kstailey 436: free(buf);
1.1 tholo 437: return r;
438: }
439:
440: Cell *getnf(Node **a, int n) /* get NF */
441: {
442: if (donefld == 0)
443: fldbld();
444: return (Cell *) a[0];
445: }
446:
447: Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
448: {
449: Cell *x, *y, *z;
450: char *s;
451: Node *np;
1.13 kstailey 452: char *buf;
453: int bufsz = recsize;
454: int nsub = strlen(*SUBSEP);
455:
1.15 millert 456: if ((buf = (char *) malloc(bufsz)) == NULL)
1.16 millert 457: FATAL("out of memory in array");
1.1 tholo 458:
459: x = execute(a[0]); /* Cell* for symbol table */
460: buf[0] = 0;
461: for (np = a[1]; np; np = np->nnext) {
462: y = execute(np); /* subscript */
463: s = getsval(y);
1.13 kstailey 464: if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
1.16 millert 465: FATAL("out of memory for %s[%s...]", x->nval, buf);
1.20 pvalchev 466: strlcat(buf, s, bufsz);
1.1 tholo 467: if (np->nnext)
1.20 pvalchev 468: strlcat(buf, *SUBSEP, bufsz);
1.1 tholo 469: tempfree(y);
470: }
471: if (!isarr(x)) {
1.18 millert 472: dprintf( ("making %s into an array\n", NN(x->nval)) );
1.1 tholo 473: if (freeable(x))
474: xfree(x->sval);
475: x->tval &= ~(STR|NUM|DONTFREE);
476: x->tval |= ARR;
477: x->sval = (char *) makesymtab(NSYMTAB);
478: }
479: z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
480: z->ctype = OCELL;
481: z->csub = CVAR;
482: tempfree(x);
1.13 kstailey 483: free(buf);
1.1 tholo 484: return(z);
485: }
486:
1.14 millert 487: Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
1.1 tholo 488: {
489: Cell *x, *y;
490: Node *np;
1.13 kstailey 491: char *s;
492: int nsub = strlen(*SUBSEP);
1.1 tholo 493:
494: x = execute(a[0]); /* Cell* for symbol table */
495: if (!isarr(x))
1.15 millert 496: return True;
1.1 tholo 497: if (a[1] == 0) { /* delete the elements, not the table */
498: freesymtab(x);
499: x->tval &= ~STR;
500: x->tval |= ARR;
501: x->sval = (char *) makesymtab(NSYMTAB);
502: } else {
1.13 kstailey 503: int bufsz = recsize;
504: char *buf;
1.15 millert 505: if ((buf = (char *) malloc(bufsz)) == NULL)
1.16 millert 506: FATAL("out of memory in adelete");
1.1 tholo 507: buf[0] = 0;
508: for (np = a[1]; np; np = np->nnext) {
509: y = execute(np); /* subscript */
510: s = getsval(y);
1.13 kstailey 511: if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
1.16 millert 512: FATAL("out of memory deleting %s[%s...]", x->nval, buf);
1.20 pvalchev 513: strlcat(buf, s, bufsz);
1.1 tholo 514: if (np->nnext)
1.20 pvalchev 515: strlcat(buf, *SUBSEP, bufsz);
1.1 tholo 516: tempfree(y);
517: }
518: freeelem(x, buf);
1.13 kstailey 519: free(buf);
1.1 tholo 520: }
521: tempfree(x);
1.15 millert 522: return True;
1.1 tholo 523: }
524:
525: Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
526: {
527: Cell *x, *ap, *k;
528: Node *p;
1.13 kstailey 529: char *buf;
1.1 tholo 530: char *s;
1.13 kstailey 531: int bufsz = recsize;
532: int nsub = strlen(*SUBSEP);
1.1 tholo 533:
534: ap = execute(a[1]); /* array name */
535: if (!isarr(ap)) {
1.13 kstailey 536: dprintf( ("making %s into an array\n", ap->nval) );
1.1 tholo 537: if (freeable(ap))
538: xfree(ap->sval);
539: ap->tval &= ~(STR|NUM|DONTFREE);
540: ap->tval |= ARR;
541: ap->sval = (char *) makesymtab(NSYMTAB);
542: }
1.15 millert 543: if ((buf = (char *) malloc(bufsz)) == NULL) {
1.16 millert 544: FATAL("out of memory in intest");
1.13 kstailey 545: }
1.1 tholo 546: buf[0] = 0;
547: for (p = a[0]; p; p = p->nnext) {
548: x = execute(p); /* expr */
549: s = getsval(x);
1.13 kstailey 550: if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
1.16 millert 551: FATAL("out of memory deleting %s[%s...]", x->nval, buf);
1.20 pvalchev 552: strlcat(buf, s, bufsz);
1.1 tholo 553: tempfree(x);
554: if (p->nnext)
1.20 pvalchev 555: strlcat(buf, *SUBSEP, bufsz);
1.1 tholo 556: }
557: k = lookup(buf, (Array *) ap->sval);
558: tempfree(ap);
1.13 kstailey 559: free(buf);
1.1 tholo 560: if (k == NULL)
1.15 millert 561: return(False);
1.1 tholo 562: else
1.15 millert 563: return(True);
1.1 tholo 564: }
565:
566:
567: Cell *matchop(Node **a, int n) /* ~ and match() */
568: {
569: Cell *x, *y;
570: char *s, *t;
571: int i;
572: fa *pfa;
1.18 millert 573: int (*mf)(fa *, const char *) = match, mode = 0;
1.1 tholo 574:
575: if (n == MATCHFCN) {
576: mf = pmatch;
577: mode = 1;
578: }
579: x = execute(a[1]); /* a[1] = target text */
580: s = getsval(x);
581: if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */
582: i = (*mf)((fa *) a[2], s);
583: else {
584: y = execute(a[2]); /* a[2] = regular expr */
585: t = getsval(y);
586: pfa = makedfa(t, mode);
587: i = (*mf)(pfa, s);
588: tempfree(y);
589: }
590: tempfree(x);
591: if (n == MATCHFCN) {
592: int start = patbeg - s + 1;
593: if (patlen < 0)
594: start = 0;
595: setfval(rstartloc, (Awkfloat) start);
596: setfval(rlengthloc, (Awkfloat) patlen);
597: x = gettemp();
598: x->tval = NUM;
599: x->fval = start;
600: return x;
601: } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
1.15 millert 602: return(True);
1.1 tholo 603: else
1.15 millert 604: return(False);
1.1 tholo 605: }
606:
607:
608: Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
609: {
610: Cell *x, *y;
611: int i;
612:
613: x = execute(a[0]);
614: i = istrue(x);
615: tempfree(x);
616: switch (n) {
617: case BOR:
1.15 millert 618: if (i) return(True);
1.1 tholo 619: y = execute(a[1]);
620: i = istrue(y);
621: tempfree(y);
1.15 millert 622: if (i) return(True);
623: else return(False);
1.1 tholo 624: case AND:
1.15 millert 625: if ( !i ) return(False);
1.1 tholo 626: y = execute(a[1]);
627: i = istrue(y);
628: tempfree(y);
1.15 millert 629: if (i) return(True);
630: else return(False);
1.1 tholo 631: case NOT:
1.15 millert 632: if (i) return(False);
633: else return(True);
1.1 tholo 634: default: /* can't happen */
1.16 millert 635: FATAL("unknown boolean operator %d", n);
1.1 tholo 636: }
637: return 0; /*NOTREACHED*/
638: }
639:
640: Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
641: {
642: int i;
643: Cell *x, *y;
644: Awkfloat j;
645:
646: x = execute(a[0]);
647: y = execute(a[1]);
648: if (x->tval&NUM && y->tval&NUM) {
649: j = x->fval - y->fval;
650: i = j<0? -1: (j>0? 1: 0);
651: } else {
652: i = strcmp(getsval(x), getsval(y));
653: }
654: tempfree(x);
655: tempfree(y);
656: switch (n) {
1.15 millert 657: case LT: if (i<0) return(True);
658: else return(False);
659: case LE: if (i<=0) return(True);
660: else return(False);
661: case NE: if (i!=0) return(True);
662: else return(False);
663: case EQ: if (i == 0) return(True);
664: else return(False);
665: case GE: if (i>=0) return(True);
666: else return(False);
667: case GT: if (i>0) return(True);
668: else return(False);
1.1 tholo 669: default: /* can't happen */
1.16 millert 670: FATAL("unknown relational operator %d", n);
1.1 tholo 671: }
672: return 0; /*NOTREACHED*/
673: }
674:
675: void tfree(Cell *a) /* free a tempcell */
676: {
1.13 kstailey 677: if (freeable(a)) {
1.18 millert 678: dprintf( ("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval) );
1.1 tholo 679: xfree(a->sval);
1.13 kstailey 680: }
1.1 tholo 681: if (a == tmps)
1.16 millert 682: FATAL("tempcell list is curdled");
1.1 tholo 683: a->cnext = tmps;
684: tmps = a;
685: }
686:
687: Cell *gettemp(void) /* get a tempcell */
688: { int i;
689: Cell *x;
690:
691: if (!tmps) {
692: tmps = (Cell *) calloc(100, sizeof(Cell));
693: if (!tmps)
1.16 millert 694: FATAL("out of space for temporaries");
1.1 tholo 695: for(i = 1; i < 100; i++)
696: tmps[i-1].cnext = &tmps[i];
697: tmps[i-1].cnext = 0;
698: }
699: x = tmps;
700: tmps = x->cnext;
701: *x = tempcell;
702: return(x);
703: }
704:
705: Cell *indirect(Node **a, int n) /* $( a[0] ) */
706: {
707: Cell *x;
708: int m;
709: char *s;
710:
711: x = execute(a[0]);
1.14 millert 712: m = (int) getfval(x);
713: if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */
1.16 millert 714: FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
1.13 kstailey 715: /* BUG: can x->nval ever be null??? */
1.1 tholo 716: tempfree(x);
717: x = fieldadr(m);
1.13 kstailey 718: x->ctype = OCELL; /* BUG? why are these needed? */
1.1 tholo 719: x->csub = CFLD;
720: return(x);
721: }
722:
723: Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
724: {
725: int k, m, n;
726: char *s;
727: int temp;
728: Cell *x, *y, *z = 0;
729:
730: x = execute(a[0]);
731: y = execute(a[1]);
732: if (a[2] != 0)
733: z = execute(a[2]);
734: s = getsval(x);
735: k = strlen(s) + 1;
736: if (k <= 1) {
737: tempfree(x);
738: tempfree(y);
1.17 millert 739: if (a[2] != 0) {
1.1 tholo 740: tempfree(z);
1.17 millert 741: }
1.1 tholo 742: x = gettemp();
743: setsval(x, "");
744: return(x);
745: }
1.14 millert 746: m = (int) getfval(y);
1.1 tholo 747: if (m <= 0)
748: m = 1;
749: else if (m > k)
750: m = k;
751: tempfree(y);
752: if (a[2] != 0) {
1.14 millert 753: n = (int) getfval(z);
1.1 tholo 754: tempfree(z);
755: } else
756: n = k - 1;
757: if (n < 0)
758: n = 0;
759: else if (n > k - m)
760: n = k - m;
1.13 kstailey 761: dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
1.1 tholo 762: y = gettemp();
763: temp = s[n+m-1]; /* with thanks to John Linderman */
764: s[n+m-1] = '\0';
765: setsval(y, s + m - 1);
766: s[n+m-1] = temp;
767: tempfree(x);
768: return(y);
769: }
770:
771: Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
772: {
773: Cell *x, *y, *z;
774: char *s1, *s2, *p1, *p2, *q;
775: Awkfloat v = 0.0;
776:
777: x = execute(a[0]);
778: s1 = getsval(x);
779: y = execute(a[1]);
780: s2 = getsval(y);
781:
782: z = gettemp();
783: for (p1 = s1; *p1 != '\0'; p1++) {
784: for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
785: ;
786: if (*p2 == '\0') {
787: v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
788: break;
789: }
790: }
791: tempfree(x);
792: tempfree(y);
793: setfval(z, v);
794: return(z);
795: }
796:
1.13 kstailey 797: #define MAXNUMSIZE 50
798:
1.18 millert 799: int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */
1.1 tholo 800: {
1.13 kstailey 801: char *fmt;
1.18 millert 802: char *p, *t;
803: const char *os;
1.1 tholo 804: Cell *x;
1.10 kstailey 805: int flag = 0, n;
1.13 kstailey 806: int fmtwd; /* format width */
807: int fmtsz = recsize;
808: char *buf = *pbuf;
809: int bufsize = *pbufsize;
1.1 tholo 810:
811: os = s;
812: p = buf;
1.15 millert 813: if ((fmt = (char *) malloc(fmtsz)) == NULL)
1.16 millert 814: FATAL("out of memory in format()");
1.1 tholo 815: while (*s) {
1.13 kstailey 816: adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
1.1 tholo 817: if (*s != '%') {
818: *p++ = *s++;
819: continue;
820: }
821: if (*(s+1) == '%') {
822: *p++ = '%';
823: s += 2;
824: continue;
825: }
1.13 kstailey 826: /* have to be real careful in case this is a huge number, eg, %100000d */
827: fmtwd = atoi(s+1);
828: if (fmtwd < 0)
829: fmtwd = -fmtwd;
830: adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
831: for (t = fmt; (*t++ = *s) != '\0'; s++) {
832: if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
1.16 millert 833: FATAL("format item %.30s... ran format() out of memory", os);
1.17 millert 834: if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L')
1.1 tholo 835: break; /* the ansi panoply */
836: if (*s == '*') {
837: x = execute(a);
838: a = a->nnext;
1.21 tedu 839: snprintf(t-1, fmt + fmtsz - (t-1), "%d", fmtwd=(int) getfval(x));
1.13 kstailey 840: if (fmtwd < 0)
841: fmtwd = -fmtwd;
842: adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
1.1 tholo 843: t = fmt + strlen(fmt);
844: tempfree(x);
845: }
846: }
847: *t = '\0';
1.13 kstailey 848: if (fmtwd < 0)
849: fmtwd = -fmtwd;
850: adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
851:
1.1 tholo 852: switch (*s) {
853: case 'f': case 'e': case 'g': case 'E': case 'G':
1.18 millert 854: flag = 'f';
1.1 tholo 855: break;
856: case 'd': case 'i':
1.18 millert 857: flag = 'd';
1.1 tholo 858: if(*(s-1) == 'l') break;
859: *(t-1) = 'l';
860: *t = 'd';
861: *++t = '\0';
862: break;
863: case 'o': case 'x': case 'X': case 'u':
1.18 millert 864: flag = *(s-1) == 'l' ? 'd' : 'u';
1.1 tholo 865: break;
866: case 's':
1.18 millert 867: flag = 's';
1.1 tholo 868: break;
869: case 'c':
1.18 millert 870: flag = 'c';
1.1 tholo 871: break;
872: default:
1.16 millert 873: WARNING("weird printf conversion %s", fmt);
1.18 millert 874: flag = '?';
1.1 tholo 875: break;
876: }
877: if (a == NULL)
1.16 millert 878: FATAL("not enough args in printf(%s)", os);
1.1 tholo 879: x = execute(a);
880: a = a->nnext;
1.13 kstailey 881: n = MAXNUMSIZE;
882: if (fmtwd > n)
883: n = fmtwd;
884: adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
1.1 tholo 885: switch (flag) {
1.21 tedu 886: case '?': /* unknown, so dump it too */
887: snprintf(p, buf + bufsize - p, "%s", fmt);
1.13 kstailey 888: t = getsval(x);
889: n = strlen(t);
890: if (fmtwd > n)
891: n = fmtwd;
892: adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
1.5 kstailey 893: p += strlen(p);
1.21 tedu 894: snprintf(p, buf + bufsize - p, "%s", t);
1.1 tholo 895: break;
1.21 tedu 896: case 'f': snprintf(p, buf + bufsize - p, fmt, getfval(x)); break;
897: case 'd': snprintf(p, buf + bufsize - p, fmt, (long) getfval(x)); break;
898: case 'u': snprintf(p, buf + bufsize - p, fmt, (int) getfval(x)); break;
1.18 millert 899: case 's':
1.1 tholo 900: t = getsval(x);
901: n = strlen(t);
1.13 kstailey 902: if (fmtwd > n)
903: n = fmtwd;
904: if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
1.16 millert 905: FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
1.21 tedu 906: snprintf(p, buf + bufsize - p, fmt, t);
1.1 tholo 907: break;
1.18 millert 908: case 'c':
1.13 kstailey 909: if (isnum(x)) {
910: if (getfval(x))
1.21 tedu 911: snprintf(p, buf + bufsize - p, fmt, (int) getfval(x));
1.18 millert 912: else {
913: *p++ = '\0'; /* explicit null byte */
914: *p = '\0'; /* next output will start here */
915: }
1.13 kstailey 916: } else
1.21 tedu 917: snprintf(p, buf + bufsize - p, fmt, getsval(x)[0]);
1.1 tholo 918: break;
1.18 millert 919: default:
920: FATAL("can't happen: bad conversion %c in format()", flag);
1.1 tholo 921: }
922: tempfree(x);
1.5 kstailey 923: p += strlen(p);
1.1 tholo 924: s++;
925: }
926: *p = '\0';
1.13 kstailey 927: free(fmt);
1.1 tholo 928: for ( ; a; a = a->nnext) /* evaluate any remaining args */
929: execute(a);
1.13 kstailey 930: *pbuf = buf;
931: *pbufsize = bufsize;
932: return p - buf;
1.1 tholo 933: }
934:
935: Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
936: {
937: Cell *x;
938: Node *y;
1.13 kstailey 939: char *buf;
940: int bufsz=3*recsize;
1.1 tholo 941:
1.15 millert 942: if ((buf = (char *) malloc(bufsz)) == NULL)
1.16 millert 943: FATAL("out of memory in awksprintf");
1.1 tholo 944: y = a[0]->nnext;
945: x = execute(a[0]);
1.13 kstailey 946: if (format(&buf, &bufsz, getsval(x), y) == -1)
1.16 millert 947: FATAL("sprintf string %.30s... too long. can't happen.", buf);
1.1 tholo 948: tempfree(x);
949: x = gettemp();
1.13 kstailey 950: x->sval = buf;
1.1 tholo 951: x->tval = STR;
952: return(x);
953: }
954:
955: Cell *awkprintf(Node **a, int n) /* printf */
956: { /* a[0] is list of args, starting with format string */
957: /* a[1] is redirection operator, a[2] is redirection file */
958: FILE *fp;
959: Cell *x;
960: Node *y;
1.13 kstailey 961: char *buf;
1.9 kstailey 962: int len;
1.13 kstailey 963: int bufsz=3*recsize;
1.1 tholo 964:
1.15 millert 965: if ((buf = (char *) malloc(bufsz)) == NULL)
1.16 millert 966: FATAL("out of memory in awkprintf");
1.1 tholo 967: y = a[0]->nnext;
968: x = execute(a[0]);
1.13 kstailey 969: if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
1.16 millert 970: FATAL("printf string %.30s... too long. can't happen.", buf);
1.1 tholo 971: tempfree(x);
972: if (a[1] == NULL) {
1.13 kstailey 973: /* fputs(buf, stdout); */
1.9 kstailey 974: fwrite(buf, len, 1, stdout);
1.8 kstailey 975: if (ferror(stdout))
1.16 millert 976: FATAL("write error on stdout");
1.1 tholo 977: } else {
1.15 millert 978: fp = redirect(ptoi(a[1]), a[2]);
1.13 kstailey 979: /* fputs(buf, fp); */
1.9 kstailey 980: fwrite(buf, len, 1, fp);
1.8 kstailey 981: fflush(fp);
982: if (ferror(fp))
1.16 millert 983: FATAL("write error on %s", filename(fp));
1.1 tholo 984: }
1.13 kstailey 985: free(buf);
1.15 millert 986: return(True);
1.1 tholo 987: }
988:
989: Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
990: {
991: Awkfloat i, j = 0;
992: double v;
993: Cell *x, *y, *z;
994:
995: x = execute(a[0]);
996: i = getfval(x);
997: tempfree(x);
998: if (n != UMINUS) {
999: y = execute(a[1]);
1000: j = getfval(y);
1001: tempfree(y);
1002: }
1003: z = gettemp();
1004: switch (n) {
1005: case ADD:
1006: i += j;
1007: break;
1008: case MINUS:
1009: i -= j;
1010: break;
1011: case MULT:
1012: i *= j;
1013: break;
1014: case DIVIDE:
1015: if (j == 0)
1.16 millert 1016: FATAL("division by zero");
1.1 tholo 1017: i /= j;
1018: break;
1019: case MOD:
1020: if (j == 0)
1.16 millert 1021: FATAL("division by zero in mod");
1.1 tholo 1022: modf(i/j, &v);
1023: i = i - j * v;
1024: break;
1025: case UMINUS:
1026: i = -i;
1027: break;
1028: case POWER:
1029: if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1.12 millert 1030: i = ipow(i, (int) j);
1.1 tholo 1031: else
1032: i = errcheck(pow(i, j), "pow");
1033: break;
1034: default: /* can't happen */
1.16 millert 1035: FATAL("illegal arithmetic operator %d", n);
1.1 tholo 1036: }
1037: setfval(z, i);
1038: return(z);
1039: }
1040:
1041: double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
1042: {
1043: double v;
1044:
1045: if (n <= 0)
1046: return 1;
1047: v = ipow(x, n/2);
1048: if (n % 2 == 0)
1049: return v * v;
1050: else
1051: return x * v * v;
1052: }
1053:
1054: Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
1055: {
1056: Cell *x, *z;
1057: int k;
1058: Awkfloat xf;
1059:
1060: x = execute(a[0]);
1061: xf = getfval(x);
1062: k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1063: if (n == PREINCR || n == PREDECR) {
1064: setfval(x, xf + k);
1065: return(x);
1066: }
1067: z = gettemp();
1068: setfval(z, xf);
1069: setfval(x, xf + k);
1070: tempfree(x);
1071: return(z);
1072: }
1073:
1074: Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
1075: { /* this is subtle; don't muck with it. */
1076: Cell *x, *y;
1077: Awkfloat xf, yf;
1078: double v;
1079:
1080: y = execute(a[1]);
1081: x = execute(a[0]);
1082: if (n == ASSIGN) { /* ordinary assignment */
1083: if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
1084: ; /* leave alone unless it's a field */
1085: else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1086: setsval(x, getsval(y));
1087: x->fval = getfval(y);
1088: x->tval |= NUM;
1089: }
1.13 kstailey 1090: else if (isstr(y))
1.1 tholo 1091: setsval(x, getsval(y));
1.13 kstailey 1092: else if (isnum(y))
1.1 tholo 1093: setfval(x, getfval(y));
1094: else
1095: funnyvar(y, "read value of");
1096: tempfree(y);
1097: return(x);
1098: }
1099: xf = getfval(x);
1100: yf = getfval(y);
1101: switch (n) {
1102: case ADDEQ:
1103: xf += yf;
1104: break;
1105: case SUBEQ:
1106: xf -= yf;
1107: break;
1108: case MULTEQ:
1109: xf *= yf;
1110: break;
1111: case DIVEQ:
1112: if (yf == 0)
1.16 millert 1113: FATAL("division by zero in /=");
1.1 tholo 1114: xf /= yf;
1115: break;
1116: case MODEQ:
1117: if (yf == 0)
1.16 millert 1118: FATAL("division by zero in %%=");
1.1 tholo 1119: modf(xf/yf, &v);
1120: xf = xf - yf * v;
1121: break;
1122: case POWEQ:
1123: if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1.12 millert 1124: xf = ipow(xf, (int) yf);
1.1 tholo 1125: else
1126: xf = errcheck(pow(xf, yf), "pow");
1127: break;
1128: default:
1.16 millert 1129: FATAL("illegal assignment operator %d", n);
1.1 tholo 1130: break;
1131: }
1132: tempfree(y);
1133: setfval(x, xf);
1134: return(x);
1135: }
1136:
1137: Cell *cat(Node **a, int q) /* a[0] cat a[1] */
1138: {
1139: Cell *x, *y, *z;
1140: int n1, n2;
1141: char *s;
1.21 tedu 1142: size_t len;
1.1 tholo 1143:
1144: x = execute(a[0]);
1145: y = execute(a[1]);
1146: getsval(x);
1147: getsval(y);
1148: n1 = strlen(x->sval);
1149: n2 = strlen(y->sval);
1.21 tedu 1150: len = n1 + n2 + 1;
1151: s = (char *) malloc(len);
1.1 tholo 1152: if (s == NULL)
1.16 millert 1153: FATAL("out of space concatenating %.15s... and %.15s...",
1154: x->sval, y->sval);
1.21 tedu 1155: strlcpy(s, x->sval, len);
1156: strlcpy(s+n1, y->sval, len - n1);
1.1 tholo 1157: tempfree(y);
1158: z = gettemp();
1159: z->sval = s;
1160: z->tval = STR;
1161: tempfree(x);
1162: return(z);
1163: }
1164:
1165: Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
1166: {
1167: Cell *x;
1168:
1169: if (a[0] == 0)
1170: x = execute(a[1]);
1171: else {
1172: x = execute(a[0]);
1173: if (istrue(x)) {
1174: tempfree(x);
1175: x = execute(a[1]);
1176: }
1177: }
1178: return x;
1179: }
1180:
1181: Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
1182: {
1183: Cell *x;
1184: int pair;
1185:
1.15 millert 1186: pair = ptoi(a[3]);
1.1 tholo 1187: if (pairstack[pair] == 0) {
1188: x = execute(a[0]);
1189: if (istrue(x))
1190: pairstack[pair] = 1;
1191: tempfree(x);
1192: }
1193: if (pairstack[pair] == 1) {
1194: x = execute(a[1]);
1195: if (istrue(x))
1196: pairstack[pair] = 0;
1197: tempfree(x);
1198: x = execute(a[2]);
1199: return(x);
1200: }
1.15 millert 1201: return(False);
1.1 tholo 1202: }
1203:
1204: Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
1205: {
1206: Cell *x = 0, *y, *ap;
1207: char *s;
1208: int sep;
1.13 kstailey 1209: char *t, temp, num[50], *fs = 0;
1.15 millert 1210: int n, tempstat, arg3type;
1.1 tholo 1211:
1212: y = execute(a[0]); /* source string */
1213: s = getsval(y);
1.15 millert 1214: arg3type = ptoi(a[3]);
1.1 tholo 1215: if (a[2] == 0) /* fs string */
1216: fs = *FS;
1.15 millert 1217: else if (arg3type == STRING) { /* split(str,arr,"string") */
1.1 tholo 1218: x = execute(a[2]);
1219: fs = getsval(x);
1.15 millert 1220: } else if (arg3type == REGEXPR)
1.13 kstailey 1221: fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1.1 tholo 1222: else
1.16 millert 1223: FATAL("illegal type of split");
1.1 tholo 1224: sep = *fs;
1225: ap = execute(a[1]); /* array name */
1226: freesymtab(ap);
1.18 millert 1227: dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs) );
1.1 tholo 1228: ap->tval &= ~STR;
1229: ap->tval |= ARR;
1230: ap->sval = (char *) makesymtab(NSYMTAB);
1231:
1232: n = 0;
1.15 millert 1233: if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) { /* reg expr */
1.1 tholo 1234: fa *pfa;
1.15 millert 1235: if (arg3type == REGEXPR) { /* it's ready already */
1.1 tholo 1236: pfa = (fa *) a[2];
1237: } else {
1238: pfa = makedfa(fs, 1);
1239: }
1240: if (nematch(pfa,s)) {
1241: tempstat = pfa->initstat;
1242: pfa->initstat = 2;
1243: do {
1244: n++;
1.19 deraadt 1245: snprintf(num, sizeof num, "%d", n);
1.1 tholo 1246: temp = *patbeg;
1247: *patbeg = '\0';
1.14 millert 1248: if (is_number(s))
1.13 kstailey 1249: setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1.1 tholo 1250: else
1251: setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1252: *patbeg = temp;
1253: s = patbeg + patlen;
1254: if (*(patbeg+patlen-1) == 0 || *s == 0) {
1255: n++;
1.19 deraadt 1256: snprintf(num, sizeof num, "%d", n);
1.1 tholo 1257: setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1258: pfa->initstat = tempstat;
1259: goto spdone;
1260: }
1261: } while (nematch(pfa,s));
1262: }
1263: n++;
1.19 deraadt 1264: snprintf(num, sizeof num, "%d", n);
1.14 millert 1265: if (is_number(s))
1.13 kstailey 1266: setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1.1 tholo 1267: else
1268: setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1269: spdone:
1270: pfa = NULL;
1271: } else if (sep == ' ') {
1272: for (n = 0; ; ) {
1273: while (*s == ' ' || *s == '\t' || *s == '\n')
1274: s++;
1275: if (*s == 0)
1276: break;
1277: n++;
1278: t = s;
1279: do
1280: s++;
1281: while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1282: temp = *s;
1283: *s = '\0';
1.19 deraadt 1284: snprintf(num, sizeof num, "%d", n);
1.14 millert 1285: if (is_number(t))
1.13 kstailey 1286: setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1.1 tholo 1287: else
1288: setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1289: *s = temp;
1290: if (*s != 0)
1291: s++;
1292: }
1293: } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1294: for (n = 0; *s != 0; s++) {
1295: char buf[2];
1296: n++;
1.19 deraadt 1297: snprintf(num, sizeof num, "%d", n);
1.1 tholo 1298: buf[0] = *s;
1299: buf[1] = 0;
1.17 millert 1300: if (isdigit((uschar)buf[0]))
1.1 tholo 1301: setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1302: else
1303: setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1304: }
1305: } else if (*s != 0) {
1306: for (;;) {
1307: n++;
1308: t = s;
1309: while (*s != sep && *s != '\n' && *s != '\0')
1310: s++;
1311: temp = *s;
1312: *s = '\0';
1.19 deraadt 1313: snprintf(num, sizeof num, "%d", n);
1.14 millert 1314: if (is_number(t))
1.13 kstailey 1315: setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1.1 tholo 1316: else
1317: setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1318: *s = temp;
1319: if (*s++ == 0)
1320: break;
1321: }
1322: }
1323: tempfree(ap);
1324: tempfree(y);
1.17 millert 1325: if (a[2] != 0 && arg3type == STRING) {
1.1 tholo 1326: tempfree(x);
1.17 millert 1327: }
1.1 tholo 1328: x = gettemp();
1329: x->tval = NUM;
1330: x->fval = n;
1331: return(x);
1332: }
1333:
1334: Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1335: {
1336: Cell *x;
1337:
1338: x = execute(a[0]);
1339: if (istrue(x)) {
1340: tempfree(x);
1341: x = execute(a[1]);
1342: } else {
1343: tempfree(x);
1344: x = execute(a[2]);
1345: }
1346: return(x);
1347: }
1348:
1349: Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1350: {
1351: Cell *x;
1352:
1353: x = execute(a[0]);
1354: if (istrue(x)) {
1355: tempfree(x);
1356: x = execute(a[1]);
1357: } else if (a[2] != 0) {
1358: tempfree(x);
1359: x = execute(a[2]);
1360: }
1361: return(x);
1362: }
1363:
1364: Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
1365: {
1366: Cell *x;
1367:
1368: for (;;) {
1369: x = execute(a[0]);
1370: if (!istrue(x))
1371: return(x);
1372: tempfree(x);
1373: x = execute(a[1]);
1374: if (isbreak(x)) {
1.15 millert 1375: x = True;
1.1 tholo 1376: return(x);
1377: }
1378: if (isnext(x) || isexit(x) || isret(x))
1379: return(x);
1380: tempfree(x);
1381: }
1382: }
1383:
1384: Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
1385: {
1386: Cell *x;
1387:
1388: for (;;) {
1389: x = execute(a[0]);
1390: if (isbreak(x))
1.15 millert 1391: return True;
1.17 millert 1392: if (isnext(x) || isexit(x) || isret(x))
1.1 tholo 1393: return(x);
1394: tempfree(x);
1395: x = execute(a[1]);
1396: if (!istrue(x))
1397: return(x);
1398: tempfree(x);
1399: }
1400: }
1401:
1402: Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
1403: {
1404: Cell *x;
1405:
1406: x = execute(a[0]);
1407: tempfree(x);
1408: for (;;) {
1409: if (a[1]!=0) {
1410: x = execute(a[1]);
1411: if (!istrue(x)) return(x);
1412: else tempfree(x);
1413: }
1414: x = execute(a[3]);
1415: if (isbreak(x)) /* turn off break */
1.15 millert 1416: return True;
1.1 tholo 1417: if (isnext(x) || isexit(x) || isret(x))
1418: return(x);
1419: tempfree(x);
1420: x = execute(a[2]);
1421: tempfree(x);
1422: }
1423: }
1424:
1425: Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1426: {
1427: Cell *x, *vp, *arrayp, *cp, *ncp;
1428: Array *tp;
1429: int i;
1430:
1431: vp = execute(a[0]);
1432: arrayp = execute(a[1]);
1433: if (!isarr(arrayp)) {
1.15 millert 1434: return True;
1.1 tholo 1435: }
1436: tp = (Array *) arrayp->sval;
1437: tempfree(arrayp);
1438: for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1439: for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1440: setsval(vp, cp->nval);
1441: ncp = cp->cnext;
1442: x = execute(a[2]);
1443: if (isbreak(x)) {
1444: tempfree(vp);
1.15 millert 1445: return True;
1.1 tholo 1446: }
1447: if (isnext(x) || isexit(x) || isret(x)) {
1448: tempfree(vp);
1449: return(x);
1450: }
1451: tempfree(x);
1452: }
1453: }
1.15 millert 1454: return True;
1.1 tholo 1455: }
1456:
1457: Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
1458: {
1459: Cell *x, *y;
1460: Awkfloat u;
1461: int t;
1.13 kstailey 1462: char *p, *buf;
1.1 tholo 1463: Node *nextarg;
1464: FILE *fp;
1.18 millert 1465: void flush_all(void);
1.1 tholo 1466:
1.15 millert 1467: t = ptoi(a[0]);
1.1 tholo 1468: x = execute(a[1]);
1469: nextarg = a[1]->nnext;
1470: switch (t) {
1471: case FLENGTH:
1.18 millert 1472: if (isarr(x))
1473: u = ((Array *) x->sval)->nelem; /* GROT. should be function*/
1474: else
1475: u = strlen(getsval(x));
1476: break;
1.1 tholo 1477: case FLOG:
1478: u = errcheck(log(getfval(x)), "log"); break;
1479: case FINT:
1480: modf(getfval(x), &u); break;
1481: case FEXP:
1482: u = errcheck(exp(getfval(x)), "exp"); break;
1483: case FSQRT:
1484: u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1485: case FSIN:
1486: u = sin(getfval(x)); break;
1487: case FCOS:
1488: u = cos(getfval(x)); break;
1489: case FATAN:
1490: if (nextarg == 0) {
1.16 millert 1491: WARNING("atan2 requires two arguments; returning 1.0");
1.1 tholo 1492: u = 1.0;
1493: } else {
1494: y = execute(a[1]->nnext);
1495: u = atan2(getfval(x), getfval(y));
1496: tempfree(y);
1497: nextarg = nextarg->nnext;
1498: }
1499: break;
1500: case FSYSTEM:
1501: fflush(stdout); /* in case something is buffered already */
1.13 kstailey 1502: u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */
1.1 tholo 1503: break;
1504: case FRAND:
1.24 ! millert 1505: if (use_arc4)
! 1506: u = (Awkfloat) (arc4random() % RAND_MAX) / RAND_MAX;
! 1507: else
! 1508: u = (Awkfloat) (random() % RAND_MAX) / RAND_MAX;
1.1 tholo 1509: break;
1510: case FSRAND:
1.24 ! millert 1511: if (isrec(x)) /* no argument provided, want arc4random() */
! 1512: use_arc4 = 1;
! 1513: else {
1.1 tholo 1514: u = getfval(x);
1.24 ! millert 1515: srandom((unsigned int) u);
! 1516: use_arc4 = 0;
! 1517: }
1.1 tholo 1518: break;
1519: case FTOUPPER:
1520: case FTOLOWER:
1.13 kstailey 1521: buf = tostring(getsval(x));
1.1 tholo 1522: if (t == FTOUPPER) {
1523: for (p = buf; *p; p++)
1.17 millert 1524: if (islower((uschar) *p))
1.1 tholo 1525: *p = toupper(*p);
1526: } else {
1527: for (p = buf; *p; p++)
1.17 millert 1528: if (isupper((uschar) *p))
1.1 tholo 1529: *p = tolower(*p);
1530: }
1531: tempfree(x);
1532: x = gettemp();
1533: setsval(x, buf);
1.13 kstailey 1534: free(buf);
1.1 tholo 1535: return x;
1536: case FFLUSH:
1.18 millert 1537: if (isrec(x) || strlen(getsval(x)) == 0) {
1538: flush_all(); /* fflush() or fflush("") -> all */
1539: u = 0;
1540: } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1.1 tholo 1541: u = EOF;
1542: else
1543: u = fflush(fp);
1544: break;
1545: default: /* can't happen */
1.16 millert 1546: FATAL("illegal function type %d", t);
1.1 tholo 1547: break;
1548: }
1549: tempfree(x);
1550: x = gettemp();
1551: setfval(x, u);
1552: if (nextarg != 0) {
1.16 millert 1553: WARNING("warning: function has too many arguments");
1.1 tholo 1554: for ( ; nextarg; nextarg = nextarg->nnext)
1555: execute(nextarg);
1556: }
1557: return(x);
1558: }
1559:
1560: Cell *printstat(Node **a, int n) /* print a[0] */
1561: {
1562: Node *x;
1563: Cell *y;
1564: FILE *fp;
1565:
1566: if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
1567: fp = stdout;
1568: else
1.15 millert 1569: fp = redirect(ptoi(a[1]), a[2]);
1.1 tholo 1570: for (x = a[0]; x != NULL; x = x->nnext) {
1571: y = execute(x);
1.18 millert 1572: fputs(getpssval(y), fp);
1.1 tholo 1573: tempfree(y);
1574: if (x->nnext == NULL)
1.13 kstailey 1575: fputs(*ORS, fp);
1.1 tholo 1576: else
1.13 kstailey 1577: fputs(*OFS, fp);
1.1 tholo 1578: }
1579: if (a[1] != 0)
1580: fflush(fp);
1581: if (ferror(fp))
1.16 millert 1582: FATAL("write error on %s", filename(fp));
1.15 millert 1583: return(True);
1.1 tholo 1584: }
1585:
1586: Cell *nullproc(Node **a, int n)
1587: {
1.15 millert 1588: n = n;
1589: a = a;
1.1 tholo 1590: return 0;
1591: }
1592:
1593:
1594: FILE *redirect(int a, Node *b) /* set up all i/o redirections */
1595: {
1596: FILE *fp;
1597: Cell *x;
1598: char *fname;
1599:
1600: x = execute(b);
1601: fname = getsval(x);
1602: fp = openfile(a, fname);
1603: if (fp == NULL)
1.16 millert 1604: FATAL("can't open file %s", fname);
1.1 tholo 1605: tempfree(x);
1606: return fp;
1607: }
1608:
1609: struct files {
1610: FILE *fp;
1.18 millert 1611: const char *fname;
1.1 tholo 1612: int mode; /* '|', 'a', 'w' => LE/LT, GT */
1613: } files[FOPEN_MAX] ={
1.16 millert 1614: { NULL, "/dev/stdin", LT }, /* watch out: don't free this! */
1615: { NULL, "/dev/stdout", GT },
1616: { NULL, "/dev/stderr", GT }
1.1 tholo 1617: };
1618:
1.16 millert 1619: void stdinit(void) /* in case stdin, etc., are not constants */
1620: {
1621: files[0].fp = stdin;
1622: files[1].fp = stdout;
1623: files[2].fp = stderr;
1624: }
1625:
1.18 millert 1626: FILE *openfile(int a, const char *us)
1.1 tholo 1627: {
1.18 millert 1628: const char *s = us;
1.1 tholo 1629: int i, m;
1630: FILE *fp = 0;
1631:
1632: if (*s == '\0')
1.16 millert 1633: FATAL("null file name in print or getline");
1.1 tholo 1634: for (i=0; i < FOPEN_MAX; i++)
1.13 kstailey 1635: if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1.1 tholo 1636: if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1637: return files[i].fp;
1.13 kstailey 1638: if (a == FFLUSH)
1639: return files[i].fp;
1640: }
1641: if (a == FFLUSH) /* didn't find it, so don't create it! */
1642: return NULL;
1643:
1.1 tholo 1644: for (i=0; i < FOPEN_MAX; i++)
1645: if (files[i].fp == 0)
1646: break;
1647: if (i >= FOPEN_MAX)
1.16 millert 1648: FATAL("%s makes too many open files", s);
1.1 tholo 1649: fflush(stdout); /* force a semblance of order */
1650: m = a;
1651: if (a == GT) {
1652: fp = fopen(s, "w");
1653: } else if (a == APPEND) {
1654: fp = fopen(s, "a");
1655: m = GT; /* so can mix > and >> */
1656: } else if (a == '|') { /* output pipe */
1657: fp = popen(s, "w");
1658: } else if (a == LE) { /* input pipe */
1659: fp = popen(s, "r");
1660: } else if (a == LT) { /* getline <file */
1661: fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
1662: } else /* can't happen */
1.16 millert 1663: FATAL("illegal redirection %d", a);
1.1 tholo 1664: if (fp != NULL) {
1665: files[i].fname = tostring(s);
1666: files[i].fp = fp;
1667: files[i].mode = m;
1668: }
1669: return fp;
1670: }
1671:
1.18 millert 1672: const char *filename(FILE *fp)
1.1 tholo 1673: {
1674: int i;
1675:
1676: for (i = 0; i < FOPEN_MAX; i++)
1677: if (fp == files[i].fp)
1678: return files[i].fname;
1679: return "???";
1680: }
1681:
1682: Cell *closefile(Node **a, int n)
1683: {
1684: Cell *x;
1685: int i, stat;
1686:
1.15 millert 1687: n = n;
1.1 tholo 1688: x = execute(a[0]);
1689: getsval(x);
1.17 millert 1690: stat = -1;
1691: for (i = 0; i < FOPEN_MAX; i++) {
1.1 tholo 1692: if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1693: if (ferror(files[i].fp))
1.16 millert 1694: WARNING( "i/o error occurred on %s", files[i].fname );
1.1 tholo 1695: if (files[i].mode == '|' || files[i].mode == LE)
1696: stat = pclose(files[i].fp);
1697: else
1698: stat = fclose(files[i].fp);
1699: if (stat == EOF)
1.16 millert 1700: WARNING( "i/o error occurred closing %s", files[i].fname );
1.1 tholo 1701: if (i > 2) /* don't do /dev/std... */
1702: xfree(files[i].fname);
1703: files[i].fname = NULL; /* watch out for ref thru this */
1704: files[i].fp = NULL;
1705: }
1.17 millert 1706: }
1.1 tholo 1707: tempfree(x);
1.17 millert 1708: x = gettemp();
1709: setfval(x, (Awkfloat) stat);
1710: return(x);
1.1 tholo 1711: }
1712:
1713: void closeall(void)
1714: {
1715: int i, stat;
1716:
1.17 millert 1717: for (i = 0; i < FOPEN_MAX; i++) {
1.1 tholo 1718: if (files[i].fp) {
1719: if (ferror(files[i].fp))
1.16 millert 1720: WARNING( "i/o error occurred on %s", files[i].fname );
1.1 tholo 1721: if (files[i].mode == '|' || files[i].mode == LE)
1722: stat = pclose(files[i].fp);
1723: else
1724: stat = fclose(files[i].fp);
1725: if (stat == EOF)
1.16 millert 1726: WARNING( "i/o error occurred while closing %s", files[i].fname );
1.1 tholo 1727: }
1.17 millert 1728: }
1.18 millert 1729: }
1730:
1731: void flush_all(void)
1732: {
1733: int i;
1734:
1735: for (i = 0; i < FOPEN_MAX; i++)
1736: if (files[i].fp)
1737: fflush(files[i].fp);
1.1 tholo 1738: }
1739:
1.13 kstailey 1740: void backsub(char **pb_ptr, char **sptr_ptr);
1.1 tholo 1741:
1742: Cell *sub(Node **a, int nnn) /* substitute command */
1743: {
1744: char *sptr, *pb, *q;
1745: Cell *x, *y, *result;
1.13 kstailey 1746: char *t, *buf;
1.1 tholo 1747: fa *pfa;
1.13 kstailey 1748: int bufsz = recsize;
1.1 tholo 1749:
1.15 millert 1750: if ((buf = (char *) malloc(bufsz)) == NULL)
1.16 millert 1751: FATAL("out of memory in sub");
1.1 tholo 1752: x = execute(a[3]); /* target string */
1753: t = getsval(x);
1754: if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1755: pfa = (fa *) a[1]; /* regular expression */
1756: else {
1757: y = execute(a[1]);
1758: pfa = makedfa(getsval(y), 1);
1759: tempfree(y);
1760: }
1761: y = execute(a[2]); /* replacement string */
1.15 millert 1762: result = False;
1.1 tholo 1763: if (pmatch(pfa, t)) {
1.13 kstailey 1764: sptr = t;
1765: adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1.1 tholo 1766: pb = buf;
1767: while (sptr < patbeg)
1768: *pb++ = *sptr++;
1769: sptr = getsval(y);
1.13 kstailey 1770: while (*sptr != 0) {
1771: adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1772: if (*sptr == '\\') {
1773: backsub(&pb, &sptr);
1.1 tholo 1774: } else if (*sptr == '&') {
1775: sptr++;
1.13 kstailey 1776: adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1.1 tholo 1777: for (q = patbeg; q < patbeg+patlen; )
1778: *pb++ = *q++;
1779: } else
1780: *pb++ = *sptr++;
1.13 kstailey 1781: }
1.1 tholo 1782: *pb = '\0';
1.13 kstailey 1783: if (pb > buf + bufsz)
1.16 millert 1784: FATAL("sub result1 %.30s too big; can't happen", buf);
1.1 tholo 1785: sptr = patbeg + patlen;
1.13 kstailey 1786: if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1787: adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1.1 tholo 1788: while ((*pb++ = *sptr++) != 0)
1789: ;
1.13 kstailey 1790: }
1791: if (pb > buf + bufsz)
1.16 millert 1792: FATAL("sub result2 %.30s too big; can't happen", buf);
1.13 kstailey 1793: setsval(x, buf); /* BUG: should be able to avoid copy */
1.23 millert 1794: result = True;
1.1 tholo 1795: }
1796: tempfree(x);
1797: tempfree(y);
1.13 kstailey 1798: free(buf);
1.1 tholo 1799: return result;
1800: }
1801:
1802: Cell *gsub(Node **a, int nnn) /* global substitute */
1803: {
1804: Cell *x, *y;
1.13 kstailey 1805: char *rptr, *sptr, *t, *pb, *q;
1806: char *buf;
1.1 tholo 1807: fa *pfa;
1808: int mflag, tempstat, num;
1.13 kstailey 1809: int bufsz = recsize;
1.1 tholo 1810:
1.15 millert 1811: if ((buf = (char *) malloc(bufsz)) == NULL)
1.16 millert 1812: FATAL("out of memory in gsub");
1.1 tholo 1813: mflag = 0; /* if mflag == 0, can replace empty string */
1814: num = 0;
1815: x = execute(a[3]); /* target string */
1816: t = getsval(x);
1817: if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1818: pfa = (fa *) a[1]; /* regular expression */
1819: else {
1820: y = execute(a[1]);
1821: pfa = makedfa(getsval(y), 1);
1822: tempfree(y);
1823: }
1824: y = execute(a[2]); /* replacement string */
1825: if (pmatch(pfa, t)) {
1826: tempstat = pfa->initstat;
1827: pfa->initstat = 2;
1828: pb = buf;
1829: rptr = getsval(y);
1830: do {
1831: if (patlen == 0 && *patbeg != 0) { /* matched empty string */
1832: if (mflag == 0) { /* can replace empty */
1833: num++;
1834: sptr = rptr;
1.13 kstailey 1835: while (*sptr != 0) {
1836: adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1837: if (*sptr == '\\') {
1838: backsub(&pb, &sptr);
1.1 tholo 1839: } else if (*sptr == '&') {
1840: sptr++;
1.13 kstailey 1841: adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1.1 tholo 1842: for (q = patbeg; q < patbeg+patlen; )
1843: *pb++ = *q++;
1844: } else
1845: *pb++ = *sptr++;
1.13 kstailey 1846: }
1.1 tholo 1847: }
1848: if (*t == 0) /* at end */
1849: goto done;
1.13 kstailey 1850: adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1.1 tholo 1851: *pb++ = *t++;
1.13 kstailey 1852: if (pb > buf + bufsz) /* BUG: not sure of this test */
1.16 millert 1853: FATAL("gsub result0 %.30s too big; can't happen", buf);
1.1 tholo 1854: mflag = 0;
1855: }
1856: else { /* matched nonempty string */
1857: num++;
1858: sptr = t;
1.13 kstailey 1859: adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1860: while (sptr < patbeg)
1.1 tholo 1861: *pb++ = *sptr++;
1862: sptr = rptr;
1.13 kstailey 1863: while (*sptr != 0) {
1864: adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1865: if (*sptr == '\\') {
1866: backsub(&pb, &sptr);
1.1 tholo 1867: } else if (*sptr == '&') {
1868: sptr++;
1.13 kstailey 1869: adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1.1 tholo 1870: for (q = patbeg; q < patbeg+patlen; )
1871: *pb++ = *q++;
1872: } else
1873: *pb++ = *sptr++;
1.13 kstailey 1874: }
1.1 tholo 1875: t = patbeg + patlen;
1876: if (patlen == 0 || *t == 0 || *(t-1) == 0)
1877: goto done;
1.13 kstailey 1878: if (pb > buf + bufsz)
1.16 millert 1879: FATAL("gsub result1 %.30s too big; can't happen", buf);
1.1 tholo 1880: mflag = 1;
1881: }
1882: } while (pmatch(pfa,t));
1883: sptr = t;
1.13 kstailey 1884: adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1.1 tholo 1885: while ((*pb++ = *sptr++) != 0)
1886: ;
1.13 kstailey 1887: done: if (pb > buf + bufsz)
1.16 millert 1888: FATAL("gsub result2 %.30s too big; can't happen", buf);
1.1 tholo 1889: *pb = '\0';
1.13 kstailey 1890: setsval(x, buf); /* BUG: should be able to avoid copy + free */
1.1 tholo 1891: pfa->initstat = tempstat;
1892: }
1893: tempfree(x);
1894: tempfree(y);
1895: x = gettemp();
1896: x->tval = NUM;
1897: x->fval = num;
1.13 kstailey 1898: free(buf);
1.1 tholo 1899: return(x);
1.13 kstailey 1900: }
1901:
1902: void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
1903: { /* sptr[0] == '\\' */
1904: char *pb = *pb_ptr, *sptr = *sptr_ptr;
1905:
1906: if (sptr[1] == '\\') {
1907: if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
1908: *pb++ = '\\';
1909: *pb++ = '&';
1910: sptr += 4;
1911: } else if (sptr[2] == '&') { /* \\& -> \ + matched */
1912: *pb++ = '\\';
1913: sptr += 2;
1914: } else { /* \\x -> \\x */
1915: *pb++ = *sptr++;
1916: *pb++ = *sptr++;
1917: }
1918: } else if (sptr[1] == '&') { /* literal & */
1919: sptr++;
1920: *pb++ = *sptr++;
1921: } else /* literal \ */
1922: *pb++ = *sptr++;
1923:
1924: *pb_ptr = pb;
1925: *sptr_ptr = sptr;
1.1 tholo 1926: }