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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (C) Lucent Technologies 1997 29 * All Rights Reserved 30 * 31 * Permission to use, copy, modify, and distribute this software and 32 * its documentation for any purpose and without fee is hereby 33 * granted, provided that the above copyright notice appear in all 34 * copies and that both that the copyright notice and this 35 * permission notice and warranty disclaimer appear in supporting 36 * documentation, and that the name Lucent Technologies or any of 37 * its entities not be used in advertising or publicity pertaining 38 * to distribution of the software without specific, written prior 39 * permission. 40 * 41 * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 42 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 43 * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 44 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 45 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 46 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 47 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 48 * THIS SOFTWARE. 49 */ 50 51 #include <errno.h> 52 #include <stdarg.h> 53 #include <math.h> 54 #include "awk.h" 55 #include "y.tab.h" 56 57 uchar *record; 58 size_t record_size = RECSIZE; 59 60 Cell **fldtab; /* pointers to Cells */ 61 char inputFS[100] = " "; 62 63 #define MAXFLD 2 64 int nfields = MAXFLD; /* last allocated slot for $i */ 65 66 int donefld; /* 1 = implies rec broken into fields */ 67 int donerec; /* 1 = record is valid (no flds have changed) */ 68 69 int lastfld = 0; /* last used field */ 70 71 static FILE *infile = NULL; 72 static uchar *file = (uchar*) ""; 73 static uchar *fields; 74 static size_t fields_size = RECSIZE; 75 76 static int argno = 1; /* current input argument number */ 77 78 static uchar *getargv(int); 79 static void cleanfld(int, int); 80 static int refldbld(uchar *, uchar *); 81 static void bcheck2(int, int, int); 82 static void eprint(void); 83 static void bclass(int); 84 static void makefields(int, int); 85 86 87 static Cell dollar0 = { OCELL, CFLD, NULL, (uchar *)"", 0.0, REC|STR|DONTFREE }; 88 static Cell dollar1 = { OCELL, CFLD, NULL, (uchar *)"", 0.0, FLD|STR|DONTFREE }; 89 90 void 91 recinit(unsigned int n) 92 { 93 if ((record = (uchar *)malloc(n)) == NULL || 94 (fields = (uchar *)malloc(n+1)) == NULL || 95 (fldtab = (Cell **)malloc((nfields + 1) * 96 sizeof (Cell *))) == NULL || 97 (fldtab[0] = (Cell *)malloc(sizeof (Cell))) == NULL) 98 FATAL("out of space for $0 and fields"); 99 *fldtab[0] = dollar0; 100 fldtab[0]->sval = record; 101 fldtab[0]->nval = tostring((uchar *)"0"); 102 makefields(1, nfields); 103 } 104 105 static void 106 makefields(int n1, int n2) /* create $n1..$n2 inclusive */ 107 { 108 char temp[50]; 109 int i; 110 111 for (i = n1; i <= n2; i++) { 112 fldtab[i] = (Cell *)malloc(sizeof (struct Cell)); 113 if (fldtab[i] == NULL) 114 FATAL("out of space in makefields %d", i); 115 *fldtab[i] = dollar1; 116 (void) sprintf(temp, "%d", i); 117 fldtab[i]->nval = tostring((uchar *)temp); 118 } 119 } 120 121 static void 122 initgetrec(void) 123 { 124 int i; 125 uchar *p; 126 127 for (i = 1; i < *ARGC; i++) { 128 p = getargv(i); /* find 1st real filename */ 129 if (p == NULL || *p == '\0') { /* deleted or zapped */ 130 argno++; 131 continue; 132 } 133 if (!isclvar(p)) { 134 (void) setsval(lookup((uchar *)"FILENAME", symtab), p); 135 return; 136 } 137 setclvar(p); /* a commandline assignment before filename */ 138 argno++; 139 } 140 infile = stdin; /* no filenames, so use stdin */ 141 } 142 143 static int firsttime = 1; 144 145 int 146 getrec(uchar **pbuf, size_t *pbufsize, int isrecord) 147 { /* get next input record */ 148 /* note: cares whether buf == record */ 149 int c; 150 uchar_t *buf = *pbuf; 151 uchar saveb0; 152 size_t bufsize = *pbufsize, savebufsize = bufsize; 153 154 if (firsttime) { 155 firsttime = 0; 156 initgetrec(); 157 } 158 dprintf(("RS=<%s>, FS=<%s>, ARGC=%f, FILENAME=%s\n", 159 *RS, *FS, *ARGC, *FILENAME)); 160 if (isrecord) { 161 donefld = 0; 162 donerec = 1; 163 } 164 saveb0 = buf[0]; 165 buf[0] = 0; 166 while (argno < *ARGC || infile == stdin) { 167 dprintf(("argno=%d, file=|%s|\n", argno, file)); 168 if (infile == NULL) { /* have to open a new file */ 169 file = getargv(argno); 170 /* deleted or zapped */ 171 if (file == NULL || *file == '\0') { 172 argno++; 173 continue; 174 } 175 if (isclvar(file)) { /* a var=value arg */ 176 setclvar(file); 177 argno++; 178 continue; 179 } 180 *FILENAME = file; 181 dprintf(("opening file %s\n", file)); 182 if (*file == '-' && *(file+1) == '\0') 183 infile = stdin; 184 else if ((infile = fopen((char *)file, "r")) == NULL) 185 FATAL("can't open file %s", file); 186 (void) setfval(fnrloc, 0.0); 187 } 188 c = readrec(&buf, &bufsize, infile); 189 if (c != 0 || buf[0] != '\0') { /* normal record */ 190 if (isrecord) { 191 if (freeable(fldtab[0])) 192 xfree(fldtab[0]->sval); 193 fldtab[0]->sval = buf; /* buf == record */ 194 fldtab[0]->tval = REC | STR | DONTFREE; 195 if (is_number(fldtab[0]->sval)) { 196 fldtab[0]->fval = 197 atof((const char *)fldtab[0]->sval); 198 fldtab[0]->tval |= NUM; 199 } 200 } 201 (void) setfval(nrloc, nrloc->fval+1); 202 (void) setfval(fnrloc, fnrloc->fval+1); 203 *pbuf = buf; 204 *pbufsize = bufsize; 205 return (1); 206 } 207 /* EOF arrived on this file; set up next */ 208 if (infile != stdin) 209 (void) fclose(infile); 210 infile = NULL; 211 argno++; 212 } 213 buf[0] = saveb0; 214 *pbuf = buf; 215 *pbufsize = savebufsize; 216 return (0); /* true end of file */ 217 } 218 219 void 220 nextfile(void) 221 { 222 if (infile != NULL && infile != stdin) 223 (void) fclose(infile); 224 infile = NULL; 225 argno++; 226 } 227 228 /* 229 * read one record into buf 230 */ 231 int 232 readrec(uchar **pbuf, size_t *pbufsize, FILE *inf) 233 { 234 int sep, c; 235 uchar *rr, *buf = *pbuf; 236 size_t bufsize = *pbufsize; 237 238 if (strlen((char *)*FS) >= sizeof (inputFS)) 239 FATAL("field separator %.10s... is too long", *FS); 240 /* 241 * fflush(stdout); avoids some buffering problem 242 * but makes it 25% slower 243 */ 244 245 /* for subsequent field splitting */ 246 (void) strcpy(inputFS, (char *)*FS); 247 if ((sep = **RS) == 0) { 248 sep = '\n'; 249 /* skip leading \n's */ 250 while ((c = getc(inf)) == '\n' && c != EOF) 251 ; 252 if (c != EOF) 253 (void) ungetc(c, inf); 254 } 255 for (rr = buf; ; ) { 256 for (; (c = getc(inf)) != sep && c != EOF; ) { 257 if (rr-buf+1 > bufsize) 258 if (!adjbuf(&buf, &bufsize, 1+rr-buf, 259 record_size, &rr, "readrec 1")) 260 FATAL( 261 "input record `%.30s...' too long", buf); 262 *rr++ = c; 263 } 264 if (**RS == sep || c == EOF) 265 break; 266 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */ 267 break; 268 if (!adjbuf(&buf, &bufsize, 2+rr-buf, record_size, &rr, 269 "readrec 2")) 270 FATAL("input record `%.30s...' too long", buf); 271 *rr++ = '\n'; 272 *rr++ = c; 273 } 274 if (!adjbuf(&buf, &bufsize, 1+rr-buf, record_size, &rr, "readrec 3")) 275 FATAL("input record `%.30s...' too long", buf); 276 *rr = 0; 277 dprintf(("readrec saw <%s>, returns %d\n", 278 buf, c == EOF && rr == buf ? 0 : 1)); 279 *pbuf = buf; 280 *pbufsize = bufsize; 281 return (c == EOF && rr == buf ? 0 : 1); 282 } 283 284 static uchar * 285 getargv(int n) /* get ARGV[n] */ 286 { 287 Cell *x; 288 uchar *s, temp[50]; 289 extern Array *ARGVtab; 290 291 (void) sprintf((char *)temp, "%d", n); 292 if (lookup(temp, ARGVtab) == NULL) 293 return (NULL); 294 x = setsymtab(temp, (uchar *)"", 0.0, STR, ARGVtab); 295 s = getsval(x); 296 dprintf(("getargv(%d) returns |%s|\n", n, s)); 297 return (s); 298 } 299 300 void 301 setclvar(uchar *s) /* set var=value from s */ 302 { 303 uchar *p; 304 Cell *q; 305 306 for (p = s; *p != '='; p++) 307 ; 308 *p++ = 0; 309 p = qstring(p, '\0'); 310 q = setsymtab(s, p, 0.0, STR, symtab); 311 (void) setsval(q, p); 312 if (is_number(q->sval)) { 313 q->fval = atof((const char *)q->sval); 314 q->tval |= NUM; 315 } 316 dprintf(("command line set %s to |%s|\n", s, p)); 317 } 318 319 void 320 fldbld(void) /* create fields from current record */ 321 { 322 /* this relies on having fields[] the same length as $0 */ 323 /* the fields are all stored in this one array with \0's */ 324 /* possibly with a final trailing \0 not associated with any field */ 325 uchar *r, *fr, sep; 326 Cell *p; 327 int i, j; 328 size_t n; 329 330 if (donefld) 331 return; 332 if (!isstr(fldtab[0])) 333 (void) getsval(fldtab[0]); 334 r = fldtab[0]->sval; 335 n = strlen((char *)r); 336 if (n > fields_size) { 337 xfree(fields); 338 /* possibly 2 final \0s */ 339 if ((fields = (uchar *)malloc(n + 2)) == NULL) 340 FATAL("out of space for fields in fldbld %d", n); 341 fields_size = n; 342 } 343 fr = fields; 344 i = 0; /* number of fields accumulated here */ 345 (void) strcpy(inputFS, (char *)*FS); 346 if (strlen(inputFS) > 1) { /* it's a regular expression */ 347 i = refldbld(r, (uchar *)inputFS); 348 } else if ((sep = *inputFS) == ' ') { /* default whitespace */ 349 for (i = 0; ; ) { 350 while (*r == ' ' || *r == '\t' || *r == '\n') 351 r++; 352 if (*r == 0) 353 break; 354 i++; 355 if (i > nfields) 356 growfldtab(i); 357 if (freeable(fldtab[i])) 358 xfree(fldtab[i]->sval); 359 fldtab[i]->sval = fr; 360 fldtab[i]->tval = FLD | STR | DONTFREE; 361 do 362 *fr++ = *r++; 363 while (*r != ' ' && *r != '\t' && *r != '\n' && 364 *r != '\0') 365 ; 366 *fr++ = 0; 367 } 368 *fr = 0; 369 } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */ 370 for (i = 0; *r != 0; r++) { 371 uchar buf[2]; 372 i++; 373 if (i > nfields) 374 growfldtab(i); 375 if (freeable(fldtab[i])) 376 xfree(fldtab[i]->sval); 377 buf[0] = *r; 378 buf[1] = 0; 379 fldtab[i]->sval = tostring(buf); 380 fldtab[i]->tval = FLD | STR; 381 } 382 *fr = 0; 383 } else if (*r != 0) { /* if 0, it's a null field */ 384 /* 385 * subtlecase : if length(FS) == 1 && length(RS > 0) 386 * \n is NOT a field separator (cf awk book 61,84). 387 * this variable is tested in the inner while loop. 388 */ 389 int rtest = '\n'; /* normal case */ 390 if (strlen((char *)*RS) > 0) 391 rtest = '\0'; 392 for (;;) { 393 i++; 394 if (i > nfields) 395 growfldtab(i); 396 if (freeable(fldtab[i])) 397 xfree(fldtab[i]->sval); 398 fldtab[i]->sval = fr; 399 fldtab[i]->tval = FLD | STR | DONTFREE; 400 /* \n is always a separator */ 401 while (*r != sep && *r != rtest && *r != '\0') 402 *fr++ = *r++; 403 *fr++ = 0; 404 if (*r++ == 0) 405 break; 406 } 407 *fr = 0; 408 } 409 if (i > nfields) 410 FATAL("record `%.30s...' has too many fields; can't happen", r); 411 /* clean out junk from previous record */ 412 cleanfld(i + 1, lastfld); 413 lastfld = i; 414 donefld = 1; 415 for (j = 1; j <= lastfld; j++) { 416 p = fldtab[j]; 417 if (is_number(p->sval)) { 418 p->fval = atof((const char *)p->sval); 419 p->tval |= NUM; 420 } 421 } 422 (void) setfval(nfloc, (Awkfloat)lastfld); 423 if (dbg) { 424 for (j = 0; j <= lastfld; j++) { 425 p = fldtab[j]; 426 (void) printf("field %d (%s): |%s|\n", j, p->nval, 427 p->sval); 428 } 429 } 430 } 431 432 static void 433 cleanfld(int n1, int n2) /* clean out fields n1..n2 inclusive */ 434 { /* nvals remain intact */ 435 static uchar *nullstat = (uchar *)""; 436 Cell *p; 437 int i; 438 439 for (i = n1; i <= n2; i++) { 440 p = fldtab[i]; 441 if (freeable(p)) 442 xfree(p->sval); 443 p->sval = nullstat; 444 p->tval = FLD | STR | DONTFREE; 445 } 446 } 447 448 void 449 newfld(int n) /* add field n after end of existing lastfld */ 450 { 451 if (n > nfields) 452 growfldtab(n); 453 cleanfld(lastfld + 1, n); 454 lastfld = n; 455 (void) setfval(nfloc, (Awkfloat)n); 456 } 457 458 Cell * 459 fieldadr(int n) /* get nth field */ 460 { 461 if (n < 0) 462 FATAL("trying to access out of range field %d", n); 463 if (n > nfields) /* fields after NF are empty */ 464 growfldtab(n); /* but does not increase NF */ 465 return (fldtab[n]); 466 } 467 468 void 469 growfldtab(int n) /* make new fields up to at least $n */ 470 { 471 int nf = 2 * nfields; 472 size_t s; 473 474 if (n > nf) 475 nf = n; 476 /* freebsd: how much do we need? */ 477 s = (nf + 1) * (sizeof (struct Cell *)); 478 if (s / sizeof (struct Cell *) - 1 == nf) /* didn't overflow */ 479 fldtab = (Cell **) realloc(fldtab, s); 480 else /* overflow sizeof int */ 481 xfree(fldtab); /* make it null */ 482 if (fldtab == NULL) 483 FATAL("out of space creating %d fields", nf); 484 makefields(nfields + 1, nf); 485 nfields = nf; 486 } 487 488 static int 489 refldbld(uchar *rec, uchar *fs) /* build fields from reg expr in FS */ 490 { 491 /* this relies on having fields[] the same length as $0 */ 492 /* the fields are all stored in this one array with \0's */ 493 uchar *fr; 494 int i, tempstat; 495 fa *pfa; 496 size_t n; 497 498 n = strlen((char *)rec); 499 if (n > fields_size) { 500 xfree(fields); 501 if ((fields = (uchar *)malloc(n + 1)) == NULL) 502 FATAL("out of space for fields in refldbld %d", n); 503 fields_size = n; 504 } 505 fr = fields; 506 *fr = '\0'; 507 if (*rec == '\0') 508 return (0); 509 pfa = makedfa(fs, 1); 510 dprintf(("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs)); 511 tempstat = pfa->initstat; 512 for (i = 1; ; i++) { 513 if (i > nfields) 514 growfldtab(i); 515 if (freeable(fldtab[i])) 516 xfree(fldtab[i]->sval); 517 fldtab[i]->tval = FLD | STR | DONTFREE; 518 fldtab[i]->sval = fr; 519 dprintf(("refldbld: i=%d\n", i)); 520 if (nematch(pfa, rec)) { 521 pfa->initstat = 2; /* horrible coupling to b.c */ 522 dprintf(("match %s (%d chars)\n", patbeg, patlen)); 523 (void) strncpy((char *)fr, (char *)rec, patbeg-rec); 524 fr += patbeg - rec + 1; 525 *(fr-1) = '\0'; 526 rec = patbeg + patlen; 527 } else { 528 dprintf(("no match %s\n", rec)); 529 (void) strcpy((char *)fr, (char *)rec); 530 pfa->initstat = tempstat; 531 break; 532 } 533 } 534 return (i); 535 } 536 537 void 538 recbld(void) /* create $0 from $1..$NF if necessary */ 539 { 540 int i; 541 uchar *r, *p; 542 543 if (donerec == 1) 544 return; 545 r = record; 546 for (i = 1; i <= *NF; i++) { 547 p = getsval(fldtab[i]); 548 if (!adjbuf(&record, &record_size, 1 + strlen((char *)p) + r - 549 record, record_size, &r, "recbld 1")) 550 FATAL("created $0 `%.30s...' too long", record); 551 while ((*r = *p++) != 0) 552 r++; 553 if (i < *NF) { 554 if (!adjbuf(&record, &record_size, 2 + 555 strlen((char *)*OFS) + r - record, record_size, 556 &r, "recbld 2")) 557 FATAL("created $0 `%.30s...' too long", record); 558 for (p = *OFS; (*r = *p++) != 0; ) 559 r++; 560 } 561 } 562 if (!adjbuf(&record, &record_size, 2 + r - record, record_size, &r, 563 "recbld 3")) 564 FATAL("built giant record `%.30s...'", record); 565 *r = '\0'; 566 dprintf(("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, 567 (void *)fldtab[0])); 568 569 if (freeable(fldtab[0])) 570 xfree(fldtab[0]->sval); 571 fldtab[0]->tval = REC | STR | DONTFREE; 572 fldtab[0]->sval = record; 573 574 dprintf(("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, 575 (void *)fldtab[0])); 576 dprintf(("recbld = |%s|\n", record)); 577 donerec = 1; 578 } 579 580 int errorflag = 0; 581 582 void 583 yyerror(char *s) 584 { 585 SYNTAX("%s", s); 586 } 587 588 void 589 SYNTAX(const char *fmt, ...) 590 { 591 extern uchar *cmdname, *curfname; 592 static int been_here = 0; 593 va_list varg; 594 595 if (been_here++ > 2) 596 return; 597 (void) fprintf(stderr, "%s: ", cmdname); 598 va_start(varg, fmt); 599 (void) vfprintf(stderr, fmt, varg); 600 va_end(varg); 601 (void) fprintf(stderr, gettext(" at source line %lld"), lineno); 602 if (curfname != NULL) 603 (void) fprintf(stderr, gettext(" in function %s"), curfname); 604 if (compile_time == 1 && cursource() != NULL) 605 (void) fprintf(stderr, gettext(" source file %s"), cursource()); 606 (void) fprintf(stderr, "\n"); 607 errorflag = 2; 608 eprint(); 609 } 610 611 void 612 fpecatch(int n) 613 { 614 FATAL("floating point exception %d", n); 615 } 616 617 extern int bracecnt, brackcnt, parencnt; 618 619 void 620 bracecheck(void) 621 { 622 int c; 623 static int beenhere = 0; 624 625 if (beenhere++) 626 return; 627 while ((c = input()) != EOF && c != '\0') 628 bclass(c); 629 bcheck2(bracecnt, '{', '}'); 630 bcheck2(brackcnt, '[', ']'); 631 bcheck2(parencnt, '(', ')'); 632 } 633 634 /*ARGSUSED*/ 635 static void 636 bcheck2(int n, int c1, int c2) 637 { 638 if (n == 1) 639 (void) fprintf(stderr, gettext("\tmissing %c\n"), c2); 640 else if (n > 1) 641 (void) fprintf(stderr, gettext("\t%d missing %c's\n"), n, c2); 642 else if (n == -1) 643 (void) fprintf(stderr, gettext("\textra %c\n"), c2); 644 else if (n < -1) 645 (void) fprintf(stderr, gettext("\t%d extra %c's\n"), -n, c2); 646 } 647 648 void 649 FATAL(const char *fmt, ...) 650 { 651 extern uchar *cmdname; 652 va_list varg; 653 654 (void) fflush(stdout); 655 (void) fprintf(stderr, "%s: ", cmdname); 656 va_start(varg, fmt); 657 (void) vfprintf(stderr, fmt, varg); 658 va_end(varg); 659 error(); 660 if (dbg > 1) /* core dump if serious debugging on */ 661 abort(); 662 exit(2); 663 } 664 665 void 666 WARNING(const char *fmt, ...) 667 { 668 extern uchar *cmdname; 669 va_list varg; 670 671 (void) fflush(stdout); 672 (void) fprintf(stderr, "%s: ", cmdname); 673 va_start(varg, fmt); 674 (void) vfprintf(stderr, fmt, varg); 675 va_end(varg); 676 error(); 677 } 678 679 void 680 error(void) 681 { 682 extern Node *curnode; 683 684 (void) fprintf(stderr, "\n"); 685 if (compile_time != 2 && NR && *NR > 0) { 686 (void) fprintf(stderr, 687 gettext(" input record number %g"), (int) (*FNR)); 688 if (strcmp((char *)*FILENAME, "-") != 0) 689 (void) fprintf(stderr, gettext(", file %s"), *FILENAME); 690 (void) fprintf(stderr, "\n"); 691 } 692 if (compile_time != 2 && curnode) 693 (void) fprintf(stderr, gettext(" source line number %d"), 694 curnode->lineno); 695 else if (compile_time != 2 && lineno) { 696 (void) fprintf(stderr, 697 gettext(" source line number %d"), lineno); 698 } 699 if (compile_time == 1 && cursource() != NULL) 700 (void) fprintf(stderr, 701 gettext(" source file %s"), cursource()); 702 (void) fprintf(stderr, "\n"); 703 eprint(); 704 } 705 706 static void 707 eprint(void) /* try to print context around error */ 708 { 709 uchar *p, *q; 710 int c; 711 static int been_here = 0; 712 extern uchar ebuf[], *ep; 713 714 if (compile_time == 2 || compile_time == 0 || been_here++ > 0) 715 return; 716 p = ep - 1; 717 if (p > ebuf && *p == '\n') 718 p--; 719 for (; p > ebuf && *p != '\n' && *p != '\0'; p--) 720 ; 721 while (*p == '\n') 722 p++; 723 (void) fprintf(stderr, gettext(" context is\n\t")); 724 for (q = ep-1; q >= p && *q != ' ' && *q != '\t' && *q != '\n'; q--) 725 ; 726 for (; p < q; p++) 727 if (*p) 728 (void) putc(*p, stderr); 729 (void) fprintf(stderr, " >>> "); 730 for (; p < ep; p++) 731 if (*p) 732 (void) putc(*p, stderr); 733 (void) fprintf(stderr, " <<< "); 734 if (*ep) 735 while ((c = input()) != '\n' && c != '\0' && c != EOF) { 736 (void) putc(c, stderr); 737 bclass(c); 738 } 739 (void) putc('\n', stderr); 740 ep = ebuf; 741 } 742 743 static void 744 bclass(int c) 745 { 746 switch (c) { 747 case '{': bracecnt++; break; 748 case '}': bracecnt--; break; 749 case '[': brackcnt++; break; 750 case ']': brackcnt--; break; 751 case '(': parencnt++; break; 752 case ')': parencnt--; break; 753 } 754 } 755 756 double 757 errcheck(double x, const char *s) 758 { 759 if (errno == EDOM) { 760 errno = 0; 761 WARNING("%s argument out of domain", s); 762 x = 1; 763 } else if (errno == ERANGE) { 764 errno = 0; 765 WARNING("%s result out of range", s); 766 x = 1; 767 } 768 return (x); 769 } 770 771 int 772 isclvar(const uchar *s) /* is s of form var=something? */ 773 { 774 const uchar *os = s; 775 776 if (!isalpha(*s) && *s != '_') 777 return (0); 778 for (; *s; s++) { 779 if (!(isalnum(*s) || *s == '_')) 780 break; 781 } 782 783 return (*s == '=' && s > os && *(s+1) != '='); 784 } 785 786 /* strtod is supposed to be a proper test of what's a valid number */ 787 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */ 788 /* wrong: violates 4.10.1.4 of ansi C standard */ 789 790 int 791 is_number(const uchar *s) 792 { 793 double r; 794 char *ep; 795 errno = 0; 796 r = strtod((const char *)s, &ep); 797 if (ep == (char *)s || r == HUGE_VAL || errno == ERANGE) 798 return (0); 799 while (*ep == ' ' || *ep == '\t' || *ep == '\n') 800 ep++; 801 if (*ep == '\0') 802 return (1); 803 else 804 return (0); 805 }