aboutsummaryrefslogtreecommitdiff
path: root/lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib.c')
-rw-r--r--lib.c179
1 files changed, 124 insertions, 55 deletions
diff --git a/lib.c b/lib.c
index 0485e5a..18adbd2 100644
--- a/lib.c
+++ b/lib.c
@@ -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;
}