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>
2848f09a05SAntonio 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>
3448f09a05SAntonio Huete Jimenez #include <math.h>
354b588458SPeter Avalos #include "awk.h"
364b588458SPeter Avalos
37*ed569bc2SAaron LI extern int u8_nextlen(const char *s);
38*ed569bc2SAaron LI
391d48fce0SDaniel Fojt char EMPTY[] = { '\0' };
404b588458SPeter Avalos FILE *infile = NULL;
411d48fce0SDaniel Fojt bool innew; /* true = infile has not been read by readrec */
421d48fce0SDaniel Fojt char *file = EMPTY;
434b588458SPeter Avalos char *record;
444b588458SPeter Avalos int recsize = RECSIZE;
454b588458SPeter Avalos char *fields;
464b588458SPeter Avalos int fieldssize = RECSIZE;
474b588458SPeter Avalos
484b588458SPeter Avalos Cell **fldtab; /* pointers to Cells */
491d48fce0SDaniel Fojt static size_t len_inputFS = 0;
501d48fce0SDaniel Fojt static char *inputFS = NULL; /* FS at time of input, for field splitting */
514b588458SPeter Avalos
524b588458SPeter Avalos #define MAXFLD 2
534b588458SPeter Avalos int nfields = MAXFLD; /* last allocated slot for $i */
544b588458SPeter Avalos
551d48fce0SDaniel Fojt bool donefld; /* true = implies rec broken into fields */
561d48fce0SDaniel Fojt bool donerec; /* true = record is valid (no flds have changed) */
574b588458SPeter Avalos
584b588458SPeter Avalos int lastfld = 0; /* last used field */
594b588458SPeter Avalos int argno = 1; /* current input argument number */
604b588458SPeter Avalos extern Awkfloat *ARGC;
614b588458SPeter Avalos
621d48fce0SDaniel Fojt static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL, NULL };
631d48fce0SDaniel Fojt static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL, NULL };
644b588458SPeter Avalos
recinit(unsigned int n)654b588458SPeter Avalos void recinit(unsigned int n)
664b588458SPeter Avalos {
6748f09a05SAntonio Huete Jimenez if ( (record = (char *) malloc(n)) == NULL
6848f09a05SAntonio Huete Jimenez || (fields = (char *) malloc(n+1)) == NULL
6948f09a05SAntonio Huete Jimenez || (fldtab = (Cell **) calloc(nfields+2, sizeof(*fldtab))) == NULL
7048f09a05SAntonio Huete Jimenez || (fldtab[0] = (Cell *) malloc(sizeof(**fldtab))) == NULL)
714b588458SPeter Avalos FATAL("out of space for $0 and fields");
721d48fce0SDaniel Fojt *record = '\0';
734b588458SPeter Avalos *fldtab[0] = dollar0;
744b588458SPeter Avalos fldtab[0]->sval = record;
754b588458SPeter Avalos fldtab[0]->nval = tostring("0");
764b588458SPeter Avalos makefields(1, nfields);
774b588458SPeter Avalos }
784b588458SPeter Avalos
makefields(int n1,int n2)794b588458SPeter Avalos void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
804b588458SPeter Avalos {
814b588458SPeter Avalos char temp[50];
824b588458SPeter Avalos int i;
834b588458SPeter Avalos
844b588458SPeter Avalos for (i = n1; i <= n2; i++) {
8548f09a05SAntonio Huete Jimenez fldtab[i] = (Cell *) malloc(sizeof(**fldtab));
864b588458SPeter Avalos if (fldtab[i] == NULL)
874b588458SPeter Avalos FATAL("out of space in makefields %d", i);
884b588458SPeter Avalos *fldtab[i] = dollar1;
891d48fce0SDaniel Fojt snprintf(temp, sizeof(temp), "%d", i);
904b588458SPeter Avalos fldtab[i]->nval = tostring(temp);
914b588458SPeter Avalos }
924b588458SPeter Avalos }
934b588458SPeter Avalos
initgetrec(void)944b588458SPeter Avalos void initgetrec(void)
954b588458SPeter Avalos {
964b588458SPeter Avalos int i;
974b588458SPeter Avalos char *p;
984b588458SPeter Avalos
994b588458SPeter Avalos for (i = 1; i < *ARGC; i++) {
100b12bae18SSascha Wildner p = getargv(i); /* find 1st real filename */
101b12bae18SSascha Wildner if (p == NULL || *p == '\0') { /* deleted or zapped */
102b12bae18SSascha Wildner argno++;
103b12bae18SSascha Wildner continue;
104b12bae18SSascha Wildner }
105b12bae18SSascha Wildner if (!isclvar(p)) {
106b12bae18SSascha Wildner setsval(lookup("FILENAME", symtab), p);
1074b588458SPeter Avalos return;
1084b588458SPeter Avalos }
1094b588458SPeter Avalos setclvar(p); /* a commandline assignment before filename */
1104b588458SPeter Avalos argno++;
1114b588458SPeter Avalos }
1124b588458SPeter Avalos infile = stdin; /* no filenames, so use stdin */
1131d48fce0SDaniel Fojt innew = true;
1144b588458SPeter Avalos }
1154b588458SPeter Avalos
1161d48fce0SDaniel Fojt /*
1171d48fce0SDaniel Fojt * POSIX specifies that fields are supposed to be evaluated as if they were
1181d48fce0SDaniel Fojt * split using the value of FS at the time that the record's value ($0) was
1191d48fce0SDaniel Fojt * read.
1201d48fce0SDaniel Fojt *
1211d48fce0SDaniel Fojt * Since field-splitting is done lazily, we save the current value of FS
1221d48fce0SDaniel Fojt * whenever a new record is read in (implicitly or via getline), or when
1231d48fce0SDaniel Fojt * a new value is assigned to $0.
1241d48fce0SDaniel Fojt */
savefs(void)1251d48fce0SDaniel Fojt void savefs(void)
1261d48fce0SDaniel Fojt {
1271d48fce0SDaniel Fojt size_t len;
1281d48fce0SDaniel Fojt if ((len = strlen(getsval(fsloc))) < len_inputFS) {
1291d48fce0SDaniel Fojt strcpy(inputFS, *FS); /* for subsequent field splitting */
1301d48fce0SDaniel Fojt return;
1311d48fce0SDaniel Fojt }
1324b588458SPeter Avalos
1331d48fce0SDaniel Fojt len_inputFS = len + 1;
13448f09a05SAntonio Huete Jimenez inputFS = (char *) realloc(inputFS, len_inputFS);
1351d48fce0SDaniel Fojt if (inputFS == NULL)
1361d48fce0SDaniel Fojt FATAL("field separator %.10s... is too long", *FS);
1371d48fce0SDaniel Fojt memcpy(inputFS, *FS, len_inputFS);
1381d48fce0SDaniel Fojt }
1391d48fce0SDaniel Fojt
1401d48fce0SDaniel Fojt static bool firsttime = true;
1411d48fce0SDaniel Fojt
getrec(char ** pbuf,int * pbufsize,bool isrecord)1421d48fce0SDaniel Fojt int getrec(char **pbuf, int *pbufsize, bool isrecord) /* get next input record */
1434b588458SPeter Avalos { /* note: cares whether buf == record */
1444b588458SPeter Avalos int c;
1454b588458SPeter Avalos char *buf = *pbuf;
1464b588458SPeter Avalos uschar saveb0;
1474b588458SPeter Avalos int bufsize = *pbufsize, savebufsize = bufsize;
1484b588458SPeter Avalos
1494b588458SPeter Avalos if (firsttime) {
1501d48fce0SDaniel Fojt firsttime = false;
1514b588458SPeter Avalos initgetrec();
1524b588458SPeter Avalos }
153e5e686a0SDaniel Fojt DPRINTF("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
154e5e686a0SDaniel Fojt *RS, *FS, *ARGC, *FILENAME);
1554b588458SPeter Avalos saveb0 = buf[0];
1564b588458SPeter Avalos buf[0] = 0;
1574b588458SPeter Avalos while (argno < *ARGC || infile == stdin) {
158e5e686a0SDaniel Fojt DPRINTF("argno=%d, file=|%s|\n", argno, file);
1594b588458SPeter Avalos if (infile == NULL) { /* have to open a new file */
1604b588458SPeter Avalos file = getargv(argno);
161b12bae18SSascha Wildner if (file == NULL || *file == '\0') { /* deleted or zapped */
1624b588458SPeter Avalos argno++;
1634b588458SPeter Avalos continue;
1644b588458SPeter Avalos }
1654b588458SPeter Avalos if (isclvar(file)) { /* a var=value arg */
1664b588458SPeter Avalos setclvar(file);
1674b588458SPeter Avalos argno++;
1684b588458SPeter Avalos continue;
1694b588458SPeter Avalos }
1704b588458SPeter Avalos *FILENAME = file;
171e5e686a0SDaniel Fojt DPRINTF("opening file %s\n", file);
1724b588458SPeter Avalos if (*file == '-' && *(file+1) == '\0')
1734b588458SPeter Avalos infile = stdin;
1744b588458SPeter Avalos else if ((infile = fopen(file, "r")) == NULL)
1754b588458SPeter Avalos FATAL("can't open file %s", file);
17648f09a05SAntonio Huete Jimenez innew = true;
1774b588458SPeter Avalos setfval(fnrloc, 0.0);
1784b588458SPeter Avalos }
1791d48fce0SDaniel Fojt c = readrec(&buf, &bufsize, infile, innew);
1801d48fce0SDaniel Fojt if (innew)
1811d48fce0SDaniel Fojt innew = false;
1824b588458SPeter Avalos if (c != 0 || buf[0] != '\0') { /* normal record */
1834b588458SPeter Avalos if (isrecord) {
18448f09a05SAntonio Huete Jimenez double result;
18548f09a05SAntonio Huete Jimenez
1864b588458SPeter Avalos if (freeable(fldtab[0]))
1874b588458SPeter Avalos xfree(fldtab[0]->sval);
1884b588458SPeter Avalos fldtab[0]->sval = buf; /* buf == record */
1894b588458SPeter Avalos fldtab[0]->tval = REC | STR | DONTFREE;
19048f09a05SAntonio Huete Jimenez if (is_number(fldtab[0]->sval, & result)) {
19148f09a05SAntonio Huete Jimenez fldtab[0]->fval = result;
1924b588458SPeter Avalos fldtab[0]->tval |= NUM;
1934b588458SPeter Avalos }
194*ed569bc2SAaron LI donefld = false;
195*ed569bc2SAaron LI donerec = true;
196*ed569bc2SAaron LI savefs();
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
nextfile(void)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
224*ed569bc2SAaron LI extern int readcsvrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag);
225*ed569bc2SAaron LI
readrec(char ** pbuf,int * pbufsize,FILE * inf,bool newflag)2261d48fce0SDaniel Fojt int readrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag) /* read one record into buf */
2274b588458SPeter Avalos {
228*ed569bc2SAaron LI int sep, c, isrec; // POTENTIAL BUG? isrec is a macro in awk.h
229*ed569bc2SAaron LI char *rr = *pbuf, *buf = *pbuf;
2304b588458SPeter Avalos int bufsize = *pbufsize;
2311d48fce0SDaniel Fojt char *rs = getsval(rsloc);
2324b588458SPeter Avalos
233*ed569bc2SAaron LI if (CSV) {
234*ed569bc2SAaron LI c = readcsvrec(pbuf, pbufsize, inf, newflag);
235*ed569bc2SAaron LI isrec = (c == EOF && rr == buf) ? false : true;
236*ed569bc2SAaron LI } else if (*rs && rs[1]) {
2371d48fce0SDaniel Fojt bool found;
2381d48fce0SDaniel Fojt
239*ed569bc2SAaron LI memset(buf, 0, bufsize);
2401d48fce0SDaniel Fojt fa *pfa = makedfa(rs, 1);
2411d48fce0SDaniel Fojt if (newflag)
2421d48fce0SDaniel Fojt found = fnematch(pfa, inf, &buf, &bufsize, recsize);
2431d48fce0SDaniel Fojt else {
2441d48fce0SDaniel Fojt int tempstat = pfa->initstat;
2451d48fce0SDaniel Fojt pfa->initstat = 2;
2461d48fce0SDaniel Fojt found = fnematch(pfa, inf, &buf, &bufsize, recsize);
2471d48fce0SDaniel Fojt pfa->initstat = tempstat;
2481d48fce0SDaniel Fojt }
2491d48fce0SDaniel Fojt if (found)
2501d48fce0SDaniel Fojt setptr(patbeg, '\0');
25148f09a05SAntonio Huete Jimenez isrec = (found == 0 && *buf == '\0') ? false : true;
252*ed569bc2SAaron LI
2531d48fce0SDaniel Fojt } else {
2541d48fce0SDaniel Fojt if ((sep = *rs) == 0) {
2554b588458SPeter Avalos sep = '\n';
2564b588458SPeter Avalos while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
2574b588458SPeter Avalos ;
2584b588458SPeter Avalos if (c != EOF)
2594b588458SPeter Avalos ungetc(c, inf);
2604b588458SPeter Avalos }
2614b588458SPeter Avalos for (rr = buf; ; ) {
2624b588458SPeter Avalos for (; (c=getc(inf)) != sep && c != EOF; ) {
2634b588458SPeter Avalos if (rr-buf+1 > bufsize)
2641d48fce0SDaniel Fojt if (!adjbuf(&buf, &bufsize, 1+rr-buf,
2651d48fce0SDaniel Fojt recsize, &rr, "readrec 1"))
2664b588458SPeter Avalos FATAL("input record `%.30s...' too long", buf);
2674b588458SPeter Avalos *rr++ = c;
2684b588458SPeter Avalos }
2691d48fce0SDaniel Fojt if (*rs == sep || c == EOF)
2704b588458SPeter Avalos break;
2714b588458SPeter Avalos if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
2724b588458SPeter Avalos break;
2731d48fce0SDaniel Fojt if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr,
2741d48fce0SDaniel Fojt "readrec 2"))
2754b588458SPeter Avalos FATAL("input record `%.30s...' too long", buf);
2764b588458SPeter Avalos *rr++ = '\n';
2774b588458SPeter Avalos *rr++ = c;
2784b588458SPeter Avalos }
2794b588458SPeter Avalos if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
2804b588458SPeter Avalos FATAL("input record `%.30s...' too long", buf);
2814b588458SPeter Avalos *rr = 0;
28248f09a05SAntonio Huete Jimenez isrec = (c == EOF && rr == buf) ? false : true;
2831d48fce0SDaniel Fojt }
2844b588458SPeter Avalos *pbuf = buf;
2854b588458SPeter Avalos *pbufsize = bufsize;
286e5e686a0SDaniel Fojt DPRINTF("readrec saw <%s>, returns %d\n", buf, isrec);
2871d48fce0SDaniel Fojt return isrec;
2884b588458SPeter Avalos }
2894b588458SPeter Avalos
290*ed569bc2SAaron LI
291*ed569bc2SAaron LI /*******************
292*ed569bc2SAaron LI * loose ends here:
293*ed569bc2SAaron LI * \r\n should become \n
294*ed569bc2SAaron LI * what about bare \r? Excel uses that for embedded newlines
295*ed569bc2SAaron LI * can't have "" in unquoted fields, according to RFC 4180
296*ed569bc2SAaron LI */
297*ed569bc2SAaron LI
298*ed569bc2SAaron LI
readcsvrec(char ** pbuf,int * pbufsize,FILE * inf,bool newflag)299*ed569bc2SAaron LI int readcsvrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag) /* csv can have \n's */
300*ed569bc2SAaron LI { /* so read a complete record that might be multiple lines */
301*ed569bc2SAaron LI int sep, c;
302*ed569bc2SAaron LI char *rr = *pbuf, *buf = *pbuf;
303*ed569bc2SAaron LI int bufsize = *pbufsize;
304*ed569bc2SAaron LI bool in_quote = false;
305*ed569bc2SAaron LI
306*ed569bc2SAaron LI sep = '\n'; /* the only separator; have to skip over \n embedded in "..." */
307*ed569bc2SAaron LI rr = buf;
308*ed569bc2SAaron LI while ((c = getc(inf)) != EOF) {
309*ed569bc2SAaron LI if (c == sep) {
310*ed569bc2SAaron LI if (! in_quote)
311*ed569bc2SAaron LI break;
312*ed569bc2SAaron LI if (rr > buf && rr[-1] == '\r') // remove \r if was \r\n
313*ed569bc2SAaron LI rr--;
314*ed569bc2SAaron LI }
315*ed569bc2SAaron LI
316*ed569bc2SAaron LI if (rr-buf+1 > bufsize)
317*ed569bc2SAaron LI if (!adjbuf(&buf, &bufsize, 1+rr-buf,
318*ed569bc2SAaron LI recsize, &rr, "readcsvrec 1"))
319*ed569bc2SAaron LI FATAL("input record `%.30s...' too long", buf);
320*ed569bc2SAaron LI *rr++ = c;
321*ed569bc2SAaron LI if (c == '"')
322*ed569bc2SAaron LI in_quote = ! in_quote;
323*ed569bc2SAaron LI }
324*ed569bc2SAaron LI if (c == '\n' && rr > buf && rr[-1] == '\r') // remove \r if was \r\n
325*ed569bc2SAaron LI rr--;
326*ed569bc2SAaron LI
327*ed569bc2SAaron LI if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readcsvrec 4"))
328*ed569bc2SAaron LI FATAL("input record `%.30s...' too long", buf);
329*ed569bc2SAaron LI *rr = 0;
330*ed569bc2SAaron LI *pbuf = buf;
331*ed569bc2SAaron LI *pbufsize = bufsize;
332*ed569bc2SAaron LI DPRINTF("readcsvrec saw <%s>, returns %d\n", buf, c);
333*ed569bc2SAaron LI return c;
334*ed569bc2SAaron LI }
335*ed569bc2SAaron LI
getargv(int n)3364b588458SPeter Avalos char *getargv(int n) /* get ARGV[n] */
3374b588458SPeter Avalos {
3384b588458SPeter Avalos Cell *x;
3394b588458SPeter Avalos char *s, temp[50];
3404b588458SPeter Avalos extern Array *ARGVtab;
3414b588458SPeter Avalos
3421d48fce0SDaniel Fojt snprintf(temp, sizeof(temp), "%d", n);
343b12bae18SSascha Wildner if (lookup(temp, ARGVtab) == NULL)
344b12bae18SSascha Wildner return NULL;
3454b588458SPeter Avalos x = setsymtab(temp, "", 0.0, STR, ARGVtab);
3464b588458SPeter Avalos s = getsval(x);
347e5e686a0SDaniel Fojt DPRINTF("getargv(%d) returns |%s|\n", n, s);
3484b588458SPeter Avalos return s;
3494b588458SPeter Avalos }
3504b588458SPeter Avalos
setclvar(char * s)3514b588458SPeter Avalos void setclvar(char *s) /* set var=value from s */
3524b588458SPeter Avalos {
35348f09a05SAntonio Huete Jimenez char *e, *p;
3544b588458SPeter Avalos Cell *q;
35548f09a05SAntonio Huete Jimenez double result;
3564b588458SPeter Avalos
357*ed569bc2SAaron LI /* commit f3d9187d4e0f02294fb1b0e31152070506314e67 broke T.argv test */
358*ed569bc2SAaron LI /* I don't understand why it was changed. */
359*ed569bc2SAaron LI
3604b588458SPeter Avalos for (p=s; *p != '='; p++)
3614b588458SPeter Avalos ;
36248f09a05SAntonio Huete Jimenez e = p;
3634b588458SPeter Avalos *p++ = 0;
3644b588458SPeter Avalos p = qstring(p, '\0');
3654b588458SPeter Avalos q = setsymtab(s, p, 0.0, STR, symtab);
3664b588458SPeter Avalos setsval(q, p);
36748f09a05SAntonio Huete Jimenez if (is_number(q->sval, & result)) {
36848f09a05SAntonio Huete Jimenez q->fval = result;
3694b588458SPeter Avalos q->tval |= NUM;
3704b588458SPeter Avalos }
371e5e686a0SDaniel Fojt DPRINTF("command line set %s to |%s|\n", s, p);
37248f09a05SAntonio Huete Jimenez free(p);
37348f09a05SAntonio Huete Jimenez *e = '=';
3744b588458SPeter Avalos }
3754b588458SPeter Avalos
3764b588458SPeter Avalos
fldbld(void)3774b588458SPeter Avalos void fldbld(void) /* create fields from current record */
3784b588458SPeter Avalos {
3794b588458SPeter Avalos /* this relies on having fields[] the same length as $0 */
3804b588458SPeter Avalos /* the fields are all stored in this one array with \0's */
3810020174dSPeter Avalos /* possibly with a final trailing \0 not associated with any field */
3824b588458SPeter Avalos char *r, *fr, sep;
3834b588458SPeter Avalos Cell *p;
3844b588458SPeter Avalos int i, j, n;
3854b588458SPeter Avalos
3864b588458SPeter Avalos if (donefld)
3874b588458SPeter Avalos return;
3884b588458SPeter Avalos if (!isstr(fldtab[0]))
3894b588458SPeter Avalos getsval(fldtab[0]);
3904b588458SPeter Avalos r = fldtab[0]->sval;
3914b588458SPeter Avalos n = strlen(r);
3924b588458SPeter Avalos if (n > fieldssize) {
3934b588458SPeter Avalos xfree(fields);
39448f09a05SAntonio Huete Jimenez if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
3954b588458SPeter Avalos FATAL("out of space for fields in fldbld %d", n);
3964b588458SPeter Avalos fieldssize = n;
3974b588458SPeter Avalos }
3984b588458SPeter Avalos fr = fields;
3994b588458SPeter Avalos i = 0; /* number of fields accumulated here */
4001d48fce0SDaniel Fojt if (inputFS == NULL) /* make sure we have a copy of FS */
4011d48fce0SDaniel Fojt savefs();
402*ed569bc2SAaron LI if (!CSV && strlen(inputFS) > 1) { /* it's a regular expression */
4034b588458SPeter Avalos i = refldbld(r, inputFS);
404*ed569bc2SAaron LI } else if (!CSV && (sep = *inputFS) == ' ') { /* default whitespace */
4054b588458SPeter Avalos for (i = 0; ; ) {
4064b588458SPeter Avalos while (*r == ' ' || *r == '\t' || *r == '\n')
4074b588458SPeter Avalos r++;
4084b588458SPeter Avalos if (*r == 0)
4094b588458SPeter Avalos break;
4104b588458SPeter Avalos i++;
4114b588458SPeter Avalos if (i > nfields)
4124b588458SPeter Avalos growfldtab(i);
4134b588458SPeter Avalos if (freeable(fldtab[i]))
4144b588458SPeter Avalos xfree(fldtab[i]->sval);
4154b588458SPeter Avalos fldtab[i]->sval = fr;
4164b588458SPeter Avalos fldtab[i]->tval = FLD | STR | DONTFREE;
4174b588458SPeter Avalos do
4184b588458SPeter Avalos *fr++ = *r++;
4194b588458SPeter Avalos while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
4204b588458SPeter Avalos *fr++ = 0;
4214b588458SPeter Avalos }
4224b588458SPeter Avalos *fr = 0;
423*ed569bc2SAaron LI } else if (CSV) { /* CSV processing. no error handling */
424*ed569bc2SAaron LI if (*r != 0) {
425*ed569bc2SAaron LI for (;;) {
4264b588458SPeter Avalos i++;
4274b588458SPeter Avalos if (i > nfields)
4284b588458SPeter Avalos growfldtab(i);
4294b588458SPeter Avalos if (freeable(fldtab[i]))
4304b588458SPeter Avalos xfree(fldtab[i]->sval);
431*ed569bc2SAaron LI fldtab[i]->sval = fr;
432*ed569bc2SAaron LI fldtab[i]->tval = FLD | STR | DONTFREE;
433*ed569bc2SAaron LI if (*r == '"' ) { /* start of "..." */
434*ed569bc2SAaron LI for (r++ ; *r != '\0'; ) {
435*ed569bc2SAaron LI if (*r == '"' && r[1] != '\0' && r[1] == '"') {
436*ed569bc2SAaron LI r += 2; /* doubled quote */
437*ed569bc2SAaron LI *fr++ = '"';
438*ed569bc2SAaron LI } else if (*r == '"' && (r[1] == '\0' || r[1] == ',')) {
439*ed569bc2SAaron LI r++; /* skip over closing quote */
440*ed569bc2SAaron LI break;
441*ed569bc2SAaron LI } else {
442*ed569bc2SAaron LI *fr++ = *r++;
443*ed569bc2SAaron LI }
444*ed569bc2SAaron LI }
445*ed569bc2SAaron LI *fr++ = 0;
446*ed569bc2SAaron LI } else { /* unquoted field */
447*ed569bc2SAaron LI while (*r != ',' && *r != '\0')
448*ed569bc2SAaron LI *fr++ = *r++;
449*ed569bc2SAaron LI *fr++ = 0;
450*ed569bc2SAaron LI }
451*ed569bc2SAaron LI if (*r++ == 0)
452*ed569bc2SAaron LI break;
453*ed569bc2SAaron LI
454*ed569bc2SAaron LI }
455*ed569bc2SAaron LI }
456*ed569bc2SAaron LI *fr = 0;
457*ed569bc2SAaron LI } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
458*ed569bc2SAaron LI for (i = 0; *r != '\0'; ) {
459*ed569bc2SAaron LI char buf[10];
460*ed569bc2SAaron LI i++;
461*ed569bc2SAaron LI if (i > nfields)
462*ed569bc2SAaron LI growfldtab(i);
463*ed569bc2SAaron LI if (freeable(fldtab[i]))
464*ed569bc2SAaron LI xfree(fldtab[i]->sval);
465*ed569bc2SAaron LI n = u8_nextlen(r);
466*ed569bc2SAaron LI for (j = 0; j < n; j++)
467*ed569bc2SAaron LI buf[j] = *r++;
468*ed569bc2SAaron LI buf[j] = '\0';
4694b588458SPeter Avalos fldtab[i]->sval = tostring(buf);
4704b588458SPeter Avalos fldtab[i]->tval = FLD | STR;
4714b588458SPeter Avalos }
4724b588458SPeter Avalos *fr = 0;
4734b588458SPeter Avalos } else if (*r != 0) { /* if 0, it's a null field */
4744b588458SPeter Avalos /* subtle case: if length(FS) == 1 && length(RS > 0)
4754b588458SPeter Avalos * \n is NOT a field separator (cf awk book 61,84).
4764b588458SPeter Avalos * this variable is tested in the inner while loop.
4774b588458SPeter Avalos */
4784b588458SPeter Avalos int rtest = '\n'; /* normal case */
4794b588458SPeter Avalos if (strlen(*RS) > 0)
4804b588458SPeter Avalos rtest = '\0';
4814b588458SPeter Avalos for (;;) {
4824b588458SPeter Avalos i++;
4834b588458SPeter Avalos if (i > nfields)
4844b588458SPeter Avalos growfldtab(i);
4854b588458SPeter Avalos if (freeable(fldtab[i]))
4864b588458SPeter Avalos xfree(fldtab[i]->sval);
4874b588458SPeter Avalos fldtab[i]->sval = fr;
4884b588458SPeter Avalos fldtab[i]->tval = FLD | STR | DONTFREE;
4894b588458SPeter Avalos while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */
4904b588458SPeter Avalos *fr++ = *r++;
4914b588458SPeter Avalos *fr++ = 0;
4924b588458SPeter Avalos if (*r++ == 0)
4934b588458SPeter Avalos break;
4944b588458SPeter Avalos }
4954b588458SPeter Avalos *fr = 0;
4964b588458SPeter Avalos }
4974b588458SPeter Avalos if (i > nfields)
4984b588458SPeter Avalos FATAL("record `%.30s...' has too many fields; can't happen", r);
4994b588458SPeter Avalos cleanfld(i+1, lastfld); /* clean out junk from previous record */
5004b588458SPeter Avalos lastfld = i;
5011d48fce0SDaniel Fojt donefld = true;
5024b588458SPeter Avalos for (j = 1; j <= lastfld; j++) {
50348f09a05SAntonio Huete Jimenez double result;
50448f09a05SAntonio Huete Jimenez
5054b588458SPeter Avalos p = fldtab[j];
50648f09a05SAntonio Huete Jimenez if(is_number(p->sval, & result)) {
50748f09a05SAntonio Huete Jimenez p->fval = result;
5084b588458SPeter Avalos p->tval |= NUM;
5094b588458SPeter Avalos }
5104b588458SPeter Avalos }
5114b588458SPeter Avalos setfval(nfloc, (Awkfloat) lastfld);
5121d48fce0SDaniel Fojt donerec = true; /* restore */
5134b588458SPeter Avalos if (dbg) {
5144b588458SPeter Avalos for (j = 0; j <= lastfld; j++) {
5154b588458SPeter Avalos p = fldtab[j];
5164b588458SPeter Avalos printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
5174b588458SPeter Avalos }
5184b588458SPeter Avalos }
5194b588458SPeter Avalos }
5204b588458SPeter Avalos
cleanfld(int n1,int n2)5214b588458SPeter Avalos void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
5224b588458SPeter Avalos { /* nvals remain intact */
5234b588458SPeter Avalos Cell *p;
5244b588458SPeter Avalos int i;
5254b588458SPeter Avalos
5264b588458SPeter Avalos for (i = n1; i <= n2; i++) {
5274b588458SPeter Avalos p = fldtab[i];
5284b588458SPeter Avalos if (freeable(p))
5294b588458SPeter Avalos xfree(p->sval);
5301d48fce0SDaniel Fojt p->sval = EMPTY,
5314b588458SPeter Avalos p->tval = FLD | STR | DONTFREE;
5324b588458SPeter Avalos }
5334b588458SPeter Avalos }
5344b588458SPeter Avalos
newfld(int n)5354b588458SPeter Avalos void newfld(int n) /* add field n after end of existing lastfld */
5364b588458SPeter Avalos {
5374b588458SPeter Avalos if (n > nfields)
5384b588458SPeter Avalos growfldtab(n);
5394b588458SPeter Avalos cleanfld(lastfld+1, n);
5404b588458SPeter Avalos lastfld = n;
5414b588458SPeter Avalos setfval(nfloc, (Awkfloat) n);
5424b588458SPeter Avalos }
5434b588458SPeter Avalos
setlastfld(int n)5441d48fce0SDaniel Fojt void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */
5451d48fce0SDaniel Fojt {
5461d48fce0SDaniel Fojt if (n < 0)
5471d48fce0SDaniel Fojt FATAL("cannot set NF to a negative value");
5481d48fce0SDaniel Fojt if (n > nfields)
5491d48fce0SDaniel Fojt growfldtab(n);
5501d48fce0SDaniel Fojt
5511d48fce0SDaniel Fojt if (lastfld < n)
5521d48fce0SDaniel Fojt cleanfld(lastfld+1, n);
5531d48fce0SDaniel Fojt else
5541d48fce0SDaniel Fojt cleanfld(n+1, lastfld);
5551d48fce0SDaniel Fojt
5561d48fce0SDaniel Fojt lastfld = n;
5571d48fce0SDaniel Fojt }
5581d48fce0SDaniel Fojt
fieldadr(int n)5594b588458SPeter Avalos Cell *fieldadr(int n) /* get nth field */
5604b588458SPeter Avalos {
5614b588458SPeter Avalos if (n < 0)
5624b588458SPeter Avalos FATAL("trying to access out of range field %d", n);
5634b588458SPeter Avalos if (n > nfields) /* fields after NF are empty */
5644b588458SPeter Avalos growfldtab(n); /* but does not increase NF */
5654b588458SPeter Avalos return(fldtab[n]);
5664b588458SPeter Avalos }
5674b588458SPeter Avalos
growfldtab(int n)5684b588458SPeter Avalos void growfldtab(int n) /* make new fields up to at least $n */
5694b588458SPeter Avalos {
5704b588458SPeter Avalos int nf = 2 * nfields;
5714b588458SPeter Avalos size_t s;
5724b588458SPeter Avalos
5734b588458SPeter Avalos if (n > nf)
5744b588458SPeter Avalos nf = n;
5754b588458SPeter Avalos s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
5761d48fce0SDaniel Fojt if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
57748f09a05SAntonio Huete Jimenez fldtab = (Cell **) realloc(fldtab, s);
5784b588458SPeter Avalos else /* overflow sizeof int */
5794b588458SPeter Avalos xfree(fldtab); /* make it null */
5804b588458SPeter Avalos if (fldtab == NULL)
5814b588458SPeter Avalos FATAL("out of space creating %d fields", nf);
5824b588458SPeter Avalos makefields(nfields+1, nf);
5834b588458SPeter Avalos nfields = nf;
5844b588458SPeter Avalos }
5854b588458SPeter Avalos
refldbld(const char * rec,const char * fs)5864b588458SPeter Avalos int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */
5874b588458SPeter Avalos {
5884b588458SPeter Avalos /* this relies on having fields[] the same length as $0 */
5894b588458SPeter Avalos /* the fields are all stored in this one array with \0's */
5904b588458SPeter Avalos char *fr;
5914b588458SPeter Avalos int i, tempstat, n;
5924b588458SPeter Avalos fa *pfa;
5934b588458SPeter Avalos
5944b588458SPeter Avalos n = strlen(rec);
5954b588458SPeter Avalos if (n > fieldssize) {
5964b588458SPeter Avalos xfree(fields);
59748f09a05SAntonio Huete Jimenez if ((fields = (char *) malloc(n+1)) == NULL)
5984b588458SPeter Avalos FATAL("out of space for fields in refldbld %d", n);
5994b588458SPeter Avalos fieldssize = n;
6004b588458SPeter Avalos }
6014b588458SPeter Avalos fr = fields;
6024b588458SPeter Avalos *fr = '\0';
6034b588458SPeter Avalos if (*rec == '\0')
6044b588458SPeter Avalos return 0;
6054b588458SPeter Avalos pfa = makedfa(fs, 1);
606e5e686a0SDaniel Fojt DPRINTF("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs);
6074b588458SPeter Avalos tempstat = pfa->initstat;
6084b588458SPeter Avalos for (i = 1; ; i++) {
6094b588458SPeter Avalos if (i > nfields)
6104b588458SPeter Avalos growfldtab(i);
6114b588458SPeter Avalos if (freeable(fldtab[i]))
6124b588458SPeter Avalos xfree(fldtab[i]->sval);
6134b588458SPeter Avalos fldtab[i]->tval = FLD | STR | DONTFREE;
6144b588458SPeter Avalos fldtab[i]->sval = fr;
615e5e686a0SDaniel Fojt DPRINTF("refldbld: i=%d\n", i);
6164b588458SPeter Avalos if (nematch(pfa, rec)) {
6174b588458SPeter Avalos pfa->initstat = 2; /* horrible coupling to b.c */
618e5e686a0SDaniel Fojt DPRINTF("match %s (%d chars)\n", patbeg, patlen);
6194b588458SPeter Avalos strncpy(fr, rec, patbeg-rec);
6204b588458SPeter Avalos fr += patbeg - rec + 1;
6214b588458SPeter Avalos *(fr-1) = '\0';
6224b588458SPeter Avalos rec = patbeg + patlen;
6234b588458SPeter Avalos } else {
624e5e686a0SDaniel Fojt DPRINTF("no match %s\n", rec);
6254b588458SPeter Avalos strcpy(fr, rec);
6264b588458SPeter Avalos pfa->initstat = tempstat;
6274b588458SPeter Avalos break;
6284b588458SPeter Avalos }
6294b588458SPeter Avalos }
6304b588458SPeter Avalos return i;
6314b588458SPeter Avalos }
6324b588458SPeter Avalos
recbld(void)6334b588458SPeter Avalos void recbld(void) /* create $0 from $1..$NF if necessary */
6344b588458SPeter Avalos {
6354b588458SPeter Avalos int i;
6364b588458SPeter Avalos char *r, *p;
6371d48fce0SDaniel Fojt char *sep = getsval(ofsloc);
6384b588458SPeter Avalos
6391d48fce0SDaniel Fojt if (donerec)
6404b588458SPeter Avalos return;
6414b588458SPeter Avalos r = record;
6424b588458SPeter Avalos for (i = 1; i <= *NF; i++) {
6434b588458SPeter Avalos p = getsval(fldtab[i]);
6444b588458SPeter Avalos if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
6454b588458SPeter Avalos FATAL("created $0 `%.30s...' too long", record);
6464b588458SPeter Avalos while ((*r = *p++) != 0)
6474b588458SPeter Avalos r++;
6484b588458SPeter Avalos if (i < *NF) {
6491d48fce0SDaniel Fojt if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2"))
6504b588458SPeter Avalos FATAL("created $0 `%.30s...' too long", record);
6511d48fce0SDaniel Fojt for (p = sep; (*r = *p++) != 0; )
6524b588458SPeter Avalos r++;
6534b588458SPeter Avalos }
6544b588458SPeter Avalos }
6554b588458SPeter Avalos if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
6564b588458SPeter Avalos FATAL("built giant record `%.30s...'", record);
6574b588458SPeter Avalos *r = '\0';
658e5e686a0SDaniel Fojt DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]);
6594b588458SPeter Avalos
6604b588458SPeter Avalos if (freeable(fldtab[0]))
6614b588458SPeter Avalos xfree(fldtab[0]->sval);
6624b588458SPeter Avalos fldtab[0]->tval = REC | STR | DONTFREE;
6634b588458SPeter Avalos fldtab[0]->sval = record;
6644b588458SPeter Avalos
665e5e686a0SDaniel Fojt DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]);
666e5e686a0SDaniel Fojt DPRINTF("recbld = |%s|\n", record);
6671d48fce0SDaniel Fojt donerec = true;
6684b588458SPeter Avalos }
6694b588458SPeter Avalos
6704b588458SPeter Avalos int errorflag = 0;
6714b588458SPeter Avalos
yyerror(const char * s)6724b588458SPeter Avalos void yyerror(const char *s)
6734b588458SPeter Avalos {
6744b588458SPeter Avalos SYNTAX("%s", s);
6754b588458SPeter Avalos }
6764b588458SPeter Avalos
SYNTAX(const char * fmt,...)6774b588458SPeter Avalos void SYNTAX(const char *fmt, ...)
6784b588458SPeter Avalos {
6794b588458SPeter Avalos extern char *cmdname, *curfname;
6804b588458SPeter Avalos static int been_here = 0;
6814b588458SPeter Avalos va_list varg;
6824b588458SPeter Avalos
6834b588458SPeter Avalos if (been_here++ > 2)
6844b588458SPeter Avalos return;
6854b588458SPeter Avalos fprintf(stderr, "%s: ", cmdname);
6864b588458SPeter Avalos va_start(varg, fmt);
6874b588458SPeter Avalos vfprintf(stderr, fmt, varg);
6884b588458SPeter Avalos va_end(varg);
6894b588458SPeter Avalos fprintf(stderr, " at source line %d", lineno);
6904b588458SPeter Avalos if (curfname != NULL)
6914b588458SPeter Avalos fprintf(stderr, " in function %s", curfname);
6921d48fce0SDaniel Fojt if (compile_time == COMPILING && cursource() != NULL)
6934b588458SPeter Avalos fprintf(stderr, " source file %s", cursource());
6944b588458SPeter Avalos fprintf(stderr, "\n");
6954b588458SPeter Avalos errorflag = 2;
6964b588458SPeter Avalos eprint();
6974b588458SPeter Avalos }
6984b588458SPeter Avalos
6994b588458SPeter Avalos extern int bracecnt, brackcnt, parencnt;
7004b588458SPeter Avalos
bracecheck(void)7014b588458SPeter Avalos void bracecheck(void)
7024b588458SPeter Avalos {
7034b588458SPeter Avalos int c;
7044b588458SPeter Avalos static int beenhere = 0;
7054b588458SPeter Avalos
7064b588458SPeter Avalos if (beenhere++)
7074b588458SPeter Avalos return;
7084b588458SPeter Avalos while ((c = input()) != EOF && c != '\0')
7094b588458SPeter Avalos bclass(c);
7104b588458SPeter Avalos bcheck2(bracecnt, '{', '}');
7114b588458SPeter Avalos bcheck2(brackcnt, '[', ']');
7124b588458SPeter Avalos bcheck2(parencnt, '(', ')');
7134b588458SPeter Avalos }
7144b588458SPeter Avalos
bcheck2(int n,int c1,int c2)7154b588458SPeter Avalos void bcheck2(int n, int c1, int c2)
7164b588458SPeter Avalos {
7174b588458SPeter Avalos if (n == 1)
7184b588458SPeter Avalos fprintf(stderr, "\tmissing %c\n", c2);
7194b588458SPeter Avalos else if (n > 1)
7204b588458SPeter Avalos fprintf(stderr, "\t%d missing %c's\n", n, c2);
7214b588458SPeter Avalos else if (n == -1)
7224b588458SPeter Avalos fprintf(stderr, "\textra %c\n", c2);
7234b588458SPeter Avalos else if (n < -1)
7244b588458SPeter Avalos fprintf(stderr, "\t%d extra %c's\n", -n, c2);
7254b588458SPeter Avalos }
7264b588458SPeter Avalos
FATAL(const char * fmt,...)7274b588458SPeter Avalos void FATAL(const char *fmt, ...)
7284b588458SPeter Avalos {
7294b588458SPeter Avalos extern char *cmdname;
7304b588458SPeter Avalos va_list varg;
7314b588458SPeter Avalos
7324b588458SPeter Avalos fflush(stdout);
7334b588458SPeter Avalos fprintf(stderr, "%s: ", cmdname);
7344b588458SPeter Avalos va_start(varg, fmt);
7354b588458SPeter Avalos vfprintf(stderr, fmt, varg);
7364b588458SPeter Avalos va_end(varg);
7374b588458SPeter Avalos error();
7384b588458SPeter Avalos if (dbg > 1) /* core dump if serious debugging on */
7394b588458SPeter Avalos abort();
7404b588458SPeter Avalos exit(2);
7414b588458SPeter Avalos }
7424b588458SPeter Avalos
WARNING(const char * fmt,...)7434b588458SPeter Avalos void WARNING(const char *fmt, ...)
7444b588458SPeter Avalos {
7454b588458SPeter Avalos extern char *cmdname;
7464b588458SPeter Avalos va_list varg;
7474b588458SPeter Avalos
7484b588458SPeter Avalos fflush(stdout);
7494b588458SPeter Avalos fprintf(stderr, "%s: ", cmdname);
7504b588458SPeter Avalos va_start(varg, fmt);
7514b588458SPeter Avalos vfprintf(stderr, fmt, varg);
7524b588458SPeter Avalos va_end(varg);
7534b588458SPeter Avalos error();
7544b588458SPeter Avalos }
7554b588458SPeter Avalos
error()7564b588458SPeter Avalos void error()
7574b588458SPeter Avalos {
7584b588458SPeter Avalos extern Node *curnode;
7594b588458SPeter Avalos
7604b588458SPeter Avalos fprintf(stderr, "\n");
7611d48fce0SDaniel Fojt if (compile_time != ERROR_PRINTING) {
7621d48fce0SDaniel Fojt if (NR && *NR > 0) {
7634b588458SPeter Avalos fprintf(stderr, " input record number %d", (int) (*FNR));
7644b588458SPeter Avalos if (strcmp(*FILENAME, "-") != 0)
7654b588458SPeter Avalos fprintf(stderr, ", file %s", *FILENAME);
7664b588458SPeter Avalos fprintf(stderr, "\n");
7674b588458SPeter Avalos }
7681d48fce0SDaniel Fojt if (curnode)
7694b588458SPeter Avalos fprintf(stderr, " source line number %d", curnode->lineno);
7701d48fce0SDaniel Fojt else if (lineno)
7714b588458SPeter Avalos fprintf(stderr, " source line number %d", lineno);
7721d48fce0SDaniel Fojt if (compile_time == COMPILING && cursource() != NULL)
7734b588458SPeter Avalos fprintf(stderr, " source file %s", cursource());
7744b588458SPeter Avalos fprintf(stderr, "\n");
7754b588458SPeter Avalos eprint();
7764b588458SPeter Avalos }
77748f09a05SAntonio Huete Jimenez }
7784b588458SPeter Avalos
eprint(void)7794b588458SPeter Avalos void eprint(void) /* try to print context around error */
7804b588458SPeter Avalos {
7814b588458SPeter Avalos char *p, *q;
7824b588458SPeter Avalos int c;
7834b588458SPeter Avalos static int been_here = 0;
7844b588458SPeter Avalos extern char ebuf[], *ep;
7854b588458SPeter Avalos
7861d48fce0SDaniel Fojt if (compile_time != COMPILING || been_here++ > 0 || ebuf == ep)
7871d48fce0SDaniel Fojt return;
7881d48fce0SDaniel Fojt if (ebuf == ep)
7894b588458SPeter Avalos return;
7904b588458SPeter Avalos p = ep - 1;
7914b588458SPeter Avalos if (p > ebuf && *p == '\n')
7924b588458SPeter Avalos p--;
7934b588458SPeter Avalos for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
7944b588458SPeter Avalos ;
7954b588458SPeter Avalos while (*p == '\n')
7964b588458SPeter Avalos p++;
7974b588458SPeter Avalos fprintf(stderr, " context is\n\t");
7984b588458SPeter Avalos for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
7994b588458SPeter Avalos ;
8004b588458SPeter Avalos for ( ; p < q; p++)
8014b588458SPeter Avalos if (*p)
8024b588458SPeter Avalos putc(*p, stderr);
8034b588458SPeter Avalos fprintf(stderr, " >>> ");
8044b588458SPeter Avalos for ( ; p < ep; p++)
8054b588458SPeter Avalos if (*p)
8064b588458SPeter Avalos putc(*p, stderr);
8074b588458SPeter Avalos fprintf(stderr, " <<< ");
8084b588458SPeter Avalos if (*ep)
8094b588458SPeter Avalos while ((c = input()) != '\n' && c != '\0' && c != EOF) {
8104b588458SPeter Avalos putc(c, stderr);
8114b588458SPeter Avalos bclass(c);
8124b588458SPeter Avalos }
8134b588458SPeter Avalos putc('\n', stderr);
8144b588458SPeter Avalos ep = ebuf;
8154b588458SPeter Avalos }
8164b588458SPeter Avalos
bclass(int c)8174b588458SPeter Avalos void bclass(int c)
8184b588458SPeter Avalos {
8194b588458SPeter Avalos switch (c) {
8204b588458SPeter Avalos case '{': bracecnt++; break;
8214b588458SPeter Avalos case '}': bracecnt--; break;
8224b588458SPeter Avalos case '[': brackcnt++; break;
8234b588458SPeter Avalos case ']': brackcnt--; break;
8244b588458SPeter Avalos case '(': parencnt++; break;
8254b588458SPeter Avalos case ')': parencnt--; break;
8264b588458SPeter Avalos }
8274b588458SPeter Avalos }
8284b588458SPeter Avalos
errcheck(double x,const char * s)8294b588458SPeter Avalos double errcheck(double x, const char *s)
8304b588458SPeter Avalos {
8314b588458SPeter Avalos
8324b588458SPeter Avalos if (errno == EDOM) {
8334b588458SPeter Avalos errno = 0;
8344b588458SPeter Avalos WARNING("%s argument out of domain", s);
8354b588458SPeter Avalos x = 1;
8364b588458SPeter Avalos } else if (errno == ERANGE) {
8374b588458SPeter Avalos errno = 0;
8384b588458SPeter Avalos WARNING("%s result out of range", s);
8394b588458SPeter Avalos x = 1;
8404b588458SPeter Avalos }
8414b588458SPeter Avalos return x;
8424b588458SPeter Avalos }
8434b588458SPeter Avalos
isclvar(const char * s)8444b588458SPeter Avalos int isclvar(const char *s) /* is s of form var=something ? */
8454b588458SPeter Avalos {
8464b588458SPeter Avalos const char *os = s;
8474b588458SPeter Avalos
848*ed569bc2SAaron LI if (!isalpha((int) *s) && *s != '_')
8494b588458SPeter Avalos return 0;
8504b588458SPeter Avalos for ( ; *s; s++)
851*ed569bc2SAaron LI if (!(isalnum((int) *s) || *s == '_'))
8524b588458SPeter Avalos break;
8531d48fce0SDaniel Fojt return *s == '=' && s > os;
8544b588458SPeter Avalos }
8554b588458SPeter Avalos
8564b588458SPeter Avalos /* strtod is supposed to be a proper test of what's a valid number */
8574b588458SPeter Avalos /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
8584b588458SPeter Avalos /* wrong: violates 4.10.1.4 of ansi C standard */
85948f09a05SAntonio Huete Jimenez
8601d48fce0SDaniel Fojt /* well, not quite. As of C99, hex floating point is allowed. so this is
86148f09a05SAntonio Huete Jimenez * a bit of a mess. We work around the mess by checking for a hexadecimal
86248f09a05SAntonio Huete Jimenez * value and disallowing it. Similarly, we now follow gawk and allow only
86348f09a05SAntonio Huete Jimenez * +nan, -nan, +inf, and -inf for NaN and infinity values.
8641d48fce0SDaniel Fojt */
8654b588458SPeter Avalos
86648f09a05SAntonio Huete Jimenez /*
86748f09a05SAntonio Huete Jimenez * This routine now has a more complicated interface, the main point
86848f09a05SAntonio Huete Jimenez * being to avoid the double conversion of a string to double, and
86948f09a05SAntonio Huete Jimenez * also to convey out, if requested, the information that the numeric
87048f09a05SAntonio Huete Jimenez * value was a leading string or is all of the string. The latter bit
87148f09a05SAntonio Huete Jimenez * is used in getfval().
87248f09a05SAntonio Huete Jimenez */
87348f09a05SAntonio Huete Jimenez
is_valid_number(const char * s,bool trailing_stuff_ok,bool * no_trailing,double * result)87448f09a05SAntonio Huete Jimenez bool is_valid_number(const char *s, bool trailing_stuff_ok,
87548f09a05SAntonio Huete Jimenez bool *no_trailing, double *result)
8764b588458SPeter Avalos {
8774b588458SPeter Avalos double r;
8784b588458SPeter Avalos char *ep;
87948f09a05SAntonio Huete Jimenez bool retval = false;
88048f09a05SAntonio Huete Jimenez bool is_nan = false;
88148f09a05SAntonio Huete Jimenez bool is_inf = false;
88248f09a05SAntonio Huete Jimenez
88348f09a05SAntonio Huete Jimenez if (no_trailing)
88448f09a05SAntonio Huete Jimenez *no_trailing = false;
88548f09a05SAntonio Huete Jimenez
886*ed569bc2SAaron LI while (isspace((int) *s))
88748f09a05SAntonio Huete Jimenez s++;
88848f09a05SAntonio Huete Jimenez
889*ed569bc2SAaron LI /* no hex floating point, sorry */
89048f09a05SAntonio Huete Jimenez if (s[0] == '0' && tolower(s[1]) == 'x')
89148f09a05SAntonio Huete Jimenez return false;
89248f09a05SAntonio Huete Jimenez
893*ed569bc2SAaron LI /* allow +nan, -nan, +inf, -inf, any other letter, no */
89448f09a05SAntonio Huete Jimenez if (s[0] == '+' || s[0] == '-') {
89548f09a05SAntonio Huete Jimenez is_nan = (strncasecmp(s+1, "nan", 3) == 0);
89648f09a05SAntonio Huete Jimenez is_inf = (strncasecmp(s+1, "inf", 3) == 0);
89748f09a05SAntonio Huete Jimenez if ((is_nan || is_inf)
898*ed569bc2SAaron LI && (isspace((int) s[4]) || s[4] == '\0'))
89948f09a05SAntonio Huete Jimenez goto convert;
90048f09a05SAntonio Huete Jimenez else if (! isdigit(s[1]) && s[1] != '.')
90148f09a05SAntonio Huete Jimenez return false;
90248f09a05SAntonio Huete Jimenez }
90348f09a05SAntonio Huete Jimenez else if (! isdigit(s[0]) && s[0] != '.')
90448f09a05SAntonio Huete Jimenez return false;
90548f09a05SAntonio Huete Jimenez
90648f09a05SAntonio Huete Jimenez convert:
9074b588458SPeter Avalos errno = 0;
9084b588458SPeter Avalos r = strtod(s, &ep);
90948f09a05SAntonio Huete Jimenez if (ep == s || errno == ERANGE)
91048f09a05SAntonio Huete Jimenez return false;
91148f09a05SAntonio Huete Jimenez
91248f09a05SAntonio Huete Jimenez if (isnan(r) && s[0] == '-' && signbit(r) == 0)
91348f09a05SAntonio Huete Jimenez r = -r;
91448f09a05SAntonio Huete Jimenez
91548f09a05SAntonio Huete Jimenez if (result != NULL)
91648f09a05SAntonio Huete Jimenez *result = r;
91748f09a05SAntonio Huete Jimenez
91848f09a05SAntonio Huete Jimenez /*
91948f09a05SAntonio Huete Jimenez * check for trailing stuff
92048f09a05SAntonio Huete Jimenez */
921*ed569bc2SAaron LI while (isspace((int) *ep))
9224b588458SPeter Avalos ep++;
92348f09a05SAntonio Huete Jimenez
92448f09a05SAntonio Huete Jimenez if (no_trailing != NULL)
92548f09a05SAntonio Huete Jimenez *no_trailing = (*ep == '\0');
92648f09a05SAntonio Huete Jimenez
927*ed569bc2SAaron LI /* return true if found the end, or trailing stuff is allowed */
92848f09a05SAntonio Huete Jimenez retval = *ep == '\0' || trailing_stuff_ok;
92948f09a05SAntonio Huete Jimenez
93048f09a05SAntonio Huete Jimenez return retval;
9314b588458SPeter Avalos }
932