14b588458SPeter Avalos /**************************************************************** 24b588458SPeter Avalos Copyright (C) Lucent Technologies 1997 34b588458SPeter Avalos All Rights Reserved 44b588458SPeter Avalos 54b588458SPeter Avalos Permission to use, copy, modify, and distribute this software and 64b588458SPeter Avalos its documentation for any purpose and without fee is hereby 74b588458SPeter Avalos granted, provided that the above copyright notice appear in all 84b588458SPeter Avalos copies and that both that the copyright notice and this 94b588458SPeter Avalos permission notice and warranty disclaimer appear in supporting 104b588458SPeter Avalos documentation, and that the name Lucent Technologies or any of 114b588458SPeter Avalos its entities not be used in advertising or publicity pertaining 124b588458SPeter Avalos to distribution of the software without specific, written prior 134b588458SPeter Avalos permission. 144b588458SPeter Avalos 154b588458SPeter Avalos LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 164b588458SPeter Avalos INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 174b588458SPeter Avalos IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 184b588458SPeter Avalos SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 194b588458SPeter Avalos WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 204b588458SPeter Avalos IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 214b588458SPeter Avalos ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 224b588458SPeter Avalos THIS SOFTWARE. 234b588458SPeter Avalos ****************************************************************/ 244b588458SPeter Avalos 254b588458SPeter Avalos #define DEBUG 264b588458SPeter Avalos #include <stdio.h> 274b588458SPeter Avalos #include <string.h> 28*48f09a05SAntonio Huete Jimenez #include <strings.h> 294b588458SPeter Avalos #include <ctype.h> 304b588458SPeter Avalos #include <errno.h> 314b588458SPeter Avalos #include <stdlib.h> 324b588458SPeter Avalos #include <stdarg.h> 331d48fce0SDaniel Fojt #include <limits.h> 34*48f09a05SAntonio Huete Jimenez #include <math.h> 354b588458SPeter Avalos #include "awk.h" 364b588458SPeter Avalos 371d48fce0SDaniel Fojt char EMPTY[] = { '\0' }; 384b588458SPeter Avalos FILE *infile = NULL; 391d48fce0SDaniel Fojt bool innew; /* true = infile has not been read by readrec */ 401d48fce0SDaniel Fojt char *file = EMPTY; 414b588458SPeter Avalos char *record; 424b588458SPeter Avalos int recsize = RECSIZE; 434b588458SPeter Avalos char *fields; 444b588458SPeter Avalos int fieldssize = RECSIZE; 454b588458SPeter Avalos 464b588458SPeter Avalos Cell **fldtab; /* pointers to Cells */ 471d48fce0SDaniel Fojt static size_t len_inputFS = 0; 481d48fce0SDaniel Fojt static char *inputFS = NULL; /* FS at time of input, for field splitting */ 494b588458SPeter Avalos 504b588458SPeter Avalos #define MAXFLD 2 514b588458SPeter Avalos int nfields = MAXFLD; /* last allocated slot for $i */ 524b588458SPeter Avalos 531d48fce0SDaniel Fojt bool donefld; /* true = implies rec broken into fields */ 541d48fce0SDaniel Fojt bool donerec; /* true = record is valid (no flds have changed) */ 554b588458SPeter Avalos 564b588458SPeter Avalos int lastfld = 0; /* last used field */ 574b588458SPeter Avalos int argno = 1; /* current input argument number */ 584b588458SPeter Avalos extern Awkfloat *ARGC; 594b588458SPeter Avalos 601d48fce0SDaniel Fojt static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL, NULL }; 611d48fce0SDaniel Fojt static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL, NULL }; 624b588458SPeter Avalos 634b588458SPeter Avalos void recinit(unsigned int n) 644b588458SPeter Avalos { 65*48f09a05SAntonio Huete Jimenez if ( (record = (char *) malloc(n)) == NULL 66*48f09a05SAntonio Huete Jimenez || (fields = (char *) malloc(n+1)) == NULL 67*48f09a05SAntonio Huete Jimenez || (fldtab = (Cell **) calloc(nfields+2, sizeof(*fldtab))) == NULL 68*48f09a05SAntonio Huete Jimenez || (fldtab[0] = (Cell *) malloc(sizeof(**fldtab))) == NULL) 694b588458SPeter Avalos FATAL("out of space for $0 and fields"); 701d48fce0SDaniel Fojt *record = '\0'; 714b588458SPeter Avalos *fldtab[0] = dollar0; 724b588458SPeter Avalos fldtab[0]->sval = record; 734b588458SPeter Avalos fldtab[0]->nval = tostring("0"); 744b588458SPeter Avalos makefields(1, nfields); 754b588458SPeter Avalos } 764b588458SPeter Avalos 774b588458SPeter Avalos void makefields(int n1, int n2) /* create $n1..$n2 inclusive */ 784b588458SPeter Avalos { 794b588458SPeter Avalos char temp[50]; 804b588458SPeter Avalos int i; 814b588458SPeter Avalos 824b588458SPeter Avalos for (i = n1; i <= n2; i++) { 83*48f09a05SAntonio Huete Jimenez fldtab[i] = (Cell *) malloc(sizeof(**fldtab)); 844b588458SPeter Avalos if (fldtab[i] == NULL) 854b588458SPeter Avalos FATAL("out of space in makefields %d", i); 864b588458SPeter Avalos *fldtab[i] = dollar1; 871d48fce0SDaniel Fojt snprintf(temp, sizeof(temp), "%d", i); 884b588458SPeter Avalos fldtab[i]->nval = tostring(temp); 894b588458SPeter Avalos } 904b588458SPeter Avalos } 914b588458SPeter Avalos 924b588458SPeter Avalos void initgetrec(void) 934b588458SPeter Avalos { 944b588458SPeter Avalos int i; 954b588458SPeter Avalos char *p; 964b588458SPeter Avalos 974b588458SPeter Avalos for (i = 1; i < *ARGC; i++) { 98b12bae18SSascha Wildner p = getargv(i); /* find 1st real filename */ 99b12bae18SSascha Wildner if (p == NULL || *p == '\0') { /* deleted or zapped */ 100b12bae18SSascha Wildner argno++; 101b12bae18SSascha Wildner continue; 102b12bae18SSascha Wildner } 103b12bae18SSascha Wildner if (!isclvar(p)) { 104b12bae18SSascha Wildner setsval(lookup("FILENAME", symtab), p); 1054b588458SPeter Avalos return; 1064b588458SPeter Avalos } 1074b588458SPeter Avalos setclvar(p); /* a commandline assignment before filename */ 1084b588458SPeter Avalos argno++; 1094b588458SPeter Avalos } 1104b588458SPeter Avalos infile = stdin; /* no filenames, so use stdin */ 1111d48fce0SDaniel Fojt innew = true; 1124b588458SPeter Avalos } 1134b588458SPeter Avalos 1141d48fce0SDaniel Fojt /* 1151d48fce0SDaniel Fojt * POSIX specifies that fields are supposed to be evaluated as if they were 1161d48fce0SDaniel Fojt * split using the value of FS at the time that the record's value ($0) was 1171d48fce0SDaniel Fojt * read. 1181d48fce0SDaniel Fojt * 1191d48fce0SDaniel Fojt * Since field-splitting is done lazily, we save the current value of FS 1201d48fce0SDaniel Fojt * whenever a new record is read in (implicitly or via getline), or when 1211d48fce0SDaniel Fojt * a new value is assigned to $0. 1221d48fce0SDaniel Fojt */ 1231d48fce0SDaniel Fojt void savefs(void) 1241d48fce0SDaniel Fojt { 1251d48fce0SDaniel Fojt size_t len; 1261d48fce0SDaniel Fojt if ((len = strlen(getsval(fsloc))) < len_inputFS) { 1271d48fce0SDaniel Fojt strcpy(inputFS, *FS); /* for subsequent field splitting */ 1281d48fce0SDaniel Fojt return; 1291d48fce0SDaniel Fojt } 1304b588458SPeter Avalos 1311d48fce0SDaniel Fojt len_inputFS = len + 1; 132*48f09a05SAntonio Huete Jimenez inputFS = (char *) realloc(inputFS, len_inputFS); 1331d48fce0SDaniel Fojt if (inputFS == NULL) 1341d48fce0SDaniel Fojt FATAL("field separator %.10s... is too long", *FS); 1351d48fce0SDaniel Fojt memcpy(inputFS, *FS, len_inputFS); 1361d48fce0SDaniel Fojt } 1371d48fce0SDaniel Fojt 1381d48fce0SDaniel Fojt static bool firsttime = true; 1391d48fce0SDaniel Fojt 1401d48fce0SDaniel Fojt int getrec(char **pbuf, int *pbufsize, bool isrecord) /* get next input record */ 1414b588458SPeter Avalos { /* note: cares whether buf == record */ 1424b588458SPeter Avalos int c; 1434b588458SPeter Avalos char *buf = *pbuf; 1444b588458SPeter Avalos uschar saveb0; 1454b588458SPeter Avalos int bufsize = *pbufsize, savebufsize = bufsize; 1464b588458SPeter Avalos 1474b588458SPeter Avalos if (firsttime) { 1481d48fce0SDaniel Fojt firsttime = false; 1494b588458SPeter Avalos initgetrec(); 1504b588458SPeter Avalos } 151e5e686a0SDaniel Fojt DPRINTF("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n", 152e5e686a0SDaniel Fojt *RS, *FS, *ARGC, *FILENAME); 1534b588458SPeter Avalos if (isrecord) { 1541d48fce0SDaniel Fojt donefld = false; 1551d48fce0SDaniel Fojt donerec = true; 1561d48fce0SDaniel Fojt savefs(); 1574b588458SPeter Avalos } 1584b588458SPeter Avalos saveb0 = buf[0]; 1594b588458SPeter Avalos buf[0] = 0; 1604b588458SPeter Avalos while (argno < *ARGC || infile == stdin) { 161e5e686a0SDaniel Fojt DPRINTF("argno=%d, file=|%s|\n", argno, file); 1624b588458SPeter Avalos if (infile == NULL) { /* have to open a new file */ 1634b588458SPeter Avalos file = getargv(argno); 164b12bae18SSascha Wildner if (file == NULL || *file == '\0') { /* deleted or zapped */ 1654b588458SPeter Avalos argno++; 1664b588458SPeter Avalos continue; 1674b588458SPeter Avalos } 1684b588458SPeter Avalos if (isclvar(file)) { /* a var=value arg */ 1694b588458SPeter Avalos setclvar(file); 1704b588458SPeter Avalos argno++; 1714b588458SPeter Avalos continue; 1724b588458SPeter Avalos } 1734b588458SPeter Avalos *FILENAME = file; 174e5e686a0SDaniel Fojt DPRINTF("opening file %s\n", file); 1754b588458SPeter Avalos if (*file == '-' && *(file+1) == '\0') 1764b588458SPeter Avalos infile = stdin; 1774b588458SPeter Avalos else if ((infile = fopen(file, "r")) == NULL) 1784b588458SPeter Avalos FATAL("can't open file %s", file); 179*48f09a05SAntonio Huete Jimenez innew = true; 1804b588458SPeter Avalos setfval(fnrloc, 0.0); 1814b588458SPeter Avalos } 1821d48fce0SDaniel Fojt c = readrec(&buf, &bufsize, infile, innew); 1831d48fce0SDaniel Fojt if (innew) 1841d48fce0SDaniel Fojt innew = false; 1854b588458SPeter Avalos if (c != 0 || buf[0] != '\0') { /* normal record */ 1864b588458SPeter Avalos if (isrecord) { 187*48f09a05SAntonio Huete Jimenez double result; 188*48f09a05SAntonio Huete Jimenez 1894b588458SPeter Avalos if (freeable(fldtab[0])) 1904b588458SPeter Avalos xfree(fldtab[0]->sval); 1914b588458SPeter Avalos fldtab[0]->sval = buf; /* buf == record */ 1924b588458SPeter Avalos fldtab[0]->tval = REC | STR | DONTFREE; 193*48f09a05SAntonio Huete Jimenez if (is_number(fldtab[0]->sval, & result)) { 194*48f09a05SAntonio Huete Jimenez fldtab[0]->fval = result; 1954b588458SPeter Avalos fldtab[0]->tval |= NUM; 1964b588458SPeter Avalos } 1974b588458SPeter Avalos } 1984b588458SPeter Avalos setfval(nrloc, nrloc->fval+1); 1994b588458SPeter Avalos setfval(fnrloc, fnrloc->fval+1); 2004b588458SPeter Avalos *pbuf = buf; 2014b588458SPeter Avalos *pbufsize = bufsize; 2024b588458SPeter Avalos return 1; 2034b588458SPeter Avalos } 2044b588458SPeter Avalos /* EOF arrived on this file; set up next */ 2054b588458SPeter Avalos if (infile != stdin) 2064b588458SPeter Avalos fclose(infile); 2074b588458SPeter Avalos infile = NULL; 2084b588458SPeter Avalos argno++; 2094b588458SPeter Avalos } 2104b588458SPeter Avalos buf[0] = saveb0; 2114b588458SPeter Avalos *pbuf = buf; 2124b588458SPeter Avalos *pbufsize = savebufsize; 2134b588458SPeter Avalos return 0; /* true end of file */ 2144b588458SPeter Avalos } 2154b588458SPeter Avalos 2164b588458SPeter Avalos void nextfile(void) 2174b588458SPeter Avalos { 2184b588458SPeter Avalos if (infile != NULL && infile != stdin) 2194b588458SPeter Avalos fclose(infile); 2204b588458SPeter Avalos infile = NULL; 2214b588458SPeter Avalos argno++; 2224b588458SPeter Avalos } 2234b588458SPeter Avalos 2241d48fce0SDaniel Fojt int readrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag) /* read one record into buf */ 2254b588458SPeter Avalos { 2261d48fce0SDaniel Fojt int sep, c, isrec; 2274b588458SPeter Avalos char *rr, *buf = *pbuf; 2284b588458SPeter Avalos int bufsize = *pbufsize; 2291d48fce0SDaniel Fojt char *rs = getsval(rsloc); 2304b588458SPeter Avalos 2311d48fce0SDaniel Fojt if (*rs && rs[1]) { 2321d48fce0SDaniel Fojt bool found; 2331d48fce0SDaniel Fojt 2341d48fce0SDaniel Fojt fa *pfa = makedfa(rs, 1); 2351d48fce0SDaniel Fojt if (newflag) 2361d48fce0SDaniel Fojt found = fnematch(pfa, inf, &buf, &bufsize, recsize); 2371d48fce0SDaniel Fojt else { 2381d48fce0SDaniel Fojt int tempstat = pfa->initstat; 2391d48fce0SDaniel Fojt pfa->initstat = 2; 2401d48fce0SDaniel Fojt found = fnematch(pfa, inf, &buf, &bufsize, recsize); 2411d48fce0SDaniel Fojt pfa->initstat = tempstat; 2421d48fce0SDaniel Fojt } 2431d48fce0SDaniel Fojt if (found) 2441d48fce0SDaniel Fojt setptr(patbeg, '\0'); 245*48f09a05SAntonio Huete Jimenez isrec = (found == 0 && *buf == '\0') ? false : true; 2461d48fce0SDaniel Fojt } else { 2471d48fce0SDaniel Fojt if ((sep = *rs) == 0) { 2484b588458SPeter Avalos sep = '\n'; 2494b588458SPeter Avalos while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */ 2504b588458SPeter Avalos ; 2514b588458SPeter Avalos if (c != EOF) 2524b588458SPeter Avalos ungetc(c, inf); 2534b588458SPeter Avalos } 2544b588458SPeter Avalos for (rr = buf; ; ) { 2554b588458SPeter Avalos for (; (c=getc(inf)) != sep && c != EOF; ) { 2564b588458SPeter Avalos if (rr-buf+1 > bufsize) 2571d48fce0SDaniel Fojt if (!adjbuf(&buf, &bufsize, 1+rr-buf, 2581d48fce0SDaniel Fojt recsize, &rr, "readrec 1")) 2594b588458SPeter Avalos FATAL("input record `%.30s...' too long", buf); 2604b588458SPeter Avalos *rr++ = c; 2614b588458SPeter Avalos } 2621d48fce0SDaniel Fojt if (*rs == sep || c == EOF) 2634b588458SPeter Avalos break; 2644b588458SPeter Avalos if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */ 2654b588458SPeter Avalos break; 2661d48fce0SDaniel Fojt if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, 2671d48fce0SDaniel Fojt "readrec 2")) 2684b588458SPeter Avalos FATAL("input record `%.30s...' too long", buf); 2694b588458SPeter Avalos *rr++ = '\n'; 2704b588458SPeter Avalos *rr++ = c; 2714b588458SPeter Avalos } 2724b588458SPeter Avalos if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3")) 2734b588458SPeter Avalos FATAL("input record `%.30s...' too long", buf); 2744b588458SPeter Avalos *rr = 0; 275*48f09a05SAntonio Huete Jimenez isrec = (c == EOF && rr == buf) ? false : true; 2761d48fce0SDaniel Fojt } 2774b588458SPeter Avalos *pbuf = buf; 2784b588458SPeter Avalos *pbufsize = bufsize; 279e5e686a0SDaniel Fojt DPRINTF("readrec saw <%s>, returns %d\n", buf, isrec); 2801d48fce0SDaniel Fojt return isrec; 2814b588458SPeter Avalos } 2824b588458SPeter Avalos 2834b588458SPeter Avalos char *getargv(int n) /* get ARGV[n] */ 2844b588458SPeter Avalos { 2854b588458SPeter Avalos Cell *x; 2864b588458SPeter Avalos char *s, temp[50]; 2874b588458SPeter Avalos extern Array *ARGVtab; 2884b588458SPeter Avalos 2891d48fce0SDaniel Fojt snprintf(temp, sizeof(temp), "%d", n); 290b12bae18SSascha Wildner if (lookup(temp, ARGVtab) == NULL) 291b12bae18SSascha Wildner return NULL; 2924b588458SPeter Avalos x = setsymtab(temp, "", 0.0, STR, ARGVtab); 2934b588458SPeter Avalos s = getsval(x); 294e5e686a0SDaniel Fojt DPRINTF("getargv(%d) returns |%s|\n", n, s); 2954b588458SPeter Avalos return s; 2964b588458SPeter Avalos } 2974b588458SPeter Avalos 2984b588458SPeter Avalos void setclvar(char *s) /* set var=value from s */ 2994b588458SPeter Avalos { 300*48f09a05SAntonio Huete Jimenez char *e, *p; 3014b588458SPeter Avalos Cell *q; 302*48f09a05SAntonio Huete Jimenez double result; 3034b588458SPeter Avalos 3044b588458SPeter Avalos for (p=s; *p != '='; p++) 3054b588458SPeter Avalos ; 306*48f09a05SAntonio Huete Jimenez e = p; 3074b588458SPeter Avalos *p++ = 0; 3084b588458SPeter Avalos p = qstring(p, '\0'); 3094b588458SPeter Avalos q = setsymtab(s, p, 0.0, STR, symtab); 3104b588458SPeter Avalos setsval(q, p); 311*48f09a05SAntonio Huete Jimenez if (is_number(q->sval, & result)) { 312*48f09a05SAntonio Huete Jimenez q->fval = result; 3134b588458SPeter Avalos q->tval |= NUM; 3144b588458SPeter Avalos } 315e5e686a0SDaniel Fojt DPRINTF("command line set %s to |%s|\n", s, p); 316*48f09a05SAntonio Huete Jimenez free(p); 317*48f09a05SAntonio Huete Jimenez *e = '='; 3184b588458SPeter Avalos } 3194b588458SPeter Avalos 3204b588458SPeter Avalos 3214b588458SPeter Avalos void fldbld(void) /* create fields from current record */ 3224b588458SPeter Avalos { 3234b588458SPeter Avalos /* this relies on having fields[] the same length as $0 */ 3244b588458SPeter Avalos /* the fields are all stored in this one array with \0's */ 3250020174dSPeter Avalos /* possibly with a final trailing \0 not associated with any field */ 3264b588458SPeter Avalos char *r, *fr, sep; 3274b588458SPeter Avalos Cell *p; 3284b588458SPeter Avalos int i, j, n; 3294b588458SPeter Avalos 3304b588458SPeter Avalos if (donefld) 3314b588458SPeter Avalos return; 3324b588458SPeter Avalos if (!isstr(fldtab[0])) 3334b588458SPeter Avalos getsval(fldtab[0]); 3344b588458SPeter Avalos r = fldtab[0]->sval; 3354b588458SPeter Avalos n = strlen(r); 3364b588458SPeter Avalos if (n > fieldssize) { 3374b588458SPeter Avalos xfree(fields); 338*48f09a05SAntonio Huete Jimenez if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */ 3394b588458SPeter Avalos FATAL("out of space for fields in fldbld %d", n); 3404b588458SPeter Avalos fieldssize = n; 3414b588458SPeter Avalos } 3424b588458SPeter Avalos fr = fields; 3434b588458SPeter Avalos i = 0; /* number of fields accumulated here */ 3441d48fce0SDaniel Fojt if (inputFS == NULL) /* make sure we have a copy of FS */ 3451d48fce0SDaniel Fojt savefs(); 3464b588458SPeter Avalos if (strlen(inputFS) > 1) { /* it's a regular expression */ 3474b588458SPeter Avalos i = refldbld(r, inputFS); 3484b588458SPeter Avalos } else if ((sep = *inputFS) == ' ') { /* default whitespace */ 3494b588458SPeter Avalos for (i = 0; ; ) { 3504b588458SPeter Avalos while (*r == ' ' || *r == '\t' || *r == '\n') 3514b588458SPeter Avalos r++; 3524b588458SPeter Avalos if (*r == 0) 3534b588458SPeter Avalos break; 3544b588458SPeter Avalos i++; 3554b588458SPeter Avalos if (i > nfields) 3564b588458SPeter Avalos growfldtab(i); 3574b588458SPeter Avalos if (freeable(fldtab[i])) 3584b588458SPeter Avalos xfree(fldtab[i]->sval); 3594b588458SPeter Avalos fldtab[i]->sval = fr; 3604b588458SPeter Avalos fldtab[i]->tval = FLD | STR | DONTFREE; 3614b588458SPeter Avalos do 3624b588458SPeter Avalos *fr++ = *r++; 3634b588458SPeter Avalos while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0'); 3644b588458SPeter Avalos *fr++ = 0; 3654b588458SPeter Avalos } 3664b588458SPeter Avalos *fr = 0; 3674b588458SPeter Avalos } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */ 3681d48fce0SDaniel Fojt for (i = 0; *r != '\0'; r += n) { 3691d48fce0SDaniel Fojt char buf[MB_LEN_MAX + 1]; 3701d48fce0SDaniel Fojt 3714b588458SPeter Avalos i++; 3724b588458SPeter Avalos if (i > nfields) 3734b588458SPeter Avalos growfldtab(i); 3744b588458SPeter Avalos if (freeable(fldtab[i])) 3754b588458SPeter Avalos xfree(fldtab[i]->sval); 3761d48fce0SDaniel Fojt n = mblen(r, MB_LEN_MAX); 3771d48fce0SDaniel Fojt if (n < 0) 3781d48fce0SDaniel Fojt n = 1; 3791d48fce0SDaniel Fojt memcpy(buf, r, n); 3801d48fce0SDaniel Fojt buf[n] = '\0'; 3814b588458SPeter Avalos fldtab[i]->sval = tostring(buf); 3824b588458SPeter Avalos fldtab[i]->tval = FLD | STR; 3834b588458SPeter Avalos } 3844b588458SPeter Avalos *fr = 0; 3854b588458SPeter Avalos } else if (*r != 0) { /* if 0, it's a null field */ 3864b588458SPeter Avalos /* subtlecase : if length(FS) == 1 && length(RS > 0) 3874b588458SPeter Avalos * \n is NOT a field separator (cf awk book 61,84). 3884b588458SPeter Avalos * this variable is tested in the inner while loop. 3894b588458SPeter Avalos */ 3904b588458SPeter Avalos int rtest = '\n'; /* normal case */ 3914b588458SPeter Avalos if (strlen(*RS) > 0) 3924b588458SPeter Avalos rtest = '\0'; 3934b588458SPeter Avalos for (;;) { 3944b588458SPeter Avalos i++; 3954b588458SPeter Avalos if (i > nfields) 3964b588458SPeter Avalos growfldtab(i); 3974b588458SPeter Avalos if (freeable(fldtab[i])) 3984b588458SPeter Avalos xfree(fldtab[i]->sval); 3994b588458SPeter Avalos fldtab[i]->sval = fr; 4004b588458SPeter Avalos fldtab[i]->tval = FLD | STR | DONTFREE; 4014b588458SPeter Avalos while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */ 4024b588458SPeter Avalos *fr++ = *r++; 4034b588458SPeter Avalos *fr++ = 0; 4044b588458SPeter Avalos if (*r++ == 0) 4054b588458SPeter Avalos break; 4064b588458SPeter Avalos } 4074b588458SPeter Avalos *fr = 0; 4084b588458SPeter Avalos } 4094b588458SPeter Avalos if (i > nfields) 4104b588458SPeter Avalos FATAL("record `%.30s...' has too many fields; can't happen", r); 4114b588458SPeter Avalos cleanfld(i+1, lastfld); /* clean out junk from previous record */ 4124b588458SPeter Avalos lastfld = i; 4131d48fce0SDaniel Fojt donefld = true; 4144b588458SPeter Avalos for (j = 1; j <= lastfld; j++) { 415*48f09a05SAntonio Huete Jimenez double result; 416*48f09a05SAntonio Huete Jimenez 4174b588458SPeter Avalos p = fldtab[j]; 418*48f09a05SAntonio Huete Jimenez if(is_number(p->sval, & result)) { 419*48f09a05SAntonio Huete Jimenez p->fval = result; 4204b588458SPeter Avalos p->tval |= NUM; 4214b588458SPeter Avalos } 4224b588458SPeter Avalos } 4234b588458SPeter Avalos setfval(nfloc, (Awkfloat) lastfld); 4241d48fce0SDaniel Fojt donerec = true; /* restore */ 4254b588458SPeter Avalos if (dbg) { 4264b588458SPeter Avalos for (j = 0; j <= lastfld; j++) { 4274b588458SPeter Avalos p = fldtab[j]; 4284b588458SPeter Avalos printf("field %d (%s): |%s|\n", j, p->nval, p->sval); 4294b588458SPeter Avalos } 4304b588458SPeter Avalos } 4314b588458SPeter Avalos } 4324b588458SPeter Avalos 4334b588458SPeter Avalos void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */ 4344b588458SPeter Avalos { /* nvals remain intact */ 4354b588458SPeter Avalos Cell *p; 4364b588458SPeter Avalos int i; 4374b588458SPeter Avalos 4384b588458SPeter Avalos for (i = n1; i <= n2; i++) { 4394b588458SPeter Avalos p = fldtab[i]; 4404b588458SPeter Avalos if (freeable(p)) 4414b588458SPeter Avalos xfree(p->sval); 4421d48fce0SDaniel Fojt p->sval = EMPTY, 4434b588458SPeter Avalos p->tval = FLD | STR | DONTFREE; 4444b588458SPeter Avalos } 4454b588458SPeter Avalos } 4464b588458SPeter Avalos 4474b588458SPeter Avalos void newfld(int n) /* add field n after end of existing lastfld */ 4484b588458SPeter Avalos { 4494b588458SPeter Avalos if (n > nfields) 4504b588458SPeter Avalos growfldtab(n); 4514b588458SPeter Avalos cleanfld(lastfld+1, n); 4524b588458SPeter Avalos lastfld = n; 4534b588458SPeter Avalos setfval(nfloc, (Awkfloat) n); 4544b588458SPeter Avalos } 4554b588458SPeter Avalos 4561d48fce0SDaniel Fojt void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */ 4571d48fce0SDaniel Fojt { 4581d48fce0SDaniel Fojt if (n < 0) 4591d48fce0SDaniel Fojt FATAL("cannot set NF to a negative value"); 4601d48fce0SDaniel Fojt if (n > nfields) 4611d48fce0SDaniel Fojt growfldtab(n); 4621d48fce0SDaniel Fojt 4631d48fce0SDaniel Fojt if (lastfld < n) 4641d48fce0SDaniel Fojt cleanfld(lastfld+1, n); 4651d48fce0SDaniel Fojt else 4661d48fce0SDaniel Fojt cleanfld(n+1, lastfld); 4671d48fce0SDaniel Fojt 4681d48fce0SDaniel Fojt lastfld = n; 4691d48fce0SDaniel Fojt } 4701d48fce0SDaniel Fojt 4714b588458SPeter Avalos Cell *fieldadr(int n) /* get nth field */ 4724b588458SPeter Avalos { 4734b588458SPeter Avalos if (n < 0) 4744b588458SPeter Avalos FATAL("trying to access out of range field %d", n); 4754b588458SPeter Avalos if (n > nfields) /* fields after NF are empty */ 4764b588458SPeter Avalos growfldtab(n); /* but does not increase NF */ 4774b588458SPeter Avalos return(fldtab[n]); 4784b588458SPeter Avalos } 4794b588458SPeter Avalos 4804b588458SPeter Avalos void growfldtab(int n) /* make new fields up to at least $n */ 4814b588458SPeter Avalos { 4824b588458SPeter Avalos int nf = 2 * nfields; 4834b588458SPeter Avalos size_t s; 4844b588458SPeter Avalos 4854b588458SPeter Avalos if (n > nf) 4864b588458SPeter Avalos nf = n; 4874b588458SPeter Avalos s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */ 4881d48fce0SDaniel Fojt if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */ 489*48f09a05SAntonio Huete Jimenez fldtab = (Cell **) realloc(fldtab, s); 4904b588458SPeter Avalos else /* overflow sizeof int */ 4914b588458SPeter Avalos xfree(fldtab); /* make it null */ 4924b588458SPeter Avalos if (fldtab == NULL) 4934b588458SPeter Avalos FATAL("out of space creating %d fields", nf); 4944b588458SPeter Avalos makefields(nfields+1, nf); 4954b588458SPeter Avalos nfields = nf; 4964b588458SPeter Avalos } 4974b588458SPeter Avalos 4984b588458SPeter Avalos int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */ 4994b588458SPeter Avalos { 5004b588458SPeter Avalos /* this relies on having fields[] the same length as $0 */ 5014b588458SPeter Avalos /* the fields are all stored in this one array with \0's */ 5024b588458SPeter Avalos char *fr; 5034b588458SPeter Avalos int i, tempstat, n; 5044b588458SPeter Avalos fa *pfa; 5054b588458SPeter Avalos 5064b588458SPeter Avalos n = strlen(rec); 5074b588458SPeter Avalos if (n > fieldssize) { 5084b588458SPeter Avalos xfree(fields); 509*48f09a05SAntonio Huete Jimenez if ((fields = (char *) malloc(n+1)) == NULL) 5104b588458SPeter Avalos FATAL("out of space for fields in refldbld %d", n); 5114b588458SPeter Avalos fieldssize = n; 5124b588458SPeter Avalos } 5134b588458SPeter Avalos fr = fields; 5144b588458SPeter Avalos *fr = '\0'; 5154b588458SPeter Avalos if (*rec == '\0') 5164b588458SPeter Avalos return 0; 5174b588458SPeter Avalos pfa = makedfa(fs, 1); 518e5e686a0SDaniel Fojt DPRINTF("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs); 5194b588458SPeter Avalos tempstat = pfa->initstat; 5204b588458SPeter Avalos for (i = 1; ; i++) { 5214b588458SPeter Avalos if (i > nfields) 5224b588458SPeter Avalos growfldtab(i); 5234b588458SPeter Avalos if (freeable(fldtab[i])) 5244b588458SPeter Avalos xfree(fldtab[i]->sval); 5254b588458SPeter Avalos fldtab[i]->tval = FLD | STR | DONTFREE; 5264b588458SPeter Avalos fldtab[i]->sval = fr; 527e5e686a0SDaniel Fojt DPRINTF("refldbld: i=%d\n", i); 5284b588458SPeter Avalos if (nematch(pfa, rec)) { 5294b588458SPeter Avalos pfa->initstat = 2; /* horrible coupling to b.c */ 530e5e686a0SDaniel Fojt DPRINTF("match %s (%d chars)\n", patbeg, patlen); 5314b588458SPeter Avalos strncpy(fr, rec, patbeg-rec); 5324b588458SPeter Avalos fr += patbeg - rec + 1; 5334b588458SPeter Avalos *(fr-1) = '\0'; 5344b588458SPeter Avalos rec = patbeg + patlen; 5354b588458SPeter Avalos } else { 536e5e686a0SDaniel Fojt DPRINTF("no match %s\n", rec); 5374b588458SPeter Avalos strcpy(fr, rec); 5384b588458SPeter Avalos pfa->initstat = tempstat; 5394b588458SPeter Avalos break; 5404b588458SPeter Avalos } 5414b588458SPeter Avalos } 5424b588458SPeter Avalos return i; 5434b588458SPeter Avalos } 5444b588458SPeter Avalos 5454b588458SPeter Avalos void recbld(void) /* create $0 from $1..$NF if necessary */ 5464b588458SPeter Avalos { 5474b588458SPeter Avalos int i; 5484b588458SPeter Avalos char *r, *p; 5491d48fce0SDaniel Fojt char *sep = getsval(ofsloc); 5504b588458SPeter Avalos 5511d48fce0SDaniel Fojt if (donerec) 5524b588458SPeter Avalos return; 5534b588458SPeter Avalos r = record; 5544b588458SPeter Avalos for (i = 1; i <= *NF; i++) { 5554b588458SPeter Avalos p = getsval(fldtab[i]); 5564b588458SPeter Avalos if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1")) 5574b588458SPeter Avalos FATAL("created $0 `%.30s...' too long", record); 5584b588458SPeter Avalos while ((*r = *p++) != 0) 5594b588458SPeter Avalos r++; 5604b588458SPeter Avalos if (i < *NF) { 5611d48fce0SDaniel Fojt if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2")) 5624b588458SPeter Avalos FATAL("created $0 `%.30s...' too long", record); 5631d48fce0SDaniel Fojt for (p = sep; (*r = *p++) != 0; ) 5644b588458SPeter Avalos r++; 5654b588458SPeter Avalos } 5664b588458SPeter Avalos } 5674b588458SPeter Avalos if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3")) 5684b588458SPeter Avalos FATAL("built giant record `%.30s...'", record); 5694b588458SPeter Avalos *r = '\0'; 570e5e686a0SDaniel Fojt DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]); 5714b588458SPeter Avalos 5724b588458SPeter Avalos if (freeable(fldtab[0])) 5734b588458SPeter Avalos xfree(fldtab[0]->sval); 5744b588458SPeter Avalos fldtab[0]->tval = REC | STR | DONTFREE; 5754b588458SPeter Avalos fldtab[0]->sval = record; 5764b588458SPeter Avalos 577e5e686a0SDaniel Fojt DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]); 578e5e686a0SDaniel Fojt DPRINTF("recbld = |%s|\n", record); 5791d48fce0SDaniel Fojt donerec = true; 5804b588458SPeter Avalos } 5814b588458SPeter Avalos 5824b588458SPeter Avalos int errorflag = 0; 5834b588458SPeter Avalos 5844b588458SPeter Avalos void yyerror(const char *s) 5854b588458SPeter Avalos { 5864b588458SPeter Avalos SYNTAX("%s", s); 5874b588458SPeter Avalos } 5884b588458SPeter Avalos 5894b588458SPeter Avalos void SYNTAX(const char *fmt, ...) 5904b588458SPeter Avalos { 5914b588458SPeter Avalos extern char *cmdname, *curfname; 5924b588458SPeter Avalos static int been_here = 0; 5934b588458SPeter Avalos va_list varg; 5944b588458SPeter Avalos 5954b588458SPeter Avalos if (been_here++ > 2) 5964b588458SPeter Avalos return; 5974b588458SPeter Avalos fprintf(stderr, "%s: ", cmdname); 5984b588458SPeter Avalos va_start(varg, fmt); 5994b588458SPeter Avalos vfprintf(stderr, fmt, varg); 6004b588458SPeter Avalos va_end(varg); 6014b588458SPeter Avalos fprintf(stderr, " at source line %d", lineno); 6024b588458SPeter Avalos if (curfname != NULL) 6034b588458SPeter Avalos fprintf(stderr, " in function %s", curfname); 6041d48fce0SDaniel Fojt if (compile_time == COMPILING && cursource() != NULL) 6054b588458SPeter Avalos fprintf(stderr, " source file %s", cursource()); 6064b588458SPeter Avalos fprintf(stderr, "\n"); 6074b588458SPeter Avalos errorflag = 2; 6084b588458SPeter Avalos eprint(); 6094b588458SPeter Avalos } 6104b588458SPeter Avalos 6114b588458SPeter Avalos extern int bracecnt, brackcnt, parencnt; 6124b588458SPeter Avalos 6134b588458SPeter Avalos void bracecheck(void) 6144b588458SPeter Avalos { 6154b588458SPeter Avalos int c; 6164b588458SPeter Avalos static int beenhere = 0; 6174b588458SPeter Avalos 6184b588458SPeter Avalos if (beenhere++) 6194b588458SPeter Avalos return; 6204b588458SPeter Avalos while ((c = input()) != EOF && c != '\0') 6214b588458SPeter Avalos bclass(c); 6224b588458SPeter Avalos bcheck2(bracecnt, '{', '}'); 6234b588458SPeter Avalos bcheck2(brackcnt, '[', ']'); 6244b588458SPeter Avalos bcheck2(parencnt, '(', ')'); 6254b588458SPeter Avalos } 6264b588458SPeter Avalos 6274b588458SPeter Avalos void bcheck2(int n, int c1, int c2) 6284b588458SPeter Avalos { 6294b588458SPeter Avalos if (n == 1) 6304b588458SPeter Avalos fprintf(stderr, "\tmissing %c\n", c2); 6314b588458SPeter Avalos else if (n > 1) 6324b588458SPeter Avalos fprintf(stderr, "\t%d missing %c's\n", n, c2); 6334b588458SPeter Avalos else if (n == -1) 6344b588458SPeter Avalos fprintf(stderr, "\textra %c\n", c2); 6354b588458SPeter Avalos else if (n < -1) 6364b588458SPeter Avalos fprintf(stderr, "\t%d extra %c's\n", -n, c2); 6374b588458SPeter Avalos } 6384b588458SPeter Avalos 6394b588458SPeter Avalos void FATAL(const char *fmt, ...) 6404b588458SPeter Avalos { 6414b588458SPeter Avalos extern char *cmdname; 6424b588458SPeter Avalos va_list varg; 6434b588458SPeter Avalos 6444b588458SPeter Avalos fflush(stdout); 6454b588458SPeter Avalos fprintf(stderr, "%s: ", cmdname); 6464b588458SPeter Avalos va_start(varg, fmt); 6474b588458SPeter Avalos vfprintf(stderr, fmt, varg); 6484b588458SPeter Avalos va_end(varg); 6494b588458SPeter Avalos error(); 6504b588458SPeter Avalos if (dbg > 1) /* core dump if serious debugging on */ 6514b588458SPeter Avalos abort(); 6524b588458SPeter Avalos exit(2); 6534b588458SPeter Avalos } 6544b588458SPeter Avalos 6554b588458SPeter Avalos void WARNING(const char *fmt, ...) 6564b588458SPeter Avalos { 6574b588458SPeter Avalos extern char *cmdname; 6584b588458SPeter Avalos va_list varg; 6594b588458SPeter Avalos 6604b588458SPeter Avalos fflush(stdout); 6614b588458SPeter Avalos fprintf(stderr, "%s: ", cmdname); 6624b588458SPeter Avalos va_start(varg, fmt); 6634b588458SPeter Avalos vfprintf(stderr, fmt, varg); 6644b588458SPeter Avalos va_end(varg); 6654b588458SPeter Avalos error(); 6664b588458SPeter Avalos } 6674b588458SPeter Avalos 6684b588458SPeter Avalos void error() 6694b588458SPeter Avalos { 6704b588458SPeter Avalos extern Node *curnode; 6714b588458SPeter Avalos 6724b588458SPeter Avalos fprintf(stderr, "\n"); 6731d48fce0SDaniel Fojt if (compile_time != ERROR_PRINTING) { 6741d48fce0SDaniel Fojt if (NR && *NR > 0) { 6754b588458SPeter Avalos fprintf(stderr, " input record number %d", (int) (*FNR)); 6764b588458SPeter Avalos if (strcmp(*FILENAME, "-") != 0) 6774b588458SPeter Avalos fprintf(stderr, ", file %s", *FILENAME); 6784b588458SPeter Avalos fprintf(stderr, "\n"); 6794b588458SPeter Avalos } 6801d48fce0SDaniel Fojt if (curnode) 6814b588458SPeter Avalos fprintf(stderr, " source line number %d", curnode->lineno); 6821d48fce0SDaniel Fojt else if (lineno) 6834b588458SPeter Avalos fprintf(stderr, " source line number %d", lineno); 6841d48fce0SDaniel Fojt if (compile_time == COMPILING && cursource() != NULL) 6854b588458SPeter Avalos fprintf(stderr, " source file %s", cursource()); 6864b588458SPeter Avalos fprintf(stderr, "\n"); 6874b588458SPeter Avalos eprint(); 6884b588458SPeter Avalos } 689*48f09a05SAntonio Huete Jimenez } 6904b588458SPeter Avalos 6914b588458SPeter Avalos void eprint(void) /* try to print context around error */ 6924b588458SPeter Avalos { 6934b588458SPeter Avalos char *p, *q; 6944b588458SPeter Avalos int c; 6954b588458SPeter Avalos static int been_here = 0; 6964b588458SPeter Avalos extern char ebuf[], *ep; 6974b588458SPeter Avalos 6981d48fce0SDaniel Fojt if (compile_time != COMPILING || been_here++ > 0 || ebuf == ep) 6991d48fce0SDaniel Fojt return; 7001d48fce0SDaniel Fojt if (ebuf == ep) 7014b588458SPeter Avalos return; 7024b588458SPeter Avalos p = ep - 1; 7034b588458SPeter Avalos if (p > ebuf && *p == '\n') 7044b588458SPeter Avalos p--; 7054b588458SPeter Avalos for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--) 7064b588458SPeter Avalos ; 7074b588458SPeter Avalos while (*p == '\n') 7084b588458SPeter Avalos p++; 7094b588458SPeter Avalos fprintf(stderr, " context is\n\t"); 7104b588458SPeter Avalos for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) 7114b588458SPeter Avalos ; 7124b588458SPeter Avalos for ( ; p < q; p++) 7134b588458SPeter Avalos if (*p) 7144b588458SPeter Avalos putc(*p, stderr); 7154b588458SPeter Avalos fprintf(stderr, " >>> "); 7164b588458SPeter Avalos for ( ; p < ep; p++) 7174b588458SPeter Avalos if (*p) 7184b588458SPeter Avalos putc(*p, stderr); 7194b588458SPeter Avalos fprintf(stderr, " <<< "); 7204b588458SPeter Avalos if (*ep) 7214b588458SPeter Avalos while ((c = input()) != '\n' && c != '\0' && c != EOF) { 7224b588458SPeter Avalos putc(c, stderr); 7234b588458SPeter Avalos bclass(c); 7244b588458SPeter Avalos } 7254b588458SPeter Avalos putc('\n', stderr); 7264b588458SPeter Avalos ep = ebuf; 7274b588458SPeter Avalos } 7284b588458SPeter Avalos 7294b588458SPeter Avalos void bclass(int c) 7304b588458SPeter Avalos { 7314b588458SPeter Avalos switch (c) { 7324b588458SPeter Avalos case '{': bracecnt++; break; 7334b588458SPeter Avalos case '}': bracecnt--; break; 7344b588458SPeter Avalos case '[': brackcnt++; break; 7354b588458SPeter Avalos case ']': brackcnt--; break; 7364b588458SPeter Avalos case '(': parencnt++; break; 7374b588458SPeter Avalos case ')': parencnt--; break; 7384b588458SPeter Avalos } 7394b588458SPeter Avalos } 7404b588458SPeter Avalos 7414b588458SPeter Avalos double errcheck(double x, const char *s) 7424b588458SPeter Avalos { 7434b588458SPeter Avalos 7444b588458SPeter Avalos if (errno == EDOM) { 7454b588458SPeter Avalos errno = 0; 7464b588458SPeter Avalos WARNING("%s argument out of domain", s); 7474b588458SPeter Avalos x = 1; 7484b588458SPeter Avalos } else if (errno == ERANGE) { 7494b588458SPeter Avalos errno = 0; 7504b588458SPeter Avalos WARNING("%s result out of range", s); 7514b588458SPeter Avalos x = 1; 7524b588458SPeter Avalos } 7534b588458SPeter Avalos return x; 7544b588458SPeter Avalos } 7554b588458SPeter Avalos 7564b588458SPeter Avalos int isclvar(const char *s) /* is s of form var=something ? */ 7574b588458SPeter Avalos { 7584b588458SPeter Avalos const char *os = s; 7594b588458SPeter Avalos 7604b588458SPeter Avalos if (!isalpha((uschar) *s) && *s != '_') 7614b588458SPeter Avalos return 0; 7624b588458SPeter Avalos for ( ; *s; s++) 7634b588458SPeter Avalos if (!(isalnum((uschar) *s) || *s == '_')) 7644b588458SPeter Avalos break; 7651d48fce0SDaniel Fojt return *s == '=' && s > os; 7664b588458SPeter Avalos } 7674b588458SPeter Avalos 7684b588458SPeter Avalos /* strtod is supposed to be a proper test of what's a valid number */ 7694b588458SPeter Avalos /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */ 7704b588458SPeter Avalos /* wrong: violates 4.10.1.4 of ansi C standard */ 771*48f09a05SAntonio Huete Jimenez 7721d48fce0SDaniel Fojt /* well, not quite. As of C99, hex floating point is allowed. so this is 773*48f09a05SAntonio Huete Jimenez * a bit of a mess. We work around the mess by checking for a hexadecimal 774*48f09a05SAntonio Huete Jimenez * value and disallowing it. Similarly, we now follow gawk and allow only 775*48f09a05SAntonio Huete Jimenez * +nan, -nan, +inf, and -inf for NaN and infinity values. 7761d48fce0SDaniel Fojt */ 7774b588458SPeter Avalos 778*48f09a05SAntonio Huete Jimenez /* 779*48f09a05SAntonio Huete Jimenez * This routine now has a more complicated interface, the main point 780*48f09a05SAntonio Huete Jimenez * being to avoid the double conversion of a string to double, and 781*48f09a05SAntonio Huete Jimenez * also to convey out, if requested, the information that the numeric 782*48f09a05SAntonio Huete Jimenez * value was a leading string or is all of the string. The latter bit 783*48f09a05SAntonio Huete Jimenez * is used in getfval(). 784*48f09a05SAntonio Huete Jimenez */ 785*48f09a05SAntonio Huete Jimenez 786*48f09a05SAntonio Huete Jimenez bool is_valid_number(const char *s, bool trailing_stuff_ok, 787*48f09a05SAntonio Huete Jimenez bool *no_trailing, double *result) 7884b588458SPeter Avalos { 7894b588458SPeter Avalos double r; 7904b588458SPeter Avalos char *ep; 791*48f09a05SAntonio Huete Jimenez bool retval = false; 792*48f09a05SAntonio Huete Jimenez bool is_nan = false; 793*48f09a05SAntonio Huete Jimenez bool is_inf = false; 794*48f09a05SAntonio Huete Jimenez 795*48f09a05SAntonio Huete Jimenez if (no_trailing) 796*48f09a05SAntonio Huete Jimenez *no_trailing = false; 797*48f09a05SAntonio Huete Jimenez 798*48f09a05SAntonio Huete Jimenez while (isspace(*s)) 799*48f09a05SAntonio Huete Jimenez s++; 800*48f09a05SAntonio Huete Jimenez 801*48f09a05SAntonio Huete Jimenez // no hex floating point, sorry 802*48f09a05SAntonio Huete Jimenez if (s[0] == '0' && tolower(s[1]) == 'x') 803*48f09a05SAntonio Huete Jimenez return false; 804*48f09a05SAntonio Huete Jimenez 805*48f09a05SAntonio Huete Jimenez // allow +nan, -nan, +inf, -inf, any other letter, no 806*48f09a05SAntonio Huete Jimenez if (s[0] == '+' || s[0] == '-') { 807*48f09a05SAntonio Huete Jimenez is_nan = (strncasecmp(s+1, "nan", 3) == 0); 808*48f09a05SAntonio Huete Jimenez is_inf = (strncasecmp(s+1, "inf", 3) == 0); 809*48f09a05SAntonio Huete Jimenez if ((is_nan || is_inf) 810*48f09a05SAntonio Huete Jimenez && (isspace(s[4]) || s[4] == '\0')) 811*48f09a05SAntonio Huete Jimenez goto convert; 812*48f09a05SAntonio Huete Jimenez else if (! isdigit(s[1]) && s[1] != '.') 813*48f09a05SAntonio Huete Jimenez return false; 814*48f09a05SAntonio Huete Jimenez } 815*48f09a05SAntonio Huete Jimenez else if (! isdigit(s[0]) && s[0] != '.') 816*48f09a05SAntonio Huete Jimenez return false; 817*48f09a05SAntonio Huete Jimenez 818*48f09a05SAntonio Huete Jimenez convert: 8194b588458SPeter Avalos errno = 0; 8204b588458SPeter Avalos r = strtod(s, &ep); 821*48f09a05SAntonio Huete Jimenez if (ep == s || errno == ERANGE) 822*48f09a05SAntonio Huete Jimenez return false; 823*48f09a05SAntonio Huete Jimenez 824*48f09a05SAntonio Huete Jimenez if (isnan(r) && s[0] == '-' && signbit(r) == 0) 825*48f09a05SAntonio Huete Jimenez r = -r; 826*48f09a05SAntonio Huete Jimenez 827*48f09a05SAntonio Huete Jimenez if (result != NULL) 828*48f09a05SAntonio Huete Jimenez *result = r; 829*48f09a05SAntonio Huete Jimenez 830*48f09a05SAntonio Huete Jimenez /* 831*48f09a05SAntonio Huete Jimenez * check for trailing stuff 832*48f09a05SAntonio Huete Jimenez */ 833*48f09a05SAntonio Huete Jimenez while (isspace(*ep)) 8344b588458SPeter Avalos ep++; 835*48f09a05SAntonio Huete Jimenez 836*48f09a05SAntonio Huete Jimenez if (no_trailing != NULL) 837*48f09a05SAntonio Huete Jimenez *no_trailing = (*ep == '\0'); 838*48f09a05SAntonio Huete Jimenez 839*48f09a05SAntonio Huete Jimenez // return true if found the end, or trailing stuff is allowed 840*48f09a05SAntonio Huete Jimenez retval = *ep == '\0' || trailing_stuff_ok; 841*48f09a05SAntonio Huete Jimenez 842*48f09a05SAntonio Huete Jimenez return retval; 8434b588458SPeter Avalos } 844