master xplshn/aruu / cmd / posix / awk / run.c
   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}