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> 324b588458SPeter Avalos #include "awk.h" 334b588458SPeter Avalos #include "ytab.h" 344b588458SPeter Avalos 354b588458SPeter Avalos FILE *infile = NULL; 364b588458SPeter Avalos char *file = ""; 374b588458SPeter Avalos char *record; 384b588458SPeter Avalos int recsize = RECSIZE; 394b588458SPeter Avalos char *fields; 404b588458SPeter Avalos int fieldssize = RECSIZE; 414b588458SPeter Avalos 424b588458SPeter Avalos Cell **fldtab; /* pointers to Cells */ 434b588458SPeter Avalos char inputFS[100] = " "; 444b588458SPeter Avalos 454b588458SPeter Avalos #define MAXFLD 2 464b588458SPeter Avalos int nfields = MAXFLD; /* last allocated slot for $i */ 474b588458SPeter Avalos 484b588458SPeter Avalos int donefld; /* 1 = implies rec broken into fields */ 494b588458SPeter Avalos int donerec; /* 1 = record is valid (no flds have changed) */ 504b588458SPeter Avalos 514b588458SPeter Avalos int lastfld = 0; /* last used field */ 524b588458SPeter Avalos int argno = 1; /* current input argument number */ 534b588458SPeter Avalos extern Awkfloat *ARGC; 544b588458SPeter Avalos 554b588458SPeter Avalos static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE }; 564b588458SPeter Avalos static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE }; 574b588458SPeter Avalos 584b588458SPeter Avalos void recinit(unsigned int n) 594b588458SPeter Avalos { 604b588458SPeter Avalos if ( (record = (char *) malloc(n)) == NULL 614b588458SPeter Avalos || (fields = (char *) malloc(n+1)) == NULL 624b588458SPeter Avalos || (fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *))) == NULL 634b588458SPeter Avalos || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL ) 644b588458SPeter Avalos FATAL("out of space for $0 and fields"); 654b588458SPeter Avalos *fldtab[0] = dollar0; 664b588458SPeter Avalos fldtab[0]->sval = record; 674b588458SPeter Avalos fldtab[0]->nval = tostring("0"); 684b588458SPeter Avalos makefields(1, nfields); 694b588458SPeter Avalos } 704b588458SPeter Avalos 714b588458SPeter Avalos void makefields(int n1, int n2) /* create $n1..$n2 inclusive */ 724b588458SPeter Avalos { 734b588458SPeter Avalos char temp[50]; 744b588458SPeter Avalos int i; 754b588458SPeter Avalos 764b588458SPeter Avalos for (i = n1; i <= n2; i++) { 774b588458SPeter Avalos fldtab[i] = (Cell *) malloc(sizeof (struct Cell)); 784b588458SPeter Avalos if (fldtab[i] == NULL) 794b588458SPeter Avalos FATAL("out of space in makefields %d", i); 804b588458SPeter Avalos *fldtab[i] = dollar1; 814b588458SPeter Avalos sprintf(temp, "%d", i); 824b588458SPeter Avalos fldtab[i]->nval = tostring(temp); 834b588458SPeter Avalos } 844b588458SPeter Avalos } 854b588458SPeter Avalos 864b588458SPeter Avalos void initgetrec(void) 874b588458SPeter Avalos { 884b588458SPeter Avalos int i; 894b588458SPeter Avalos char *p; 904b588458SPeter Avalos 914b588458SPeter Avalos for (i = 1; i < *ARGC; i++) { 92*b12bae18SSascha Wildner p = getargv(i); /* find 1st real filename */ 93*b12bae18SSascha Wildner if (p == NULL || *p == '\0') { /* deleted or zapped */ 94*b12bae18SSascha Wildner argno++; 95*b12bae18SSascha Wildner continue; 96*b12bae18SSascha Wildner } 97*b12bae18SSascha Wildner if (!isclvar(p)) { 98*b12bae18SSascha Wildner setsval(lookup("FILENAME", symtab), p); 994b588458SPeter Avalos return; 1004b588458SPeter Avalos } 1014b588458SPeter Avalos setclvar(p); /* a commandline assignment before filename */ 1024b588458SPeter Avalos argno++; 1034b588458SPeter Avalos } 1044b588458SPeter Avalos infile = stdin; /* no filenames, so use stdin */ 1054b588458SPeter Avalos } 1064b588458SPeter Avalos 1074b588458SPeter Avalos static int firsttime = 1; 1084b588458SPeter Avalos 1094b588458SPeter Avalos int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */ 1104b588458SPeter Avalos { /* note: cares whether buf == record */ 1114b588458SPeter Avalos int c; 1124b588458SPeter Avalos char *buf = *pbuf; 1134b588458SPeter Avalos uschar saveb0; 1144b588458SPeter Avalos int bufsize = *pbufsize, savebufsize = bufsize; 1154b588458SPeter Avalos 1164b588458SPeter Avalos if (firsttime) { 1174b588458SPeter Avalos firsttime = 0; 1184b588458SPeter Avalos initgetrec(); 1194b588458SPeter Avalos } 1204b588458SPeter Avalos dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n", 1214b588458SPeter Avalos *RS, *FS, *ARGC, *FILENAME) ); 1224b588458SPeter Avalos if (isrecord) { 1234b588458SPeter Avalos donefld = 0; 1244b588458SPeter Avalos donerec = 1; 1254b588458SPeter Avalos } 1264b588458SPeter Avalos saveb0 = buf[0]; 1274b588458SPeter Avalos buf[0] = 0; 1284b588458SPeter Avalos while (argno < *ARGC || infile == stdin) { 1294b588458SPeter Avalos dprintf( ("argno=%d, file=|%s|\n", argno, file) ); 1304b588458SPeter Avalos if (infile == NULL) { /* have to open a new file */ 1314b588458SPeter Avalos file = getargv(argno); 132*b12bae18SSascha Wildner if (file == NULL || *file == '\0') { /* deleted or zapped */ 1334b588458SPeter Avalos argno++; 1344b588458SPeter Avalos continue; 1354b588458SPeter Avalos } 1364b588458SPeter Avalos if (isclvar(file)) { /* a var=value arg */ 1374b588458SPeter Avalos setclvar(file); 1384b588458SPeter Avalos argno++; 1394b588458SPeter Avalos continue; 1404b588458SPeter Avalos } 1414b588458SPeter Avalos *FILENAME = file; 1424b588458SPeter Avalos dprintf( ("opening file %s\n", file) ); 1434b588458SPeter Avalos if (*file == '-' && *(file+1) == '\0') 1444b588458SPeter Avalos infile = stdin; 1454b588458SPeter Avalos else if ((infile = fopen(file, "r")) == NULL) 1464b588458SPeter Avalos FATAL("can't open file %s", file); 1474b588458SPeter Avalos setfval(fnrloc, 0.0); 1484b588458SPeter Avalos } 1494b588458SPeter Avalos c = readrec(&buf, &bufsize, infile); 1504b588458SPeter Avalos if (c != 0 || buf[0] != '\0') { /* normal record */ 1514b588458SPeter Avalos if (isrecord) { 1524b588458SPeter Avalos if (freeable(fldtab[0])) 1534b588458SPeter Avalos xfree(fldtab[0]->sval); 1544b588458SPeter Avalos fldtab[0]->sval = buf; /* buf == record */ 1554b588458SPeter Avalos fldtab[0]->tval = REC | STR | DONTFREE; 1564b588458SPeter Avalos if (is_number(fldtab[0]->sval)) { 1574b588458SPeter Avalos fldtab[0]->fval = atof(fldtab[0]->sval); 1584b588458SPeter Avalos fldtab[0]->tval |= NUM; 1594b588458SPeter Avalos } 1604b588458SPeter Avalos } 1614b588458SPeter Avalos setfval(nrloc, nrloc->fval+1); 1624b588458SPeter Avalos setfval(fnrloc, fnrloc->fval+1); 1634b588458SPeter Avalos *pbuf = buf; 1644b588458SPeter Avalos *pbufsize = bufsize; 1654b588458SPeter Avalos return 1; 1664b588458SPeter Avalos } 1674b588458SPeter Avalos /* EOF arrived on this file; set up next */ 1684b588458SPeter Avalos if (infile != stdin) 1694b588458SPeter Avalos fclose(infile); 1704b588458SPeter Avalos infile = NULL; 1714b588458SPeter Avalos argno++; 1724b588458SPeter Avalos } 1734b588458SPeter Avalos buf[0] = saveb0; 1744b588458SPeter Avalos *pbuf = buf; 1754b588458SPeter Avalos *pbufsize = savebufsize; 1764b588458SPeter Avalos return 0; /* true end of file */ 1774b588458SPeter Avalos } 1784b588458SPeter Avalos 1794b588458SPeter Avalos void nextfile(void) 1804b588458SPeter Avalos { 1814b588458SPeter Avalos if (infile != NULL && infile != stdin) 1824b588458SPeter Avalos fclose(infile); 1834b588458SPeter Avalos infile = NULL; 1844b588458SPeter Avalos argno++; 1854b588458SPeter Avalos } 1864b588458SPeter Avalos 1874b588458SPeter Avalos int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */ 1884b588458SPeter Avalos { 1894b588458SPeter Avalos int sep, c; 1904b588458SPeter Avalos char *rr, *buf = *pbuf; 1914b588458SPeter Avalos int bufsize = *pbufsize; 1924b588458SPeter Avalos 1934b588458SPeter Avalos if (strlen(*FS) >= sizeof(inputFS)) 1944b588458SPeter Avalos FATAL("field separator %.10s... is too long", *FS); 195*b12bae18SSascha Wildner /*fflush(stdout); avoids some buffering problem but makes it 25% slower*/ 1964b588458SPeter Avalos strcpy(inputFS, *FS); /* for subsequent field splitting */ 1974b588458SPeter Avalos if ((sep = **RS) == 0) { 1984b588458SPeter Avalos sep = '\n'; 1994b588458SPeter Avalos while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */ 2004b588458SPeter Avalos ; 2014b588458SPeter Avalos if (c != EOF) 2024b588458SPeter Avalos ungetc(c, inf); 2034b588458SPeter Avalos } 2044b588458SPeter Avalos for (rr = buf; ; ) { 2054b588458SPeter Avalos for (; (c=getc(inf)) != sep && c != EOF; ) { 2064b588458SPeter Avalos if (rr-buf+1 > bufsize) 2074b588458SPeter Avalos if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1")) 2084b588458SPeter Avalos FATAL("input record `%.30s...' too long", buf); 2094b588458SPeter Avalos *rr++ = c; 2104b588458SPeter Avalos } 2114b588458SPeter Avalos if (**RS == sep || c == EOF) 2124b588458SPeter Avalos break; 2134b588458SPeter Avalos if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */ 2144b588458SPeter Avalos break; 2154b588458SPeter Avalos if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2")) 2164b588458SPeter Avalos FATAL("input record `%.30s...' too long", buf); 2174b588458SPeter Avalos *rr++ = '\n'; 2184b588458SPeter Avalos *rr++ = c; 2194b588458SPeter Avalos } 2204b588458SPeter Avalos if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3")) 2214b588458SPeter Avalos FATAL("input record `%.30s...' too long", buf); 2224b588458SPeter Avalos *rr = 0; 2234b588458SPeter Avalos dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) ); 2244b588458SPeter Avalos *pbuf = buf; 2254b588458SPeter Avalos *pbufsize = bufsize; 2264b588458SPeter Avalos return c == EOF && rr == buf ? 0 : 1; 2274b588458SPeter Avalos } 2284b588458SPeter Avalos 2294b588458SPeter Avalos char *getargv(int n) /* get ARGV[n] */ 2304b588458SPeter Avalos { 2314b588458SPeter Avalos Cell *x; 2324b588458SPeter Avalos char *s, temp[50]; 2334b588458SPeter Avalos extern Array *ARGVtab; 2344b588458SPeter Avalos 2354b588458SPeter Avalos sprintf(temp, "%d", n); 236*b12bae18SSascha Wildner if (lookup(temp, ARGVtab) == NULL) 237*b12bae18SSascha Wildner return NULL; 2384b588458SPeter Avalos x = setsymtab(temp, "", 0.0, STR, ARGVtab); 2394b588458SPeter Avalos s = getsval(x); 2404b588458SPeter Avalos dprintf( ("getargv(%d) returns |%s|\n", n, s) ); 2414b588458SPeter Avalos return s; 2424b588458SPeter Avalos } 2434b588458SPeter Avalos 2444b588458SPeter Avalos void setclvar(char *s) /* set var=value from s */ 2454b588458SPeter Avalos { 2464b588458SPeter Avalos char *p; 2474b588458SPeter Avalos Cell *q; 2484b588458SPeter Avalos 2494b588458SPeter Avalos for (p=s; *p != '='; p++) 2504b588458SPeter Avalos ; 2514b588458SPeter Avalos *p++ = 0; 2524b588458SPeter Avalos p = qstring(p, '\0'); 2534b588458SPeter Avalos q = setsymtab(s, p, 0.0, STR, symtab); 2544b588458SPeter Avalos setsval(q, p); 2554b588458SPeter Avalos if (is_number(q->sval)) { 2564b588458SPeter Avalos q->fval = atof(q->sval); 2574b588458SPeter Avalos q->tval |= NUM; 2584b588458SPeter Avalos } 2594b588458SPeter Avalos dprintf( ("command line set %s to |%s|\n", s, p) ); 2604b588458SPeter Avalos } 2614b588458SPeter Avalos 2624b588458SPeter Avalos 2634b588458SPeter Avalos void fldbld(void) /* create fields from current record */ 2644b588458SPeter Avalos { 2654b588458SPeter Avalos /* this relies on having fields[] the same length as $0 */ 2664b588458SPeter Avalos /* the fields are all stored in this one array with \0's */ 2670020174dSPeter Avalos /* possibly with a final trailing \0 not associated with any field */ 2684b588458SPeter Avalos char *r, *fr, sep; 2694b588458SPeter Avalos Cell *p; 2704b588458SPeter Avalos int i, j, n; 2714b588458SPeter Avalos 2724b588458SPeter Avalos if (donefld) 2734b588458SPeter Avalos return; 2744b588458SPeter Avalos if (!isstr(fldtab[0])) 2754b588458SPeter Avalos getsval(fldtab[0]); 2764b588458SPeter Avalos r = fldtab[0]->sval; 2774b588458SPeter Avalos n = strlen(r); 2784b588458SPeter Avalos if (n > fieldssize) { 2794b588458SPeter Avalos xfree(fields); 2800020174dSPeter Avalos if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */ 2814b588458SPeter Avalos FATAL("out of space for fields in fldbld %d", n); 2824b588458SPeter Avalos fieldssize = n; 2834b588458SPeter Avalos } 2844b588458SPeter Avalos fr = fields; 2854b588458SPeter Avalos i = 0; /* number of fields accumulated here */ 2864b588458SPeter Avalos strcpy(inputFS, *FS); 2874b588458SPeter Avalos if (strlen(inputFS) > 1) { /* it's a regular expression */ 2884b588458SPeter Avalos i = refldbld(r, inputFS); 2894b588458SPeter Avalos } else if ((sep = *inputFS) == ' ') { /* default whitespace */ 2904b588458SPeter Avalos for (i = 0; ; ) { 2914b588458SPeter Avalos while (*r == ' ' || *r == '\t' || *r == '\n') 2924b588458SPeter Avalos r++; 2934b588458SPeter Avalos if (*r == 0) 2944b588458SPeter Avalos break; 2954b588458SPeter Avalos i++; 2964b588458SPeter Avalos if (i > nfields) 2974b588458SPeter Avalos growfldtab(i); 2984b588458SPeter Avalos if (freeable(fldtab[i])) 2994b588458SPeter Avalos xfree(fldtab[i]->sval); 3004b588458SPeter Avalos fldtab[i]->sval = fr; 3014b588458SPeter Avalos fldtab[i]->tval = FLD | STR | DONTFREE; 3024b588458SPeter Avalos do 3034b588458SPeter Avalos *fr++ = *r++; 3044b588458SPeter Avalos while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0'); 3054b588458SPeter Avalos *fr++ = 0; 3064b588458SPeter Avalos } 3074b588458SPeter Avalos *fr = 0; 3084b588458SPeter Avalos } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */ 3094b588458SPeter Avalos for (i = 0; *r != 0; r++) { 3104b588458SPeter Avalos char buf[2]; 3114b588458SPeter Avalos i++; 3124b588458SPeter Avalos if (i > nfields) 3134b588458SPeter Avalos growfldtab(i); 3144b588458SPeter Avalos if (freeable(fldtab[i])) 3154b588458SPeter Avalos xfree(fldtab[i]->sval); 3164b588458SPeter Avalos buf[0] = *r; 3174b588458SPeter Avalos buf[1] = 0; 3184b588458SPeter Avalos fldtab[i]->sval = tostring(buf); 3194b588458SPeter Avalos fldtab[i]->tval = FLD | STR; 3204b588458SPeter Avalos } 3214b588458SPeter Avalos *fr = 0; 3224b588458SPeter Avalos } else if (*r != 0) { /* if 0, it's a null field */ 3234b588458SPeter Avalos /* subtlecase : if length(FS) == 1 && length(RS > 0) 3244b588458SPeter Avalos * \n is NOT a field separator (cf awk book 61,84). 3254b588458SPeter Avalos * this variable is tested in the inner while loop. 3264b588458SPeter Avalos */ 3274b588458SPeter Avalos int rtest = '\n'; /* normal case */ 3284b588458SPeter Avalos if (strlen(*RS) > 0) 3294b588458SPeter Avalos rtest = '\0'; 3304b588458SPeter Avalos for (;;) { 3314b588458SPeter Avalos i++; 3324b588458SPeter Avalos if (i > nfields) 3334b588458SPeter Avalos growfldtab(i); 3344b588458SPeter Avalos if (freeable(fldtab[i])) 3354b588458SPeter Avalos xfree(fldtab[i]->sval); 3364b588458SPeter Avalos fldtab[i]->sval = fr; 3374b588458SPeter Avalos fldtab[i]->tval = FLD | STR | DONTFREE; 3384b588458SPeter Avalos while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */ 3394b588458SPeter Avalos *fr++ = *r++; 3404b588458SPeter Avalos *fr++ = 0; 3414b588458SPeter Avalos if (*r++ == 0) 3424b588458SPeter Avalos break; 3434b588458SPeter Avalos } 3444b588458SPeter Avalos *fr = 0; 3454b588458SPeter Avalos } 3464b588458SPeter Avalos if (i > nfields) 3474b588458SPeter Avalos FATAL("record `%.30s...' has too many fields; can't happen", r); 3484b588458SPeter Avalos cleanfld(i+1, lastfld); /* clean out junk from previous record */ 3494b588458SPeter Avalos lastfld = i; 3504b588458SPeter Avalos donefld = 1; 3514b588458SPeter Avalos for (j = 1; j <= lastfld; j++) { 3524b588458SPeter Avalos p = fldtab[j]; 3534b588458SPeter Avalos if(is_number(p->sval)) { 3544b588458SPeter Avalos p->fval = atof(p->sval); 3554b588458SPeter Avalos p->tval |= NUM; 3564b588458SPeter Avalos } 3574b588458SPeter Avalos } 3584b588458SPeter Avalos setfval(nfloc, (Awkfloat) lastfld); 3594b588458SPeter Avalos if (dbg) { 3604b588458SPeter Avalos for (j = 0; j <= lastfld; j++) { 3614b588458SPeter Avalos p = fldtab[j]; 3624b588458SPeter Avalos printf("field %d (%s): |%s|\n", j, p->nval, p->sval); 3634b588458SPeter Avalos } 3644b588458SPeter Avalos } 3654b588458SPeter Avalos } 3664b588458SPeter Avalos 3674b588458SPeter Avalos void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */ 3684b588458SPeter Avalos { /* nvals remain intact */ 3694b588458SPeter Avalos Cell *p; 3704b588458SPeter Avalos int i; 3714b588458SPeter Avalos 3724b588458SPeter Avalos for (i = n1; i <= n2; i++) { 3734b588458SPeter Avalos p = fldtab[i]; 3744b588458SPeter Avalos if (freeable(p)) 3754b588458SPeter Avalos xfree(p->sval); 3764b588458SPeter Avalos p->sval = ""; 3774b588458SPeter Avalos p->tval = FLD | STR | DONTFREE; 3784b588458SPeter Avalos } 3794b588458SPeter Avalos } 3804b588458SPeter Avalos 3814b588458SPeter Avalos void newfld(int n) /* add field n after end of existing lastfld */ 3824b588458SPeter Avalos { 3834b588458SPeter Avalos if (n > nfields) 3844b588458SPeter Avalos growfldtab(n); 3854b588458SPeter Avalos cleanfld(lastfld+1, n); 3864b588458SPeter Avalos lastfld = n; 3874b588458SPeter Avalos setfval(nfloc, (Awkfloat) n); 3884b588458SPeter Avalos } 3894b588458SPeter Avalos 3904b588458SPeter Avalos Cell *fieldadr(int n) /* get nth field */ 3914b588458SPeter Avalos { 3924b588458SPeter Avalos if (n < 0) 3934b588458SPeter Avalos FATAL("trying to access out of range field %d", n); 3944b588458SPeter Avalos if (n > nfields) /* fields after NF are empty */ 3954b588458SPeter Avalos growfldtab(n); /* but does not increase NF */ 3964b588458SPeter Avalos return(fldtab[n]); 3974b588458SPeter Avalos } 3984b588458SPeter Avalos 3994b588458SPeter Avalos void growfldtab(int n) /* make new fields up to at least $n */ 4004b588458SPeter Avalos { 4014b588458SPeter Avalos int nf = 2 * nfields; 4024b588458SPeter Avalos size_t s; 4034b588458SPeter Avalos 4044b588458SPeter Avalos if (n > nf) 4054b588458SPeter Avalos nf = n; 4064b588458SPeter Avalos s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */ 4074b588458SPeter Avalos if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */ 4084b588458SPeter Avalos fldtab = (Cell **) realloc(fldtab, s); 4094b588458SPeter Avalos else /* overflow sizeof int */ 4104b588458SPeter Avalos xfree(fldtab); /* make it null */ 4114b588458SPeter Avalos if (fldtab == NULL) 4124b588458SPeter Avalos FATAL("out of space creating %d fields", nf); 4134b588458SPeter Avalos makefields(nfields+1, nf); 4144b588458SPeter Avalos nfields = nf; 4154b588458SPeter Avalos } 4164b588458SPeter Avalos 4174b588458SPeter Avalos int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */ 4184b588458SPeter Avalos { 4194b588458SPeter Avalos /* this relies on having fields[] the same length as $0 */ 4204b588458SPeter Avalos /* the fields are all stored in this one array with \0's */ 4214b588458SPeter Avalos char *fr; 4224b588458SPeter Avalos int i, tempstat, n; 4234b588458SPeter Avalos fa *pfa; 4244b588458SPeter Avalos 4254b588458SPeter Avalos n = strlen(rec); 4264b588458SPeter Avalos if (n > fieldssize) { 4274b588458SPeter Avalos xfree(fields); 4284b588458SPeter Avalos if ((fields = (char *) malloc(n+1)) == NULL) 4294b588458SPeter Avalos FATAL("out of space for fields in refldbld %d", n); 4304b588458SPeter Avalos fieldssize = n; 4314b588458SPeter Avalos } 4324b588458SPeter Avalos fr = fields; 4334b588458SPeter Avalos *fr = '\0'; 4344b588458SPeter Avalos if (*rec == '\0') 4354b588458SPeter Avalos return 0; 4364b588458SPeter Avalos pfa = makedfa(fs, 1); 4374b588458SPeter Avalos dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) ); 4384b588458SPeter Avalos tempstat = pfa->initstat; 4394b588458SPeter Avalos for (i = 1; ; i++) { 4404b588458SPeter Avalos if (i > nfields) 4414b588458SPeter Avalos growfldtab(i); 4424b588458SPeter Avalos if (freeable(fldtab[i])) 4434b588458SPeter Avalos xfree(fldtab[i]->sval); 4444b588458SPeter Avalos fldtab[i]->tval = FLD | STR | DONTFREE; 4454b588458SPeter Avalos fldtab[i]->sval = fr; 4464b588458SPeter Avalos dprintf( ("refldbld: i=%d\n", i) ); 4474b588458SPeter Avalos if (nematch(pfa, rec)) { 4484b588458SPeter Avalos pfa->initstat = 2; /* horrible coupling to b.c */ 4494b588458SPeter Avalos dprintf( ("match %s (%d chars)\n", patbeg, patlen) ); 4504b588458SPeter Avalos strncpy(fr, rec, patbeg-rec); 4514b588458SPeter Avalos fr += patbeg - rec + 1; 4524b588458SPeter Avalos *(fr-1) = '\0'; 4534b588458SPeter Avalos rec = patbeg + patlen; 4544b588458SPeter Avalos } else { 4554b588458SPeter Avalos dprintf( ("no match %s\n", rec) ); 4564b588458SPeter Avalos strcpy(fr, rec); 4574b588458SPeter Avalos pfa->initstat = tempstat; 4584b588458SPeter Avalos break; 4594b588458SPeter Avalos } 4604b588458SPeter Avalos } 4614b588458SPeter Avalos return i; 4624b588458SPeter Avalos } 4634b588458SPeter Avalos 4644b588458SPeter Avalos void recbld(void) /* create $0 from $1..$NF if necessary */ 4654b588458SPeter Avalos { 4664b588458SPeter Avalos int i; 4674b588458SPeter Avalos char *r, *p; 4684b588458SPeter Avalos 4694b588458SPeter Avalos if (donerec == 1) 4704b588458SPeter Avalos return; 4714b588458SPeter Avalos r = record; 4724b588458SPeter Avalos for (i = 1; i <= *NF; i++) { 4734b588458SPeter Avalos p = getsval(fldtab[i]); 4744b588458SPeter Avalos if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1")) 4754b588458SPeter Avalos FATAL("created $0 `%.30s...' too long", record); 4764b588458SPeter Avalos while ((*r = *p++) != 0) 4774b588458SPeter Avalos r++; 4784b588458SPeter Avalos if (i < *NF) { 4794b588458SPeter Avalos if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2")) 4804b588458SPeter Avalos FATAL("created $0 `%.30s...' too long", record); 4814b588458SPeter Avalos for (p = *OFS; (*r = *p++) != 0; ) 4824b588458SPeter Avalos r++; 4834b588458SPeter Avalos } 4844b588458SPeter Avalos } 4854b588458SPeter Avalos if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3")) 4864b588458SPeter Avalos FATAL("built giant record `%.30s...'", record); 4874b588458SPeter Avalos *r = '\0'; 488*b12bae18SSascha Wildner dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) ); 4894b588458SPeter Avalos 4904b588458SPeter Avalos if (freeable(fldtab[0])) 4914b588458SPeter Avalos xfree(fldtab[0]->sval); 4924b588458SPeter Avalos fldtab[0]->tval = REC | STR | DONTFREE; 4934b588458SPeter Avalos fldtab[0]->sval = record; 4944b588458SPeter Avalos 495*b12bae18SSascha Wildner dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) ); 4964b588458SPeter Avalos dprintf( ("recbld = |%s|\n", record) ); 4974b588458SPeter Avalos donerec = 1; 4984b588458SPeter Avalos } 4994b588458SPeter Avalos 5004b588458SPeter Avalos int errorflag = 0; 5014b588458SPeter Avalos 5024b588458SPeter Avalos void yyerror(const char *s) 5034b588458SPeter Avalos { 5044b588458SPeter Avalos SYNTAX("%s", s); 5054b588458SPeter Avalos } 5064b588458SPeter Avalos 5074b588458SPeter Avalos void SYNTAX(const char *fmt, ...) 5084b588458SPeter Avalos { 5094b588458SPeter Avalos extern char *cmdname, *curfname; 5104b588458SPeter Avalos static int been_here = 0; 5114b588458SPeter Avalos va_list varg; 5124b588458SPeter Avalos 5134b588458SPeter Avalos if (been_here++ > 2) 5144b588458SPeter Avalos return; 5154b588458SPeter Avalos fprintf(stderr, "%s: ", cmdname); 5164b588458SPeter Avalos va_start(varg, fmt); 5174b588458SPeter Avalos vfprintf(stderr, fmt, varg); 5184b588458SPeter Avalos va_end(varg); 5194b588458SPeter Avalos fprintf(stderr, " at source line %d", lineno); 5204b588458SPeter Avalos if (curfname != NULL) 5214b588458SPeter Avalos fprintf(stderr, " in function %s", curfname); 5224b588458SPeter Avalos if (compile_time == 1 && cursource() != NULL) 5234b588458SPeter Avalos fprintf(stderr, " source file %s", cursource()); 5244b588458SPeter Avalos fprintf(stderr, "\n"); 5254b588458SPeter Avalos errorflag = 2; 5264b588458SPeter Avalos eprint(); 5274b588458SPeter Avalos } 5284b588458SPeter Avalos 5294b588458SPeter Avalos void fpecatch(int n) 5304b588458SPeter Avalos { 5314b588458SPeter Avalos FATAL("floating point exception %d", n); 5324b588458SPeter Avalos } 5334b588458SPeter Avalos 5344b588458SPeter Avalos extern int bracecnt, brackcnt, parencnt; 5354b588458SPeter Avalos 5364b588458SPeter Avalos void bracecheck(void) 5374b588458SPeter Avalos { 5384b588458SPeter Avalos int c; 5394b588458SPeter Avalos static int beenhere = 0; 5404b588458SPeter Avalos 5414b588458SPeter Avalos if (beenhere++) 5424b588458SPeter Avalos return; 5434b588458SPeter Avalos while ((c = input()) != EOF && c != '\0') 5444b588458SPeter Avalos bclass(c); 5454b588458SPeter Avalos bcheck2(bracecnt, '{', '}'); 5464b588458SPeter Avalos bcheck2(brackcnt, '[', ']'); 5474b588458SPeter Avalos bcheck2(parencnt, '(', ')'); 5484b588458SPeter Avalos } 5494b588458SPeter Avalos 5504b588458SPeter Avalos void bcheck2(int n, int c1, int c2) 5514b588458SPeter Avalos { 5524b588458SPeter Avalos if (n == 1) 5534b588458SPeter Avalos fprintf(stderr, "\tmissing %c\n", c2); 5544b588458SPeter Avalos else if (n > 1) 5554b588458SPeter Avalos fprintf(stderr, "\t%d missing %c's\n", n, c2); 5564b588458SPeter Avalos else if (n == -1) 5574b588458SPeter Avalos fprintf(stderr, "\textra %c\n", c2); 5584b588458SPeter Avalos else if (n < -1) 5594b588458SPeter Avalos fprintf(stderr, "\t%d extra %c's\n", -n, c2); 5604b588458SPeter Avalos } 5614b588458SPeter Avalos 5624b588458SPeter Avalos void FATAL(const char *fmt, ...) 5634b588458SPeter Avalos { 5644b588458SPeter Avalos extern char *cmdname; 5654b588458SPeter Avalos va_list varg; 5664b588458SPeter Avalos 5674b588458SPeter Avalos fflush(stdout); 5684b588458SPeter Avalos fprintf(stderr, "%s: ", cmdname); 5694b588458SPeter Avalos va_start(varg, fmt); 5704b588458SPeter Avalos vfprintf(stderr, fmt, varg); 5714b588458SPeter Avalos va_end(varg); 5724b588458SPeter Avalos error(); 5734b588458SPeter Avalos if (dbg > 1) /* core dump if serious debugging on */ 5744b588458SPeter Avalos abort(); 5754b588458SPeter Avalos exit(2); 5764b588458SPeter Avalos } 5774b588458SPeter Avalos 5784b588458SPeter Avalos void WARNING(const char *fmt, ...) 5794b588458SPeter Avalos { 5804b588458SPeter Avalos extern char *cmdname; 5814b588458SPeter Avalos va_list varg; 5824b588458SPeter Avalos 5834b588458SPeter Avalos fflush(stdout); 5844b588458SPeter Avalos fprintf(stderr, "%s: ", cmdname); 5854b588458SPeter Avalos va_start(varg, fmt); 5864b588458SPeter Avalos vfprintf(stderr, fmt, varg); 5874b588458SPeter Avalos va_end(varg); 5884b588458SPeter Avalos error(); 5894b588458SPeter Avalos } 5904b588458SPeter Avalos 5914b588458SPeter Avalos void error() 5924b588458SPeter Avalos { 5934b588458SPeter Avalos extern Node *curnode; 5944b588458SPeter Avalos 5954b588458SPeter Avalos fprintf(stderr, "\n"); 5964b588458SPeter Avalos if (compile_time != 2 && NR && *NR > 0) { 5974b588458SPeter Avalos fprintf(stderr, " input record number %d", (int) (*FNR)); 5984b588458SPeter Avalos if (strcmp(*FILENAME, "-") != 0) 5994b588458SPeter Avalos fprintf(stderr, ", file %s", *FILENAME); 6004b588458SPeter Avalos fprintf(stderr, "\n"); 6014b588458SPeter Avalos } 6024b588458SPeter Avalos if (compile_time != 2 && curnode) 6034b588458SPeter Avalos fprintf(stderr, " source line number %d", curnode->lineno); 6044b588458SPeter Avalos else if (compile_time != 2 && lineno) 6054b588458SPeter Avalos fprintf(stderr, " source line number %d", lineno); 6064b588458SPeter Avalos if (compile_time == 1 && cursource() != NULL) 6074b588458SPeter Avalos fprintf(stderr, " source file %s", cursource()); 6084b588458SPeter Avalos fprintf(stderr, "\n"); 6094b588458SPeter Avalos eprint(); 6104b588458SPeter Avalos } 6114b588458SPeter Avalos 6124b588458SPeter Avalos void eprint(void) /* try to print context around error */ 6134b588458SPeter Avalos { 6144b588458SPeter Avalos char *p, *q; 6154b588458SPeter Avalos int c; 6164b588458SPeter Avalos static int been_here = 0; 6174b588458SPeter Avalos extern char ebuf[], *ep; 6184b588458SPeter Avalos 6194b588458SPeter Avalos if (compile_time == 2 || compile_time == 0 || been_here++ > 0) 6204b588458SPeter Avalos return; 6214b588458SPeter Avalos p = ep - 1; 6224b588458SPeter Avalos if (p > ebuf && *p == '\n') 6234b588458SPeter Avalos p--; 6244b588458SPeter Avalos for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--) 6254b588458SPeter Avalos ; 6264b588458SPeter Avalos while (*p == '\n') 6274b588458SPeter Avalos p++; 6284b588458SPeter Avalos fprintf(stderr, " context is\n\t"); 6294b588458SPeter Avalos for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) 6304b588458SPeter Avalos ; 6314b588458SPeter Avalos for ( ; p < q; p++) 6324b588458SPeter Avalos if (*p) 6334b588458SPeter Avalos putc(*p, stderr); 6344b588458SPeter Avalos fprintf(stderr, " >>> "); 6354b588458SPeter Avalos for ( ; p < ep; p++) 6364b588458SPeter Avalos if (*p) 6374b588458SPeter Avalos putc(*p, stderr); 6384b588458SPeter Avalos fprintf(stderr, " <<< "); 6394b588458SPeter Avalos if (*ep) 6404b588458SPeter Avalos while ((c = input()) != '\n' && c != '\0' && c != EOF) { 6414b588458SPeter Avalos putc(c, stderr); 6424b588458SPeter Avalos bclass(c); 6434b588458SPeter Avalos } 6444b588458SPeter Avalos putc('\n', stderr); 6454b588458SPeter Avalos ep = ebuf; 6464b588458SPeter Avalos } 6474b588458SPeter Avalos 6484b588458SPeter Avalos void bclass(int c) 6494b588458SPeter Avalos { 6504b588458SPeter Avalos switch (c) { 6514b588458SPeter Avalos case '{': bracecnt++; break; 6524b588458SPeter Avalos case '}': bracecnt--; break; 6534b588458SPeter Avalos case '[': brackcnt++; break; 6544b588458SPeter Avalos case ']': brackcnt--; break; 6554b588458SPeter Avalos case '(': parencnt++; break; 6564b588458SPeter Avalos case ')': parencnt--; break; 6574b588458SPeter Avalos } 6584b588458SPeter Avalos } 6594b588458SPeter Avalos 6604b588458SPeter Avalos double errcheck(double x, const char *s) 6614b588458SPeter Avalos { 6624b588458SPeter Avalos 6634b588458SPeter Avalos if (errno == EDOM) { 6644b588458SPeter Avalos errno = 0; 6654b588458SPeter Avalos WARNING("%s argument out of domain", s); 6664b588458SPeter Avalos x = 1; 6674b588458SPeter Avalos } else if (errno == ERANGE) { 6684b588458SPeter Avalos errno = 0; 6694b588458SPeter Avalos WARNING("%s result out of range", s); 6704b588458SPeter Avalos x = 1; 6714b588458SPeter Avalos } 6724b588458SPeter Avalos return x; 6734b588458SPeter Avalos } 6744b588458SPeter Avalos 6754b588458SPeter Avalos int isclvar(const char *s) /* is s of form var=something ? */ 6764b588458SPeter Avalos { 6774b588458SPeter Avalos const char *os = s; 6784b588458SPeter Avalos 6794b588458SPeter Avalos if (!isalpha((uschar) *s) && *s != '_') 6804b588458SPeter Avalos return 0; 6814b588458SPeter Avalos for ( ; *s; s++) 6824b588458SPeter Avalos if (!(isalnum((uschar) *s) || *s == '_')) 6834b588458SPeter Avalos break; 6844b588458SPeter Avalos return *s == '=' && s > os && *(s+1) != '='; 6854b588458SPeter Avalos } 6864b588458SPeter Avalos 6874b588458SPeter Avalos /* strtod is supposed to be a proper test of what's a valid number */ 6884b588458SPeter Avalos /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */ 6894b588458SPeter Avalos /* wrong: violates 4.10.1.4 of ansi C standard */ 6904b588458SPeter Avalos 6914b588458SPeter Avalos #include <math.h> 6924b588458SPeter Avalos int is_number(const char *s) 6934b588458SPeter Avalos { 6944b588458SPeter Avalos double r; 6954b588458SPeter Avalos char *ep; 6964b588458SPeter Avalos errno = 0; 6974b588458SPeter Avalos r = strtod(s, &ep); 6984b588458SPeter Avalos if (ep == s || r == HUGE_VAL || errno == ERANGE) 6994b588458SPeter Avalos return 0; 7004b588458SPeter Avalos while (*ep == ' ' || *ep == '\t' || *ep == '\n') 7014b588458SPeter Avalos ep++; 7024b588458SPeter Avalos if (*ep == '\0') 7034b588458SPeter Avalos return 1; 7044b588458SPeter Avalos else 7054b588458SPeter Avalos return 0; 7064b588458SPeter Avalos } 707