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