1/* ***************************************************************
2 * copyright (c) lucent technologies 1997
3 * all rights reserved
4 *
5 * permission to use, copy, modify, and distribute this software and
6 * its documentation for any purpose and without fee is hereby
7 * granted, provided that the above copyright notice appear in all
8 * copies and that both that the copyright notice and this
9 * permission notice and warranty disclaimer appear in supporting
10 * documentation, and that the name lucent technologies or any of
11 * its entities not be used in advertising or publicity pertaining
12 * to distribution of the software without specific, written prior
13 * permission
14 *
15 * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
17 * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22 * THIS SOFTWARE
23 * ************************************************************** */
24
25#ifdef __GNUC__
26#pragma GCC diagnostic ignored "-Wunused-parameter"
27#endif
28
29#define DEBUG
30#include "awk.h"
31#include "awkgram.tab.h"
32#include <ctype.h>
33#include <fcntl.h>
34#include <limits.h>
35#include <math.h>
36#include <setjmp.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/stat.h>
41#include <sys/types.h>
42#include <sys/wait.h>
43#include <time.h>
44#include <wctype.h>
45
46static void stdinit(void);
47static void flush_all(void);
48static char *wide_char_to_byte_str(int rune, size_t *outlen);
49
50#if 1
51#define tempfree(x) \
52 do { \
53 if (istemp(x)) \
54 tfree(x); \
55 } while (/* CONSTCOND */ 0)
56#else
57void
58tempfree(Cell *p)
59{
60 if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
61 WARNING("bad csub %d in Cell %d %s", p->csub, p->ctype, p->sval);
62 }
63 if (istemp(p))
64 tfree(p);
65}
66#endif
67
68/* do we really need these? */
69/* #ifdef _NFILE */
70/* #ifndef FOPEN_MAX */
71/* #define FOPEN_MAX _NFILE */
72/* #endif */
73/* #endif */
74
75/* #ifndef fopen_max */
76/* #define fopen_max 40 */ /* max number of open files */
77/* #endif */
78
79jmp_buf env;
80extern int pairstack[];
81extern Awkfloat srand_seed;
82
83Node *winner = NULL; /* root of parse tree */
84Cell *tmps; /* free temporary cells for execution */
85
86static Cell truecell = {OBOOL, BTRUE, 0, 0, 1.0, NUM, NULL, NULL};
87Cell *True = &truecell;
88static Cell falsecell = {OBOOL, BFALSE, 0, 0, 0.0, NUM, NULL, NULL};
89Cell *False = &falsecell;
90static Cell breakcell = {OJUMP, JBREAK, 0, 0, 0.0, NUM, NULL, NULL};
91Cell *jbreak = &breakcell;
92static Cell contcell = {OJUMP, JCONT, 0, 0, 0.0, NUM, NULL, NULL};
93Cell *jcont = &contcell;
94static Cell nextcell = {OJUMP, JNEXT, 0, 0, 0.0, NUM, NULL, NULL};
95Cell *jnext = &nextcell;
96static Cell nextfilecell = {OJUMP, JNEXTFILE, 0, 0, 0.0, NUM, NULL, NULL};
97Cell *jnextfile = &nextfilecell;
98static Cell exitcell = {OJUMP, JEXIT, 0, 0, 0.0, NUM, NULL, NULL};
99Cell *jexit = &exitcell;
100static Cell retcell = {OJUMP, JRET, 0, 0, 0.0, NUM, NULL, NULL};
101Cell *jret = &retcell;
102static Cell tempcell = {OCELL, CTEMP, 0, EMPTY, 0.0, NUM | STR | DONTFREE, NULL, NULL};
103
104Node *curnode = NULL; /* the node being executed, for debugging */
105
106/* buffer memory management */
107int
108adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr, const char *whatrtn)
109/* pbuf: address of pointer to buffer being managed
110 * psiz: address of buffer size variable
111 * minlen: minimum length of buffer needed
112 * quantum: buffer size quantum
113 * pbptr: address of movable pointer into buffer, or 0 if none
114 * whatrtn: name of the calling routine if failure should cause fatal error
115 *
116 * return 0 for realloc failure, !=0 for success
117 */
118{
119 if (minlen > *psiz) {
120 char *tbuf;
121 int rminlen = quantum ? minlen % quantum : 0;
122 int boff = pbptr ? *pbptr - *pbuf : 0;
123 /* round up to next multiple of quantum */
124 if (rminlen)
125 minlen += quantum - rminlen;
126 tbuf = (char *)realloc(*pbuf, minlen);
127 DPRINTF(
128 "adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, (void *)*pbuf, (void *)tbuf
129 );
130 if (tbuf == NULL) {
131 if (whatrtn)
132 FATAL("out of memory in %s", whatrtn);
133 return 0;
134 }
135 *pbuf = tbuf;
136 *psiz = minlen;
137 if (pbptr)
138 *pbptr = tbuf + boff;
139 }
140 return 1;
141}
142
143void
144run(Node *a) /* execution of parse tree starts here */
145{
146 stdinit();
147 execute(a);
148 closeall();
149}
150
151Cell *
152execute(Node *u) /* execute a node of the parse tree */
153{
154 Cell *(*proc)(Node **, int);
155 Cell *x;
156 Node *a;
157
158 if (u == NULL)
159 return (True);
160 for (a = u;; a = a->nnext) {
161 curnode = a;
162 if (isvalue(a)) {
163 x = (Cell *)(a->narg[0]);
164 if (isfld(x) && !donefld)
165 fldbld();
166 else if (isrec(x) && !donerec)
167 recbld();
168 return (x);
169 }
170 if (notlegal(a->nobj)) /* probably a cell* but too risky to
171 * print */
172 FATAL("illegal statement");
173 proc = proctab[a->nobj - FIRSTTOKEN];
174 x = (*proc)(a->narg, a->nobj);
175 if (isfld(x) && !donefld)
176 fldbld();
177 else if (isrec(x) && !donerec)
178 recbld();
179 if (isexpr(a))
180 return (x);
181 if (isjump(x))
182 return (x);
183 if (a->nnext == NULL)
184 return (x);
185 tempfree(x);
186 }
187}
188
189Cell *
190program(Node **a, int n) /* execute an awk program */
191{ /* a[0] = BEGIN, a[1] = body, a[2] = END */
192 Cell *x;
193
194 if (setjmp(env) != 0)
195 goto ex;
196 if (a[0]) { /* BEGIN */
197 x = execute(a[0]);
198 if (isexit(x))
199 return (True);
200 if (isjump(x))
201 FATAL(
202 "illegal break, continue, next or nextfile from "
203 "BEGIN"
204 );
205 tempfree(x);
206 }
207 if (a[1] || a[2])
208 while (getrec(&record, &recsize, true) > 0) {
209 x = execute(a[1]);
210 if (isexit(x))
211 break;
212 tempfree(x);
213 }
214ex:
215 if (setjmp(env) != 0) /* handles exit within END */
216 goto ex1;
217 if (a[2]) { /* END */
218 x = execute(a[2]);
219 if (isbreak(x) || isnext(x) || iscont(x))
220 FATAL(
221 "illegal break, continue, next or nextfile from "
222 "END"
223 );
224 tempfree(x);
225 }
226ex1:
227 return (True);
228}
229
230struct Frame { /* stack frame for awk function calls */
231 int nargs; /* number of arguments in this call */
232 Cell *fcncell; /* pointer to cell for function */
233 Cell **args; /* pointer to array of arguments after execute */
234 Cell *retval; /* return value */
235};
236
237#define NARGS 50 /* max args in a call */
238
239struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
240int nframe = 0; /* number of frames allocated */
241struct Frame *frp = NULL; /* frame pointer. bottom level unused */
242
243Cell *
244call(Node **a, int n) /* function call. very kludgy and fragile */
245{
246 static const Cell newcopycell = {OCELL, CCOPY, 0, EMPTY, 0.0, NUM | STR | DONTFREE, NULL, NULL};
247 int i, ncall, ndef;
248 int freed = 0; /* handles potential double freeing when fcn & param
249 * share a tempcell */
250 Node *x;
251 Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */
252 Cell *y, *z, *fcn;
253 char *s;
254
255 fcn = execute(a[0]); /* the function itself */
256 s = fcn->nval;
257 if (!isfcn(fcn))
258 FATAL("calling undefined function %s", s);
259 if (frame == NULL) {
260 frp = frame = (struct Frame *)calloc(nframe += 100, sizeof(*frame));
261 if (frame == NULL)
262 FATAL("out of space for stack frames calling %s", s);
263 }
264 for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
265 ncall++;
266 ndef = (int)fcn->fval; /* args in defn */
267 DPRINTF("calling %s, %d args (%d in defn), frp=%d\n", s, ncall, ndef, (int)(frp - frame));
268 if (ncall > ndef)
269 WARNING("function %s called with %d args, uses only %d", s, ncall, ndef);
270 if (ncall + ndef > NARGS)
271 FATAL("function %s has %d arguments, limit %d", s, ncall + ndef, NARGS);
272 for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */
273 DPRINTF("evaluate args[%d], frp=%d:\n", i, (int)(frp - frame));
274 y = execute(x);
275 oargs[i] = y;
276 DPRINTF(
277 "args[%d]: %s %f <%s>, t=%o\n",
278 i,
279 NN(y->nval),
280 y->fval,
281 isarr(y) ? "(array)" : NN(y->sval),
282 y->tval
283 );
284 if (isfcn(y))
285 FATAL("can't use function %s as argument in %s", y->nval, s);
286 if (isarr(y))
287 args[i] = y; /* arrays by ref */
288 else
289 args[i] = copycell(y);
290 tempfree(y);
291 }
292 for (; i < ndef; i++) { /* add null args for ones not provided */
293 args[i] = gettemp();
294 *args[i] = newcopycell;
295 }
296 frp++; /* now ok to up frame */
297 if (frp >= frame + nframe) {
298 int dfp = frp - frame; /* old index */
299 frame = (struct Frame *)realloc(frame, (nframe += 100) * sizeof(*frame));
300 if (frame == NULL)
301 FATAL("out of space for stack frames in %s", s);
302 frp = frame + dfp;
303 }
304 frp->fcncell = fcn;
305 frp->args = args;
306 frp->nargs = ndef; /* number defined with (excess are locals) */
307 frp->retval = gettemp();
308
309 DPRINTF("start exec of %s, frp=%d\n", s, (int)(frp - frame));
310 y = execute((Node *)(fcn->sval)); /* execute body */
311 DPRINTF("finished exec of %s, frp=%d\n", s, (int)(frp - frame));
312
313 for (i = 0; i < ndef; i++) {
314 Cell *t = frp->args[i];
315 if (isarr(t)) {
316 if (t->csub == CCOPY) {
317 if (i >= ncall) {
318 freesymtab(t);
319 t->csub = CTEMP;
320 tempfree(t);
321 } else {
322 oargs[i]->tval = t->tval;
323 oargs[i]->tval &= ~(STR | NUM | DONTFREE);
324 oargs[i]->sval = t->sval;
325 tempfree(t);
326 }
327 }
328 } else if (t != y) { /* kludge to prevent freeing twice */
329 t->csub = CTEMP;
330 tempfree(t);
331 } else if (t == y && t->csub == CCOPY) {
332 t->csub = CTEMP;
333 tempfree(t);
334 freed = 1;
335 }
336 }
337 tempfree(fcn);
338 if (isexit(y) || isnext(y))
339 return y;
340 if (freed == 0) {
341 tempfree(y); /* dont free twice! */
342 }
343 z = frp->retval; /* return value */
344 DPRINTF("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval);
345 frp--;
346 return (z);
347}
348
349Cell *
350copycell(Cell *x) /* make a copy of a cell in a temp */
351{
352 Cell *y;
353
354 /* copy is not constant or field */
355
356 y = gettemp();
357 y->tval = x->tval & ~(CON | FLD | REC);
358 y->csub = CCOPY; /* prevents freeing until call is over */
359 y->nval = x->nval; /* BUG? */
360 if (isstr(x) /* || x->ctype == OCELL */) {
361 y->sval = tostring(x->sval);
362 y->tval &= ~DONTFREE;
363 } else
364 y->tval |= DONTFREE;
365 y->fval = x->fval;
366 return y;
367}
368
369Cell *
370arg(Node **a, int n) /* nth argument of a function */
371{
372 n = ptoi(a[0]); /* argument number, counting from 0 */
373 DPRINTF("arg(%d), frp->nargs=%d\n", n, frp->nargs);
374 if (n + 1 > frp->nargs)
375 FATAL("argument #%d of function %s was not supplied", n + 1, frp->fcncell->nval);
376 return frp->args[n];
377}
378
379Cell *
380jump(Node **a, int n) /* break, continue, next, nextfile, return */
381{
382 Cell *y;
383
384 switch (n) {
385 case EXIT:
386 if (a[0] != NULL) {
387 y = execute(a[0]);
388 errorflag = (int)getfval(y);
389 tempfree(y);
390 }
391 longjmp(env, 1);
392 case RETURN:
393 if (a[0] != NULL) {
394 y = execute(a[0]);
395 if ((y->tval & (STR | NUM)) == (STR | NUM)) {
396 setsval(frp->retval, getsval(y));
397 frp->retval->fval = getfval(y);
398 frp->retval->tval |= NUM;
399 } else if (y->tval & STR)
400 setsval(frp->retval, getsval(y));
401 else if (y->tval & NUM)
402 setfval(frp->retval, getfval(y));
403 else /* cant happen */
404 FATAL("bad type variable %d", y->tval);
405 tempfree(y);
406 }
407 return (jret);
408 case NEXT:
409 return (jnext);
410 case NEXTFILE:
411 nextfile();
412 return (jnextfile);
413 case BREAK:
414 return (jbreak);
415 case CONTINUE:
416 return (jcont);
417 default: /* cant happen */
418 FATAL("illegal jump type %d", n);
419 }
420 return 0; /* not reached */
421}
422
423Cell *
424awkgetline(Node **a, int n) /* get next line from specific input */
425{ /* a[0] is variable, a[1] is operator, a[2] is filename */
426 Cell *r, *x;
427 extern Cell **fldtab;
428 FILE *fp;
429 char *buf;
430 int bufsize = recsize;
431 int mode;
432 bool newflag;
433 double result;
434
435 if ((buf = (char *)malloc(bufsize)) == NULL)
436 FATAL("out of memory in getline");
437
438 fflush(stdout); /* in case someone is waiting for a prompt */
439 r = gettemp();
440 if (a[1] != NULL) { /* getline < file */
441 x = execute(a[2]); /* filename */
442 mode = ptoi(a[1]);
443 if (mode == '|') /* input pipe */
444 mode = LE; /* arbitrary flag */
445 fp = openfile(mode, getsval(x), &newflag);
446 tempfree(x);
447 if (fp == NULL)
448 n = -1;
449 else
450 n = readrec(&buf, &bufsize, fp, newflag);
451 if (n <= 0) {
452 ;
453 } else if (a[0] != NULL) { /* getline var <file */
454 x = execute(a[0]);
455 setsval(x, buf);
456 if (is_number(x->sval, &result)) {
457 x->fval = result;
458 x->tval |= NUM;
459 }
460 tempfree(x);
461 } else { /* getline <file */
462 setsval(fldtab[0], buf);
463 if (is_number(fldtab[0]->sval, &result)) {
464 fldtab[0]->fval = result;
465 fldtab[0]->tval |= NUM;
466 }
467 }
468 } else { /* bare getline; use current input */
469 if (a[0] == NULL) /* getline */
470 n = getrec(&record, &recsize, true);
471 else { /* getline var */
472 n = getrec(&buf, &bufsize, false);
473 if (n > 0) {
474 x = execute(a[0]);
475 setsval(x, buf);
476 if (is_number(x->sval, &result)) {
477 x->fval = result;
478 x->tval |= NUM;
479 }
480 tempfree(x);
481 }
482 }
483 }
484 setfval(r, (Awkfloat)n);
485 free(buf);
486 return r;
487}
488
489Cell *
490getnf(Node **a, int n) /* get NF */
491{
492 if (!donefld)
493 fldbld();
494 return (Cell *)a[0];
495}
496
497static char *
498makearraystring(Node *p, const char *func)
499{
500 char *buf;
501 int bufsz = recsize;
502 size_t blen;
503
504 if ((buf = (char *)malloc(bufsz)) == NULL) {
505 FATAL("%s: out of memory", func);
506 }
507
508 blen = 0;
509 buf[blen] = '\0';
510
511 for (; p; p = p->nnext) {
512 Cell *x = execute(p); /* expr */
513 char *s = getsval(x);
514 size_t seplen = strlen(getsval(subseploc));
515 size_t nsub = p->nnext ? seplen : 0;
516 size_t slen = strlen(s);
517 size_t tlen = blen + slen + nsub;
518
519 if (!adjbuf(&buf, &bufsz, tlen + 1, recsize, 0, func)) {
520 FATAL("%s: out of memory %s[%s...]", func, x->nval, buf);
521 }
522 memcpy(buf + blen, s, slen);
523 if (nsub) {
524 memcpy(buf + blen + slen, *SUBSEP, nsub);
525 }
526 buf[tlen] = '\0';
527 blen = tlen;
528 tempfree(x);
529 }
530 return buf;
531}
532
533Cell *
534array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
535{
536 Cell *x, *z;
537 char *buf;
538
539 x = execute(a[0]); /* cell* for symbol table */
540 buf = makearraystring(a[1], __func__);
541 if (!isarr(x)) {
542 DPRINTF("making %s into an array\n", NN(x->nval));
543 if (freeable(x))
544 xfree(x->sval);
545 x->tval &= ~(STR | NUM | DONTFREE);
546 x->tval |= ARR;
547 x->sval = (char *)makesymtab(NSYMTAB);
548 }
549 z = setsymtab(buf, "", 0.0, STR | NUM, (Array *)x->sval);
550 z->ctype = OCELL;
551 z->csub = CVAR;
552 tempfree(x);
553 free(buf);
554 return (z);
555}
556
557Cell *
558awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
559{
560 Cell *x;
561
562 x = execute(a[0]); /* cell* for symbol table */
563 if (x == symtabloc) {
564 FATAL("cannot delete SYMTAB or its elements");
565 }
566 if (!isarr(x))
567 return True;
568 if (a[1] == NULL) { /* delete the elements, not the table */
569 freesymtab(x);
570 x->tval &= ~STR;
571 x->tval |= ARR;
572 x->sval = (char *)makesymtab(NSYMTAB);
573 } else {
574 char *buf = makearraystring(a[1], __func__);
575 freeelem(x, buf);
576 free(buf);
577 }
578 tempfree(x);
579 return True;
580}
581
582Cell *
583intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
584{
585 Cell *ap, *k;
586 char *buf;
587
588 ap = execute(a[1]); /* array name */
589 if (!isarr(ap)) {
590 DPRINTF("making %s into an array\n", ap->nval);
591 if (freeable(ap))
592 xfree(ap->sval);
593 ap->tval &= ~(STR | NUM | DONTFREE);
594 ap->tval |= ARR;
595 ap->sval = (char *)makesymtab(NSYMTAB);
596 }
597 buf = makearraystring(a[0], __func__);
598 k = lookup(buf, (Array *)ap->sval);
599 tempfree(ap);
600 free(buf);
601 if (k == NULL)
602 return (False);
603 else
604 return (True);
605}
606
607/* ======== utf-8 code ========== */
608
609/*
610 * awk strings can contain ascii, random 8-bit items (eg latin-1),
611 * or utf-8. u8_isutf tests whether a string starts with a valid
612 * utf-8 sequence, and returns 0 if not (e.g., high bit set)
613 * u8_nextlen returns length of next valid sequence, which is
614 * 1 for ascii, 2..4 for utf-8, or 1 for high bit non-utf
615 * u8_strlen returns length of string in valid utf-8 sequences
616 * and/or high-bit bytes. conversion functions go between byte
617 * number and character number
618 *
619 * in theory, this behaves the same as before for non-utf8 bytes
620 *
621 * limited checking! this is a potential security hole
622 */
623
624/* is s the beginning of a valid utf-8 string? */
625/* return length 1..4 if yes, 0 if no */
626int
627u8_isutf(const char *s)
628{
629 int n, ret;
630 unsigned char c;
631
632 c = s[0];
633 if (c < 128 || awk_mb_cur_max == 1)
634 return 1; /* what if its 0? */
635
636 n = strlen(s);
637 if (n >= 2 && ((c >> 5) & 0x7) == 0x6 && (s[1] & 0xC0) == 0x80) {
638 ret = 2; /* 110xxxxx 10xxxxxx */
639 } else if (n >= 3 && ((c >> 4) & 0xF) == 0xE && (s[1] & 0xC0) == 0x80 && (s[2] & 0xC0) == 0x80) {
640 ret = 3; /* 1110xxxx 10xxxxxx 10xxxxxx */
641 } else if (
642 n >= 4 && ((c >> 3) & 0x1F) == 0x1E && (s[1] & 0xC0) == 0x80 && (s[2] & 0xC0) == 0x80
643 && (s[3] & 0xC0) == 0x80
644 ) {
645 ret = 4; /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
646 } else {
647 ret = 0;
648 }
649 return ret;
650}
651
652/* convert (prefix of) utf8 string to utf-32 rune */
653/* sets *rune to the value, returns the length */
654/* no error checking: watch out */
655int
656u8_rune(int *rune, const char *s)
657{
658 int n, ret;
659 unsigned char c;
660
661 c = s[0];
662 if (c < 128 || awk_mb_cur_max == 1) {
663 *rune = c;
664 return 1;
665 }
666
667 n = strlen(s);
668 if (n >= 2 && ((c >> 5) & 0x7) == 0x6 && (s[1] & 0xC0) == 0x80) {
669 *rune = ((c & 0x1F) << 6) | (s[1] & 0x3F); /* 110xxxxx 10xxxxxx */
670 ret = 2;
671 } else if (n >= 3 && ((c >> 4) & 0xF) == 0xE && (s[1] & 0xC0) == 0x80 && (s[2] & 0xC0) == 0x80) {
672 *rune = ((c & 0xF) << 12) | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F);
673 /* 1110xxxx 10xxxxxx 10xxxxxx */
674 ret = 3;
675 } else if (
676 n >= 4 && ((c >> 3) & 0x1F) == 0x1E && (s[1] & 0xC0) == 0x80 && (s[2] & 0xC0) == 0x80
677 && (s[3] & 0xC0) == 0x80
678 ) {
679 *rune = ((c & 0x7) << 18) | ((s[1] & 0x3F) << 12) | ((s[2] & 0x3F) << 6) | (s[3] & 0x3F);
680 /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
681 ret = 4;
682 } else {
683 *rune = c;
684 ret = 1;
685 }
686 return ret; /* returns one byte if sequence doesnt look like utf */
687}
688
689/* return length of next sequence: 1 for ascii or random, 2..4 for valid utf8 */
690int
691u8_nextlen(const char *s)
692{
693 int len;
694
695 len = u8_isutf(s);
696 if (len == 0)
697 len = 1;
698 return len;
699}
700
701/* return number of utf characters or single non-utf bytes */
702int
703u8_strlen(const char *s)
704{
705 int i, len, n, totlen;
706 unsigned char c;
707
708 n = strlen(s);
709 totlen = 0;
710 for (i = 0; i < n; i += len) {
711 c = s[i];
712 if (c < 128 || awk_mb_cur_max == 1) {
713 len = 1;
714 } else {
715 len = u8_nextlen(&s[i]);
716 }
717 totlen++;
718 if (i > n)
719 FATAL("bad utf count [%s] n=%d i=%d\n", s, n, i);
720 }
721 return totlen;
722}
723
724/* convert utf-8 char number in a string to its byte offset */
725int
726u8_char2byte(const char *s, int charnum)
727{
728 int n;
729 int bytenum = 0;
730
731 while (charnum > 0) {
732 n = u8_nextlen(s);
733 s += n;
734 bytenum += n;
735 charnum--;
736 }
737 return bytenum;
738}
739
740/* convert byte offset in s to utf-8 char number that starts there */
741int
742u8_byte2char(const char *s, int bytenum)
743{
744 int i, len, b;
745 int charnum = 0; /* BUG: what origin? */
746 /* should be 0 to match start==0 which means no match */
747
748 b = strlen(s);
749 if (bytenum > b) {
750 return -1; /* ??? */
751 }
752 for (i = 0; i <= bytenum; i += len) {
753 len = u8_nextlen(s + i);
754 charnum++;
755 }
756 return charnum;
757}
758
759/* runetochar() adapted from rune.c in the plan 9 distribution */
760
761enum {
762 Runeerror = 128, /* from somewhere else */
763 Runemax = 0x10FFFF,
764
765 Bit1 = 7,
766 Bitx = 6,
767 Bit2 = 5,
768 Bit3 = 4,
769 Bit4 = 3,
770 Bit5 = 2,
771
772 T1 = ((1 << (Bit1 + 1)) - 1) ^ 0xFF, /* 0000 0000 */
773 Tx = ((1 << (Bitx + 1)) - 1) ^ 0xFF, /* 1000 0000 */
774 T2 = ((1 << (Bit2 + 1)) - 1) ^ 0xFF, /* 1100 0000 */
775 T3 = ((1 << (Bit3 + 1)) - 1) ^ 0xFF, /* 1110 0000 */
776 T4 = ((1 << (Bit4 + 1)) - 1) ^ 0xFF, /* 1111 0000 */
777 T5 = ((1 << (Bit5 + 1)) - 1) ^ 0xFF, /* 1111 1000 */
778
779 Rune1 = (1 << (Bit1 + 0 * Bitx)) - 1, /* 0000 0000 0000 0000 0111 1111 */
780 Rune2 = (1 << (Bit2 + 1 * Bitx)) - 1, /* 0000 0000 0000 0111 1111 1111 */
781 Rune3 = (1 << (Bit3 + 2 * Bitx)) - 1, /* 0000 0000 1111 1111 1111 1111 */
782 Rune4 = (1 << (Bit4 + 3 * Bitx)) - 1, /* 0011 1111 1111 1111 1111 1111 */
783
784 Maskx = (1 << Bitx) - 1, /* 0011 1111 */
785 Testx = Maskx ^ 0xFF, /* 1100 0000 */
786
787};
788
789int
790runetochar(char *str, int c)
791{
792 /* one character sequence 00000-0007F => 00-7F */
793 if (c <= Rune1) {
794 str[0] = c;
795 return 1;
796 }
797
798 /* two character sequence 00080-007FF => T2 tx */
799 if (c <= Rune2) {
800 str[0] = T2 | (c >> 1 * Bitx);
801 str[1] = Tx | (c & Maskx);
802 return 2;
803 }
804
805 /* three character sequence 00800-0FFFF => T3 tx tx */
806 if (c > Runemax)
807 c = Runeerror;
808 if (c <= Rune3) {
809 str[0] = T3 | (c >> 2 * Bitx);
810 str[1] = Tx | ((c >> 1 * Bitx) & Maskx);
811 str[2] = Tx | (c & Maskx);
812 return 3;
813 }
814
815 /* four character sequence 010000-1FFFFF => T4 tx tx tx */
816 str[0] = T4 | (c >> 3 * Bitx);
817 str[1] = Tx | ((c >> 2 * Bitx) & Maskx);
818 str[2] = Tx | ((c >> 1 * Bitx) & Maskx);
819 str[3] = Tx | (c & Maskx);
820 return 4;
821}
822
823/* ========== end of utf8 code =========== */
824
825Cell *
826matchop(Node **a, int n) /* ~ and match() */
827{
828 Cell *x, *y, *z;
829 char *s, *t;
830 int i;
831 int cstart, cpatlen, len;
832 fa *pfa;
833 int (*mf)(fa *, const char *) = match, mode = 0;
834
835 if (n == MATCHFCN) {
836 mf = pmatch;
837 mode = 1;
838 }
839 x = execute(a[1]); /* a[1] = target text */
840 s = getsval(x);
841 if (a[0] == NULL) /* a[1] == 0: already-compiled reg expr */
842 i = (*mf)((fa *)a[2], s);
843 else {
844 y = execute(a[2]); /* a[2] = regular expr */
845 t = getsval(y);
846 pfa = makedfa(t, mode);
847 i = (*mf)(pfa, s);
848 tempfree(y);
849 }
850 z = x;
851 if (n == MATCHFCN) {
852 int start = patbeg - s + 1; /* origin 1 */
853 if (patlen < 0) {
854 start = 0; /* not found */
855 } else {
856 cstart = u8_byte2char(s, start - 1);
857 cpatlen = 0;
858 for (i = 0; i < patlen; i += len) {
859 len = u8_nextlen(patbeg + i);
860 cpatlen++;
861 }
862
863 start = cstart;
864 patlen = cpatlen;
865 }
866
867 setfval(rstartloc, (Awkfloat)start);
868 setfval(rlengthloc, (Awkfloat)patlen);
869 x = gettemp();
870 x->tval = NUM;
871 x->fval = start;
872 } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
873 x = True;
874 else
875 x = False;
876
877 tempfree(z);
878 return x;
879}
880
881Cell *
882boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
883{
884 Cell *x, *y;
885 int i;
886
887 x = execute(a[0]);
888 i = istrue(x);
889 tempfree(x);
890 switch (n) {
891 case BOR:
892 if (i)
893 return (True);
894 y = execute(a[1]);
895 i = istrue(y);
896 tempfree(y);
897 if (i)
898 return (True);
899 else
900 return (False);
901 case AND:
902 if (!i)
903 return (False);
904 y = execute(a[1]);
905 i = istrue(y);
906 tempfree(y);
907 if (i)
908 return (True);
909 else
910 return (False);
911 case NOT:
912 if (i)
913 return (False);
914 else
915 return (True);
916 default: /* cant happen */
917 FATAL("unknown boolean operator %d", n);
918 }
919 return 0; /* NOTREACHED */
920}
921
922Cell *
923relop(Node **a, int n) /* a[0 < a[1], etc */
924{
925 int i;
926 Cell *x, *y;
927 Awkfloat j;
928 bool x_is_nan, y_is_nan;
929
930 x = execute(a[0]);
931 y = execute(a[1]);
932 x_is_nan = isnan(x->fval);
933 y_is_nan = isnan(y->fval);
934 if (x->tval & NUM && y->tval & NUM) {
935 if ((x_is_nan || y_is_nan) && n != NE)
936 return (False);
937 j = x->fval - y->fval;
938 i = j < 0 ? -1 : (j > 0 ? 1 : 0);
939 } else {
940 i = strcmp(getsval(x), getsval(y));
941 }
942 tempfree(x);
943 tempfree(y);
944 switch (n) {
945 case LT:
946 if (i < 0)
947 return (True);
948 else
949 return (False);
950 case LE:
951 if (i <= 0)
952 return (True);
953 else
954 return (False);
955 case NE:
956 if (x_is_nan && y_is_nan)
957 return (True);
958 else if (i != 0)
959 return (True);
960 else
961 return (False);
962 case EQ:
963 if (i == 0)
964 return (True);
965 else
966 return (False);
967 case GE:
968 if (i >= 0)
969 return (True);
970 else
971 return (False);
972 case GT:
973 if (i > 0)
974 return (True);
975 else
976 return (False);
977 default: /* cant happen */
978 FATAL("unknown relational operator %d", n);
979 }
980 return 0; /* NOTREACHED */
981}
982
983void
984tfree(Cell *a) /* free a tempcell */
985{
986 if (freeable(a)) {
987 DPRINTF("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval);
988 xfree(a->sval);
989 }
990 if (a == tmps)
991 FATAL("tempcell list is curdled");
992 a->cnext = tmps;
993 tmps = a;
994}
995
996Cell *
997gettemp(void) /* get a tempcell */
998{
999 int i;
1000 Cell *x;
1001
1002 if (!tmps) {
1003 tmps = (Cell *)calloc(100, sizeof(*tmps));
1004 if (!tmps)
1005 FATAL("out of space for temporaries");
1006 for (i = 1; i < 100; i++)
1007 tmps[i - 1].cnext = &tmps[i];
1008 tmps[i - 1].cnext = NULL;
1009 }
1010 x = tmps;
1011 tmps = x->cnext;
1012 *x = tempcell;
1013 return (x);
1014}
1015
1016Cell *
1017indirect(Node **a, int n) /* $( a[0] ) */
1018{
1019 Awkfloat val;
1020 Cell *x;
1021 int m;
1022
1023 x = execute(a[0]);
1024 val = getfval(x); /* freebsd: defend against super large field numbers */
1025 if ((Awkfloat)INT_MAX < val)
1026 FATAL("trying to access out of range field %s", x->nval);
1027 m = (int)val;
1028 tempfree(x);
1029 x = fieldadr(m);
1030 x->ctype = OCELL; /* BUG? why are these needed? */
1031 x->csub = CFLD;
1032 return (x);
1033}
1034
1035Cell *
1036substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
1037{
1038 int k, m, n;
1039 int mb, nb;
1040 char *s;
1041 int temp;
1042 Cell *x, *y, *z = NULL;
1043
1044 x = execute(a[0]);
1045 y = execute(a[1]);
1046 if (a[2] != NULL)
1047 z = execute(a[2]);
1048 s = getsval(x);
1049 k = u8_strlen(s) + 1;
1050 if (k <= 1) {
1051 tempfree(x);
1052 tempfree(y);
1053 if (a[2] != NULL) {
1054 tempfree(z);
1055 }
1056 x = gettemp();
1057 setsval(x, "");
1058 return (x);
1059 }
1060 m = (int)getfval(y);
1061 if (m <= 0)
1062 m = 1;
1063 else if (m > k)
1064 m = k;
1065 tempfree(y);
1066 if (a[2] != NULL) {
1067 n = (int)getfval(z);
1068 tempfree(z);
1069 } else
1070 n = k - 1;
1071 if (n < 0)
1072 n = 0;
1073 else if (n > k - m)
1074 n = k - m;
1075 /* m is start, n is length from there */
1076 DPRINTF("substr: m=%d, n=%d, s=%s\n", m, n, s);
1077 y = gettemp();
1078 mb = u8_char2byte(s, m - 1); /* byte offset of start char in s */
1079 nb = u8_char2byte(s, m - 1 + n); /* byte offset of end+1 char in s */
1080
1081 temp = s[nb]; /* with thanks to john linderman */
1082 s[nb] = '\0';
1083 setsval(y, s + mb);
1084 s[nb] = temp;
1085 tempfree(x);
1086 return (y);
1087}
1088
1089Cell *
1090sindex(Node **a, int nnn) /* index(a[0], a[1]) */
1091{
1092 Cell *x, *y, *z;
1093 char *s1, *s2, *p1, *p2, *q;
1094 Awkfloat v = 0.0;
1095
1096 x = execute(a[0]);
1097 s1 = getsval(x);
1098 y = execute(a[1]);
1099 s2 = getsval(y);
1100
1101 z = gettemp();
1102 for (p1 = s1; *p1 != '\0'; p1++) {
1103 for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++)
1104 continue;
1105 if (*p2 == '\0') {
1106 /* v = (awkfloat) (p1 - s1 + 1); origin 1 */
1107
1108 /* should be a function: used in match() as well */
1109 int i, len;
1110 v = 0;
1111 for (i = 0; i < p1 - s1 + 1; i += len) {
1112 len = u8_nextlen(s1 + i);
1113 v++;
1114 }
1115 break;
1116 }
1117 }
1118 tempfree(x);
1119 tempfree(y);
1120 setfval(z, v);
1121 return (z);
1122}
1123
1124int
1125has_utf8(char *s) /* return 1 if s contains any utf-8 (2 bytes or more)
1126 * character */
1127{
1128 int n;
1129
1130 for (n = 0; *s != 0; s += n) {
1131 n = u8_nextlen(s);
1132 if (n > 1)
1133 return 1;
1134 }
1135 return 0;
1136}
1137
1138#define MAXNUMSIZE 50
1139
1140int
1141format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */
1142{
1143 char *fmt;
1144 char *p, *t;
1145 const char *os;
1146 Cell *x;
1147 int flag = 0, n;
1148 int fmtwd; /* format width */
1149 int fmtsz = recsize;
1150 char *buf = *pbuf;
1151 int bufsize = *pbufsize;
1152#define FMTSZ(a) (fmtsz - ((a) - fmt))
1153#define BUFSZ(a) (bufsize - ((a) - buf))
1154
1155 static bool first = true;
1156 static bool have_a_format = false;
1157
1158 if (first) {
1159 char xbuf[100];
1160
1161 snprintf(xbuf, sizeof(xbuf), "%a", 42.0);
1162 have_a_format = (strcmp(xbuf, "0x1.5p+5") == 0);
1163 first = false;
1164 }
1165
1166 os = s;
1167 p = buf;
1168 if ((fmt = (char *)malloc(fmtsz)) == NULL)
1169 FATAL("out of memory in format()");
1170 while (*s) {
1171 adjbuf(&buf, &bufsize, MAXNUMSIZE + 1 + p - buf, recsize, &p, "format1");
1172 if (*s != '%') {
1173 *p++ = *s++;
1174 continue;
1175 }
1176 if (*(s + 1) == '%') {
1177 *p++ = '%';
1178 s += 2;
1179 continue;
1180 }
1181 fmtwd = atoi(s + 1);
1182 if (fmtwd < 0)
1183 fmtwd = -fmtwd;
1184 adjbuf(&buf, &bufsize, fmtwd + 1 + p - buf, recsize, &p, "format2");
1185 for (t = fmt; (*t++ = *s) != '\0'; s++) {
1186 if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE + 1 + t - fmt, recsize, &t, "format3"))
1187 FATAL(
1188 "format item %.30s... ran format() out "
1189 "of memory",
1190 os
1191 );
1192 /* ignore size specifiers */
1193 if (strchr("hjLlqtz", *s) != NULL) { /* the ansi panoply */
1194 t--;
1195 continue;
1196 }
1197 if (isalpha((uschar)*s))
1198 break;
1199 if (*s == '$') {
1200 FATAL("'$' not permitted in awk formats");
1201 }
1202 if (*s == '*') {
1203 if (a == NULL) {
1204 FATAL("not enough args in printf(%s)", os);
1205 }
1206 x = execute(a);
1207 a = a->nnext;
1208 snprintf(t - 1, FMTSZ(t - 1), "%d", fmtwd = (int)getfval(x));
1209 if (fmtwd < 0)
1210 fmtwd = -fmtwd;
1211 adjbuf(&buf, &bufsize, fmtwd + 1 + p - buf, recsize, &p, "format");
1212 t = fmt + strlen(fmt);
1213 tempfree(x);
1214 }
1215 }
1216 *t = '\0';
1217 if (fmtwd < 0)
1218 fmtwd = -fmtwd;
1219 adjbuf(&buf, &bufsize, fmtwd + 1 + p - buf, recsize, &p, "format4");
1220 switch (*s) {
1221 case 'a':
1222 case 'A':
1223 if (have_a_format)
1224 flag = *s;
1225 else
1226 flag = 'f';
1227 break;
1228 case 'f':
1229 case 'e':
1230 case 'g':
1231 case 'E':
1232 case 'G':
1233 flag = 'f';
1234 break;
1235 case 'd':
1236 case 'i':
1237 case 'o':
1238 case 'x':
1239 case 'X':
1240 case 'u':
1241 flag = (*s == 'd' || *s == 'i') ? 'd' : 'u';
1242 *(t - 1) = 'j';
1243 *t = *s;
1244 *++t = '\0';
1245 break;
1246 case 's':
1247 flag = 's';
1248 break;
1249 case 'c':
1250 flag = 'c';
1251 break;
1252 default:
1253 WARNING("weird printf conversion %s", fmt);
1254 flag = '?';
1255 break;
1256 }
1257 if (a == NULL)
1258 FATAL("not enough args in printf(%s)", os);
1259 x = execute(a);
1260 a = a->nnext;
1261 n = MAXNUMSIZE;
1262 if (fmtwd > n)
1263 n = fmtwd;
1264 adjbuf(&buf, &bufsize, 1 + n + p - buf, recsize, &p, "format5");
1265 switch (flag) {
1266 case '?':
1267 snprintf(p, BUFSZ(p), "%s", fmt); /* unknown, so dump it too */
1268 t = getsval(x);
1269 n = strlen(t);
1270 if (fmtwd > n)
1271 n = fmtwd;
1272 adjbuf(&buf, &bufsize, 1 + strlen(p) + n + p - buf, recsize, &p, "format6");
1273 p += strlen(p);
1274 snprintf(p, BUFSZ(p), "%s", t);
1275 break;
1276 case 'a':
1277 case 'A':
1278 case 'f':
1279 snprintf(p, BUFSZ(p), fmt, getfval(x));
1280 break;
1281 case 'd':
1282 snprintf(p, BUFSZ(p), fmt, (intmax_t)getfval(x));
1283 break;
1284 case 'u':
1285 snprintf(p, BUFSZ(p), fmt, (uintmax_t)getfval(x));
1286 break;
1287
1288 case 's': {
1289 t = getsval(x);
1290 n = strlen(t);
1291 /* if simple format or no utf-8 in the string, sprintf
1292 * works */
1293 if (!has_utf8(t) || strcmp(fmt, "%s") == 0) {
1294 if (fmtwd > n)
1295 n = fmtwd;
1296 if (!adjbuf(&buf, &bufsize, 1 + n + p - buf, recsize, &p, "format7"))
1297 FATAL(
1298 "huge string/format (%d chars) "
1299 "in printf %.30s..."
1300 " ran format() out of memory",
1301 n,
1302 t
1303 );
1304 snprintf(p, BUFSZ(p), fmt, t);
1305 break;
1306 }
1307
1308 /* get here if string has utf-8 chars and fmt is not
1309 * plain %s */
1310 /* "%-w.ps", where -, w and .p are all optional */
1311 /* '0' before the w is a flag character */
1312 /* fmt points at % */
1313 int ljust = 0, wid = 0, prec = n, pad = 0;
1314 char *f = fmt + 1;
1315 if (f[0] == '-') {
1316 ljust = 1;
1317 f++;
1318 }
1319 /* flags '0' and '+' are recognized but skipped */
1320 if (f[0] == '0') {
1321 f++;
1322 if (f[0] == '+')
1323 f++;
1324 }
1325 if (f[0] == '+') {
1326 f++;
1327 if (f[0] == '0')
1328 f++;
1329 }
1330 if (isdigit(f[0])) { /* there is a wid */
1331 wid = strtol(f, &f, 10);
1332 }
1333 if (f[0] == '.') { /* there is a .prec */
1334 prec = strtol(++f, &f, 10);
1335 }
1336 if (prec > u8_strlen(t))
1337 prec = u8_strlen(t);
1338 pad = wid > prec ? wid - prec : 0; /* has to be >= 0 */
1339 int i, k, n;
1340
1341 if (ljust) { /* print prec chars from t, then pad blanks */
1342 n = u8_char2byte(t, prec);
1343 for (k = 0; k < n; k++) {
1344 /* putchar(t[k]); */
1345 *p++ = t[k];
1346 }
1347 for (i = 0; i < pad; i++) {
1348 /* printf(" "); */
1349 *p++ = ' ';
1350 }
1351 } else { /* print pad blanks, then prec chars from t */
1352 for (i = 0; i < pad; i++) {
1353 /* printf(" "); */
1354 *p++ = ' ';
1355 }
1356 n = u8_char2byte(t, prec);
1357 for (k = 0; k < n; k++) {
1358 /* putchar(t[k]); */
1359 *p++ = t[k];
1360 }
1361 }
1362 *p = 0;
1363 break;
1364 }
1365
1366 case 'c': {
1367 /*
1368 * if a numeric value is given, awk should just turn
1369 * it into a character and print it:
1370 * BEGIN { printf("%c\n", 65) }
1371 * prints "a"
1372 *
1373 * but what if the numeric value is > 128 and
1374 * represents a valid unicode code point?!? we do
1375 * our best to convert it back into UTF-8. if we
1376 * cant, we output the encoding of the unicode
1377 * "invalid character", 0xfffd
1378 */
1379 if (isnum(x)) {
1380 int charval = (int)getfval(x);
1381
1382 if (charval != 0) {
1383 if (charval < 128 || awk_mb_cur_max == 1)
1384 snprintf(p, BUFSZ(p), fmt, charval);
1385 else {
1386 /* possible unicode character */
1387 size_t count;
1388 char *bs = wide_char_to_byte_str(charval, &count);
1389
1390 if (bs == NULL) { /* invalid character */
1391 /* use unicode invalid
1392 * character, 0xfffd */
1393 static char invalid_char[] = "\357\277"
1394 "\275";
1395 bs = invalid_char;
1396 count = 3;
1397 }
1398 t = bs;
1399 n = count;
1400 goto format_percent_c;
1401 }
1402 } else {
1403 *p++ = '\0'; /* explicit null byte */
1404 *p = '\0'; /* next output will start
1405 * here */
1406 }
1407 break;
1408 }
1409 t = getsval(x);
1410 n = u8_nextlen(t);
1411 format_percent_c:
1412 if (n < 2) { /* not utf8 */
1413 snprintf(p, BUFSZ(p), fmt, getsval(x)[0]);
1414 break;
1415 }
1416
1417 /* utf8 character, almost same song and dance as for %s */
1418 int ljust = 0, wid = 0, prec = n, pad = 0;
1419 char *f = fmt + 1;
1420 if (f[0] == '-') {
1421 ljust = 1;
1422 f++;
1423 }
1424 /* flags '0' and '+' are recognized but skipped */
1425 if (f[0] == '0') {
1426 f++;
1427 if (f[0] == '+')
1428 f++;
1429 }
1430 if (f[0] == '+') {
1431 f++;
1432 if (f[0] == '0')
1433 f++;
1434 }
1435 if (isdigit(f[0])) { /* there is a wid */
1436 wid = strtol(f, &f, 10);
1437 }
1438 if (f[0] == '.') { /* there is a .prec */
1439 prec = strtol(++f, &f, 10);
1440 }
1441 if (prec > 1) /* %c: only one character */
1442 prec = 1;
1443 pad = wid > prec ? wid - prec : 0; /* has to be >= 0 */
1444 int i;
1445
1446 if (ljust) { /* print one char from t, then pad blanks */
1447 for (i = 0; i < n; i++)
1448 *p++ = t[i];
1449 for (i = 0; i < pad; i++) {
1450 /* printf(" "); */
1451 *p++ = ' ';
1452 }
1453 } else { /* print pad blanks, then prec chars from t */
1454 for (i = 0; i < pad; i++) {
1455 /* printf(" "); */
1456 *p++ = ' ';
1457 }
1458 for (i = 0; i < n; i++)
1459 *p++ = t[i];
1460 }
1461 *p = 0;
1462 break;
1463 }
1464 default:
1465 FATAL("can't happen: bad conversion %c in format()", flag);
1466 }
1467
1468 tempfree(x);
1469 p += strlen(p);
1470 s++;
1471 }
1472 *p = '\0';
1473 free(fmt);
1474 for (; a; a = a->nnext) { /* evaluate any remaining args */
1475 x = execute(a);
1476 tempfree(x);
1477 }
1478 *pbuf = buf;
1479 *pbufsize = bufsize;
1480 return p - buf;
1481}
1482
1483Cell *
1484awksprintf(Node **a, int n) /* sprintf(a[0]) */
1485{
1486 Cell *x;
1487 Node *y;
1488 char *buf;
1489 int bufsz = 3 * recsize;
1490
1491 if ((buf = (char *)malloc(bufsz)) == NULL)
1492 FATAL("out of memory in awksprintf");
1493 y = a[0]->nnext;
1494 x = execute(a[0]);
1495 if (format(&buf, &bufsz, getsval(x), y) == -1)
1496 FATAL("sprintf string %.30s... too long. can't happen.", buf);
1497 tempfree(x);
1498 x = gettemp();
1499 x->sval = buf;
1500 x->tval = STR;
1501 return (x);
1502}
1503
1504Cell *
1505awkprintf(Node **a, int n) /* printf */
1506{ /* a[0] is list of args, starting with format string */
1507 /* a[1] is redirection operator, a[2] is redirection file */
1508 FILE *fp;
1509 Cell *x;
1510 Node *y;
1511 char *buf;
1512 int len;
1513 int bufsz = 3 * recsize;
1514
1515 if ((buf = (char *)malloc(bufsz)) == NULL)
1516 FATAL("out of memory in awkprintf");
1517 y = a[0]->nnext;
1518 x = execute(a[0]);
1519 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
1520 FATAL("printf string %.30s... too long. can't happen.", buf);
1521 tempfree(x);
1522 if (a[1] == NULL) {
1523 /* fputs(buf, stdout); */
1524 fwrite(buf, len, 1, stdout);
1525 if (ferror(stdout))
1526 FATAL("write error on stdout");
1527 } else {
1528 fp = redirect(ptoi(a[1]), a[2]);
1529 /* fputs(buf, fp); */
1530 fwrite(buf, len, 1, fp);
1531 fflush(fp);
1532 if (ferror(fp))
1533 FATAL("write error on %s", filename(fp));
1534 }
1535 free(buf);
1536 return (True);
1537}
1538
1539Cell *
1540arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
1541{
1542 Awkfloat i, j = 0;
1543 double v;
1544 Cell *x, *y, *z;
1545
1546 x = execute(a[0]);
1547 i = getfval(x);
1548 tempfree(x);
1549 if (n != UMINUS && n != UPLUS) {
1550 y = execute(a[1]);
1551 j = getfval(y);
1552 tempfree(y);
1553 }
1554 z = gettemp();
1555 switch (n) {
1556 case ADD:
1557 i += j;
1558 break;
1559 case MINUS:
1560 i -= j;
1561 break;
1562 case MULT:
1563 i *= j;
1564 break;
1565 case DIVIDE:
1566 if (j == 0)
1567 FATAL("division by zero");
1568 i /= j;
1569 break;
1570 case MOD:
1571 if (j == 0)
1572 FATAL("division by zero in mod");
1573 modf(i / j, &v);
1574 i = i - j * v;
1575 break;
1576 case UMINUS:
1577 i = -i;
1578 break;
1579 case UPLUS: /* handled by getfval(), above */
1580 break;
1581 case POWER:
1582 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1583 i = ipow(i, (int)j);
1584 else
1585 i = pow_errcheck(i, j);
1586 break;
1587 default: /* cant happen */
1588 FATAL("illegal arithmetic operator %d", n);
1589 }
1590 setfval(z, i);
1591 return (z);
1592}
1593
1594double
1595ipow(double x, int n) /* x**n. ought to be done by pow, but isnt always */
1596{
1597 double v;
1598
1599 if (n <= 0)
1600 return 1;
1601 v = ipow(x, n / 2);
1602 if (n % 2 == 0)
1603 return v * v;
1604 else
1605 return x * v * v;
1606}
1607
1608Cell *
1609incrdecr(Node **a, int n) /* a[0]++, etc */
1610{
1611 Cell *x, *z;
1612 int k;
1613 Awkfloat xf;
1614
1615 x = execute(a[0]);
1616 xf = getfval(x);
1617 k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1618 if (n == PREINCR || n == PREDECR) {
1619 setfval(x, xf + k);
1620 return (x);
1621 }
1622 z = gettemp();
1623 setfval(z, xf);
1624 setfval(x, xf + k);
1625 tempfree(x);
1626 return (z);
1627}
1628
1629Cell *
1630assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc */
1631{ /* this is subtle; dont muck with it */
1632 Cell *x, *y;
1633 Awkfloat xf, yf;
1634 double v;
1635
1636 y = execute(a[1]);
1637 x = execute(a[0]);
1638 if (n == ASSIGN) { /* ordinary assignment */
1639 if (x == y && !(x->tval & (FLD | REC)) && x != nfloc)
1640 ; /* self-assignment: leave alone unless its a field or
1641 * NF */
1642 else if ((y->tval & (STR | NUM)) == (STR | NUM)) {
1643 yf = getfval(y);
1644 setsval(x, getsval(y));
1645 x->fval = yf;
1646 x->tval |= NUM;
1647 } else if (isstr(y))
1648 setsval(x, getsval(y));
1649 else if (isnum(y))
1650 setfval(x, getfval(y));
1651 else
1652 funnyvar(y, "read value of");
1653 tempfree(y);
1654 return (x);
1655 }
1656 xf = getfval(x);
1657 yf = getfval(y);
1658 switch (n) {
1659 case ADDEQ:
1660 xf += yf;
1661 break;
1662 case SUBEQ:
1663 xf -= yf;
1664 break;
1665 case MULTEQ:
1666 xf *= yf;
1667 break;
1668 case DIVEQ:
1669 if ((x->tval & CON) != 0)
1670 FATAL("non-constant required for left side of /=");
1671 if (yf == 0)
1672 FATAL("division by zero in /=");
1673 xf /= yf;
1674 break;
1675 case MODEQ:
1676 if (yf == 0)
1677 FATAL("division by zero in %%=");
1678 modf(xf / yf, &v);
1679 xf = xf - yf * v;
1680 break;
1681 case POWEQ:
1682 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1683 xf = ipow(xf, (int)yf);
1684 else
1685 xf = pow_errcheck(xf, yf);
1686 break;
1687 default:
1688 FATAL("illegal assignment operator %d", n);
1689 break;
1690 }
1691 tempfree(y);
1692 setfval(x, xf);
1693 return (x);
1694}
1695
1696Cell *
1697cat(Node **a, int q) /* a[0] cat a[1] */
1698{
1699 Cell *x, *y, *z;
1700 int n1, n2;
1701 char *s = NULL;
1702 int ssz = 0;
1703
1704 x = execute(a[0]);
1705 n1 = strlen(getsval(x));
1706 adjbuf(&s, &ssz, n1 + 1, recsize, 0, "cat1");
1707 memcpy(s, x->sval, n1);
1708
1709 tempfree(x);
1710
1711 y = execute(a[1]);
1712 n2 = strlen(getsval(y));
1713 adjbuf(&s, &ssz, n1 + n2 + 1, recsize, 0, "cat2");
1714 memcpy(s + n1, y->sval, n2);
1715 s[n1 + n2] = '\0';
1716
1717 tempfree(y);
1718
1719 z = gettemp();
1720 z->sval = s;
1721 z->tval = STR;
1722
1723 return (z);
1724}
1725
1726Cell *
1727pastat(Node **a, int n) /* a[0] { a[1] } */
1728{
1729 Cell *x;
1730
1731 if (a[0] == NULL)
1732 x = execute(a[1]);
1733 else {
1734 x = execute(a[0]);
1735 if (istrue(x)) {
1736 tempfree(x);
1737 x = execute(a[1]);
1738 }
1739 }
1740 return x;
1741}
1742
1743Cell *
1744dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
1745{
1746 Cell *x;
1747 int pair;
1748
1749 pair = ptoi(a[3]);
1750 if (pairstack[pair] == 0) {
1751 x = execute(a[0]);
1752 if (istrue(x))
1753 pairstack[pair] = 1;
1754 tempfree(x);
1755 }
1756 if (pairstack[pair] == 1) {
1757 x = execute(a[1]);
1758 if (istrue(x))
1759 pairstack[pair] = 0;
1760 tempfree(x);
1761 x = execute(a[2]);
1762 return (x);
1763 }
1764 return (False);
1765}
1766
1767Cell *
1768split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
1769{
1770 Cell *x = NULL, *y, *ap;
1771 const char *s, *origs, *t;
1772 const char *fs = NULL;
1773 char *origfs = NULL;
1774 int sep;
1775 char temp, num[50];
1776 int n, tempstat, arg3type;
1777 int j;
1778 double result;
1779
1780 y = execute(a[0]); /* source string */
1781 origs = s = strdup(getsval(y));
1782 tempfree(y);
1783 arg3type = ptoi(a[3]);
1784 if (a[2] == NULL) { /* BUG: CSV should override implicit fs but not explicit */
1785 fs = getsval(fsloc);
1786 } else if (arg3type == STRING) { /* split(str,arr,"string") */
1787 x = execute(a[2]);
1788 fs = origfs = strdup(getsval(x));
1789 tempfree(x);
1790 } else if (arg3type == REGEXPR) {
1791 fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1792 } else {
1793 FATAL("illegal type of split");
1794 }
1795 sep = *fs;
1796 ap = execute(a[1]); /* array name */
1797 /* BUG 7/26/22: this appears not to reset array: see c1/asplit */
1798 freesymtab(ap);
1799 DPRINTF("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs);
1800 ap->tval &= ~STR;
1801 ap->tval |= ARR;
1802 ap->sval = (char *)makesymtab(NSYMTAB);
1803
1804 n = 0;
1805 if (arg3type == REGEXPR && strlen((char *)((fa *)a[2])->restr) == 0) {
1806 /* split(s, a, // ); have to arrange that it looks like empty sep
1807 */
1808 arg3type = 0;
1809 fs = "";
1810 sep = 0;
1811 }
1812 if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) { /* reg expr */
1813 fa *pfa;
1814 if (arg3type == REGEXPR) { /* its ready already */
1815 pfa = (fa *)a[2];
1816 } else {
1817 pfa = makedfa(fs, 1);
1818 }
1819 if (nematch(pfa, s)) {
1820 tempstat = pfa->initstat;
1821 pfa->initstat = 2;
1822 do {
1823 n++;
1824 snprintf(num, sizeof(num), "%d", n);
1825 temp = *patbeg;
1826 setptr(patbeg, '\0');
1827 if (is_number(s, &result))
1828 setsymtab(num, s, result, STR | NUM, (Array *)ap->sval);
1829 else
1830 setsymtab(num, s, 0.0, STR, (Array *)ap->sval);
1831 setptr(patbeg, temp);
1832 s = patbeg + patlen;
1833 if (*(patbeg + patlen - 1) == '\0' || *s == '\0') {
1834 n++;
1835 snprintf(num, sizeof(num), "%d", n);
1836 setsymtab(num, "", 0.0, STR, (Array *)ap->sval);
1837 pfa->initstat = tempstat;
1838 goto spdone;
1839 }
1840 } while (nematch(pfa, s));
1841 pfa->initstat = tempstat; /* bwk: has to be here to reset */
1842 /* cf gsub and refldbld */
1843 }
1844 n++;
1845 snprintf(num, sizeof(num), "%d", n);
1846 if (is_number(s, &result))
1847 setsymtab(num, s, result, STR | NUM, (Array *)ap->sval);
1848 else
1849 setsymtab(num, s, 0.0, STR, (Array *)ap->sval);
1850 spdone:
1851 pfa = NULL;
1852
1853 } else if (a[2] == NULL && CSV) { /* CSV only if no explicit separator */
1854 char *newt = (char *)malloc(strlen(s) + 1); /* for building new string; reuse for each field */
1855 if (newt == NULL)
1856 FATAL("out of space in split");
1857 for (;;) {
1858 char *fr = newt;
1859 n++;
1860 if (*s == '"') { /* start of "..." */
1861 for (s++; *s != '\0';) {
1862 if (*s == '"' && s[1] != '\0' && s[1] == '"') {
1863 s += 2; /* doubled quote */
1864 *fr++ = '"';
1865 } else if (*s == '"' && (s[1] == '\0' || s[1] == ',')) {
1866 s++; /* skip over closing quote
1867 */
1868 break;
1869 } else {
1870 *fr++ = *s++;
1871 }
1872 }
1873 *fr++ = 0;
1874 } else { /* unquoted field */
1875 while (*s != ',' && *s != '\0')
1876 *fr++ = *s++;
1877 *fr++ = 0;
1878 }
1879 snprintf(num, sizeof(num), "%d", n);
1880 if (is_number(newt, &result))
1881 setsymtab(num, newt, result, STR | NUM, (Array *)ap->sval);
1882 else
1883 setsymtab(num, newt, 0.0, STR, (Array *)ap->sval);
1884 if (*s++ == '\0')
1885 break;
1886 }
1887 free(newt);
1888
1889 } else if (!CSV && sep == ' ') { /* usual case: split on white space */
1890 for (n = 0;;) {
1891#define ISWS(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
1892 while (ISWS(*s))
1893 s++;
1894 if (*s == '\0')
1895 break;
1896 n++;
1897 t = s;
1898 do
1899 s++;
1900 while (*s != '\0' && !ISWS(*s));
1901 temp = *s;
1902 setptr(s, '\0');
1903 snprintf(num, sizeof(num), "%d", n);
1904 if (is_number(t, &result))
1905 setsymtab(num, t, result, STR | NUM, (Array *)ap->sval);
1906 else
1907 setsymtab(num, t, 0.0, STR, (Array *)ap->sval);
1908 setptr(s, temp);
1909 if (*s != '\0')
1910 s++;
1911 }
1912
1913 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1914 for (n = 0; *s != '\0'; s += u8_nextlen(s)) {
1915 char buf[10];
1916 n++;
1917 snprintf(num, sizeof(num), "%d", n);
1918
1919 for (j = 0; j < u8_nextlen(s); j++) {
1920 buf[j] = s[j];
1921 }
1922 buf[j] = '\0';
1923
1924 if (isdigit((uschar)buf[0]))
1925 setsymtab(num, buf, atof(buf), STR | NUM, (Array *)ap->sval);
1926 else
1927 setsymtab(num, buf, 0.0, STR, (Array *)ap->sval);
1928 }
1929
1930 } else if (*s != '\0') { /* some random single character */
1931 for (;;) {
1932 n++;
1933 t = s;
1934 while (*s != sep && *s != '\0')
1935 s++;
1936 temp = *s;
1937 setptr(s, '\0');
1938 snprintf(num, sizeof(num), "%d", n);
1939 if (is_number(t, &result))
1940 setsymtab(num, t, result, STR | NUM, (Array *)ap->sval);
1941 else
1942 setsymtab(num, t, 0.0, STR, (Array *)ap->sval);
1943 setptr(s, temp);
1944 if (*s++ == '\0')
1945 break;
1946 }
1947 }
1948 tempfree(ap);
1949 xfree(origs);
1950 xfree(origfs);
1951 x = gettemp();
1952 x->tval = NUM;
1953 x->fval = n;
1954 return (x);
1955}
1956
1957Cell *
1958condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1959{
1960 Cell *x;
1961
1962 x = execute(a[0]);
1963 if (istrue(x)) {
1964 tempfree(x);
1965 x = execute(a[1]);
1966 } else {
1967 tempfree(x);
1968 x = execute(a[2]);
1969 }
1970 return (x);
1971}
1972
1973Cell *
1974ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1975{
1976 Cell *x;
1977
1978 x = execute(a[0]);
1979 if (istrue(x)) {
1980 tempfree(x);
1981 x = execute(a[1]);
1982 } else if (a[2] != NULL) {
1983 tempfree(x);
1984 x = execute(a[2]);
1985 }
1986 return (x);
1987}
1988
1989Cell *
1990whilestat(Node **a, int n) /* while (a[0]) a[1] */
1991{
1992 Cell *x;
1993
1994 for (;;) {
1995 x = execute(a[0]);
1996 if (!istrue(x))
1997 return (x);
1998 tempfree(x);
1999 x = execute(a[1]);
2000 if (isbreak(x)) {
2001 x = True;
2002 return (x);
2003 }
2004 if (isnext(x) || isexit(x) || isret(x))
2005 return (x);
2006 tempfree(x);
2007 }
2008}
2009
2010Cell *
2011dostat(Node **a, int n) /* do a[0]; while(a[1]) */
2012{
2013 Cell *x;
2014
2015 for (;;) {
2016 x = execute(a[0]);
2017 if (isbreak(x))
2018 return True;
2019 if (isnext(x) || isexit(x) || isret(x))
2020 return (x);
2021 tempfree(x);
2022 x = execute(a[1]);
2023 if (!istrue(x))
2024 return (x);
2025 tempfree(x);
2026 }
2027}
2028
2029Cell *
2030forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
2031{
2032 Cell *x;
2033
2034 x = execute(a[0]);
2035 tempfree(x);
2036 for (;;) {
2037 if (a[1] != NULL) {
2038 x = execute(a[1]);
2039 if (!istrue(x))
2040 return (x);
2041 else
2042 tempfree(x);
2043 }
2044 x = execute(a[3]);
2045 if (isbreak(x)) /* turn off break */
2046 return True;
2047 if (isnext(x) || isexit(x) || isret(x))
2048 return (x);
2049 tempfree(x);
2050 x = execute(a[2]);
2051 tempfree(x);
2052 }
2053}
2054
2055Cell *
2056instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
2057{
2058 Cell *x, *vp, *arrayp, *cp, *ncp;
2059 Array *tp;
2060 int i;
2061
2062 vp = execute(a[0]);
2063 arrayp = execute(a[1]);
2064 if (!isarr(arrayp)) {
2065 return True;
2066 }
2067 tp = (Array *)arrayp->sval;
2068 tempfree(arrayp);
2069 for (i = 0; i < tp->size; i++) { /* this routine knows too much */
2070 for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
2071 setsval(vp, cp->nval);
2072 ncp = cp->cnext;
2073 x = execute(a[2]);
2074 if (isbreak(x)) {
2075 tempfree(vp);
2076 return True;
2077 }
2078 if (isnext(x) || isexit(x) || isret(x)) {
2079 tempfree(vp);
2080 return (x);
2081 }
2082 tempfree(x);
2083 }
2084 }
2085 return True;
2086}
2087
2088static char *
2089nawk_convert(const char *s, int (*fun_c)(int), wint_t (*fun_wc)(wint_t))
2090{
2091 char *buf = NULL;
2092 char *pbuf = NULL;
2093 const char *ps = NULL;
2094 size_t n = 0;
2095 wchar_t wc;
2096 const size_t sz = awk_mb_cur_max;
2097 int unused;
2098
2099 if (sz == 1) {
2100 buf = tostring(s);
2101
2102 for (pbuf = buf; *pbuf; pbuf++)
2103 *pbuf = fun_c((uschar)*pbuf);
2104
2105 return buf;
2106 } else {
2107 /* upper/lower character may be shorter/longer */
2108 buf = tostringN(s, strlen(s) * sz + 1);
2109
2110 (void)mbtowc(NULL, NULL, 0); /* reset internal state */
2111 /*
2112 * reset internal state here too
2113 * assign result to avoid a compiler warning. (casting to void
2114 * doesnt work.)
2115 * increment said variable to avoid a different warning
2116 */
2117 unused = wctomb(NULL, L'\0');
2118 unused++;
2119
2120 ps = s;
2121 pbuf = buf;
2122 while (n = mbtowc(&wc, ps, sz), n > 0 && n != (size_t)-1 && n != (size_t)-2) {
2123 ps += n;
2124
2125 n = wctomb(pbuf, fun_wc(wc));
2126 if (n == (size_t)-1)
2127 FATAL("illegal wide character %s", s);
2128
2129 pbuf += n;
2130 }
2131
2132 *pbuf = '\0';
2133
2134 if (n)
2135 FATAL("illegal byte sequence %s", s);
2136
2137 return buf;
2138 }
2139}
2140
2141#ifdef __DJGPP__
2142static wint_t
2143towupper(wint_t wc)
2144{
2145 if (wc >= 0 && wc < 256)
2146 return toupper(wc & 0xFF);
2147
2148 return wc;
2149}
2150
2151static wint_t
2152towlower(wint_t wc)
2153{
2154 if (wc >= 0 && wc < 256)
2155 return tolower(wc & 0xFF);
2156
2157 return wc;
2158}
2159#endif
2160
2161static char *
2162nawk_toupper(const char *s)
2163{
2164 return nawk_convert(s, toupper, towupper);
2165}
2166
2167static char *
2168nawk_tolower(const char *s)
2169{
2170 return nawk_convert(s, tolower, towlower);
2171}
2172
2173Cell *
2174bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
2175{
2176 Cell *x, *y;
2177 Awkfloat u = 0;
2178 int t;
2179 Awkfloat tmp;
2180 char *buf;
2181 Node *nextarg;
2182 FILE *fp;
2183 int status = 0;
2184 int estatus = 0;
2185
2186 t = ptoi(a[0]);
2187 x = execute(a[1]);
2188 nextarg = a[1]->nnext;
2189 switch (t) {
2190 case FLENGTH:
2191 if (isarr(x))
2192 u = ((Array *)x->sval)->nelem; /* GROT. should be function */
2193 else
2194 u = u8_strlen(getsval(x));
2195 break;
2196 case FLOG:
2197 u = log_errcheck(getfval(x));
2198 break;
2199 case FINT:
2200 modf(getfval(x), &u);
2201 break;
2202 case FEXP:
2203 u = exp_errcheck(getfval(x));
2204 break;
2205 case FSQRT:
2206 u = sqrt_errcheck(getfval(x));
2207 break;
2208 case FSIN:
2209 u = sin(getfval(x));
2210 break;
2211 case FCOS:
2212 u = cos(getfval(x));
2213 break;
2214 case FATAN:
2215 if (nextarg == NULL) {
2216 WARNING("atan2 requires two arguments; returning 1.0");
2217 u = 1.0;
2218 } else {
2219 y = execute(a[1]->nnext);
2220 u = atan2(getfval(x), getfval(y));
2221 tempfree(y);
2222 nextarg = nextarg->nnext;
2223 }
2224 break;
2225 case FSYSTEM:
2226 fflush(stdout); /* in case something is buffered already */
2227 estatus = status = system(getsval(x));
2228 if (status != -1) {
2229 if (WIFEXITED(status)) {
2230 estatus = WEXITSTATUS(status);
2231 } else if (WIFSIGNALED(status)) {
2232 estatus = WTERMSIG(status) + 256;
2233#ifdef WCOREDUMP
2234 if (WCOREDUMP(status))
2235 estatus += 256;
2236#endif
2237 } else /* something else?!? */
2238 estatus = 0;
2239 }
2240 /* else estatus was set to -1 */
2241 u = estatus;
2242 break;
2243 case FRAND:
2244 /* random() returns numbers in [0..2^31-1]
2245 * in order to get a number in [0, 1), divide it by 2^31
2246 */
2247 do {
2248 /* exact if awkfloat wide enough */
2249 u = (Awkfloat)random();
2250 u /= 0x80000000; /* should be exact */
2251 } while (u >= 1.0); /* in case awkfloat is narrow */
2252 break;
2253 case FSRAND:
2254 if (isrec(x)) /* no argument provided */
2255 u = time((time_t *)0);
2256 else
2257 u = getfval(x);
2258 tmp = u;
2259 srandom((unsigned long)u);
2260 u = srand_seed;
2261 srand_seed = tmp;
2262 break;
2263 case FTOUPPER:
2264 case FTOLOWER:
2265 if (t == FTOUPPER)
2266 buf = nawk_toupper(getsval(x));
2267 else
2268 buf = nawk_tolower(getsval(x));
2269 tempfree(x);
2270 x = gettemp();
2271 setsval(x, buf);
2272 free(buf);
2273 return x;
2274 case FFLUSH:
2275 if (isrec(x) || strlen(getsval(x)) == 0) {
2276 flush_all(); /* fflush() or fflush("") -> all */
2277 u = 0;
2278 } else if ((fp = openfile(FFLUSH, getsval(x), NULL)) == NULL)
2279 u = EOF;
2280 else
2281 u = fflush(fp);
2282 break;
2283 default: /* cant happen */
2284 FATAL("illegal function type %d", t);
2285 break;
2286 }
2287 tempfree(x);
2288 x = gettemp();
2289 setfval(x, u);
2290 if (nextarg != NULL) {
2291 WARNING("warning: function has too many arguments");
2292 for (; nextarg; nextarg = nextarg->nnext) {
2293 y = execute(nextarg);
2294 tempfree(y);
2295 }
2296 }
2297 return (x);
2298}
2299
2300Cell *
2301printstat(Node **a, int n) /* print a[0] */
2302{
2303 Node *x;
2304 Cell *y;
2305 FILE *fp;
2306
2307 if (a[1] == NULL) /* a[1] is redirection operator, a[2] is file */
2308 fp = stdout;
2309 else
2310 fp = redirect(ptoi(a[1]), a[2]);
2311 for (x = a[0]; x != NULL; x = x->nnext) {
2312 y = execute(x);
2313 fputs(getpssval(y), fp);
2314 tempfree(y);
2315 if (x->nnext == NULL)
2316 fputs(getsval(orsloc), fp);
2317 else
2318 fputs(getsval(ofsloc), fp);
2319 }
2320 if (a[1] != NULL)
2321 fflush(fp);
2322 if (ferror(fp))
2323 FATAL("write error on %s", filename(fp));
2324 return (True);
2325}
2326
2327Cell *
2328nullproc(Node **a, int n)
2329{
2330 return 0;
2331}
2332
2333FILE *
2334redirect(int a, Node *b) /* set up all i/o redirections */
2335{
2336 FILE *fp;
2337 Cell *x;
2338 char *fname;
2339
2340 x = execute(b);
2341 fname = getsval(x);
2342 fp = openfile(a, fname, NULL);
2343 if (fp == NULL)
2344 FATAL("can't open file %s", fname);
2345 tempfree(x);
2346 return fp;
2347}
2348
2349struct files {
2350 FILE *fp;
2351 const char *fname;
2352 int mode; /* '|', 'a', 'w' => LE/LT, GT */
2353} *files;
2354
2355size_t nfiles;
2356
2357static void
2358stdinit(void) /* in case stdin, etc., are not constants */
2359{
2360 nfiles = FOPEN_MAX;
2361 files = (struct files *)calloc(nfiles, sizeof(*files));
2362 if (files == NULL)
2363 FATAL("can't allocate file memory for %zu files", nfiles);
2364 files[0].fp = stdin;
2365 files[0].fname = tostring("/dev/stdin");
2366 files[0].mode = LT;
2367 files[1].fp = stdout;
2368 files[1].fname = tostring("/dev/stdout");
2369 files[1].mode = GT;
2370 files[2].fp = stderr;
2371 files[2].fname = tostring("/dev/stderr");
2372 files[2].mode = GT;
2373}
2374
2375FILE *
2376openfile(int a, const char *us, bool *pnewflag)
2377{
2378 const char *s = us;
2379 size_t i;
2380 int m;
2381 FILE *fp = NULL;
2382 struct stat sbuf;
2383
2384 if (*s == '\0')
2385 FATAL("null file name in print or getline");
2386
2387 for (i = 0; i < nfiles; i++)
2388 if (files[i].fname && strcmp(s, files[i].fname) == 0
2389 && (a == files[i].mode || (a == APPEND && files[i].mode == GT) || a == FFLUSH)) {
2390 if (pnewflag)
2391 *pnewflag = false;
2392 return files[i].fp;
2393 }
2394 if (a == FFLUSH) /* didn't find it, so dont create it! */
2395 return NULL;
2396 for (i = 0; i < nfiles; i++)
2397 if (files[i].fp == NULL)
2398 break;
2399 if (i >= nfiles) {
2400 struct files *nf;
2401 size_t nnf = nfiles + FOPEN_MAX;
2402 nf = (struct files *)realloc(files, nnf * sizeof(*nf));
2403 if (nf == NULL)
2404 FATAL("cannot grow files for %s and %zu files", s, nnf);
2405 memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf));
2406 nfiles = nnf;
2407 files = nf;
2408 }
2409
2410 fflush(stdout); /* force a semblance of order */
2411
2412 /* dont try to read or write a directory */
2413 if (a == LT || a == GT || a == APPEND)
2414 if (stat(s, &sbuf) == 0 && S_ISDIR(sbuf.st_mode))
2415 return NULL;
2416
2417 m = a;
2418 if (a == GT) {
2419 fp = fopen(s, "w");
2420 } else if (a == APPEND) {
2421 fp = fopen(s, "a");
2422 m = GT; /* so can mix > and >> */
2423 } else if (a == '|') { /* output pipe */
2424 fp = popen(s, "w");
2425 } else if (a == LE) { /* input pipe */
2426 fp = popen(s, "r");
2427 } else if (a == LT) { /* getline <file */
2428 fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
2429 } else /* cant happen */
2430 FATAL("illegal redirection %d", a);
2431 if (fp != NULL) {
2432 files[i].fname = tostring(s);
2433 files[i].fp = fp;
2434 files[i].mode = m;
2435 if (pnewflag)
2436 *pnewflag = true;
2437 if (fp != stdin && fp != stdout && fp != stderr)
2438 (void)fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
2439 }
2440 return fp;
2441}
2442
2443const char *
2444filename(FILE *fp)
2445{
2446 size_t i;
2447
2448 for (i = 0; i < nfiles; i++)
2449 if (fp == files[i].fp)
2450 return files[i].fname;
2451 return "???";
2452}
2453
2454Cell *
2455closefile(Node **a, int n)
2456{
2457 Cell *x;
2458 size_t i;
2459 bool stat;
2460
2461 x = execute(a[0]);
2462 getsval(x);
2463 stat = true;
2464 for (i = 0; i < nfiles; i++) {
2465 if (!files[i].fname || strcmp(x->sval, files[i].fname) != 0)
2466 continue;
2467 if (files[i].mode == GT || files[i].mode == '|')
2468 fflush(files[i].fp);
2469 if (ferror(files[i].fp)) {
2470 if ((files[i].mode == GT && files[i].fp != stderr) || files[i].mode == '|')
2471 FATAL("write error on %s", files[i].fname);
2472 else
2473 WARNING("i/o error occurred on %s", files[i].fname);
2474 }
2475 if (files[i].fp == stdin || files[i].fp == stdout || files[i].fp == stderr)
2476 stat = freopen("/dev/null", "r+", files[i].fp) == NULL;
2477 else if (files[i].mode == '|' || files[i].mode == LE)
2478 stat = pclose(files[i].fp) == -1;
2479 else
2480 stat = fclose(files[i].fp) == EOF;
2481 if (stat)
2482 WARNING("i/o error occurred closing %s", files[i].fname);
2483 xfree(files[i].fname);
2484 files[i].fname = NULL; /* watch out for ref thru this */
2485 files[i].fp = NULL;
2486 break;
2487 }
2488 tempfree(x);
2489 x = gettemp();
2490 setfval(x, (Awkfloat)(stat ? -1 : 0));
2491 return (x);
2492}
2493
2494void
2495closeall(void)
2496{
2497 size_t i;
2498 bool stat = false;
2499
2500 for (i = 0; i < nfiles; i++) {
2501 if (!files[i].fp)
2502 continue;
2503 if (files[i].mode == GT || files[i].mode == '|')
2504 fflush(files[i].fp);
2505 if (ferror(files[i].fp)) {
2506 if ((files[i].mode == GT && files[i].fp != stderr) || files[i].mode == '|')
2507 FATAL("write error on %s", files[i].fname);
2508 else
2509 WARNING("i/o error occurred on %s", files[i].fname);
2510 }
2511 if (files[i].fp == stdin || files[i].fp == stdout || files[i].fp == stderr)
2512 continue;
2513 if (files[i].mode == '|' || files[i].mode == LE)
2514 stat = pclose(files[i].fp) == -1;
2515 else
2516 stat = fclose(files[i].fp) == EOF;
2517 if (stat)
2518 WARNING("i/o error occurred while closing %s", files[i].fname);
2519 }
2520}
2521
2522static void
2523flush_all(void)
2524{
2525 size_t i;
2526
2527 for (i = 0; i < nfiles; i++)
2528 if (files[i].fp)
2529 fflush(files[i].fp);
2530}
2531
2532void backsub(char **pb_ptr, const char **sptr_ptr);
2533
2534Cell *
2535dosub(Node **a, int subop) /* sub and gsub */
2536{
2537 fa *pfa;
2538 int tempstat = 0;
2539 char *repl;
2540 Cell *x;
2541
2542 char *buf = NULL;
2543 char *pb = NULL;
2544 int bufsz = recsize;
2545
2546 const char *r, *s;
2547 const char *start;
2548 const char *noempty = NULL; /* empty match disallowed here */
2549 size_t m = 0; /* match count */
2550 size_t whichm = 0; /* which match to select, 0 = global */
2551 int mtype; /* match type */
2552
2553 if (a[0] == NULL) { /* 0 => a[1] is already-compiled regexpr */
2554 pfa = (fa *)a[1];
2555 } else {
2556 x = execute(a[1]);
2557 pfa = makedfa(getsval(x), 1);
2558 tempfree(x);
2559 }
2560
2561 x = execute(a[2]); /* replacement string */
2562 repl = tostring(getsval(x));
2563 tempfree(x);
2564
2565 switch (subop) {
2566 case SUB:
2567 whichm = 1;
2568 x = execute(a[3]); /* source string */
2569 break;
2570 case GSUB:
2571 whichm = 0;
2572 x = execute(a[3]); /* source string */
2573 break;
2574 default:
2575 FATAL("dosub: unrecognized subop: %d", subop);
2576 }
2577
2578 start = getsval(x);
2579 while (pmatch(pfa, start)) {
2580 if (buf == NULL) {
2581 if ((pb = buf = (char *)malloc(bufsz)) == NULL)
2582 FATAL("out of memory in dosub");
2583 tempstat = pfa->initstat;
2584 pfa->initstat = 2;
2585 }
2586
2587/* match types */
2588#define MT_IGNORE 0 /* unselected or invalid */
2589#define MT_INSERT 1 /* selected, empty */
2590#define MT_REPLACE 2 /* selected, not empty */
2591
2592 /* an empty match just after replacement is invalid */
2593
2594 if (patbeg == noempty && patlen == 0) {
2595 mtype = MT_IGNORE; /* invalid, not counted */
2596 } else if (whichm == ++m || whichm == 0) {
2597 mtype = patlen ? MT_REPLACE : MT_INSERT;
2598 } else {
2599 mtype = MT_IGNORE; /* unselected, but counted */
2600 }
2601
2602 /* leading text: */
2603 if (patbeg > start) {
2604 adjbuf(&buf, &bufsz, (pb - buf) + (patbeg - start), recsize, &pb, "dosub");
2605 s = start;
2606 while (s < patbeg)
2607 *pb++ = *s++;
2608 }
2609
2610 if (mtype == MT_IGNORE)
2611 goto matching_text; /* skip replacement text */
2612
2613 r = repl;
2614 while (*r != 0) {
2615 adjbuf(&buf, &bufsz, 5 + pb - buf, recsize, &pb, "dosub");
2616 if (*r == '\\') {
2617 backsub(&pb, &r);
2618 } else if (*r == '&') {
2619 r++;
2620 adjbuf(&buf, &bufsz, 1 + patlen + pb - buf, recsize, &pb, "dosub");
2621 for (s = patbeg; s < patbeg + patlen;)
2622 *pb++ = *s++;
2623 } else {
2624 *pb++ = *r++;
2625 }
2626 }
2627
2628 matching_text:
2629 if (mtype == MT_REPLACE || *patbeg == '\0')
2630 goto next_search; /* skip matching text */
2631
2632 if (patlen == 0)
2633 patlen = u8_nextlen(patbeg);
2634 adjbuf(&buf, &bufsz, (pb - buf) + patlen, recsize, &pb, "dosub");
2635 s = patbeg;
2636 while (s < patbeg + patlen)
2637 *pb++ = *s++;
2638
2639 next_search:
2640 start = patbeg + patlen;
2641 if (m == whichm || *patbeg == '\0')
2642 break;
2643 if (mtype == MT_REPLACE)
2644 noempty = start;
2645
2646#undef MT_IGNORE
2647#undef MT_INSERT
2648#undef MT_REPLACE
2649 }
2650
2651 if (repl) {
2652 free(repl);
2653 }
2654
2655 if (buf != NULL) {
2656 pfa->initstat = tempstat;
2657
2658 /* trailing text */
2659 adjbuf(&buf, &bufsz, 1 + strlen(start) + pb - buf, 0, &pb, "dosub");
2660 while ((*pb++ = *start++) != '\0')
2661 ;
2662
2663 setsval(x, buf);
2664 free(buf);
2665 }
2666
2667 tempfree(x);
2668 x = gettemp();
2669 x->tval = NUM;
2670 x->fval = m;
2671 return x;
2672}
2673
2674void
2675backsub(char **pb_ptr, const char **sptr_ptr) /* handle \\& variations */
2676{ /* sptr[0] == '\\' */
2677 char *pb = *pb_ptr;
2678 const char *sptr = *sptr_ptr;
2679 static bool first = true;
2680 static bool do_posix = false;
2681
2682 if (first) {
2683 first = false;
2684 do_posix = (getenv("POSIXLY_CORRECT") != NULL);
2685 }
2686
2687 if (sptr[1] == '\\') {
2688 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
2689 *pb++ = '\\';
2690 *pb++ = '&';
2691 sptr += 4;
2692 } else if (sptr[2] == '&') { /* \\& -> \ + matched */
2693 *pb++ = '\\';
2694 sptr += 2;
2695 } else if (do_posix) { /* \\x -> \x */
2696 sptr++;
2697 *pb++ = *sptr++;
2698 } else { /* \\x -> \\x */
2699 *pb++ = *sptr++;
2700 *pb++ = *sptr++;
2701 }
2702 } else if (sptr[1] == '&') { /* literal & */
2703 sptr++;
2704 *pb++ = *sptr++;
2705 } else /* literal \ */
2706 *pb++ = *sptr++;
2707
2708 *pb_ptr = pb;
2709 *sptr_ptr = sptr;
2710}
2711
2712static char *
2713wide_char_to_byte_str(int rune, size_t *outlen)
2714{
2715 static char buf[5];
2716 int len;
2717
2718 if (rune < 0 || rune > 0x10FFFF)
2719 return NULL;
2720
2721 memset(buf, 0, sizeof(buf));
2722
2723 len = 0;
2724 if (rune <= 0x0000007F) {
2725 buf[len++] = rune;
2726 } else if (rune <= 0x000007FF) {
2727 /* 110xxxxx 10xxxxxx */
2728 buf[len++] = 0xC0 | (rune >> 6);
2729 buf[len++] = 0x80 | (rune & 0x3F);
2730 } else if (rune <= 0x0000FFFF) {
2731 /* 1110xxxx 10xxxxxx 10xxxxxx */
2732 buf[len++] = 0xE0 | (rune >> 12);
2733 buf[len++] = 0x80 | ((rune >> 6) & 0x3F);
2734 buf[len++] = 0x80 | (rune & 0x3F);
2735
2736 } else {
2737 /* 0x00010000 - 0x10ffff
2738 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
2739 buf[len++] = 0xF0 | (rune >> 18);
2740 buf[len++] = 0x80 | ((rune >> 12) & 0x3F);
2741 buf[len++] = 0x80 | ((rune >> 6) & 0x3F);
2742 buf[len++] = 0x80 | (rune & 0x3F);
2743 }
2744
2745 *outlen = len;
2746 buf[len++] = '\0';
2747
2748 return buf;
2749}