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 /* 26 * CDDL HEADER START 27 * 28 * The contents of this file are subject to the terms of the 29 * Common Development and Distribution License (the "License"). 30 * You may not use this file except in compliance with the License. 31 * 32 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 33 * or http://www.opensolaris.org/os/licensing. 34 * See the License for the specific language governing permissions 35 * and limitations under the License. 36 * 37 * When distributing Covered Code, include this CDDL HEADER in each 38 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 39 * If applicable, add the following below this CDDL HEADER, with the 40 * fields enclosed by brackets "[]" replaced with your own identifying 41 * information: Portions Copyright [yyyy] [name of copyright owner] 42 * 43 * CDDL HEADER END 44 */ 45 46 /* 47 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 48 * Use is subject to license terms. 49 */ 50 51 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 52 /* All Rights Reserved */ 53 54 /* Copyright (c) Lucent Technologies 1997 */ 55 /* All Rights Reserved */ 56 57 #include <stdio.h> 58 #include <string.h> 59 #include <ctype.h> 60 #include <errno.h> 61 #include <stdlib.h> 62 #include <stdarg.h> 63 #include "awk.h" 64 #include "y.tab.h" 65 66 static FILE *infile = NULL; 67 static char *file = ""; 68 char *record; 69 size_t recsize = RECSIZE; 70 static char *fields; 71 static size_t fieldssize = RECSIZE; 72 static char *rtbuf; 73 static size_t rtbufsize = RECSIZE; 74 75 Cell **fldtab; /* pointers to Cells */ 76 char inputFS[100] = " "; 77 78 #define MAXFLD 2 79 int nfields = MAXFLD; /* last allocated slot for $i */ 80 81 int donefld; /* 1 = implies rec broken into fields */ 82 int donerec; /* 1 = record is valid (no flds have changed) */ 83 84 static int lastfld = 0; /* last used field */ 85 static int argno = 1; /* current input argument number */ 86 87 static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE }; 88 static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE }; 89 90 static char *getargv(int); 91 static void cleanfld(int, int); 92 static int refldbld(const char *, const char *); 93 static void bcheck2(int, int, int); 94 static void eprint(void); 95 static void bclass(int); 96 97 void 98 recinit(unsigned int n) 99 { 100 if ((record = (char *)malloc(n)) == NULL || 101 (fields = (char *)malloc(n+2)) == NULL || 102 (fldtab = (Cell **)malloc((nfields+1) * sizeof (Cell *))) == NULL || 103 (fldtab[0] = (Cell *)malloc(sizeof (Cell))) == NULL) 104 FATAL("out of space for $0 and fields"); 105 *fldtab[0] = dollar0; 106 fldtab[0]->sval = record; 107 fldtab[0]->nval = tostring("0"); 108 makefields(1, nfields); 109 } 110 111 void 112 makefields(int n1, int n2) /* create $n1..$n2 inclusive */ 113 { 114 char temp[50]; 115 int i; 116 117 for (i = n1; i <= n2; i++) { 118 fldtab[i] = (Cell *)malloc(sizeof (Cell)); 119 if (fldtab[i] == NULL) 120 FATAL("out of space in makefields %d", i); 121 *fldtab[i] = dollar1; 122 (void) sprintf(temp, "%d", i); 123 fldtab[i]->nval = tostring(temp); 124 } 125 } 126 127 static void 128 initgetrec(void) 129 { 130 int i; 131 char *p; 132 133 for (i = 1; i < *ARGC; i++) { 134 p = getargv(i); /* find 1st real filename */ 135 if (p == NULL || *p == '\0') { /* deleted or zapped */ 136 argno++; 137 continue; 138 } 139 if (!isclvar(p)) { 140 (void) setsval(lookup("FILENAME", symtab), p); 141 return; 142 } 143 setclvar(p); /* a commandline assignment before filename */ 144 argno++; 145 } 146 infile = stdin; /* no filenames, so use stdin */ 147 } 148 149 /* 150 * POSIX specifies that fields are supposed to be evaluated as if they were 151 * split using the value of FS at the time that the record's value ($0) was 152 * read. 153 * 154 * Since field-splitting is done lazily, we save the current value of FS 155 * whenever a new record is read in (implicitly or via getline), or when 156 * a new value is assigned to $0. 157 */ 158 void 159 savefs(void) 160 { 161 if (strlen(getsval(fsloc)) >= sizeof (inputFS)) 162 FATAL("field separator %.10s... is too long", *FS); 163 (void) strcpy(inputFS, *FS); 164 } 165 166 static int firsttime = 1; 167 168 /* 169 * get next input record 170 * note: cares whether buf == record 171 */ 172 int 173 getrec(char **pbuf, size_t *pbufsize, int isrecord) 174 { 175 int c; 176 char *buf = *pbuf; 177 uschar saveb0; 178 size_t bufsize = *pbufsize, savebufsize = bufsize; 179 180 if (firsttime) { 181 firsttime = 0; 182 initgetrec(); 183 } 184 dprintf(("RS=<%s>, FS=<%s>, ARGC=%f, FILENAME=%s\n", 185 *RS, *FS, *ARGC, *FILENAME)); 186 if (isrecord) { 187 donefld = 0; 188 donerec = 1; 189 savefs(); 190 } 191 saveb0 = buf[0]; 192 buf[0] = '\0'; 193 while (argno < *ARGC || infile == stdin) { 194 dprintf(("argno=%d, file=|%s|\n", argno, file)); 195 if (infile == NULL) { /* have to open a new file */ 196 file = getargv(argno); 197 if (file == NULL || *file == '\0') { 198 /* deleted or zapped */ 199 argno++; 200 continue; 201 } 202 if (isclvar(file)) { 203 /* a var=value arg */ 204 setclvar(file); 205 argno++; 206 continue; 207 } 208 *FILENAME = file; 209 dprintf(("opening file %s\n", file)); 210 if (*file == '-' && *(file+1) == '\0') 211 infile = stdin; 212 else if ((infile = fopen(file, "rF")) == NULL) 213 FATAL("can't open file %s", file); 214 (void) setfval(fnrloc, 0.0); 215 } 216 c = readrec(&buf, &bufsize, infile); 217 218 if (c != 0 || buf[0] != '\0') { /* normal record */ 219 if (isrecord) { 220 if (freeable(recloc)) 221 xfree(recloc->sval); 222 recloc->sval = buf; /* buf == record */ 223 recloc->tval = REC | STR | DONTFREE; 224 if (is_number(recloc->sval)) { 225 recloc->fval = 226 atof(recloc->sval); 227 recloc->tval |= NUM; 228 } 229 } 230 (void) setfval(nrloc, nrloc->fval+1); 231 (void) setfval(fnrloc, fnrloc->fval+1); 232 *pbuf = buf; 233 *pbufsize = bufsize; 234 return (1); 235 } 236 /* EOF arrived on this file; set up next */ 237 if (infile != stdin) 238 (void) fclose(infile); 239 infile = NULL; 240 argno++; 241 } 242 buf[0] = saveb0; 243 *pbuf = buf; 244 *pbufsize = savebufsize; 245 return (0); /* true end of file */ 246 } 247 248 void 249 nextfile(void) 250 { 251 if (infile != NULL && infile != stdin) 252 (void) fclose(infile); 253 infile = NULL; 254 argno++; 255 } 256 257 /* 258 * read one record into buf 259 */ 260 int 261 readrec(char **pbuf, size_t *pbufsize, FILE *inf) 262 { 263 int sep, c; 264 char *rr, *rt, *buf = *pbuf; 265 size_t bufsize = *pbufsize; 266 char *rs = getsval(rsloc); 267 268 if (rtbuf == NULL && (rtbuf = malloc(rtbufsize)) == NULL) 269 FATAL("out of memory in readrec"); 270 271 rr = buf; 272 rt = rtbuf; 273 274 if ((sep = *rs) == '\0') { 275 sep = '\n'; 276 /* skip leading \n's */ 277 while ((c = getc(inf)) == '\n' && c != EOF) 278 ; 279 if (c != EOF) 280 (void) ungetc(c, inf); 281 } 282 while ((c = getc(inf)) != EOF) { 283 if (c != sep) { 284 if (rr-buf+1 > bufsize) { 285 (void) adjbuf(&buf, &bufsize, 286 1+rr-buf, recsize, &rr, "readrec1"); 287 } 288 *rr++ = c; 289 continue; 290 } 291 292 /* 293 * Ensure enough space for either a single separator 294 * character, or at least two '\n' chars (when RS is 295 * the empty string). 296 */ 297 (void) adjbuf(&rtbuf, &rtbufsize, 298 2+rt-rtbuf, recsize, &rt, "readrec2"); 299 300 if (*rs == sep) { 301 *rt++ = sep; 302 break; 303 } 304 305 if ((c = getc(inf)) == '\n') { /* 2 in a row */ 306 *rt++ = '\n'; 307 *rt++ = '\n'; 308 while ((c = getc(inf)) == '\n' && c != EOF) { 309 /* Read any further \n's and add them to RT. */ 310 (void) adjbuf(&rtbuf, &rtbufsize, 311 1+rt-rtbuf, recsize, &rt, "readrec3"); 312 *rt++ = '\n'; 313 } 314 if (c != EOF) 315 (void) ungetc(c, inf); 316 break; 317 } 318 319 if (c == EOF) { 320 *rt++ = '\n'; 321 break; 322 } 323 324 (void) adjbuf(&buf, &bufsize, 325 2+rr-buf, recsize, &rr, "readrec4"); 326 *rr++ = '\n'; 327 *rr++ = c; 328 } 329 (void) adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec5"); 330 (void) adjbuf(&rtbuf, &rtbufsize, 1+rt-rtbuf, recsize, &rt, "readrec6"); 331 *rr = '\0'; 332 *rt = '\0'; 333 dprintf(("readrec saw <%s>, returns %d\n", 334 buf, c == EOF && rr == buf ? 0 : 1)); 335 *pbuf = buf; 336 *pbufsize = bufsize; 337 if (c == EOF && rr == buf) { 338 return (0); 339 } else { 340 (void) setsval(rtloc, rtbuf); 341 return (1); 342 } 343 } 344 345 /* get ARGV[n] */ 346 static char * 347 getargv(int n) 348 { 349 Cell *x; 350 char *s, temp[50]; 351 extern Array *ARGVtab; 352 353 (void) sprintf(temp, "%d", n); 354 if (lookup(temp, ARGVtab) == NULL) 355 return (NULL); 356 x = setsymtab(temp, "", 0.0, STR, ARGVtab); 357 s = getsval(x); 358 dprintf(("getargv(%d) returns |%s|\n", n, s)); 359 return (s); 360 } 361 362 void 363 setclvar(char *s) /* set var=value from s */ 364 { 365 char *p; 366 Cell *q; 367 368 for (p = s; *p != '='; p++) 369 ; 370 *p++ = 0; 371 p = qstring(p, '\0'); 372 q = setsymtab(s, p, 0.0, STR, symtab); 373 (void) setsval(q, p); 374 if (is_number(q->sval)) { 375 q->fval = atof(q->sval); 376 q->tval |= NUM; 377 } 378 dprintf(("command line set %s to |%s|\n", s, p)); 379 free(p); 380 } 381 382 void 383 fldbld(void) /* create fields from current record */ 384 { 385 /* this relies on having fields[] the same length as $0 */ 386 /* the fields are all stored in this one array with \0's */ 387 /* possibly with a final trailing \0 not associated with any field */ 388 char *r, *fr, sep; 389 Cell *p; 390 int i, j, n; 391 392 if (donefld) 393 return; 394 if (!isstr(fldtab[0])) 395 (void) getsval(fldtab[0]); 396 r = fldtab[0]->sval; 397 n = strlen(r); 398 if (n > fieldssize) { 399 xfree(fields); 400 /* possibly 2 final \0s */ 401 if ((fields = (char *)malloc(n + 2)) == NULL) 402 FATAL("out of space for fields in fldbld %d", n); 403 fieldssize = n; 404 } 405 fr = fields; 406 407 i = 0; /* number of fields accumulated here */ 408 if (strlen(inputFS) > 1) { /* it's a regular expression */ 409 i = refldbld(r, inputFS); 410 } else if ((sep = *inputFS) == ' ') { /* default whitespace */ 411 for (i = 0; ; ) { 412 while (*r == ' ' || *r == '\t' || *r == '\n') 413 r++; 414 if (*r == '\0') 415 break; 416 i++; 417 if (i > nfields) 418 growfldtab(i); 419 if (freeable(fldtab[i])) 420 xfree(fldtab[i]->sval); 421 fldtab[i]->sval = fr; 422 fldtab[i]->tval = FLD | STR | DONTFREE; 423 do 424 *fr++ = *r++; 425 while (*r != ' ' && *r != '\t' && *r != '\n' && 426 *r != '\0') 427 ; 428 *fr++ = '\0'; 429 } 430 *fr = '\0'; 431 } else if ((sep = *inputFS) == '\0') { 432 /* new: FS="" => 1 char/field */ 433 for (i = 0; *r != '\0'; r++) { 434 char buf[2]; 435 i++; 436 if (i > nfields) 437 growfldtab(i); 438 if (freeable(fldtab[i])) 439 xfree(fldtab[i]->sval); 440 buf[0] = *r; 441 buf[1] = '\0'; 442 fldtab[i]->sval = tostring(buf); 443 fldtab[i]->tval = FLD | STR; 444 } 445 *fr = '\0'; 446 } else if (*r != '\0') { /* if 0, it's a null field */ 447 /* 448 * subtlecase : if length(FS) == 1 && length(RS > 0) 449 * \n is NOT a field separator (cf awk book 61,84). 450 * this variable is tested in the inner while loop. 451 */ 452 int rtest = '\n'; /* normal case */ 453 if (strlen(*RS) > 0) 454 rtest = '\0'; 455 for (;;) { 456 i++; 457 if (i > nfields) 458 growfldtab(i); 459 if (freeable(fldtab[i])) 460 xfree(fldtab[i]->sval); 461 fldtab[i]->sval = fr; 462 fldtab[i]->tval = FLD | STR | DONTFREE; 463 /* \n is always a separator */ 464 while (*r != sep && *r != rtest && *r != '\0') 465 *fr++ = *r++; 466 *fr++ = '\0'; 467 if (*r++ == '\0') 468 break; 469 } 470 *fr = '\0'; 471 } 472 if (i > nfields) 473 FATAL("record `%.30s...' has too many fields; can't happen", r); 474 /* clean out junk from previous record */ 475 cleanfld(i+1, lastfld); 476 lastfld = i; 477 donefld = 1; 478 for (j = 1; j <= lastfld; j++) { 479 p = fldtab[j]; 480 if (is_number(p->sval)) { 481 p->fval = atof(p->sval); 482 p->tval |= NUM; 483 } 484 } 485 (void) setfval(nfloc, (Awkfloat)lastfld); 486 donerec = 1; /* restore */ 487 if (dbg) { 488 for (j = 0; j <= lastfld; j++) { 489 p = fldtab[j]; 490 (void) printf("field %d (%s): |%s|\n", 491 j, p->nval, p->sval); 492 } 493 } 494 } 495 496 /* clean out fields n1 .. n2 inclusive; nvals remain intact */ 497 static void 498 cleanfld(int n1, int n2) 499 { 500 Cell *p; 501 int i; 502 503 for (i = n1; i <= n2; i++) { 504 p = fldtab[i]; 505 if (freeable(p)) 506 xfree(p->sval); 507 p->sval = ""; 508 p->tval = FLD | STR | DONTFREE; 509 } 510 } 511 512 void 513 newfld(int n) /* add field n after end of existing lastfld */ 514 { 515 if (n > nfields) 516 growfldtab(n); 517 cleanfld(lastfld+1, n); 518 lastfld = n; 519 (void) setfval(nfloc, (Awkfloat)n); 520 } 521 522 void 523 setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */ 524 { 525 if (n < 0) 526 FATAL("cannot set NF to a negative value"); 527 if (n > nfields) 528 growfldtab(n); 529 530 if (lastfld < n) 531 cleanfld(lastfld+1, n); 532 else 533 cleanfld(n+1, lastfld); 534 535 lastfld = n; 536 } 537 538 Cell * 539 fieldadr(int n) /* get nth field */ 540 { 541 if (n < 0) 542 FATAL("trying to access out of range field %d", n); 543 if (n > nfields) /* fields after NF are empty */ 544 growfldtab(n); /* but does not increase NF */ 545 return (fldtab[n]); 546 } 547 548 void 549 growfldtab(int n) /* make new fields up to at least $n */ 550 { 551 int nf = 2 * nfields; 552 size_t s; 553 554 if (n > nf) 555 nf = n; 556 s = (nf+1) * (sizeof (Cell *)); /* freebsd: how much do we need? */ 557 if (s / sizeof (Cell *) - 1 == nf) /* didn't overflow */ 558 fldtab = (Cell **)realloc(fldtab, s); 559 else /* overflow sizeof int */ 560 xfree(fldtab); /* make it null */ 561 if (fldtab == NULL) 562 FATAL("out of space creating %d fields", nf); 563 makefields(nfields+1, nf); 564 nfields = nf; 565 } 566 567 /* build fields from reg expr in FS */ 568 static int 569 refldbld(const char *rec, const char *fs) 570 { 571 /* this relies on having fields[] the same length as $0 */ 572 /* the fields are all stored in this one array with \0's */ 573 char *fr; 574 int i, tempstat, n; 575 fa *pfa; 576 577 n = strlen(rec); 578 if (n > fieldssize) { 579 xfree(fields); 580 if ((fields = (char *)malloc(n+1)) == NULL) 581 FATAL("out of space for fields in refldbld %d", n); 582 fieldssize = n; 583 } 584 fr = fields; 585 *fr = '\0'; 586 if (*rec == '\0') 587 return (0); 588 pfa = makedfa(fs, 1); 589 dprintf(("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs)); 590 tempstat = pfa->initstat; 591 for (i = 1; ; i++) { 592 if (i > nfields) 593 growfldtab(i); 594 if (freeable(fldtab[i])) 595 xfree(fldtab[i]->sval); 596 fldtab[i]->tval = FLD | STR | DONTFREE; 597 fldtab[i]->sval = fr; 598 dprintf(("refldbld: i=%d\n", i)); 599 if (nematch(pfa, rec)) { 600 pfa->initstat = 2; /* horrible coupling to b.c */ 601 dprintf(("match %s (%d chars)\n", patbeg, patlen)); 602 (void) strncpy(fr, rec, patbeg-rec); 603 fr += patbeg - rec + 1; 604 *(fr-1) = '\0'; 605 rec = patbeg + patlen; 606 } else { 607 dprintf(("no match %s\n", rec)); 608 (void) strcpy(fr, rec); 609 pfa->initstat = tempstat; 610 break; 611 } 612 } 613 return (i); 614 } 615 616 void 617 recbld(void) /* create $0 from $1..$NF if necessary */ 618 { 619 int i; 620 char *p; 621 size_t cnt, len, olen; 622 char *sep = getsval(ofsloc); 623 624 if (donerec == 1) 625 return; 626 cnt = 0; 627 olen = strlen(sep); 628 for (i = 1; i <= *NF; i++) { 629 p = getsval(fldtab[i]); 630 len = strlen(p); 631 expand_buf(&record, &recsize, cnt + len + olen); 632 (void) memcpy(&record[cnt], p, len); 633 cnt += len; 634 if (i < *NF) { 635 (void) memcpy(&record[cnt], sep, olen); 636 cnt += olen; 637 } 638 } 639 record[cnt] = '\0'; 640 dprintf(("in recbld inputFS=%s, recloc=%p\n", inputFS, (void *)recloc)); 641 if (freeable(recloc)) 642 xfree(recloc->sval); 643 recloc->tval = REC | STR | DONTFREE; 644 recloc->sval = record; 645 dprintf(("in recbld inputFS=%s, recloc=%p\n", inputFS, (void *)recloc)); 646 dprintf(("recbld = |%s|\n", record)); 647 donerec = 1; 648 } 649 650 int errorflag = 0; 651 652 int 653 yyerror(const char *s) 654 { 655 SYNTAX("%s", s); 656 return (0); 657 } 658 659 void 660 SYNTAX(const char *fmt, ...) 661 { 662 extern char *cmdname, *curfname; 663 static int been_here = 0; 664 va_list varg; 665 666 if (been_here++ > 2) 667 return; 668 (void) fprintf(stderr, "%s: ", cmdname); 669 va_start(varg, fmt); 670 (void) vfprintf(stderr, fmt, varg); 671 va_end(varg); 672 (void) fprintf(stderr, " at source line %lld", lineno); 673 if (curfname != NULL) 674 (void) fprintf(stderr, " in function %s", curfname); 675 if (compile_time == 1 && cursource() != NULL) 676 (void) fprintf(stderr, " source file %s", cursource()); 677 (void) fprintf(stderr, "\n"); 678 errorflag = 2; 679 eprint(); 680 } 681 682 void 683 fpecatch(int n) 684 { 685 FATAL("floating point exception %d", n); 686 } 687 688 extern int bracecnt, brackcnt, parencnt; 689 690 void 691 bracecheck(void) 692 { 693 int c; 694 static int beenhere = 0; 695 696 if (beenhere++) 697 return; 698 while ((c = input()) != EOF && c != '\0') 699 bclass(c); 700 bcheck2(bracecnt, '{', '}'); 701 bcheck2(brackcnt, '[', ']'); 702 bcheck2(parencnt, '(', ')'); 703 } 704 705 /*ARGSUSED*/ 706 static void 707 bcheck2(int n, int c1, int c2) 708 { 709 if (n == 1) 710 (void) fprintf(stderr, gettext("\tmissing %c\n"), c2); 711 else if (n > 1) 712 (void) fprintf(stderr, gettext("\t%d missing %c's\n"), n, c2); 713 else if (n == -1) 714 (void) fprintf(stderr, gettext("\textra %c\n"), c2); 715 else if (n < -1) 716 (void) fprintf(stderr, gettext("\t%d extra %c's\n"), -n, c2); 717 } 718 719 void 720 FATAL(const char *fmt, ...) 721 { 722 extern char *cmdname; 723 va_list varg; 724 725 (void) fflush(stdout); 726 (void) fprintf(stderr, "%s: ", cmdname); 727 va_start(varg, fmt); 728 (void) vfprintf(stderr, fmt, varg); 729 va_end(varg); 730 error(); 731 if (dbg > 1) /* core dump if serious debugging on */ 732 abort(); 733 exit(2); 734 } 735 736 void 737 WARNING(const char *fmt, ...) 738 { 739 extern char *cmdname; 740 va_list varg; 741 742 (void) fflush(stdout); 743 (void) fprintf(stderr, "%s: ", cmdname); 744 va_start(varg, fmt); 745 (void) vfprintf(stderr, fmt, varg); 746 va_end(varg); 747 error(); 748 } 749 750 void 751 error(void) 752 { 753 extern Node *curnode; 754 755 (void) fprintf(stderr, "\n"); 756 if (compile_time != 2 && NR && *NR > 0) { 757 (void) fprintf(stderr, 758 gettext(" input record number %g"), *FNR); 759 if (strcmp(*FILENAME, "-") != 0) 760 (void) fprintf(stderr, gettext(", file %s"), *FILENAME); 761 (void) fprintf(stderr, "\n"); 762 } 763 if (compile_time != 2 && curnode) 764 (void) fprintf(stderr, gettext(" source line number %lld"), 765 curnode->lineno); 766 else if (compile_time != 2 && lineno) { 767 (void) fprintf(stderr, 768 gettext(" source line number %lld"), lineno); 769 } 770 if (compile_time == 1 && cursource() != NULL) 771 (void) fprintf(stderr, gettext(" source file %s"), cursource()); 772 (void) fprintf(stderr, "\n"); 773 eprint(); 774 } 775 776 static void 777 eprint(void) /* try to print context around error */ 778 { 779 char *p, *q; 780 int c; 781 static int been_here = 0; 782 extern char ebuf[], *ep; 783 784 if (compile_time == 2 || compile_time == 0 || been_here++ > 0) 785 return; 786 if (ebuf == ep) 787 return; 788 p = ep - 1; 789 if (p > ebuf && *p == '\n') 790 p--; 791 for (; p > ebuf && *p != '\n' && *p != '\0'; p--) 792 ; 793 while (*p == '\n') 794 p++; 795 (void) fprintf(stderr, gettext(" context is\n\t")); 796 for (q = ep-1; q >= p && *q != ' ' && *q != '\t' && *q != '\n'; q--) 797 ; 798 for (; p < q; p++) 799 if (*p) 800 (void) putc(*p, stderr); 801 (void) fprintf(stderr, " >>> "); 802 for (; p < ep; p++) 803 if (*p) 804 (void) putc(*p, stderr); 805 (void) fprintf(stderr, " <<< "); 806 if (*ep) 807 while ((c = input()) != '\n' && c != '\0' && c != EOF) { 808 (void) putc(c, stderr); 809 bclass(c); 810 } 811 (void) putc('\n', stderr); 812 ep = ebuf; 813 } 814 815 static void 816 bclass(int c) 817 { 818 switch (c) { 819 case '{': bracecnt++; break; 820 case '}': bracecnt--; break; 821 case '[': brackcnt++; break; 822 case ']': brackcnt--; break; 823 case '(': parencnt++; break; 824 case ')': parencnt--; break; 825 } 826 } 827 828 double 829 errcheck(double x, const char *s) 830 { 831 if (errno == EDOM) { 832 errno = 0; 833 WARNING("%s argument out of domain", s); 834 x = 1; 835 } else if (errno == ERANGE) { 836 errno = 0; 837 WARNING("%s result out of range", s); 838 x = 1; 839 } 840 return (x); 841 } 842 843 int 844 isclvar(const char *s) /* is s of form var=something ? */ 845 { 846 if (s != NULL) { 847 848 /* Must begin with an underscore or alphabetic character */ 849 if (isalpha(*s) || (*s == '_')) { 850 851 for (s++; *s; s++) { 852 /* 853 * followed by a sequence of underscores, 854 * digits, and alphabetics 855 */ 856 if (!(isalnum(*s) || *s == '_')) { 857 break; 858 } 859 } 860 return (*s == '=' && *(s + 1) != '='); 861 } 862 } 863 864 return (0); 865 } 866 867 #include <math.h> 868 int 869 is_number(const char *s) 870 { 871 double r; 872 char *ep; 873 errno = 0; 874 r = strtod(s, &ep); 875 if (ep == s || r == HUGE_VAL || errno == ERANGE) 876 return (0); 877 while (*ep == ' ' || *ep == '\t' || *ep == '\n') 878 ep++; 879 if (*ep == '\0') 880 return (1); 881 else 882 return (0); 883 } 884 885 void 886 r_expand_buf(char **optr, size_t *sizep, size_t req) 887 { 888 char *nptr; 889 size_t amt, size = *sizep; 890 891 if (size != 0 && req < (size - 1)) 892 return; 893 amt = req + 1 - size; 894 amt = (amt / LINE_INCR + 1) * LINE_INCR; 895 896 if ((nptr = realloc(*optr, size + amt)) == NULL) 897 FATAL("out of space in expand_buf"); 898 /* initial buffer should have NULL terminated */ 899 if (size == 0) 900 *nptr = '\0'; 901 *sizep += amt; 902 *optr = nptr; 903 } 904