blob: 4270e54d2d8e13a34522778d8e88265434f26f83 [file] [log] [blame]
Brian Kernighan87b94932012-12-22 10:35:39 -05001/****************************************************************
2Copyright (C) Lucent Technologies 1997
3All Rights Reserved
4
5Permission to use, copy, modify, and distribute this software and
6its documentation for any purpose and without fee is hereby
7granted, provided that the above copyright notice appear in all
8copies and that both that the copyright notice and this
9permission notice and warranty disclaimer appear in supporting
10documentation, and that the name Lucent Technologies or any of
11its entities not be used in advertising or publicity pertaining
12to distribution of the software without specific, written prior
13permission.
14
15LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22THIS SOFTWARE.
23****************************************************************/
24
25#define DEBUG
26#include <stdio.h>
27#include <ctype.h>
Arnold D. Robbins5068d202020-02-06 22:27:31 +020028#include <wchar.h>
29#include <wctype.h>
Arnold D. Robbins5a18f632020-01-22 02:10:59 -070030#include <fcntl.h>
Brian Kernighan87b94932012-12-22 10:35:39 -050031#include <setjmp.h>
32#include <limits.h>
33#include <math.h>
34#include <string.h>
35#include <stdlib.h>
36#include <time.h>
Arnold D. Robbins32093f52018-08-22 20:40:26 +030037#include <sys/types.h>
38#include <sys/wait.h>
Brian Kernighan87b94932012-12-22 10:35:39 -050039#include "awk.h"
40#include "ytab.h"
41
Arnold D. Robbins5068d202020-02-06 22:27:31 +020042static void stdinit(void);
43static void flush_all(void);
Brian Kernighan87b94932012-12-22 10:35:39 -050044
Arnold D. Robbins5068d202020-02-06 22:27:31 +020045#if 1
46#define tempfree(x) do { if (istemp(x)) tfree(x); } while (/*CONSTCOND*/0)
47#else
Brian Kernighan87b94932012-12-22 10:35:39 -050048void tempfree(Cell *p) {
49 if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
50 WARNING("bad csub %d in Cell %d %s",
51 p->csub, p->ctype, p->sval);
52 }
53 if (istemp(p))
54 tfree(p);
55}
Arnold D. Robbins5068d202020-02-06 22:27:31 +020056#endif
Brian Kernighan87b94932012-12-22 10:35:39 -050057
58/* do we really need these? */
59/* #ifdef _NFILE */
60/* #ifndef FOPEN_MAX */
61/* #define FOPEN_MAX _NFILE */
62/* #endif */
63/* #endif */
64/* */
65/* #ifndef FOPEN_MAX */
66/* #define FOPEN_MAX 40 */ /* max number of open files */
67/* #endif */
68/* */
69/* #ifndef RAND_MAX */
70/* #define RAND_MAX 32767 */ /* all that ansi guarantees */
71/* #endif */
72
73jmp_buf env;
74extern int pairstack[];
75extern Awkfloat srand_seed;
76
77Node *winner = NULL; /* root of parse tree */
78Cell *tmps; /* free temporary cells for execution */
79
Brian Kernighan3ed9e242018-08-15 10:45:03 -040080static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050081Cell *True = &truecell;
Brian Kernighan3ed9e242018-08-15 10:45:03 -040082static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050083Cell *False = &falsecell;
Brian Kernighan3ed9e242018-08-15 10:45:03 -040084static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050085Cell *jbreak = &breakcell;
Brian Kernighan3ed9e242018-08-15 10:45:03 -040086static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050087Cell *jcont = &contcell;
Brian Kernighan3ed9e242018-08-15 10:45:03 -040088static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050089Cell *jnext = &nextcell;
Brian Kernighan3ed9e242018-08-15 10:45:03 -040090static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050091Cell *jnextfile = &nextfilecell;
Brian Kernighan3ed9e242018-08-15 10:45:03 -040092static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050093Cell *jexit = &exitcell;
Brian Kernighan3ed9e242018-08-15 10:45:03 -040094static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050095Cell *jret = &retcell;
zoulasc6a877092020-01-24 04:11:59 -050096static Cell tempcell ={ OCELL, CTEMP, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050097
98Node *curnode = NULL; /* the node being executed, for debugging */
99
100/* buffer memory management */
101int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
102 const char *whatrtn)
103/* pbuf: address of pointer to buffer being managed
104 * psiz: address of buffer size variable
105 * minlen: minimum length of buffer needed
106 * quantum: buffer size quantum
107 * pbptr: address of movable pointer into buffer, or 0 if none
108 * whatrtn: name of the calling routine if failure should cause fatal error
109 *
110 * return 0 for realloc failure, !=0 for success
111 */
112{
113 if (minlen > *psiz) {
114 char *tbuf;
115 int rminlen = quantum ? minlen % quantum : 0;
116 int boff = pbptr ? *pbptr - *pbuf : 0;
117 /* round up to next multiple of quantum */
118 if (rminlen)
119 minlen += quantum - rminlen;
zoulasc65892082019-10-24 09:40:15 -0400120 tbuf = realloc(*pbuf, minlen);
121 dprintf( ("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, *pbuf, tbuf) );
Brian Kernighan87b94932012-12-22 10:35:39 -0500122 if (tbuf == NULL) {
123 if (whatrtn)
124 FATAL("out of memory in %s", whatrtn);
125 return 0;
126 }
127 *pbuf = tbuf;
128 *psiz = minlen;
129 if (pbptr)
130 *pbptr = tbuf + boff;
131 }
132 return 1;
133}
134
135void run(Node *a) /* execution of parse tree starts here */
136{
Brian Kernighan87b94932012-12-22 10:35:39 -0500137
138 stdinit();
139 execute(a);
140 closeall();
141}
142
143Cell *execute(Node *u) /* execute a node of the parse tree */
144{
145 Cell *(*proc)(Node **, int);
146 Cell *x;
147 Node *a;
148
149 if (u == NULL)
150 return(True);
151 for (a = u; ; a = a->nnext) {
152 curnode = a;
153 if (isvalue(a)) {
154 x = (Cell *) (a->narg[0]);
155 if (isfld(x) && !donefld)
156 fldbld();
157 else if (isrec(x) && !donerec)
158 recbld();
159 return(x);
160 }
161 if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */
162 FATAL("illegal statement");
163 proc = proctab[a->nobj-FIRSTTOKEN];
164 x = (*proc)(a->narg, a->nobj);
165 if (isfld(x) && !donefld)
166 fldbld();
167 else if (isrec(x) && !donerec)
168 recbld();
169 if (isexpr(a))
170 return(x);
171 if (isjump(x))
172 return(x);
173 if (a->nnext == NULL)
174 return(x);
175 tempfree(x);
176 }
177}
178
179
180Cell *program(Node **a, int n) /* execute an awk program */
181{ /* a[0] = BEGIN, a[1] = body, a[2] = END */
182 Cell *x;
183
184 if (setjmp(env) != 0)
185 goto ex;
186 if (a[0]) { /* BEGIN */
187 x = execute(a[0]);
188 if (isexit(x))
189 return(True);
190 if (isjump(x))
191 FATAL("illegal break, continue, next or nextfile from BEGIN");
192 tempfree(x);
193 }
194 if (a[1] || a[2])
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200195 while (getrec(&record, &recsize, true) > 0) {
Brian Kernighan87b94932012-12-22 10:35:39 -0500196 x = execute(a[1]);
197 if (isexit(x))
198 break;
199 tempfree(x);
200 }
201 ex:
202 if (setjmp(env) != 0) /* handles exit within END */
203 goto ex1;
204 if (a[2]) { /* END */
205 x = execute(a[2]);
206 if (isbreak(x) || isnext(x) || iscont(x))
207 FATAL("illegal break, continue, next or nextfile from END");
208 tempfree(x);
209 }
210 ex1:
211 return(True);
212}
213
214struct Frame { /* stack frame for awk function calls */
215 int nargs; /* number of arguments in this call */
216 Cell *fcncell; /* pointer to Cell for function */
217 Cell **args; /* pointer to array of arguments after execute */
218 Cell *retval; /* return value */
219};
220
221#define NARGS 50 /* max args in a call */
222
223struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
224int nframe = 0; /* number of frames allocated */
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200225struct Frame *frp = NULL; /* frame pointer. bottom level unused */
Brian Kernighan87b94932012-12-22 10:35:39 -0500226
227Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
228{
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200229 static const Cell newcopycell = { OCELL, CCOPY, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -0500230 int i, ncall, ndef;
231 int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */
232 Node *x;
233 Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */
234 Cell *y, *z, *fcn;
235 char *s;
236
237 fcn = execute(a[0]); /* the function itself */
238 s = fcn->nval;
239 if (!isfcn(fcn))
240 FATAL("calling undefined function %s", s);
241 if (frame == NULL) {
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200242 frp = frame = calloc(nframe += 100, sizeof(*frame));
Brian Kernighan87b94932012-12-22 10:35:39 -0500243 if (frame == NULL)
244 FATAL("out of space for stack frames calling %s", s);
245 }
246 for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
247 ncall++;
248 ndef = (int) fcn->fval; /* args in defn */
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200249 dprintf( ("calling %s, %d args (%d in defn), frp=%d\n", s, ncall, ndef, (int) (frp-frame)) );
Brian Kernighan87b94932012-12-22 10:35:39 -0500250 if (ncall > ndef)
251 WARNING("function %s called with %d args, uses only %d",
252 s, ncall, ndef);
253 if (ncall + ndef > NARGS)
254 FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
255 for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200256 dprintf( ("evaluate args[%d], frp=%d:\n", i, (int) (frp-frame)) );
Brian Kernighan87b94932012-12-22 10:35:39 -0500257 y = execute(x);
258 oargs[i] = y;
259 dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
260 i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval) );
261 if (isfcn(y))
262 FATAL("can't use function %s as argument in %s", y->nval, s);
263 if (isarr(y))
264 args[i] = y; /* arrays by ref */
265 else
266 args[i] = copycell(y);
267 tempfree(y);
268 }
269 for ( ; i < ndef; i++) { /* add null args for ones not provided */
270 args[i] = gettemp();
271 *args[i] = newcopycell;
272 }
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200273 frp++; /* now ok to up frame */
274 if (frp >= frame + nframe) {
275 int dfp = frp - frame; /* old index */
zoulasc65892082019-10-24 09:40:15 -0400276 frame = realloc(frame, (nframe += 100) * sizeof(*frame));
Brian Kernighan87b94932012-12-22 10:35:39 -0500277 if (frame == NULL)
278 FATAL("out of space for stack frames in %s", s);
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200279 frp = frame + dfp;
Brian Kernighan87b94932012-12-22 10:35:39 -0500280 }
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200281 frp->fcncell = fcn;
282 frp->args = args;
283 frp->nargs = ndef; /* number defined with (excess are locals) */
284 frp->retval = gettemp();
Brian Kernighan87b94932012-12-22 10:35:39 -0500285
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200286 dprintf( ("start exec of %s, frp=%d\n", s, (int) (frp-frame)) );
Brian Kernighan87b94932012-12-22 10:35:39 -0500287 y = execute((Node *)(fcn->sval)); /* execute body */
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200288 dprintf( ("finished exec of %s, frp=%d\n", s, (int) (frp-frame)) );
Brian Kernighan87b94932012-12-22 10:35:39 -0500289
290 for (i = 0; i < ndef; i++) {
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200291 Cell *t = frp->args[i];
Brian Kernighan87b94932012-12-22 10:35:39 -0500292 if (isarr(t)) {
293 if (t->csub == CCOPY) {
294 if (i >= ncall) {
295 freesymtab(t);
296 t->csub = CTEMP;
297 tempfree(t);
298 } else {
299 oargs[i]->tval = t->tval;
300 oargs[i]->tval &= ~(STR|NUM|DONTFREE);
301 oargs[i]->sval = t->sval;
302 tempfree(t);
303 }
304 }
305 } else if (t != y) { /* kludge to prevent freeing twice */
306 t->csub = CTEMP;
307 tempfree(t);
308 } else if (t == y && t->csub == CCOPY) {
309 t->csub = CTEMP;
310 tempfree(t);
311 freed = 1;
312 }
313 }
314 tempfree(fcn);
315 if (isexit(y) || isnext(y))
316 return y;
317 if (freed == 0) {
318 tempfree(y); /* don't free twice! */
319 }
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200320 z = frp->retval; /* return value */
Brian Kernighan87b94932012-12-22 10:35:39 -0500321 dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200322 frp--;
Brian Kernighan87b94932012-12-22 10:35:39 -0500323 return(z);
324}
325
326Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
327{
328 Cell *y;
329
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300330 /* copy is not constant or field */
331
Brian Kernighan87b94932012-12-22 10:35:39 -0500332 y = gettemp();
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300333 y->tval = x->tval & ~(CON|FLD|REC);
Brian Kernighan87b94932012-12-22 10:35:39 -0500334 y->csub = CCOPY; /* prevents freeing until call is over */
335 y->nval = x->nval; /* BUG? */
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300336 if (isstr(x) /* || x->ctype == OCELL */) {
Brian Kernighan87b94932012-12-22 10:35:39 -0500337 y->sval = tostring(x->sval);
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300338 y->tval &= ~DONTFREE;
339 } else
340 y->tval |= DONTFREE;
Brian Kernighan87b94932012-12-22 10:35:39 -0500341 y->fval = x->fval;
Brian Kernighan87b94932012-12-22 10:35:39 -0500342 return y;
343}
344
345Cell *arg(Node **a, int n) /* nth argument of a function */
346{
347
348 n = ptoi(a[0]); /* argument number, counting from 0 */
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200349 dprintf( ("arg(%d), frp->nargs=%d\n", n, frp->nargs) );
350 if (n+1 > frp->nargs)
Brian Kernighan87b94932012-12-22 10:35:39 -0500351 FATAL("argument #%d of function %s was not supplied",
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200352 n+1, frp->fcncell->nval);
353 return frp->args[n];
Brian Kernighan87b94932012-12-22 10:35:39 -0500354}
355
356Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
357{
358 Cell *y;
359
360 switch (n) {
361 case EXIT:
362 if (a[0] != NULL) {
363 y = execute(a[0]);
364 errorflag = (int) getfval(y);
365 tempfree(y);
366 }
367 longjmp(env, 1);
368 case RETURN:
369 if (a[0] != NULL) {
370 y = execute(a[0]);
371 if ((y->tval & (STR|NUM)) == (STR|NUM)) {
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200372 setsval(frp->retval, getsval(y));
373 frp->retval->fval = getfval(y);
374 frp->retval->tval |= NUM;
Brian Kernighan87b94932012-12-22 10:35:39 -0500375 }
376 else if (y->tval & STR)
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200377 setsval(frp->retval, getsval(y));
Brian Kernighan87b94932012-12-22 10:35:39 -0500378 else if (y->tval & NUM)
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200379 setfval(frp->retval, getfval(y));
Brian Kernighan87b94932012-12-22 10:35:39 -0500380 else /* can't happen */
381 FATAL("bad type variable %d", y->tval);
382 tempfree(y);
383 }
384 return(jret);
385 case NEXT:
386 return(jnext);
387 case NEXTFILE:
388 nextfile();
389 return(jnextfile);
390 case BREAK:
391 return(jbreak);
392 case CONTINUE:
393 return(jcont);
394 default: /* can't happen */
395 FATAL("illegal jump type %d", n);
396 }
397 return 0; /* not reached */
398}
399
400Cell *awkgetline(Node **a, int n) /* get next line from specific input */
401{ /* a[0] is variable, a[1] is operator, a[2] is filename */
402 Cell *r, *x;
403 extern Cell **fldtab;
404 FILE *fp;
405 char *buf;
406 int bufsize = recsize;
407 int mode;
408
zoulasc65892082019-10-24 09:40:15 -0400409 if ((buf = malloc(bufsize)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500410 FATAL("out of memory in getline");
411
412 fflush(stdout); /* in case someone is waiting for a prompt */
413 r = gettemp();
414 if (a[1] != NULL) { /* getline < file */
415 x = execute(a[2]); /* filename */
416 mode = ptoi(a[1]);
417 if (mode == '|') /* input pipe */
418 mode = LE; /* arbitrary flag */
419 fp = openfile(mode, getsval(x));
420 tempfree(x);
421 if (fp == NULL)
422 n = -1;
423 else
424 n = readrec(&buf, &bufsize, fp);
425 if (n <= 0) {
426 ;
427 } else if (a[0] != NULL) { /* getline var <file */
428 x = execute(a[0]);
429 setsval(x, buf);
Arnold D. Robbins9dbd1f12019-01-25 12:56:06 +0200430 if (is_number(x->sval)) {
431 x->fval = atof(x->sval);
432 x->tval |= NUM;
433 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500434 tempfree(x);
435 } else { /* getline <file */
436 setsval(fldtab[0], buf);
437 if (is_number(fldtab[0]->sval)) {
438 fldtab[0]->fval = atof(fldtab[0]->sval);
439 fldtab[0]->tval |= NUM;
440 }
441 }
442 } else { /* bare getline; use current input */
443 if (a[0] == NULL) /* getline */
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200444 n = getrec(&record, &recsize, true);
Brian Kernighan87b94932012-12-22 10:35:39 -0500445 else { /* getline var */
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200446 n = getrec(&buf, &bufsize, false);
Brian Kernighan87b94932012-12-22 10:35:39 -0500447 x = execute(a[0]);
448 setsval(x, buf);
Arnold D. Robbins9dbd1f12019-01-25 12:56:06 +0200449 if (is_number(x->sval)) {
450 x->fval = atof(x->sval);
451 x->tval |= NUM;
452 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500453 tempfree(x);
454 }
455 }
456 setfval(r, (Awkfloat) n);
457 free(buf);
458 return r;
459}
460
461Cell *getnf(Node **a, int n) /* get NF */
462{
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200463 if (!donefld)
Brian Kernighan87b94932012-12-22 10:35:39 -0500464 fldbld();
465 return (Cell *) a[0];
466}
467
zoulasc0d8778b2019-10-25 10:59:10 -0400468static char *
469makearraystring(Node *p, const char *func)
Brian Kernighan87b94932012-12-22 10:35:39 -0500470{
Brian Kernighan87b94932012-12-22 10:35:39 -0500471 char *buf;
472 int bufsz = recsize;
zoulasc0d8778b2019-10-25 10:59:10 -0400473 size_t blen, seplen;
Brian Kernighan87b94932012-12-22 10:35:39 -0500474
zoulasc0d8778b2019-10-25 10:59:10 -0400475 if ((buf = malloc(bufsz)) == NULL) {
476 FATAL("%s: out of memory", func);
477 }
478
479 blen = 0;
480 buf[blen] = '\0';
481 seplen = strlen(getsval(subseploc));
482
483 for (; p; p = p->nnext) {
484 Cell *x = execute(p); /* expr */
485 char *s = getsval(x);
486 size_t nsub = p->nnext ? seplen : 0;
487 size_t slen = strlen(s);
488 size_t tlen = blen + slen + nsub;
489
490 if (!adjbuf(&buf, &bufsz, tlen + 1, recsize, 0, func)) {
491 FATAL("%s: out of memory %s[%s...]",
492 func, x->nval, buf);
493 }
494 memcpy(buf + blen, s, slen);
495 if (nsub) {
496 memcpy(buf + blen + slen, *SUBSEP, nsub);
497 }
498 buf[tlen] = '\0';
499 blen = tlen;
500 tempfree(x);
501 }
502 return buf;
503}
504
505Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
506{
507 Cell *x, *z;
508 char *buf;
Brian Kernighan87b94932012-12-22 10:35:39 -0500509
510 x = execute(a[0]); /* Cell* for symbol table */
zoulasc0d8778b2019-10-25 10:59:10 -0400511 buf = makearraystring(a[1], __func__);
Brian Kernighan87b94932012-12-22 10:35:39 -0500512 if (!isarr(x)) {
513 dprintf( ("making %s into an array\n", NN(x->nval)) );
514 if (freeable(x))
515 xfree(x->sval);
516 x->tval &= ~(STR|NUM|DONTFREE);
517 x->tval |= ARR;
518 x->sval = (char *) makesymtab(NSYMTAB);
519 }
520 z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
521 z->ctype = OCELL;
522 z->csub = CVAR;
523 tempfree(x);
524 free(buf);
525 return(z);
526}
527
528Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
529{
zoulasc0d8778b2019-10-25 10:59:10 -0400530 Cell *x;
Brian Kernighan87b94932012-12-22 10:35:39 -0500531
532 x = execute(a[0]); /* Cell* for symbol table */
Cody Melloae99b752019-06-17 10:08:54 -0900533 if (x == symtabloc) {
534 FATAL("cannot delete SYMTAB or its elements");
535 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500536 if (!isarr(x))
537 return True;
pfg52421942016-06-03 21:23:11 +0000538 if (a[1] == NULL) { /* delete the elements, not the table */
Brian Kernighan87b94932012-12-22 10:35:39 -0500539 freesymtab(x);
540 x->tval &= ~STR;
541 x->tval |= ARR;
542 x->sval = (char *) makesymtab(NSYMTAB);
543 } else {
zoulasc0d8778b2019-10-25 10:59:10 -0400544 char *buf = makearraystring(a[1], __func__);
Brian Kernighan87b94932012-12-22 10:35:39 -0500545 freeelem(x, buf);
546 free(buf);
547 }
548 tempfree(x);
549 return True;
550}
551
552Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
553{
zoulasc0d8778b2019-10-25 10:59:10 -0400554 Cell *ap, *k;
Brian Kernighan87b94932012-12-22 10:35:39 -0500555 char *buf;
Brian Kernighan87b94932012-12-22 10:35:39 -0500556
557 ap = execute(a[1]); /* array name */
558 if (!isarr(ap)) {
559 dprintf( ("making %s into an array\n", ap->nval) );
560 if (freeable(ap))
561 xfree(ap->sval);
562 ap->tval &= ~(STR|NUM|DONTFREE);
563 ap->tval |= ARR;
564 ap->sval = (char *) makesymtab(NSYMTAB);
565 }
zoulasc0d8778b2019-10-25 10:59:10 -0400566 buf = makearraystring(a[0], __func__);
Brian Kernighan87b94932012-12-22 10:35:39 -0500567 k = lookup(buf, (Array *) ap->sval);
568 tempfree(ap);
569 free(buf);
570 if (k == NULL)
571 return(False);
572 else
573 return(True);
574}
575
576
577Cell *matchop(Node **a, int n) /* ~ and match() */
578{
579 Cell *x, *y;
580 char *s, *t;
581 int i;
582 fa *pfa;
583 int (*mf)(fa *, const char *) = match, mode = 0;
584
585 if (n == MATCHFCN) {
586 mf = pmatch;
587 mode = 1;
588 }
589 x = execute(a[1]); /* a[1] = target text */
590 s = getsval(x);
pfg52421942016-06-03 21:23:11 +0000591 if (a[0] == NULL) /* a[1] == 0: already-compiled reg expr */
Brian Kernighan87b94932012-12-22 10:35:39 -0500592 i = (*mf)((fa *) a[2], s);
593 else {
594 y = execute(a[2]); /* a[2] = regular expr */
595 t = getsval(y);
596 pfa = makedfa(t, mode);
597 i = (*mf)(pfa, s);
598 tempfree(y);
599 }
600 tempfree(x);
601 if (n == MATCHFCN) {
602 int start = patbeg - s + 1;
603 if (patlen < 0)
604 start = 0;
605 setfval(rstartloc, (Awkfloat) start);
606 setfval(rlengthloc, (Awkfloat) patlen);
607 x = gettemp();
608 x->tval = NUM;
609 x->fval = start;
610 return x;
611 } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
612 return(True);
613 else
614 return(False);
615}
616
617
618Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
619{
620 Cell *x, *y;
621 int i;
622
623 x = execute(a[0]);
624 i = istrue(x);
625 tempfree(x);
626 switch (n) {
627 case BOR:
628 if (i) return(True);
629 y = execute(a[1]);
630 i = istrue(y);
631 tempfree(y);
632 if (i) return(True);
633 else return(False);
634 case AND:
635 if ( !i ) return(False);
636 y = execute(a[1]);
637 i = istrue(y);
638 tempfree(y);
639 if (i) return(True);
640 else return(False);
641 case NOT:
642 if (i) return(False);
643 else return(True);
644 default: /* can't happen */
645 FATAL("unknown boolean operator %d", n);
646 }
647 return 0; /*NOTREACHED*/
648}
649
650Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
651{
652 int i;
653 Cell *x, *y;
654 Awkfloat j;
655
656 x = execute(a[0]);
657 y = execute(a[1]);
658 if (x->tval&NUM && y->tval&NUM) {
659 j = x->fval - y->fval;
660 i = j<0? -1: (j>0? 1: 0);
661 } else {
662 i = strcmp(getsval(x), getsval(y));
663 }
664 tempfree(x);
665 tempfree(y);
666 switch (n) {
667 case LT: if (i<0) return(True);
668 else return(False);
669 case LE: if (i<=0) return(True);
670 else return(False);
671 case NE: if (i!=0) return(True);
672 else return(False);
673 case EQ: if (i == 0) return(True);
674 else return(False);
675 case GE: if (i>=0) return(True);
676 else return(False);
677 case GT: if (i>0) return(True);
678 else return(False);
679 default: /* can't happen */
680 FATAL("unknown relational operator %d", n);
681 }
682 return 0; /*NOTREACHED*/
683}
684
685void tfree(Cell *a) /* free a tempcell */
686{
687 if (freeable(a)) {
688 dprintf( ("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval) );
689 xfree(a->sval);
690 }
691 if (a == tmps)
692 FATAL("tempcell list is curdled");
693 a->cnext = tmps;
694 tmps = a;
695}
696
697Cell *gettemp(void) /* get a tempcell */
698{ int i;
699 Cell *x;
700
701 if (!tmps) {
zoulasc65892082019-10-24 09:40:15 -0400702 tmps = calloc(100, sizeof(*tmps));
Brian Kernighan87b94932012-12-22 10:35:39 -0500703 if (!tmps)
704 FATAL("out of space for temporaries");
Arnold D. Robbins0ba1d032019-10-08 10:30:09 +0300705 for (i = 1; i < 100; i++)
Brian Kernighan87b94932012-12-22 10:35:39 -0500706 tmps[i-1].cnext = &tmps[i];
pfg52421942016-06-03 21:23:11 +0000707 tmps[i-1].cnext = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -0500708 }
709 x = tmps;
710 tmps = x->cnext;
711 *x = tempcell;
712 return(x);
713}
714
715Cell *indirect(Node **a, int n) /* $( a[0] ) */
716{
717 Awkfloat val;
718 Cell *x;
719 int m;
720 char *s;
721
722 x = execute(a[0]);
723 val = getfval(x); /* freebsd: defend against super large field numbers */
724 if ((Awkfloat)INT_MAX < val)
725 FATAL("trying to access out of range field %s", x->nval);
726 m = (int) val;
727 if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */
728 FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
729 /* BUG: can x->nval ever be null??? */
730 tempfree(x);
731 x = fieldadr(m);
732 x->ctype = OCELL; /* BUG? why are these needed? */
733 x->csub = CFLD;
734 return(x);
735}
736
737Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
738{
739 int k, m, n;
740 char *s;
741 int temp;
pfg52421942016-06-03 21:23:11 +0000742 Cell *x, *y, *z = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -0500743
744 x = execute(a[0]);
745 y = execute(a[1]);
pfg52421942016-06-03 21:23:11 +0000746 if (a[2] != NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500747 z = execute(a[2]);
748 s = getsval(x);
749 k = strlen(s) + 1;
750 if (k <= 1) {
751 tempfree(x);
752 tempfree(y);
pfg52421942016-06-03 21:23:11 +0000753 if (a[2] != NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -0500754 tempfree(z);
755 }
756 x = gettemp();
757 setsval(x, "");
758 return(x);
759 }
760 m = (int) getfval(y);
761 if (m <= 0)
762 m = 1;
763 else if (m > k)
764 m = k;
765 tempfree(y);
pfg52421942016-06-03 21:23:11 +0000766 if (a[2] != NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -0500767 n = (int) getfval(z);
768 tempfree(z);
769 } else
770 n = k - 1;
771 if (n < 0)
772 n = 0;
773 else if (n > k - m)
774 n = k - m;
775 dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
776 y = gettemp();
777 temp = s[n+m-1]; /* with thanks to John Linderman */
778 s[n+m-1] = '\0';
779 setsval(y, s + m - 1);
780 s[n+m-1] = temp;
781 tempfree(x);
782 return(y);
783}
784
785Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
786{
787 Cell *x, *y, *z;
788 char *s1, *s2, *p1, *p2, *q;
789 Awkfloat v = 0.0;
790
791 x = execute(a[0]);
792 s1 = getsval(x);
793 y = execute(a[1]);
794 s2 = getsval(y);
795
796 z = gettemp();
797 for (p1 = s1; *p1 != '\0'; p1++) {
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200798 for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++)
799 continue;
Brian Kernighan87b94932012-12-22 10:35:39 -0500800 if (*p2 == '\0') {
801 v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
802 break;
803 }
804 }
805 tempfree(x);
806 tempfree(y);
807 setfval(z, v);
808 return(z);
809}
810
811#define MAXNUMSIZE 50
812
813int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */
814{
815 char *fmt;
816 char *p, *t;
817 const char *os;
818 Cell *x;
819 int flag = 0, n;
820 int fmtwd; /* format width */
821 int fmtsz = recsize;
822 char *buf = *pbuf;
823 int bufsize = *pbufsize;
zoulasc0d8778b2019-10-25 10:59:10 -0400824#define FMTSZ(a) (fmtsz - ((a) - fmt))
825#define BUFSZ(a) (bufsize - ((a) - buf))
Brian Kernighan87b94932012-12-22 10:35:39 -0500826
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200827 static bool first = true;
828 static bool have_a_format = false;
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300829
830 if (first) {
831 char buf[100];
832
zoulasc0d8778b2019-10-25 10:59:10 -0400833 snprintf(buf, sizeof(buf), "%a", 42.0);
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300834 have_a_format = (strcmp(buf, "0x1.5p+5") == 0);
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200835 first = false;
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300836 }
837
Brian Kernighan87b94932012-12-22 10:35:39 -0500838 os = s;
839 p = buf;
zoulasc65892082019-10-24 09:40:15 -0400840 if ((fmt = malloc(fmtsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500841 FATAL("out of memory in format()");
842 while (*s) {
843 adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1");
844 if (*s != '%') {
845 *p++ = *s++;
846 continue;
847 }
848 if (*(s+1) == '%') {
849 *p++ = '%';
850 s += 2;
851 continue;
852 }
853 /* have to be real careful in case this is a huge number, eg, %100000d */
854 fmtwd = atoi(s+1);
855 if (fmtwd < 0)
856 fmtwd = -fmtwd;
857 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format2");
858 for (t = fmt; (*t++ = *s) != '\0'; s++) {
859 if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3"))
860 FATAL("format item %.30s... ran format() out of memory", os);
zoulasca96aebb2019-12-11 02:17:34 -0500861 /* Ignore size specifiers */
Arnold D. Robbins0b82bc62019-12-11 09:24:38 +0200862 if (strchr("hjLlqtz", *s) != NULL) { /* the ansi panoply */
zoulasca96aebb2019-12-11 02:17:34 -0500863 t--;
864 continue;
865 }
866 if (isalpha((uschar)*s))
Arnold D. Robbins0b82bc62019-12-11 09:24:38 +0200867 break;
Brian Kernighan22aff9e2018-08-27 08:52:34 -0400868 if (*s == '$') {
869 FATAL("'$' not permitted in awk formats");
870 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500871 if (*s == '*') {
Cody Peter Mello6cf37e92018-09-14 17:29:06 -0700872 if (a == NULL) {
873 FATAL("not enough args in printf(%s)", os);
874 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500875 x = execute(a);
876 a = a->nnext;
zoulasc0d8778b2019-10-25 10:59:10 -0400877 snprintf(t - 1, FMTSZ(t - 1),
878 "%d", fmtwd=(int) getfval(x));
Brian Kernighan87b94932012-12-22 10:35:39 -0500879 if (fmtwd < 0)
880 fmtwd = -fmtwd;
881 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
882 t = fmt + strlen(fmt);
883 tempfree(x);
884 }
885 }
886 *t = '\0';
887 if (fmtwd < 0)
888 fmtwd = -fmtwd;
889 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4");
Brian Kernighan87b94932012-12-22 10:35:39 -0500890 switch (*s) {
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300891 case 'a': case 'A':
892 if (have_a_format)
893 flag = *s;
894 else
895 flag = 'f';
896 break;
Brian Kernighan87b94932012-12-22 10:35:39 -0500897 case 'f': case 'e': case 'g': case 'E': case 'G':
898 flag = 'f';
899 break;
zoulasca96aebb2019-12-11 02:17:34 -0500900 case 'd': case 'i': case 'o': case 'x': case 'X': case 'u':
Arnold D. Robbins0b82bc62019-12-11 09:24:38 +0200901 flag = (*s == 'd' || *s == 'i') ? 'd' : 'u';
zoulascff5d6762019-12-08 14:41:27 -0500902 *(t-1) = 'j';
zoulasc0d8778b2019-10-25 10:59:10 -0400903 *t = *s;
904 *++t = '\0';
Brian Kernighan87b94932012-12-22 10:35:39 -0500905 break;
906 case 's':
907 flag = 's';
908 break;
909 case 'c':
910 flag = 'c';
911 break;
912 default:
913 WARNING("weird printf conversion %s", fmt);
914 flag = '?';
915 break;
916 }
917 if (a == NULL)
918 FATAL("not enough args in printf(%s)", os);
919 x = execute(a);
920 a = a->nnext;
921 n = MAXNUMSIZE;
922 if (fmtwd > n)
923 n = fmtwd;
924 adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5");
925 switch (flag) {
zoulasc0d8778b2019-10-25 10:59:10 -0400926 case '?': snprintf(p, BUFSZ(p), "%s", fmt); /* unknown, so dump it too */
Brian Kernighan87b94932012-12-22 10:35:39 -0500927 t = getsval(x);
928 n = strlen(t);
929 if (fmtwd > n)
930 n = fmtwd;
931 adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6");
932 p += strlen(p);
zoulasc0d8778b2019-10-25 10:59:10 -0400933 snprintf(p, BUFSZ(p), "%s", t);
Brian Kernighan87b94932012-12-22 10:35:39 -0500934 break;
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300935 case 'a':
936 case 'A':
zoulasc0d8778b2019-10-25 10:59:10 -0400937 case 'f': snprintf(p, BUFSZ(p), fmt, getfval(x)); break;
zoulascff5d6762019-12-08 14:41:27 -0500938 case 'd': snprintf(p, BUFSZ(p), fmt, (intmax_t) getfval(x)); break;
939 case 'u': snprintf(p, BUFSZ(p), fmt, (uintmax_t) getfval(x)); break;
Brian Kernighan87b94932012-12-22 10:35:39 -0500940 case 's':
941 t = getsval(x);
942 n = strlen(t);
943 if (fmtwd > n)
944 n = fmtwd;
945 if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7"))
946 FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
zoulasc0d8778b2019-10-25 10:59:10 -0400947 snprintf(p, BUFSZ(p), fmt, t);
Brian Kernighan87b94932012-12-22 10:35:39 -0500948 break;
949 case 'c':
950 if (isnum(x)) {
M. Warner Losh966fdc92019-06-02 14:53:15 -0600951 if ((int)getfval(x))
zoulasc0d8778b2019-10-25 10:59:10 -0400952 snprintf(p, BUFSZ(p), fmt, (int) getfval(x));
Brian Kernighan87b94932012-12-22 10:35:39 -0500953 else {
954 *p++ = '\0'; /* explicit null byte */
955 *p = '\0'; /* next output will start here */
956 }
957 } else
zoulasc0d8778b2019-10-25 10:59:10 -0400958 snprintf(p, BUFSZ(p), fmt, getsval(x)[0]);
Brian Kernighan87b94932012-12-22 10:35:39 -0500959 break;
960 default:
961 FATAL("can't happen: bad conversion %c in format()", flag);
962 }
963 tempfree(x);
964 p += strlen(p);
965 s++;
966 }
967 *p = '\0';
968 free(fmt);
969 for ( ; a; a = a->nnext) /* evaluate any remaining args */
970 execute(a);
971 *pbuf = buf;
972 *pbufsize = bufsize;
973 return p - buf;
974}
975
976Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
977{
978 Cell *x;
979 Node *y;
980 char *buf;
981 int bufsz=3*recsize;
982
zoulasc65892082019-10-24 09:40:15 -0400983 if ((buf = malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500984 FATAL("out of memory in awksprintf");
985 y = a[0]->nnext;
986 x = execute(a[0]);
987 if (format(&buf, &bufsz, getsval(x), y) == -1)
988 FATAL("sprintf string %.30s... too long. can't happen.", buf);
989 tempfree(x);
990 x = gettemp();
991 x->sval = buf;
992 x->tval = STR;
993 return(x);
994}
995
996Cell *awkprintf(Node **a, int n) /* printf */
997{ /* a[0] is list of args, starting with format string */
998 /* a[1] is redirection operator, a[2] is redirection file */
999 FILE *fp;
1000 Cell *x;
1001 Node *y;
1002 char *buf;
1003 int len;
1004 int bufsz=3*recsize;
1005
zoulasc65892082019-10-24 09:40:15 -04001006 if ((buf = malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001007 FATAL("out of memory in awkprintf");
1008 y = a[0]->nnext;
1009 x = execute(a[0]);
1010 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
1011 FATAL("printf string %.30s... too long. can't happen.", buf);
1012 tempfree(x);
1013 if (a[1] == NULL) {
1014 /* fputs(buf, stdout); */
1015 fwrite(buf, len, 1, stdout);
1016 if (ferror(stdout))
1017 FATAL("write error on stdout");
1018 } else {
1019 fp = redirect(ptoi(a[1]), a[2]);
1020 /* fputs(buf, fp); */
1021 fwrite(buf, len, 1, fp);
1022 fflush(fp);
1023 if (ferror(fp))
1024 FATAL("write error on %s", filename(fp));
1025 }
1026 free(buf);
1027 return(True);
1028}
1029
1030Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
1031{
1032 Awkfloat i, j = 0;
1033 double v;
1034 Cell *x, *y, *z;
1035
1036 x = execute(a[0]);
1037 i = getfval(x);
1038 tempfree(x);
Arnold D. Robbins32093f52018-08-22 20:40:26 +03001039 if (n != UMINUS && n != UPLUS) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001040 y = execute(a[1]);
1041 j = getfval(y);
1042 tempfree(y);
1043 }
1044 z = gettemp();
1045 switch (n) {
1046 case ADD:
1047 i += j;
1048 break;
1049 case MINUS:
1050 i -= j;
1051 break;
1052 case MULT:
1053 i *= j;
1054 break;
1055 case DIVIDE:
1056 if (j == 0)
1057 FATAL("division by zero");
1058 i /= j;
1059 break;
1060 case MOD:
1061 if (j == 0)
1062 FATAL("division by zero in mod");
1063 modf(i/j, &v);
1064 i = i - j * v;
1065 break;
1066 case UMINUS:
1067 i = -i;
1068 break;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001069 case UPLUS: /* handled by getfval(), above */
Arnold D. Robbins32093f52018-08-22 20:40:26 +03001070 break;
Brian Kernighan87b94932012-12-22 10:35:39 -05001071 case POWER:
1072 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1073 i = ipow(i, (int) j);
1074 else
1075 i = errcheck(pow(i, j), "pow");
1076 break;
1077 default: /* can't happen */
1078 FATAL("illegal arithmetic operator %d", n);
1079 }
1080 setfval(z, i);
1081 return(z);
1082}
1083
1084double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
1085{
1086 double v;
1087
1088 if (n <= 0)
1089 return 1;
1090 v = ipow(x, n/2);
1091 if (n % 2 == 0)
1092 return v * v;
1093 else
1094 return x * v * v;
1095}
1096
1097Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
1098{
1099 Cell *x, *z;
1100 int k;
1101 Awkfloat xf;
1102
1103 x = execute(a[0]);
1104 xf = getfval(x);
1105 k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1106 if (n == PREINCR || n == PREDECR) {
1107 setfval(x, xf + k);
1108 return(x);
1109 }
1110 z = gettemp();
1111 setfval(z, xf);
1112 setfval(x, xf + k);
1113 tempfree(x);
1114 return(z);
1115}
1116
1117Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
1118{ /* this is subtle; don't muck with it. */
1119 Cell *x, *y;
1120 Awkfloat xf, yf;
1121 double v;
1122
1123 y = execute(a[1]);
1124 x = execute(a[0]);
1125 if (n == ASSIGN) { /* ordinary assignment */
Cody Peter Mello63155252018-09-23 17:59:52 -07001126 if (x == y && !(x->tval & (FLD|REC)) && x != nfloc)
1127 ; /* self-assignment: leave alone unless it's a field or NF */
Brian Kernighan87b94932012-12-22 10:35:39 -05001128 else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1129 setsval(x, getsval(y));
1130 x->fval = getfval(y);
1131 x->tval |= NUM;
1132 }
1133 else if (isstr(y))
1134 setsval(x, getsval(y));
1135 else if (isnum(y))
1136 setfval(x, getfval(y));
1137 else
1138 funnyvar(y, "read value of");
1139 tempfree(y);
1140 return(x);
1141 }
1142 xf = getfval(x);
1143 yf = getfval(y);
1144 switch (n) {
1145 case ADDEQ:
1146 xf += yf;
1147 break;
1148 case SUBEQ:
1149 xf -= yf;
1150 break;
1151 case MULTEQ:
1152 xf *= yf;
1153 break;
1154 case DIVEQ:
1155 if (yf == 0)
1156 FATAL("division by zero in /=");
1157 xf /= yf;
1158 break;
1159 case MODEQ:
1160 if (yf == 0)
1161 FATAL("division by zero in %%=");
1162 modf(xf/yf, &v);
1163 xf = xf - yf * v;
1164 break;
1165 case POWEQ:
1166 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1167 xf = ipow(xf, (int) yf);
1168 else
1169 xf = errcheck(pow(xf, yf), "pow");
1170 break;
1171 default:
1172 FATAL("illegal assignment operator %d", n);
1173 break;
1174 }
1175 tempfree(y);
1176 setfval(x, xf);
1177 return(x);
1178}
1179
1180Cell *cat(Node **a, int q) /* a[0] cat a[1] */
1181{
1182 Cell *x, *y, *z;
1183 int n1, n2;
Cody Peter Melloe2623742018-09-15 01:38:39 -07001184 char *s = NULL;
1185 int ssz = 0;
Brian Kernighan87b94932012-12-22 10:35:39 -05001186
1187 x = execute(a[0]);
Cody Peter Melloe2623742018-09-15 01:38:39 -07001188 n1 = strlen(getsval(x));
Cody Peter Melloe2623742018-09-15 01:38:39 -07001189
Brian Kernighan87b94932012-12-22 10:35:39 -05001190 y = execute(a[1]);
Cody Peter Melloe2623742018-09-15 01:38:39 -07001191 n2 = strlen(getsval(y));
Arnold D. Robbins1d6ddfd2019-10-24 10:06:10 -04001192
1193 adjbuf(&s, &ssz, n1 + n2 + 1, recsize, 0, "cat");
1194 memcpy(s, x->sval, n1);
1195 memcpy(s + n1, y->sval, n2);
1196 s[n1 + n2] = '\0';
Cody Peter Melloe2623742018-09-15 01:38:39 -07001197
Brian Kernighan87b94932012-12-22 10:35:39 -05001198 tempfree(x);
1199 tempfree(y);
Cody Peter Melloe2623742018-09-15 01:38:39 -07001200
Brian Kernighan87b94932012-12-22 10:35:39 -05001201 z = gettemp();
1202 z->sval = s;
1203 z->tval = STR;
Cody Peter Melloe2623742018-09-15 01:38:39 -07001204
Brian Kernighan87b94932012-12-22 10:35:39 -05001205 return(z);
1206}
1207
1208Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
1209{
1210 Cell *x;
1211
pfg52421942016-06-03 21:23:11 +00001212 if (a[0] == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001213 x = execute(a[1]);
1214 else {
1215 x = execute(a[0]);
1216 if (istrue(x)) {
1217 tempfree(x);
1218 x = execute(a[1]);
1219 }
1220 }
1221 return x;
1222}
1223
1224Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
1225{
1226 Cell *x;
1227 int pair;
1228
1229 pair = ptoi(a[3]);
1230 if (pairstack[pair] == 0) {
1231 x = execute(a[0]);
1232 if (istrue(x))
1233 pairstack[pair] = 1;
1234 tempfree(x);
1235 }
1236 if (pairstack[pair] == 1) {
1237 x = execute(a[1]);
1238 if (istrue(x))
1239 pairstack[pair] = 0;
1240 tempfree(x);
1241 x = execute(a[2]);
1242 return(x);
1243 }
1244 return(False);
1245}
1246
1247Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
1248{
pfg52421942016-06-03 21:23:11 +00001249 Cell *x = NULL, *y, *ap;
zoulasc65892082019-10-24 09:40:15 -04001250 const char *s, *origs, *t;
zoulasc6a877092020-01-24 04:11:59 -05001251 const char *fs = NULL;
1252 char *origfs = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -05001253 int sep;
zoulasc65892082019-10-24 09:40:15 -04001254 char temp, num[50];
Brian Kernighan87b94932012-12-22 10:35:39 -05001255 int n, tempstat, arg3type;
1256
1257 y = execute(a[0]); /* source string */
1258 origs = s = strdup(getsval(y));
1259 arg3type = ptoi(a[3]);
pfg52421942016-06-03 21:23:11 +00001260 if (a[2] == NULL) /* fs string */
Cody Peter Mello52566c02018-09-18 15:45:55 -07001261 fs = getsval(fsloc);
Brian Kernighan87b94932012-12-22 10:35:39 -05001262 else if (arg3type == STRING) { /* split(str,arr,"string") */
1263 x = execute(a[2]);
zoulasc6a877092020-01-24 04:11:59 -05001264 fs = origfs = strdup(getsval(x));
Cody Peter Mellod45db5e2018-09-18 15:20:44 -07001265 tempfree(x);
Brian Kernighan87b94932012-12-22 10:35:39 -05001266 } else if (arg3type == REGEXPR)
1267 fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1268 else
1269 FATAL("illegal type of split");
1270 sep = *fs;
1271 ap = execute(a[1]); /* array name */
1272 freesymtab(ap);
1273 dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs) );
1274 ap->tval &= ~STR;
1275 ap->tval |= ARR;
1276 ap->sval = (char *) makesymtab(NSYMTAB);
1277
1278 n = 0;
1279 if (arg3type == REGEXPR && strlen((char*)((fa*)a[2])->restr) == 0) {
1280 /* split(s, a, //); have to arrange that it looks like empty sep */
1281 arg3type = 0;
1282 fs = "";
1283 sep = 0;
1284 }
1285 if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) { /* reg expr */
1286 fa *pfa;
1287 if (arg3type == REGEXPR) { /* it's ready already */
1288 pfa = (fa *) a[2];
1289 } else {
1290 pfa = makedfa(fs, 1);
1291 }
1292 if (nematch(pfa,s)) {
1293 tempstat = pfa->initstat;
1294 pfa->initstat = 2;
1295 do {
1296 n++;
zoulasc0d8778b2019-10-25 10:59:10 -04001297 snprintf(num, sizeof(num), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -05001298 temp = *patbeg;
zoulasc65892082019-10-24 09:40:15 -04001299 setptr(patbeg, '\0');
Brian Kernighan87b94932012-12-22 10:35:39 -05001300 if (is_number(s))
1301 setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1302 else
1303 setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
zoulasc65892082019-10-24 09:40:15 -04001304 setptr(patbeg, temp);
Brian Kernighan87b94932012-12-22 10:35:39 -05001305 s = patbeg + patlen;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001306 if (*(patbeg+patlen-1) == '\0' || *s == '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05001307 n++;
zoulasc0d8778b2019-10-25 10:59:10 -04001308 snprintf(num, sizeof(num), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -05001309 setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1310 pfa->initstat = tempstat;
1311 goto spdone;
1312 }
1313 } while (nematch(pfa,s));
1314 pfa->initstat = tempstat; /* bwk: has to be here to reset */
1315 /* cf gsub and refldbld */
1316 }
1317 n++;
zoulasc0d8778b2019-10-25 10:59:10 -04001318 snprintf(num, sizeof(num), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -05001319 if (is_number(s))
1320 setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1321 else
1322 setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1323 spdone:
1324 pfa = NULL;
1325 } else if (sep == ' ') {
1326 for (n = 0; ; ) {
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001327#define ISWS(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
1328 while (ISWS(*s))
Brian Kernighan87b94932012-12-22 10:35:39 -05001329 s++;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001330 if (*s == '\0')
Brian Kernighan87b94932012-12-22 10:35:39 -05001331 break;
1332 n++;
1333 t = s;
1334 do
1335 s++;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001336 while (*s != '\0' && !ISWS(*s));
Brian Kernighan87b94932012-12-22 10:35:39 -05001337 temp = *s;
zoulasc65892082019-10-24 09:40:15 -04001338 setptr(s, '\0');
zoulasc0d8778b2019-10-25 10:59:10 -04001339 snprintf(num, sizeof(num), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -05001340 if (is_number(t))
1341 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1342 else
1343 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
zoulasc65892082019-10-24 09:40:15 -04001344 setptr(s, temp);
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001345 if (*s != '\0')
Brian Kernighan87b94932012-12-22 10:35:39 -05001346 s++;
1347 }
1348 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001349 for (n = 0; *s != '\0'; s++) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001350 char buf[2];
1351 n++;
zoulasc0d8778b2019-10-25 10:59:10 -04001352 snprintf(num, sizeof(num), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -05001353 buf[0] = *s;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001354 buf[1] = '\0';
Brian Kernighan87b94932012-12-22 10:35:39 -05001355 if (isdigit((uschar)buf[0]))
1356 setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1357 else
1358 setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1359 }
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001360 } else if (*s != '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05001361 for (;;) {
1362 n++;
1363 t = s;
1364 while (*s != sep && *s != '\n' && *s != '\0')
1365 s++;
1366 temp = *s;
zoulasc65892082019-10-24 09:40:15 -04001367 setptr(s, '\0');
zoulasc0d8778b2019-10-25 10:59:10 -04001368 snprintf(num, sizeof(num), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -05001369 if (is_number(t))
1370 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1371 else
1372 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
zoulasc65892082019-10-24 09:40:15 -04001373 setptr(s, temp);
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001374 if (*s++ == '\0')
Brian Kernighan87b94932012-12-22 10:35:39 -05001375 break;
1376 }
1377 }
1378 tempfree(ap);
1379 tempfree(y);
zoulasc65892082019-10-24 09:40:15 -04001380 xfree(origs);
1381 xfree(origfs);
Brian Kernighan87b94932012-12-22 10:35:39 -05001382 x = gettemp();
1383 x->tval = NUM;
1384 x->fval = n;
1385 return(x);
1386}
1387
1388Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1389{
1390 Cell *x;
1391
1392 x = execute(a[0]);
1393 if (istrue(x)) {
1394 tempfree(x);
1395 x = execute(a[1]);
1396 } else {
1397 tempfree(x);
1398 x = execute(a[2]);
1399 }
1400 return(x);
1401}
1402
1403Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1404{
1405 Cell *x;
1406
1407 x = execute(a[0]);
1408 if (istrue(x)) {
1409 tempfree(x);
1410 x = execute(a[1]);
pfg52421942016-06-03 21:23:11 +00001411 } else if (a[2] != NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001412 tempfree(x);
1413 x = execute(a[2]);
1414 }
1415 return(x);
1416}
1417
1418Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
1419{
1420 Cell *x;
1421
1422 for (;;) {
1423 x = execute(a[0]);
1424 if (!istrue(x))
1425 return(x);
1426 tempfree(x);
1427 x = execute(a[1]);
1428 if (isbreak(x)) {
1429 x = True;
1430 return(x);
1431 }
1432 if (isnext(x) || isexit(x) || isret(x))
1433 return(x);
1434 tempfree(x);
1435 }
1436}
1437
1438Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
1439{
1440 Cell *x;
1441
1442 for (;;) {
1443 x = execute(a[0]);
1444 if (isbreak(x))
1445 return True;
1446 if (isnext(x) || isexit(x) || isret(x))
1447 return(x);
1448 tempfree(x);
1449 x = execute(a[1]);
1450 if (!istrue(x))
1451 return(x);
1452 tempfree(x);
1453 }
1454}
1455
1456Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
1457{
1458 Cell *x;
1459
1460 x = execute(a[0]);
1461 tempfree(x);
1462 for (;;) {
pfg52421942016-06-03 21:23:11 +00001463 if (a[1]!=NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001464 x = execute(a[1]);
1465 if (!istrue(x)) return(x);
1466 else tempfree(x);
1467 }
1468 x = execute(a[3]);
1469 if (isbreak(x)) /* turn off break */
1470 return True;
1471 if (isnext(x) || isexit(x) || isret(x))
1472 return(x);
1473 tempfree(x);
1474 x = execute(a[2]);
1475 tempfree(x);
1476 }
1477}
1478
1479Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1480{
1481 Cell *x, *vp, *arrayp, *cp, *ncp;
1482 Array *tp;
1483 int i;
1484
1485 vp = execute(a[0]);
1486 arrayp = execute(a[1]);
1487 if (!isarr(arrayp)) {
1488 return True;
1489 }
1490 tp = (Array *) arrayp->sval;
1491 tempfree(arrayp);
1492 for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1493 for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1494 setsval(vp, cp->nval);
1495 ncp = cp->cnext;
1496 x = execute(a[2]);
1497 if (isbreak(x)) {
1498 tempfree(vp);
1499 return True;
1500 }
1501 if (isnext(x) || isexit(x) || isret(x)) {
1502 tempfree(vp);
1503 return(x);
1504 }
1505 tempfree(x);
1506 }
1507 }
1508 return True;
1509}
1510
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001511static char *nawk_convert(const char *s, int (*fun_c)(int),
1512 wint_t (*fun_wc)(wint_t))
1513{
1514 char *buf = NULL;
1515 char *pbuf = NULL;
1516 const char *ps = NULL;
1517 size_t n = 0;
1518 mbstate_t mbs, mbs2;
1519 wchar_t wc;
1520 size_t sz = MB_CUR_MAX;
1521
1522 if (sz == 1) {
1523 buf = tostring(s);
1524
1525 for (pbuf = buf; *pbuf; pbuf++)
1526 *pbuf = fun_c((uschar)*pbuf);
1527
1528 return buf;
1529 } else {
1530 /* upper/lower character may be shorter/longer */
1531 buf = tostringN(s, strlen(s) * sz + 1);
1532
1533 memset(&mbs, 0, sizeof(mbs));
1534 memset(&mbs2, 0, sizeof(mbs2));
1535
1536 ps = s;
1537 pbuf = buf;
1538 while (n = mbrtowc(&wc, ps, sz, &mbs),
1539 n > 0 && n != (size_t)-1 && n != (size_t)-2)
1540 {
1541 ps += n;
1542
1543 n = wcrtomb(pbuf, fun_wc(wc), &mbs2);
1544 if (n == (size_t)-1)
1545 FATAL("illegal wide character %s", s);
1546
1547 pbuf += n;
1548 }
1549
1550 *pbuf = '\0';
1551
1552 if (n)
1553 FATAL("illegal byte sequence %s", s);
1554
1555 return buf;
1556 }
1557}
1558
1559static char *nawk_toupper(const char *s)
1560{
1561 return nawk_convert(s, toupper, towupper);
1562}
1563
1564static char *nawk_tolower(const char *s)
1565{
1566 return nawk_convert(s, tolower, towlower);
1567}
1568
Brian Kernighan87b94932012-12-22 10:35:39 -05001569Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
1570{
1571 Cell *x, *y;
1572 Awkfloat u;
1573 int t;
1574 Awkfloat tmp;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001575 char *buf;
Brian Kernighan87b94932012-12-22 10:35:39 -05001576 Node *nextarg;
1577 FILE *fp;
Arnold D. Robbins32093f52018-08-22 20:40:26 +03001578 int status = 0;
Brian Kernighan87b94932012-12-22 10:35:39 -05001579
1580 t = ptoi(a[0]);
1581 x = execute(a[1]);
1582 nextarg = a[1]->nnext;
1583 switch (t) {
1584 case FLENGTH:
1585 if (isarr(x))
1586 u = ((Array *) x->sval)->nelem; /* GROT. should be function*/
1587 else
1588 u = strlen(getsval(x));
1589 break;
1590 case FLOG:
1591 u = errcheck(log(getfval(x)), "log"); break;
1592 case FINT:
1593 modf(getfval(x), &u); break;
1594 case FEXP:
1595 u = errcheck(exp(getfval(x)), "exp"); break;
1596 case FSQRT:
1597 u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1598 case FSIN:
1599 u = sin(getfval(x)); break;
1600 case FCOS:
1601 u = cos(getfval(x)); break;
1602 case FATAN:
pfg52421942016-06-03 21:23:11 +00001603 if (nextarg == NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001604 WARNING("atan2 requires two arguments; returning 1.0");
1605 u = 1.0;
1606 } else {
1607 y = execute(a[1]->nnext);
1608 u = atan2(getfval(x), getfval(y));
1609 tempfree(y);
1610 nextarg = nextarg->nnext;
1611 }
1612 break;
1613 case FSYSTEM:
1614 fflush(stdout); /* in case something is buffered already */
Arnold D. Robbins32093f52018-08-22 20:40:26 +03001615 status = system(getsval(x));
1616 u = status;
1617 if (status != -1) {
1618 if (WIFEXITED(status)) {
1619 u = WEXITSTATUS(status);
1620 } else if (WIFSIGNALED(status)) {
1621 u = WTERMSIG(status) + 256;
1622#ifdef WCOREDUMP
1623 if (WCOREDUMP(status))
1624 u += 256;
1625#endif
1626 } else /* something else?!? */
1627 u = 0;
1628 }
Brian Kernighan87b94932012-12-22 10:35:39 -05001629 break;
1630 case FRAND:
pfgc70b9fe2014-09-19 18:24:02 +00001631 /* random() returns numbers in [0..2^31-1]
1632 * in order to get a number in [0, 1), divide it by 2^31
1633 */
1634 u = (Awkfloat) random() / (0x7fffffffL + 0x1UL);
Brian Kernighan87b94932012-12-22 10:35:39 -05001635 break;
1636 case FSRAND:
1637 if (isrec(x)) /* no argument provided */
1638 u = time((time_t *)0);
1639 else
1640 u = getfval(x);
1641 tmp = u;
pfgc70b9fe2014-09-19 18:24:02 +00001642 srandom((unsigned long) u);
Brian Kernighan87b94932012-12-22 10:35:39 -05001643 u = srand_seed;
1644 srand_seed = tmp;
1645 break;
1646 case FTOUPPER:
1647 case FTOLOWER:
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001648 if (t == FTOUPPER)
1649 buf = nawk_toupper(getsval(x));
1650 else
1651 buf = nawk_tolower(getsval(x));
Brian Kernighan87b94932012-12-22 10:35:39 -05001652 tempfree(x);
1653 x = gettemp();
1654 setsval(x, buf);
1655 free(buf);
1656 return x;
1657 case FFLUSH:
1658 if (isrec(x) || strlen(getsval(x)) == 0) {
1659 flush_all(); /* fflush() or fflush("") -> all */
1660 u = 0;
1661 } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1662 u = EOF;
1663 else
1664 u = fflush(fp);
1665 break;
1666 default: /* can't happen */
1667 FATAL("illegal function type %d", t);
1668 break;
1669 }
1670 tempfree(x);
1671 x = gettemp();
1672 setfval(x, u);
pfg52421942016-06-03 21:23:11 +00001673 if (nextarg != NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001674 WARNING("warning: function has too many arguments");
1675 for ( ; nextarg; nextarg = nextarg->nnext)
1676 execute(nextarg);
1677 }
1678 return(x);
1679}
1680
1681Cell *printstat(Node **a, int n) /* print a[0] */
1682{
1683 Node *x;
1684 Cell *y;
1685 FILE *fp;
1686
pfg52421942016-06-03 21:23:11 +00001687 if (a[1] == NULL) /* a[1] is redirection operator, a[2] is file */
Brian Kernighan87b94932012-12-22 10:35:39 -05001688 fp = stdout;
1689 else
1690 fp = redirect(ptoi(a[1]), a[2]);
1691 for (x = a[0]; x != NULL; x = x->nnext) {
1692 y = execute(x);
1693 fputs(getpssval(y), fp);
1694 tempfree(y);
1695 if (x->nnext == NULL)
Cody Peter Mello52566c02018-09-18 15:45:55 -07001696 fputs(getsval(orsloc), fp);
Brian Kernighan87b94932012-12-22 10:35:39 -05001697 else
Cody Peter Mello52566c02018-09-18 15:45:55 -07001698 fputs(getsval(ofsloc), fp);
Brian Kernighan87b94932012-12-22 10:35:39 -05001699 }
pfg52421942016-06-03 21:23:11 +00001700 if (a[1] != NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001701 fflush(fp);
1702 if (ferror(fp))
1703 FATAL("write error on %s", filename(fp));
1704 return(True);
1705}
1706
1707Cell *nullproc(Node **a, int n)
1708{
Brian Kernighan87b94932012-12-22 10:35:39 -05001709 return 0;
1710}
1711
1712
1713FILE *redirect(int a, Node *b) /* set up all i/o redirections */
1714{
1715 FILE *fp;
1716 Cell *x;
1717 char *fname;
1718
1719 x = execute(b);
1720 fname = getsval(x);
1721 fp = openfile(a, fname);
1722 if (fp == NULL)
1723 FATAL("can't open file %s", fname);
1724 tempfree(x);
1725 return fp;
1726}
1727
1728struct files {
1729 FILE *fp;
1730 const char *fname;
1731 int mode; /* '|', 'a', 'w' => LE/LT, GT */
1732} *files;
1733
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001734size_t nfiles;
Brian Kernighan87b94932012-12-22 10:35:39 -05001735
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001736static void stdinit(void) /* in case stdin, etc., are not constants */
Brian Kernighan87b94932012-12-22 10:35:39 -05001737{
1738 nfiles = FOPEN_MAX;
1739 files = calloc(nfiles, sizeof(*files));
1740 if (files == NULL)
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001741 FATAL("can't allocate file memory for %zu files", nfiles);
Brian Kernighan87b94932012-12-22 10:35:39 -05001742 files[0].fp = stdin;
1743 files[0].fname = "/dev/stdin";
1744 files[0].mode = LT;
1745 files[1].fp = stdout;
1746 files[1].fname = "/dev/stdout";
1747 files[1].mode = GT;
1748 files[2].fp = stderr;
1749 files[2].fname = "/dev/stderr";
1750 files[2].mode = GT;
1751}
1752
1753FILE *openfile(int a, const char *us)
1754{
1755 const char *s = us;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001756 size_t i;
1757 int m;
pfg52421942016-06-03 21:23:11 +00001758 FILE *fp = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -05001759
1760 if (*s == '\0')
1761 FATAL("null file name in print or getline");
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001762 for (i = 0; i < nfiles; i++)
Brian Kernighan87b94932012-12-22 10:35:39 -05001763 if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1764 if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1765 return files[i].fp;
1766 if (a == FFLUSH)
1767 return files[i].fp;
1768 }
1769 if (a == FFLUSH) /* didn't find it, so don't create it! */
1770 return NULL;
1771
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001772 for (i = 0; i < nfiles; i++)
pfg52421942016-06-03 21:23:11 +00001773 if (files[i].fp == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001774 break;
1775 if (i >= nfiles) {
1776 struct files *nf;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001777 size_t nnf = nfiles + FOPEN_MAX;
Brian Kernighan87b94932012-12-22 10:35:39 -05001778 nf = realloc(files, nnf * sizeof(*nf));
1779 if (nf == NULL)
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001780 FATAL("cannot grow files for %s and %zu files", s, nnf);
Brian Kernighan87b94932012-12-22 10:35:39 -05001781 memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf));
1782 nfiles = nnf;
1783 files = nf;
1784 }
1785 fflush(stdout); /* force a semblance of order */
1786 m = a;
1787 if (a == GT) {
1788 fp = fopen(s, "w");
1789 } else if (a == APPEND) {
1790 fp = fopen(s, "a");
1791 m = GT; /* so can mix > and >> */
1792 } else if (a == '|') { /* output pipe */
1793 fp = popen(s, "w");
1794 } else if (a == LE) { /* input pipe */
1795 fp = popen(s, "r");
1796 } else if (a == LT) { /* getline <file */
1797 fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
1798 } else /* can't happen */
1799 FATAL("illegal redirection %d", a);
1800 if (fp != NULL) {
1801 files[i].fname = tostring(s);
1802 files[i].fp = fp;
1803 files[i].mode = m;
Arnold D. Robbins5a18f632020-01-22 02:10:59 -07001804 if (fp != stdin && fp != stdout && fp != stderr)
1805 (void) fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
Brian Kernighan87b94932012-12-22 10:35:39 -05001806 }
1807 return fp;
1808}
1809
1810const char *filename(FILE *fp)
1811{
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001812 size_t i;
Brian Kernighan87b94932012-12-22 10:35:39 -05001813
1814 for (i = 0; i < nfiles; i++)
1815 if (fp == files[i].fp)
1816 return files[i].fname;
1817 return "???";
1818}
1819
Arnold D. Robbinscd552112020-02-06 22:32:55 +02001820 Cell *closefile(Node **a, int n)
1821 {
1822 Cell *x;
1823 size_t i;
1824 bool stat;
1825
1826 x = execute(a[0]);
1827 getsval(x);
1828 stat = true;
1829 for (i = 0; i < nfiles; i++) {
1830 if (!files[i].fname || strcmp(x->sval, files[i].fname) != 0)
1831 continue;
1832 if (ferror(files[i].fp))
1833 FATAL("i/o error occurred on %s", files[i].fname);
1834 if (files[i].mode == '|' || files[i].mode == LE)
1835 stat = pclose(files[i].fp) == -1;
1836 else
1837 stat = fclose(files[i].fp) == EOF;
1838 if (stat)
1839 FATAL("i/o error occurred closing %s", files[i].fname);
1840 if (i > 2) /* don't do /dev/std... */
1841 xfree(files[i].fname);
1842 files[i].fname = NULL; /* watch out for ref thru this */
1843 files[i].fp = NULL;
1844 }
1845 tempfree(x);
1846 x = gettemp();
1847 setfval(x, (Awkfloat) (stat ? -1 : 0));
1848 return(x);
1849 }
Brian Kernighan87b94932012-12-22 10:35:39 -05001850
1851void closeall(void)
1852{
Arnold D. Robbinse6fe6742020-02-06 22:38:30 +02001853 size_t i;
1854 bool stat = false;
Brian Kernighan87b94932012-12-22 10:35:39 -05001855
Arnold D. Robbinse6fe6742020-02-06 22:38:30 +02001856 for (i = 0; i < nfiles; i++) {
1857 if (! files[i].fp)
1858 continue;
1859 if (ferror(files[i].fp))
1860 FATAL( "i/o error occurred on %s", files[i].fname );
1861 if (files[i].mode == '|' || files[i].mode == LE)
1862 stat = pclose(files[i].fp) == -1;
1863 else
1864 stat = fclose(files[i].fp) == EOF;
1865 if (stat)
1866 FATAL( "i/o error occurred while closing %s", files[i].fname );
Brian Kernighan87b94932012-12-22 10:35:39 -05001867 }
1868}
1869
Arnold D. Robbinse6fe6742020-02-06 22:38:30 +02001870static void flush_all(void)
Brian Kernighan87b94932012-12-22 10:35:39 -05001871{
1872 int i;
1873
1874 for (i = 0; i < nfiles; i++)
1875 if (files[i].fp)
1876 fflush(files[i].fp);
1877}
1878
zoulasc65892082019-10-24 09:40:15 -04001879void backsub(char **pb_ptr, const char **sptr_ptr);
Brian Kernighan87b94932012-12-22 10:35:39 -05001880
1881Cell *sub(Node **a, int nnn) /* substitute command */
1882{
zoulasc65892082019-10-24 09:40:15 -04001883 const char *sptr, *q;
Brian Kernighan87b94932012-12-22 10:35:39 -05001884 Cell *x, *y, *result;
zoulasc65892082019-10-24 09:40:15 -04001885 char *t, *buf, *pb;
Brian Kernighan87b94932012-12-22 10:35:39 -05001886 fa *pfa;
1887 int bufsz = recsize;
1888
Arnold D. Robbins938b26c2019-10-25 11:01:17 -04001889 if ((buf = malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001890 FATAL("out of memory in sub");
1891 x = execute(a[3]); /* target string */
1892 t = getsval(x);
pfg52421942016-06-03 21:23:11 +00001893 if (a[0] == NULL) /* 0 => a[1] is already-compiled regexpr */
Brian Kernighan87b94932012-12-22 10:35:39 -05001894 pfa = (fa *) a[1]; /* regular expression */
1895 else {
1896 y = execute(a[1]);
1897 pfa = makedfa(getsval(y), 1);
1898 tempfree(y);
1899 }
1900 y = execute(a[2]); /* replacement string */
1901 result = False;
1902 if (pmatch(pfa, t)) {
1903 sptr = t;
1904 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1905 pb = buf;
1906 while (sptr < patbeg)
1907 *pb++ = *sptr++;
1908 sptr = getsval(y);
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001909 while (*sptr != '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05001910 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1911 if (*sptr == '\\') {
1912 backsub(&pb, &sptr);
1913 } else if (*sptr == '&') {
1914 sptr++;
1915 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1916 for (q = patbeg; q < patbeg+patlen; )
1917 *pb++ = *q++;
1918 } else
1919 *pb++ = *sptr++;
1920 }
1921 *pb = '\0';
1922 if (pb > buf + bufsz)
1923 FATAL("sub result1 %.30s too big; can't happen", buf);
1924 sptr = patbeg + patlen;
1925 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1926 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001927 while ((*pb++ = *sptr++) != '\0')
1928 continue;
Brian Kernighan87b94932012-12-22 10:35:39 -05001929 }
1930 if (pb > buf + bufsz)
1931 FATAL("sub result2 %.30s too big; can't happen", buf);
1932 setsval(x, buf); /* BUG: should be able to avoid copy */
pfg52421942016-06-03 21:23:11 +00001933 result = True;
Brian Kernighan87b94932012-12-22 10:35:39 -05001934 }
1935 tempfree(x);
1936 tempfree(y);
1937 free(buf);
1938 return result;
1939}
1940
1941Cell *gsub(Node **a, int nnn) /* global substitute */
1942{
1943 Cell *x, *y;
zoulasc65892082019-10-24 09:40:15 -04001944 char *rptr, *pb;
1945 const char *q, *t, *sptr;
Brian Kernighan87b94932012-12-22 10:35:39 -05001946 char *buf;
1947 fa *pfa;
1948 int mflag, tempstat, num;
1949 int bufsz = recsize;
1950
zoulasc65892082019-10-24 09:40:15 -04001951 if ((buf = malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001952 FATAL("out of memory in gsub");
1953 mflag = 0; /* if mflag == 0, can replace empty string */
1954 num = 0;
1955 x = execute(a[3]); /* target string */
1956 t = getsval(x);
pfg52421942016-06-03 21:23:11 +00001957 if (a[0] == NULL) /* 0 => a[1] is already-compiled regexpr */
Brian Kernighan87b94932012-12-22 10:35:39 -05001958 pfa = (fa *) a[1]; /* regular expression */
1959 else {
1960 y = execute(a[1]);
1961 pfa = makedfa(getsval(y), 1);
1962 tempfree(y);
1963 }
1964 y = execute(a[2]); /* replacement string */
1965 if (pmatch(pfa, t)) {
1966 tempstat = pfa->initstat;
1967 pfa->initstat = 2;
1968 pb = buf;
1969 rptr = getsval(y);
1970 do {
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001971 if (patlen == 0 && *patbeg != '\0') { /* matched empty string */
Brian Kernighan87b94932012-12-22 10:35:39 -05001972 if (mflag == 0) { /* can replace empty */
1973 num++;
1974 sptr = rptr;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001975 while (*sptr != '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05001976 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1977 if (*sptr == '\\') {
1978 backsub(&pb, &sptr);
1979 } else if (*sptr == '&') {
1980 sptr++;
1981 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1982 for (q = patbeg; q < patbeg+patlen; )
1983 *pb++ = *q++;
1984 } else
1985 *pb++ = *sptr++;
1986 }
1987 }
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001988 if (*t == '\0') /* at end */
Brian Kernighan87b94932012-12-22 10:35:39 -05001989 goto done;
1990 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1991 *pb++ = *t++;
1992 if (pb > buf + bufsz) /* BUG: not sure of this test */
1993 FATAL("gsub result0 %.30s too big; can't happen", buf);
1994 mflag = 0;
1995 }
1996 else { /* matched nonempty string */
1997 num++;
1998 sptr = t;
1999 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
2000 while (sptr < patbeg)
2001 *pb++ = *sptr++;
2002 sptr = rptr;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002003 while (*sptr != '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05002004 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
2005 if (*sptr == '\\') {
2006 backsub(&pb, &sptr);
2007 } else if (*sptr == '&') {
2008 sptr++;
2009 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
2010 for (q = patbeg; q < patbeg+patlen; )
2011 *pb++ = *q++;
2012 } else
2013 *pb++ = *sptr++;
2014 }
2015 t = patbeg + patlen;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002016 if (patlen == 0 || *t == '\0' || *(t-1) == '\0')
Brian Kernighan87b94932012-12-22 10:35:39 -05002017 goto done;
2018 if (pb > buf + bufsz)
2019 FATAL("gsub result1 %.30s too big; can't happen", buf);
2020 mflag = 1;
2021 }
2022 } while (pmatch(pfa,t));
2023 sptr = t;
2024 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002025 while ((*pb++ = *sptr++) != '\0')
2026 continue;
Brian Kernighan87b94932012-12-22 10:35:39 -05002027 done: if (pb < buf + bufsz)
2028 *pb = '\0';
2029 else if (*(pb-1) != '\0')
2030 FATAL("gsub result2 %.30s truncated; can't happen", buf);
2031 setsval(x, buf); /* BUG: should be able to avoid copy + free */
2032 pfa->initstat = tempstat;
2033 }
2034 tempfree(x);
2035 tempfree(y);
2036 x = gettemp();
2037 x->tval = NUM;
2038 x->fval = num;
2039 free(buf);
2040 return(x);
2041}
2042
zoulasc65892082019-10-24 09:40:15 -04002043void backsub(char **pb_ptr, const char **sptr_ptr) /* handle \\& variations */
Brian Kernighan87b94932012-12-22 10:35:39 -05002044{ /* sptr[0] == '\\' */
zoulasc65892082019-10-24 09:40:15 -04002045 char *pb = *pb_ptr;
2046 const char *sptr = *sptr_ptr;
Arnold D. Robbinsde6284e2020-01-19 20:37:33 +02002047 static bool first = true;
2048 static bool do_posix = false;
2049
2050 if (first) {
2051 first = false;
2052 do_posix = (getenv("POSIXLY_CORRECT") != NULL);
2053 }
Brian Kernighan87b94932012-12-22 10:35:39 -05002054
2055 if (sptr[1] == '\\') {
2056 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
2057 *pb++ = '\\';
2058 *pb++ = '&';
2059 sptr += 4;
2060 } else if (sptr[2] == '&') { /* \\& -> \ + matched */
2061 *pb++ = '\\';
2062 sptr += 2;
Arnold D. Robbinsde6284e2020-01-19 20:37:33 +02002063 } else if (do_posix) { /* \\x -> \x */
2064 sptr++;
2065 *pb++ = *sptr++;
Brian Kernighan87b94932012-12-22 10:35:39 -05002066 } else { /* \\x -> \\x */
2067 *pb++ = *sptr++;
2068 *pb++ = *sptr++;
2069 }
2070 } else if (sptr[1] == '&') { /* literal & */
2071 sptr++;
2072 *pb++ = *sptr++;
2073 } else /* literal \ */
2074 *pb++ = *sptr++;
2075
2076 *pb_ptr = pb;
2077 *sptr_ptr = sptr;
2078}