blob: f5c19a158fda3b7b0154406425718906ef004c77 [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);
Todd C. Miller1debe192021-11-01 11:58:54 -0600450 if (n > 0) {
451 x = execute(a[0]);
452 setsval(x, buf);
453 if (is_number(x->sval, & result)) {
454 x->fval = result;
455 x->tval |= NUM;
456 }
457 tempfree(x);
Arnold D. Robbins9dbd1f12019-01-25 12:56:06 +0200458 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500459 }
460 }
461 setfval(r, (Awkfloat) n);
462 free(buf);
463 return r;
464}
465
466Cell *getnf(Node **a, int n) /* get NF */
467{
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200468 if (!donefld)
Brian Kernighan87b94932012-12-22 10:35:39 -0500469 fldbld();
470 return (Cell *) a[0];
471}
472
zoulasc0d8778b2019-10-25 10:59:10 -0400473static char *
474makearraystring(Node *p, const char *func)
Brian Kernighan87b94932012-12-22 10:35:39 -0500475{
Brian Kernighan87b94932012-12-22 10:35:39 -0500476 char *buf;
477 int bufsz = recsize;
Tim van der Molenee5b49b2020-07-02 20:22:15 +0200478 size_t blen;
Brian Kernighan87b94932012-12-22 10:35:39 -0500479
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300480 if ((buf = (char *) malloc(bufsz)) == NULL) {
zoulasc0d8778b2019-10-25 10:59:10 -0400481 FATAL("%s: out of memory", func);
482 }
483
484 blen = 0;
485 buf[blen] = '\0';
zoulasc0d8778b2019-10-25 10:59:10 -0400486
487 for (; p; p = p->nnext) {
488 Cell *x = execute(p); /* expr */
489 char *s = getsval(x);
Tim van der Molenee5b49b2020-07-02 20:22:15 +0200490 size_t seplen = strlen(getsval(subseploc));
zoulasc0d8778b2019-10-25 10:59:10 -0400491 size_t nsub = p->nnext ? seplen : 0;
492 size_t slen = strlen(s);
493 size_t tlen = blen + slen + nsub;
494
495 if (!adjbuf(&buf, &bufsz, tlen + 1, recsize, 0, func)) {
496 FATAL("%s: out of memory %s[%s...]",
497 func, x->nval, buf);
498 }
499 memcpy(buf + blen, s, slen);
500 if (nsub) {
501 memcpy(buf + blen + slen, *SUBSEP, nsub);
502 }
503 buf[tlen] = '\0';
504 blen = tlen;
505 tempfree(x);
506 }
507 return buf;
508}
509
510Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
511{
512 Cell *x, *z;
513 char *buf;
Brian Kernighan87b94932012-12-22 10:35:39 -0500514
515 x = execute(a[0]); /* Cell* for symbol table */
zoulasc0d8778b2019-10-25 10:59:10 -0400516 buf = makearraystring(a[1], __func__);
Brian Kernighan87b94932012-12-22 10:35:39 -0500517 if (!isarr(x)) {
Todd C. Miller292d39f2020-06-25 12:32:34 -0600518 DPRINTF("making %s into an array\n", NN(x->nval));
Brian Kernighan87b94932012-12-22 10:35:39 -0500519 if (freeable(x))
520 xfree(x->sval);
521 x->tval &= ~(STR|NUM|DONTFREE);
522 x->tval |= ARR;
523 x->sval = (char *) makesymtab(NSYMTAB);
524 }
525 z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
526 z->ctype = OCELL;
527 z->csub = CVAR;
528 tempfree(x);
529 free(buf);
530 return(z);
531}
532
533Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
534{
zoulasc0d8778b2019-10-25 10:59:10 -0400535 Cell *x;
Brian Kernighan87b94932012-12-22 10:35:39 -0500536
537 x = execute(a[0]); /* Cell* for symbol table */
Cody Melloae99b752019-06-17 10:08:54 -0900538 if (x == symtabloc) {
539 FATAL("cannot delete SYMTAB or its elements");
540 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500541 if (!isarr(x))
542 return True;
pfg52421942016-06-03 21:23:11 +0000543 if (a[1] == NULL) { /* delete the elements, not the table */
Brian Kernighan87b94932012-12-22 10:35:39 -0500544 freesymtab(x);
545 x->tval &= ~STR;
546 x->tval |= ARR;
547 x->sval = (char *) makesymtab(NSYMTAB);
548 } else {
zoulasc0d8778b2019-10-25 10:59:10 -0400549 char *buf = makearraystring(a[1], __func__);
Brian Kernighan87b94932012-12-22 10:35:39 -0500550 freeelem(x, buf);
551 free(buf);
552 }
553 tempfree(x);
554 return True;
555}
556
557Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
558{
zoulasc0d8778b2019-10-25 10:59:10 -0400559 Cell *ap, *k;
Brian Kernighan87b94932012-12-22 10:35:39 -0500560 char *buf;
Brian Kernighan87b94932012-12-22 10:35:39 -0500561
562 ap = execute(a[1]); /* array name */
563 if (!isarr(ap)) {
Todd C. Miller292d39f2020-06-25 12:32:34 -0600564 DPRINTF("making %s into an array\n", ap->nval);
Brian Kernighan87b94932012-12-22 10:35:39 -0500565 if (freeable(ap))
566 xfree(ap->sval);
567 ap->tval &= ~(STR|NUM|DONTFREE);
568 ap->tval |= ARR;
569 ap->sval = (char *) makesymtab(NSYMTAB);
570 }
zoulasc0d8778b2019-10-25 10:59:10 -0400571 buf = makearraystring(a[0], __func__);
Brian Kernighan87b94932012-12-22 10:35:39 -0500572 k = lookup(buf, (Array *) ap->sval);
573 tempfree(ap);
574 free(buf);
575 if (k == NULL)
576 return(False);
577 else
578 return(True);
579}
580
581
582Cell *matchop(Node **a, int n) /* ~ and match() */
583{
584 Cell *x, *y;
585 char *s, *t;
586 int i;
587 fa *pfa;
588 int (*mf)(fa *, const char *) = match, mode = 0;
589
590 if (n == MATCHFCN) {
591 mf = pmatch;
592 mode = 1;
593 }
594 x = execute(a[1]); /* a[1] = target text */
595 s = getsval(x);
pfg52421942016-06-03 21:23:11 +0000596 if (a[0] == NULL) /* a[1] == 0: already-compiled reg expr */
Brian Kernighan87b94932012-12-22 10:35:39 -0500597 i = (*mf)((fa *) a[2], s);
598 else {
599 y = execute(a[2]); /* a[2] = regular expr */
600 t = getsval(y);
601 pfa = makedfa(t, mode);
602 i = (*mf)(pfa, s);
603 tempfree(y);
604 }
605 tempfree(x);
606 if (n == MATCHFCN) {
607 int start = patbeg - s + 1;
608 if (patlen < 0)
609 start = 0;
610 setfval(rstartloc, (Awkfloat) start);
611 setfval(rlengthloc, (Awkfloat) patlen);
612 x = gettemp();
613 x->tval = NUM;
614 x->fval = start;
615 return x;
616 } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
617 return(True);
618 else
619 return(False);
620}
621
622
623Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
624{
625 Cell *x, *y;
626 int i;
627
628 x = execute(a[0]);
629 i = istrue(x);
630 tempfree(x);
631 switch (n) {
632 case BOR:
633 if (i) return(True);
634 y = execute(a[1]);
635 i = istrue(y);
636 tempfree(y);
637 if (i) return(True);
638 else return(False);
639 case AND:
640 if ( !i ) return(False);
641 y = execute(a[1]);
642 i = istrue(y);
643 tempfree(y);
644 if (i) return(True);
645 else return(False);
646 case NOT:
647 if (i) return(False);
648 else return(True);
649 default: /* can't happen */
650 FATAL("unknown boolean operator %d", n);
651 }
652 return 0; /*NOTREACHED*/
653}
654
655Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
656{
657 int i;
658 Cell *x, *y;
659 Awkfloat j;
660
661 x = execute(a[0]);
662 y = execute(a[1]);
663 if (x->tval&NUM && y->tval&NUM) {
664 j = x->fval - y->fval;
665 i = j<0? -1: (j>0? 1: 0);
666 } else {
667 i = strcmp(getsval(x), getsval(y));
668 }
669 tempfree(x);
670 tempfree(y);
671 switch (n) {
672 case LT: if (i<0) return(True);
673 else return(False);
674 case LE: if (i<=0) return(True);
675 else return(False);
676 case NE: if (i!=0) return(True);
677 else return(False);
678 case EQ: if (i == 0) return(True);
679 else return(False);
680 case GE: if (i>=0) return(True);
681 else return(False);
682 case GT: if (i>0) return(True);
683 else return(False);
684 default: /* can't happen */
685 FATAL("unknown relational operator %d", n);
686 }
687 return 0; /*NOTREACHED*/
688}
689
690void tfree(Cell *a) /* free a tempcell */
691{
692 if (freeable(a)) {
Todd C. Miller292d39f2020-06-25 12:32:34 -0600693 DPRINTF("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval);
Brian Kernighan87b94932012-12-22 10:35:39 -0500694 xfree(a->sval);
695 }
696 if (a == tmps)
697 FATAL("tempcell list is curdled");
698 a->cnext = tmps;
699 tmps = a;
700}
701
702Cell *gettemp(void) /* get a tempcell */
703{ int i;
704 Cell *x;
705
706 if (!tmps) {
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300707 tmps = (Cell *) calloc(100, sizeof(*tmps));
Brian Kernighan87b94932012-12-22 10:35:39 -0500708 if (!tmps)
709 FATAL("out of space for temporaries");
Arnold D. Robbins0ba1d032019-10-08 10:30:09 +0300710 for (i = 1; i < 100; i++)
Brian Kernighan87b94932012-12-22 10:35:39 -0500711 tmps[i-1].cnext = &tmps[i];
pfg52421942016-06-03 21:23:11 +0000712 tmps[i-1].cnext = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -0500713 }
714 x = tmps;
715 tmps = x->cnext;
716 *x = tempcell;
717 return(x);
718}
719
720Cell *indirect(Node **a, int n) /* $( a[0] ) */
721{
722 Awkfloat val;
723 Cell *x;
724 int m;
725 char *s;
726
727 x = execute(a[0]);
728 val = getfval(x); /* freebsd: defend against super large field numbers */
729 if ((Awkfloat)INT_MAX < val)
730 FATAL("trying to access out of range field %s", x->nval);
731 m = (int) val;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200732 if (m == 0 && !is_number(s = getsval(x), NULL)) /* suspicion! */
Brian Kernighan87b94932012-12-22 10:35:39 -0500733 FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
734 /* BUG: can x->nval ever be null??? */
735 tempfree(x);
736 x = fieldadr(m);
737 x->ctype = OCELL; /* BUG? why are these needed? */
738 x->csub = CFLD;
739 return(x);
740}
741
742Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
743{
744 int k, m, n;
745 char *s;
746 int temp;
pfg52421942016-06-03 21:23:11 +0000747 Cell *x, *y, *z = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -0500748
749 x = execute(a[0]);
750 y = execute(a[1]);
pfg52421942016-06-03 21:23:11 +0000751 if (a[2] != NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500752 z = execute(a[2]);
753 s = getsval(x);
754 k = strlen(s) + 1;
755 if (k <= 1) {
756 tempfree(x);
757 tempfree(y);
pfg52421942016-06-03 21:23:11 +0000758 if (a[2] != NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -0500759 tempfree(z);
760 }
761 x = gettemp();
762 setsval(x, "");
763 return(x);
764 }
765 m = (int) getfval(y);
766 if (m <= 0)
767 m = 1;
768 else if (m > k)
769 m = k;
770 tempfree(y);
pfg52421942016-06-03 21:23:11 +0000771 if (a[2] != NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -0500772 n = (int) getfval(z);
773 tempfree(z);
774 } else
775 n = k - 1;
776 if (n < 0)
777 n = 0;
778 else if (n > k - m)
779 n = k - m;
Todd C. Miller292d39f2020-06-25 12:32:34 -0600780 DPRINTF("substr: m=%d, n=%d, s=%s\n", m, n, s);
Brian Kernighan87b94932012-12-22 10:35:39 -0500781 y = gettemp();
782 temp = s[n+m-1]; /* with thanks to John Linderman */
783 s[n+m-1] = '\0';
784 setsval(y, s + m - 1);
785 s[n+m-1] = temp;
786 tempfree(x);
787 return(y);
788}
789
790Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
791{
792 Cell *x, *y, *z;
793 char *s1, *s2, *p1, *p2, *q;
794 Awkfloat v = 0.0;
795
796 x = execute(a[0]);
797 s1 = getsval(x);
798 y = execute(a[1]);
799 s2 = getsval(y);
800
801 z = gettemp();
802 for (p1 = s1; *p1 != '\0'; p1++) {
Arnold D. Robbins5068d202020-02-06 22:27:31 +0200803 for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++)
804 continue;
Brian Kernighan87b94932012-12-22 10:35:39 -0500805 if (*p2 == '\0') {
806 v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
807 break;
808 }
809 }
810 tempfree(x);
811 tempfree(y);
812 setfval(z, v);
813 return(z);
814}
815
816#define MAXNUMSIZE 50
817
818int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */
819{
820 char *fmt;
821 char *p, *t;
822 const char *os;
823 Cell *x;
824 int flag = 0, n;
825 int fmtwd; /* format width */
826 int fmtsz = recsize;
827 char *buf = *pbuf;
828 int bufsize = *pbufsize;
zoulasc0d8778b2019-10-25 10:59:10 -0400829#define FMTSZ(a) (fmtsz - ((a) - fmt))
830#define BUFSZ(a) (bufsize - ((a) - buf))
Brian Kernighan87b94932012-12-22 10:35:39 -0500831
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200832 static bool first = true;
833 static bool have_a_format = false;
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300834
835 if (first) {
zoulascc2c8ecb2020-02-19 13:44:49 -0500836 char xbuf[100];
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300837
zoulascc2c8ecb2020-02-19 13:44:49 -0500838 snprintf(xbuf, sizeof(xbuf), "%a", 42.0);
839 have_a_format = (strcmp(xbuf, "0x1.5p+5") == 0);
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200840 first = false;
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300841 }
842
Brian Kernighan87b94932012-12-22 10:35:39 -0500843 os = s;
844 p = buf;
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300845 if ((fmt = (char *) malloc(fmtsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500846 FATAL("out of memory in format()");
847 while (*s) {
848 adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1");
849 if (*s != '%') {
850 *p++ = *s++;
851 continue;
852 }
853 if (*(s+1) == '%') {
854 *p++ = '%';
855 s += 2;
856 continue;
857 }
858 /* have to be real careful in case this is a huge number, eg, %100000d */
859 fmtwd = atoi(s+1);
860 if (fmtwd < 0)
861 fmtwd = -fmtwd;
862 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format2");
863 for (t = fmt; (*t++ = *s) != '\0'; s++) {
864 if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3"))
865 FATAL("format item %.30s... ran format() out of memory", os);
zoulasca96aebb2019-12-11 02:17:34 -0500866 /* Ignore size specifiers */
Arnold D. Robbins0b82bc62019-12-11 09:24:38 +0200867 if (strchr("hjLlqtz", *s) != NULL) { /* the ansi panoply */
zoulasca96aebb2019-12-11 02:17:34 -0500868 t--;
869 continue;
870 }
871 if (isalpha((uschar)*s))
Arnold D. Robbins0b82bc62019-12-11 09:24:38 +0200872 break;
Brian Kernighan22aff9e2018-08-27 08:52:34 -0400873 if (*s == '$') {
874 FATAL("'$' not permitted in awk formats");
875 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500876 if (*s == '*') {
Cody Peter Mello6cf37e92018-09-14 17:29:06 -0700877 if (a == NULL) {
878 FATAL("not enough args in printf(%s)", os);
879 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500880 x = execute(a);
881 a = a->nnext;
zoulasc0d8778b2019-10-25 10:59:10 -0400882 snprintf(t - 1, FMTSZ(t - 1),
883 "%d", fmtwd=(int) getfval(x));
Brian Kernighan87b94932012-12-22 10:35:39 -0500884 if (fmtwd < 0)
885 fmtwd = -fmtwd;
886 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
887 t = fmt + strlen(fmt);
888 tempfree(x);
889 }
890 }
891 *t = '\0';
892 if (fmtwd < 0)
893 fmtwd = -fmtwd;
894 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4");
Brian Kernighan87b94932012-12-22 10:35:39 -0500895 switch (*s) {
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300896 case 'a': case 'A':
897 if (have_a_format)
898 flag = *s;
899 else
900 flag = 'f';
901 break;
Brian Kernighan87b94932012-12-22 10:35:39 -0500902 case 'f': case 'e': case 'g': case 'E': case 'G':
903 flag = 'f';
904 break;
zoulasca96aebb2019-12-11 02:17:34 -0500905 case 'd': case 'i': case 'o': case 'x': case 'X': case 'u':
Arnold D. Robbins0b82bc62019-12-11 09:24:38 +0200906 flag = (*s == 'd' || *s == 'i') ? 'd' : 'u';
zoulascff5d6762019-12-08 14:41:27 -0500907 *(t-1) = 'j';
zoulasc0d8778b2019-10-25 10:59:10 -0400908 *t = *s;
909 *++t = '\0';
Brian Kernighan87b94932012-12-22 10:35:39 -0500910 break;
911 case 's':
912 flag = 's';
913 break;
914 case 'c':
915 flag = 'c';
916 break;
917 default:
918 WARNING("weird printf conversion %s", fmt);
919 flag = '?';
920 break;
921 }
922 if (a == NULL)
923 FATAL("not enough args in printf(%s)", os);
924 x = execute(a);
925 a = a->nnext;
926 n = MAXNUMSIZE;
927 if (fmtwd > n)
928 n = fmtwd;
929 adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5");
930 switch (flag) {
zoulasc0d8778b2019-10-25 10:59:10 -0400931 case '?': snprintf(p, BUFSZ(p), "%s", fmt); /* unknown, so dump it too */
Brian Kernighan87b94932012-12-22 10:35:39 -0500932 t = getsval(x);
933 n = strlen(t);
934 if (fmtwd > n)
935 n = fmtwd;
936 adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6");
937 p += strlen(p);
zoulasc0d8778b2019-10-25 10:59:10 -0400938 snprintf(p, BUFSZ(p), "%s", t);
Brian Kernighan87b94932012-12-22 10:35:39 -0500939 break;
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300940 case 'a':
941 case 'A':
zoulasc0d8778b2019-10-25 10:59:10 -0400942 case 'f': snprintf(p, BUFSZ(p), fmt, getfval(x)); break;
zoulascff5d6762019-12-08 14:41:27 -0500943 case 'd': snprintf(p, BUFSZ(p), fmt, (intmax_t) getfval(x)); break;
944 case 'u': snprintf(p, BUFSZ(p), fmt, (uintmax_t) getfval(x)); break;
Brian Kernighan87b94932012-12-22 10:35:39 -0500945 case 's':
946 t = getsval(x);
947 n = strlen(t);
948 if (fmtwd > n)
949 n = fmtwd;
950 if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7"))
951 FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
zoulasc0d8778b2019-10-25 10:59:10 -0400952 snprintf(p, BUFSZ(p), fmt, t);
Brian Kernighan87b94932012-12-22 10:35:39 -0500953 break;
954 case 'c':
955 if (isnum(x)) {
M. Warner Losh966fdc92019-06-02 14:53:15 -0600956 if ((int)getfval(x))
zoulasc0d8778b2019-10-25 10:59:10 -0400957 snprintf(p, BUFSZ(p), fmt, (int) getfval(x));
Brian Kernighan87b94932012-12-22 10:35:39 -0500958 else {
959 *p++ = '\0'; /* explicit null byte */
960 *p = '\0'; /* next output will start here */
961 }
962 } else
zoulasc0d8778b2019-10-25 10:59:10 -0400963 snprintf(p, BUFSZ(p), fmt, getsval(x)[0]);
Brian Kernighan87b94932012-12-22 10:35:39 -0500964 break;
965 default:
966 FATAL("can't happen: bad conversion %c in format()", flag);
967 }
968 tempfree(x);
969 p += strlen(p);
970 s++;
971 }
972 *p = '\0';
973 free(fmt);
974 for ( ; a; a = a->nnext) /* evaluate any remaining args */
975 execute(a);
976 *pbuf = buf;
977 *pbufsize = bufsize;
978 return p - buf;
979}
980
981Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
982{
983 Cell *x;
984 Node *y;
985 char *buf;
986 int bufsz=3*recsize;
987
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300988 if ((buf = (char *) malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500989 FATAL("out of memory in awksprintf");
990 y = a[0]->nnext;
991 x = execute(a[0]);
992 if (format(&buf, &bufsz, getsval(x), y) == -1)
993 FATAL("sprintf string %.30s... too long. can't happen.", buf);
994 tempfree(x);
995 x = gettemp();
996 x->sval = buf;
997 x->tval = STR;
998 return(x);
999}
1000
1001Cell *awkprintf(Node **a, int n) /* printf */
1002{ /* a[0] is list of args, starting with format string */
1003 /* a[1] is redirection operator, a[2] is redirection file */
1004 FILE *fp;
1005 Cell *x;
1006 Node *y;
1007 char *buf;
1008 int len;
1009 int bufsz=3*recsize;
1010
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +03001011 if ((buf = (char *) malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001012 FATAL("out of memory in awkprintf");
1013 y = a[0]->nnext;
1014 x = execute(a[0]);
1015 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
1016 FATAL("printf string %.30s... too long. can't happen.", buf);
1017 tempfree(x);
1018 if (a[1] == NULL) {
1019 /* fputs(buf, stdout); */
1020 fwrite(buf, len, 1, stdout);
1021 if (ferror(stdout))
1022 FATAL("write error on stdout");
1023 } else {
1024 fp = redirect(ptoi(a[1]), a[2]);
1025 /* fputs(buf, fp); */
1026 fwrite(buf, len, 1, fp);
1027 fflush(fp);
1028 if (ferror(fp))
1029 FATAL("write error on %s", filename(fp));
1030 }
1031 free(buf);
1032 return(True);
1033}
1034
1035Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
1036{
1037 Awkfloat i, j = 0;
1038 double v;
1039 Cell *x, *y, *z;
1040
1041 x = execute(a[0]);
1042 i = getfval(x);
1043 tempfree(x);
Arnold D. Robbins32093f52018-08-22 20:40:26 +03001044 if (n != UMINUS && n != UPLUS) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001045 y = execute(a[1]);
1046 j = getfval(y);
1047 tempfree(y);
1048 }
1049 z = gettemp();
1050 switch (n) {
1051 case ADD:
1052 i += j;
1053 break;
1054 case MINUS:
1055 i -= j;
1056 break;
1057 case MULT:
1058 i *= j;
1059 break;
1060 case DIVIDE:
1061 if (j == 0)
1062 FATAL("division by zero");
1063 i /= j;
1064 break;
1065 case MOD:
1066 if (j == 0)
1067 FATAL("division by zero in mod");
1068 modf(i/j, &v);
1069 i = i - j * v;
1070 break;
1071 case UMINUS:
1072 i = -i;
1073 break;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001074 case UPLUS: /* handled by getfval(), above */
Arnold D. Robbins32093f52018-08-22 20:40:26 +03001075 break;
Brian Kernighan87b94932012-12-22 10:35:39 -05001076 case POWER:
1077 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1078 i = ipow(i, (int) j);
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001079 else {
1080 errno = 0;
Brian Kernighan87b94932012-12-22 10:35:39 -05001081 i = errcheck(pow(i, j), "pow");
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001082 }
Brian Kernighan87b94932012-12-22 10:35:39 -05001083 break;
1084 default: /* can't happen */
1085 FATAL("illegal arithmetic operator %d", n);
1086 }
1087 setfval(z, i);
1088 return(z);
1089}
1090
1091double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
1092{
1093 double v;
1094
1095 if (n <= 0)
1096 return 1;
1097 v = ipow(x, n/2);
1098 if (n % 2 == 0)
1099 return v * v;
1100 else
1101 return x * v * v;
1102}
1103
1104Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
1105{
1106 Cell *x, *z;
1107 int k;
1108 Awkfloat xf;
1109
1110 x = execute(a[0]);
1111 xf = getfval(x);
1112 k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1113 if (n == PREINCR || n == PREDECR) {
1114 setfval(x, xf + k);
1115 return(x);
1116 }
1117 z = gettemp();
1118 setfval(z, xf);
1119 setfval(x, xf + k);
1120 tempfree(x);
1121 return(z);
1122}
1123
1124Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
1125{ /* this is subtle; don't muck with it. */
1126 Cell *x, *y;
1127 Awkfloat xf, yf;
1128 double v;
1129
1130 y = execute(a[1]);
1131 x = execute(a[0]);
1132 if (n == ASSIGN) { /* ordinary assignment */
Cody Peter Mello63155252018-09-23 17:59:52 -07001133 if (x == y && !(x->tval & (FLD|REC)) && x != nfloc)
1134 ; /* self-assignment: leave alone unless it's a field or NF */
Brian Kernighan87b94932012-12-22 10:35:39 -05001135 else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1136 setsval(x, getsval(y));
1137 x->fval = getfval(y);
1138 x->tval |= NUM;
1139 }
1140 else if (isstr(y))
1141 setsval(x, getsval(y));
1142 else if (isnum(y))
1143 setfval(x, getfval(y));
1144 else
1145 funnyvar(y, "read value of");
1146 tempfree(y);
1147 return(x);
1148 }
1149 xf = getfval(x);
1150 yf = getfval(y);
1151 switch (n) {
1152 case ADDEQ:
1153 xf += yf;
1154 break;
1155 case SUBEQ:
1156 xf -= yf;
1157 break;
1158 case MULTEQ:
1159 xf *= yf;
1160 break;
1161 case DIVEQ:
1162 if (yf == 0)
1163 FATAL("division by zero in /=");
1164 xf /= yf;
1165 break;
1166 case MODEQ:
1167 if (yf == 0)
1168 FATAL("division by zero in %%=");
1169 modf(xf/yf, &v);
1170 xf = xf - yf * v;
1171 break;
1172 case POWEQ:
1173 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1174 xf = ipow(xf, (int) yf);
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001175 else {
1176 errno = 0;
Brian Kernighan87b94932012-12-22 10:35:39 -05001177 xf = errcheck(pow(xf, yf), "pow");
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001178 }
Brian Kernighan87b94932012-12-22 10:35:39 -05001179 break;
1180 default:
1181 FATAL("illegal assignment operator %d", n);
1182 break;
1183 }
1184 tempfree(y);
1185 setfval(x, xf);
1186 return(x);
1187}
1188
1189Cell *cat(Node **a, int q) /* a[0] cat a[1] */
1190{
1191 Cell *x, *y, *z;
1192 int n1, n2;
Cody Peter Melloe2623742018-09-15 01:38:39 -07001193 char *s = NULL;
1194 int ssz = 0;
Brian Kernighan87b94932012-12-22 10:35:39 -05001195
1196 x = execute(a[0]);
Cody Peter Melloe2623742018-09-15 01:38:39 -07001197 n1 = strlen(getsval(x));
Tim van der Molencc19af12020-07-02 20:21:10 +02001198 adjbuf(&s, &ssz, n1, recsize, 0, "cat1");
1199 memcpy(s, x->sval, n1);
Cody Peter Melloe2623742018-09-15 01:38:39 -07001200
Brian Kernighan87b94932012-12-22 10:35:39 -05001201 y = execute(a[1]);
Cody Peter Melloe2623742018-09-15 01:38:39 -07001202 n2 = strlen(getsval(y));
Tim van der Molencc19af12020-07-02 20:21:10 +02001203 adjbuf(&s, &ssz, n1 + n2 + 1, recsize, 0, "cat2");
Arnold D. Robbins1d6ddfd2019-10-24 10:06:10 -04001204 memcpy(s + n1, y->sval, n2);
1205 s[n1 + n2] = '\0';
Cody Peter Melloe2623742018-09-15 01:38:39 -07001206
Brian Kernighan87b94932012-12-22 10:35:39 -05001207 tempfree(x);
1208 tempfree(y);
Cody Peter Melloe2623742018-09-15 01:38:39 -07001209
Brian Kernighan87b94932012-12-22 10:35:39 -05001210 z = gettemp();
1211 z->sval = s;
1212 z->tval = STR;
Cody Peter Melloe2623742018-09-15 01:38:39 -07001213
Brian Kernighan87b94932012-12-22 10:35:39 -05001214 return(z);
1215}
1216
1217Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
1218{
1219 Cell *x;
1220
pfg52421942016-06-03 21:23:11 +00001221 if (a[0] == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001222 x = execute(a[1]);
1223 else {
1224 x = execute(a[0]);
1225 if (istrue(x)) {
1226 tempfree(x);
1227 x = execute(a[1]);
1228 }
1229 }
1230 return x;
1231}
1232
1233Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
1234{
1235 Cell *x;
1236 int pair;
1237
1238 pair = ptoi(a[3]);
1239 if (pairstack[pair] == 0) {
1240 x = execute(a[0]);
1241 if (istrue(x))
1242 pairstack[pair] = 1;
1243 tempfree(x);
1244 }
1245 if (pairstack[pair] == 1) {
1246 x = execute(a[1]);
1247 if (istrue(x))
1248 pairstack[pair] = 0;
1249 tempfree(x);
1250 x = execute(a[2]);
1251 return(x);
1252 }
1253 return(False);
1254}
1255
1256Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
1257{
pfg52421942016-06-03 21:23:11 +00001258 Cell *x = NULL, *y, *ap;
zoulasc65892082019-10-24 09:40:15 -04001259 const char *s, *origs, *t;
zoulasc6a877092020-01-24 04:11:59 -05001260 const char *fs = NULL;
1261 char *origfs = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -05001262 int sep;
zoulasc65892082019-10-24 09:40:15 -04001263 char temp, num[50];
Brian Kernighan87b94932012-12-22 10:35:39 -05001264 int n, tempstat, arg3type;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +02001265 double result;
Brian Kernighan87b94932012-12-22 10:35:39 -05001266
1267 y = execute(a[0]); /* source string */
1268 origs = s = strdup(getsval(y));
1269 arg3type = ptoi(a[3]);
pfg52421942016-06-03 21:23:11 +00001270 if (a[2] == NULL) /* fs string */
Cody Peter Mello52566c02018-09-18 15:45:55 -07001271 fs = getsval(fsloc);
Brian Kernighan87b94932012-12-22 10:35:39 -05001272 else if (arg3type == STRING) { /* split(str,arr,"string") */
1273 x = execute(a[2]);
zoulasc6a877092020-01-24 04:11:59 -05001274 fs = origfs = strdup(getsval(x));
Cody Peter Mellod45db5e2018-09-18 15:20:44 -07001275 tempfree(x);
Brian Kernighan87b94932012-12-22 10:35:39 -05001276 } else if (arg3type == REGEXPR)
1277 fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1278 else
1279 FATAL("illegal type of split");
1280 sep = *fs;
1281 ap = execute(a[1]); /* array name */
1282 freesymtab(ap);
Todd C. Miller292d39f2020-06-25 12:32:34 -06001283 DPRINTF("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs);
Brian Kernighan87b94932012-12-22 10:35:39 -05001284 ap->tval &= ~STR;
1285 ap->tval |= ARR;
1286 ap->sval = (char *) makesymtab(NSYMTAB);
1287
1288 n = 0;
1289 if (arg3type == REGEXPR && strlen((char*)((fa*)a[2])->restr) == 0) {
1290 /* split(s, a, //); have to arrange that it looks like empty sep */
1291 arg3type = 0;
1292 fs = "";
1293 sep = 0;
1294 }
1295 if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) { /* reg expr */
1296 fa *pfa;
1297 if (arg3type == REGEXPR) { /* it's ready already */
1298 pfa = (fa *) a[2];
1299 } else {
1300 pfa = makedfa(fs, 1);
1301 }
1302 if (nematch(pfa,s)) {
1303 tempstat = pfa->initstat;
1304 pfa->initstat = 2;
1305 do {
1306 n++;
zoulasc0d8778b2019-10-25 10:59:10 -04001307 snprintf(num, sizeof(num), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -05001308 temp = *patbeg;
zoulasc65892082019-10-24 09:40:15 -04001309 setptr(patbeg, '\0');
Arnold Robbinscc9e9b62020-12-08 08:05:22 +02001310 if (is_number(s, & result))
1311 setsymtab(num, s, result, STR|NUM, (Array *) ap->sval);
Brian Kernighan87b94932012-12-22 10:35:39 -05001312 else
1313 setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
zoulasc65892082019-10-24 09:40:15 -04001314 setptr(patbeg, temp);
Brian Kernighan87b94932012-12-22 10:35:39 -05001315 s = patbeg + patlen;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001316 if (*(patbeg+patlen-1) == '\0' || *s == '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05001317 n++;
zoulasc0d8778b2019-10-25 10:59:10 -04001318 snprintf(num, sizeof(num), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -05001319 setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1320 pfa->initstat = tempstat;
1321 goto spdone;
1322 }
1323 } while (nematch(pfa,s));
1324 pfa->initstat = tempstat; /* bwk: has to be here to reset */
1325 /* cf gsub and refldbld */
1326 }
1327 n++;
zoulasc0d8778b2019-10-25 10:59:10 -04001328 snprintf(num, sizeof(num), "%d", n);
Arnold Robbinscc9e9b62020-12-08 08:05:22 +02001329 if (is_number(s, & result))
1330 setsymtab(num, s, result, STR|NUM, (Array *) ap->sval);
Brian Kernighan87b94932012-12-22 10:35:39 -05001331 else
1332 setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1333 spdone:
1334 pfa = NULL;
1335 } else if (sep == ' ') {
1336 for (n = 0; ; ) {
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001337#define ISWS(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
1338 while (ISWS(*s))
Brian Kernighan87b94932012-12-22 10:35:39 -05001339 s++;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001340 if (*s == '\0')
Brian Kernighan87b94932012-12-22 10:35:39 -05001341 break;
1342 n++;
1343 t = s;
1344 do
1345 s++;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001346 while (*s != '\0' && !ISWS(*s));
Brian Kernighan87b94932012-12-22 10:35:39 -05001347 temp = *s;
zoulasc65892082019-10-24 09:40:15 -04001348 setptr(s, '\0');
zoulasc0d8778b2019-10-25 10:59:10 -04001349 snprintf(num, sizeof(num), "%d", n);
Arnold Robbinscc9e9b62020-12-08 08:05:22 +02001350 if (is_number(t, & result))
1351 setsymtab(num, t, result, STR|NUM, (Array *) ap->sval);
Brian Kernighan87b94932012-12-22 10:35:39 -05001352 else
1353 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
zoulasc65892082019-10-24 09:40:15 -04001354 setptr(s, temp);
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001355 if (*s != '\0')
Brian Kernighan87b94932012-12-22 10:35:39 -05001356 s++;
1357 }
1358 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001359 for (n = 0; *s != '\0'; s++) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001360 char buf[2];
1361 n++;
zoulasc0d8778b2019-10-25 10:59:10 -04001362 snprintf(num, sizeof(num), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -05001363 buf[0] = *s;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001364 buf[1] = '\0';
Brian Kernighan87b94932012-12-22 10:35:39 -05001365 if (isdigit((uschar)buf[0]))
1366 setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1367 else
1368 setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1369 }
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001370 } else if (*s != '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05001371 for (;;) {
1372 n++;
1373 t = s;
1374 while (*s != sep && *s != '\n' && *s != '\0')
1375 s++;
1376 temp = *s;
zoulasc65892082019-10-24 09:40:15 -04001377 setptr(s, '\0');
zoulasc0d8778b2019-10-25 10:59:10 -04001378 snprintf(num, sizeof(num), "%d", n);
Arnold Robbinscc9e9b62020-12-08 08:05:22 +02001379 if (is_number(t, & result))
1380 setsymtab(num, t, result, STR|NUM, (Array *) ap->sval);
Brian Kernighan87b94932012-12-22 10:35:39 -05001381 else
1382 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
zoulasc65892082019-10-24 09:40:15 -04001383 setptr(s, temp);
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001384 if (*s++ == '\0')
Brian Kernighan87b94932012-12-22 10:35:39 -05001385 break;
1386 }
1387 }
1388 tempfree(ap);
1389 tempfree(y);
zoulasc65892082019-10-24 09:40:15 -04001390 xfree(origs);
1391 xfree(origfs);
Brian Kernighan87b94932012-12-22 10:35:39 -05001392 x = gettemp();
1393 x->tval = NUM;
1394 x->fval = n;
1395 return(x);
1396}
1397
1398Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1399{
1400 Cell *x;
1401
1402 x = execute(a[0]);
1403 if (istrue(x)) {
1404 tempfree(x);
1405 x = execute(a[1]);
1406 } else {
1407 tempfree(x);
1408 x = execute(a[2]);
1409 }
1410 return(x);
1411}
1412
1413Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1414{
1415 Cell *x;
1416
1417 x = execute(a[0]);
1418 if (istrue(x)) {
1419 tempfree(x);
1420 x = execute(a[1]);
pfg52421942016-06-03 21:23:11 +00001421 } else if (a[2] != NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001422 tempfree(x);
1423 x = execute(a[2]);
1424 }
1425 return(x);
1426}
1427
1428Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
1429{
1430 Cell *x;
1431
1432 for (;;) {
1433 x = execute(a[0]);
1434 if (!istrue(x))
1435 return(x);
1436 tempfree(x);
1437 x = execute(a[1]);
1438 if (isbreak(x)) {
1439 x = True;
1440 return(x);
1441 }
1442 if (isnext(x) || isexit(x) || isret(x))
1443 return(x);
1444 tempfree(x);
1445 }
1446}
1447
1448Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
1449{
1450 Cell *x;
1451
1452 for (;;) {
1453 x = execute(a[0]);
1454 if (isbreak(x))
1455 return True;
1456 if (isnext(x) || isexit(x) || isret(x))
1457 return(x);
1458 tempfree(x);
1459 x = execute(a[1]);
1460 if (!istrue(x))
1461 return(x);
1462 tempfree(x);
1463 }
1464}
1465
1466Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
1467{
1468 Cell *x;
1469
1470 x = execute(a[0]);
1471 tempfree(x);
1472 for (;;) {
pfg52421942016-06-03 21:23:11 +00001473 if (a[1]!=NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001474 x = execute(a[1]);
1475 if (!istrue(x)) return(x);
1476 else tempfree(x);
1477 }
1478 x = execute(a[3]);
1479 if (isbreak(x)) /* turn off break */
1480 return True;
1481 if (isnext(x) || isexit(x) || isret(x))
1482 return(x);
1483 tempfree(x);
1484 x = execute(a[2]);
1485 tempfree(x);
1486 }
1487}
1488
1489Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1490{
1491 Cell *x, *vp, *arrayp, *cp, *ncp;
1492 Array *tp;
1493 int i;
1494
1495 vp = execute(a[0]);
1496 arrayp = execute(a[1]);
1497 if (!isarr(arrayp)) {
1498 return True;
1499 }
1500 tp = (Array *) arrayp->sval;
1501 tempfree(arrayp);
1502 for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1503 for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1504 setsval(vp, cp->nval);
1505 ncp = cp->cnext;
1506 x = execute(a[2]);
1507 if (isbreak(x)) {
1508 tempfree(vp);
1509 return True;
1510 }
1511 if (isnext(x) || isexit(x) || isret(x)) {
1512 tempfree(vp);
1513 return(x);
1514 }
1515 tempfree(x);
1516 }
1517 }
1518 return True;
1519}
1520
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001521static char *nawk_convert(const char *s, int (*fun_c)(int),
1522 wint_t (*fun_wc)(wint_t))
1523{
1524 char *buf = NULL;
1525 char *pbuf = NULL;
1526 const char *ps = NULL;
1527 size_t n = 0;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001528 wchar_t wc;
1529 size_t sz = MB_CUR_MAX;
1530
1531 if (sz == 1) {
1532 buf = tostring(s);
1533
1534 for (pbuf = buf; *pbuf; pbuf++)
1535 *pbuf = fun_c((uschar)*pbuf);
1536
1537 return buf;
1538 } else {
1539 /* upper/lower character may be shorter/longer */
1540 buf = tostringN(s, strlen(s) * sz + 1);
1541
Arnold D. Robbins1b398462020-08-04 10:02:26 +03001542 (void) mbtowc(NULL, NULL, 0); /* reset internal state */
1543 /*
1544 * Reset internal state here too.
1545 * Assign result to avoid a compiler warning. (Casting to void
1546 * doesn't work.)
1547 * Increment said variable to avoid a different warning.
1548 */
1549 int unused = wctomb(NULL, L'\0');
1550 unused++;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001551
1552 ps = s;
1553 pbuf = buf;
Arnold D. Robbins1b398462020-08-04 10:02:26 +03001554 while (n = mbtowc(&wc, ps, sz),
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001555 n > 0 && n != (size_t)-1 && n != (size_t)-2)
1556 {
1557 ps += n;
1558
Arnold D. Robbins1b398462020-08-04 10:02:26 +03001559 n = wctomb(pbuf, fun_wc(wc));
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001560 if (n == (size_t)-1)
1561 FATAL("illegal wide character %s", s);
1562
1563 pbuf += n;
1564 }
1565
1566 *pbuf = '\0';
1567
1568 if (n)
1569 FATAL("illegal byte sequence %s", s);
1570
1571 return buf;
1572 }
1573}
1574
Arnold D. Robbins98042852020-08-16 18:48:05 +03001575#ifdef __DJGPP__
1576static wint_t towupper(wint_t wc)
1577{
1578 if (wc >= 0 && wc < 256)
1579 return toupper(wc & 0xFF);
1580
1581 return wc;
1582}
1583
1584static wint_t towlower(wint_t wc)
1585{
1586 if (wc >= 0 && wc < 256)
1587 return tolower(wc & 0xFF);
1588
1589 return wc;
1590}
1591#endif
1592
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001593static char *nawk_toupper(const char *s)
1594{
1595 return nawk_convert(s, toupper, towupper);
1596}
1597
1598static char *nawk_tolower(const char *s)
1599{
1600 return nawk_convert(s, tolower, towlower);
1601}
1602
Brian Kernighan87b94932012-12-22 10:35:39 -05001603Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
1604{
1605 Cell *x, *y;
1606 Awkfloat u;
1607 int t;
1608 Awkfloat tmp;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001609 char *buf;
Brian Kernighan87b94932012-12-22 10:35:39 -05001610 Node *nextarg;
1611 FILE *fp;
Arnold D. Robbins32093f52018-08-22 20:40:26 +03001612 int status = 0;
Brian Kernighan87b94932012-12-22 10:35:39 -05001613
1614 t = ptoi(a[0]);
1615 x = execute(a[1]);
1616 nextarg = a[1]->nnext;
1617 switch (t) {
1618 case FLENGTH:
1619 if (isarr(x))
1620 u = ((Array *) x->sval)->nelem; /* GROT. should be function*/
1621 else
1622 u = strlen(getsval(x));
1623 break;
1624 case FLOG:
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001625 errno = 0;
1626 u = errcheck(log(getfval(x)), "log");
1627 break;
Brian Kernighan87b94932012-12-22 10:35:39 -05001628 case FINT:
1629 modf(getfval(x), &u); break;
1630 case FEXP:
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001631 errno = 0;
1632 u = errcheck(exp(getfval(x)), "exp");
1633 break;
Brian Kernighan87b94932012-12-22 10:35:39 -05001634 case FSQRT:
Todd C. Millerb2de1c42020-06-12 05:16:12 -06001635 errno = 0;
1636 u = errcheck(sqrt(getfval(x)), "sqrt");
1637 break;
Brian Kernighan87b94932012-12-22 10:35:39 -05001638 case FSIN:
1639 u = sin(getfval(x)); break;
1640 case FCOS:
1641 u = cos(getfval(x)); break;
1642 case FATAN:
pfg52421942016-06-03 21:23:11 +00001643 if (nextarg == NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001644 WARNING("atan2 requires two arguments; returning 1.0");
1645 u = 1.0;
1646 } else {
1647 y = execute(a[1]->nnext);
1648 u = atan2(getfval(x), getfval(y));
1649 tempfree(y);
1650 nextarg = nextarg->nnext;
1651 }
1652 break;
1653 case FSYSTEM:
1654 fflush(stdout); /* in case something is buffered already */
Arnold D. Robbins32093f52018-08-22 20:40:26 +03001655 status = system(getsval(x));
1656 u = status;
1657 if (status != -1) {
1658 if (WIFEXITED(status)) {
1659 u = WEXITSTATUS(status);
1660 } else if (WIFSIGNALED(status)) {
1661 u = WTERMSIG(status) + 256;
1662#ifdef WCOREDUMP
1663 if (WCOREDUMP(status))
1664 u += 256;
1665#endif
1666 } else /* something else?!? */
1667 u = 0;
1668 }
Brian Kernighan87b94932012-12-22 10:35:39 -05001669 break;
1670 case FRAND:
pfgc70b9fe2014-09-19 18:24:02 +00001671 /* random() returns numbers in [0..2^31-1]
1672 * in order to get a number in [0, 1), divide it by 2^31
1673 */
1674 u = (Awkfloat) random() / (0x7fffffffL + 0x1UL);
Brian Kernighan87b94932012-12-22 10:35:39 -05001675 break;
1676 case FSRAND:
1677 if (isrec(x)) /* no argument provided */
1678 u = time((time_t *)0);
1679 else
1680 u = getfval(x);
1681 tmp = u;
pfgc70b9fe2014-09-19 18:24:02 +00001682 srandom((unsigned long) u);
Brian Kernighan87b94932012-12-22 10:35:39 -05001683 u = srand_seed;
1684 srand_seed = tmp;
1685 break;
1686 case FTOUPPER:
1687 case FTOLOWER:
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001688 if (t == FTOUPPER)
1689 buf = nawk_toupper(getsval(x));
1690 else
1691 buf = nawk_tolower(getsval(x));
Brian Kernighan87b94932012-12-22 10:35:39 -05001692 tempfree(x);
1693 x = gettemp();
1694 setsval(x, buf);
1695 free(buf);
1696 return x;
1697 case FFLUSH:
1698 if (isrec(x) || strlen(getsval(x)) == 0) {
1699 flush_all(); /* fflush() or fflush("") -> all */
1700 u = 0;
zoulascffee7782020-02-28 06:23:54 -05001701 } else if ((fp = openfile(FFLUSH, getsval(x), NULL)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001702 u = EOF;
1703 else
1704 u = fflush(fp);
1705 break;
1706 default: /* can't happen */
1707 FATAL("illegal function type %d", t);
1708 break;
1709 }
1710 tempfree(x);
1711 x = gettemp();
1712 setfval(x, u);
pfg52421942016-06-03 21:23:11 +00001713 if (nextarg != NULL) {
Brian Kernighan87b94932012-12-22 10:35:39 -05001714 WARNING("warning: function has too many arguments");
1715 for ( ; nextarg; nextarg = nextarg->nnext)
1716 execute(nextarg);
1717 }
1718 return(x);
1719}
1720
1721Cell *printstat(Node **a, int n) /* print a[0] */
1722{
1723 Node *x;
1724 Cell *y;
1725 FILE *fp;
1726
pfg52421942016-06-03 21:23:11 +00001727 if (a[1] == NULL) /* a[1] is redirection operator, a[2] is file */
Brian Kernighan87b94932012-12-22 10:35:39 -05001728 fp = stdout;
1729 else
1730 fp = redirect(ptoi(a[1]), a[2]);
1731 for (x = a[0]; x != NULL; x = x->nnext) {
1732 y = execute(x);
1733 fputs(getpssval(y), fp);
1734 tempfree(y);
1735 if (x->nnext == NULL)
Cody Peter Mello52566c02018-09-18 15:45:55 -07001736 fputs(getsval(orsloc), fp);
Brian Kernighan87b94932012-12-22 10:35:39 -05001737 else
Cody Peter Mello52566c02018-09-18 15:45:55 -07001738 fputs(getsval(ofsloc), fp);
Brian Kernighan87b94932012-12-22 10:35:39 -05001739 }
pfg52421942016-06-03 21:23:11 +00001740 if (a[1] != NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001741 fflush(fp);
1742 if (ferror(fp))
1743 FATAL("write error on %s", filename(fp));
1744 return(True);
1745}
1746
1747Cell *nullproc(Node **a, int n)
1748{
Brian Kernighan87b94932012-12-22 10:35:39 -05001749 return 0;
1750}
1751
1752
1753FILE *redirect(int a, Node *b) /* set up all i/o redirections */
1754{
1755 FILE *fp;
1756 Cell *x;
1757 char *fname;
1758
1759 x = execute(b);
1760 fname = getsval(x);
zoulascffee7782020-02-28 06:23:54 -05001761 fp = openfile(a, fname, NULL);
Brian Kernighan87b94932012-12-22 10:35:39 -05001762 if (fp == NULL)
1763 FATAL("can't open file %s", fname);
1764 tempfree(x);
1765 return fp;
1766}
1767
1768struct files {
1769 FILE *fp;
1770 const char *fname;
1771 int mode; /* '|', 'a', 'w' => LE/LT, GT */
1772} *files;
1773
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001774size_t nfiles;
Brian Kernighan87b94932012-12-22 10:35:39 -05001775
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001776static void stdinit(void) /* in case stdin, etc., are not constants */
Brian Kernighan87b94932012-12-22 10:35:39 -05001777{
1778 nfiles = FOPEN_MAX;
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +03001779 files = (struct files *) calloc(nfiles, sizeof(*files));
Brian Kernighan87b94932012-12-22 10:35:39 -05001780 if (files == NULL)
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001781 FATAL("can't allocate file memory for %zu files", nfiles);
Brian Kernighan87b94932012-12-22 10:35:39 -05001782 files[0].fp = stdin;
1783 files[0].fname = "/dev/stdin";
1784 files[0].mode = LT;
1785 files[1].fp = stdout;
1786 files[1].fname = "/dev/stdout";
1787 files[1].mode = GT;
1788 files[2].fp = stderr;
1789 files[2].fname = "/dev/stderr";
1790 files[2].mode = GT;
1791}
1792
zoulascffee7782020-02-28 06:23:54 -05001793FILE *openfile(int a, const char *us, bool *pnewflag)
Brian Kernighan87b94932012-12-22 10:35:39 -05001794{
1795 const char *s = us;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001796 size_t i;
1797 int m;
pfg52421942016-06-03 21:23:11 +00001798 FILE *fp = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -05001799
1800 if (*s == '\0')
1801 FATAL("null file name in print or getline");
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001802 for (i = 0; i < nfiles; i++)
zoulascffee7782020-02-28 06:23:54 -05001803 if (files[i].fname && strcmp(s, files[i].fname) == 0 &&
1804 (a == files[i].mode || (a==APPEND && files[i].mode==GT) ||
1805 a == FFLUSH)) {
1806 if (pnewflag)
1807 *pnewflag = false;
1808 return files[i].fp;
Brian Kernighan87b94932012-12-22 10:35:39 -05001809 }
1810 if (a == FFLUSH) /* didn't find it, so don't create it! */
1811 return NULL;
1812
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001813 for (i = 0; i < nfiles; i++)
pfg52421942016-06-03 21:23:11 +00001814 if (files[i].fp == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001815 break;
1816 if (i >= nfiles) {
1817 struct files *nf;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001818 size_t nnf = nfiles + FOPEN_MAX;
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +03001819 nf = (struct files *) realloc(files, nnf * sizeof(*nf));
Brian Kernighan87b94932012-12-22 10:35:39 -05001820 if (nf == NULL)
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001821 FATAL("cannot grow files for %s and %zu files", s, nnf);
Brian Kernighan87b94932012-12-22 10:35:39 -05001822 memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf));
1823 nfiles = nnf;
1824 files = nf;
1825 }
1826 fflush(stdout); /* force a semblance of order */
1827 m = a;
1828 if (a == GT) {
1829 fp = fopen(s, "w");
1830 } else if (a == APPEND) {
1831 fp = fopen(s, "a");
1832 m = GT; /* so can mix > and >> */
1833 } else if (a == '|') { /* output pipe */
1834 fp = popen(s, "w");
1835 } else if (a == LE) { /* input pipe */
1836 fp = popen(s, "r");
1837 } else if (a == LT) { /* getline <file */
1838 fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
1839 } else /* can't happen */
1840 FATAL("illegal redirection %d", a);
1841 if (fp != NULL) {
1842 files[i].fname = tostring(s);
1843 files[i].fp = fp;
1844 files[i].mode = m;
zoulascffee7782020-02-28 06:23:54 -05001845 if (pnewflag)
1846 *pnewflag = true;
Arnold D. Robbins5a18f632020-01-22 02:10:59 -07001847 if (fp != stdin && fp != stdout && fp != stderr)
1848 (void) fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
Brian Kernighan87b94932012-12-22 10:35:39 -05001849 }
1850 return fp;
1851}
1852
1853const char *filename(FILE *fp)
1854{
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001855 size_t i;
Brian Kernighan87b94932012-12-22 10:35:39 -05001856
1857 for (i = 0; i < nfiles; i++)
1858 if (fp == files[i].fp)
1859 return files[i].fname;
1860 return "???";
1861}
1862
Miguel Pineiro Jr1d780ac2021-12-08 18:42:59 -05001863Cell *closefile(Node **a, int n)
1864{
Arnold D. Robbinscd552112020-02-06 22:32:55 +02001865 Cell *x;
1866 size_t i;
1867 bool stat;
Chrisb7851412020-08-07 18:10:20 +08001868
Arnold D. Robbinscd552112020-02-06 22:32:55 +02001869 x = execute(a[0]);
1870 getsval(x);
1871 stat = true;
1872 for (i = 0; i < nfiles; i++) {
1873 if (!files[i].fname || strcmp(x->sval, files[i].fname) != 0)
1874 continue;
Miguel Pineiro Jr7816d472021-12-16 20:07:10 -05001875 if (files[i].mode == GT || files[i].mode == '|')
1876 fflush(files[i].fp);
Miguel Pineiro Jr99f6a432021-12-08 21:37:28 -05001877 if (ferror(files[i].fp)) {
1878 if ((files[i].mode == GT && files[i].fp != stderr)
1879 || files[i].mode == '|')
1880 FATAL("write error on %s", files[i].fname);
1881 else
1882 WARNING("i/o error occurred on %s", files[i].fname);
1883 }
Todd C. Millerb82b6492020-07-27 01:03:58 -06001884 if (files[i].fp == stdin || files[i].fp == stdout ||
1885 files[i].fp == stderr)
1886 stat = freopen("/dev/null", "r+", files[i].fp) == NULL;
1887 else if (files[i].mode == '|' || files[i].mode == LE)
Arnold D. Robbinscd552112020-02-06 22:32:55 +02001888 stat = pclose(files[i].fp) == -1;
1889 else
1890 stat = fclose(files[i].fp) == EOF;
1891 if (stat)
Miguel Pineiro Jr99f6a432021-12-08 21:37:28 -05001892 WARNING("i/o error occurred closing %s", files[i].fname);
Arnold D. Robbinscd552112020-02-06 22:32:55 +02001893 if (i > 2) /* don't do /dev/std... */
1894 xfree(files[i].fname);
1895 files[i].fname = NULL; /* watch out for ref thru this */
1896 files[i].fp = NULL;
Todd C. Millerb82b6492020-07-27 01:03:58 -06001897 break;
Arnold D. Robbinscd552112020-02-06 22:32:55 +02001898 }
1899 tempfree(x);
1900 x = gettemp();
1901 setfval(x, (Awkfloat) (stat ? -1 : 0));
1902 return(x);
Miguel Pineiro Jr1d780ac2021-12-08 18:42:59 -05001903}
Brian Kernighan87b94932012-12-22 10:35:39 -05001904
1905void closeall(void)
1906{
Arnold D. Robbinse6fe6742020-02-06 22:38:30 +02001907 size_t i;
1908 bool stat = false;
Brian Kernighan87b94932012-12-22 10:35:39 -05001909
Arnold D. Robbinse6fe6742020-02-06 22:38:30 +02001910 for (i = 0; i < nfiles; i++) {
1911 if (! files[i].fp)
1912 continue;
Miguel Pineiro Jr7816d472021-12-16 20:07:10 -05001913 if (files[i].mode == GT || files[i].mode == '|')
1914 fflush(files[i].fp);
Miguel Pineiro Jr99f6a432021-12-08 21:37:28 -05001915 if (ferror(files[i].fp)) {
1916 if ((files[i].mode == GT && files[i].fp != stderr)
1917 || files[i].mode == '|')
1918 FATAL("write error on %s", files[i].fname);
1919 else
1920 WARNING("i/o error occurred on %s", files[i].fname);
1921 }
1922 if (files[i].fp == stdin || files[i].fp == stdout ||
1923 files[i].fp == stderr)
Todd C. Millerb82b6492020-07-27 01:03:58 -06001924 continue;
Arnold D. Robbinse6fe6742020-02-06 22:38:30 +02001925 if (files[i].mode == '|' || files[i].mode == LE)
1926 stat = pclose(files[i].fp) == -1;
1927 else
1928 stat = fclose(files[i].fp) == EOF;
1929 if (stat)
Miguel Pineiro Jr99f6a432021-12-08 21:37:28 -05001930 WARNING("i/o error occurred while closing %s", files[i].fname);
Brian Kernighan87b94932012-12-22 10:35:39 -05001931 }
1932}
1933
Arnold D. Robbinse6fe6742020-02-06 22:38:30 +02001934static void flush_all(void)
Brian Kernighan87b94932012-12-22 10:35:39 -05001935{
zoulascc2c8ecb2020-02-19 13:44:49 -05001936 size_t i;
Brian Kernighan87b94932012-12-22 10:35:39 -05001937
1938 for (i = 0; i < nfiles; i++)
1939 if (files[i].fp)
1940 fflush(files[i].fp);
1941}
1942
zoulasc65892082019-10-24 09:40:15 -04001943void backsub(char **pb_ptr, const char **sptr_ptr);
Brian Kernighan87b94932012-12-22 10:35:39 -05001944
1945Cell *sub(Node **a, int nnn) /* substitute command */
1946{
zoulasc65892082019-10-24 09:40:15 -04001947 const char *sptr, *q;
Brian Kernighan87b94932012-12-22 10:35:39 -05001948 Cell *x, *y, *result;
zoulasc65892082019-10-24 09:40:15 -04001949 char *t, *buf, *pb;
Brian Kernighan87b94932012-12-22 10:35:39 -05001950 fa *pfa;
1951 int bufsz = recsize;
1952
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +03001953 if ((buf = (char *) malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05001954 FATAL("out of memory in sub");
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 result = False;
1966 if (pmatch(pfa, t)) {
1967 sptr = t;
1968 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1969 pb = buf;
1970 while (sptr < patbeg)
1971 *pb++ = *sptr++;
1972 sptr = getsval(y);
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001973 while (*sptr != '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05001974 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1975 if (*sptr == '\\') {
1976 backsub(&pb, &sptr);
1977 } else if (*sptr == '&') {
1978 sptr++;
1979 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1980 for (q = patbeg; q < patbeg+patlen; )
1981 *pb++ = *q++;
1982 } else
1983 *pb++ = *sptr++;
1984 }
1985 *pb = '\0';
1986 if (pb > buf + bufsz)
1987 FATAL("sub result1 %.30s too big; can't happen", buf);
1988 sptr = patbeg + patlen;
1989 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1990 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
Arnold D. Robbins5068d202020-02-06 22:27:31 +02001991 while ((*pb++ = *sptr++) != '\0')
1992 continue;
Brian Kernighan87b94932012-12-22 10:35:39 -05001993 }
1994 if (pb > buf + bufsz)
1995 FATAL("sub result2 %.30s too big; can't happen", buf);
1996 setsval(x, buf); /* BUG: should be able to avoid copy */
pfg52421942016-06-03 21:23:11 +00001997 result = True;
Brian Kernighan87b94932012-12-22 10:35:39 -05001998 }
1999 tempfree(x);
2000 tempfree(y);
2001 free(buf);
2002 return result;
2003}
2004
2005Cell *gsub(Node **a, int nnn) /* global substitute */
2006{
2007 Cell *x, *y;
zoulasc65892082019-10-24 09:40:15 -04002008 char *rptr, *pb;
2009 const char *q, *t, *sptr;
Brian Kernighan87b94932012-12-22 10:35:39 -05002010 char *buf;
2011 fa *pfa;
2012 int mflag, tempstat, num;
2013 int bufsz = recsize;
2014
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +03002015 if ((buf = (char *) malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -05002016 FATAL("out of memory in gsub");
2017 mflag = 0; /* if mflag == 0, can replace empty string */
2018 num = 0;
2019 x = execute(a[3]); /* target string */
2020 t = getsval(x);
pfg52421942016-06-03 21:23:11 +00002021 if (a[0] == NULL) /* 0 => a[1] is already-compiled regexpr */
Brian Kernighan87b94932012-12-22 10:35:39 -05002022 pfa = (fa *) a[1]; /* regular expression */
2023 else {
2024 y = execute(a[1]);
2025 pfa = makedfa(getsval(y), 1);
2026 tempfree(y);
2027 }
2028 y = execute(a[2]); /* replacement string */
2029 if (pmatch(pfa, t)) {
2030 tempstat = pfa->initstat;
2031 pfa->initstat = 2;
2032 pb = buf;
2033 rptr = getsval(y);
2034 do {
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002035 if (patlen == 0 && *patbeg != '\0') { /* matched empty string */
Brian Kernighan87b94932012-12-22 10:35:39 -05002036 if (mflag == 0) { /* can replace empty */
2037 num++;
2038 sptr = rptr;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002039 while (*sptr != '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05002040 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
2041 if (*sptr == '\\') {
2042 backsub(&pb, &sptr);
2043 } else if (*sptr == '&') {
2044 sptr++;
2045 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
2046 for (q = patbeg; q < patbeg+patlen; )
2047 *pb++ = *q++;
2048 } else
2049 *pb++ = *sptr++;
2050 }
2051 }
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002052 if (*t == '\0') /* at end */
Brian Kernighan87b94932012-12-22 10:35:39 -05002053 goto done;
2054 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
2055 *pb++ = *t++;
2056 if (pb > buf + bufsz) /* BUG: not sure of this test */
2057 FATAL("gsub result0 %.30s too big; can't happen", buf);
2058 mflag = 0;
2059 }
2060 else { /* matched nonempty string */
2061 num++;
2062 sptr = t;
2063 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
2064 while (sptr < patbeg)
2065 *pb++ = *sptr++;
2066 sptr = rptr;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002067 while (*sptr != '\0') {
Brian Kernighan87b94932012-12-22 10:35:39 -05002068 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
2069 if (*sptr == '\\') {
2070 backsub(&pb, &sptr);
2071 } else if (*sptr == '&') {
2072 sptr++;
2073 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
2074 for (q = patbeg; q < patbeg+patlen; )
2075 *pb++ = *q++;
2076 } else
2077 *pb++ = *sptr++;
2078 }
2079 t = patbeg + patlen;
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002080 if (patlen == 0 || *t == '\0' || *(t-1) == '\0')
Brian Kernighan87b94932012-12-22 10:35:39 -05002081 goto done;
2082 if (pb > buf + bufsz)
2083 FATAL("gsub result1 %.30s too big; can't happen", buf);
2084 mflag = 1;
2085 }
2086 } while (pmatch(pfa,t));
2087 sptr = t;
2088 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
Arnold D. Robbins5068d202020-02-06 22:27:31 +02002089 while ((*pb++ = *sptr++) != '\0')
2090 continue;
Brian Kernighan87b94932012-12-22 10:35:39 -05002091 done: if (pb < buf + bufsz)
2092 *pb = '\0';
2093 else if (*(pb-1) != '\0')
2094 FATAL("gsub result2 %.30s truncated; can't happen", buf);
2095 setsval(x, buf); /* BUG: should be able to avoid copy + free */
2096 pfa->initstat = tempstat;
2097 }
2098 tempfree(x);
2099 tempfree(y);
2100 x = gettemp();
2101 x->tval = NUM;
2102 x->fval = num;
2103 free(buf);
2104 return(x);
2105}
2106
zoulasc65892082019-10-24 09:40:15 -04002107void backsub(char **pb_ptr, const char **sptr_ptr) /* handle \\& variations */
Brian Kernighan87b94932012-12-22 10:35:39 -05002108{ /* sptr[0] == '\\' */
zoulasc65892082019-10-24 09:40:15 -04002109 char *pb = *pb_ptr;
2110 const char *sptr = *sptr_ptr;
Arnold D. Robbinsde6284e2020-01-19 20:37:33 +02002111 static bool first = true;
2112 static bool do_posix = false;
2113
2114 if (first) {
2115 first = false;
2116 do_posix = (getenv("POSIXLY_CORRECT") != NULL);
2117 }
Brian Kernighan87b94932012-12-22 10:35:39 -05002118
2119 if (sptr[1] == '\\') {
2120 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
2121 *pb++ = '\\';
2122 *pb++ = '&';
2123 sptr += 4;
2124 } else if (sptr[2] == '&') { /* \\& -> \ + matched */
2125 *pb++ = '\\';
2126 sptr += 2;
Arnold D. Robbinsde6284e2020-01-19 20:37:33 +02002127 } else if (do_posix) { /* \\x -> \x */
2128 sptr++;
2129 *pb++ = *sptr++;
Brian Kernighan87b94932012-12-22 10:35:39 -05002130 } else { /* \\x -> \\x */
2131 *pb++ = *sptr++;
2132 *pb++ = *sptr++;
2133 }
2134 } else if (sptr[1] == '&') { /* literal & */
2135 sptr++;
2136 *pb++ = *sptr++;
2137 } else /* literal \ */
2138 *pb++ = *sptr++;
2139
2140 *pb_ptr = pb;
2141 *sptr_ptr = sptr;
2142}