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> 284b588458SPeter Avalos #include <ctype.h> 294b588458SPeter Avalos #include <errno.h> 304b588458SPeter Avalos #include <stdlib.h> 314b588458SPeter Avalos #include <stdarg.h> 32*1d48fce0SDaniel Fojt #include <limits.h> 334b588458SPeter Avalos #include "awk.h" 344b588458SPeter Avalos #include "ytab.h" 354b588458SPeter Avalos 36*1d48fce0SDaniel Fojt char EMPTY[] = { '\0' }; 374b588458SPeter Avalos FILE *infile = NULL; 38*1d48fce0SDaniel Fojt bool innew; /* true = infile has not been read by readrec */ 39*1d48fce0SDaniel Fojt char *file = EMPTY; 404b588458SPeter Avalos char *record; 414b588458SPeter Avalos int recsize = RECSIZE; 424b588458SPeter Avalos char *fields; 434b588458SPeter Avalos int fieldssize = RECSIZE; 444b588458SPeter Avalos 454b588458SPeter Avalos Cell **fldtab; /* pointers to Cells */ 46*1d48fce0SDaniel Fojt static size_t len_inputFS = 0; 47*1d48fce0SDaniel Fojt static char *inputFS = NULL; /* FS at time of input, for field splitting */ 484b588458SPeter Avalos 494b588458SPeter Avalos #define MAXFLD 2 504b588458SPeter Avalos int nfields = MAXFLD; /* last allocated slot for $i */ 514b588458SPeter Avalos 52*1d48fce0SDaniel Fojt bool donefld; /* true = implies rec broken into fields */ 53*1d48fce0SDaniel Fojt bool donerec; /* true = record is valid (no flds have changed) */ 544b588458SPeter Avalos 554b588458SPeter Avalos int lastfld = 0; /* last used field */ 564b588458SPeter Avalos int argno = 1; /* current input argument number */ 574b588458SPeter Avalos extern Awkfloat *ARGC; 584b588458SPeter Avalos 59*1d48fce0SDaniel Fojt static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL, NULL }; 60*1d48fce0SDaniel Fojt static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL, NULL }; 614b588458SPeter Avalos 624b588458SPeter Avalos void recinit(unsigned int n) 634b588458SPeter Avalos { 64*1d48fce0SDaniel Fojt if ( (record = malloc(n)) == NULL 65*1d48fce0SDaniel Fojt || (fields = malloc(n+1)) == NULL 66*1d48fce0SDaniel Fojt || (fldtab = calloc(nfields+2, sizeof(*fldtab))) == NULL 67*1d48fce0SDaniel Fojt || (fldtab[0] = malloc(sizeof(**fldtab))) == NULL) 684b588458SPeter Avalos FATAL("out of space for $0 and fields"); 69*1d48fce0SDaniel Fojt *record = '\0'; 704b588458SPeter Avalos *fldtab[0] = dollar0; 714b588458SPeter Avalos fldtab[0]->sval = record; 724b588458SPeter Avalos fldtab[0]->nval = tostring("0"); 734b588458SPeter Avalos makefields(1, nfields); 744b588458SPeter Avalos } 754b588458SPeter Avalos 764b588458SPeter Avalos void makefields(int n1, int n2) /* create $n1..$n2 inclusive */ 774b588458SPeter Avalos { 784b588458SPeter Avalos char temp[50]; 794b588458SPeter Avalos int i; 804b588458SPeter Avalos 814b588458SPeter Avalos for (i = n1; i <= n2; i++) { 82*1d48fce0SDaniel Fojt fldtab[i] = malloc(sizeof(**fldtab)); 834b588458SPeter Avalos if (fldtab[i] == NULL) 844b588458SPeter Avalos FATAL("out of space in makefields %d", i); 854b588458SPeter Avalos *fldtab[i] = dollar1; 86*1d48fce0SDaniel Fojt snprintf(temp, sizeof(temp), "%d", i); 874b588458SPeter Avalos fldtab[i]->nval = tostring(temp); 884b588458SPeter Avalos } 894b588458SPeter Avalos } 904b588458SPeter Avalos 914b588458SPeter Avalos void initgetrec(void) 924b588458SPeter Avalos { 934b588458SPeter Avalos int i; 944b588458SPeter Avalos char *p; 954b588458SPeter Avalos 964b588458SPeter Avalos for (i = 1; i < *ARGC; i++) { 97b12bae18SSascha Wildner p = getargv(i); /* find 1st real filename */ 98b12bae18SSascha Wildner if (p == NULL || *p == '\0') { /* deleted or zapped */ 99b12bae18SSascha Wildner argno++; 100b12bae18SSascha Wildner continue; 101b12bae18SSascha Wildner } 102b12bae18SSascha Wildner if (!isclvar(p)) { 103b12bae18SSascha Wildner setsval(lookup("FILENAME", symtab), p); 1044b588458SPeter Avalos return; 1054b588458SPeter Avalos } 1064b588458SPeter Avalos setclvar(p); /* a commandline assignment before filename */ 1074b588458SPeter Avalos argno++; 1084b588458SPeter Avalos } 1094b588458SPeter Avalos infile = stdin; /* no filenames, so use stdin */ 110*1d48fce0SDaniel Fojt innew = true; 1114b588458SPeter Avalos } 1124b588458SPeter Avalos 113*1d48fce0SDaniel Fojt /* 114*1d48fce0SDaniel Fojt * POSIX specifies that fields are supposed to be evaluated as if they were 115*1d48fce0SDaniel Fojt * split using the value of FS at the time that the record's value ($0) was 116*1d48fce0SDaniel Fojt * read. 117*1d48fce0SDaniel Fojt * 118*1d48fce0SDaniel Fojt * Since field-splitting is done lazily, we save the current value of FS 119*1d48fce0SDaniel Fojt * whenever a new record is read in (implicitly or via getline), or when 120*1d48fce0SDaniel Fojt * a new value is assigned to $0. 121*1d48fce0SDaniel Fojt */ 122*1d48fce0SDaniel Fojt void savefs(void) 123*1d48fce0SDaniel Fojt { 124*1d48fce0SDaniel Fojt size_t len; 125*1d48fce0SDaniel Fojt if ((len = strlen(getsval(fsloc))) < len_inputFS) { 126*1d48fce0SDaniel Fojt strcpy(inputFS, *FS); /* for subsequent field splitting */ 127*1d48fce0SDaniel Fojt return; 128*1d48fce0SDaniel Fojt } 1294b588458SPeter Avalos 130*1d48fce0SDaniel Fojt len_inputFS = len + 1; 131*1d48fce0SDaniel Fojt inputFS = realloc(inputFS, len_inputFS); 132*1d48fce0SDaniel Fojt if (inputFS == NULL) 133*1d48fce0SDaniel Fojt FATAL("field separator %.10s... is too long", *FS); 134*1d48fce0SDaniel Fojt memcpy(inputFS, *FS, len_inputFS); 135*1d48fce0SDaniel Fojt } 136*1d48fce0SDaniel Fojt 137*1d48fce0SDaniel Fojt static bool firsttime = true; 138*1d48fce0SDaniel Fojt 139*1d48fce0SDaniel Fojt int getrec(char **pbuf, int *pbufsize, bool isrecord) /* get next input record */ 1404b588458SPeter Avalos { /* note: cares whether buf == record */ 1414b588458SPeter Avalos int c; 1424b588458SPeter Avalos char *buf = *pbuf; 1434b588458SPeter Avalos uschar saveb0; 1444b588458SPeter Avalos int bufsize = *pbufsize, savebufsize = bufsize; 1454b588458SPeter Avalos 1464b588458SPeter Avalos if (firsttime) { 147*1d48fce0SDaniel Fojt firsttime = false; 1484b588458SPeter Avalos initgetrec(); 1494b588458SPeter Avalos } 1504b588458SPeter Avalos dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n", 1514b588458SPeter Avalos *RS, *FS, *ARGC, *FILENAME) ); 1524b588458SPeter Avalos if (isrecord) { 153*1d48fce0SDaniel Fojt donefld = false; 154*1d48fce0SDaniel Fojt donerec = true; 155*1d48fce0SDaniel Fojt savefs(); 1564b588458SPeter Avalos } 1574b588458SPeter Avalos saveb0 = buf[0]; 1584b588458SPeter Avalos buf[0] = 0; 1594b588458SPeter Avalos while (argno < *ARGC || infile == stdin) { 1604b588458SPeter Avalos dprintf( ("argno=%d, file=|%s|\n", argno, file) ); 1614b588458SPeter Avalos if (infile == NULL) { /* have to open a new file */ 1624b588458SPeter Avalos file = getargv(argno); 163b12bae18SSascha Wildner if (file == NULL || *file == '\0') { /* deleted or zapped */ 1644b588458SPeter Avalos argno++; 1654b588458SPeter Avalos continue; 1664b588458SPeter Avalos } 1674b588458SPeter Avalos if (isclvar(file)) { /* a var=value arg */ 1684b588458SPeter Avalos setclvar(file); 1694b588458SPeter Avalos argno++; 1704b588458SPeter Avalos continue; 1714b588458SPeter Avalos } 1724b588458SPeter Avalos *FILENAME = file; 1734b588458SPeter Avalos dprintf( ("opening file %s\n", file) ); 1744b588458SPeter Avalos if (*file == '-' && *(file+1) == '\0') 1754b588458SPeter Avalos infile = stdin; 1764b588458SPeter Avalos else if ((infile = fopen(file, "r")) == NULL) 1774b588458SPeter Avalos FATAL("can't open file %s", file); 1784b588458SPeter Avalos setfval(fnrloc, 0.0); 1794b588458SPeter Avalos } 180*1d48fce0SDaniel Fojt c = readrec(&buf, &bufsize, infile, innew); 181*1d48fce0SDaniel Fojt if (innew) 182*1d48fce0SDaniel Fojt innew = false; 1834b588458SPeter Avalos if (c != 0 || buf[0] != '\0') { /* normal record */ 1844b588458SPeter Avalos if (isrecord) { 1854b588458SPeter Avalos if (freeable(fldtab[0])) 1864b588458SPeter Avalos xfree(fldtab[0]->sval); 1874b588458SPeter Avalos fldtab[0]->sval = buf; /* buf == record */ 1884b588458SPeter Avalos fldtab[0]->tval = REC | STR | DONTFREE; 1894b588458SPeter Avalos if (is_number(fldtab[0]->sval)) { 1904b588458SPeter Avalos fldtab[0]->fval = atof(fldtab[0]->sval); 1914b588458SPeter Avalos fldtab[0]->tval |= NUM; 1924b588458SPeter Avalos } 1934b588458SPeter Avalos } 1944b588458SPeter Avalos setfval(nrloc, nrloc->fval+1); 1954b588458SPeter Avalos setfval(fnrloc, fnrloc->fval+1); 1964b588458SPeter Avalos *pbuf = buf; 1974b588458SPeter Avalos *pbufsize = bufsize; 1984b588458SPeter Avalos return 1; 1994b588458SPeter Avalos } 2004b588458SPeter Avalos /* EOF arrived on this file; set up next */ 2014b588458SPeter Avalos if (infile != stdin) 2024b588458SPeter Avalos fclose(infile); 2034b588458SPeter Avalos infile = NULL; 2044b588458SPeter Avalos argno++; 2054b588458SPeter Avalos } 2064b588458SPeter Avalos buf[0] = saveb0; 2074b588458SPeter Avalos *pbuf = buf; 2084b588458SPeter Avalos *pbufsize = savebufsize; 2094b588458SPeter Avalos return 0; /* true end of file */ 2104b588458SPeter Avalos } 2114b588458SPeter Avalos 2124b588458SPeter Avalos void nextfile(void) 2134b588458SPeter Avalos { 2144b588458SPeter Avalos if (infile != NULL && infile != stdin) 2154b588458SPeter Avalos fclose(infile); 2164b588458SPeter Avalos infile = NULL; 2174b588458SPeter Avalos argno++; 2184b588458SPeter Avalos } 2194b588458SPeter Avalos 220*1d48fce0SDaniel Fojt int readrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag) /* read one record into buf */ 2214b588458SPeter Avalos { 222*1d48fce0SDaniel Fojt int sep, c, isrec; 2234b588458SPeter Avalos char *rr, *buf = *pbuf; 2244b588458SPeter Avalos int bufsize = *pbufsize; 225*1d48fce0SDaniel Fojt char *rs = getsval(rsloc); 2264b588458SPeter Avalos 227*1d48fce0SDaniel Fojt if (*rs && rs[1]) { 228*1d48fce0SDaniel Fojt bool found; 229*1d48fce0SDaniel Fojt 230*1d48fce0SDaniel Fojt fa *pfa = makedfa(rs, 1); 231*1d48fce0SDaniel Fojt if (newflag) 232*1d48fce0SDaniel Fojt found = fnematch(pfa, inf, &buf, &bufsize, recsize); 233*1d48fce0SDaniel Fojt else { 234*1d48fce0SDaniel Fojt int tempstat = pfa->initstat; 235*1d48fce0SDaniel Fojt pfa->initstat = 2; 236*1d48fce0SDaniel Fojt found = fnematch(pfa, inf, &buf, &bufsize, recsize); 237*1d48fce0SDaniel Fojt pfa->initstat = tempstat; 238*1d48fce0SDaniel Fojt } 239*1d48fce0SDaniel Fojt if (found) 240*1d48fce0SDaniel Fojt setptr(patbeg, '\0'); 241*1d48fce0SDaniel Fojt } else { 242*1d48fce0SDaniel Fojt if ((sep = *rs) == 0) { 2434b588458SPeter Avalos sep = '\n'; 2444b588458SPeter Avalos while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */ 2454b588458SPeter Avalos ; 2464b588458SPeter Avalos if (c != EOF) 2474b588458SPeter Avalos ungetc(c, inf); 2484b588458SPeter Avalos } 2494b588458SPeter Avalos for (rr = buf; ; ) { 2504b588458SPeter Avalos for (; (c=getc(inf)) != sep && c != EOF; ) { 2514b588458SPeter Avalos if (rr-buf+1 > bufsize) 252*1d48fce0SDaniel Fojt if (!adjbuf(&buf, &bufsize, 1+rr-buf, 253*1d48fce0SDaniel Fojt recsize, &rr, "readrec 1")) 2544b588458SPeter Avalos FATAL("input record `%.30s...' too long", buf); 2554b588458SPeter Avalos *rr++ = c; 2564b588458SPeter Avalos } 257*1d48fce0SDaniel Fojt if (*rs == sep || c == EOF) 2584b588458SPeter Avalos break; 2594b588458SPeter Avalos if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */ 2604b588458SPeter Avalos break; 261*1d48fce0SDaniel Fojt if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, 262*1d48fce0SDaniel Fojt "readrec 2")) 2634b588458SPeter Avalos FATAL("input record `%.30s...' too long", buf); 2644b588458SPeter Avalos *rr++ = '\n'; 2654b588458SPeter Avalos *rr++ = c; 2664b588458SPeter Avalos } 2674b588458SPeter Avalos if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3")) 2684b588458SPeter Avalos FATAL("input record `%.30s...' too long", buf); 2694b588458SPeter Avalos *rr = 0; 270*1d48fce0SDaniel Fojt } 2714b588458SPeter Avalos *pbuf = buf; 2724b588458SPeter Avalos *pbufsize = bufsize; 273*1d48fce0SDaniel Fojt isrec = *buf || !feof(inf); 274*1d48fce0SDaniel Fojt dprintf( ("readrec saw <%s>, returns %d\n", buf, isrec) ); 275*1d48fce0SDaniel Fojt return isrec; 2764b588458SPeter Avalos } 2774b588458SPeter Avalos 2784b588458SPeter Avalos char *getargv(int n) /* get ARGV[n] */ 2794b588458SPeter Avalos { 2804b588458SPeter Avalos Cell *x; 2814b588458SPeter Avalos char *s, temp[50]; 2824b588458SPeter Avalos extern Array *ARGVtab; 2834b588458SPeter Avalos 284*1d48fce0SDaniel Fojt snprintf(temp, sizeof(temp), "%d", n); 285b12bae18SSascha Wildner if (lookup(temp, ARGVtab) == NULL) 286b12bae18SSascha Wildner return NULL; 2874b588458SPeter Avalos x = setsymtab(temp, "", 0.0, STR, ARGVtab); 2884b588458SPeter Avalos s = getsval(x); 2894b588458SPeter Avalos dprintf( ("getargv(%d) returns |%s|\n", n, s) ); 2904b588458SPeter Avalos return s; 2914b588458SPeter Avalos } 2924b588458SPeter Avalos 2934b588458SPeter Avalos void setclvar(char *s) /* set var=value from s */ 2944b588458SPeter Avalos { 2954b588458SPeter Avalos char *p; 2964b588458SPeter Avalos Cell *q; 2974b588458SPeter Avalos 2984b588458SPeter Avalos for (p=s; *p != '='; p++) 2994b588458SPeter Avalos ; 3004b588458SPeter Avalos *p++ = 0; 3014b588458SPeter Avalos p = qstring(p, '\0'); 3024b588458SPeter Avalos q = setsymtab(s, p, 0.0, STR, symtab); 3034b588458SPeter Avalos setsval(q, p); 3044b588458SPeter Avalos if (is_number(q->sval)) { 3054b588458SPeter Avalos q->fval = atof(q->sval); 3064b588458SPeter Avalos q->tval |= NUM; 3074b588458SPeter Avalos } 3084b588458SPeter Avalos dprintf( ("command line set %s to |%s|\n", s, p) ); 3094b588458SPeter Avalos } 3104b588458SPeter Avalos 3114b588458SPeter Avalos 3124b588458SPeter Avalos void fldbld(void) /* create fields from current record */ 3134b588458SPeter Avalos { 3144b588458SPeter Avalos /* this relies on having fields[] the same length as $0 */ 3154b588458SPeter Avalos /* the fields are all stored in this one array with \0's */ 3160020174dSPeter Avalos /* possibly with a final trailing \0 not associated with any field */ 3174b588458SPeter Avalos char *r, *fr, sep; 3184b588458SPeter Avalos Cell *p; 3194b588458SPeter Avalos int i, j, n; 3204b588458SPeter Avalos 3214b588458SPeter Avalos if (donefld) 3224b588458SPeter Avalos return; 3234b588458SPeter Avalos if (!isstr(fldtab[0])) 3244b588458SPeter Avalos getsval(fldtab[0]); 3254b588458SPeter Avalos r = fldtab[0]->sval; 3264b588458SPeter Avalos n = strlen(r); 3274b588458SPeter Avalos if (n > fieldssize) { 3284b588458SPeter Avalos xfree(fields); 329*1d48fce0SDaniel Fojt if ((fields = malloc(n+2)) == NULL) /* possibly 2 final \0s */ 3304b588458SPeter Avalos FATAL("out of space for fields in fldbld %d", n); 3314b588458SPeter Avalos fieldssize = n; 3324b588458SPeter Avalos } 3334b588458SPeter Avalos fr = fields; 3344b588458SPeter Avalos i = 0; /* number of fields accumulated here */ 335*1d48fce0SDaniel Fojt if (inputFS == NULL) /* make sure we have a copy of FS */ 336*1d48fce0SDaniel Fojt savefs(); 3374b588458SPeter Avalos if (strlen(inputFS) > 1) { /* it's a regular expression */ 3384b588458SPeter Avalos i = refldbld(r, inputFS); 3394b588458SPeter Avalos } else if ((sep = *inputFS) == ' ') { /* default whitespace */ 3404b588458SPeter Avalos for (i = 0; ; ) { 3414b588458SPeter Avalos while (*r == ' ' || *r == '\t' || *r == '\n') 3424b588458SPeter Avalos r++; 3434b588458SPeter Avalos if (*r == 0) 3444b588458SPeter Avalos break; 3454b588458SPeter Avalos i++; 3464b588458SPeter Avalos if (i > nfields) 3474b588458SPeter Avalos growfldtab(i); 3484b588458SPeter Avalos if (freeable(fldtab[i])) 3494b588458SPeter Avalos xfree(fldtab[i]->sval); 3504b588458SPeter Avalos fldtab[i]->sval = fr; 3514b588458SPeter Avalos fldtab[i]->tval = FLD | STR | DONTFREE; 3524b588458SPeter Avalos do 3534b588458SPeter Avalos *fr++ = *r++; 3544b588458SPeter Avalos while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0'); 3554b588458SPeter Avalos *fr++ = 0; 3564b588458SPeter Avalos } 3574b588458SPeter Avalos *fr = 0; 3584b588458SPeter Avalos } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */ 359*1d48fce0SDaniel Fojt for (i = 0; *r != '\0'; r += n) { 360*1d48fce0SDaniel Fojt char buf[MB_LEN_MAX + 1]; 361*1d48fce0SDaniel Fojt 3624b588458SPeter Avalos i++; 3634b588458SPeter Avalos if (i > nfields) 3644b588458SPeter Avalos growfldtab(i); 3654b588458SPeter Avalos if (freeable(fldtab[i])) 3664b588458SPeter Avalos xfree(fldtab[i]->sval); 367*1d48fce0SDaniel Fojt n = mblen(r, MB_LEN_MAX); 368*1d48fce0SDaniel Fojt if (n < 0) 369*1d48fce0SDaniel Fojt n = 1; 370*1d48fce0SDaniel Fojt memcpy(buf, r, n); 371*1d48fce0SDaniel Fojt buf[n] = '\0'; 3724b588458SPeter Avalos fldtab[i]->sval = tostring(buf); 3734b588458SPeter Avalos fldtab[i]->tval = FLD | STR; 3744b588458SPeter Avalos } 3754b588458SPeter Avalos *fr = 0; 3764b588458SPeter Avalos } else if (*r != 0) { /* if 0, it's a null field */ 3774b588458SPeter Avalos /* subtlecase : if length(FS) == 1 && length(RS > 0) 3784b588458SPeter Avalos * \n is NOT a field separator (cf awk book 61,84). 3794b588458SPeter Avalos * this variable is tested in the inner while loop. 3804b588458SPeter Avalos */ 3814b588458SPeter Avalos int rtest = '\n'; /* normal case */ 3824b588458SPeter Avalos if (strlen(*RS) > 0) 3834b588458SPeter Avalos rtest = '\0'; 3844b588458SPeter Avalos for (;;) { 3854b588458SPeter Avalos i++; 3864b588458SPeter Avalos if (i > nfields) 3874b588458SPeter Avalos growfldtab(i); 3884b588458SPeter Avalos if (freeable(fldtab[i])) 3894b588458SPeter Avalos xfree(fldtab[i]->sval); 3904b588458SPeter Avalos fldtab[i]->sval = fr; 3914b588458SPeter Avalos fldtab[i]->tval = FLD | STR | DONTFREE; 3924b588458SPeter Avalos while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */ 3934b588458SPeter Avalos *fr++ = *r++; 3944b588458SPeter Avalos *fr++ = 0; 3954b588458SPeter Avalos if (*r++ == 0) 3964b588458SPeter Avalos break; 3974b588458SPeter Avalos } 3984b588458SPeter Avalos *fr = 0; 3994b588458SPeter Avalos } 4004b588458SPeter Avalos if (i > nfields) 4014b588458SPeter Avalos FATAL("record `%.30s...' has too many fields; can't happen", r); 4024b588458SPeter Avalos cleanfld(i+1, lastfld); /* clean out junk from previous record */ 4034b588458SPeter Avalos lastfld = i; 404*1d48fce0SDaniel Fojt donefld = true; 4054b588458SPeter Avalos for (j = 1; j <= lastfld; j++) { 4064b588458SPeter Avalos p = fldtab[j]; 4074b588458SPeter Avalos if(is_number(p->sval)) { 4084b588458SPeter Avalos p->fval = atof(p->sval); 4094b588458SPeter Avalos p->tval |= NUM; 4104b588458SPeter Avalos } 4114b588458SPeter Avalos } 4124b588458SPeter Avalos setfval(nfloc, (Awkfloat) lastfld); 413*1d48fce0SDaniel Fojt donerec = true; /* restore */ 4144b588458SPeter Avalos if (dbg) { 4154b588458SPeter Avalos for (j = 0; j <= lastfld; j++) { 4164b588458SPeter Avalos p = fldtab[j]; 4174b588458SPeter Avalos printf("field %d (%s): |%s|\n", j, p->nval, p->sval); 4184b588458SPeter Avalos } 4194b588458SPeter Avalos } 4204b588458SPeter Avalos } 4214b588458SPeter Avalos 4224b588458SPeter Avalos void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */ 4234b588458SPeter Avalos { /* nvals remain intact */ 4244b588458SPeter Avalos Cell *p; 4254b588458SPeter Avalos int i; 4264b588458SPeter Avalos 4274b588458SPeter Avalos for (i = n1; i <= n2; i++) { 4284b588458SPeter Avalos p = fldtab[i]; 4294b588458SPeter Avalos if (freeable(p)) 4304b588458SPeter Avalos xfree(p->sval); 431*1d48fce0SDaniel Fojt p->sval = EMPTY, 4324b588458SPeter Avalos p->tval = FLD | STR | DONTFREE; 4334b588458SPeter Avalos } 4344b588458SPeter Avalos } 4354b588458SPeter Avalos 4364b588458SPeter Avalos void newfld(int n) /* add field n after end of existing lastfld */ 4374b588458SPeter Avalos { 4384b588458SPeter Avalos if (n > nfields) 4394b588458SPeter Avalos growfldtab(n); 4404b588458SPeter Avalos cleanfld(lastfld+1, n); 4414b588458SPeter Avalos lastfld = n; 4424b588458SPeter Avalos setfval(nfloc, (Awkfloat) n); 4434b588458SPeter Avalos } 4444b588458SPeter Avalos 445*1d48fce0SDaniel Fojt void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */ 446*1d48fce0SDaniel Fojt { 447*1d48fce0SDaniel Fojt if (n < 0) 448*1d48fce0SDaniel Fojt FATAL("cannot set NF to a negative value"); 449*1d48fce0SDaniel Fojt if (n > nfields) 450*1d48fce0SDaniel Fojt growfldtab(n); 451*1d48fce0SDaniel Fojt 452*1d48fce0SDaniel Fojt if (lastfld < n) 453*1d48fce0SDaniel Fojt cleanfld(lastfld+1, n); 454*1d48fce0SDaniel Fojt else 455*1d48fce0SDaniel Fojt cleanfld(n+1, lastfld); 456*1d48fce0SDaniel Fojt 457*1d48fce0SDaniel Fojt lastfld = n; 458*1d48fce0SDaniel Fojt } 459*1d48fce0SDaniel Fojt 4604b588458SPeter Avalos Cell *fieldadr(int n) /* get nth field */ 4614b588458SPeter Avalos { 4624b588458SPeter Avalos if (n < 0) 4634b588458SPeter Avalos FATAL("trying to access out of range field %d", n); 4644b588458SPeter Avalos if (n > nfields) /* fields after NF are empty */ 4654b588458SPeter Avalos growfldtab(n); /* but does not increase NF */ 4664b588458SPeter Avalos return(fldtab[n]); 4674b588458SPeter Avalos } 4684b588458SPeter Avalos 4694b588458SPeter Avalos void growfldtab(int n) /* make new fields up to at least $n */ 4704b588458SPeter Avalos { 4714b588458SPeter Avalos int nf = 2 * nfields; 4724b588458SPeter Avalos size_t s; 4734b588458SPeter Avalos 4744b588458SPeter Avalos if (n > nf) 4754b588458SPeter Avalos nf = n; 4764b588458SPeter Avalos s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */ 477*1d48fce0SDaniel Fojt if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */ 478*1d48fce0SDaniel Fojt fldtab = realloc(fldtab, s); 4794b588458SPeter Avalos else /* overflow sizeof int */ 4804b588458SPeter Avalos xfree(fldtab); /* make it null */ 4814b588458SPeter Avalos if (fldtab == NULL) 4824b588458SPeter Avalos FATAL("out of space creating %d fields", nf); 4834b588458SPeter Avalos makefields(nfields+1, nf); 4844b588458SPeter Avalos nfields = nf; 4854b588458SPeter Avalos } 4864b588458SPeter Avalos 4874b588458SPeter Avalos int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */ 4884b588458SPeter Avalos { 4894b588458SPeter Avalos /* this relies on having fields[] the same length as $0 */ 4904b588458SPeter Avalos /* the fields are all stored in this one array with \0's */ 4914b588458SPeter Avalos char *fr; 4924b588458SPeter Avalos int i, tempstat, n; 4934b588458SPeter Avalos fa *pfa; 4944b588458SPeter Avalos 4954b588458SPeter Avalos n = strlen(rec); 4964b588458SPeter Avalos if (n > fieldssize) { 4974b588458SPeter Avalos xfree(fields); 498*1d48fce0SDaniel Fojt if ((fields = malloc(n+1)) == NULL) 4994b588458SPeter Avalos FATAL("out of space for fields in refldbld %d", n); 5004b588458SPeter Avalos fieldssize = n; 5014b588458SPeter Avalos } 5024b588458SPeter Avalos fr = fields; 5034b588458SPeter Avalos *fr = '\0'; 5044b588458SPeter Avalos if (*rec == '\0') 5054b588458SPeter Avalos return 0; 5064b588458SPeter Avalos pfa = makedfa(fs, 1); 5074b588458SPeter Avalos dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) ); 5084b588458SPeter Avalos tempstat = pfa->initstat; 5094b588458SPeter Avalos for (i = 1; ; i++) { 5104b588458SPeter Avalos if (i > nfields) 5114b588458SPeter Avalos growfldtab(i); 5124b588458SPeter Avalos if (freeable(fldtab[i])) 5134b588458SPeter Avalos xfree(fldtab[i]->sval); 5144b588458SPeter Avalos fldtab[i]->tval = FLD | STR | DONTFREE; 5154b588458SPeter Avalos fldtab[i]->sval = fr; 5164b588458SPeter Avalos dprintf( ("refldbld: i=%d\n", i) ); 5174b588458SPeter Avalos if (nematch(pfa, rec)) { 5184b588458SPeter Avalos pfa->initstat = 2; /* horrible coupling to b.c */ 5194b588458SPeter Avalos dprintf( ("match %s (%d chars)\n", patbeg, patlen) ); 5204b588458SPeter Avalos strncpy(fr, rec, patbeg-rec); 5214b588458SPeter Avalos fr += patbeg - rec + 1; 5224b588458SPeter Avalos *(fr-1) = '\0'; 5234b588458SPeter Avalos rec = patbeg + patlen; 5244b588458SPeter Avalos } else { 5254b588458SPeter Avalos dprintf( ("no match %s\n", rec) ); 5264b588458SPeter Avalos strcpy(fr, rec); 5274b588458SPeter Avalos pfa->initstat = tempstat; 5284b588458SPeter Avalos break; 5294b588458SPeter Avalos } 5304b588458SPeter Avalos } 5314b588458SPeter Avalos return i; 5324b588458SPeter Avalos } 5334b588458SPeter Avalos 5344b588458SPeter Avalos void recbld(void) /* create $0 from $1..$NF if necessary */ 5354b588458SPeter Avalos { 5364b588458SPeter Avalos int i; 5374b588458SPeter Avalos char *r, *p; 538*1d48fce0SDaniel Fojt char *sep = getsval(ofsloc); 5394b588458SPeter Avalos 540*1d48fce0SDaniel Fojt if (donerec) 5414b588458SPeter Avalos return; 5424b588458SPeter Avalos r = record; 5434b588458SPeter Avalos for (i = 1; i <= *NF; i++) { 5444b588458SPeter Avalos p = getsval(fldtab[i]); 5454b588458SPeter Avalos if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1")) 5464b588458SPeter Avalos FATAL("created $0 `%.30s...' too long", record); 5474b588458SPeter Avalos while ((*r = *p++) != 0) 5484b588458SPeter Avalos r++; 5494b588458SPeter Avalos if (i < *NF) { 550*1d48fce0SDaniel Fojt if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2")) 5514b588458SPeter Avalos FATAL("created $0 `%.30s...' too long", record); 552*1d48fce0SDaniel Fojt for (p = sep; (*r = *p++) != 0; ) 5534b588458SPeter Avalos r++; 5544b588458SPeter Avalos } 5554b588458SPeter Avalos } 5564b588458SPeter Avalos if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3")) 5574b588458SPeter Avalos FATAL("built giant record `%.30s...'", record); 5584b588458SPeter Avalos *r = '\0'; 559b12bae18SSascha Wildner dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) ); 5604b588458SPeter Avalos 5614b588458SPeter Avalos if (freeable(fldtab[0])) 5624b588458SPeter Avalos xfree(fldtab[0]->sval); 5634b588458SPeter Avalos fldtab[0]->tval = REC | STR | DONTFREE; 5644b588458SPeter Avalos fldtab[0]->sval = record; 5654b588458SPeter Avalos 566b12bae18SSascha Wildner dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) ); 5674b588458SPeter Avalos dprintf( ("recbld = |%s|\n", record) ); 568*1d48fce0SDaniel Fojt donerec = true; 5694b588458SPeter Avalos } 5704b588458SPeter Avalos 5714b588458SPeter Avalos int errorflag = 0; 5724b588458SPeter Avalos 5734b588458SPeter Avalos void yyerror(const char *s) 5744b588458SPeter Avalos { 5754b588458SPeter Avalos SYNTAX("%s", s); 5764b588458SPeter Avalos } 5774b588458SPeter Avalos 5784b588458SPeter Avalos void SYNTAX(const char *fmt, ...) 5794b588458SPeter Avalos { 5804b588458SPeter Avalos extern char *cmdname, *curfname; 5814b588458SPeter Avalos static int been_here = 0; 5824b588458SPeter Avalos va_list varg; 5834b588458SPeter Avalos 5844b588458SPeter Avalos if (been_here++ > 2) 5854b588458SPeter Avalos return; 5864b588458SPeter Avalos fprintf(stderr, "%s: ", cmdname); 5874b588458SPeter Avalos va_start(varg, fmt); 5884b588458SPeter Avalos vfprintf(stderr, fmt, varg); 5894b588458SPeter Avalos va_end(varg); 5904b588458SPeter Avalos fprintf(stderr, " at source line %d", lineno); 5914b588458SPeter Avalos if (curfname != NULL) 5924b588458SPeter Avalos fprintf(stderr, " in function %s", curfname); 593*1d48fce0SDaniel Fojt if (compile_time == COMPILING && cursource() != NULL) 5944b588458SPeter Avalos fprintf(stderr, " source file %s", cursource()); 5954b588458SPeter Avalos fprintf(stderr, "\n"); 5964b588458SPeter Avalos errorflag = 2; 5974b588458SPeter Avalos eprint(); 5984b588458SPeter Avalos } 5994b588458SPeter Avalos 6004b588458SPeter Avalos extern int bracecnt, brackcnt, parencnt; 6014b588458SPeter Avalos 6024b588458SPeter Avalos void bracecheck(void) 6034b588458SPeter Avalos { 6044b588458SPeter Avalos int c; 6054b588458SPeter Avalos static int beenhere = 0; 6064b588458SPeter Avalos 6074b588458SPeter Avalos if (beenhere++) 6084b588458SPeter Avalos return; 6094b588458SPeter Avalos while ((c = input()) != EOF && c != '\0') 6104b588458SPeter Avalos bclass(c); 6114b588458SPeter Avalos bcheck2(bracecnt, '{', '}'); 6124b588458SPeter Avalos bcheck2(brackcnt, '[', ']'); 6134b588458SPeter Avalos bcheck2(parencnt, '(', ')'); 6144b588458SPeter Avalos } 6154b588458SPeter Avalos 6164b588458SPeter Avalos void bcheck2(int n, int c1, int c2) 6174b588458SPeter Avalos { 6184b588458SPeter Avalos if (n == 1) 6194b588458SPeter Avalos fprintf(stderr, "\tmissing %c\n", c2); 6204b588458SPeter Avalos else if (n > 1) 6214b588458SPeter Avalos fprintf(stderr, "\t%d missing %c's\n", n, c2); 6224b588458SPeter Avalos else if (n == -1) 6234b588458SPeter Avalos fprintf(stderr, "\textra %c\n", c2); 6244b588458SPeter Avalos else if (n < -1) 6254b588458SPeter Avalos fprintf(stderr, "\t%d extra %c's\n", -n, c2); 6264b588458SPeter Avalos } 6274b588458SPeter Avalos 6284b588458SPeter Avalos void FATAL(const char *fmt, ...) 6294b588458SPeter Avalos { 6304b588458SPeter Avalos extern char *cmdname; 6314b588458SPeter Avalos va_list varg; 6324b588458SPeter Avalos 6334b588458SPeter Avalos fflush(stdout); 6344b588458SPeter Avalos fprintf(stderr, "%s: ", cmdname); 6354b588458SPeter Avalos va_start(varg, fmt); 6364b588458SPeter Avalos vfprintf(stderr, fmt, varg); 6374b588458SPeter Avalos va_end(varg); 6384b588458SPeter Avalos error(); 6394b588458SPeter Avalos if (dbg > 1) /* core dump if serious debugging on */ 6404b588458SPeter Avalos abort(); 6414b588458SPeter Avalos exit(2); 6424b588458SPeter Avalos } 6434b588458SPeter Avalos 6444b588458SPeter Avalos void WARNING(const char *fmt, ...) 6454b588458SPeter Avalos { 6464b588458SPeter Avalos extern char *cmdname; 6474b588458SPeter Avalos va_list varg; 6484b588458SPeter Avalos 6494b588458SPeter Avalos fflush(stdout); 6504b588458SPeter Avalos fprintf(stderr, "%s: ", cmdname); 6514b588458SPeter Avalos va_start(varg, fmt); 6524b588458SPeter Avalos vfprintf(stderr, fmt, varg); 6534b588458SPeter Avalos va_end(varg); 6544b588458SPeter Avalos error(); 6554b588458SPeter Avalos } 6564b588458SPeter Avalos 6574b588458SPeter Avalos void error() 6584b588458SPeter Avalos { 6594b588458SPeter Avalos extern Node *curnode; 6604b588458SPeter Avalos 6614b588458SPeter Avalos fprintf(stderr, "\n"); 662*1d48fce0SDaniel Fojt if (compile_time != ERROR_PRINTING) { 663*1d48fce0SDaniel Fojt if (NR && *NR > 0) { 6644b588458SPeter Avalos fprintf(stderr, " input record number %d", (int) (*FNR)); 6654b588458SPeter Avalos if (strcmp(*FILENAME, "-") != 0) 6664b588458SPeter Avalos fprintf(stderr, ", file %s", *FILENAME); 6674b588458SPeter Avalos fprintf(stderr, "\n"); 6684b588458SPeter Avalos } 669*1d48fce0SDaniel Fojt if (curnode) 6704b588458SPeter Avalos fprintf(stderr, " source line number %d", curnode->lineno); 671*1d48fce0SDaniel Fojt else if (lineno) 6724b588458SPeter Avalos fprintf(stderr, " source line number %d", lineno); 673*1d48fce0SDaniel Fojt } 674*1d48fce0SDaniel Fojt 675*1d48fce0SDaniel Fojt if (compile_time == COMPILING && cursource() != NULL) 6764b588458SPeter Avalos fprintf(stderr, " source file %s", cursource()); 6774b588458SPeter Avalos fprintf(stderr, "\n"); 6784b588458SPeter Avalos eprint(); 6794b588458SPeter Avalos } 6804b588458SPeter Avalos 6814b588458SPeter Avalos void eprint(void) /* try to print context around error */ 6824b588458SPeter Avalos { 6834b588458SPeter Avalos char *p, *q; 6844b588458SPeter Avalos int c; 6854b588458SPeter Avalos static int been_here = 0; 6864b588458SPeter Avalos extern char ebuf[], *ep; 6874b588458SPeter Avalos 688*1d48fce0SDaniel Fojt if (compile_time != COMPILING || been_here++ > 0 || ebuf == ep) 689*1d48fce0SDaniel Fojt return; 690*1d48fce0SDaniel Fojt if (ebuf == ep) 6914b588458SPeter Avalos return; 6924b588458SPeter Avalos p = ep - 1; 6934b588458SPeter Avalos if (p > ebuf && *p == '\n') 6944b588458SPeter Avalos p--; 6954b588458SPeter Avalos for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--) 6964b588458SPeter Avalos ; 6974b588458SPeter Avalos while (*p == '\n') 6984b588458SPeter Avalos p++; 6994b588458SPeter Avalos fprintf(stderr, " context is\n\t"); 7004b588458SPeter Avalos for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) 7014b588458SPeter Avalos ; 7024b588458SPeter Avalos for ( ; p < q; p++) 7034b588458SPeter Avalos if (*p) 7044b588458SPeter Avalos putc(*p, stderr); 7054b588458SPeter Avalos fprintf(stderr, " >>> "); 7064b588458SPeter Avalos for ( ; p < ep; p++) 7074b588458SPeter Avalos if (*p) 7084b588458SPeter Avalos putc(*p, stderr); 7094b588458SPeter Avalos fprintf(stderr, " <<< "); 7104b588458SPeter Avalos if (*ep) 7114b588458SPeter Avalos while ((c = input()) != '\n' && c != '\0' && c != EOF) { 7124b588458SPeter Avalos putc(c, stderr); 7134b588458SPeter Avalos bclass(c); 7144b588458SPeter Avalos } 7154b588458SPeter Avalos putc('\n', stderr); 7164b588458SPeter Avalos ep = ebuf; 7174b588458SPeter Avalos } 7184b588458SPeter Avalos 7194b588458SPeter Avalos void bclass(int c) 7204b588458SPeter Avalos { 7214b588458SPeter Avalos switch (c) { 7224b588458SPeter Avalos case '{': bracecnt++; break; 7234b588458SPeter Avalos case '}': bracecnt--; break; 7244b588458SPeter Avalos case '[': brackcnt++; break; 7254b588458SPeter Avalos case ']': brackcnt--; break; 7264b588458SPeter Avalos case '(': parencnt++; break; 7274b588458SPeter Avalos case ')': parencnt--; break; 7284b588458SPeter Avalos } 7294b588458SPeter Avalos } 7304b588458SPeter Avalos 7314b588458SPeter Avalos double errcheck(double x, const char *s) 7324b588458SPeter Avalos { 7334b588458SPeter Avalos 7344b588458SPeter Avalos if (errno == EDOM) { 7354b588458SPeter Avalos errno = 0; 7364b588458SPeter Avalos WARNING("%s argument out of domain", s); 7374b588458SPeter Avalos x = 1; 7384b588458SPeter Avalos } else if (errno == ERANGE) { 7394b588458SPeter Avalos errno = 0; 7404b588458SPeter Avalos WARNING("%s result out of range", s); 7414b588458SPeter Avalos x = 1; 7424b588458SPeter Avalos } 7434b588458SPeter Avalos return x; 7444b588458SPeter Avalos } 7454b588458SPeter Avalos 7464b588458SPeter Avalos int isclvar(const char *s) /* is s of form var=something ? */ 7474b588458SPeter Avalos { 7484b588458SPeter Avalos const char *os = s; 7494b588458SPeter Avalos 7504b588458SPeter Avalos if (!isalpha((uschar) *s) && *s != '_') 7514b588458SPeter Avalos return 0; 7524b588458SPeter Avalos for ( ; *s; s++) 7534b588458SPeter Avalos if (!(isalnum((uschar) *s) || *s == '_')) 7544b588458SPeter Avalos break; 755*1d48fce0SDaniel Fojt return *s == '=' && s > os; 7564b588458SPeter Avalos } 7574b588458SPeter Avalos 7584b588458SPeter Avalos /* strtod is supposed to be a proper test of what's a valid number */ 7594b588458SPeter Avalos /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */ 7604b588458SPeter Avalos /* wrong: violates 4.10.1.4 of ansi C standard */ 761*1d48fce0SDaniel Fojt /* well, not quite. As of C99, hex floating point is allowed. so this is 762*1d48fce0SDaniel Fojt * a bit of a mess. 763*1d48fce0SDaniel Fojt */ 7644b588458SPeter Avalos 7654b588458SPeter Avalos #include <math.h> 7664b588458SPeter Avalos int is_number(const char *s) 7674b588458SPeter Avalos { 7684b588458SPeter Avalos double r; 7694b588458SPeter Avalos char *ep; 7704b588458SPeter Avalos errno = 0; 7714b588458SPeter Avalos r = strtod(s, &ep); 7724b588458SPeter Avalos if (ep == s || r == HUGE_VAL || errno == ERANGE) 7734b588458SPeter Avalos return 0; 774*1d48fce0SDaniel Fojt /* allow \r as well. windows files aren't going to go away. */ 775*1d48fce0SDaniel Fojt while (*ep == ' ' || *ep == '\t' || *ep == '\n' || *ep == '\r') 7764b588458SPeter Avalos ep++; 7774b588458SPeter Avalos if (*ep == '\0') 7784b588458SPeter Avalos return 1; 7794b588458SPeter Avalos else 7804b588458SPeter Avalos return 0; 7814b588458SPeter Avalos } 782