blob: da4f555264eabfdb74407bc78bf74c24c899f2e7 [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>
Todd C. Millerb2de1c42020-06-12 05:16:12 -060028#include <errno.h>
Arnold D. Robbins5068d202020-02-06 22:27:31 +020029#include <wchar.h>
30#include <wctype.h>
Arnold D. Robbins5a18f632020-01-22 02:10:59 -070031#include <fcntl.h>
Brian Kernighan87b94932012-12-22 10:35:39 -050032#include <setjmp.h>
33#include <limits.h>
34#include <math.h>
35#include <string.h>
36#include <stdlib.h>
37#include <time.h>
Arnold D. Robbins32093f52018-08-22 20:40:26 +030038#include <sys/types.h>
39#include <sys/wait.h>
Brian Kernighan87b94932012-12-22 10:35:39 -050040#include "awk.h"
Arnold D. Robbins07f04382020-07-30 17:12:45 +030041#include "awkgram.tab.h"
Brian Kernighan87b94932012-12-22 10:35:39 -050042
Arnold D. Robbins5068d202020-02-06 22:27:31 +020043static void stdinit(void);
44static void flush_all(void);
Brian Kernighan87b94932012-12-22 10:35:39 -050045
Arnold D. Robbins5068d202020-02-06 22:27:31 +020046#if 1
47#define tempfree(x) do { if (istemp(x)) tfree(x); } while (/*CONSTCOND*/0)
48#else
Brian Kernighan87b94932012-12-22 10:35:39 -050049void tempfree(Cell *p) {
50 if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
51 WARNING("bad csub %d in Cell %d %s",
52 p->csub, p->ctype, p->sval);
53 }
54 if (istemp(p))
55 tfree(p);
56}
Arnold D. Robbins5068d202020-02-06 22:27:31 +020057#endif
Brian Kernighan87b94932012-12-22 10:35:39 -050058
59/* do we really need these? */
60/* #ifdef _NFILE */
61/* #ifndef FOPEN_MAX */
62/* #define FOPEN_MAX _NFILE */
63/* #endif */
64/* #endif */
65/* */
66/* #ifndef FOPEN_MAX */
67/* #define FOPEN_MAX 40 */ /* max number of open files */
68/* #endif */
69/* */
70/* #ifndef RAND_MAX */
71/* #define RAND_MAX 32767 */ /* all that ansi guarantees */
72/* #endif */
73
74jmp_buf env;
75extern int pairstack[];
76extern Awkfloat srand_seed;
77
78Node *winner = NULL; /* root of parse tree */
79Cell *tmps; /* free temporary cells for execution */
80
zoulascc2c8ecb2020-02-19 13:44:49 -050081static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM, NULL, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050082Cell *True = &truecell;
zoulascc2c8ecb2020-02-19 13:44:49 -050083static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM, NULL, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050084Cell *False = &falsecell;
zoulascc2c8ecb2020-02-19 13:44:49 -050085static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM, NULL, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050086Cell *jbreak = &breakcell;
zoulascc2c8ecb2020-02-19 13:44:49 -050087static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM, NULL, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050088Cell *jcont = &contcell;
zoulascc2c8ecb2020-02-19 13:44:49 -050089static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM, NULL, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050090Cell *jnext = &nextcell;
zoulascc2c8ecb2020-02-19 13:44:49 -050091static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM, NULL, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050092Cell *jnextfile = &nextfilecell;
zoulascc2c8ecb2020-02-19 13:44:49 -050093static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM, NULL, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050094Cell *jexit = &exitcell;
zoulascc2c8ecb2020-02-19 13:44:49 -050095static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM, NULL, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050096Cell *jret = &retcell;
zoulascc2c8ecb2020-02-19 13:44:49 -050097static Cell tempcell ={ OCELL, CTEMP, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050098
99Node *curnode = NULL; /* the node being executed, for debugging */
100
101/* buffer memory management */
102int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
103 const char *whatrtn)
104/* pbuf: address of pointer to buffer being managed
105 * psiz: address of buffer size variable
106 * minlen: minimum length of buffer needed
107 * quantum: buffer size quantum
108 * pbptr: address of movable pointer into buffer, or 0 if none
109 * whatrtn: name of the calling routine if failure should cause fatal error
110 *
111 * return 0 for realloc failure, !=0 for success
112 */
113{
114 if (minlen > *psiz) {
115 char *tbuf;
116 int rminlen = quantum ? minlen % quantum : 0;
117 int boff = pbptr ? *pbptr - *pbuf : 0;
118 /* round up to next multiple of quantum */
119 if (rminlen)
120 minlen += quantum - rminlen;
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300121 tbuf = (char *) realloc(*pbuf, minlen);
Chrisb7851412020-08-07 18:10:20 +0800122 DPRINTF("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, (void*)*pbuf, (void*)tbuf);
Brian Kernighan87b94932012-12-22 10:35:39 -0500123 if (tbuf == NULL) {
124 if (whatrtn)
125 FATAL("out of memory in %s", whatrtn);
126 return 0;
127 }
128 *pbuf = tbuf;
129 *psiz = minlen;
130 if (pbptr)
131 *pbptr = tbuf + boff;
132 }
133 return 1;
134}
135
136void run(Node *a) /* execution of parse tree starts here */
137{
Brian Kernighan87b94932012-12-22 10:35:39 -0500138
139 stdinit();
140 execute(a);
141 closeall();
142}
143
144Cell *execute(Node *u) /* execute a node of the parse tree */
145{
146 Cell *(*proc)(Node **, int);
147 Cell *x;
148 Node *a;
149
150 if (u == NULL)
151 return(True);
152 for (a = u; ; a = a->nnext) {
153 curnode = a;
154 if (isvalue(a)) {
155 x = (Cell *) (a->narg[0]);
156 if (isfld(x) && !donefld)
157 fldbld();
158 else if (isrec(x) && !donerec)
159 recbld();
160 return(x);
161 }
162 if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */
163 FATAL("illegal statement");
164 proc = proctab[a->nobj-FIRSTTOKEN];
165 x = (*proc)(a->narg, a->nobj);
166 if (isfld(x) && !donefld)
167 fldbld();
168 else if (isrec(x) && !donerec)
169 recbld();
170 if (isexpr(a))
171 return(x);
172 if (isjump(x))
173 return(x);
174 if (a->nnext == NULL)
175 return(x);
176 tempfree(x);
177 }
178}
179
180
181Cell *program(Node **a, int n) /* execute an awk program */
182{ /* a[0] = BEGIN, a[1] = body, a[2] = END */
183 Cell *x;
184
185 if (setjmp(env) != 0)
186 goto ex;
187 if (a[0]) { /* BEGIN */
188 x = execute(a[0]);
189 if (isexit(x))
190 return(True);
191 if (isjump(x))
192 FATAL("illegal break, continue, next or nextfile from BEGIN");
193 tempfree(x);
194 }
195 if (a[1] || a[2])
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200196 while (getrec(&record, &recsize, true) > 0) {
Brian Kernighan87b94932012-12-22 10:35:39 -0500197 x = execute(a[1]);
198 if (isexit(x))
199 break;
200 tempfree(x);
201 }
202 ex:
203 if (setjmp(env) != 0) /* handles exit within END */
204 goto ex1;
205 if (a[2]) { /* END */
206 x = execute(a[2]);
207 if (isbreak(x) || isnext(x) || iscont(x))
208 FATAL("illegal break, continue, next or nextfile from END");
209 tempfree(x);
210 }
211 ex1:
212 return(True);
213}
214
215struct Frame { /* stack frame for awk function calls */
216 int nargs; /* number of arguments in this call */
217 Cell *fcncell; /* pointer to Cell for function */
218 Cell **args; /* pointer to array of arguments after execute */
219 Cell *retval; /* return value */
220};
221
222#define NARGS 50 /* max args in a call */
223
224struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
225int nframe = 0; /* number of frames allocated */
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200226struct Frame *frp = NULL; /* frame pointer. bottom level unused */
Brian Kernighan87b94932012-12-22 10:35:39 -0500227
228Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
229{
zoulascc2c8ecb2020-02-19 13:44:49 -0500230 static const Cell newcopycell = { OCELL, CCOPY, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -0500231 int i, ncall, ndef;
232 int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */
233 Node *x;
234 Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */
235 Cell *y, *z, *fcn;
236 char *s;
237
238 fcn = execute(a[0]); /* the function itself */
239 s = fcn->nval;
240 if (!isfcn(fcn))
241 FATAL("calling undefined function %s", s);
242 if (frame == NULL) {
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300243 frp = frame = (struct Frame *) calloc(nframe += 100, sizeof(*frame));
Brian Kernighan87b94932012-12-22 10:35:39 -0500244 if (frame == NULL)
245 FATAL("out of space for stack frames calling %s", s);
246 }
247 for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
248 ncall++;
249 ndef = (int) fcn->fval; /* args in defn */
Todd C. Miller292d39f2020-06-25 12:32:34 -0600250 DPRINTF("calling %s, %d args (%d in defn), frp=%d\n", s, ncall, ndef, (int) (frp-frame));
Brian Kernighan87b94932012-12-22 10:35:39 -0500251 if (ncall > ndef)
252 WARNING("function %s called with %d args, uses only %d",
253 s, ncall, ndef);
254 if (ncall + ndef > NARGS)
255 FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
256 for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */
Todd C. Miller292d39f2020-06-25 12:32:34 -0600257 DPRINTF("evaluate args[%d], frp=%d:\n", i, (int) (frp-frame));
Brian Kernighan87b94932012-12-22 10:35:39 -0500258 y = execute(x);
259 oargs[i] = y;
Todd C. Miller292d39f2020-06-25 12:32:34 -0600260 DPRINTF("args[%d]: %s %f <%s>, t=%o\n",
261 i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval);
Brian Kernighan87b94932012-12-22 10:35:39 -0500262 if (isfcn(y))
263 FATAL("can't use function %s as argument in %s", y->nval, s);
264 if (isarr(y))
265 args[i] = y; /* arrays by ref */
266 else
267 args[i] = copycell(y);
268 tempfree(y);
269 }
270 for ( ; i < ndef; i++) { /* add null args for ones not provided */
271 args[i] = gettemp();
272 *args[i] = newcopycell;
273 }
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200274 frp++; /* now ok to up frame */
275 if (frp >= frame + nframe) {
276 int dfp = frp - frame; /* old index */
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300277 frame = (struct Frame *) realloc(frame, (nframe += 100) * sizeof(*frame));
Brian Kernighan87b94932012-12-22 10:35:39 -0500278 if (frame == NULL)
279 FATAL("out of space for stack frames in %s", s);
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200280 frp = frame + dfp;
Brian Kernighan87b94932012-12-22 10:35:39 -0500281 }
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200282 frp->fcncell = fcn;
283 frp->args = args;
284 frp->nargs = ndef; /* number defined with (excess are locals) */
285 frp->retval = gettemp();
Brian Kernighan87b94932012-12-22 10:35:39 -0500286
Todd C. Miller292d39f2020-06-25 12:32:34 -0600287 DPRINTF("start exec of %s, frp=%d\n", s, (int) (frp-frame));
Brian Kernighan87b94932012-12-22 10:35:39 -0500288 y = execute((Node *)(fcn->sval)); /* execute body */
Todd C. Miller292d39f2020-06-25 12:32:34 -0600289 DPRINTF("finished exec of %s, frp=%d\n", s, (int) (frp-frame));
Brian Kernighan87b94932012-12-22 10:35:39 -0500290
291 for (i = 0; i < ndef; i++) {
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200292 Cell *t = frp->args[i];
Brian Kernighan87b94932012-12-22 10:35:39 -0500293 if (isarr(t)) {
294 if (t->csub == CCOPY) {
295 if (i >= ncall) {
296 freesymtab(t);
297 t->csub = CTEMP;
298 tempfree(t);
299 } else {
300 oargs[i]->tval = t->tval;
301 oargs[i]->tval &= ~(STR|NUM|DONTFREE);
302 oargs[i]->sval = t->sval;
303 tempfree(t);
304 }
305 }
306 } else if (t != y) { /* kludge to prevent freeing twice */
307 t->csub = CTEMP;
308 tempfree(t);
309 } else if (t == y && t->csub == CCOPY) {
310 t->csub = CTEMP;
311 tempfree(t);
312 freed = 1;
313 }
314 }
315 tempfree(fcn);
316 if (isexit(y) || isnext(y))
317 return y;
318 if (freed == 0) {
319 tempfree(y); /* don't free twice! */
320 }
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200321 z = frp->retval; /* return value */
Todd C. Miller292d39f2020-06-25 12:32:34 -0600322 DPRINTF("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval);
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200323 frp--;
Brian Kernighan87b94932012-12-22 10:35:39 -0500324 return(z);
325}
326
327Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
328{
329 Cell *y;
330
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300331 /* copy is not constant or field */
332
Brian Kernighan87b94932012-12-22 10:35:39 -0500333 y = gettemp();
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300334 y->tval = x->tval & ~(CON|FLD|REC);
Brian Kernighan87b94932012-12-22 10:35:39 -0500335 y->csub = CCOPY; /* prevents freeing until call is over */
336 y->nval = x->nval; /* BUG? */
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300337 if (isstr(x) /* || x->ctype == OCELL */) {
Brian Kernighan87b94932012-12-22 10:35:39 -0500338 y->sval = tostring(x->sval);
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300339 y->tval &= ~DONTFREE;
340 } else
341 y->tval |= DONTFREE;
Brian Kernighan87b94932012-12-22 10:35:39 -0500342 y->fval = x->fval;
Brian Kernighan87b94932012-12-22 10:35:39 -0500343 return y;
344}
345
346Cell *arg(Node **a, int n) /* nth argument of a function */
347{
348
349 n = ptoi(a[0]); /* argument number, counting from 0 */
Todd C. Miller292d39f2020-06-25 12:32:34 -0600350 DPRINTF("arg(%d), frp->nargs=%d\n", n, frp->nargs);
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200351 if (n+1 > frp->nargs)
Brian Kernighan87b94932012-12-22 10:35:39 -0500352 FATAL("argument #%d of function %s was not supplied",
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200353 n+1, frp->fcncell->nval);
354 return frp->args[n];
Brian Kernighan87b94932012-12-22 10:35:39 -0500355}
356
357Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
358{
359 Cell *y;
360
361 switch (n) {
362 case EXIT:
363 if (a[0] != NULL) {
364 y = execute(a[0]);
365 errorflag = (int) getfval(y);
366 tempfree(y);
367 }
368 longjmp(env, 1);
369 case RETURN:
370 if (a[0] != NULL) {
371 y = execute(a[0]);
372 if ((y->tval & (STR|NUM)) == (STR|NUM)) {
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200373 setsval(frp->retval, getsval(y));
374 frp->retval->fval = getfval(y);
375 frp->retval->tval |= NUM;
Brian Kernighan87b94932012-12-22 10:35:39 -0500376 }
377 else if (y->tval & STR)
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200378 setsval(frp->retval, getsval(y));
Brian Kernighan87b94932012-12-22 10:35:39 -0500379 else if (y->tval & NUM)
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200380 setfval(frp->retval, getfval(y));
Brian Kernighan87b94932012-12-22 10:35:39 -0500381 else /* can't happen */
382 FATAL("bad type variable %d", y->tval);
383 tempfree(y);
384 }
385 return(jret);
386 case NEXT:
387 return(jnext);
388 case NEXTFILE:
389 nextfile();
390 return(jnextfile);
391 case BREAK:
392 return(jbreak);
393 case CONTINUE:
394 return(jcont);
395 default: /* can't happen */
396 FATAL("illegal jump type %d", n);
397 }
398 return 0; /* not reached */
399}
400
401Cell *awkgetline(Node **a, int n) /* get next line from specific input */
402{ /* a[0] is variable, a[1] is operator, a[2] is filename */
403 Cell *r, *x;
404 extern Cell **fldtab;
405 FILE *fp;
406 char *buf;
407 int bufsize = recsize;
408 int mode;
zoulascffee7782020-02-28 06:23:54 -0500409 bool newflag;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200410 double result;
Brian Kernighan87b94932012-12-22 10:35:39 -0500411
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300412 if ((buf = (char *) malloc(bufsize)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500413 FATAL("out of memory in getline");
414
415 fflush(stdout); /* in case someone is waiting for a prompt */
416 r = gettemp();
417 if (a[1] != NULL) { /* getline < file */
418 x = execute(a[2]); /* filename */
419 mode = ptoi(a[1]);
420 if (mode == '|') /* input pipe */
421 mode = LE; /* arbitrary flag */
zoulascffee7782020-02-28 06:23:54 -0500422 fp = openfile(mode, getsval(x), &newflag);
Brian Kernighan87b94932012-12-22 10:35:39 -0500423 tempfree(x);
424 if (fp == NULL)
425 n = -1;
426 else
zoulascffee7782020-02-28 06:23:54 -0500427 n = readrec(&buf, &bufsize, fp, newflag);
Brian Kernighan87b94932012-12-22 10:35:39 -0500428 if (n <= 0) {
429 ;
430 } else if (a[0] != NULL) { /* getline var <file */
431 x = execute(a[0]);
432 setsval(x, buf);
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200433 if (is_number(x->sval, & result)) {
434 x->fval = result;
Arnold D. Robbins9dbd1f12019-01-25 12:56:06 +0200435 x->tval |= NUM;
436 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500437 tempfree(x);
438 } else { /* getline <file */
439 setsval(fldtab[0], buf);
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200440 if (is_number(fldtab[0]->sval, & result)) {
441 fldtab[0]->fval = result;
Brian Kernighan87b94932012-12-22 10:35:39 -0500442 fldtab[0]->tval |= NUM;
443 }
444 }
445 } else { /* bare getline; use current input */
446 if (a[0] == NULL) /* getline */
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200447 n = getrec(&record, &recsize, true);
Brian Kernighan87b94932012-12-22 10:35:39 -0500448 else { /* getline var */
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200449 n = getrec(&buf, &bufsize, false);
Brian Kernighan87b94932012-12-22 10:35:39 -0500450 x = execute(a[0]);
451 setsval(x, buf);
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200452 if (is_number(x->sval, & result)) {
453 x->fval = result;
Arnold D. Robbins9dbd1f12019-01-25 12:56:06 +0200454 x->tval |= NUM;
455 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500456 tempfree(x);
457 }
458 }
459 setfval(r, (Awkfloat) n);
460 free(buf);
461 return r;
462}
463
464Cell *getnf(Node **a, int n) /* get NF */
465{
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200466 if (!donefld)
Brian Kernighan87b94932012-12-22 10:35:39 -0500467 fldbld();
468 return (Cell *) a[0];
469}
470
zoulasc0d8778b2019-10-25 10:59:10 -0400471static char *
472makearraystring(Node *p, const char *func)
Brian Kernighan87b94932012-12-22 10:35:39 -0500473{
Brian Kernighan87b94932012-12-22 10:35:39 -0500474 char *buf;
475 int bufsz = recsize;
Tim van der Molenee5b49b2020-07-02 20:22:15 +0200476 size_t blen;
Brian Kernighan87b94932012-12-22 10:35:39 -0500477
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300478 if ((buf = (char *) malloc(bufsz)) == NULL) {
zoulasc0d8778b2019-10-25 10:59:10 -0400479 FATAL("%s: out of memory", func);
480 }
481
482 blen = 0;
483 buf[blen] = '\0';
zoulasc0d8778b2019-10-25 10:59:10 -0400484
485 for (; p; p = p->nnext) {
486 Cell *x = execute(p); /* expr */
487 char *s = getsval(x);
Tim van der Molenee5b49b2020-07-02 20:22:15 +0200488 size_t seplen = strlen(getsval(subseploc));
zoulasc0d8778b2019-10-25 10:59:10 -0400489 size_t nsub = p->nnext ? seplen : 0;
490 size_t slen = strlen(s);
491 size_t tlen = blen + slen + nsub;
492
493 if (!adjbuf(&buf, &bufsz, tlen + 1, recsize, 0, func)) {
494 FATAL("%s: out of memory %s[%s...]",
495 func, x->nval, buf);
496 }
497 memcpy(buf + blen, s, slen);
498 if (nsub) {
499 memcpy(buf + blen + slen, *SUBSEP, nsub);
500 }
501 buf[tlen] = '\0';
502 blen = tlen;
503 tempfree(x);
504 }
505 return buf;
506}
507
508Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
509{
510 Cell *x, *z;
511 char *buf;
Brian Kernighan87b94932012-12-22 10:35:39 -0500512
513 x = execute(a[0]); /* Cell* for symbol table */
zoulasc0d8778b2019-10-25 10:59:10 -0400514 buf = makearraystring(a[1], __func__);
Brian Kernighan87b94932012-12-22 10:35:39 -0500515 if (!isarr(x)) {
Todd C. Miller292d39f2020-06-25 12:32:34 -0600516 DPRINTF("making %s into an array\n", NN(x->nval));
Brian Kernighan87b94932012-12-22 10:35:39 -0500517 if (freeable(x))
518 xfree(x->sval);
519 x->tval &= ~(STR|NUM|DONTFREE);
520 x->tval |= ARR;
521 x->sval = (char *) makesymtab(NSYMTAB);
522 }
523 z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
524 z->ctype = OCELL;
525 z->csub = CVAR;
526 tempfree(x);
527 free(buf);
528 return(z);
529}
530
531Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
532{
zoulasc0d8778b2019-10-25 10:59:10 -0400533 Cell *x;
Brian Kernighan87b94932012-12-22 10:35:39 -0500534
535 x = execute(a[0]); /* Cell* for symbol table */
Cody Melloae99b752019-06-17 10:08:54 -0900536 if (x == symtabloc) {
537 FATAL("cannot delete SYMTAB or its elements");
538 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500539 if (!isarr(x))
540 return True;
pfg52421942016-06-03 21:23:11 +0000541 if (a[1] == NULL) { /* delete the elements, not the table */
Brian Kernighan87b94932012-12-22 10:35:39 -0500542 freesymtab(x);
543 x->tval &= ~STR;
544 x->tval |= ARR;
545 x->sval = (char *) makesymtab(NSYMTAB);
546 } else {
zoulasc0d8778b2019-10-25 10:59:10 -0400547 char *buf = makearraystring(a[1], __func__);
Brian Kernighan87b94932012-12-22 10:35:39 -0500548 freeelem(x, buf);
549 free(buf);
550 }
551 tempfree(x);
552 return True;
553}
554
555Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
556{
zoulasc0d8778b2019-10-25 10:59:10 -0400557 Cell *ap, *k;
Brian Kernighan87b94932012-12-22 10:35:39 -0500558 char *buf;
Brian Kernighan87b94932012-12-22 10:35:39 -0500559
560 ap = execute(a[1]); /* array name */
561 if (!isarr(ap)) {
Todd C. Miller292d39f2020-06-25 12:32:34 -0600562 DPRINTF("making %s into an array\n", ap->nval);
Brian Kernighan87b94932012-12-22 10:35:39 -0500563 if (freeable(ap))
564 xfree(ap->sval);
565 ap->tval &= ~(STR|NUM|DONTFREE);
566 ap->tval |= ARR;
567 ap->sval = (char *) makesymtab(NSYMTAB);
568 }
zoulasc0d8778b2019-10-25 10:59:10 -0400569 buf = makearraystring(a[0], __func__);
Brian Kernighan87b94932012-12-22 10:35:39 -0500570 k = lookup(buf, (Array *) ap->sval);
571 tempfree(ap);
572 free(buf);
573 if (k == NULL)
574 return(False);
575 else
576 return(True);
577}
578
579
580Cell *matchop(Node **a, int n) /* ~ and match() */
581{
582 Cell *x, *y;
583 char *s, *t;
584 int i;
585 fa *pfa;
586 int (*mf)(fa *, const char *) = match, mode = 0;
587
588 if (n == MATCHFCN) {
589 mf = pmatch;
590 mode = 1;
591 }
592 x = execute(a[1]); /* a[1] = target text */
593 s = getsval(x);
pfg52421942016-06-03 21:23:11 +0000594 if (a[0] == NULL) /* a[1] == 0: already-compiled reg expr */
Brian Kernighan87b94932012-12-22 10:35:39 -0500595 i = (*mf)((fa *) a[2], s);
596 else {
597 y = execute(a[2]); /* a[2] = regular expr */
598 t = getsval(y);
599 pfa = makedfa(t, mode);
600 i = (*mf)(pfa, s);
601 tempfree(y);
602 }
603 tempfree(x);
604 if (n == MATCHFCN) {
605 int start = patbeg - s + 1;
606 if (patlen < 0)
607 start = 0;
608 setfval(rstartloc, (Awkfloat) start);
609 setfval(rlengthloc, (Awkfloat) patlen);
610 x = gettemp();
611 x->tval = NUM;
612 x->fval = start;
613 return x;
614 } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
615 return(True);
616 else
617 return(False);
618}
619
620
621Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
622{
623 Cell *x, *y;
624 int i;
625
626 x = execute(a[0]);
627 i = istrue(x);
628 tempfree(x);
629 switch (n) {
630 case BOR:
631 if (i) return(True);
632 y = execute(a[1]);
633 i = istrue(y);
634 tempfree(y);
635 if (i) return(True);
636 else return(False);
637 case AND:
638 if ( !i ) return(False);
639 y = execute(a[1]);
640 i = istrue(y);
641 tempfree(y);
642 if (i) return(True);
643 else return(False);
644 case NOT:
645 if (i) return(False);
646 else return(True);
647 default: /* can't happen */
648 FATAL("unknown boolean operator %d", n);
649 }
650 return 0; /*NOTREACHED*/
651}
652
653Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
654{
655 int i;
656 Cell *x, *y;
657 Awkfloat j;
658
659 x = execute(a[0]);
660 y = execute(a[1]);
661 if (x->tval&NUM && y->tval&NUM) {
662 j = x->fval - y->fval;
663 i = j<0? -1: (j>0? 1: 0);
664 } else {
665 i = strcmp(getsval(x), getsval(y));
666 }
667 tempfree(x);
668 tempfree(y);
669 switch (n) {
670 case LT: if (i<0) return(True);
671 else return(False);
672 case LE: if (i<=0) return(True);
673 else return(False);
674 case NE: if (i!=0) return(True);
675 else return(False);
676 case EQ: if (i == 0) return(True);
677 else return(False);
678 case GE: if (i>=0) return(True);
679 else return(False);
680 case GT: if (i>0) return(True);
681 else return(False);
682 default: /* can't happen */
683 FATAL("unknown relational operator %d", n);
684 }
685 return 0; /*NOTREACHED*/
686}
687
688void tfree(Cell *a) /* free a tempcell */
689{
690 if (freeable(a)) {
Todd C. Miller292d39f2020-06-25 12:32:34 -0600691 DPRINTF("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval);
Brian Kernighan87b94932012-12-22 10:35:39 -0500692 xfree(a->sval);
693 }
694 if (a == tmps)
695 FATAL("tempcell list is curdled");
696 a->cnext = tmps;
697 tmps = a;
698}
699
700Cell *gettemp(void) /* get a tempcell */
701{ int i;
702 Cell *x;
703
704 if (!tmps) {
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300705 tmps = (Cell *) calloc(100, sizeof(*tmps));
Brian Kernighan87b94932012-12-22 10:35:39 -0500706 if (!tmps)
707 FATAL("out of space for temporaries");
Arnold D. Robbins0ba1d032019-10-08 10:30:09 +0300708 for (i = 1; i < 100; i++)
Brian Kernighan87b94932012-12-22 10:35:39 -0500709 tmps[i-1].cnext = &tmps[i];
pfg52421942016-06-03 21:23:11 +0000710 tmps[i-1].cnext = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -0500711 }
712 x = tmps;
713 tmps = x->cnext;
714 *x = tempcell;
715 return(x);
716}
717
718Cell *indirect(Node **a, int n) /* $( a[0] ) */
719{
720 Awkfloat val;
721 Cell *x;
722 int m;
723 char *s;
724
725 x = execute(a[0]);
726 val = getfval(x); /* freebsd: defend against super large field numbers */
727 if ((Awkfloat)INT_MAX < val)
728 FATAL("trying to access out of range field %s", x->nval);
729 m = (int) val;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200730 if (m == 0 && !is_number(s = getsval(x), NULL)) /* suspicion! */
Brian Kernighan87b94932012-12-22 10:35:39 -0500731 FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
732 /* BUG: can x->nval ever be null??? */
733 tempfree(x);
734 x = fieldadr(m);
735 x->ctype = OCELL; /* BUG? why are these needed? */
736 x->csub = CFLD;
737 return(x);
738}
739
740Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
741{
742 int k, m, n;
743 char *s;
744 int temp;
pfg52421942016-06-03 21:23:11 +0000745 Cell *x, *y, *z = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -0500746
747 x = execute(a[0]);
748 y = execute(a[1]);
pfg52421942016-06-03 21:23:11 +0000749 if (a[2] != NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500750 z = execute(a[2]);
751 s = getsval(x);
752 k = strlen(s) + 1;
753 if (k <= 1) {
754 tempfree(x);
755 tempfree(y);
pfg52421942016-06-03 21:23:11 +0000756 if (a[2] != NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -0500757 tempfree(z);
758 }
759 x = gettemp();
760 setsval(x, "");
761 return(x);
762 }
763 m = (int) getfval(y);
764 if (m <= 0)
765 m = 1;
766 else if (m > k)
767 m = k;
768 tempfree(y);
pfg52421942016-06-03 21:23:11 +0000769 if (a[2] != NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -0500770 n = (int) getfval(z);
771 tempfree(z);
772 } else
773 n = k - 1;
774 if (n < 0)
775 n = 0;
776 else if (n > k - m)
777 n = k - m;
Todd C. Miller292d39f2020-06-25 12:32:34 -0600778 DPRINTF("substr: m=%d, n=%d, s=%s\n", m, n, s);
Brian Kernighan87b94932012-12-22 10:35:39 -0500779 y = gettemp();
780 temp = s[n+m-1]; /* with thanks to John Linderman */
781 s[n+m-1] = '\0';
782 setsval(y, s + m - 1);
783 s[n+m-1] = temp;
784 tempfree(x);
785 return(y);
786}
787
788Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
789{
790 Cell *x, *y, *z;
791 char *s1, *s2, *p1, *p2, *q;
792 Awkfloat v = 0.0;
793
794 x = execute(a[0]);
795 s1 = getsval(x);
796 y = execute(a[1]);
797 s2 = getsval(y);
798
799 z = gettemp();
800 for (p1 = s1; *p1 != '\0'; p1++) {
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200801 for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++)
802 continue;
Brian Kernighan87b94932012-12-22 10:35:39 -0500803 if (*p2 == '\0') {
804 v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
805 break;
806 }
807 }
808 tempfree(x);
809 tempfree(y);
810 setfval(z, v);
811 return(z);
812}
813
814#define MAXNUMSIZE 50
815
816int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */
817{
818 char *fmt;
819 char *p, *t;
820 const char *os;
821 Cell *x;
822 int flag = 0, n;
823 int fmtwd; /* format width */
824 int fmtsz = recsize;
825 char *buf = *pbuf;
826 int bufsize = *pbufsize;
zoulasc0d8778b2019-10-25 10:59:10 -0400827#define FMTSZ(a) (fmtsz - ((a) - fmt))
828#define BUFSZ(a) (bufsize - ((a) - buf))
Brian Kernighan87b94932012-12-22 10:35:39 -0500829
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200830 static bool first = true;
831 static bool have_a_format = false;
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300832
833 if (first) {
zoulascc2c8ecb2020-02-19 13:44:49 -0500834 char xbuf[100];
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300835
zoulascc2c8ecb2020-02-19 13:44:49 -0500836 snprintf(xbuf, sizeof(xbuf), "%a", 42.0);
837 have_a_format = (strcmp(xbuf, "0x1.5p+5") == 0);
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200838 first = false;
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300839 }
840
Brian Kernighan87b94932012-12-22 10:35:39 -0500841 os = s;
842 p = buf;
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300843 if ((fmt = (char *) malloc(fmtsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500844 FATAL("out of memory in format()");
845 while (*s) {
846 adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1");
847 if (*s != '%') {
848 *p++ = *s++;
849 continue;
850 }
851 if (*(s+1) == '%') {
852 *p++ = '%';
853 s += 2;
854 continue;
855 }
856 /* have to be real careful in case this is a huge number, eg, %100000d */
857 fmtwd = atoi(s+1);
858 if (fmtwd < 0)
859 fmtwd = -fmtwd;
860 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format2");
861 for (t = fmt; (*t++ = *s) != '\0'; s++) {
862 if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3"))
863 FATAL("format item %.30s... ran format() out of memory", os);
zoulasca96aebb2019-12-11 02:17:34 -0500864 /* Ignore size specifiers */
Arnold D. Robbins0b82bc62019-12-11 09:24:38 +0200865 if (strchr("hjLlqtz", *s) != NULL) { /* the ansi panoply */
zoulasca96aebb2019-12-11 02:17:34 -0500866 t--;
867 continue;
868 }
869 if (isalpha((uschar)*s))
Arnold D. Robbins0b82bc62019-12-11 09:24:38 +0200870 break;
Brian Kernighan22aff9e2018-08-27 08:52:34 -0400871 if (*s == '$') {
872 FATAL("'$' not permitted in awk formats");
873 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500874 if (*s == '*') {
Cody Peter Mello6cf37e92018-09-14 17:29:06 -0700875 if (a == NULL) {
876 FATAL("not enough args in printf(%s)", os);
877 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500878 x = execute(a);
879 a = a->nnext;
zoulasc0d8778b2019-10-25 10:59:10 -0400880 snprintf(t - 1, FMTSZ(t - 1),
881 "%d", fmtwd=(int) getfval(x));
Brian Kernighan87b94932012-12-22 10:35:39 -0500882 if (fmtwd < 0)
883 fmtwd = -fmtwd;
884 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
885 t = fmt + strlen(fmt);
886 tempfree(x);
887 }
888 }
889 *t = '\0';
890 if (fmtwd < 0)
891 fmtwd = -fmtwd;
892 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4");
Brian Kernighan87b94932012-12-22 10:35:39 -0500893 switch (*s) {
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300894 case 'a': case 'A':
895 if (have_a_format)
896 flag = *s;
897 else
898 flag = 'f';
899 break;
Brian Kernighan87b94932012-12-22 10:35:39 -0500900 case 'f': case 'e': case 'g': case 'E': case 'G':
901 flag = 'f';
902 break;
zoulasca96aebb2019-12-11 02:17:34 -0500903 case 'd': case 'i': case 'o': case 'x': case 'X': case 'u':
Arnold D. Robbins0b82bc62019-12-11 09:24:38 +0200904 flag = (*s == 'd' || *s == 'i') ? 'd' : 'u';
zoulascff5d6762019-12-08 14:41:27 -0500905 *(t-1) = 'j';
zoulasc0d8778b2019-10-25 10:59:10 -0400906 *t = *s;
907 *++t = '\0';
Brian Kernighan87b94932012-12-22 10:35:39 -0500908 break;
909 case 's':
910 flag = 's';
911 break;
912 case 'c':
913 flag = 'c';
914 break;
915 default:
916 WARNING("weird printf conversion %s", fmt);
917 flag = '?';
918 break;
919 }
920 if (a == NULL)
921 FATAL("not enough args in printf(%s)", os);
922 x = execute(a);
923 a = a->nnext;
924 n = MAXNUMSIZE;
925 if (fmtwd > n)
926 n = fmtwd;
927 adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5");
928 switch (flag) {
zoulasc0d8778b2019-10-25 10:59:10 -0400929 case '?': snprintf(p, BUFSZ(p), "%s", fmt); /* unknown, so dump it too */
Brian Kernighan87b94932012-12-22 10:35:39 -0500930 t = getsval(x);
931 n = strlen(t);
932 if (fmtwd > n)
933 n = fmtwd;
934 adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6");
935 p += strlen(p);
zoulasc0d8778b2019-10-25 10:59:10 -0400936 snprintf(p, BUFSZ(p), "%s", t);
Brian Kernighan87b94932012-12-22 10:35:39 -0500937 break;
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300938 case 'a':
939 case 'A':
zoulasc0d8778b2019-10-25 10:59:10 -0400940 case 'f': snprintf(p, BUFSZ(p), fmt, getfval(x)); break;
zoulascff5d6762019-12-08 14:41:27 -0500941 case 'd': snprintf(p, BUFSZ(p), fmt, (intmax_t) getfval(x)); break;
942 case 'u': snprintf(p, BUFSZ(p), fmt, (uintmax_t) getfval(x)); break;
Brian Kernighan87b94932012-12-22 10:35:39 -0500943 case 's':
944 t = getsval(x);
945 n = strlen(t);
946 if (fmtwd > n)
947 n = fmtwd;
948 if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7"))
949 FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
zoulasc0d8778b2019-10-25 10:59:10 -0400950 snprintf(p, BUFSZ(p), fmt, t);
Brian Kernighan87b94932012-12-22 10:35:39 -0500951 break;
952 case 'c':
953 if (isnum(x)) {
M. Warner Losh966fdc92019-06-02 14:53:15 -0600954 if ((int)getfval(x))
zoulasc0d8778b2019-10-25 10:59:10 -0400955 snprintf(p, BUFSZ(p), fmt, (int) getfval(x));
Brian Kernighan87b94932012-12-22 10:35:39 -0500956 else {
957 *p++ = '\0'; /* explicit null byte */
958 *p = '\0'; /* next output will start here */
959 }
960 } else
zoulasc0d8778b2019-10-25 10:59:10 -0400961 snprintf(p, BUFSZ(p), fmt, getsval(x)[0]);
Brian Kernighan87b94932012-12-22 10:35:39 -0500962 break;
963 default:
964 FATAL("can't happen: bad conversion %c in format()", flag);
965 }
966 tempfree(x);
967 p += strlen(p);
968 s++;
969 }
970 *p = '\0';
971 free(fmt);
972 for ( ; a; a = a->nnext) /* evaluate any remaining args */
973 execute(a);
974 *pbuf = buf;
975 *pbufsize = bufsize;
976 return p - buf;
977}
978
979Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
980{
981 Cell *x;
982 Node *y;
983 char *buf;
984 int bufsz=3*recsize;
985
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300986 if ((buf = (char *) malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500987 FATAL("out of memory in awksprintf");
988 y = a[0]->nnext;
989 x = execute(a[0]);
990 if (format(&buf, &bufsz, getsval(x), y) == -1)
991 FATAL("sprintf string %.30s... too long. can't happen.", buf);
992 tempfree(x);
993 x = gettemp();
994 x->sval = buf;
995 x->tval = STR;
996 return(x);
997}
998
999Cell *awkprintf(Node **a, int n) /* printf */
1000{ /* a[0] is list of args, starting with format string */
1001 /* a[1] is redirection operator, a[2] is redirection file */
1002 FILE *fp;
1003 Cell *x;
1004 Node *y;
1005 char *buf;
1006 int len;
1007 int bufsz=3*recsize;
1008
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +03001009 if ((buf = (char *) malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001010 FATAL("out of memory in awkprintf");
1011 y = a[0]->nnext;
1012 x = execute(a[0]);
1013 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
1014 FATAL("printf string %.30s... too long. can't happen.", buf);
1015 tempfree(x);
1016 if (a[1] == NULL) {
1017 /* fputs(buf, stdout); */
1018 fwrite(buf, len, 1, stdout);
1019 if (ferror(stdout))
1020 FATAL("write error on stdout");
1021 } else {
1022 fp = redirect(ptoi(a[1]), a[2]);
1023 /* fputs(buf, fp); */
1024 fwrite(buf, len, 1, fp);
1025 fflush(fp);
1026 if (ferror(fp))
1027 FATAL("write error on %s", filename(fp));
1028 }
1029 free(buf);
1030 return(True);
1031}
1032
1033Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
1034{
1035 Awkfloat i, j = 0;
1036 double v;
1037 Cell *x, *y, *z;
1038
1039 x = execute(a[0]);
1040 i = getfval(x);
1041 tempfree(x);
Arnold D. Robbins32093f52018-08-22 20:40:26 +03001042 if (n != UMINUS && n != UPLUS) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001043 y = execute(a[1]);
1044 j = getfval(y);
1045 tempfree(y);
1046 }
1047 z = gettemp();
1048 switch (n) {
1049 case ADD:
1050 i += j;
1051 break;
1052 case MINUS:
1053 i -= j;
1054 break;
1055 case MULT:
1056 i *= j;
1057 break;
1058 case DIVIDE:
1059 if (j == 0)
1060 FATAL("division by zero");
1061 i /= j;
1062 break;
1063 case MOD:
1064 if (j == 0)
1065 FATAL("division by zero in mod");
1066 modf(i/j, &v);
1067 i = i - j * v;
1068 break;
1069 case UMINUS:
1070 i = -i;
1071 break;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001072 case UPLUS: /* handled by getfval(), above */
Arnold D. Robbins32093f52018-08-22 20:40:26 +03001073 break;
Brian Kernighan87b94932012-12-22 10:35:39 -05001074 case POWER:
1075 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1076 i = ipow(i, (int) j);
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001077 else {
1078 errno = 0;
Brian Kernighan87b94932012-12-22 10:35:39 -05001079 i = errcheck(pow(i, j), "pow");
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001080 }
Brian Kernighan87b94932012-12-22 10:35:39 -05001081 break;
1082 default: /* can't happen */
1083 FATAL("illegal arithmetic operator %d", n);
1084 }
1085 setfval(z, i);
1086 return(z);
1087}
1088
1089double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
1090{
1091 double v;
1092
1093 if (n <= 0)
1094 return 1;
1095 v = ipow(x, n/2);
1096 if (n % 2 == 0)
1097 return v * v;
1098 else
1099 return x * v * v;
1100}
1101
1102Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
1103{
1104 Cell *x, *z;
1105 int k;
1106 Awkfloat xf;
1107
1108 x = execute(a[0]);
1109 xf = getfval(x);
1110 k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1111 if (n == PREINCR || n == PREDECR) {
1112 setfval(x, xf + k);
1113 return(x);
1114 }
1115 z = gettemp();
1116 setfval(z, xf);
1117 setfval(x, xf + k);
1118 tempfree(x);
1119 return(z);
1120}
1121
1122Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
1123{ /* this is subtle; don't muck with it. */
1124 Cell *x, *y;
1125 Awkfloat xf, yf;
1126 double v;
1127
1128 y = execute(a[1]);
1129 x = execute(a[0]);
1130 if (n == ASSIGN) { /* ordinary assignment */
Cody Peter Mello63155252018-09-23 17:59:52 -07001131 if (x == y && !(x->tval & (FLD|REC)) && x != nfloc)
1132 ; /* self-assignment: leave alone unless it's a field or NF */
Brian Kernighan87b94932012-12-22 10:35:39 -05001133 else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1134 setsval(x, getsval(y));
1135 x->fval = getfval(y);
1136 x->tval |= NUM;
1137 }
1138 else if (isstr(y))
1139 setsval(x, getsval(y));
1140 else if (isnum(y))
1141 setfval(x, getfval(y));
1142 else
1143 funnyvar(y, "read value of");
1144 tempfree(y);
1145 return(x);
1146 }
1147 xf = getfval(x);
1148 yf = getfval(y);
1149 switch (n) {
1150 case ADDEQ:
1151 xf += yf;
1152 break;
1153 case SUBEQ:
1154 xf -= yf;
1155 break;
1156 case MULTEQ:
1157 xf *= yf;
1158 break;
1159 case DIVEQ:
1160 if (yf == 0)
1161 FATAL("division by zero in /=");
1162 xf /= yf;
1163 break;
1164 case MODEQ:
1165 if (yf == 0)
1166 FATAL("division by zero in %%=");
1167 modf(xf/yf, &v);
1168 xf = xf - yf * v;
1169 break;
1170 case POWEQ:
1171 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1172 xf = ipow(xf, (int) yf);
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001173 else {
1174 errno = 0;
Brian Kernighan87b94932012-12-22 10:35:39 -05001175 xf = errcheck(pow(xf, yf), "pow");
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001176 }
Brian Kernighan87b94932012-12-22 10:35:39 -05001177 break;
1178 default:
1179 FATAL("illegal assignment operator %d", n);
1180 break;
1181 }
1182 tempfree(y);
1183 setfval(x, xf);
1184 return(x);
1185}
1186
1187Cell *cat(Node **a, int q) /* a[0] cat a[1] */
1188{
1189 Cell *x, *y, *z;
1190 int n1, n2;
Cody Peter Melloe2623742018-09-15 01:38:39 -07001191 char *s = NULL;
1192 int ssz = 0;
Brian Kernighan87b94932012-12-22 10:35:39 -05001193
1194 x = execute(a[0]);
Cody Peter Melloe2623742018-09-15 01:38:39 -07001195 n1 = strlen(getsval(x));
Tim van der Molencc19af12020-07-02 20:21:10 +02001196 adjbuf(&s, &ssz, n1, recsize, 0, "cat1");
1197 memcpy(s, x->sval, n1);
Cody Peter Melloe2623742018-09-15 01:38:39 -07001198
Brian Kernighan87b94932012-12-22 10:35:39 -05001199 y = execute(a[1]);
Cody Peter Melloe2623742018-09-15 01:38:39 -07001200 n2 = strlen(getsval(y));
Tim van der Molencc19af12020-07-02 20:21:10 +02001201 adjbuf(&s, &ssz, n1 + n2 + 1, recsize, 0, "cat2");
Arnold D. Robbins1d6ddfd2019-10-24 10:06:10 -04001202 memcpy(s + n1, y->sval, n2);
1203 s[n1 + n2] = '\0';
Cody Peter Melloe2623742018-09-15 01:38:39 -07001204
Brian Kernighan87b94932012-12-22 10:35:39 -05001205 tempfree(x);
1206 tempfree(y);
Cody Peter Melloe2623742018-09-15 01:38:39 -07001207
Brian Kernighan87b94932012-12-22 10:35:39 -05001208 z = gettemp();
1209 z->sval = s;
1210 z->tval = STR;
Cody Peter Melloe2623742018-09-15 01:38:39 -07001211
Brian Kernighan87b94932012-12-22 10:35:39 -05001212 return(z);
1213}
1214
1215Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
1216{
1217 Cell *x;
1218
pfg52421942016-06-03 21:23:11 +00001219 if (a[0] == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001220 x = execute(a[1]);
1221 else {
1222 x = execute(a[0]);
1223 if (istrue(x)) {
1224 tempfree(x);
1225 x = execute(a[1]);
1226 }
1227 }
1228 return x;
1229}
1230
1231Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
1232{
1233 Cell *x;
1234 int pair;
1235
1236 pair = ptoi(a[3]);
1237 if (pairstack[pair] == 0) {
1238 x = execute(a[0]);
1239 if (istrue(x))
1240 pairstack[pair] = 1;
1241 tempfree(x);
1242 }
1243 if (pairstack[pair] == 1) {
1244 x = execute(a[1]);
1245 if (istrue(x))
1246 pairstack[pair] = 0;
1247 tempfree(x);
1248 x = execute(a[2]);
1249 return(x);
1250 }
1251 return(False);
1252}
1253
1254Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
1255{
pfg52421942016-06-03 21:23:11 +00001256 Cell *x = NULL, *y, *ap;
zoulasc65892082019-10-24 09:40:15 -04001257 const char *s, *origs, *t;
zoulasc6a877092020-01-24 04:11:59 -05001258 const char *fs = NULL;
1259 char *origfs = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -05001260 int sep;
zoulasc65892082019-10-24 09:40:15 -04001261 char temp, num[50];
Brian Kernighan87b94932012-12-22 10:35:39 -05001262 int n, tempstat, arg3type;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +02001263 double result;
Brian Kernighan87b94932012-12-22 10:35:39 -05001264
1265 y = execute(a[0]); /* source string */
1266 origs = s = strdup(getsval(y));
1267 arg3type = ptoi(a[3]);
pfg52421942016-06-03 21:23:11 +00001268 if (a[2] == NULL) /* fs string */
Cody Peter Mello52566c02018-09-18 15:45:55 -07001269 fs = getsval(fsloc);
Brian Kernighan87b94932012-12-22 10:35:39 -05001270 else if (arg3type == STRING) { /* split(str,arr,"string") */
1271 x = execute(a[2]);
zoulasc6a877092020-01-24 04:11:59 -05001272 fs = origfs = strdup(getsval(x));
Cody Peter Mellod45db5e2018-09-18 15:20:44 -07001273 tempfree(x);
Brian Kernighan87b94932012-12-22 10:35:39 -05001274 } else if (arg3type == REGEXPR)
1275 fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1276 else
1277 FATAL("illegal type of split");
1278 sep = *fs;
1279 ap = execute(a[1]); /* array name */
1280 freesymtab(ap);
Todd C. Miller292d39f2020-06-25 12:32:34 -06001281 DPRINTF("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs);
Brian Kernighan87b94932012-12-22 10:35:39 -05001282 ap->tval &= ~STR;
1283 ap->tval |= ARR;
1284 ap->sval = (char *) makesymtab(NSYMTAB);
1285
1286 n = 0;
1287 if (arg3type == REGEXPR && strlen((char*)((fa*)a[2])->restr) == 0) {
1288 /* split(s, a, //); have to arrange that it looks like empty sep */
1289 arg3type = 0;
1290 fs = "";
1291 sep = 0;
1292 }
1293 if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) { /* reg expr */
1294 fa *pfa;
1295 if (arg3type == REGEXPR) { /* it's ready already */
1296 pfa = (fa *) a[2];
1297 } else {
1298 pfa = makedfa(fs, 1);
1299 }
1300 if (nematch(pfa,s)) {
1301 tempstat = pfa->initstat;
1302 pfa->initstat = 2;
1303 do {
1304 n++;
zoulasc0d8778b2019-10-25 10:59:10 -04001305 snprintf(num, sizeof(num), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -05001306 temp = *patbeg;
zoulasc65892082019-10-24 09:40:15 -04001307 setptr(patbeg, '\0');
Arnold Robbinscc9e9b62020-12-08 08:05:22 +02001308 if (is_number(s, & result))
1309 setsymtab(num, s, result, STR|NUM, (Array *) ap->sval);
Brian Kernighan87b94932012-12-22 10:35:39 -05001310 else
1311 setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
zoulasc65892082019-10-24 09:40:15 -04001312 setptr(patbeg, temp);
Brian Kernighan87b94932012-12-22 10:35:39 -05001313 s = patbeg + patlen;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001314 if (*(patbeg+patlen-1) == '\0' || *s == '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05001315 n++;
zoulasc0d8778b2019-10-25 10:59:10 -04001316 snprintf(num, sizeof(num), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -05001317 setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1318 pfa->initstat = tempstat;
1319 goto spdone;
1320 }
1321 } while (nematch(pfa,s));
1322 pfa->initstat = tempstat; /* bwk: has to be here to reset */
1323 /* cf gsub and refldbld */
1324 }
1325 n++;
zoulasc0d8778b2019-10-25 10:59:10 -04001326 snprintf(num, sizeof(num), "%d", n);
Arnold Robbinscc9e9b62020-12-08 08:05:22 +02001327 if (is_number(s, & result))
1328 setsymtab(num, s, result, STR|NUM, (Array *) ap->sval);
Brian Kernighan87b94932012-12-22 10:35:39 -05001329 else
1330 setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1331 spdone:
1332 pfa = NULL;
1333 } else if (sep == ' ') {
1334 for (n = 0; ; ) {
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001335#define ISWS(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
1336 while (ISWS(*s))
Brian Kernighan87b94932012-12-22 10:35:39 -05001337 s++;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001338 if (*s == '\0')
Brian Kernighan87b94932012-12-22 10:35:39 -05001339 break;
1340 n++;
1341 t = s;
1342 do
1343 s++;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001344 while (*s != '\0' && !ISWS(*s));
Brian Kernighan87b94932012-12-22 10:35:39 -05001345 temp = *s;
zoulasc65892082019-10-24 09:40:15 -04001346 setptr(s, '\0');
zoulasc0d8778b2019-10-25 10:59:10 -04001347 snprintf(num, sizeof(num), "%d", n);
Arnold Robbinscc9e9b62020-12-08 08:05:22 +02001348 if (is_number(t, & result))
1349 setsymtab(num, t, result, STR|NUM, (Array *) ap->sval);
Brian Kernighan87b94932012-12-22 10:35:39 -05001350 else
1351 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
zoulasc65892082019-10-24 09:40:15 -04001352 setptr(s, temp);
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001353 if (*s != '\0')
Brian Kernighan87b94932012-12-22 10:35:39 -05001354 s++;
1355 }
1356 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001357 for (n = 0; *s != '\0'; s++) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001358 char buf[2];
1359 n++;
zoulasc0d8778b2019-10-25 10:59:10 -04001360 snprintf(num, sizeof(num), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -05001361 buf[0] = *s;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001362 buf[1] = '\0';
Brian Kernighan87b94932012-12-22 10:35:39 -05001363 if (isdigit((uschar)buf[0]))
1364 setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1365 else
1366 setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1367 }
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001368 } else if (*s != '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05001369 for (;;) {
1370 n++;
1371 t = s;
1372 while (*s != sep && *s != '\n' && *s != '\0')
1373 s++;
1374 temp = *s;
zoulasc65892082019-10-24 09:40:15 -04001375 setptr(s, '\0');
zoulasc0d8778b2019-10-25 10:59:10 -04001376 snprintf(num, sizeof(num), "%d", n);
Arnold Robbinscc9e9b62020-12-08 08:05:22 +02001377 if (is_number(t, & result))
1378 setsymtab(num, t, result, STR|NUM, (Array *) ap->sval);
Brian Kernighan87b94932012-12-22 10:35:39 -05001379 else
1380 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
zoulasc65892082019-10-24 09:40:15 -04001381 setptr(s, temp);
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001382 if (*s++ == '\0')
Brian Kernighan87b94932012-12-22 10:35:39 -05001383 break;
1384 }
1385 }
1386 tempfree(ap);
1387 tempfree(y);
zoulasc65892082019-10-24 09:40:15 -04001388 xfree(origs);
1389 xfree(origfs);
Brian Kernighan87b94932012-12-22 10:35:39 -05001390 x = gettemp();
1391 x->tval = NUM;
1392 x->fval = n;
1393 return(x);
1394}
1395
1396Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1397{
1398 Cell *x;
1399
1400 x = execute(a[0]);
1401 if (istrue(x)) {
1402 tempfree(x);
1403 x = execute(a[1]);
1404 } else {
1405 tempfree(x);
1406 x = execute(a[2]);
1407 }
1408 return(x);
1409}
1410
1411Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1412{
1413 Cell *x;
1414
1415 x = execute(a[0]);
1416 if (istrue(x)) {
1417 tempfree(x);
1418 x = execute(a[1]);
pfg52421942016-06-03 21:23:11 +00001419 } else if (a[2] != NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001420 tempfree(x);
1421 x = execute(a[2]);
1422 }
1423 return(x);
1424}
1425
1426Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
1427{
1428 Cell *x;
1429
1430 for (;;) {
1431 x = execute(a[0]);
1432 if (!istrue(x))
1433 return(x);
1434 tempfree(x);
1435 x = execute(a[1]);
1436 if (isbreak(x)) {
1437 x = True;
1438 return(x);
1439 }
1440 if (isnext(x) || isexit(x) || isret(x))
1441 return(x);
1442 tempfree(x);
1443 }
1444}
1445
1446Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
1447{
1448 Cell *x;
1449
1450 for (;;) {
1451 x = execute(a[0]);
1452 if (isbreak(x))
1453 return True;
1454 if (isnext(x) || isexit(x) || isret(x))
1455 return(x);
1456 tempfree(x);
1457 x = execute(a[1]);
1458 if (!istrue(x))
1459 return(x);
1460 tempfree(x);
1461 }
1462}
1463
1464Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
1465{
1466 Cell *x;
1467
1468 x = execute(a[0]);
1469 tempfree(x);
1470 for (;;) {
pfg52421942016-06-03 21:23:11 +00001471 if (a[1]!=NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001472 x = execute(a[1]);
1473 if (!istrue(x)) return(x);
1474 else tempfree(x);
1475 }
1476 x = execute(a[3]);
1477 if (isbreak(x)) /* turn off break */
1478 return True;
1479 if (isnext(x) || isexit(x) || isret(x))
1480 return(x);
1481 tempfree(x);
1482 x = execute(a[2]);
1483 tempfree(x);
1484 }
1485}
1486
1487Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1488{
1489 Cell *x, *vp, *arrayp, *cp, *ncp;
1490 Array *tp;
1491 int i;
1492
1493 vp = execute(a[0]);
1494 arrayp = execute(a[1]);
1495 if (!isarr(arrayp)) {
1496 return True;
1497 }
1498 tp = (Array *) arrayp->sval;
1499 tempfree(arrayp);
1500 for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1501 for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1502 setsval(vp, cp->nval);
1503 ncp = cp->cnext;
1504 x = execute(a[2]);
1505 if (isbreak(x)) {
1506 tempfree(vp);
1507 return True;
1508 }
1509 if (isnext(x) || isexit(x) || isret(x)) {
1510 tempfree(vp);
1511 return(x);
1512 }
1513 tempfree(x);
1514 }
1515 }
1516 return True;
1517}
1518
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001519static char *nawk_convert(const char *s, int (*fun_c)(int),
1520 wint_t (*fun_wc)(wint_t))
1521{
1522 char *buf = NULL;
1523 char *pbuf = NULL;
1524 const char *ps = NULL;
1525 size_t n = 0;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001526 wchar_t wc;
1527 size_t sz = MB_CUR_MAX;
1528
1529 if (sz == 1) {
1530 buf = tostring(s);
1531
1532 for (pbuf = buf; *pbuf; pbuf++)
1533 *pbuf = fun_c((uschar)*pbuf);
1534
1535 return buf;
1536 } else {
1537 /* upper/lower character may be shorter/longer */
1538 buf = tostringN(s, strlen(s) * sz + 1);
1539
Arnold D. Robbins1b398462020-08-04 10:02:26 +03001540 (void) mbtowc(NULL, NULL, 0); /* reset internal state */
1541 /*
1542 * Reset internal state here too.
1543 * Assign result to avoid a compiler warning. (Casting to void
1544 * doesn't work.)
1545 * Increment said variable to avoid a different warning.
1546 */
1547 int unused = wctomb(NULL, L'\0');
1548 unused++;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001549
1550 ps = s;
1551 pbuf = buf;
Arnold D. Robbins1b398462020-08-04 10:02:26 +03001552 while (n = mbtowc(&wc, ps, sz),
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001553 n > 0 && n != (size_t)-1 && n != (size_t)-2)
1554 {
1555 ps += n;
1556
Arnold D. Robbins1b398462020-08-04 10:02:26 +03001557 n = wctomb(pbuf, fun_wc(wc));
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001558 if (n == (size_t)-1)
1559 FATAL("illegal wide character %s", s);
1560
1561 pbuf += n;
1562 }
1563
1564 *pbuf = '\0';
1565
1566 if (n)
1567 FATAL("illegal byte sequence %s", s);
1568
1569 return buf;
1570 }
1571}
1572
Arnold D. Robbins98042852020-08-16 18:48:05 +03001573#ifdef __DJGPP__
1574static wint_t towupper(wint_t wc)
1575{
1576 if (wc >= 0 && wc < 256)
1577 return toupper(wc & 0xFF);
1578
1579 return wc;
1580}
1581
1582static wint_t towlower(wint_t wc)
1583{
1584 if (wc >= 0 && wc < 256)
1585 return tolower(wc & 0xFF);
1586
1587 return wc;
1588}
1589#endif
1590
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001591static char *nawk_toupper(const char *s)
1592{
1593 return nawk_convert(s, toupper, towupper);
1594}
1595
1596static char *nawk_tolower(const char *s)
1597{
1598 return nawk_convert(s, tolower, towlower);
1599}
1600
Brian Kernighan87b94932012-12-22 10:35:39 -05001601Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
1602{
1603 Cell *x, *y;
1604 Awkfloat u;
1605 int t;
1606 Awkfloat tmp;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001607 char *buf;
Brian Kernighan87b94932012-12-22 10:35:39 -05001608 Node *nextarg;
1609 FILE *fp;
Arnold D. Robbins32093f52018-08-22 20:40:26 +03001610 int status = 0;
Brian Kernighan87b94932012-12-22 10:35:39 -05001611
1612 t = ptoi(a[0]);
1613 x = execute(a[1]);
1614 nextarg = a[1]->nnext;
1615 switch (t) {
1616 case FLENGTH:
1617 if (isarr(x))
1618 u = ((Array *) x->sval)->nelem; /* GROT. should be function*/
1619 else
1620 u = strlen(getsval(x));
1621 break;
1622 case FLOG:
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001623 errno = 0;
1624 u = errcheck(log(getfval(x)), "log");
1625 break;
Brian Kernighan87b94932012-12-22 10:35:39 -05001626 case FINT:
1627 modf(getfval(x), &u); break;
1628 case FEXP:
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001629 errno = 0;
1630 u = errcheck(exp(getfval(x)), "exp");
1631 break;
Brian Kernighan87b94932012-12-22 10:35:39 -05001632 case FSQRT:
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001633 errno = 0;
1634 u = errcheck(sqrt(getfval(x)), "sqrt");
1635 break;
Brian Kernighan87b94932012-12-22 10:35:39 -05001636 case FSIN:
1637 u = sin(getfval(x)); break;
1638 case FCOS:
1639 u = cos(getfval(x)); break;
1640 case FATAN:
pfg52421942016-06-03 21:23:11 +00001641 if (nextarg == NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001642 WARNING("atan2 requires two arguments; returning 1.0");
1643 u = 1.0;
1644 } else {
1645 y = execute(a[1]->nnext);
1646 u = atan2(getfval(x), getfval(y));
1647 tempfree(y);
1648 nextarg = nextarg->nnext;
1649 }
1650 break;
1651 case FSYSTEM:
1652 fflush(stdout); /* in case something is buffered already */
Arnold D. Robbins32093f52018-08-22 20:40:26 +03001653 status = system(getsval(x));
1654 u = status;
1655 if (status != -1) {
1656 if (WIFEXITED(status)) {
1657 u = WEXITSTATUS(status);
1658 } else if (WIFSIGNALED(status)) {
1659 u = WTERMSIG(status) + 256;
1660#ifdef WCOREDUMP
1661 if (WCOREDUMP(status))
1662 u += 256;
1663#endif
1664 } else /* something else?!? */
1665 u = 0;
1666 }
Brian Kernighan87b94932012-12-22 10:35:39 -05001667 break;
1668 case FRAND:
pfgc70b9fe2014-09-19 18:24:02 +00001669 /* random() returns numbers in [0..2^31-1]
1670 * in order to get a number in [0, 1), divide it by 2^31
1671 */
1672 u = (Awkfloat) random() / (0x7fffffffL + 0x1UL);
Brian Kernighan87b94932012-12-22 10:35:39 -05001673 break;
1674 case FSRAND:
1675 if (isrec(x)) /* no argument provided */
1676 u = time((time_t *)0);
1677 else
1678 u = getfval(x);
1679 tmp = u;
pfgc70b9fe2014-09-19 18:24:02 +00001680 srandom((unsigned long) u);
Brian Kernighan87b94932012-12-22 10:35:39 -05001681 u = srand_seed;
1682 srand_seed = tmp;
1683 break;
1684 case FTOUPPER:
1685 case FTOLOWER:
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001686 if (t == FTOUPPER)
1687 buf = nawk_toupper(getsval(x));
1688 else
1689 buf = nawk_tolower(getsval(x));
Brian Kernighan87b94932012-12-22 10:35:39 -05001690 tempfree(x);
1691 x = gettemp();
1692 setsval(x, buf);
1693 free(buf);
1694 return x;
1695 case FFLUSH:
1696 if (isrec(x) || strlen(getsval(x)) == 0) {
1697 flush_all(); /* fflush() or fflush("") -> all */
1698 u = 0;
zoulascffee7782020-02-28 06:23:54 -05001699 } else if ((fp = openfile(FFLUSH, getsval(x), NULL)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001700 u = EOF;
1701 else
1702 u = fflush(fp);
1703 break;
1704 default: /* can't happen */
1705 FATAL("illegal function type %d", t);
1706 break;
1707 }
1708 tempfree(x);
1709 x = gettemp();
1710 setfval(x, u);
pfg52421942016-06-03 21:23:11 +00001711 if (nextarg != NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001712 WARNING("warning: function has too many arguments");
1713 for ( ; nextarg; nextarg = nextarg->nnext)
1714 execute(nextarg);
1715 }
1716 return(x);
1717}
1718
1719Cell *printstat(Node **a, int n) /* print a[0] */
1720{
1721 Node *x;
1722 Cell *y;
1723 FILE *fp;
1724
pfg52421942016-06-03 21:23:11 +00001725 if (a[1] == NULL) /* a[1] is redirection operator, a[2] is file */
Brian Kernighan87b94932012-12-22 10:35:39 -05001726 fp = stdout;
1727 else
1728 fp = redirect(ptoi(a[1]), a[2]);
1729 for (x = a[0]; x != NULL; x = x->nnext) {
1730 y = execute(x);
1731 fputs(getpssval(y), fp);
1732 tempfree(y);
1733 if (x->nnext == NULL)
Cody Peter Mello52566c02018-09-18 15:45:55 -07001734 fputs(getsval(orsloc), fp);
Brian Kernighan87b94932012-12-22 10:35:39 -05001735 else
Cody Peter Mello52566c02018-09-18 15:45:55 -07001736 fputs(getsval(ofsloc), fp);
Brian Kernighan87b94932012-12-22 10:35:39 -05001737 }
pfg52421942016-06-03 21:23:11 +00001738 if (a[1] != NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001739 fflush(fp);
1740 if (ferror(fp))
1741 FATAL("write error on %s", filename(fp));
1742 return(True);
1743}
1744
1745Cell *nullproc(Node **a, int n)
1746{
Brian Kernighan87b94932012-12-22 10:35:39 -05001747 return 0;
1748}
1749
1750
1751FILE *redirect(int a, Node *b) /* set up all i/o redirections */
1752{
1753 FILE *fp;
1754 Cell *x;
1755 char *fname;
1756
1757 x = execute(b);
1758 fname = getsval(x);
zoulascffee7782020-02-28 06:23:54 -05001759 fp = openfile(a, fname, NULL);
Brian Kernighan87b94932012-12-22 10:35:39 -05001760 if (fp == NULL)
1761 FATAL("can't open file %s", fname);
1762 tempfree(x);
1763 return fp;
1764}
1765
1766struct files {
1767 FILE *fp;
1768 const char *fname;
1769 int mode; /* '|', 'a', 'w' => LE/LT, GT */
1770} *files;
1771
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001772size_t nfiles;
Brian Kernighan87b94932012-12-22 10:35:39 -05001773
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001774static void stdinit(void) /* in case stdin, etc., are not constants */
Brian Kernighan87b94932012-12-22 10:35:39 -05001775{
1776 nfiles = FOPEN_MAX;
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +03001777 files = (struct files *) calloc(nfiles, sizeof(*files));
Brian Kernighan87b94932012-12-22 10:35:39 -05001778 if (files == NULL)
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001779 FATAL("can't allocate file memory for %zu files", nfiles);
Brian Kernighan87b94932012-12-22 10:35:39 -05001780 files[0].fp = stdin;
1781 files[0].fname = "/dev/stdin";
1782 files[0].mode = LT;
1783 files[1].fp = stdout;
1784 files[1].fname = "/dev/stdout";
1785 files[1].mode = GT;
1786 files[2].fp = stderr;
1787 files[2].fname = "/dev/stderr";
1788 files[2].mode = GT;
1789}
1790
zoulascffee7782020-02-28 06:23:54 -05001791FILE *openfile(int a, const char *us, bool *pnewflag)
Brian Kernighan87b94932012-12-22 10:35:39 -05001792{
1793 const char *s = us;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001794 size_t i;
1795 int m;
pfg52421942016-06-03 21:23:11 +00001796 FILE *fp = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -05001797
1798 if (*s == '\0')
1799 FATAL("null file name in print or getline");
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001800 for (i = 0; i < nfiles; i++)
zoulascffee7782020-02-28 06:23:54 -05001801 if (files[i].fname && strcmp(s, files[i].fname) == 0 &&
1802 (a == files[i].mode || (a==APPEND && files[i].mode==GT) ||
1803 a == FFLUSH)) {
1804 if (pnewflag)
1805 *pnewflag = false;
1806 return files[i].fp;
Brian Kernighan87b94932012-12-22 10:35:39 -05001807 }
1808 if (a == FFLUSH) /* didn't find it, so don't create it! */
1809 return NULL;
1810
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001811 for (i = 0; i < nfiles; i++)
pfg52421942016-06-03 21:23:11 +00001812 if (files[i].fp == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001813 break;
1814 if (i >= nfiles) {
1815 struct files *nf;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001816 size_t nnf = nfiles + FOPEN_MAX;
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +03001817 nf = (struct files *) realloc(files, nnf * sizeof(*nf));
Brian Kernighan87b94932012-12-22 10:35:39 -05001818 if (nf == NULL)
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001819 FATAL("cannot grow files for %s and %zu files", s, nnf);
Brian Kernighan87b94932012-12-22 10:35:39 -05001820 memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf));
1821 nfiles = nnf;
1822 files = nf;
1823 }
1824 fflush(stdout); /* force a semblance of order */
1825 m = a;
1826 if (a == GT) {
1827 fp = fopen(s, "w");
1828 } else if (a == APPEND) {
1829 fp = fopen(s, "a");
1830 m = GT; /* so can mix > and >> */
1831 } else if (a == '|') { /* output pipe */
1832 fp = popen(s, "w");
1833 } else if (a == LE) { /* input pipe */
1834 fp = popen(s, "r");
1835 } else if (a == LT) { /* getline <file */
1836 fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
1837 } else /* can't happen */
1838 FATAL("illegal redirection %d", a);
1839 if (fp != NULL) {
1840 files[i].fname = tostring(s);
1841 files[i].fp = fp;
1842 files[i].mode = m;
zoulascffee7782020-02-28 06:23:54 -05001843 if (pnewflag)
1844 *pnewflag = true;
Arnold D. Robbins5a18f632020-01-22 02:10:59 -07001845 if (fp != stdin && fp != stdout && fp != stderr)
1846 (void) fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
Brian Kernighan87b94932012-12-22 10:35:39 -05001847 }
1848 return fp;
1849}
1850
1851const char *filename(FILE *fp)
1852{
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001853 size_t i;
Brian Kernighan87b94932012-12-22 10:35:39 -05001854
1855 for (i = 0; i < nfiles; i++)
1856 if (fp == files[i].fp)
1857 return files[i].fname;
1858 return "???";
1859}
1860
Arnold D. Robbinscd552112020-02-06 22:32:55 +02001861 Cell *closefile(Node **a, int n)
1862 {
1863 Cell *x;
1864 size_t i;
1865 bool stat;
Chrisb7851412020-08-07 18:10:20 +08001866
Arnold D. Robbinscd552112020-02-06 22:32:55 +02001867 x = execute(a[0]);
1868 getsval(x);
1869 stat = true;
1870 for (i = 0; i < nfiles; i++) {
1871 if (!files[i].fname || strcmp(x->sval, files[i].fname) != 0)
1872 continue;
1873 if (ferror(files[i].fp))
1874 FATAL("i/o error occurred on %s", files[i].fname);
Todd C. Millerb82b6492020-07-27 01:03:58 -06001875 if (files[i].fp == stdin || files[i].fp == stdout ||
1876 files[i].fp == stderr)
1877 stat = freopen("/dev/null", "r+", files[i].fp) == NULL;
1878 else if (files[i].mode == '|' || files[i].mode == LE)
Arnold D. Robbinscd552112020-02-06 22:32:55 +02001879 stat = pclose(files[i].fp) == -1;
1880 else
1881 stat = fclose(files[i].fp) == EOF;
1882 if (stat)
1883 FATAL("i/o error occurred closing %s", files[i].fname);
1884 if (i > 2) /* don't do /dev/std... */
1885 xfree(files[i].fname);
1886 files[i].fname = NULL; /* watch out for ref thru this */
1887 files[i].fp = NULL;
Todd C. Millerb82b6492020-07-27 01:03:58 -06001888 break;
Arnold D. Robbinscd552112020-02-06 22:32:55 +02001889 }
1890 tempfree(x);
1891 x = gettemp();
1892 setfval(x, (Awkfloat) (stat ? -1 : 0));
1893 return(x);
1894 }
Brian Kernighan87b94932012-12-22 10:35:39 -05001895
1896void closeall(void)
1897{
Arnold D. Robbinse6fe6742020-02-06 22:38:30 +02001898 size_t i;
1899 bool stat = false;
Brian Kernighan87b94932012-12-22 10:35:39 -05001900
Arnold D. Robbinse6fe6742020-02-06 22:38:30 +02001901 for (i = 0; i < nfiles; i++) {
1902 if (! files[i].fp)
1903 continue;
1904 if (ferror(files[i].fp))
1905 FATAL( "i/o error occurred on %s", files[i].fname );
Todd C. Millerb82b6492020-07-27 01:03:58 -06001906 if (files[i].fp == stdin)
1907 continue;
Arnold D. Robbinse6fe6742020-02-06 22:38:30 +02001908 if (files[i].mode == '|' || files[i].mode == LE)
1909 stat = pclose(files[i].fp) == -1;
Todd C. Millerb82b6492020-07-27 01:03:58 -06001910 else if (files[i].fp == stdout || files[i].fp == stderr)
1911 stat = fflush(files[i].fp) == EOF;
Arnold D. Robbinse6fe6742020-02-06 22:38:30 +02001912 else
1913 stat = fclose(files[i].fp) == EOF;
1914 if (stat)
1915 FATAL( "i/o error occurred while closing %s", files[i].fname );
Brian Kernighan87b94932012-12-22 10:35:39 -05001916 }
1917}
1918
Arnold D. Robbinse6fe6742020-02-06 22:38:30 +02001919static void flush_all(void)
Brian Kernighan87b94932012-12-22 10:35:39 -05001920{
zoulascc2c8ecb2020-02-19 13:44:49 -05001921 size_t i;
Brian Kernighan87b94932012-12-22 10:35:39 -05001922
1923 for (i = 0; i < nfiles; i++)
1924 if (files[i].fp)
1925 fflush(files[i].fp);
1926}
1927
zoulasc65892082019-10-24 09:40:15 -04001928void backsub(char **pb_ptr, const char **sptr_ptr);
Brian Kernighan87b94932012-12-22 10:35:39 -05001929
1930Cell *sub(Node **a, int nnn) /* substitute command */
1931{
zoulasc65892082019-10-24 09:40:15 -04001932 const char *sptr, *q;
Brian Kernighan87b94932012-12-22 10:35:39 -05001933 Cell *x, *y, *result;
zoulasc65892082019-10-24 09:40:15 -04001934 char *t, *buf, *pb;
Brian Kernighan87b94932012-12-22 10:35:39 -05001935 fa *pfa;
1936 int bufsz = recsize;
1937
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +03001938 if ((buf = (char *) malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001939 FATAL("out of memory in sub");
1940 x = execute(a[3]); /* target string */
1941 t = getsval(x);
pfg52421942016-06-03 21:23:11 +00001942 if (a[0] == NULL) /* 0 => a[1] is already-compiled regexpr */
Brian Kernighan87b94932012-12-22 10:35:39 -05001943 pfa = (fa *) a[1]; /* regular expression */
1944 else {
1945 y = execute(a[1]);
1946 pfa = makedfa(getsval(y), 1);
1947 tempfree(y);
1948 }
1949 y = execute(a[2]); /* replacement string */
1950 result = False;
1951 if (pmatch(pfa, t)) {
1952 sptr = t;
1953 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1954 pb = buf;
1955 while (sptr < patbeg)
1956 *pb++ = *sptr++;
1957 sptr = getsval(y);
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001958 while (*sptr != '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05001959 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1960 if (*sptr == '\\') {
1961 backsub(&pb, &sptr);
1962 } else if (*sptr == '&') {
1963 sptr++;
1964 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1965 for (q = patbeg; q < patbeg+patlen; )
1966 *pb++ = *q++;
1967 } else
1968 *pb++ = *sptr++;
1969 }
1970 *pb = '\0';
1971 if (pb > buf + bufsz)
1972 FATAL("sub result1 %.30s too big; can't happen", buf);
1973 sptr = patbeg + patlen;
1974 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1975 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001976 while ((*pb++ = *sptr++) != '\0')
1977 continue;
Brian Kernighan87b94932012-12-22 10:35:39 -05001978 }
1979 if (pb > buf + bufsz)
1980 FATAL("sub result2 %.30s too big; can't happen", buf);
1981 setsval(x, buf); /* BUG: should be able to avoid copy */
pfg52421942016-06-03 21:23:11 +00001982 result = True;
Brian Kernighan87b94932012-12-22 10:35:39 -05001983 }
1984 tempfree(x);
1985 tempfree(y);
1986 free(buf);
1987 return result;
1988}
1989
1990Cell *gsub(Node **a, int nnn) /* global substitute */
1991{
1992 Cell *x, *y;
zoulasc65892082019-10-24 09:40:15 -04001993 char *rptr, *pb;
1994 const char *q, *t, *sptr;
Brian Kernighan87b94932012-12-22 10:35:39 -05001995 char *buf;
1996 fa *pfa;
1997 int mflag, tempstat, num;
1998 int bufsz = recsize;
1999
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +03002000 if ((buf = (char *) malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05002001 FATAL("out of memory in gsub");
2002 mflag = 0; /* if mflag == 0, can replace empty string */
2003 num = 0;
2004 x = execute(a[3]); /* target string */
2005 t = getsval(x);
pfg52421942016-06-03 21:23:11 +00002006 if (a[0] == NULL) /* 0 => a[1] is already-compiled regexpr */
Brian Kernighan87b94932012-12-22 10:35:39 -05002007 pfa = (fa *) a[1]; /* regular expression */
2008 else {
2009 y = execute(a[1]);
2010 pfa = makedfa(getsval(y), 1);
2011 tempfree(y);
2012 }
2013 y = execute(a[2]); /* replacement string */
2014 if (pmatch(pfa, t)) {
2015 tempstat = pfa->initstat;
2016 pfa->initstat = 2;
2017 pb = buf;
2018 rptr = getsval(y);
2019 do {
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002020 if (patlen == 0 && *patbeg != '\0') { /* matched empty string */
Brian Kernighan87b94932012-12-22 10:35:39 -05002021 if (mflag == 0) { /* can replace empty */
2022 num++;
2023 sptr = rptr;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002024 while (*sptr != '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05002025 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
2026 if (*sptr == '\\') {
2027 backsub(&pb, &sptr);
2028 } else if (*sptr == '&') {
2029 sptr++;
2030 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
2031 for (q = patbeg; q < patbeg+patlen; )
2032 *pb++ = *q++;
2033 } else
2034 *pb++ = *sptr++;
2035 }
2036 }
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002037 if (*t == '\0') /* at end */
Brian Kernighan87b94932012-12-22 10:35:39 -05002038 goto done;
2039 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
2040 *pb++ = *t++;
2041 if (pb > buf + bufsz) /* BUG: not sure of this test */
2042 FATAL("gsub result0 %.30s too big; can't happen", buf);
2043 mflag = 0;
2044 }
2045 else { /* matched nonempty string */
2046 num++;
2047 sptr = t;
2048 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
2049 while (sptr < patbeg)
2050 *pb++ = *sptr++;
2051 sptr = rptr;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002052 while (*sptr != '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05002053 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
2054 if (*sptr == '\\') {
2055 backsub(&pb, &sptr);
2056 } else if (*sptr == '&') {
2057 sptr++;
2058 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
2059 for (q = patbeg; q < patbeg+patlen; )
2060 *pb++ = *q++;
2061 } else
2062 *pb++ = *sptr++;
2063 }
2064 t = patbeg + patlen;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002065 if (patlen == 0 || *t == '\0' || *(t-1) == '\0')
Brian Kernighan87b94932012-12-22 10:35:39 -05002066 goto done;
2067 if (pb > buf + bufsz)
2068 FATAL("gsub result1 %.30s too big; can't happen", buf);
2069 mflag = 1;
2070 }
2071 } while (pmatch(pfa,t));
2072 sptr = t;
2073 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002074 while ((*pb++ = *sptr++) != '\0')
2075 continue;
Brian Kernighan87b94932012-12-22 10:35:39 -05002076 done: if (pb < buf + bufsz)
2077 *pb = '\0';
2078 else if (*(pb-1) != '\0')
2079 FATAL("gsub result2 %.30s truncated; can't happen", buf);
2080 setsval(x, buf); /* BUG: should be able to avoid copy + free */
2081 pfa->initstat = tempstat;
2082 }
2083 tempfree(x);
2084 tempfree(y);
2085 x = gettemp();
2086 x->tval = NUM;
2087 x->fval = num;
2088 free(buf);
2089 return(x);
2090}
2091
zoulasc65892082019-10-24 09:40:15 -04002092void backsub(char **pb_ptr, const char **sptr_ptr) /* handle \\& variations */
Brian Kernighan87b94932012-12-22 10:35:39 -05002093{ /* sptr[0] == '\\' */
zoulasc65892082019-10-24 09:40:15 -04002094 char *pb = *pb_ptr;
2095 const char *sptr = *sptr_ptr;
Arnold D. Robbinsde6284e2020-01-19 20:37:33 +02002096 static bool first = true;
2097 static bool do_posix = false;
2098
2099 if (first) {
2100 first = false;
2101 do_posix = (getenv("POSIXLY_CORRECT") != NULL);
2102 }
Brian Kernighan87b94932012-12-22 10:35:39 -05002103
2104 if (sptr[1] == '\\') {
2105 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
2106 *pb++ = '\\';
2107 *pb++ = '&';
2108 sptr += 4;
2109 } else if (sptr[2] == '&') { /* \\& -> \ + matched */
2110 *pb++ = '\\';
2111 sptr += 2;
Arnold D. Robbinsde6284e2020-01-19 20:37:33 +02002112 } else if (do_posix) { /* \\x -> \x */
2113 sptr++;
2114 *pb++ = *sptr++;
Brian Kernighan87b94932012-12-22 10:35:39 -05002115 } else { /* \\x -> \\x */
2116 *pb++ = *sptr++;
2117 *pb++ = *sptr++;
2118 }
2119 } else if (sptr[1] == '&') { /* literal & */
2120 sptr++;
2121 *pb++ = *sptr++;
2122 } else /* literal \ */
2123 *pb++ = *sptr++;
2124
2125 *pb_ptr = pb;
2126 *sptr_ptr = sptr;
2127}