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