diff options
Diffstat (limited to 'lib.c')
-rw-r--r-- | lib.c | 179 |
1 files changed, 124 insertions, 55 deletions
@@ -25,16 +25,18 @@ THIS SOFTWARE. #define DEBUG #include <stdio.h> #include <string.h> +#include <strings.h> #include <ctype.h> #include <errno.h> #include <stdlib.h> #include <stdarg.h> #include <limits.h> +#include <math.h> #include "awk.h" -#include "ytab.h" char EMPTY[] = { '\0' }; FILE *infile = NULL; +bool innew; /* true = infile has not been read by readrec */ char *file = EMPTY; char *record; int recsize = RECSIZE; @@ -55,15 +57,15 @@ int lastfld = 0; /* last used field */ int argno = 1; /* current input argument number */ extern Awkfloat *ARGC; -static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE }; -static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE }; +static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL, NULL }; +static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL, NULL }; void recinit(unsigned int n) { - if ( (record = malloc(n)) == NULL - || (fields = malloc(n+1)) == NULL - || (fldtab = calloc(nfields+2, sizeof(*fldtab))) == NULL - || (fldtab[0] = malloc(sizeof(**fldtab))) == NULL) + if ( (record = (char *) malloc(n)) == NULL + || (fields = (char *) malloc(n+1)) == NULL + || (fldtab = (Cell **) calloc(nfields+2, sizeof(*fldtab))) == NULL + || (fldtab[0] = (Cell *) malloc(sizeof(**fldtab))) == NULL) FATAL("out of space for $0 and fields"); *record = '\0'; *fldtab[0] = dollar0; @@ -78,7 +80,7 @@ void makefields(int n1, int n2) /* create $n1..$n2 inclusive */ int i; for (i = n1; i <= n2; i++) { - fldtab[i] = malloc(sizeof(**fldtab)); + fldtab[i] = (Cell *) malloc(sizeof(**fldtab)); if (fldtab[i] == NULL) FATAL("out of space in makefields %d", i); *fldtab[i] = dollar1; @@ -106,6 +108,7 @@ void initgetrec(void) argno++; } infile = stdin; /* no filenames, so use stdin */ + innew = true; } /* @@ -126,7 +129,7 @@ void savefs(void) } len_inputFS = len + 1; - inputFS = realloc(inputFS, len_inputFS); + inputFS = (char *) realloc(inputFS, len_inputFS); if (inputFS == NULL) FATAL("field separator %.10s... is too long", *FS); memcpy(inputFS, *FS, len_inputFS); @@ -145,8 +148,8 @@ int getrec(char **pbuf, int *pbufsize, bool isrecord) /* get next input record * firsttime = false; initgetrec(); } - dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n", - *RS, *FS, *ARGC, *FILENAME) ); + DPRINTF("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n", + *RS, *FS, *ARGC, *FILENAME); if (isrecord) { donefld = false; donerec = true; @@ -155,7 +158,7 @@ int getrec(char **pbuf, int *pbufsize, bool isrecord) /* get next input record * saveb0 = buf[0]; buf[0] = 0; while (argno < *ARGC || infile == stdin) { - dprintf( ("argno=%d, file=|%s|\n", argno, file) ); + DPRINTF("argno=%d, file=|%s|\n", argno, file); if (infile == NULL) { /* have to open a new file */ file = getargv(argno); if (file == NULL || *file == '\0') { /* deleted or zapped */ @@ -168,22 +171,26 @@ int getrec(char **pbuf, int *pbufsize, bool isrecord) /* get next input record * continue; } *FILENAME = file; - dprintf( ("opening file %s\n", file) ); + DPRINTF("opening file %s\n", file); if (*file == '-' && *(file+1) == '\0') infile = stdin; else if ((infile = fopen(file, "r")) == NULL) FATAL("can't open file %s", file); setfval(fnrloc, 0.0); } - c = readrec(&buf, &bufsize, infile); + c = readrec(&buf, &bufsize, infile, innew); + if (innew) + innew = false; if (c != 0 || buf[0] != '\0') { /* normal record */ if (isrecord) { + double result; + if (freeable(fldtab[0])) xfree(fldtab[0]->sval); fldtab[0]->sval = buf; /* buf == record */ fldtab[0]->tval = REC | STR | DONTFREE; - if (is_number(fldtab[0]->sval)) { - fldtab[0]->fval = atof(fldtab[0]->sval); + if (is_number(fldtab[0]->sval, & result)) { + fldtab[0]->fval = result; fldtab[0]->tval |= NUM; } } @@ -213,7 +220,7 @@ void nextfile(void) argno++; } -int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */ +int readrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag) /* read one record into buf */ { int sep, c, isrec; char *rr, *buf = *pbuf; @@ -224,7 +231,14 @@ int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf * bool found; fa *pfa = makedfa(rs, 1); - found = fnematch(pfa, inf, &buf, &bufsize, recsize); + if (newflag) + found = fnematch(pfa, inf, &buf, &bufsize, recsize); + else { + int tempstat = pfa->initstat; + pfa->initstat = 2; + found = fnematch(pfa, inf, &buf, &bufsize, recsize); + pfa->initstat = tempstat; + } if (found) setptr(patbeg, '\0'); } else { @@ -260,7 +274,7 @@ int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf * *pbuf = buf; *pbufsize = bufsize; isrec = *buf || !feof(inf); - dprintf( ("readrec saw <%s>, returns %d\n", buf, isrec) ); + DPRINTF("readrec saw <%s>, returns %d\n", buf, isrec); return isrec; } @@ -275,7 +289,7 @@ char *getargv(int n) /* get ARGV[n] */ return NULL; x = setsymtab(temp, "", 0.0, STR, ARGVtab); s = getsval(x); - dprintf( ("getargv(%d) returns |%s|\n", n, s) ); + DPRINTF("getargv(%d) returns |%s|\n", n, s); return s; } @@ -283,6 +297,7 @@ void setclvar(char *s) /* set var=value from s */ { char *p; Cell *q; + double result; for (p=s; *p != '='; p++) ; @@ -290,11 +305,11 @@ void setclvar(char *s) /* set var=value from s */ p = qstring(p, '\0'); q = setsymtab(s, p, 0.0, STR, symtab); setsval(q, p); - if (is_number(q->sval)) { - q->fval = atof(q->sval); + if (is_number(q->sval, & result)) { + q->fval = result; q->tval |= NUM; } - dprintf( ("command line set %s to |%s|\n", s, p) ); + DPRINTF("command line set %s to |%s|\n", s, p); } @@ -315,12 +330,14 @@ void fldbld(void) /* create fields from current record */ n = strlen(r); if (n > fieldssize) { xfree(fields); - if ((fields = malloc(n+2)) == NULL) /* possibly 2 final \0s */ + if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */ FATAL("out of space for fields in fldbld %d", n); fieldssize = n; } fr = fields; i = 0; /* number of fields accumulated here */ + if (inputFS == NULL) /* make sure we have a copy of FS */ + savefs(); if (strlen(inputFS) > 1) { /* it's a regular expression */ i = refldbld(r, inputFS); } else if ((sep = *inputFS) == ' ') { /* default whitespace */ @@ -390,9 +407,11 @@ void fldbld(void) /* create fields from current record */ lastfld = i; donefld = true; for (j = 1; j <= lastfld; j++) { + double result; + p = fldtab[j]; - if(is_number(p->sval)) { - p->fval = atof(p->sval); + if(is_number(p->sval, & result)) { + p->fval = result; p->tval |= NUM; } } @@ -461,8 +480,8 @@ void growfldtab(int n) /* make new fields up to at least $n */ if (n > nf) nf = n; s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */ - if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */ - fldtab = realloc(fldtab, s); + if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */ + fldtab = (Cell **) realloc(fldtab, s); else /* overflow sizeof int */ xfree(fldtab); /* make it null */ if (fldtab == NULL) @@ -482,7 +501,7 @@ int refldbld(const char *rec, const char *fs) /* build fields from reg expr in F n = strlen(rec); if (n > fieldssize) { xfree(fields); - if ((fields = malloc(n+1)) == NULL) + if ((fields = (char *) malloc(n+1)) == NULL) FATAL("out of space for fields in refldbld %d", n); fieldssize = n; } @@ -491,7 +510,7 @@ int refldbld(const char *rec, const char *fs) /* build fields from reg expr in F if (*rec == '\0') return 0; pfa = makedfa(fs, 1); - dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) ); + DPRINTF("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs); tempstat = pfa->initstat; for (i = 1; ; i++) { if (i > nfields) @@ -500,16 +519,16 @@ int refldbld(const char *rec, const char *fs) /* build fields from reg expr in F xfree(fldtab[i]->sval); fldtab[i]->tval = FLD | STR | DONTFREE; fldtab[i]->sval = fr; - dprintf( ("refldbld: i=%d\n", i) ); + DPRINTF("refldbld: i=%d\n", i); if (nematch(pfa, rec)) { pfa->initstat = 2; /* horrible coupling to b.c */ - dprintf( ("match %s (%d chars)\n", patbeg, patlen) ); + DPRINTF("match %s (%d chars)\n", patbeg, patlen); strncpy(fr, rec, patbeg-rec); fr += patbeg - rec + 1; *(fr-1) = '\0'; rec = patbeg + patlen; } else { - dprintf( ("no match %s\n", rec) ); + DPRINTF("no match %s\n", rec); strcpy(fr, rec); pfa->initstat = tempstat; break; @@ -543,15 +562,15 @@ void recbld(void) /* create $0 from $1..$NF if necessary */ if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3")) FATAL("built giant record `%.30s...'", record); *r = '\0'; - dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) ); + DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]); if (freeable(fldtab[0])) xfree(fldtab[0]->sval); fldtab[0]->tval = REC | STR | DONTFREE; fldtab[0]->sval = record; - dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) ); - dprintf( ("recbld = |%s|\n", record) ); + DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]); + DPRINTF("recbld = |%s|\n", record); donerec = true; } @@ -584,11 +603,6 @@ void SYNTAX(const char *fmt, ...) eprint(); } -void fpecatch(int n) -{ - FATAL("floating point exception %d", n); -} - extern int bracecnt, brackcnt, parencnt; void bracecheck(void) @@ -662,12 +676,11 @@ void error() fprintf(stderr, " source line number %d", curnode->lineno); else if (lineno) fprintf(stderr, " source line number %d", lineno); + if (compile_time == COMPILING && cursource() != NULL) + fprintf(stderr, " source file %s", cursource()); + fprintf(stderr, "\n"); + eprint(); } - - if (compile_time == COMPILING && cursource() != NULL) - fprintf(stderr, " source file %s", cursource()); - fprintf(stderr, "\n"); - eprint(); } void eprint(void) /* try to print context around error */ @@ -751,19 +764,75 @@ int isclvar(const char *s) /* is s of form var=something ? */ /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */ /* wrong: violates 4.10.1.4 of ansi C standard */ -#include <math.h> -int is_number(const char *s) +/* well, not quite. As of C99, hex floating point is allowed. so this is + * a bit of a mess. We work around the mess by checking for a hexadecimal + * value and disallowing it. Similarly, we now follow gawk and allow only + * +nan, -nan, +inf, and -inf for NaN and infinity values. + */ + +/* + * This routine now has a more complicated interface, the main point + * being to avoid the double conversion of a string to double, and + * also to convey out, if requested, the information that the numeric + * value was a leading string or is all of the string. The latter bit + * is used in getfval(). + */ + +bool is_valid_number(const char *s, bool trailing_stuff_ok, + bool *no_trailing, double *result) { double r; char *ep; + bool retval = false; + bool is_nan = false; + bool is_inf = false; + + if (no_trailing) + *no_trailing = false; + + while (isspace(*s)) + s++; + + // no hex floating point, sorry + if (s[0] == '0' && tolower(s[1]) == 'x') + return false; + + // allow +nan, -nan, +inf, -inf, any other letter, no + if (s[0] == '+' || s[0] == '-') { + is_nan = (strncasecmp(s+1, "nan", 3) == 0); + is_inf = (strncasecmp(s+1, "inf", 3) == 0); + if ((is_nan || is_inf) + && (isspace(s[4]) || s[4] == '\0')) + goto convert; + else if (! isdigit(s[1]) && s[1] != '.') + return false; + } + else if (! isdigit(s[0]) && s[0] != '.') + return false; + +convert: errno = 0; r = strtod(s, &ep); - if (ep == s || r == HUGE_VAL || errno == ERANGE) - return 0; - while (*ep == ' ' || *ep == '\t' || *ep == '\n') + if (ep == s || errno == ERANGE) + return false; + + if (isnan(r) && s[0] == '-' && signbit(r) == 0) + r = -r; + + if (result != NULL) + *result = r; + + /* + * check for trailing stuff + */ + while (isspace(*ep)) ep++; - if (*ep == '\0') - return 1; - else - return 0; + + if (no_trailing != NULL) + *no_trailing = (*ep == '\0'); + + // return true if found the end, or trailing stuff is allowed + retval = *ep == '\0' || trailing_stuff_ok; + + return retval; } |