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