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