1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Copyright (C) Lucent Technologies 1997 28 * All Rights Reserved 29 * 30 * Permission to use, copy, modify, and distribute this software and 31 * its documentation for any purpose and without fee is hereby 32 * granted, provided that the above copyright notice appear in all 33 * copies and that both that the copyright notice and this 34 * permission notice and warranty disclaimer appear in supporting 35 * documentation, and that the name Lucent Technologies or any of 36 * its entities not be used in advertising or publicity pertaining 37 * to distribution of the software without specific, written prior 38 * permission. 39 * 40 * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 41 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 42 * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 43 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 44 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 45 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 46 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 47 * THIS SOFTWARE. 48 */ 49 50 #define tempfree(x) if (istemp(x)) tfree(x); 51 52 #define DEBUG 53 #include <setjmp.h> 54 #include <math.h> 55 #include <time.h> 56 #include "awk.h" 57 #include "y.tab.h" 58 59 static Cell *execute(Node *); 60 static Cell *gettemp(void); 61 static Cell *copycell(Cell *); 62 static FILE *openfile(int, const uchar *); 63 static FILE *redirect(int, Node *); 64 static const char *filename(FILE *); 65 static void flush_all(void); 66 67 static jmp_buf env; 68 extern Awkfloat srand_seed; 69 70 Node *winner = NULL; /* root of parse tree */ 71 72 static Cell *tmps; /* free temporary cells for execution */ 73 static Cell truecell = { OBOOL, BTRUE, 0, 0, 1.0, NUM }; 74 Cell *True = &truecell; 75 static Cell falsecell = { OBOOL, BFALSE, 0, 0, 0.0, NUM }; 76 Cell *False = &falsecell; 77 static Cell breakcell = { OJUMP, JBREAK, 0, 0, 0.0, NUM }; 78 Cell *jbreak = &breakcell; 79 static Cell contcell = { OJUMP, JCONT, 0, 0, 0.0, NUM }; 80 Cell *jcont = &contcell; 81 static Cell nextcell = { OJUMP, JNEXT, 0, 0, 0.0, NUM }; 82 Cell *jnext = &nextcell; 83 static Cell nextfilecell = { OJUMP, JNEXTFILE, 0, 0, 0.0, NUM }; 84 Cell *jnextfile = &nextfilecell; 85 static Cell exitcell = { OJUMP, JEXIT, 0, 0, 0.0, NUM }; 86 Cell *jexit = &exitcell; 87 static Cell retcell = { OJUMP, JRET, 0, 0, 0.0, NUM }; 88 Cell *jret = &retcell; 89 static Cell tempcell = { OCELL, CTEMP, 0, (uchar *)"", 0.0, NUM| 90 STR|DONTFREE}; 91 92 Node *curnode = NULL; /* the node being executed, for debugging */ 93 94 static void tfree(Cell *); 95 static void closeall(void); 96 static double ipow(double, int); 97 static void stdinit(void); 98 99 /* 100 * buffer memory management 101 * 102 * pbuf: address of pointer to buffer being managed 103 * psiz: address of buffer size variable 104 * minlen: minimum length of buffer needed 105 * quantum: buffer size quantum 106 * pbptr: address of movable pointer into buffer, or 0 if none 107 * whatrtn: name of the calling routine if failure should cause fatal error 108 * 109 * return 0 for realloc failure, !=0 for success 110 */ 111 int adjbuf(uchar **pbuf, size_t *psiz, int minlen, int quantum, uchar **pbptr, 112 const char *whatrtn) 113 { 114 if (minlen > *psiz) { 115 uchar *tbuf; 116 int rminlen = quantum ? minlen % quantum : 0; 117 int boff = pbptr ? *pbptr - *pbuf : 0; 118 /* round up to next multiple of quantum */ 119 if (rminlen) 120 minlen += quantum - rminlen; 121 tbuf = (uchar *)realloc(*pbuf, minlen); 122 dprintf(("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, 123 *psiz, minlen, (void *)*pbuf, (void *)tbuf)); 124 if (tbuf == NULL) { 125 if (whatrtn) 126 FATAL("out of memory in %s", whatrtn); 127 return (0); 128 } 129 *pbuf = (uchar *)tbuf; 130 *psiz = minlen; 131 if (pbptr) 132 *pbptr = tbuf + boff; 133 } 134 return (1); 135 } 136 137 void 138 run(Node *a) /* execution of parse tree starts here */ 139 { 140 stdinit(); 141 (void) execute(a); 142 closeall(); 143 } 144 145 static Cell * 146 execute(Node *u) /* execute a node of the parse tree */ 147 { 148 Cell *(*proc)(Node **, int); 149 Cell *x; 150 Node *a; 151 152 if (u == NULL) 153 return (True); 154 for (a = u; ; a = a->nnext) { 155 curnode = a; 156 if (isvalue(a)) { 157 x = (Cell *)(a->narg[0]); 158 if (isfld(x) && !donefld) 159 fldbld(); 160 else if (isrec(x) && !donerec) 161 recbld(); 162 return (x); 163 } 164 /* probably a Cell* but too risky to print */ 165 if (notlegal(a->nobj)) 166 FATAL("illegal statement"); 167 proc = proctab[a->nobj-FIRSTTOKEN]; 168 x = (*proc)(a->narg, a->nobj); 169 if (isfld(x) && !donefld) 170 fldbld(); 171 else if (isrec(x) && !donerec) 172 recbld(); 173 if (isexpr(a)) 174 return (x); 175 if (isjump(x)) 176 return (x); 177 if (a->nnext == (Node *)NULL) 178 return (x); 179 tempfree(x); 180 } 181 } 182 183 /*ARGSUSED*/ 184 Cell * 185 program(Node **a, int n) /* execute an awk program */ 186 { /* a[0] = BEGIN, a[1] = body, a[2] = END */ 187 Cell *x; 188 189 if (setjmp(env) != 0) 190 goto ex; 191 if (a[0]) { /* BEGIN */ 192 x = execute(a[0]); 193 if (isexit(x)) 194 return (True); 195 if (isjump(x)) { 196 FATAL( 197 "illegal break, continue, next or nextfile from BEGIN"); 198 } 199 tempfree(x); 200 } 201 202 if (a[1] || a[2]) { 203 while (getrec(&record, &record_size, 1) > 0) { 204 x = execute(a[1]); 205 if (isexit(x)) 206 break; 207 tempfree(x); 208 } 209 } 210 ex: 211 if (setjmp(env) != 0) /* handles exit within END */ 212 goto ex1; 213 if (a[2]) { /* END */ 214 x = execute(a[2]); 215 if (isbreak(x) || isnext(x) || iscont(x)) 216 FATAL( 217 "illegal break, continue, next or nextfile from END"); 218 tempfree(x); 219 } 220 ex1: 221 return (True); 222 } 223 224 struct Frame { /* stack frame for awk function calls */ 225 int nargs; /* number of arguments in this call */ 226 Cell *fcncell; /* pointer to Cell for function */ 227 Cell **args; /* pointer to array of arguments after execute */ 228 Cell *retval; /* return value */ 229 }; 230 231 #define NARGS 50 /* max args in a call */ 232 233 struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */ 234 int nframe = 0; /* number of frames allocated */ 235 struct Frame *fp = NULL; /* frame pointer. bottom level unused */ 236 237 /*ARGSUSED*/ 238 Cell * 239 call(Node **a, int n) /* function call. very kludgy and fragile */ 240 { 241 static Cell newcopycell = 242 { OCELL, CCOPY, 0, (uchar *) "", 0.0, NUM|STR|DONTFREE }; 243 int i, ncall, ndef; 244 /* handles potential double freeing when fcn & param share a tempcell */ 245 int freed = 0; 246 Node *x; 247 Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */ 248 Cell *y, *z, *fcn; 249 uchar *s; 250 251 fcn = execute(a[0]); /* the function itself */ 252 s = fcn->nval; 253 if (!isfcn(fcn)) 254 FATAL("calling undefined function %s", s); 255 if (frame == NULL) { 256 fp = frame = (struct Frame *)calloc(nframe += 100, 257 sizeof (struct Frame)); 258 if (frame == NULL) { 259 FATAL("out of space for stack frames calling %s", s); 260 } 261 } 262 for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */ 263 ncall++; 264 ndef = (int)fcn->fval; /* args in defn */ 265 dprintf(("calling %s, %d args (%d in defn), fp=%d\n", 266 s, ncall, ndef, (int)(fp-frame))); 267 268 if (ncall > ndef) { 269 WARNING("function %s called with %d args, uses only %d", 270 s, ncall, ndef); 271 } 272 if (ncall + ndef > NARGS) { 273 FATAL("function %s has %d arguments, limit %d", 274 s, ncall + ndef, NARGS); 275 } 276 for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { 277 /* get call args */ 278 dprintf(("evaluate args[%d], fp=%d:\n", i, (int)(fp-frame))); 279 y = execute(x); 280 oargs[i] = y; 281 dprintf(("args[%d]: %s %f <%s>, t=%o\n", 282 i, y->nval, y->fval, 283 isarr(y) ? "(array)" : (char *)y->sval, y->tval)); 284 if (isfcn(y)) { 285 FATAL("can't use function %s as argument in %s", 286 y->nval, s); 287 } 288 if (isarr(y)) 289 args[i] = y; /* arrays by ref */ 290 else 291 args[i] = copycell(y); 292 tempfree(y); 293 } 294 for (; i < ndef; i++) { /* add null args for ones not provided */ 295 args[i] = gettemp(); 296 *args[i] = newcopycell; 297 } 298 fp++; /* now ok to up frame */ 299 if (fp >= frame + nframe) { 300 int dfp = fp - frame; /* old index */ 301 frame = (struct Frame *) 302 realloc(frame, (nframe += 100) * sizeof (struct Frame)); 303 if (frame == NULL) 304 FATAL("out of space for stack frames in %s", s); 305 fp = frame + dfp; 306 } 307 fp->fcncell = fcn; 308 fp->args = args; 309 fp->nargs = ndef; /* number defined with (excess are locals) */ 310 fp->retval = gettemp(); 311 312 dprintf(("start exec of %s, fp=%d\n", s, (int)(fp-frame))); 313 /*LINTED align*/ 314 y = execute((Node *)(fcn->sval)); /* execute body */ 315 dprintf(("finished exec of %s, fp=%d\n", s, (int)(fp-frame))); 316 317 for (i = 0; i < ndef; i++) { 318 Cell *t = fp->args[i]; 319 if (isarr(t)) { 320 if (t->csub == CCOPY) { 321 if (i >= ncall) { 322 freesymtab(t); 323 t->csub = CTEMP; 324 tempfree(t); 325 } else { 326 oargs[i]->tval = t->tval; 327 oargs[i]->tval &= ~(STR|NUM|DONTFREE); 328 oargs[i]->sval = t->sval; 329 tempfree(t); 330 } 331 } 332 } else if (t != y) { /* kludge to prevent freeing twice */ 333 t->csub = CTEMP; 334 tempfree(t); 335 } else if (t == y && t->csub == CCOPY) { 336 t->csub = CTEMP; 337 tempfree(t); 338 freed = 1; 339 } 340 } 341 tempfree(fcn); 342 if (isexit(y) || isnext(y)) 343 return (y); 344 if (freed == 0) { 345 tempfree(y); /* don't free twice! */ 346 } 347 z = fp->retval; /* return value */ 348 dprintf(("%s returns %g |%s| %o\n", 349 s, getfval(z), getsval(z), z->tval)); 350 fp--; 351 return (z); 352 } 353 354 static Cell * 355 copycell(Cell *x) /* make a copy of a cell in a temp */ 356 { 357 Cell *y; 358 359 y = gettemp(); 360 y->csub = CCOPY; /* prevents freeing until call is over */ 361 y->nval = x->nval; /* BUG? */ 362 if (isstr(x)) 363 y->sval = tostring(x->sval); 364 y->fval = x->fval; 365 /* copy is not constant or field is DONTFREE right? */ 366 y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); 367 return (y); 368 } 369 370 Cell * 371 arg(Node **a, int n) /* nth argument of a function */ 372 { 373 374 n = ptoi(a[0]); /* argument number, counting from 0 */ 375 dprintf(("arg(%d), fp->nargs=%d\n", n, fp->nargs)); 376 if (n + 1 > fp->nargs) { 377 FATAL("argument #%d of function %s was not supplied", 378 n + 1, fp->fcncell->nval); 379 } 380 return (fp->args[n]); 381 } 382 383 Cell * 384 jump(Node **a, int n) /* break, continue, next, nextfile, return */ 385 { 386 Cell *y; 387 388 switch (n) { 389 case EXIT: 390 if (a[0] != NULL) { 391 y = execute(a[0]); 392 errorflag = (int)getfval(y); 393 tempfree(y); 394 } 395 longjmp(env, 1); 396 /*NOTREACHED*/ 397 case RETURN: 398 if (a[0] != NULL) { 399 y = execute(a[0]); 400 if ((y->tval & (STR|NUM)) == (STR|NUM)) { 401 (void) setsval(fp->retval, getsval(y)); 402 fp->retval->fval = getfval(y); 403 fp->retval->tval |= NUM; 404 } else if (y->tval & STR) 405 (void) setsval(fp->retval, getsval(y)); 406 else if (y->tval & NUM) 407 (void) setfval(fp->retval, getfval(y)); 408 else /* can't happen */ 409 FATAL("bad type variable %d", y->tval); 410 tempfree(y); 411 } 412 return (jret); 413 case NEXT: 414 return (jnext); 415 case NEXTFILE: 416 nextfile(); 417 return (jnextfile); 418 case BREAK: 419 return (jbreak); 420 case CONTINUE: 421 return (jcont); 422 default: /* can't happen */ 423 FATAL("illegal jump type %d", n); 424 } 425 /*NOTREACHED*/ 426 return (NULL); 427 } 428 429 /* 430 * get next line from specific input 431 * 432 * a[0] is variable, a[1] is operator, a[2] is filename 433 */ 434 Cell * 435 awkgetline(Node **a, int n) 436 { 437 Cell *r, *x; 438 extern Cell **fldtab; 439 FILE *fp; 440 uchar *buf; 441 size_t bufsize = record_size; 442 int mode; 443 444 if ((buf = (uchar *)malloc(bufsize)) == NULL) 445 FATAL("out of memory in getline"); 446 447 (void) fflush(stdout); /* in case someone is waiting for a prompt */ 448 r = gettemp(); 449 if (a[1] != NULL) { /* getline < file */ 450 x = execute(a[2]); /* filename */ 451 mode = ptoi(a[1]); 452 if (mode == '|') /* input pipe */ 453 mode = LE; /* arbitrary flag */ 454 fp = openfile(mode, getsval(x)); 455 tempfree(x); 456 if (fp == NULL) 457 n = -1; 458 else 459 n = readrec(&buf, &bufsize, fp); 460 if (a[0] != NULL) { /* getline var <file */ 461 x = execute(a[0]); 462 (void) setsval(x, buf); 463 tempfree(x); 464 } else { /* getline <file */ 465 (void) setsval(fldtab[0], buf); 466 if (is_number(fldtab[0]->sval)) { 467 fldtab[0]->fval = atof((char *)fldtab[0]->sval); 468 fldtab[0]->tval |= NUM; 469 } 470 } 471 } else { /* bare getline; use current input */ 472 if (a[0] == NULL) /* getline */ 473 n = getrec(&record, &record_size, 1); 474 else { /* getline var */ 475 n = getrec(&buf, &bufsize, 0); 476 x = execute(a[0]); 477 (void) setsval(x, buf); 478 tempfree(x); 479 } 480 } 481 (void) setfval(r, (Awkfloat)n); 482 free(buf); 483 return (r); 484 } 485 486 /*ARGSUSED*/ 487 Cell * 488 getnf(Node **a, int n) /* get NF */ 489 { 490 if (donefld == 0) 491 fldbld(); 492 return ((Cell *)a[0]); 493 } 494 495 /*ARGSUSED*/ 496 Cell * 497 array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ 498 { 499 Cell *x, *y, *z; 500 uchar *s; 501 Node *np; 502 uchar *buf; 503 size_t bufsz = record_size; 504 size_t nsub = strlen((char *)*SUBSEP); 505 506 if ((buf = (uchar *)malloc(bufsz)) == NULL) 507 FATAL("out of memory in array"); 508 509 x = execute(a[0]); /* Cell* for symbol table */ 510 buf[0] = '\0'; 511 for (np = a[1]; np; np = np->nnext) { 512 y = execute(np); /* subscript */ 513 s = getsval(y); 514 if (!adjbuf(&buf, &bufsz, strlen((char *)buf) + 515 strlen((char *)s) + nsub + 1, record_size, 0, "array")) 516 FATAL("out of memory for %s[%s...]", x->nval, buf); 517 (void) strcat((char *)buf, (char *)s); 518 if (np->nnext) 519 (void) strcat((char *)buf, (char *)*SUBSEP); 520 tempfree(y); 521 } 522 if (!isarr(x)) { 523 dprintf(("making %s into an array\n", x->nval)); 524 if (freeable(x)) 525 xfree(x->sval); 526 x->tval &= ~(STR|NUM|DONTFREE); 527 x->tval |= ARR; 528 x->sval = (uchar *)makesymtab(NSYMTAB); 529 } 530 /*LINTED align*/ 531 z = setsymtab(buf, (uchar *)"", 0.0, STR|NUM, (Array *)x->sval); 532 z->ctype = OCELL; 533 z->csub = CVAR; 534 tempfree(x); 535 free(buf); 536 return (z); 537 } 538 539 /*ARGSUSED*/ 540 Cell * 541 awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ 542 { 543 Cell *x, *y; 544 Node *np; 545 uchar *s; 546 size_t nsub = strlen((char *)*SUBSEP); 547 548 x = execute(a[0]); /* Cell* for symbol table */ 549 if (!isarr(x)) 550 return (True); 551 if (a[1] == 0) { /* delete the elements, not the table */ 552 freesymtab(x); 553 x->tval &= ~STR; 554 x->tval |= ARR; 555 x->sval = (uchar *)makesymtab(NSYMTAB); 556 } else { 557 size_t bufsz = record_size; 558 uchar *buf; 559 if ((buf = (uchar *)malloc(bufsz)) == NULL) 560 FATAL("out of memory in delete"); 561 buf[0] = '\0'; 562 for (np = a[1]; np; np = np->nnext) { 563 y = execute(np); /* subscript */ 564 s = getsval(y); 565 if (!adjbuf(&buf, &bufsz, strlen((char *)buf) + 566 strlen((char *)s) + nsub + 1, record_size, 0, 567 "awkdelete")) { 568 FATAL("out of memory deleting %s[%s...]", 569 x->nval, buf); 570 } 571 (void) strcat((char *)buf, (char *)s); 572 if (np->nnext) 573 (void) strcat((char *)buf, (char *)*SUBSEP); 574 tempfree(y); 575 } 576 freeelem(x, buf); 577 free(buf); 578 } 579 tempfree(x); 580 return (True); 581 } 582 583 /*ARGSUSED*/ 584 Cell * 585 intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */ 586 { 587 Cell *x, *ap, *k; 588 Node *p; 589 uchar *buf; 590 uchar *s; 591 size_t bufsz = record_size; 592 size_t nsub = strlen((char *)*SUBSEP); 593 594 ap = execute(a[1]); /* array name */ 595 if (!isarr(ap)) { 596 dprintf(("making %s into an array\n", ap->nval)); 597 if (freeable(ap)) 598 xfree(ap->sval); 599 ap->tval &= ~(STR|NUM|DONTFREE); 600 ap->tval |= ARR; 601 ap->sval = (uchar *)makesymtab(NSYMTAB); 602 } 603 if ((buf = (uchar *)malloc(bufsz)) == NULL) { 604 FATAL("out of memory in intest"); 605 } 606 buf[0] = 0; 607 for (p = a[0]; p; p = p->nnext) { 608 x = execute(p); /* expr */ 609 s = getsval(x); 610 if (!adjbuf(&buf, &bufsz, strlen((char *)buf) + 611 strlen((char *)s) + nsub + 1, record_size, 0, "intest")) 612 FATAL("out of memory deleting %s[%s...]", x->nval, buf); 613 (void) strcat((char *)buf, (char *)s); 614 tempfree(x); 615 if (p->nnext) 616 (void) strcat((char *)buf, (char *)*SUBSEP); 617 } 618 /*LINTED align*/ 619 k = lookup(buf, (Array *)ap->sval); 620 tempfree(ap); 621 free(buf); 622 if (k == NULL) 623 return (False); 624 else 625 return (True); 626 } 627 628 Cell * 629 matchop(Node **a, int n) /* ~ and match() */ 630 { 631 Cell *x, *y; 632 uchar *s, *t; 633 int i; 634 fa *pfa; 635 int (*mf)(fa *, const uchar *) = match, mode = 0; 636 637 if (n == MATCHFCN) { 638 mf = pmatch; 639 mode = 1; 640 } 641 x = execute(a[1]); /* a[1] = target text */ 642 s = getsval(x); 643 if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */ 644 i = (*mf)((fa *)a[2], s); 645 else { 646 y = execute(a[2]); /* a[2] = regular expr */ 647 t = getsval(y); 648 pfa = makedfa(t, mode); 649 i = (*mf)(pfa, s); 650 tempfree(y); 651 } 652 tempfree(x); 653 if (n == MATCHFCN) { 654 int start = patbeg - s + 1; 655 if (patlen < 0) 656 start = 0; 657 (void) setfval(rstartloc, (Awkfloat)start); 658 (void) setfval(rlengthloc, (Awkfloat)patlen); 659 x = gettemp(); 660 x->tval = NUM; 661 x->fval = start; 662 return (x); 663 } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0)) 664 return (True); 665 else 666 return (False); 667 } 668 669 Cell * 670 boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */ 671 { 672 Cell *x, *y; 673 int i; 674 675 x = execute(a[0]); 676 i = istrue(x); 677 tempfree(x); 678 switch (n) { 679 case BOR: 680 if (i) 681 return (True); 682 y = execute(a[1]); 683 i = istrue(y); 684 tempfree(y); 685 return (i ? True : False); 686 case AND: 687 if (!i) 688 return (False); 689 y = execute(a[1]); 690 i = istrue(y); 691 tempfree(y); 692 return (i ? True : False); 693 case NOT: 694 return (i ? False : True); 695 default: /* can't happen */ 696 FATAL("unknown boolean operator %d", n); 697 } 698 /*NOTREACHED*/ 699 return (NULL); 700 } 701 702 Cell * 703 relop(Node **a, int n) /* a[0 < a[1], etc. */ 704 { 705 int i; 706 Cell *x, *y; 707 Awkfloat j; 708 709 x = execute(a[0]); 710 y = execute(a[1]); 711 if (x->tval & NUM && y->tval & NUM) { 712 j = x->fval - y->fval; 713 i = j < 0 ? -1: (j > 0 ? 1: 0); 714 } else { 715 i = strcmp((char *)getsval(x), (char *)getsval(y)); 716 } 717 tempfree(x); 718 tempfree(y); 719 switch (n) { 720 case LT: return (i < 0 ? True : False); 721 case LE: return (i <= 0 ? True : False); 722 case NE: return (i != 0 ? True : False); 723 case EQ: return (i == 0 ? True : False); 724 case GE: return (i >= 0 ? True : False); 725 case GT: return (i > 0 ? True : False); 726 default: /* can't happen */ 727 FATAL("unknown relational operator %d", n); 728 } 729 /*NOTREACHED*/ 730 return (False); 731 } 732 733 static void 734 tfree(Cell *a) /* free a tempcell */ 735 { 736 if (freeable(a)) { 737 dprintf(("freeing %s %s %o\n", (char *)a->nval, 738 (char *)a->sval, a->tval)); 739 xfree(a->sval); 740 } 741 if (a == tmps) 742 FATAL("tempcell list is curdled"); 743 a->cnext = tmps; 744 tmps = a; 745 } 746 747 static Cell * 748 gettemp(void) /* get a tempcell */ 749 { 750 int i; 751 Cell *x; 752 753 if (!tmps) { 754 tmps = (Cell *)calloc(100, sizeof (Cell)); 755 if (!tmps) 756 FATAL("out of space for temporaries"); 757 for (i = 1; i < 100; i++) 758 tmps[i - 1].cnext = &tmps[i]; 759 tmps[i - 1].cnext = 0; 760 } 761 x = tmps; 762 tmps = x->cnext; 763 *x = tempcell; 764 return (x); 765 } 766 767 /*ARGSUSED*/ 768 Cell * 769 indirect(Node **a, int n) /* $( a[0] ) */ 770 { 771 Awkfloat val; 772 Cell *x; 773 int m; 774 uchar *s; 775 776 x = execute(a[0]); 777 /* freebsd: defend against super large field numbers */ 778 val = getfval(x); 779 if ((Awkfloat)INT_MAX < val) 780 FATAL("trying to access out of range field %s", x->nval); 781 m = (int)val; 782 if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */ 783 FATAL("illegal field $(%s), name \"%s\"", s, x->nval); 784 /* BUG: can x->nval ever be null??? */ 785 tempfree(x); 786 x = fieldadr(m); 787 x->ctype = OCELL; /* BUG? why are these needed? */ 788 x->csub = CFLD; 789 return (x); 790 } 791 792 /*ARGSUSED*/ 793 Cell * 794 substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */ 795 { 796 int k, m, n; 797 uchar *s; 798 int temp; 799 Cell *x, *y, *z = 0; 800 801 x = execute(a[0]); 802 y = execute(a[1]); 803 if (a[2] != 0) 804 z = execute(a[2]); 805 s = getsval(x); 806 k = strlen((char *)s) + 1; 807 if (k <= 1) { 808 tempfree(x); 809 tempfree(y); 810 if (a[2] != 0) { 811 tempfree(z); 812 } 813 x = gettemp(); 814 (void) setsval(x, (uchar *)""); 815 return (x); 816 } 817 m = (int)getfval(y); 818 if (m <= 0) 819 m = 1; 820 else if (m > k) 821 m = k; 822 tempfree(y); 823 if (a[2] != 0) { 824 n = (int)getfval(z); 825 tempfree(z); 826 } else 827 n = k - 1; 828 if (n < 0) 829 n = 0; 830 else if (n > k - m) 831 n = k - m; 832 dprintf(("substr: m=%d, n=%d, s=%s\n", m, n, s)); 833 y = gettemp(); 834 temp = s[n + m - 1]; /* with thanks to John Linderman */ 835 s[n + m - 1] = '\0'; 836 (void) setsval(y, s + m - 1); 837 s[n + m - 1] = temp; 838 tempfree(x); 839 return (y); 840 } 841 842 /*ARGSUSED*/ 843 Cell * 844 sindex(Node **a, int nnn) /* index(a[0], a[1]) */ 845 { 846 Cell *x, *y, *z; 847 uchar *s1, *s2, *p1, *p2, *q; 848 Awkfloat v = 0.0; 849 850 x = execute(a[0]); 851 s1 = getsval(x); 852 y = execute(a[1]); 853 s2 = getsval(y); 854 855 z = gettemp(); 856 for (p1 = s1; *p1 != '\0'; p1++) { 857 for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++) 858 ; 859 if (*p2 == '\0') { 860 v = (Awkfloat)(p1 - s1 + 1); /* origin 1 */ 861 break; 862 } 863 } 864 tempfree(x); 865 tempfree(y); 866 (void) setfval(z, v); 867 return (z); 868 } 869 870 #define MAXNUMSIZE 50 871 872 /* 873 * printf-like conversions 874 */ 875 int 876 format(uchar **bufp, size_t *pbufsize, const uchar *s, Node *a) 877 { 878 uchar *fmt; 879 uchar *p, *t; 880 const uchar *os; 881 Cell *x; 882 int flag = 0, n; 883 int fmtwd; /* format width */ 884 size_t fmtsz = record_size; 885 uchar_t *buf = *bufp; 886 size_t bufsize = *pbufsize; 887 888 os = s; 889 p = buf; 890 if ((fmt = (uchar *)malloc(fmtsz)) == NULL) 891 FATAL("out of memory in format()"); 892 while (*s) { 893 (void) adjbuf(&buf, &bufsize, MAXNUMSIZE + 1 + p - buf, 894 record_size, &p, "format1"); 895 if (*s != '%') { 896 *p++ = *s++; 897 continue; 898 } 899 if (*(s+1) == '%') { 900 *p++ = '%'; 901 s += 2; 902 continue; 903 } 904 /* 905 * have to be real careful in case this is a huge number, 906 * eg, %100000d 907 */ 908 fmtwd = atoi((char *)s + 1); 909 if (fmtwd < 0) 910 fmtwd = -fmtwd; 911 (void) adjbuf(&buf, &bufsize, fmtwd + 1 + p - buf, 912 record_size, &p, "format2"); 913 for (t = fmt; (*t++ = *s) != '\0'; s++) { 914 if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE + 1 + t - fmt, 915 record_size, &t, "format3")) 916 FATAL( 917 "format item %.30s... ran format() out of memory", os); 918 if (isalpha((uchar)*s) && *s != 'l' && *s != 'h' && 919 *s != 'L') 920 break; /* the ansi panoply */ 921 if (*s == '*') { 922 x = execute(a); 923 a = a->nnext; 924 (void) sprintf((char *)t - 1, "%d", 925 fmtwd = (int)getfval(x)); 926 if (fmtwd < 0) 927 fmtwd = -fmtwd; 928 (void) adjbuf(&buf, &bufsize, fmtwd + 1 + p - 929 buf, record_size, &p, "format"); 930 t = fmt + strlen((char *)fmt); 931 tempfree(x); 932 } 933 } 934 *t = '\0'; 935 if (fmtwd < 0) 936 fmtwd = -fmtwd; 937 (void) adjbuf(&buf, &bufsize, fmtwd + 1 + p - buf, 938 record_size, &p, "format4"); 939 940 switch (*s) { 941 case 'f': case 'e': case 'g': case 'E': case 'G': 942 flag = 'f'; 943 break; 944 case 'd': case 'i': 945 flag = 'd'; 946 if (*(s-1) == 'l') 947 break; 948 *(t-1) = 'l'; 949 *t = 'd'; 950 *++t = '\0'; 951 break; 952 case 'o': case 'x': case 'X': case 'u': 953 flag = *(s-1) == 'l' ? 'd' : 'u'; 954 break; 955 case 's': 956 flag = 's'; 957 break; 958 case 'c': 959 flag = 'c'; 960 break; 961 default: 962 WARNING("weird printf conversion %s", fmt); 963 flag = '?'; 964 break; 965 } 966 if (a == NULL) { 967 FATAL( 968 "not enough args in printf(%s)", os); 969 } 970 x = execute(a); 971 a = a->nnext; 972 n = MAXNUMSIZE; 973 if (fmtwd > n) 974 n = fmtwd; 975 (void) adjbuf(&buf, &bufsize, 1 + n + p - buf, record_size, 976 &p, "format5"); 977 978 switch (flag) { 979 case '?': 980 /* unknown, so dump it too */ 981 /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ 982 (void) sprintf((char *)p, "%s", (char *)fmt); 983 t = getsval(x); 984 n = strlen((char *)t); 985 if (fmtwd > n) 986 n = fmtwd; 987 (void) adjbuf(&buf, &bufsize, 1 + strlen((char *)p) + 988 n + p - buf, record_size, &p, "format6"); 989 p += strlen((char *)p); 990 /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ 991 (void) sprintf((char *)p, "%s", t); 992 break; 993 case 'f': 994 /* LINTED E_SEC_PRINTF_VAR_FMT */ 995 (void) sprintf((char *)p, (char *)fmt, getfval(x)); 996 break; 997 case 'd': 998 /* LINTED E_SEC_PRINTF_VAR_FMT */ 999 (void) sprintf((char *)p, (char *)fmt, 1000 (long) getfval(x)); 1001 break; 1002 case 'u': 1003 /* LINTED E_SEC_PRINTF_VAR_FMT */ 1004 (void) sprintf((char *)p, (char *)fmt, 1005 (int) getfval(x)); 1006 break; 1007 case 's': 1008 t = getsval(x); 1009 n = strlen((char *)t); 1010 if (fmtwd > n) 1011 n = fmtwd; 1012 if (!adjbuf(&buf, &bufsize, 1+n+p-buf, record_size, 1013 &p, "format7")) 1014 FATAL( 1015 "huge string/format (%d chars) in printf %.30s... " 1016 "ran format() out of memory", n, t); 1017 /* LINTED E_SEC_PRINTF_VAR_FMT */ 1018 (void) sprintf((char *)p, (char *)fmt, t); 1019 break; 1020 case 'c': 1021 if (isnum(x)) { 1022 if (getfval(x)) 1023 /* LINTED E_SEC_PRINTF_VAR_FMT */ 1024 (void) sprintf((char *)p, (char *)fmt, 1025 (int) getfval(x)); 1026 else { 1027 *p++ = '\0'; /* explicit null byte */ 1028 /* next output will start here */ 1029 *p = '\0'; 1030 } 1031 } else { 1032 /* LINTED E_SEC_PRINTF_VAR_FMT */ 1033 (void) sprintf((char *)p, (char *)fmt, 1034 getsval(x)[0]); 1035 } 1036 break; 1037 default: 1038 FATAL("can't happen: bad conversion %c in format()", 1039 flag); 1040 } 1041 tempfree(x); 1042 p += strlen((char *)p); 1043 s++; 1044 } 1045 *p = '\0'; 1046 free(fmt); 1047 for (; a; a = a->nnext) /* evaluate any remaining args */ 1048 (void) execute(a); 1049 *bufp = buf; 1050 *pbufsize = bufsize; 1051 return (p - buf); 1052 } 1053 1054 /*ARGSUSED*/ 1055 Cell * 1056 awksprintf(Node **a, int n) /* sprintf(a[0]) */ 1057 { 1058 Cell *x; 1059 Node *y; 1060 uchar *buf; 1061 size_t bufsz = 3 * record_size; 1062 1063 if ((buf = (uchar *)malloc(bufsz)) == NULL) 1064 FATAL("out of memory in awksprintf"); 1065 y = a[0]->nnext; 1066 x = execute(a[0]); 1067 if (format(&buf, &bufsz, getsval(x), y) == -1) 1068 FATAL("sprintf string %.30s... too long. can't happen.", buf); 1069 tempfree(x); 1070 x = gettemp(); 1071 x->sval = buf; 1072 x->tval = STR; 1073 return (x); 1074 } 1075 1076 /*ARGSUSED*/ 1077 Cell * 1078 awkprintf(Node **a, int n) /* printf */ 1079 { /* a[0] is list of args, starting with format string */ 1080 /* a[1] is redirection operator, a[2] is redirection file */ 1081 FILE *fp; 1082 Cell *x; 1083 Node *y; 1084 uchar *buf; 1085 int len; 1086 size_t bufsz = 3 * record_size; 1087 1088 if ((buf = (uchar *)malloc(bufsz)) == NULL) 1089 FATAL("out of memory in awkprintf"); 1090 y = a[0]->nnext; 1091 x = execute(a[0]); 1092 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1) 1093 FATAL("printf string %.30s... too long. can't happen.", buf); 1094 tempfree(x); 1095 if (a[1] == NULL) { 1096 /* fputs(buf, stdout); */ 1097 (void) fwrite((char *)buf, len, 1, stdout); 1098 if (ferror(stdout)) 1099 FATAL("write error on stdout"); 1100 } else { 1101 fp = redirect(ptoi(a[1]), a[2]); 1102 /* fputs(buf, fp); */ 1103 (void) fwrite(buf, len, 1, fp); 1104 (void) fflush(fp); 1105 if (ferror(fp)) 1106 FATAL("write error on %s", filename(fp)); 1107 } 1108 free(buf); 1109 return (True); 1110 } 1111 1112 Cell * 1113 arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */ 1114 { 1115 Awkfloat i, j = 0; 1116 double v; 1117 Cell *x, *y, *z; 1118 1119 x = execute(a[0]); 1120 i = getfval(x); 1121 tempfree(x); 1122 if (n != UMINUS) { 1123 y = execute(a[1]); 1124 j = getfval(y); 1125 tempfree(y); 1126 } 1127 z = gettemp(); 1128 switch (n) { 1129 case ADD: 1130 i += j; 1131 break; 1132 case MINUS: 1133 i -= j; 1134 break; 1135 case MULT: 1136 i *= j; 1137 break; 1138 case DIVIDE: 1139 if (j == 0) 1140 FATAL("division by zero"); 1141 i /= j; 1142 break; 1143 case MOD: 1144 if (j == 0) 1145 FATAL("division by zero in mod"); 1146 (void) modf(i/j, &v); 1147 i = i - j * v; 1148 break; 1149 case UMINUS: 1150 i = -i; 1151 break; 1152 case POWER: 1153 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */ 1154 i = ipow(i, (int)j); 1155 else 1156 i = errcheck(pow(i, j), "pow"); 1157 break; 1158 default: /* can't happen */ 1159 FATAL("illegal arithmetic operator %d", n); 1160 } 1161 (void) setfval(z, i); 1162 return (z); 1163 } 1164 1165 static double 1166 ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */ 1167 { 1168 double v; 1169 1170 if (n <= 0) 1171 return (1.0); 1172 v = ipow(x, n / 2); 1173 if (n % 2 == 0) 1174 return (v * v); 1175 else 1176 return (x * v * v); 1177 } 1178 1179 Cell * 1180 incrdecr(Node **a, int n) /* a[0]++, etc. */ 1181 { 1182 Cell *x, *z; 1183 int k; 1184 Awkfloat xf; 1185 1186 x = execute(a[0]); 1187 xf = getfval(x); 1188 k = (n == PREINCR || n == POSTINCR) ? 1 : -1; 1189 if (n == PREINCR || n == PREDECR) { 1190 (void) setfval(x, xf + k); 1191 return (x); 1192 } 1193 z = gettemp(); 1194 (void) setfval(z, xf); 1195 (void) setfval(x, xf + k); 1196 tempfree(x); 1197 return (z); 1198 } 1199 1200 Cell * 1201 assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */ 1202 { /* this is subtle; don't muck with it. */ 1203 Cell *x, *y; 1204 Awkfloat xf, yf; 1205 double v; 1206 1207 y = execute(a[1]); 1208 x = execute(a[0]); 1209 if (n == ASSIGN) { /* ordinary assignment */ 1210 /* self-assignment: */ 1211 /* LINTED E_NOP_IF_STMT */ 1212 if (x == y && !(x->tval & (FLD|REC))) 1213 /* leave alone unless it's a field */ 1214 ; 1215 else if ((y->tval & (STR|NUM)) == (STR|NUM)) { 1216 (void) setsval(x, getsval(y)); 1217 x->fval = getfval(y); 1218 x->tval |= NUM; 1219 } else if (isstr(y)) 1220 (void) setsval(x, getsval(y)); 1221 else if (isnum(y)) 1222 (void) setfval(x, getfval(y)); 1223 else 1224 funnyvar(y, "read value of"); 1225 tempfree(y); 1226 return (x); 1227 } 1228 xf = getfval(x); 1229 yf = getfval(y); 1230 switch (n) { 1231 case ADDEQ: 1232 xf += yf; 1233 break; 1234 case SUBEQ: 1235 xf -= yf; 1236 break; 1237 case MULTEQ: 1238 xf *= yf; 1239 break; 1240 case DIVEQ: 1241 if (yf == 0) 1242 FATAL("division by zero in /="); 1243 xf /= yf; 1244 break; 1245 case MODEQ: 1246 if (yf == 0) 1247 FATAL("division by zero in %%="); 1248 (void) modf(xf/yf, &v); 1249 xf = xf - yf * v; 1250 break; 1251 case POWEQ: 1252 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */ 1253 xf = ipow(xf, (int)yf); 1254 else 1255 xf = errcheck(pow(xf, yf), "pow"); 1256 break; 1257 default: 1258 FATAL("illegal assignment operator %d", n); 1259 break; 1260 } 1261 tempfree(y); 1262 (void) setfval(x, xf); 1263 return (x); 1264 } 1265 1266 /*ARGSUSED*/ 1267 Cell * 1268 cat(Node **a, int q) /* a[0] cat a[1] */ 1269 { 1270 Cell *x, *y, *z; 1271 int n1, n2; 1272 uchar *s; 1273 1274 x = execute(a[0]); 1275 y = execute(a[1]); 1276 (void) getsval(x); 1277 (void) getsval(y); 1278 n1 = strlen((char *)x->sval); 1279 n2 = strlen((char *)y->sval); 1280 s = (uchar *)malloc(n1 + n2 + 1); 1281 if (s == NULL) { 1282 FATAL("out of space concatenating %.15s... and %.15s...", 1283 x->sval, y->sval); 1284 } 1285 (void) strcpy((char *)s, (char *)x->sval); 1286 (void) strcpy((char *)s + n1, (char *)y->sval); 1287 tempfree(x); 1288 tempfree(y); 1289 z = gettemp(); 1290 z->sval = s; 1291 z->tval = STR; 1292 return (z); 1293 } 1294 1295 /*ARGSUSED*/ 1296 Cell * 1297 pastat(Node **a, int n) /* a[0] { a[1] } */ 1298 { 1299 Cell *x; 1300 1301 if (a[0] == 0) 1302 x = execute(a[1]); 1303 else { 1304 x = execute(a[0]); 1305 if (istrue(x)) { 1306 tempfree(x); 1307 x = execute(a[1]); 1308 } 1309 } 1310 return (x); 1311 } 1312 1313 /*ARGSUSED*/ 1314 Cell * 1315 dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */ 1316 { 1317 Cell *x; 1318 int pair; 1319 1320 pair = ptoi(a[3]); 1321 if (pairstack[pair] == 0) { 1322 x = execute(a[0]); 1323 if (istrue(x)) 1324 pairstack[pair] = 1; 1325 tempfree(x); 1326 } 1327 if (pairstack[pair] == 1) { 1328 x = execute(a[1]); 1329 if (istrue(x)) 1330 pairstack[pair] = 0; 1331 tempfree(x); 1332 x = execute(a[2]); 1333 return (x); 1334 } 1335 return (False); 1336 } 1337 1338 /*ARGSUSED*/ 1339 Cell * 1340 split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ 1341 { 1342 Cell *x = 0, *y, *ap; 1343 uchar *s, *origs; 1344 int sep; 1345 uchar *t, temp, num[50], *fs = 0; 1346 int n, tempstat, arg3type; 1347 1348 y = execute(a[0]); /* source string */ 1349 origs = s = (uchar *)strdup((char *)getsval(y)); 1350 arg3type = ptoi(a[3]); 1351 if (a[2] == 0) /* fs string */ 1352 fs = *FS; 1353 else if (arg3type == STRING) { /* split(str,arr,"string") */ 1354 x = execute(a[2]); 1355 fs = getsval(x); 1356 } else if (arg3type == REGEXPR) 1357 fs = (uchar *)"(regexpr)"; /* split(str,arr,/regexpr/) */ 1358 else 1359 FATAL("illegal type of split"); 1360 sep = *fs; 1361 ap = execute(a[1]); /* array name */ 1362 freesymtab(ap); 1363 dprintf(("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs)); 1364 ap->tval &= ~STR; 1365 ap->tval |= ARR; 1366 ap->sval = (uchar *)makesymtab(NSYMTAB); 1367 1368 n = 0; 1369 if (arg3type == REGEXPR && strlen((char *)((fa *)a[2])->restr) == 0) { 1370 arg3type = 0; 1371 fs = (uchar *)""; 1372 sep = 0; 1373 } 1374 if (*s != '\0' && (strlen((char *)fs) > 1 || arg3type == REGEXPR)) { 1375 /* reg expr */ 1376 fa *pfa; 1377 if (arg3type == REGEXPR) { /* it's ready already */ 1378 pfa = (fa *)a[2]; 1379 } else { 1380 pfa = makedfa(fs, 1); 1381 } 1382 if (nematch(pfa, s)) { 1383 tempstat = pfa->initstat; 1384 pfa->initstat = 2; 1385 do { 1386 n++; 1387 (void) sprintf((char *)num, "%d", n); 1388 temp = *patbeg; 1389 *patbeg = '\0'; 1390 if (is_number(s)) { 1391 (void) setsymtab(num, s, 1392 atof((char *)s), 1393 /*LINTED align*/ 1394 STR|NUM, (Array *)ap->sval); 1395 } else { 1396 (void) setsymtab(num, s, 0.0, 1397 /*LINTED align*/ 1398 STR, (Array *)ap->sval); 1399 } 1400 *patbeg = temp; 1401 s = patbeg + patlen; 1402 if (*(patbeg+patlen-1) == 0 || *s == 0) { 1403 n++; 1404 (void) sprintf((char *)num, "%d", n); 1405 (void) setsymtab(num, (uchar *)"", 0.0, 1406 /*LINTED align*/ 1407 STR, (Array *)ap->sval); 1408 pfa->initstat = tempstat; 1409 goto spdone; 1410 } 1411 } while (nematch(pfa, s)); 1412 /* bwk: has to be here to reset */ 1413 pfa->initstat = tempstat; 1414 /* cf gsub and refldbld */ 1415 } 1416 n++; 1417 (void) sprintf((char *)num, "%d", n); 1418 if (is_number(s)) { 1419 (void) setsymtab(num, s, atof((char *)s), 1420 /*LINTED align*/ 1421 STR|NUM, (Array *)ap->sval); 1422 } else { 1423 /*LINTED align*/ 1424 (void) setsymtab(num, s, 0.0, STR, (Array *)ap->sval); 1425 } 1426 spdone: 1427 pfa = NULL; 1428 } else if (sep == ' ') { 1429 for (n = 0; ; ) { 1430 while (*s == ' ' || *s == '\t' || *s == '\n') 1431 s++; 1432 if (*s == 0) 1433 break; 1434 n++; 1435 t = s; 1436 do 1437 s++; 1438 while (*s != ' ' && *s != '\t' && 1439 *s != '\n' && *s != '\0') 1440 ; 1441 temp = *s; 1442 *s = '\0'; 1443 (void) sprintf((char *)num, "%d", n); 1444 if (is_number(t)) { 1445 (void) setsymtab(num, t, atof((char *)t), 1446 /*LINTED align*/ 1447 STR|NUM, (Array *)ap->sval); 1448 } else { 1449 (void) setsymtab(num, t, 0.0, 1450 /*LINTED align*/ 1451 STR, (Array *)ap->sval); 1452 } 1453 *s = temp; 1454 if (*s != 0) 1455 s++; 1456 } 1457 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */ 1458 for (n = 0; *s != 0; s++) { 1459 uchar buf[2]; 1460 n++; 1461 (void) sprintf((char *)num, "%d", n); 1462 buf[0] = *s; 1463 buf[1] = 0; 1464 if (isdigit(buf[0])) { 1465 (void) setsymtab(num, buf, atof((char *)buf), 1466 /* LINTED align */ 1467 STR | NUM, (Array *)ap->sval); 1468 } else { 1469 (void) setsymtab(num, buf, 0.0, 1470 /* LINTED align */ 1471 STR, (Array *)ap->sval); 1472 } 1473 } 1474 } else if (*s != 0) { 1475 for (;;) { 1476 n++; 1477 t = s; 1478 while (*s != sep && *s != '\n' && *s != '\0') 1479 s++; 1480 temp = *s; 1481 *s = '\0'; 1482 (void) sprintf((char *)num, "%d", n); 1483 if (is_number(t)) { 1484 (void) setsymtab(num, t, atof((char *)t), 1485 /*LINTED align*/ 1486 STR|NUM, (Array *)ap->sval); 1487 } else { 1488 (void) setsymtab(num, t, 0.0, 1489 /*LINTED align*/ 1490 STR, (Array *)ap->sval); 1491 } 1492 *s = temp; 1493 if (*s++ == 0) 1494 break; 1495 } 1496 } 1497 tempfree(ap); 1498 tempfree(y); 1499 free(origs); 1500 if (a[2] != 0 && arg3type == STRING) { 1501 tempfree(x); 1502 } 1503 x = gettemp(); 1504 x->tval = NUM; 1505 x->fval = n; 1506 return (x); 1507 } 1508 1509 /*ARGSUSED*/ 1510 Cell * 1511 condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */ 1512 { 1513 Cell *x; 1514 1515 x = execute(a[0]); 1516 if (istrue(x)) { 1517 tempfree(x); 1518 x = execute(a[1]); 1519 } else { 1520 tempfree(x); 1521 x = execute(a[2]); 1522 } 1523 return (x); 1524 } 1525 1526 /*ARGSUSED*/ 1527 Cell * 1528 ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */ 1529 { 1530 Cell *x; 1531 1532 x = execute(a[0]); 1533 if (istrue(x)) { 1534 tempfree(x); 1535 x = execute(a[1]); 1536 } else if (a[2] != 0) { 1537 tempfree(x); 1538 x = execute(a[2]); 1539 } 1540 return (x); 1541 } 1542 1543 /*ARGSUSED*/ 1544 Cell * 1545 whilestat(Node **a, int n) /* while (a[0]) a[1] */ 1546 { 1547 Cell *x; 1548 1549 for (;;) { 1550 x = execute(a[0]); 1551 if (!istrue(x)) 1552 return (x); 1553 tempfree(x); 1554 x = execute(a[1]); 1555 if (isbreak(x)) { 1556 x = True; 1557 return (x); 1558 } 1559 if (isnext(x) || isexit(x) || isret(x)) 1560 return (x); 1561 tempfree(x); 1562 } 1563 } 1564 1565 /*ARGSUSED*/ 1566 Cell * 1567 dostat(Node **a, int n) /* do a[0]; while(a[1]) */ 1568 { 1569 Cell *x; 1570 1571 for (;;) { 1572 x = execute(a[0]); 1573 if (isbreak(x)) 1574 return (True); 1575 if (isnext(x) || isexit(x) || isret(x)) 1576 return (x); 1577 tempfree(x); 1578 x = execute(a[1]); 1579 if (!istrue(x)) 1580 return (x); 1581 tempfree(x); 1582 } 1583 } 1584 1585 /*ARGSUSED*/ 1586 Cell * 1587 forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */ 1588 { 1589 Cell *x; 1590 1591 x = execute(a[0]); 1592 tempfree(x); 1593 for (;;) { 1594 if (a[1] != 0) { 1595 x = execute(a[1]); 1596 if (!istrue(x)) 1597 return (x); 1598 else 1599 tempfree(x); 1600 } 1601 x = execute(a[3]); 1602 if (isbreak(x)) /* turn off break */ 1603 return (True); 1604 if (isnext(x) || isexit(x) || isret(x)) 1605 return (x); 1606 tempfree(x); 1607 x = execute(a[2]); 1608 tempfree(x); 1609 } 1610 } 1611 1612 /*ARGSUSED*/ 1613 Cell * 1614 instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */ 1615 { 1616 Cell *x, *vp, *arrayp, *cp, *ncp; 1617 Array *tp; 1618 int i; 1619 1620 vp = execute(a[0]); 1621 arrayp = execute(a[1]); 1622 if (!isarr(arrayp)) { 1623 return (True); 1624 } 1625 /*LINTED align*/ 1626 tp = (Array *)arrayp->sval; 1627 tempfree(arrayp); 1628 for (i = 0; i < tp->size; i++) { /* this routine knows too much */ 1629 for (cp = tp->tab[i]; cp != NULL; cp = ncp) { 1630 (void) setsval(vp, cp->nval); 1631 ncp = cp->cnext; 1632 x = execute(a[2]); 1633 if (isbreak(x)) { 1634 tempfree(vp); 1635 return (True); 1636 } 1637 if (isnext(x) || isexit(x) || isret(x)) { 1638 tempfree(vp); 1639 return (x); 1640 } 1641 tempfree(x); 1642 } 1643 } 1644 return (True); 1645 } 1646 1647 /* 1648 * builtin functions. a[0] is type, a[1] is arg list 1649 */ 1650 /*ARGSUSED*/ 1651 Cell * 1652 bltin(Node **a, int n) 1653 { 1654 Cell *x, *y; 1655 Awkfloat u; 1656 int t; 1657 Awkfloat tmp; 1658 uchar *p, *buf; 1659 Node *nextarg; 1660 FILE *fp; 1661 1662 t = ptoi(a[0]); 1663 x = execute(a[1]); 1664 nextarg = a[1]->nnext; 1665 switch (t) { 1666 case FLENGTH: 1667 if (isarr(x)) { 1668 /* GROT. should be function */ 1669 /* LINTED align */ 1670 u = (Awkfloat)((Array *)x->sval)->nelem; 1671 } else { 1672 u = (Awkfloat)strlen((char *)getsval(x)); 1673 } 1674 break; 1675 case FLOG: 1676 u = errcheck(log(getfval(x)), "log"); break; 1677 case FINT: 1678 (void) modf(getfval(x), &u); break; 1679 case FEXP: 1680 u = errcheck(exp(getfval(x)), "exp"); break; 1681 case FSQRT: 1682 u = errcheck(sqrt(getfval(x)), "sqrt"); break; 1683 case FSIN: 1684 u = sin(getfval(x)); break; 1685 case FCOS: 1686 u = cos(getfval(x)); break; 1687 case FATAN: 1688 if (nextarg == 0) { 1689 WARNING("atan2 requires two arguments; returning 1.0"); 1690 u = 1.0; 1691 } else { 1692 y = execute(a[1]->nnext); 1693 u = atan2(getfval(x), getfval(y)); 1694 tempfree(y); 1695 nextarg = nextarg->nnext; 1696 } 1697 break; 1698 case FSYSTEM: 1699 /* in case something is buffered already */ 1700 (void) fflush(stdout); 1701 /* 256 is unix-dep */ 1702 u = (Awkfloat)system((char *)getsval(x)) / 256; 1703 break; 1704 case FRAND: 1705 /* in principle, rand() returns something in 0..RAND_MAX */ 1706 u = (Awkfloat)(rand() % RAND_MAX) / RAND_MAX; 1707 break; 1708 case FSRAND: 1709 if (isrec(x)) /* no argument provided */ 1710 u = time((time_t *)0); 1711 else 1712 u = getfval(x); 1713 tmp = u; 1714 srand((unsigned int)u); 1715 u = srand_seed; 1716 srand_seed = tmp; 1717 break; 1718 case FTOUPPER: 1719 case FTOLOWER: 1720 buf = tostring(getsval(x)); 1721 if (t == FTOUPPER) { 1722 for (p = buf; *p; p++) 1723 if (islower(*p)) 1724 *p = toupper(*p); 1725 } else { 1726 for (p = buf; *p; p++) 1727 if (isupper(*p)) 1728 *p = tolower(*p); 1729 } 1730 tempfree(x); 1731 x = gettemp(); 1732 (void) setsval(x, buf); 1733 free(buf); 1734 return (x); 1735 case FFLUSH: 1736 if (isrec(x) || strlen((char *)getsval(x)) == 0) { 1737 /* fflush() or fflush("") -> all */ 1738 flush_all(); 1739 u = 0; 1740 } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL) 1741 u = EOF; 1742 else 1743 u = fflush(fp); 1744 break; 1745 default: /* can't happen */ 1746 FATAL("illegal function type %d", t); 1747 break; 1748 } 1749 tempfree(x); 1750 x = gettemp(); 1751 (void) setfval(x, u); 1752 if (nextarg != 0) { 1753 WARNING("warning: function has too many arguments"); 1754 for (; nextarg; nextarg = nextarg->nnext) 1755 (void) execute(nextarg); 1756 } 1757 return (x); 1758 } 1759 1760 /*ARGSUSED*/ 1761 Cell * 1762 printstat(Node **a, int n) /* print a[0] */ 1763 { 1764 Node *x; 1765 Cell *y; 1766 FILE *fp; 1767 1768 if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */ 1769 fp = stdout; 1770 else 1771 fp = redirect(ptoi(a[1]), a[2]); 1772 for (x = a[0]; x != NULL; x = x->nnext) { 1773 y = execute(x); 1774 (void) fputs((char *)getsval(y), fp); 1775 tempfree(y); 1776 if (x->nnext == NULL) 1777 (void) fputs((char *)*ORS, fp); 1778 else 1779 (void) fputs((char *)*OFS, fp); 1780 } 1781 if (a[1] != 0) 1782 (void) fflush(fp); 1783 if (ferror(fp)) 1784 FATAL("write error on %s", filename(fp)); 1785 return (True); 1786 } 1787 1788 /*ARGSUSED*/ 1789 Cell * 1790 nullproc(Node **a, int n) 1791 { 1792 return (0); 1793 } 1794 1795 static FILE * 1796 redirect(int a, Node *b) /* set up all i/o redirections */ 1797 { 1798 FILE *fp; 1799 Cell *x; 1800 uchar *fname; 1801 1802 x = execute(b); 1803 fname = getsval(x); 1804 fp = openfile(a, fname); 1805 if (fp == NULL) 1806 FATAL("can't open file %s", fname); 1807 tempfree(x); 1808 return (fp); 1809 } 1810 1811 struct files { 1812 FILE *fp; 1813 const uchar *fname; 1814 int mode; /* '|', 'a', 'w' => LE/LT, GT */ 1815 } *files; 1816 1817 int nfiles; 1818 1819 static void 1820 stdinit(void) /* in case stdin, etc., are not constants */ 1821 { 1822 nfiles = FOPEN_MAX; 1823 files = calloc(nfiles, sizeof (*files)); 1824 if (files == NULL) 1825 FATAL("can't allocate file memory for %u files", nfiles); 1826 files[0].fp = stdin; 1827 files[0].fname = (uchar *)"/dev/stdin"; 1828 files[0].mode = LT; 1829 files[1].fp = stdout; 1830 files[1].fname = (uchar *)"/dev/stdout"; 1831 files[1].mode = GT; 1832 files[2].fp = stderr; 1833 files[2].fname = (uchar *)"/dev/stderr"; 1834 files[2].mode = GT; 1835 } 1836 1837 static FILE * 1838 openfile(int a, const uchar *us) 1839 { 1840 const uchar *s = us; 1841 int i, m; 1842 FILE *fp = 0; 1843 1844 if (*s == '\0') 1845 FATAL("null file name in print or getline"); 1846 for (i = 0; i < nfiles; i++) { 1847 if (files[i].fname && 1848 (strcmp((char *)s, (char *)files[i].fname) == 0)) { 1849 if (a == files[i].mode || 1850 (a == APPEND && files[i].mode == GT)) { 1851 return (files[i].fp); 1852 } 1853 if (a == FFLUSH) 1854 return (files[i].fp); 1855 } 1856 } 1857 if (a == FFLUSH) /* didn't find it, so don't create it! */ 1858 return (NULL); 1859 1860 for (i = 0; i < nfiles; i++) { 1861 if (files[i].fp == 0) 1862 break; 1863 } 1864 if (i >= nfiles) { 1865 struct files *nf; 1866 int nnf = nfiles + FOPEN_MAX; 1867 nf = realloc(files, nnf * sizeof (*nf)); 1868 if (nf == NULL) 1869 FATAL("cannot grow files for %s and %d files", s, nnf); 1870 (void) memset(&nf[nfiles], 0, FOPEN_MAX * sizeof (*nf)); 1871 nfiles = nnf; 1872 files = nf; 1873 } 1874 (void) fflush(stdout); /* force a semblance of order */ 1875 m = a; 1876 if (a == GT) { 1877 fp = fopen((char *)s, "w"); 1878 } else if (a == APPEND) { 1879 fp = fopen((char *)s, "a"); 1880 m = GT; /* so can mix > and >> */ 1881 } else if (a == '|') { /* output pipe */ 1882 fp = popen((char *)s, "w"); 1883 } else if (a == LE) { /* input pipe */ 1884 fp = popen((char *)s, "r"); 1885 } else if (a == LT) { /* getline <file */ 1886 fp = strcmp((char *)s, "-") == 0 ? 1887 stdin : fopen((char *)s, "r"); /* "-" is stdin */ 1888 } else /* can't happen */ 1889 FATAL("illegal redirection %d", a); 1890 if (fp != NULL) { 1891 files[i].fname = tostring(s); 1892 files[i].fp = fp; 1893 files[i].mode = m; 1894 } 1895 return (fp); 1896 } 1897 1898 static const char * 1899 filename(FILE *fp) 1900 { 1901 int i; 1902 1903 for (i = 0; i < nfiles; i++) { 1904 if (fp == files[i].fp) 1905 return ((char *)files[i].fname); 1906 } 1907 1908 return ("???"); 1909 } 1910 1911 /*ARGSUSED*/ 1912 Cell * 1913 closefile(Node **a, int n) 1914 { 1915 Cell *x; 1916 int i, stat; 1917 1918 x = execute(a[0]); 1919 (void) getsval(x); 1920 stat = -1; 1921 for (i = 0; i < nfiles; i++) { 1922 if (files[i].fname && 1923 strcmp((char *)x->sval, (char *)files[i].fname) == 0) { 1924 if (ferror(files[i].fp)) { 1925 WARNING("i/o error occurred on %s", 1926 files[i].fname); 1927 } 1928 if (files[i].mode == '|' || files[i].mode == LE) 1929 stat = pclose(files[i].fp); 1930 else 1931 stat = fclose(files[i].fp); 1932 if (stat == EOF) { 1933 WARNING("i/o error occurred closing %s", 1934 files[i].fname); 1935 } 1936 if (i > 2) /* don't do /dev/std... */ 1937 xfree(files[i].fname); 1938 /* watch out for ref thru this */ 1939 files[i].fname = NULL; 1940 files[i].fp = NULL; 1941 } 1942 } 1943 tempfree(x); 1944 x = gettemp(); 1945 (void) setfval(x, (Awkfloat)stat); 1946 return (x); 1947 } 1948 1949 static void 1950 closeall(void) 1951 { 1952 int i, stat; 1953 1954 for (i = 0; i < FOPEN_MAX; i++) { 1955 if (files[i].fp) { 1956 if (ferror(files[i].fp)) { 1957 WARNING("i/o error occurred on %s", 1958 files[i].fname); 1959 } 1960 if (files[i].mode == '|' || files[i].mode == LE) 1961 stat = pclose(files[i].fp); 1962 else 1963 stat = fclose(files[i].fp); 1964 if (stat == EOF) { 1965 WARNING("i/o error occurred while closing %s", 1966 files[i].fname); 1967 } 1968 } 1969 } 1970 } 1971 1972 static void 1973 flush_all(void) 1974 { 1975 int i; 1976 1977 for (i = 0; i < nfiles; i++) 1978 if (files[i].fp) 1979 (void) fflush(files[i].fp); 1980 } 1981 1982 void backsub(uchar **pb_ptr, uchar **sptr_ptr); 1983 1984 /*ARGSUSED*/ 1985 Cell * 1986 sub(Node **a, int nnn) /* substitute command */ 1987 { 1988 uchar *sptr, *pb, *q; 1989 Cell *x, *y, *result; 1990 uchar *t, *buf; 1991 fa *pfa; 1992 size_t bufsz = record_size; 1993 1994 if ((buf = (uchar *)malloc(bufsz)) == NULL) 1995 FATAL("out of memory in sub"); 1996 x = execute(a[3]); /* target string */ 1997 t = getsval(x); 1998 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ 1999 pfa = (fa *)a[1]; /* regular expression */ 2000 else { 2001 y = execute(a[1]); 2002 pfa = makedfa(getsval(y), 1); 2003 tempfree(y); 2004 } 2005 y = execute(a[2]); /* replacement string */ 2006 result = False; 2007 if (pmatch(pfa, t)) { 2008 sptr = t; 2009 (void) adjbuf(&buf, &bufsz, 1+patbeg-sptr, record_size, 2010 0, "sub"); 2011 pb = buf; 2012 while (sptr < patbeg) 2013 *pb++ = *sptr++; 2014 sptr = getsval(y); 2015 while (*sptr != 0) { 2016 (void) adjbuf(&buf, &bufsz, 5 + pb - buf, record_size, 2017 &pb, "sub"); 2018 if (*sptr == '\\') { 2019 backsub(&pb, &sptr); 2020 } else if (*sptr == '&') { 2021 sptr++; 2022 (void) adjbuf(&buf, &bufsz, 1+patlen+pb-buf, 2023 record_size, &pb, "sub"); 2024 for (q = patbeg; q < patbeg + patlen; ) 2025 *pb++ = *q++; 2026 } else { 2027 *pb++ = *sptr++; 2028 } 2029 } 2030 *pb = '\0'; 2031 if (pb > buf + bufsz) 2032 FATAL("sub result1 %.30s too big; can't happen", buf); 2033 sptr = patbeg + patlen; 2034 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) { 2035 (void) adjbuf(&buf, &bufsz, 1 + strlen((char *)sptr) + 2036 pb - buf, 0, &pb, "sub"); 2037 while ((*pb++ = *sptr++) != 0) 2038 ; 2039 } 2040 if (pb > buf + bufsz) 2041 FATAL("sub result2 %.30s too big; can't happen", buf); 2042 /* BUG: should be able to avoid copy */ 2043 (void) setsval(x, buf); 2044 result = True; 2045 } 2046 tempfree(x); 2047 tempfree(y); 2048 free(buf); 2049 return (result); 2050 } 2051 2052 /*ARGSUSED*/ 2053 Cell * 2054 gsub(Node **a, int nnn) /* global substitute */ 2055 { 2056 Cell *x, *y; 2057 uchar *rptr, *sptr, *t, *pb, *q; 2058 uchar *buf; 2059 fa *pfa; 2060 int mflag, tempstat, num; 2061 size_t bufsz = record_size; 2062 2063 if ((buf = (uchar *)malloc(bufsz)) == NULL) 2064 FATAL("out of memory in gsub"); 2065 mflag = 0; /* if mflag == 0, can replace empty string */ 2066 num = 0; 2067 x = execute(a[3]); /* target string */ 2068 t = getsval(x); 2069 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ 2070 pfa = (fa *)a[1]; /* regular expression */ 2071 else { 2072 y = execute(a[1]); 2073 pfa = makedfa(getsval(y), 1); 2074 tempfree(y); 2075 } 2076 y = execute(a[2]); /* replacement string */ 2077 if (pmatch(pfa, t)) { 2078 tempstat = pfa->initstat; 2079 pfa->initstat = 2; 2080 pb = buf; 2081 rptr = getsval(y); 2082 do { 2083 if (patlen == 0 && *patbeg != 0) { 2084 /* matched empty string */ 2085 if (mflag == 0) { /* can replace empty */ 2086 num++; 2087 sptr = rptr; 2088 while (*sptr != 0) { 2089 (void) adjbuf(&buf, &bufsz, 5+pb-buf, 2090 record_size, &pb, "gsub"); 2091 if (*sptr == '\\') { 2092 backsub(&pb, &sptr); 2093 } else if (*sptr == '&') { 2094 sptr++; 2095 (void) adjbuf(&buf, &bufsz, 1 + 2096 patlen+pb-buf, record_size, 2097 &pb, "gsub"); 2098 for (q = patbeg; q < patbeg+patlen; ) 2099 *pb++ = *q++; 2100 } else { 2101 *pb++ = *sptr++; 2102 } 2103 } 2104 } 2105 if (*t == 0) /* at end */ 2106 goto done; 2107 (void) adjbuf(&buf, &bufsz, 2 + pb - buf, 2108 record_size, &pb, "gsub"); 2109 *pb++ = *t++; 2110 /* BUG: not sure of this test */ 2111 if (pb > buf + bufsz) 2112 FATAL( 2113 "gsub result0 %.30s too big; can't happen", buf); 2114 mflag = 0; 2115 } else { /* matched nonempty string */ 2116 num++; 2117 sptr = t; 2118 (void) adjbuf(&buf, &bufsz, 1 + 2119 (patbeg - sptr) + pb - buf, record_size, 2120 &pb, "gsub"); 2121 while (sptr < patbeg) 2122 *pb++ = *sptr++; 2123 sptr = rptr; 2124 while (*sptr != 0) { 2125 (void) adjbuf(&buf, &bufsz, 5 + pb - 2126 buf, record_size, &pb, "gsub"); 2127 if (*sptr == '\\') { 2128 backsub(&pb, &sptr); 2129 } else if (*sptr == '&') { 2130 sptr++; 2131 (void) adjbuf(&buf, &bufsz, 1 + 2132 patlen + pb - buf, record_size, 2133 &pb, "gsub"); 2134 for (q = patbeg; q < patbeg + patlen; ) 2135 *pb++ = *q++; 2136 } else { 2137 *pb++ = *sptr++; 2138 } 2139 } 2140 t = patbeg + patlen; 2141 if (patlen == 0 || *t == 0 || *(t - 1) == 0) 2142 goto done; 2143 if (pb > buf + bufsz) 2144 FATAL( 2145 "gsub result1 %.30s too big; can't happen", buf); 2146 mflag = 1; 2147 } 2148 } while (pmatch(pfa, t)); 2149 sptr = t; 2150 (void) adjbuf(&buf, &bufsz, 1 + strlen((char *)sptr) + pb - 2151 buf, 0, &pb, "gsub"); 2152 while ((*pb++ = *sptr++) != 0) 2153 ; 2154 done: if (pb < buf + bufsz) 2155 *pb = '\0'; 2156 else if (*(pb-1) != '\0') 2157 FATAL("gsub result2 %.30s truncated; can't happen", 2158 buf); 2159 /* BUG: should be able to avoid copy + free */ 2160 (void) setsval(x, buf); 2161 pfa->initstat = tempstat; 2162 } 2163 tempfree(x); 2164 tempfree(y); 2165 x = gettemp(); 2166 x->tval = NUM; 2167 x->fval = num; 2168 free(buf); 2169 return (x); 2170 } 2171 2172 void 2173 backsub(uchar **pb_ptr, uchar **sptr_ptr) /* handle \\& variations */ 2174 { /* sptr[0] == '\\' */ 2175 uchar *pb = *pb_ptr, *sptr = *sptr_ptr; 2176 2177 if (sptr[1] == '\\') { 2178 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */ 2179 *pb++ = '\\'; 2180 *pb++ = '&'; 2181 sptr += 4; 2182 } else if (sptr[2] == '&') { /* \\& -> \ + matched */ 2183 *pb++ = '\\'; 2184 sptr += 2; 2185 } else { /* \\x -> \\x */ 2186 *pb++ = *sptr++; 2187 *pb++ = *sptr++; 2188 } 2189 } else if (sptr[1] == '&') { /* literal & */ 2190 sptr++; 2191 *pb++ = *sptr++; 2192 } else /* literal \ */ 2193 *pb++ = *sptr++; 2194 2195 *pb_ptr = pb; 2196 *sptr_ptr = sptr; 2197 }