12a55deb1SDavid E. O'Brien /**************************************************************** 22a55deb1SDavid E. O'Brien Copyright (C) Lucent Technologies 1997 32a55deb1SDavid E. O'Brien All Rights Reserved 42a55deb1SDavid E. O'Brien 52a55deb1SDavid E. O'Brien Permission to use, copy, modify, and distribute this software and 62a55deb1SDavid E. O'Brien its documentation for any purpose and without fee is hereby 72a55deb1SDavid E. O'Brien granted, provided that the above copyright notice appear in all 82a55deb1SDavid E. O'Brien copies and that both that the copyright notice and this 92a55deb1SDavid E. O'Brien permission notice and warranty disclaimer appear in supporting 102a55deb1SDavid E. O'Brien documentation, and that the name Lucent Technologies or any of 112a55deb1SDavid E. O'Brien its entities not be used in advertising or publicity pertaining 122a55deb1SDavid E. O'Brien to distribution of the software without specific, written prior 132a55deb1SDavid E. O'Brien permission. 142a55deb1SDavid E. O'Brien 152a55deb1SDavid E. O'Brien LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 162a55deb1SDavid E. O'Brien INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 172a55deb1SDavid E. O'Brien IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 182a55deb1SDavid E. O'Brien SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 192a55deb1SDavid E. O'Brien WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 202a55deb1SDavid E. O'Brien IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 212a55deb1SDavid E. O'Brien ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 222a55deb1SDavid E. O'Brien THIS SOFTWARE. 232a55deb1SDavid E. O'Brien ****************************************************************/ 242a55deb1SDavid E. O'Brien 252a55deb1SDavid E. O'Brien #define DEBUG 262a55deb1SDavid E. O'Brien #include <stdio.h> 272a55deb1SDavid E. O'Brien #include <string.h> 28f39dd6a9SWarner Losh #include <strings.h> 292a55deb1SDavid E. O'Brien #include <ctype.h> 302a55deb1SDavid E. O'Brien #include <errno.h> 312a55deb1SDavid E. O'Brien #include <stdlib.h> 322a55deb1SDavid E. O'Brien #include <stdarg.h> 33f39dd6a9SWarner Losh #include <limits.h> 34f39dd6a9SWarner Losh #include <math.h> 352a55deb1SDavid E. O'Brien #include "awk.h" 362a55deb1SDavid E. O'Brien 37f32a6403SWarner Losh extern int u8_nextlen(const char *s); 38f32a6403SWarner Losh 39f39dd6a9SWarner Losh char EMPTY[] = { '\0' }; 402a55deb1SDavid E. O'Brien FILE *infile = NULL; 41f39dd6a9SWarner Losh bool innew; /* true = infile has not been read by readrec */ 42f39dd6a9SWarner Losh char *file = EMPTY; 432a55deb1SDavid E. O'Brien char *record; 442a55deb1SDavid E. O'Brien int recsize = RECSIZE; 452a55deb1SDavid E. O'Brien char *fields; 462a55deb1SDavid E. O'Brien int fieldssize = RECSIZE; 472a55deb1SDavid E. O'Brien 482a55deb1SDavid E. O'Brien Cell **fldtab; /* pointers to Cells */ 49f39dd6a9SWarner Losh static size_t len_inputFS = 0; 50f39dd6a9SWarner Losh static char *inputFS = NULL; /* FS at time of input, for field splitting */ 512a55deb1SDavid E. O'Brien 52addad6afSRong-En Fan #define MAXFLD 2 532a55deb1SDavid E. O'Brien int nfields = MAXFLD; /* last allocated slot for $i */ 542a55deb1SDavid E. O'Brien 55f39dd6a9SWarner Losh bool donefld; /* true = implies rec broken into fields */ 56f39dd6a9SWarner Losh bool donerec; /* true = record is valid (no flds have changed) */ 572a55deb1SDavid E. O'Brien 582a55deb1SDavid E. O'Brien int lastfld = 0; /* last used field */ 592a55deb1SDavid E. O'Brien int argno = 1; /* current input argument number */ 602a55deb1SDavid E. O'Brien extern Awkfloat *ARGC; 612a55deb1SDavid E. O'Brien 62f39dd6a9SWarner Losh static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL, NULL }; 63f39dd6a9SWarner Losh static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL, NULL }; 642a55deb1SDavid E. O'Brien 652a55deb1SDavid E. O'Brien void recinit(unsigned int n) 662a55deb1SDavid E. O'Brien { 67c263f9bfSRuslan Ermilov if ( (record = (char *) malloc(n)) == NULL 68d2f6e492SDavid E. O'Brien || (fields = (char *) malloc(n+1)) == NULL 69f39dd6a9SWarner Losh || (fldtab = (Cell **) calloc(nfields+2, sizeof(*fldtab))) == NULL 70f39dd6a9SWarner Losh || (fldtab[0] = (Cell *) malloc(sizeof(**fldtab))) == NULL) 712a55deb1SDavid E. O'Brien FATAL("out of space for $0 and fields"); 72547f34caSWarner Losh *record = '\0'; 732a55deb1SDavid E. O'Brien *fldtab[0] = dollar0; 742a55deb1SDavid E. O'Brien fldtab[0]->sval = record; 752a55deb1SDavid E. O'Brien fldtab[0]->nval = tostring("0"); 762a55deb1SDavid E. O'Brien makefields(1, nfields); 772a55deb1SDavid E. O'Brien } 782a55deb1SDavid E. O'Brien 792a55deb1SDavid E. O'Brien void makefields(int n1, int n2) /* create $n1..$n2 inclusive */ 802a55deb1SDavid E. O'Brien { 812a55deb1SDavid E. O'Brien char temp[50]; 822a55deb1SDavid E. O'Brien int i; 832a55deb1SDavid E. O'Brien 842a55deb1SDavid E. O'Brien for (i = n1; i <= n2; i++) { 85f39dd6a9SWarner Losh fldtab[i] = (Cell *) malloc(sizeof(**fldtab)); 862a55deb1SDavid E. O'Brien if (fldtab[i] == NULL) 872a55deb1SDavid E. O'Brien FATAL("out of space in makefields %d", i); 882a55deb1SDavid E. O'Brien *fldtab[i] = dollar1; 89f39dd6a9SWarner Losh snprintf(temp, sizeof(temp), "%d", i); 902a55deb1SDavid E. O'Brien fldtab[i]->nval = tostring(temp); 912a55deb1SDavid E. O'Brien } 922a55deb1SDavid E. O'Brien } 932a55deb1SDavid E. O'Brien 942a55deb1SDavid E. O'Brien void initgetrec(void) 952a55deb1SDavid E. O'Brien { 962a55deb1SDavid E. O'Brien int i; 972a55deb1SDavid E. O'Brien char *p; 982a55deb1SDavid E. O'Brien 992a55deb1SDavid E. O'Brien for (i = 1; i < *ARGC; i++) { 100aa0da2e4SRuslan Ermilov p = getargv(i); /* find 1st real filename */ 101aa0da2e4SRuslan Ermilov if (p == NULL || *p == '\0') { /* deleted or zapped */ 102aa0da2e4SRuslan Ermilov argno++; 103aa0da2e4SRuslan Ermilov continue; 104aa0da2e4SRuslan Ermilov } 105aa0da2e4SRuslan Ermilov if (!isclvar(p)) { 106aa0da2e4SRuslan Ermilov setsval(lookup("FILENAME", symtab), p); 1072a55deb1SDavid E. O'Brien return; 1082a55deb1SDavid E. O'Brien } 1092a55deb1SDavid E. O'Brien setclvar(p); /* a commandline assignment before filename */ 1102a55deb1SDavid E. O'Brien argno++; 1112a55deb1SDavid E. O'Brien } 1122a55deb1SDavid E. O'Brien infile = stdin; /* no filenames, so use stdin */ 113f39dd6a9SWarner Losh innew = true; 1142a55deb1SDavid E. O'Brien } 1152a55deb1SDavid E. O'Brien 116f39dd6a9SWarner Losh /* 117f39dd6a9SWarner Losh * POSIX specifies that fields are supposed to be evaluated as if they were 118f39dd6a9SWarner Losh * split using the value of FS at the time that the record's value ($0) was 119f39dd6a9SWarner Losh * read. 120f39dd6a9SWarner Losh * 121f39dd6a9SWarner Losh * Since field-splitting is done lazily, we save the current value of FS 122f39dd6a9SWarner Losh * whenever a new record is read in (implicitly or via getline), or when 123f39dd6a9SWarner Losh * a new value is assigned to $0. 124f39dd6a9SWarner Losh */ 125f39dd6a9SWarner Losh void savefs(void) 126f39dd6a9SWarner Losh { 127f39dd6a9SWarner Losh size_t len; 128f39dd6a9SWarner Losh if ((len = strlen(getsval(fsloc))) < len_inputFS) { 129f39dd6a9SWarner Losh strcpy(inputFS, *FS); /* for subsequent field splitting */ 130f39dd6a9SWarner Losh return; 131f39dd6a9SWarner Losh } 132c263f9bfSRuslan Ermilov 133f39dd6a9SWarner Losh len_inputFS = len + 1; 134f39dd6a9SWarner Losh inputFS = (char *) realloc(inputFS, len_inputFS); 135f39dd6a9SWarner Losh if (inputFS == NULL) 136f39dd6a9SWarner Losh FATAL("field separator %.10s... is too long", *FS); 137f39dd6a9SWarner Losh memcpy(inputFS, *FS, len_inputFS); 138f39dd6a9SWarner Losh } 139f39dd6a9SWarner Losh 140f39dd6a9SWarner Losh static bool firsttime = true; 141f39dd6a9SWarner Losh 142f39dd6a9SWarner Losh int getrec(char **pbuf, int *pbufsize, bool isrecord) /* get next input record */ 1432a55deb1SDavid E. O'Brien { /* note: cares whether buf == record */ 1442a55deb1SDavid E. O'Brien int c; 1452a55deb1SDavid E. O'Brien char *buf = *pbuf; 146c263f9bfSRuslan Ermilov uschar saveb0; 147c263f9bfSRuslan Ermilov int bufsize = *pbufsize, savebufsize = bufsize; 1482a55deb1SDavid E. O'Brien 1492a55deb1SDavid E. O'Brien if (firsttime) { 150f39dd6a9SWarner Losh firsttime = false; 1512a55deb1SDavid E. O'Brien initgetrec(); 1522a55deb1SDavid E. O'Brien } 153f39dd6a9SWarner Losh DPRINTF("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n", 154f39dd6a9SWarner Losh *RS, *FS, *ARGC, *FILENAME); 155c263f9bfSRuslan Ermilov saveb0 = buf[0]; 1562a55deb1SDavid E. O'Brien buf[0] = 0; 1572a55deb1SDavid E. O'Brien while (argno < *ARGC || infile == stdin) { 158f39dd6a9SWarner Losh DPRINTF("argno=%d, file=|%s|\n", argno, file); 1592a55deb1SDavid E. O'Brien if (infile == NULL) { /* have to open a new file */ 1602a55deb1SDavid E. O'Brien file = getargv(argno); 161d86a0988SRuslan Ermilov if (file == NULL || *file == '\0') { /* deleted or zapped */ 1622a55deb1SDavid E. O'Brien argno++; 1632a55deb1SDavid E. O'Brien continue; 1642a55deb1SDavid E. O'Brien } 1652a55deb1SDavid E. O'Brien if (isclvar(file)) { /* a var=value arg */ 1662a55deb1SDavid E. O'Brien setclvar(file); 1672a55deb1SDavid E. O'Brien argno++; 1682a55deb1SDavid E. O'Brien continue; 1692a55deb1SDavid E. O'Brien } 1702a55deb1SDavid E. O'Brien *FILENAME = file; 171f39dd6a9SWarner Losh DPRINTF("opening file %s\n", file); 1722a55deb1SDavid E. O'Brien if (*file == '-' && *(file+1) == '\0') 1732a55deb1SDavid E. O'Brien infile = stdin; 1742a55deb1SDavid E. O'Brien else if ((infile = fopen(file, "r")) == NULL) 1752a55deb1SDavid E. O'Brien FATAL("can't open file %s", file); 17623f24377SWarner Losh innew = true; 1772a55deb1SDavid E. O'Brien setfval(fnrloc, 0.0); 1782a55deb1SDavid E. O'Brien } 179f39dd6a9SWarner Losh c = readrec(&buf, &bufsize, infile, innew); 180f39dd6a9SWarner Losh if (innew) 181f39dd6a9SWarner Losh innew = false; 1822a55deb1SDavid E. O'Brien if (c != 0 || buf[0] != '\0') { /* normal record */ 1832a55deb1SDavid E. O'Brien if (isrecord) { 184f39dd6a9SWarner Losh double result; 185f39dd6a9SWarner Losh 1862a55deb1SDavid E. O'Brien if (freeable(fldtab[0])) 1872a55deb1SDavid E. O'Brien xfree(fldtab[0]->sval); 1882a55deb1SDavid E. O'Brien fldtab[0]->sval = buf; /* buf == record */ 1892a55deb1SDavid E. O'Brien fldtab[0]->tval = REC | STR | DONTFREE; 190f39dd6a9SWarner Losh if (is_number(fldtab[0]->sval, & result)) { 191f39dd6a9SWarner Losh fldtab[0]->fval = result; 1922a55deb1SDavid E. O'Brien fldtab[0]->tval |= NUM; 1932a55deb1SDavid E. O'Brien } 194f32a6403SWarner Losh donefld = false; 195f32a6403SWarner Losh donerec = true; 196f32a6403SWarner Losh savefs(); 1972a55deb1SDavid E. O'Brien } 1982a55deb1SDavid E. O'Brien setfval(nrloc, nrloc->fval+1); 1992a55deb1SDavid E. O'Brien setfval(fnrloc, fnrloc->fval+1); 2002a55deb1SDavid E. O'Brien *pbuf = buf; 2012a55deb1SDavid E. O'Brien *pbufsize = bufsize; 2022a55deb1SDavid E. O'Brien return 1; 2032a55deb1SDavid E. O'Brien } 2042a55deb1SDavid E. O'Brien /* EOF arrived on this file; set up next */ 2052a55deb1SDavid E. O'Brien if (infile != stdin) 2062a55deb1SDavid E. O'Brien fclose(infile); 2072a55deb1SDavid E. O'Brien infile = NULL; 2082a55deb1SDavid E. O'Brien argno++; 2092a55deb1SDavid E. O'Brien } 210c263f9bfSRuslan Ermilov buf[0] = saveb0; 2112a55deb1SDavid E. O'Brien *pbuf = buf; 212c263f9bfSRuslan Ermilov *pbufsize = savebufsize; 2132a55deb1SDavid E. O'Brien return 0; /* true end of file */ 2142a55deb1SDavid E. O'Brien } 2152a55deb1SDavid E. O'Brien 2162a55deb1SDavid E. O'Brien void nextfile(void) 2172a55deb1SDavid E. O'Brien { 218addad6afSRong-En Fan if (infile != NULL && infile != stdin) 2192a55deb1SDavid E. O'Brien fclose(infile); 2202a55deb1SDavid E. O'Brien infile = NULL; 2212a55deb1SDavid E. O'Brien argno++; 2222a55deb1SDavid E. O'Brien } 2232a55deb1SDavid E. O'Brien 224f32a6403SWarner Losh extern int readcsvrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag); 225f32a6403SWarner Losh 226f39dd6a9SWarner Losh int readrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag) /* read one record into buf */ 2272a55deb1SDavid E. O'Brien { 228f32a6403SWarner Losh int sep, c, isrec; // POTENTIAL BUG? isrec is a macro in awk.h 229f32a6403SWarner Losh char *rr = *pbuf, *buf = *pbuf; 2302a55deb1SDavid E. O'Brien int bufsize = *pbufsize; 231b5253557SWarner Losh char *rs = getsval(rsloc); 2322a55deb1SDavid E. O'Brien 233f32a6403SWarner Losh if (CSV) { 234*8d457988SWarner Losh c = readcsvrec(&buf, &bufsize, inf, newflag); 235f32a6403SWarner Losh isrec = (c == EOF && rr == buf) ? false : true; 236f32a6403SWarner Losh } else if (*rs && rs[1]) { 237f39dd6a9SWarner Losh bool found; 238f39dd6a9SWarner Losh 239f32a6403SWarner Losh memset(buf, 0, bufsize); 240f39dd6a9SWarner Losh fa *pfa = makedfa(rs, 1); 241f39dd6a9SWarner Losh if (newflag) 242f39dd6a9SWarner Losh found = fnematch(pfa, inf, &buf, &bufsize, recsize); 243f39dd6a9SWarner Losh else { 244f39dd6a9SWarner Losh int tempstat = pfa->initstat; 245f39dd6a9SWarner Losh pfa->initstat = 2; 246f39dd6a9SWarner Losh found = fnematch(pfa, inf, &buf, &bufsize, recsize); 247f39dd6a9SWarner Losh pfa->initstat = tempstat; 248f39dd6a9SWarner Losh } 249f39dd6a9SWarner Losh if (found) 250f39dd6a9SWarner Losh setptr(patbeg, '\0'); 25123f24377SWarner Losh isrec = (found == 0 && *buf == '\0') ? false : true; 252f32a6403SWarner Losh 253f39dd6a9SWarner Losh } else { 254b5253557SWarner Losh if ((sep = *rs) == 0) { 2552a55deb1SDavid E. O'Brien sep = '\n'; 2562a55deb1SDavid E. O'Brien while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */ 2572a55deb1SDavid E. O'Brien ; 2582a55deb1SDavid E. O'Brien if (c != EOF) 2592a55deb1SDavid E. O'Brien ungetc(c, inf); 2602a55deb1SDavid E. O'Brien } 2612a55deb1SDavid E. O'Brien for (rr = buf; ; ) { 2622a55deb1SDavid E. O'Brien for (; (c=getc(inf)) != sep && c != EOF; ) { 2632a55deb1SDavid E. O'Brien if (rr-buf+1 > bufsize) 264f39dd6a9SWarner Losh if (!adjbuf(&buf, &bufsize, 1+rr-buf, 265f39dd6a9SWarner Losh recsize, &rr, "readrec 1")) 2662a55deb1SDavid E. O'Brien FATAL("input record `%.30s...' too long", buf); 2672a55deb1SDavid E. O'Brien *rr++ = c; 2682a55deb1SDavid E. O'Brien } 269b5253557SWarner Losh if (*rs == sep || c == EOF) 2702a55deb1SDavid E. O'Brien break; 2712a55deb1SDavid E. O'Brien if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */ 2722a55deb1SDavid E. O'Brien break; 273f39dd6a9SWarner Losh if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, 274f39dd6a9SWarner Losh "readrec 2")) 2752a55deb1SDavid E. O'Brien FATAL("input record `%.30s...' too long", buf); 2762a55deb1SDavid E. O'Brien *rr++ = '\n'; 2772a55deb1SDavid E. O'Brien *rr++ = c; 2782a55deb1SDavid E. O'Brien } 2792a55deb1SDavid E. O'Brien if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3")) 2802a55deb1SDavid E. O'Brien FATAL("input record `%.30s...' too long", buf); 2812a55deb1SDavid E. O'Brien *rr = 0; 28223f24377SWarner Losh isrec = (c == EOF && rr == buf) ? false : true; 283f39dd6a9SWarner Losh } 2842a55deb1SDavid E. O'Brien *pbuf = buf; 2852a55deb1SDavid E. O'Brien *pbufsize = bufsize; 286f39dd6a9SWarner Losh DPRINTF("readrec saw <%s>, returns %d\n", buf, isrec); 287f39dd6a9SWarner Losh return isrec; 2882a55deb1SDavid E. O'Brien } 2892a55deb1SDavid E. O'Brien 290f32a6403SWarner Losh 291f32a6403SWarner Losh /******************* 292f32a6403SWarner Losh * loose ends here: 293f32a6403SWarner Losh * \r\n should become \n 294f32a6403SWarner Losh * what about bare \r? Excel uses that for embedded newlines 295f32a6403SWarner Losh * can't have "" in unquoted fields, according to RFC 4180 296f32a6403SWarner Losh */ 297f32a6403SWarner Losh 298f32a6403SWarner Losh 299f32a6403SWarner Losh int readcsvrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag) /* csv can have \n's */ 300f32a6403SWarner Losh { /* so read a complete record that might be multiple lines */ 301f32a6403SWarner Losh int sep, c; 302f32a6403SWarner Losh char *rr = *pbuf, *buf = *pbuf; 303f32a6403SWarner Losh int bufsize = *pbufsize; 304f32a6403SWarner Losh bool in_quote = false; 305f32a6403SWarner Losh 306f32a6403SWarner Losh sep = '\n'; /* the only separator; have to skip over \n embedded in "..." */ 307f32a6403SWarner Losh rr = buf; 308f32a6403SWarner Losh while ((c = getc(inf)) != EOF) { 309f32a6403SWarner Losh if (c == sep) { 310f32a6403SWarner Losh if (! in_quote) 311f32a6403SWarner Losh break; 312f32a6403SWarner Losh if (rr > buf && rr[-1] == '\r') // remove \r if was \r\n 313f32a6403SWarner Losh rr--; 314f32a6403SWarner Losh } 315f32a6403SWarner Losh 316f32a6403SWarner Losh if (rr-buf+1 > bufsize) 317f32a6403SWarner Losh if (!adjbuf(&buf, &bufsize, 1+rr-buf, 318f32a6403SWarner Losh recsize, &rr, "readcsvrec 1")) 319f32a6403SWarner Losh FATAL("input record `%.30s...' too long", buf); 320f32a6403SWarner Losh *rr++ = c; 321f32a6403SWarner Losh if (c == '"') 322f32a6403SWarner Losh in_quote = ! in_quote; 323f32a6403SWarner Losh } 324f32a6403SWarner Losh if (c == '\n' && rr > buf && rr[-1] == '\r') // remove \r if was \r\n 325f32a6403SWarner Losh rr--; 326f32a6403SWarner Losh 327f32a6403SWarner Losh if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readcsvrec 4")) 328f32a6403SWarner Losh FATAL("input record `%.30s...' too long", buf); 329f32a6403SWarner Losh *rr = 0; 330f32a6403SWarner Losh *pbuf = buf; 331f32a6403SWarner Losh *pbufsize = bufsize; 332f32a6403SWarner Losh DPRINTF("readcsvrec saw <%s>, returns %d\n", buf, c); 333f32a6403SWarner Losh return c; 334f32a6403SWarner Losh } 335f32a6403SWarner Losh 3362a55deb1SDavid E. O'Brien char *getargv(int n) /* get ARGV[n] */ 3372a55deb1SDavid E. O'Brien { 33817853db4SWarner Losh Array *ap; 3392a55deb1SDavid E. O'Brien Cell *x; 3402a55deb1SDavid E. O'Brien char *s, temp[50]; 34117853db4SWarner Losh extern Cell *ARGVcell; 3422a55deb1SDavid E. O'Brien 34317853db4SWarner Losh ap = (Array *)ARGVcell->sval; 344f39dd6a9SWarner Losh snprintf(temp, sizeof(temp), "%d", n); 34517853db4SWarner Losh if (lookup(temp, ap) == NULL) 346d86a0988SRuslan Ermilov return NULL; 34717853db4SWarner Losh x = setsymtab(temp, "", 0.0, STR, ap); 3482a55deb1SDavid E. O'Brien s = getsval(x); 349f39dd6a9SWarner Losh DPRINTF("getargv(%d) returns |%s|\n", n, s); 3502a55deb1SDavid E. O'Brien return s; 3512a55deb1SDavid E. O'Brien } 3522a55deb1SDavid E. O'Brien 3532a55deb1SDavid E. O'Brien void setclvar(char *s) /* set var=value from s */ 3542a55deb1SDavid E. O'Brien { 355f32a6403SWarner Losh char *e, *p; 3562a55deb1SDavid E. O'Brien Cell *q; 357f39dd6a9SWarner Losh double result; 3582a55deb1SDavid E. O'Brien 359f32a6403SWarner Losh /* commit f3d9187d4e0f02294fb1b0e31152070506314e67 broke T.argv test */ 360f32a6403SWarner Losh /* I don't understand why it was changed. */ 361f32a6403SWarner Losh 3622a55deb1SDavid E. O'Brien for (p=s; *p != '='; p++) 3632a55deb1SDavid E. O'Brien ; 364f32a6403SWarner Losh e = p; 3652a55deb1SDavid E. O'Brien *p++ = 0; 3662a55deb1SDavid E. O'Brien p = qstring(p, '\0'); 3672a55deb1SDavid E. O'Brien q = setsymtab(s, p, 0.0, STR, symtab); 3682a55deb1SDavid E. O'Brien setsval(q, p); 369f39dd6a9SWarner Losh if (is_number(q->sval, & result)) { 370f39dd6a9SWarner Losh q->fval = result; 3712a55deb1SDavid E. O'Brien q->tval |= NUM; 3722a55deb1SDavid E. O'Brien } 373f39dd6a9SWarner Losh DPRINTF("command line set %s to |%s|\n", s, p); 374f32a6403SWarner Losh free(p); 375f32a6403SWarner Losh *e = '='; 3762a55deb1SDavid E. O'Brien } 3772a55deb1SDavid E. O'Brien 3782a55deb1SDavid E. O'Brien 3792a55deb1SDavid E. O'Brien void fldbld(void) /* create fields from current record */ 3802a55deb1SDavid E. O'Brien { 3812a55deb1SDavid E. O'Brien /* this relies on having fields[] the same length as $0 */ 3822a55deb1SDavid E. O'Brien /* the fields are all stored in this one array with \0's */ 3831b11b783SRuslan Ermilov /* possibly with a final trailing \0 not associated with any field */ 3842a55deb1SDavid E. O'Brien char *r, *fr, sep; 3852a55deb1SDavid E. O'Brien Cell *p; 3862a55deb1SDavid E. O'Brien int i, j, n; 3872a55deb1SDavid E. O'Brien 3882a55deb1SDavid E. O'Brien if (donefld) 3892a55deb1SDavid E. O'Brien return; 3902a55deb1SDavid E. O'Brien if (!isstr(fldtab[0])) 3912a55deb1SDavid E. O'Brien getsval(fldtab[0]); 3922a55deb1SDavid E. O'Brien r = fldtab[0]->sval; 3932a55deb1SDavid E. O'Brien n = strlen(r); 3942a55deb1SDavid E. O'Brien if (n > fieldssize) { 3952a55deb1SDavid E. O'Brien xfree(fields); 3961b11b783SRuslan Ermilov if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */ 3972a55deb1SDavid E. O'Brien FATAL("out of space for fields in fldbld %d", n); 3982a55deb1SDavid E. O'Brien fieldssize = n; 3992a55deb1SDavid E. O'Brien } 4002a55deb1SDavid E. O'Brien fr = fields; 4012a55deb1SDavid E. O'Brien i = 0; /* number of fields accumulated here */ 402f39dd6a9SWarner Losh if (inputFS == NULL) /* make sure we have a copy of FS */ 403f39dd6a9SWarner Losh savefs(); 404f32a6403SWarner Losh if (!CSV && strlen(inputFS) > 1) { /* it's a regular expression */ 4052a55deb1SDavid E. O'Brien i = refldbld(r, inputFS); 406f32a6403SWarner Losh } else if (!CSV && (sep = *inputFS) == ' ') { /* default whitespace */ 4072a55deb1SDavid E. O'Brien for (i = 0; ; ) { 4082a55deb1SDavid E. O'Brien while (*r == ' ' || *r == '\t' || *r == '\n') 4092a55deb1SDavid E. O'Brien r++; 4102a55deb1SDavid E. O'Brien if (*r == 0) 4112a55deb1SDavid E. O'Brien break; 4122a55deb1SDavid E. O'Brien i++; 4132a55deb1SDavid E. O'Brien if (i > nfields) 4142a55deb1SDavid E. O'Brien growfldtab(i); 4152a55deb1SDavid E. O'Brien if (freeable(fldtab[i])) 4162a55deb1SDavid E. O'Brien xfree(fldtab[i]->sval); 4172a55deb1SDavid E. O'Brien fldtab[i]->sval = fr; 4182a55deb1SDavid E. O'Brien fldtab[i]->tval = FLD | STR | DONTFREE; 4192a55deb1SDavid E. O'Brien do 4202a55deb1SDavid E. O'Brien *fr++ = *r++; 4212a55deb1SDavid E. O'Brien while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0'); 4222a55deb1SDavid E. O'Brien *fr++ = 0; 4232a55deb1SDavid E. O'Brien } 4242a55deb1SDavid E. O'Brien *fr = 0; 425f32a6403SWarner Losh } else if (CSV) { /* CSV processing. no error handling */ 426f32a6403SWarner Losh if (*r != 0) { 427f32a6403SWarner Losh for (;;) { 4283fd60a6bSWarner Losh i++; 4293fd60a6bSWarner Losh if (i > nfields) 4303fd60a6bSWarner Losh growfldtab(i); 4313fd60a6bSWarner Losh if (freeable(fldtab[i])) 4323fd60a6bSWarner Losh xfree(fldtab[i]->sval); 433f32a6403SWarner Losh fldtab[i]->sval = fr; 434f32a6403SWarner Losh fldtab[i]->tval = FLD | STR | DONTFREE; 435f32a6403SWarner Losh if (*r == '"' ) { /* start of "..." */ 436f32a6403SWarner Losh for (r++ ; *r != '\0'; ) { 437f32a6403SWarner Losh if (*r == '"' && r[1] != '\0' && r[1] == '"') { 438f32a6403SWarner Losh r += 2; /* doubled quote */ 439f32a6403SWarner Losh *fr++ = '"'; 440f32a6403SWarner Losh } else if (*r == '"' && (r[1] == '\0' || r[1] == ',')) { 441f32a6403SWarner Losh r++; /* skip over closing quote */ 442f32a6403SWarner Losh break; 443f32a6403SWarner Losh } else { 444f32a6403SWarner Losh *fr++ = *r++; 445f32a6403SWarner Losh } 446f32a6403SWarner Losh } 447f32a6403SWarner Losh *fr++ = 0; 448f32a6403SWarner Losh } else { /* unquoted field */ 449f32a6403SWarner Losh while (*r != ',' && *r != '\0') 450f32a6403SWarner Losh *fr++ = *r++; 451f32a6403SWarner Losh *fr++ = 0; 452f32a6403SWarner Losh } 453f32a6403SWarner Losh if (*r++ == 0) 454f32a6403SWarner Losh break; 455f32a6403SWarner Losh 456f32a6403SWarner Losh } 457f32a6403SWarner Losh } 458f32a6403SWarner Losh *fr = 0; 459f32a6403SWarner Losh } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */ 460f32a6403SWarner Losh for (i = 0; *r != '\0'; ) { 461f32a6403SWarner Losh char buf[10]; 462f32a6403SWarner Losh i++; 463f32a6403SWarner Losh if (i > nfields) 464f32a6403SWarner Losh growfldtab(i); 465f32a6403SWarner Losh if (freeable(fldtab[i])) 466f32a6403SWarner Losh xfree(fldtab[i]->sval); 467f32a6403SWarner Losh n = u8_nextlen(r); 468f32a6403SWarner Losh for (j = 0; j < n; j++) 469f32a6403SWarner Losh buf[j] = *r++; 470f32a6403SWarner Losh buf[j] = '\0'; 4712a55deb1SDavid E. O'Brien fldtab[i]->sval = tostring(buf); 4722a55deb1SDavid E. O'Brien fldtab[i]->tval = FLD | STR; 4732a55deb1SDavid E. O'Brien } 4742a55deb1SDavid E. O'Brien *fr = 0; 4752a55deb1SDavid E. O'Brien } else if (*r != 0) { /* if 0, it's a null field */ 476fc6b1dfeSDavid E. O'Brien /* subtle case: if length(FS) == 1 && length(RS > 0) 477fc6b1dfeSDavid E. O'Brien * \n is NOT a field separator (cf awk book 61,84). 478fc6b1dfeSDavid E. O'Brien * this variable is tested in the inner while loop. 479fc6b1dfeSDavid E. O'Brien */ 480fc6b1dfeSDavid E. O'Brien int rtest = '\n'; /* normal case */ 481fc6b1dfeSDavid E. O'Brien if (strlen(*RS) > 0) 482fc6b1dfeSDavid E. O'Brien rtest = '\0'; 4832a55deb1SDavid E. O'Brien for (;;) { 4842a55deb1SDavid E. O'Brien i++; 4852a55deb1SDavid E. O'Brien if (i > nfields) 4862a55deb1SDavid E. O'Brien growfldtab(i); 4872a55deb1SDavid E. O'Brien if (freeable(fldtab[i])) 4882a55deb1SDavid E. O'Brien xfree(fldtab[i]->sval); 4892a55deb1SDavid E. O'Brien fldtab[i]->sval = fr; 4902a55deb1SDavid E. O'Brien fldtab[i]->tval = FLD | STR | DONTFREE; 491fc6b1dfeSDavid E. O'Brien while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */ 4922a55deb1SDavid E. O'Brien *fr++ = *r++; 4932a55deb1SDavid E. O'Brien *fr++ = 0; 4942a55deb1SDavid E. O'Brien if (*r++ == 0) 4952a55deb1SDavid E. O'Brien break; 4962a55deb1SDavid E. O'Brien } 4972a55deb1SDavid E. O'Brien *fr = 0; 4982a55deb1SDavid E. O'Brien } 4992a55deb1SDavid E. O'Brien if (i > nfields) 5002a55deb1SDavid E. O'Brien FATAL("record `%.30s...' has too many fields; can't happen", r); 5012a55deb1SDavid E. O'Brien cleanfld(i+1, lastfld); /* clean out junk from previous record */ 5022a55deb1SDavid E. O'Brien lastfld = i; 503f39dd6a9SWarner Losh donefld = true; 5042a55deb1SDavid E. O'Brien for (j = 1; j <= lastfld; j++) { 505f39dd6a9SWarner Losh double result; 506f39dd6a9SWarner Losh 5072a55deb1SDavid E. O'Brien p = fldtab[j]; 508f39dd6a9SWarner Losh if(is_number(p->sval, & result)) { 509f39dd6a9SWarner Losh p->fval = result; 5102a55deb1SDavid E. O'Brien p->tval |= NUM; 5112a55deb1SDavid E. O'Brien } 5122a55deb1SDavid E. O'Brien } 5132a55deb1SDavid E. O'Brien setfval(nfloc, (Awkfloat) lastfld); 514f39dd6a9SWarner Losh donerec = true; /* restore */ 5152a55deb1SDavid E. O'Brien if (dbg) { 5162a55deb1SDavid E. O'Brien for (j = 0; j <= lastfld; j++) { 5172a55deb1SDavid E. O'Brien p = fldtab[j]; 5182a55deb1SDavid E. O'Brien printf("field %d (%s): |%s|\n", j, p->nval, p->sval); 5192a55deb1SDavid E. O'Brien } 5202a55deb1SDavid E. O'Brien } 5212a55deb1SDavid E. O'Brien } 5222a55deb1SDavid E. O'Brien 5232a55deb1SDavid E. O'Brien void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */ 5242a55deb1SDavid E. O'Brien { /* nvals remain intact */ 5252a55deb1SDavid E. O'Brien Cell *p; 5262a55deb1SDavid E. O'Brien int i; 5272a55deb1SDavid E. O'Brien 5282a55deb1SDavid E. O'Brien for (i = n1; i <= n2; i++) { 5292a55deb1SDavid E. O'Brien p = fldtab[i]; 5302a55deb1SDavid E. O'Brien if (freeable(p)) 5312a55deb1SDavid E. O'Brien xfree(p->sval); 532f39dd6a9SWarner Losh p->sval = EMPTY, 5332a55deb1SDavid E. O'Brien p->tval = FLD | STR | DONTFREE; 5342a55deb1SDavid E. O'Brien } 5352a55deb1SDavid E. O'Brien } 5362a55deb1SDavid E. O'Brien 5372a55deb1SDavid E. O'Brien void newfld(int n) /* add field n after end of existing lastfld */ 5382a55deb1SDavid E. O'Brien { 5392a55deb1SDavid E. O'Brien if (n > nfields) 5402a55deb1SDavid E. O'Brien growfldtab(n); 5412a55deb1SDavid E. O'Brien cleanfld(lastfld+1, n); 5422a55deb1SDavid E. O'Brien lastfld = n; 5432a55deb1SDavid E. O'Brien setfval(nfloc, (Awkfloat) n); 5442a55deb1SDavid E. O'Brien } 5452a55deb1SDavid E. O'Brien 546b5253557SWarner Losh void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */ 547b5253557SWarner Losh { 548b5253557SWarner Losh if (n < 0) 549b5253557SWarner Losh FATAL("cannot set NF to a negative value"); 550b5253557SWarner Losh if (n > nfields) 551b5253557SWarner Losh growfldtab(n); 552b5253557SWarner Losh 553b5253557SWarner Losh if (lastfld < n) 554b5253557SWarner Losh cleanfld(lastfld+1, n); 555b5253557SWarner Losh else 556b5253557SWarner Losh cleanfld(n+1, lastfld); 557b5253557SWarner Losh 558b5253557SWarner Losh lastfld = n; 559b5253557SWarner Losh } 560b5253557SWarner Losh 5612a55deb1SDavid E. O'Brien Cell *fieldadr(int n) /* get nth field */ 5622a55deb1SDavid E. O'Brien { 5632a55deb1SDavid E. O'Brien if (n < 0) 564c263f9bfSRuslan Ermilov FATAL("trying to access out of range field %d", n); 5652a55deb1SDavid E. O'Brien if (n > nfields) /* fields after NF are empty */ 5662a55deb1SDavid E. O'Brien growfldtab(n); /* but does not increase NF */ 5672a55deb1SDavid E. O'Brien return(fldtab[n]); 5682a55deb1SDavid E. O'Brien } 5692a55deb1SDavid E. O'Brien 5702a55deb1SDavid E. O'Brien void growfldtab(int n) /* make new fields up to at least $n */ 5712a55deb1SDavid E. O'Brien { 5722a55deb1SDavid E. O'Brien int nf = 2 * nfields; 573c263f9bfSRuslan Ermilov size_t s; 5742a55deb1SDavid E. O'Brien 5752a55deb1SDavid E. O'Brien if (n > nf) 5762a55deb1SDavid E. O'Brien nf = n; 577c263f9bfSRuslan Ermilov s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */ 578f39dd6a9SWarner Losh if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */ 579c263f9bfSRuslan Ermilov fldtab = (Cell **) realloc(fldtab, s); 580c263f9bfSRuslan Ermilov else /* overflow sizeof int */ 581c263f9bfSRuslan Ermilov xfree(fldtab); /* make it null */ 5822a55deb1SDavid E. O'Brien if (fldtab == NULL) 5832a55deb1SDavid E. O'Brien FATAL("out of space creating %d fields", nf); 5842a55deb1SDavid E. O'Brien makefields(nfields+1, nf); 5852a55deb1SDavid E. O'Brien nfields = nf; 5862a55deb1SDavid E. O'Brien } 5872a55deb1SDavid E. O'Brien 588813da98dSDavid E. O'Brien int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */ 5892a55deb1SDavid E. O'Brien { 5902a55deb1SDavid E. O'Brien /* this relies on having fields[] the same length as $0 */ 5912a55deb1SDavid E. O'Brien /* the fields are all stored in this one array with \0's */ 5922a55deb1SDavid E. O'Brien char *fr; 5932a55deb1SDavid E. O'Brien int i, tempstat, n; 5942a55deb1SDavid E. O'Brien fa *pfa; 5952a55deb1SDavid E. O'Brien 5962a55deb1SDavid E. O'Brien n = strlen(rec); 5972a55deb1SDavid E. O'Brien if (n > fieldssize) { 5982a55deb1SDavid E. O'Brien xfree(fields); 5992a55deb1SDavid E. O'Brien if ((fields = (char *) malloc(n+1)) == NULL) 6002a55deb1SDavid E. O'Brien FATAL("out of space for fields in refldbld %d", n); 6012a55deb1SDavid E. O'Brien fieldssize = n; 6022a55deb1SDavid E. O'Brien } 6032a55deb1SDavid E. O'Brien fr = fields; 6042a55deb1SDavid E. O'Brien *fr = '\0'; 6052a55deb1SDavid E. O'Brien if (*rec == '\0') 6062a55deb1SDavid E. O'Brien return 0; 6072a55deb1SDavid E. O'Brien pfa = makedfa(fs, 1); 608f39dd6a9SWarner Losh DPRINTF("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs); 6092a55deb1SDavid E. O'Brien tempstat = pfa->initstat; 6102a55deb1SDavid E. O'Brien for (i = 1; ; i++) { 6112a55deb1SDavid E. O'Brien if (i > nfields) 6122a55deb1SDavid E. O'Brien growfldtab(i); 6132a55deb1SDavid E. O'Brien if (freeable(fldtab[i])) 6142a55deb1SDavid E. O'Brien xfree(fldtab[i]->sval); 6152a55deb1SDavid E. O'Brien fldtab[i]->tval = FLD | STR | DONTFREE; 6162a55deb1SDavid E. O'Brien fldtab[i]->sval = fr; 617f39dd6a9SWarner Losh DPRINTF("refldbld: i=%d\n", i); 6182a55deb1SDavid E. O'Brien if (nematch(pfa, rec)) { 6192a55deb1SDavid E. O'Brien pfa->initstat = 2; /* horrible coupling to b.c */ 620f39dd6a9SWarner Losh DPRINTF("match %s (%d chars)\n", patbeg, patlen); 6212a55deb1SDavid E. O'Brien strncpy(fr, rec, patbeg-rec); 6222a55deb1SDavid E. O'Brien fr += patbeg - rec + 1; 6232a55deb1SDavid E. O'Brien *(fr-1) = '\0'; 6242a55deb1SDavid E. O'Brien rec = patbeg + patlen; 6252a55deb1SDavid E. O'Brien } else { 626f39dd6a9SWarner Losh DPRINTF("no match %s\n", rec); 6272a55deb1SDavid E. O'Brien strcpy(fr, rec); 6282a55deb1SDavid E. O'Brien pfa->initstat = tempstat; 6292a55deb1SDavid E. O'Brien break; 6302a55deb1SDavid E. O'Brien } 6312a55deb1SDavid E. O'Brien } 6322a55deb1SDavid E. O'Brien return i; 6332a55deb1SDavid E. O'Brien } 6342a55deb1SDavid E. O'Brien 6352a55deb1SDavid E. O'Brien void recbld(void) /* create $0 from $1..$NF if necessary */ 6362a55deb1SDavid E. O'Brien { 6372a55deb1SDavid E. O'Brien int i; 6382a55deb1SDavid E. O'Brien char *r, *p; 639b5253557SWarner Losh char *sep = getsval(ofsloc); 6402a55deb1SDavid E. O'Brien 641f39dd6a9SWarner Losh if (donerec) 6422a55deb1SDavid E. O'Brien return; 6432a55deb1SDavid E. O'Brien r = record; 6442a55deb1SDavid E. O'Brien for (i = 1; i <= *NF; i++) { 6452a55deb1SDavid E. O'Brien p = getsval(fldtab[i]); 6462a55deb1SDavid E. O'Brien if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1")) 6472a55deb1SDavid E. O'Brien FATAL("created $0 `%.30s...' too long", record); 6482a55deb1SDavid E. O'Brien while ((*r = *p++) != 0) 6492a55deb1SDavid E. O'Brien r++; 6502a55deb1SDavid E. O'Brien if (i < *NF) { 651b5253557SWarner Losh if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2")) 6522a55deb1SDavid E. O'Brien FATAL("created $0 `%.30s...' too long", record); 653b5253557SWarner Losh for (p = sep; (*r = *p++) != 0; ) 6542a55deb1SDavid E. O'Brien r++; 6552a55deb1SDavid E. O'Brien } 6562a55deb1SDavid E. O'Brien } 6572a55deb1SDavid E. O'Brien if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3")) 6582a55deb1SDavid E. O'Brien FATAL("built giant record `%.30s...'", record); 6592a55deb1SDavid E. O'Brien *r = '\0'; 660f39dd6a9SWarner Losh DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]); 6612a55deb1SDavid E. O'Brien 6622a55deb1SDavid E. O'Brien if (freeable(fldtab[0])) 6632a55deb1SDavid E. O'Brien xfree(fldtab[0]->sval); 6642a55deb1SDavid E. O'Brien fldtab[0]->tval = REC | STR | DONTFREE; 6652a55deb1SDavid E. O'Brien fldtab[0]->sval = record; 6662a55deb1SDavid E. O'Brien 667f39dd6a9SWarner Losh DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]); 668f39dd6a9SWarner Losh DPRINTF("recbld = |%s|\n", record); 669f39dd6a9SWarner Losh donerec = true; 6702a55deb1SDavid E. O'Brien } 6712a55deb1SDavid E. O'Brien 6722a55deb1SDavid E. O'Brien int errorflag = 0; 6732a55deb1SDavid E. O'Brien 674813da98dSDavid E. O'Brien void yyerror(const char *s) 6752a55deb1SDavid E. O'Brien { 676c263f9bfSRuslan Ermilov SYNTAX("%s", s); 6772a55deb1SDavid E. O'Brien } 6782a55deb1SDavid E. O'Brien 679813da98dSDavid E. O'Brien void SYNTAX(const char *fmt, ...) 6802a55deb1SDavid E. O'Brien { 6812a55deb1SDavid E. O'Brien extern char *cmdname, *curfname; 6822a55deb1SDavid E. O'Brien static int been_here = 0; 6832a55deb1SDavid E. O'Brien va_list varg; 6842a55deb1SDavid E. O'Brien 6852a55deb1SDavid E. O'Brien if (been_here++ > 2) 6862a55deb1SDavid E. O'Brien return; 6872a55deb1SDavid E. O'Brien fprintf(stderr, "%s: ", cmdname); 6882a55deb1SDavid E. O'Brien va_start(varg, fmt); 6892a55deb1SDavid E. O'Brien vfprintf(stderr, fmt, varg); 6902a55deb1SDavid E. O'Brien va_end(varg); 6912a55deb1SDavid E. O'Brien fprintf(stderr, " at source line %d", lineno); 6922a55deb1SDavid E. O'Brien if (curfname != NULL) 6932a55deb1SDavid E. O'Brien fprintf(stderr, " in function %s", curfname); 694f39dd6a9SWarner Losh if (compile_time == COMPILING && cursource() != NULL) 6952a55deb1SDavid E. O'Brien fprintf(stderr, " source file %s", cursource()); 6962a55deb1SDavid E. O'Brien fprintf(stderr, "\n"); 6972a55deb1SDavid E. O'Brien errorflag = 2; 6982a55deb1SDavid E. O'Brien eprint(); 6992a55deb1SDavid E. O'Brien } 7002a55deb1SDavid E. O'Brien 7012a55deb1SDavid E. O'Brien extern int bracecnt, brackcnt, parencnt; 7022a55deb1SDavid E. O'Brien 7032a55deb1SDavid E. O'Brien void bracecheck(void) 7042a55deb1SDavid E. O'Brien { 7052a55deb1SDavid E. O'Brien int c; 7062a55deb1SDavid E. O'Brien static int beenhere = 0; 7072a55deb1SDavid E. O'Brien 7082a55deb1SDavid E. O'Brien if (beenhere++) 7092a55deb1SDavid E. O'Brien return; 7102a55deb1SDavid E. O'Brien while ((c = input()) != EOF && c != '\0') 7112a55deb1SDavid E. O'Brien bclass(c); 7122a55deb1SDavid E. O'Brien bcheck2(bracecnt, '{', '}'); 7132a55deb1SDavid E. O'Brien bcheck2(brackcnt, '[', ']'); 7142a55deb1SDavid E. O'Brien bcheck2(parencnt, '(', ')'); 7152a55deb1SDavid E. O'Brien } 7162a55deb1SDavid E. O'Brien 7172a55deb1SDavid E. O'Brien void bcheck2(int n, int c1, int c2) 7182a55deb1SDavid E. O'Brien { 7192a55deb1SDavid E. O'Brien if (n == 1) 7202a55deb1SDavid E. O'Brien fprintf(stderr, "\tmissing %c\n", c2); 7212a55deb1SDavid E. O'Brien else if (n > 1) 7222a55deb1SDavid E. O'Brien fprintf(stderr, "\t%d missing %c's\n", n, c2); 7232a55deb1SDavid E. O'Brien else if (n == -1) 7242a55deb1SDavid E. O'Brien fprintf(stderr, "\textra %c\n", c2); 7252a55deb1SDavid E. O'Brien else if (n < -1) 7262a55deb1SDavid E. O'Brien fprintf(stderr, "\t%d extra %c's\n", -n, c2); 7272a55deb1SDavid E. O'Brien } 7282a55deb1SDavid E. O'Brien 729813da98dSDavid E. O'Brien void FATAL(const char *fmt, ...) 7302a55deb1SDavid E. O'Brien { 7312a55deb1SDavid E. O'Brien extern char *cmdname; 7322a55deb1SDavid E. O'Brien va_list varg; 7332a55deb1SDavid E. O'Brien 7342a55deb1SDavid E. O'Brien fflush(stdout); 7352a55deb1SDavid E. O'Brien fprintf(stderr, "%s: ", cmdname); 7362a55deb1SDavid E. O'Brien va_start(varg, fmt); 7372a55deb1SDavid E. O'Brien vfprintf(stderr, fmt, varg); 7382a55deb1SDavid E. O'Brien va_end(varg); 7392a55deb1SDavid E. O'Brien error(); 7402a55deb1SDavid E. O'Brien if (dbg > 1) /* core dump if serious debugging on */ 7412a55deb1SDavid E. O'Brien abort(); 7422a55deb1SDavid E. O'Brien exit(2); 7432a55deb1SDavid E. O'Brien } 7442a55deb1SDavid E. O'Brien 745813da98dSDavid E. O'Brien void WARNING(const char *fmt, ...) 7462a55deb1SDavid E. O'Brien { 7472a55deb1SDavid E. O'Brien extern char *cmdname; 7482a55deb1SDavid E. O'Brien va_list varg; 7492a55deb1SDavid E. O'Brien 7502a55deb1SDavid E. O'Brien fflush(stdout); 7512a55deb1SDavid E. O'Brien fprintf(stderr, "%s: ", cmdname); 7522a55deb1SDavid E. O'Brien va_start(varg, fmt); 7532a55deb1SDavid E. O'Brien vfprintf(stderr, fmt, varg); 7542a55deb1SDavid E. O'Brien va_end(varg); 7552a55deb1SDavid E. O'Brien error(); 7562a55deb1SDavid E. O'Brien } 7572a55deb1SDavid E. O'Brien 7582a55deb1SDavid E. O'Brien void error() 7592a55deb1SDavid E. O'Brien { 7602a55deb1SDavid E. O'Brien extern Node *curnode; 7612a55deb1SDavid E. O'Brien 7622a55deb1SDavid E. O'Brien fprintf(stderr, "\n"); 763f39dd6a9SWarner Losh if (compile_time != ERROR_PRINTING) { 764f39dd6a9SWarner Losh if (NR && *NR > 0) { 7652a55deb1SDavid E. O'Brien fprintf(stderr, " input record number %d", (int) (*FNR)); 7662a55deb1SDavid E. O'Brien if (strcmp(*FILENAME, "-") != 0) 7672a55deb1SDavid E. O'Brien fprintf(stderr, ", file %s", *FILENAME); 7682a55deb1SDavid E. O'Brien fprintf(stderr, "\n"); 7692a55deb1SDavid E. O'Brien } 770f39dd6a9SWarner Losh if (curnode) 7712a55deb1SDavid E. O'Brien fprintf(stderr, " source line number %d", curnode->lineno); 772f39dd6a9SWarner Losh else if (lineno) 7732a55deb1SDavid E. O'Brien fprintf(stderr, " source line number %d", lineno); 774f39dd6a9SWarner Losh if (compile_time == COMPILING && cursource() != NULL) 7752a55deb1SDavid E. O'Brien fprintf(stderr, " source file %s", cursource()); 7762a55deb1SDavid E. O'Brien fprintf(stderr, "\n"); 7772a55deb1SDavid E. O'Brien eprint(); 7782a55deb1SDavid E. O'Brien } 779f39dd6a9SWarner Losh } 7802a55deb1SDavid E. O'Brien 7812a55deb1SDavid E. O'Brien void eprint(void) /* try to print context around error */ 7822a55deb1SDavid E. O'Brien { 7832a55deb1SDavid E. O'Brien char *p, *q; 7842a55deb1SDavid E. O'Brien int c; 7852a55deb1SDavid E. O'Brien static int been_here = 0; 7862a55deb1SDavid E. O'Brien extern char ebuf[], *ep; 7872a55deb1SDavid E. O'Brien 788f39dd6a9SWarner Losh if (compile_time != COMPILING || been_here++ > 0 || ebuf == ep) 7892a55deb1SDavid E. O'Brien return; 790b5253557SWarner Losh if (ebuf == ep) 791b5253557SWarner Losh return; 7922a55deb1SDavid E. O'Brien p = ep - 1; 7932a55deb1SDavid E. O'Brien if (p > ebuf && *p == '\n') 7942a55deb1SDavid E. O'Brien p--; 7952a55deb1SDavid E. O'Brien for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--) 7962a55deb1SDavid E. O'Brien ; 7972a55deb1SDavid E. O'Brien while (*p == '\n') 7982a55deb1SDavid E. O'Brien p++; 7992a55deb1SDavid E. O'Brien fprintf(stderr, " context is\n\t"); 8002a55deb1SDavid E. O'Brien for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) 8012a55deb1SDavid E. O'Brien ; 8022a55deb1SDavid E. O'Brien for ( ; p < q; p++) 8032a55deb1SDavid E. O'Brien if (*p) 8042a55deb1SDavid E. O'Brien putc(*p, stderr); 8052a55deb1SDavid E. O'Brien fprintf(stderr, " >>> "); 8062a55deb1SDavid E. O'Brien for ( ; p < ep; p++) 8072a55deb1SDavid E. O'Brien if (*p) 8082a55deb1SDavid E. O'Brien putc(*p, stderr); 8092a55deb1SDavid E. O'Brien fprintf(stderr, " <<< "); 8102a55deb1SDavid E. O'Brien if (*ep) 8112a55deb1SDavid E. O'Brien while ((c = input()) != '\n' && c != '\0' && c != EOF) { 8122a55deb1SDavid E. O'Brien putc(c, stderr); 8132a55deb1SDavid E. O'Brien bclass(c); 8142a55deb1SDavid E. O'Brien } 8152a55deb1SDavid E. O'Brien putc('\n', stderr); 8162a55deb1SDavid E. O'Brien ep = ebuf; 8172a55deb1SDavid E. O'Brien } 8182a55deb1SDavid E. O'Brien 8192a55deb1SDavid E. O'Brien void bclass(int c) 8202a55deb1SDavid E. O'Brien { 8212a55deb1SDavid E. O'Brien switch (c) { 8222a55deb1SDavid E. O'Brien case '{': bracecnt++; break; 8232a55deb1SDavid E. O'Brien case '}': bracecnt--; break; 8242a55deb1SDavid E. O'Brien case '[': brackcnt++; break; 8252a55deb1SDavid E. O'Brien case ']': brackcnt--; break; 8262a55deb1SDavid E. O'Brien case '(': parencnt++; break; 8272a55deb1SDavid E. O'Brien case ')': parencnt--; break; 8282a55deb1SDavid E. O'Brien } 8292a55deb1SDavid E. O'Brien } 8302a55deb1SDavid E. O'Brien 831813da98dSDavid E. O'Brien double errcheck(double x, const char *s) 8322a55deb1SDavid E. O'Brien { 8332a55deb1SDavid E. O'Brien 8342a55deb1SDavid E. O'Brien if (errno == EDOM) { 8352a55deb1SDavid E. O'Brien errno = 0; 8362a55deb1SDavid E. O'Brien WARNING("%s argument out of domain", s); 8372a55deb1SDavid E. O'Brien x = 1; 8382a55deb1SDavid E. O'Brien } else if (errno == ERANGE) { 8392a55deb1SDavid E. O'Brien errno = 0; 8402a55deb1SDavid E. O'Brien WARNING("%s result out of range", s); 8412a55deb1SDavid E. O'Brien x = 1; 8422a55deb1SDavid E. O'Brien } 8432a55deb1SDavid E. O'Brien return x; 8442a55deb1SDavid E. O'Brien } 8452a55deb1SDavid E. O'Brien 846813da98dSDavid E. O'Brien int isclvar(const char *s) /* is s of form var=something ? */ 8472a55deb1SDavid E. O'Brien { 848813da98dSDavid E. O'Brien const char *os = s; 8492a55deb1SDavid E. O'Brien 850f32a6403SWarner Losh if (!isalpha((int) *s) && *s != '_') 8512a55deb1SDavid E. O'Brien return 0; 8522a55deb1SDavid E. O'Brien for ( ; *s; s++) 853f32a6403SWarner Losh if (!(isalnum((int) *s) || *s == '_')) 8542a55deb1SDavid E. O'Brien break; 855b5253557SWarner Losh return *s == '=' && s > os; 8562a55deb1SDavid E. O'Brien } 8572a55deb1SDavid E. O'Brien 8582a55deb1SDavid E. O'Brien /* strtod is supposed to be a proper test of what's a valid number */ 8592a55deb1SDavid E. O'Brien /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */ 8602a55deb1SDavid E. O'Brien /* wrong: violates 4.10.1.4 of ansi C standard */ 8612a55deb1SDavid E. O'Brien 862f39dd6a9SWarner Losh /* well, not quite. As of C99, hex floating point is allowed. so this is 863f39dd6a9SWarner Losh * a bit of a mess. We work around the mess by checking for a hexadecimal 864f39dd6a9SWarner Losh * value and disallowing it. Similarly, we now follow gawk and allow only 865f39dd6a9SWarner Losh * +nan, -nan, +inf, and -inf for NaN and infinity values. 866f39dd6a9SWarner Losh */ 867f39dd6a9SWarner Losh 868f39dd6a9SWarner Losh /* 869f39dd6a9SWarner Losh * This routine now has a more complicated interface, the main point 870f39dd6a9SWarner Losh * being to avoid the double conversion of a string to double, and 871f39dd6a9SWarner Losh * also to convey out, if requested, the information that the numeric 872f39dd6a9SWarner Losh * value was a leading string or is all of the string. The latter bit 873f39dd6a9SWarner Losh * is used in getfval(). 874f39dd6a9SWarner Losh */ 875f39dd6a9SWarner Losh 876f39dd6a9SWarner Losh bool is_valid_number(const char *s, bool trailing_stuff_ok, 877f39dd6a9SWarner Losh bool *no_trailing, double *result) 8782a55deb1SDavid E. O'Brien { 8792a55deb1SDavid E. O'Brien double r; 8802a55deb1SDavid E. O'Brien char *ep; 881f39dd6a9SWarner Losh bool retval = false; 882f39dd6a9SWarner Losh bool is_nan = false; 883f39dd6a9SWarner Losh bool is_inf = false; 884f39dd6a9SWarner Losh 885f39dd6a9SWarner Losh if (no_trailing) 886f39dd6a9SWarner Losh *no_trailing = false; 887f39dd6a9SWarner Losh 888f32a6403SWarner Losh while (isspace((int) *s)) 889f39dd6a9SWarner Losh s++; 890f39dd6a9SWarner Losh 891f32a6403SWarner Losh /* no hex floating point, sorry */ 892f39dd6a9SWarner Losh if (s[0] == '0' && tolower(s[1]) == 'x') 893f39dd6a9SWarner Losh return false; 894f39dd6a9SWarner Losh 895f32a6403SWarner Losh /* allow +nan, -nan, +inf, -inf, any other letter, no */ 896f39dd6a9SWarner Losh if (s[0] == '+' || s[0] == '-') { 897f39dd6a9SWarner Losh is_nan = (strncasecmp(s+1, "nan", 3) == 0); 898f39dd6a9SWarner Losh is_inf = (strncasecmp(s+1, "inf", 3) == 0); 899f39dd6a9SWarner Losh if ((is_nan || is_inf) 900f32a6403SWarner Losh && (isspace((int) s[4]) || s[4] == '\0')) 901f39dd6a9SWarner Losh goto convert; 902f39dd6a9SWarner Losh else if (! isdigit(s[1]) && s[1] != '.') 903f39dd6a9SWarner Losh return false; 904f39dd6a9SWarner Losh } 905f39dd6a9SWarner Losh else if (! isdigit(s[0]) && s[0] != '.') 906f39dd6a9SWarner Losh return false; 907f39dd6a9SWarner Losh 908f39dd6a9SWarner Losh convert: 9092a55deb1SDavid E. O'Brien errno = 0; 9102a55deb1SDavid E. O'Brien r = strtod(s, &ep); 911f39dd6a9SWarner Losh if (ep == s || errno == ERANGE) 912f39dd6a9SWarner Losh return false; 913f39dd6a9SWarner Losh 914f39dd6a9SWarner Losh if (isnan(r) && s[0] == '-' && signbit(r) == 0) 915f39dd6a9SWarner Losh r = -r; 916f39dd6a9SWarner Losh 917f39dd6a9SWarner Losh if (result != NULL) 918f39dd6a9SWarner Losh *result = r; 919f39dd6a9SWarner Losh 920f39dd6a9SWarner Losh /* 921f39dd6a9SWarner Losh * check for trailing stuff 922f39dd6a9SWarner Losh */ 923f32a6403SWarner Losh while (isspace((int) *ep)) 9242a55deb1SDavid E. O'Brien ep++; 925f39dd6a9SWarner Losh 926f39dd6a9SWarner Losh if (no_trailing != NULL) 927f39dd6a9SWarner Losh *no_trailing = (*ep == '\0'); 928f39dd6a9SWarner Losh 929f32a6403SWarner Losh /* return true if found the end, or trailing stuff is allowed */ 930f39dd6a9SWarner Losh retval = *ep == '\0' || trailing_stuff_ok; 931f39dd6a9SWarner Losh 932f39dd6a9SWarner Losh return retval; 9332a55deb1SDavid E. O'Brien } 934