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