1 /* $OpenBSD: lib.c,v 1.25 2017/12/08 17:04:15 deraadt 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 *record = '\0'; 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 536 dprintf(STDERR_FILENO, "floating point exception\n"); 537 538 if (compile_time != 2 && NR && *NR > 0) { 539 dprintf(STDERR_FILENO, " input record number %d", (int) (*FNR)); 540 if (strcmp(*FILENAME, "-") != 0) { 541 dprintf(STDERR_FILENO, ", file %s", *FILENAME); 542 } 543 dprintf(STDERR_FILENO, "\n"); 544 } 545 if (compile_time != 2 && curnode) { 546 dprintf(STDERR_FILENO, " source line number %d", curnode->lineno); 547 } else if (compile_time != 2 && lineno) { 548 dprintf(STDERR_FILENO, " source line number %d", lineno); 549 } 550 if (compile_time == 1 && cursource() != NULL) { 551 dprintf(STDERR_FILENO, " source file %s", cursource()); 552 } 553 dprintf(STDERR_FILENO, "\n"); 554 if (dbg > 1) /* core dump if serious debugging on */ 555 abort(); 556 _exit(1); 557 } 558 559 extern int bracecnt, brackcnt, parencnt; 560 561 void bracecheck(void) 562 { 563 int c; 564 static int beenhere = 0; 565 566 if (beenhere++) 567 return; 568 while ((c = input()) != EOF && c != '\0') 569 bclass(c); 570 bcheck2(bracecnt, '{', '}'); 571 bcheck2(brackcnt, '[', ']'); 572 bcheck2(parencnt, '(', ')'); 573 } 574 575 void bcheck2(int n, int c1, int c2) 576 { 577 if (n == 1) 578 fprintf(stderr, "\tmissing %c\n", c2); 579 else if (n > 1) 580 fprintf(stderr, "\t%d missing %c's\n", n, c2); 581 else if (n == -1) 582 fprintf(stderr, "\textra %c\n", c2); 583 else if (n < -1) 584 fprintf(stderr, "\t%d extra %c's\n", -n, c2); 585 } 586 587 __dead void FATAL(const char *fmt, ...) 588 { 589 extern char *cmdname; 590 va_list varg; 591 592 fflush(stdout); 593 fprintf(stderr, "%s: ", cmdname); 594 va_start(varg, fmt); 595 vfprintf(stderr, fmt, varg); 596 va_end(varg); 597 error(); 598 if (dbg > 1) /* core dump if serious debugging on */ 599 abort(); 600 exit(2); 601 } 602 603 void WARNING(const char *fmt, ...) 604 { 605 extern char *cmdname; 606 va_list varg; 607 608 fflush(stdout); 609 fprintf(stderr, "%s: ", cmdname); 610 va_start(varg, fmt); 611 vfprintf(stderr, fmt, varg); 612 va_end(varg); 613 error(); 614 } 615 616 void error() 617 { 618 extern Node *curnode; 619 620 fprintf(stderr, "\n"); 621 if (compile_time != 2 && NR && *NR > 0) { 622 fprintf(stderr, " input record number %d", (int) (*FNR)); 623 if (strcmp(*FILENAME, "-") != 0) 624 fprintf(stderr, ", file %s", *FILENAME); 625 fprintf(stderr, "\n"); 626 } 627 if (compile_time != 2 && curnode) 628 fprintf(stderr, " source line number %d", curnode->lineno); 629 else if (compile_time != 2 && lineno) 630 fprintf(stderr, " source line number %d", lineno); 631 if (compile_time == 1 && cursource() != NULL) 632 fprintf(stderr, " source file %s", cursource()); 633 fprintf(stderr, "\n"); 634 eprint(); 635 } 636 637 void eprint(void) /* try to print context around error */ 638 { 639 char *p, *q; 640 int c; 641 static int been_here = 0; 642 extern char ebuf[], *ep; 643 644 if (compile_time == 2 || compile_time == 0 || been_here++ > 0 || 645 ebuf == ep) 646 return; 647 p = ep - 1; 648 if (p > ebuf && *p == '\n') 649 p--; 650 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--) 651 ; 652 while (*p == '\n') 653 p++; 654 fprintf(stderr, " context is\n\t"); 655 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) 656 ; 657 for ( ; p < q; p++) 658 if (*p) 659 putc(*p, stderr); 660 fprintf(stderr, " >>> "); 661 for ( ; p < ep; p++) 662 if (*p) 663 putc(*p, stderr); 664 fprintf(stderr, " <<< "); 665 if (*ep) 666 while ((c = input()) != '\n' && c != '\0' && c != EOF) { 667 putc(c, stderr); 668 bclass(c); 669 } 670 putc('\n', stderr); 671 ep = ebuf; 672 } 673 674 void bclass(int c) 675 { 676 switch (c) { 677 case '{': bracecnt++; break; 678 case '}': bracecnt--; break; 679 case '[': brackcnt++; break; 680 case ']': brackcnt--; break; 681 case '(': parencnt++; break; 682 case ')': parencnt--; break; 683 } 684 } 685 686 double errcheck(double x, const char *s) 687 { 688 689 if (errno == EDOM) { 690 errno = 0; 691 WARNING("%s argument out of domain", s); 692 x = 1; 693 } else if (errno == ERANGE) { 694 errno = 0; 695 WARNING("%s result out of range", s); 696 x = 1; 697 } 698 return x; 699 } 700 701 int isclvar(const char *s) /* is s of form var=something ? */ 702 { 703 const char *os = s; 704 705 if (!isalpha((uschar) *s) && *s != '_') 706 return 0; 707 for ( ; *s; s++) 708 if (!(isalnum((uschar) *s) || *s == '_')) 709 break; 710 return *s == '=' && s > os && *(s+1) != '='; 711 } 712 713 /* strtod is supposed to be a proper test of what's a valid number */ 714 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */ 715 /* wrong: violates 4.10.1.4 of ansi C standard */ 716 717 #include <math.h> 718 int is_number(const char *s) 719 { 720 double r; 721 char *ep; 722 errno = 0; 723 r = strtod(s, &ep); 724 if (ep == s || r == HUGE_VAL || errno == ERANGE) 725 return 0; 726 while (*ep == ' ' || *ep == '\t' || *ep == '\n') 727 ep++; 728 if (*ep == '\0') 729 return 1; 730 else 731 return 0; 732 } 733