~ubuntu-branches/ubuntu/lucid/9base/lucid

« back to all changes in this revision

Viewing changes to awk/run.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2006-01-25 15:33:00 UTC
  • Revision ID: james.westby@ubuntu.com-20060125153300-6hh4p9wx8iqqply5
Tags: upstream-2
ImportĀ upstreamĀ versionĀ 2

Show diffs side-by-side

added added

removed removed

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