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