1/****************************************************************
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#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); /* don't 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 /* can't 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: /* can't 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 it's 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 doesn't 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: /* can't 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: /* can't 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 * can't, 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: /* can't 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 isn't 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; don't 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 it's 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) { /* it's 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 * doesn't 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: /* can't 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 don't 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 /* don't 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 /* can't 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}