185587Sobrien/**************************************************************** 285587SobrienCopyright (C) Lucent Technologies 1997 385587SobrienAll Rights Reserved 485587Sobrien 585587SobrienPermission to use, copy, modify, and distribute this software and 685587Sobrienits documentation for any purpose and without fee is hereby 785587Sobriengranted, provided that the above copyright notice appear in all 885587Sobriencopies and that both that the copyright notice and this 985587Sobrienpermission notice and warranty disclaimer appear in supporting 1085587Sobriendocumentation, and that the name Lucent Technologies or any of 1185587Sobrienits entities not be used in advertising or publicity pertaining 1285587Sobriento distribution of the software without specific, written prior 1385587Sobrienpermission. 1485587Sobrien 1585587SobrienLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1685587SobrienINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 1785587SobrienIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 1885587SobrienSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1985587SobrienWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 2085587SobrienIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2185587SobrienARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 2285587SobrienTHIS SOFTWARE. 2385587Sobrien****************************************************************/ 2485587Sobrien 2585587Sobrien#define DEBUG 2685587Sobrien#include <stdio.h> 2785587Sobrien#include <string.h> 2885587Sobrien#include <ctype.h> 2985587Sobrien#include <errno.h> 3085587Sobrien#include <stdlib.h> 3185587Sobrien#include <stdarg.h> 3285587Sobrien#include "awk.h" 3385587Sobrien#include "ytab.h" 3485587Sobrien 3585587SobrienFILE *infile = NULL; 3685587Sobrienchar *file = ""; 3785587Sobrienchar *record; 3885587Sobrienint recsize = RECSIZE; 3985587Sobrienchar *fields; 4085587Sobrienint fieldssize = RECSIZE; 4185587Sobrien 4285587SobrienCell **fldtab; /* pointers to Cells */ 43172958Sobrienchar inputFS[100] = " "; 4485587Sobrien 45170331Srafan#define MAXFLD 2 4685587Sobrienint nfields = MAXFLD; /* last allocated slot for $i */ 4785587Sobrien 4885587Sobrienint donefld; /* 1 = implies rec broken into fields */ 4985587Sobrienint donerec; /* 1 = record is valid (no flds have changed) */ 5085587Sobrien 5185587Sobrienint lastfld = 0; /* last used field */ 5285587Sobrienint argno = 1; /* current input argument number */ 5385587Sobrienextern Awkfloat *ARGC; 5485587Sobrien 5585587Sobrienstatic Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE }; 5685587Sobrienstatic Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE }; 5785587Sobrien 5885587Sobrienvoid recinit(unsigned int n) 5985587Sobrien{ 60146299Sru if ( (record = (char *) malloc(n)) == NULL 61172958Sobrien || (fields = (char *) malloc(n+1)) == NULL 62146299Sru || (fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *))) == NULL 63146299Sru || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL ) 6485587Sobrien FATAL("out of space for $0 and fields"); 6585587Sobrien *fldtab[0] = dollar0; 6685587Sobrien fldtab[0]->sval = record; 6785587Sobrien fldtab[0]->nval = tostring("0"); 6885587Sobrien makefields(1, nfields); 6985587Sobrien} 7085587Sobrien 7185587Sobrienvoid makefields(int n1, int n2) /* create $n1..$n2 inclusive */ 7285587Sobrien{ 7385587Sobrien char temp[50]; 7485587Sobrien int i; 7585587Sobrien 7685587Sobrien for (i = n1; i <= n2; i++) { 7785587Sobrien fldtab[i] = (Cell *) malloc(sizeof (struct Cell)); 7885587Sobrien if (fldtab[i] == NULL) 7985587Sobrien FATAL("out of space in makefields %d", i); 8085587Sobrien *fldtab[i] = dollar1; 8185587Sobrien sprintf(temp, "%d", i); 8285587Sobrien fldtab[i]->nval = tostring(temp); 8385587Sobrien } 8485587Sobrien} 8585587Sobrien 8685587Sobrienvoid initgetrec(void) 8785587Sobrien{ 8885587Sobrien int i; 8985587Sobrien char *p; 9085587Sobrien 9185587Sobrien for (i = 1; i < *ARGC; i++) { 92224776Sru p = getargv(i); /* find 1st real filename */ 93224776Sru if (p == NULL || *p == '\0') { /* deleted or zapped */ 94224776Sru argno++; 95224776Sru continue; 96224776Sru } 97224776Sru if (!isclvar(p)) { 98224776Sru setsval(lookup("FILENAME", symtab), p); 9985587Sobrien return; 10085587Sobrien } 10185587Sobrien setclvar(p); /* a commandline assignment before filename */ 10285587Sobrien argno++; 10385587Sobrien } 10485587Sobrien infile = stdin; /* no filenames, so use stdin */ 10585587Sobrien} 10685587Sobrien 107146299Srustatic int firsttime = 1; 108146299Sru 10985587Sobrienint getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */ 11085587Sobrien{ /* note: cares whether buf == record */ 11185587Sobrien int c; 11285587Sobrien char *buf = *pbuf; 113146299Sru uschar saveb0; 114146299Sru int bufsize = *pbufsize, savebufsize = bufsize; 11585587Sobrien 11685587Sobrien if (firsttime) { 11785587Sobrien firsttime = 0; 11885587Sobrien initgetrec(); 11985587Sobrien } 12085587Sobrien dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n", 12185587Sobrien *RS, *FS, *ARGC, *FILENAME) ); 12285587Sobrien if (isrecord) { 12385587Sobrien donefld = 0; 12485587Sobrien donerec = 1; 12585587Sobrien } 126146299Sru saveb0 = buf[0]; 12785587Sobrien buf[0] = 0; 12885587Sobrien while (argno < *ARGC || infile == stdin) { 12985587Sobrien dprintf( ("argno=%d, file=|%s|\n", argno, file) ); 13085587Sobrien if (infile == NULL) { /* have to open a new file */ 13185587Sobrien file = getargv(argno); 132224731Sru if (file == NULL || *file == '\0') { /* deleted or zapped */ 13385587Sobrien argno++; 13485587Sobrien continue; 13585587Sobrien } 13685587Sobrien if (isclvar(file)) { /* a var=value arg */ 13785587Sobrien setclvar(file); 13885587Sobrien argno++; 13985587Sobrien continue; 14085587Sobrien } 14185587Sobrien *FILENAME = file; 14285587Sobrien dprintf( ("opening file %s\n", file) ); 14385587Sobrien if (*file == '-' && *(file+1) == '\0') 14485587Sobrien infile = stdin; 14585587Sobrien else if ((infile = fopen(file, "r")) == NULL) 14685587Sobrien FATAL("can't open file %s", file); 14785587Sobrien setfval(fnrloc, 0.0); 14885587Sobrien } 14985587Sobrien c = readrec(&buf, &bufsize, infile); 15085587Sobrien if (c != 0 || buf[0] != '\0') { /* normal record */ 15185587Sobrien if (isrecord) { 15285587Sobrien if (freeable(fldtab[0])) 15385587Sobrien xfree(fldtab[0]->sval); 15485587Sobrien fldtab[0]->sval = buf; /* buf == record */ 15585587Sobrien fldtab[0]->tval = REC | STR | DONTFREE; 15685587Sobrien if (is_number(fldtab[0]->sval)) { 15785587Sobrien fldtab[0]->fval = atof(fldtab[0]->sval); 15885587Sobrien fldtab[0]->tval |= NUM; 15985587Sobrien } 16085587Sobrien } 16185587Sobrien setfval(nrloc, nrloc->fval+1); 16285587Sobrien setfval(fnrloc, fnrloc->fval+1); 16385587Sobrien *pbuf = buf; 16485587Sobrien *pbufsize = bufsize; 16585587Sobrien return 1; 16685587Sobrien } 16785587Sobrien /* EOF arrived on this file; set up next */ 16885587Sobrien if (infile != stdin) 16985587Sobrien fclose(infile); 17085587Sobrien infile = NULL; 17185587Sobrien argno++; 17285587Sobrien } 173146299Sru buf[0] = saveb0; 17485587Sobrien *pbuf = buf; 175146299Sru *pbufsize = savebufsize; 17685587Sobrien return 0; /* true end of file */ 17785587Sobrien} 17885587Sobrien 17985587Sobrienvoid nextfile(void) 18085587Sobrien{ 181170331Srafan if (infile != NULL && infile != stdin) 18285587Sobrien fclose(infile); 18385587Sobrien infile = NULL; 18485587Sobrien argno++; 18585587Sobrien} 18685587Sobrien 18785587Sobrienint readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */ 18885587Sobrien{ 18985587Sobrien int sep, c; 19085587Sobrien char *rr, *buf = *pbuf; 19185587Sobrien int bufsize = *pbufsize; 19285587Sobrien 19385587Sobrien if (strlen(*FS) >= sizeof(inputFS)) 19485587Sobrien FATAL("field separator %.10s... is too long", *FS); 195224731Sru /*fflush(stdout); avoids some buffering problem but makes it 25% slower*/ 19685587Sobrien strcpy(inputFS, *FS); /* for subsequent field splitting */ 19785587Sobrien if ((sep = **RS) == 0) { 19885587Sobrien sep = '\n'; 19985587Sobrien while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */ 20085587Sobrien ; 20185587Sobrien if (c != EOF) 20285587Sobrien ungetc(c, inf); 20385587Sobrien } 20485587Sobrien for (rr = buf; ; ) { 20585587Sobrien for (; (c=getc(inf)) != sep && c != EOF; ) { 20685587Sobrien if (rr-buf+1 > bufsize) 20785587Sobrien if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1")) 20885587Sobrien FATAL("input record `%.30s...' too long", buf); 20985587Sobrien *rr++ = c; 21085587Sobrien } 21185587Sobrien if (**RS == sep || c == EOF) 21285587Sobrien break; 21385587Sobrien if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */ 21485587Sobrien break; 21585587Sobrien if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2")) 21685587Sobrien FATAL("input record `%.30s...' too long", buf); 21785587Sobrien *rr++ = '\n'; 21885587Sobrien *rr++ = c; 21985587Sobrien } 22085587Sobrien if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3")) 22185587Sobrien FATAL("input record `%.30s...' too long", buf); 22285587Sobrien *rr = 0; 22385587Sobrien dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) ); 22485587Sobrien *pbuf = buf; 22585587Sobrien *pbufsize = bufsize; 22685587Sobrien return c == EOF && rr == buf ? 0 : 1; 22785587Sobrien} 22885587Sobrien 22985587Sobrienchar *getargv(int n) /* get ARGV[n] */ 23085587Sobrien{ 23185587Sobrien Cell *x; 23285587Sobrien char *s, temp[50]; 23385587Sobrien extern Array *ARGVtab; 23485587Sobrien 23585587Sobrien sprintf(temp, "%d", n); 236224731Sru if (lookup(temp, ARGVtab) == NULL) 237224731Sru return NULL; 23885587Sobrien x = setsymtab(temp, "", 0.0, STR, ARGVtab); 23985587Sobrien s = getsval(x); 24085587Sobrien dprintf( ("getargv(%d) returns |%s|\n", n, s) ); 24185587Sobrien return s; 24285587Sobrien} 24385587Sobrien 24485587Sobrienvoid setclvar(char *s) /* set var=value from s */ 24585587Sobrien{ 24685587Sobrien char *p; 24785587Sobrien Cell *q; 24885587Sobrien 24985587Sobrien for (p=s; *p != '='; p++) 25085587Sobrien ; 25185587Sobrien *p++ = 0; 25285587Sobrien p = qstring(p, '\0'); 25385587Sobrien q = setsymtab(s, p, 0.0, STR, symtab); 25485587Sobrien setsval(q, p); 25585587Sobrien if (is_number(q->sval)) { 25685587Sobrien q->fval = atof(q->sval); 25785587Sobrien q->tval |= NUM; 25885587Sobrien } 25985587Sobrien dprintf( ("command line set %s to |%s|\n", s, p) ); 26085587Sobrien} 26185587Sobrien 26285587Sobrien 26385587Sobrienvoid fldbld(void) /* create fields from current record */ 26485587Sobrien{ 26585587Sobrien /* this relies on having fields[] the same length as $0 */ 26685587Sobrien /* the fields are all stored in this one array with \0's */ 267221381Sru /* possibly with a final trailing \0 not associated with any field */ 26885587Sobrien char *r, *fr, sep; 26985587Sobrien Cell *p; 27085587Sobrien int i, j, n; 27185587Sobrien 27285587Sobrien if (donefld) 27385587Sobrien return; 27485587Sobrien if (!isstr(fldtab[0])) 27585587Sobrien getsval(fldtab[0]); 27685587Sobrien r = fldtab[0]->sval; 27785587Sobrien n = strlen(r); 27885587Sobrien if (n > fieldssize) { 27985587Sobrien xfree(fields); 280221381Sru if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */ 28185587Sobrien FATAL("out of space for fields in fldbld %d", n); 28285587Sobrien fieldssize = n; 28385587Sobrien } 28485587Sobrien fr = fields; 28585587Sobrien i = 0; /* number of fields accumulated here */ 286201951Sru strcpy(inputFS, *FS); 28785587Sobrien if (strlen(inputFS) > 1) { /* it's a regular expression */ 28885587Sobrien i = refldbld(r, inputFS); 28985587Sobrien } else if ((sep = *inputFS) == ' ') { /* default whitespace */ 29085587Sobrien for (i = 0; ; ) { 29185587Sobrien while (*r == ' ' || *r == '\t' || *r == '\n') 29285587Sobrien r++; 29385587Sobrien if (*r == 0) 29485587Sobrien break; 29585587Sobrien i++; 29685587Sobrien if (i > nfields) 29785587Sobrien growfldtab(i); 29885587Sobrien if (freeable(fldtab[i])) 29985587Sobrien xfree(fldtab[i]->sval); 30085587Sobrien fldtab[i]->sval = fr; 30185587Sobrien fldtab[i]->tval = FLD | STR | DONTFREE; 30285587Sobrien do 30385587Sobrien *fr++ = *r++; 30485587Sobrien while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0'); 30585587Sobrien *fr++ = 0; 30685587Sobrien } 30785587Sobrien *fr = 0; 30885587Sobrien } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */ 30985587Sobrien for (i = 0; *r != 0; r++) { 31085587Sobrien char buf[2]; 31185587Sobrien i++; 31285587Sobrien if (i > nfields) 31385587Sobrien growfldtab(i); 31485587Sobrien if (freeable(fldtab[i])) 31585587Sobrien xfree(fldtab[i]->sval); 31685587Sobrien buf[0] = *r; 31785587Sobrien buf[1] = 0; 31885587Sobrien fldtab[i]->sval = tostring(buf); 31985587Sobrien fldtab[i]->tval = FLD | STR; 32085587Sobrien } 32185587Sobrien *fr = 0; 32285587Sobrien } else if (*r != 0) { /* if 0, it's a null field */ 323112336Sobrien /* subtlecase : if length(FS) == 1 && length(RS > 0) 324112336Sobrien * \n is NOT a field separator (cf awk book 61,84). 325112336Sobrien * this variable is tested in the inner while loop. 326112336Sobrien */ 327112336Sobrien int rtest = '\n'; /* normal case */ 328112336Sobrien if (strlen(*RS) > 0) 329112336Sobrien rtest = '\0'; 33085587Sobrien for (;;) { 33185587Sobrien i++; 33285587Sobrien if (i > nfields) 33385587Sobrien growfldtab(i); 33485587Sobrien if (freeable(fldtab[i])) 33585587Sobrien xfree(fldtab[i]->sval); 33685587Sobrien fldtab[i]->sval = fr; 33785587Sobrien fldtab[i]->tval = FLD | STR | DONTFREE; 338112336Sobrien while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */ 33985587Sobrien *fr++ = *r++; 34085587Sobrien *fr++ = 0; 34185587Sobrien if (*r++ == 0) 34285587Sobrien break; 34385587Sobrien } 34485587Sobrien *fr = 0; 34585587Sobrien } 34685587Sobrien if (i > nfields) 34785587Sobrien FATAL("record `%.30s...' has too many fields; can't happen", r); 34885587Sobrien cleanfld(i+1, lastfld); /* clean out junk from previous record */ 34985587Sobrien lastfld = i; 35085587Sobrien donefld = 1; 35185587Sobrien for (j = 1; j <= lastfld; j++) { 35285587Sobrien p = fldtab[j]; 35385587Sobrien if(is_number(p->sval)) { 35485587Sobrien p->fval = atof(p->sval); 35585587Sobrien p->tval |= NUM; 35685587Sobrien } 35785587Sobrien } 35885587Sobrien setfval(nfloc, (Awkfloat) lastfld); 35985587Sobrien if (dbg) { 36085587Sobrien for (j = 0; j <= lastfld; j++) { 36185587Sobrien p = fldtab[j]; 36285587Sobrien printf("field %d (%s): |%s|\n", j, p->nval, p->sval); 36385587Sobrien } 36485587Sobrien } 36585587Sobrien} 36685587Sobrien 36785587Sobrienvoid cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */ 36885587Sobrien{ /* nvals remain intact */ 36985587Sobrien Cell *p; 37085587Sobrien int i; 37185587Sobrien 37285587Sobrien for (i = n1; i <= n2; i++) { 37385587Sobrien p = fldtab[i]; 37485587Sobrien if (freeable(p)) 37585587Sobrien xfree(p->sval); 37685587Sobrien p->sval = ""; 37785587Sobrien p->tval = FLD | STR | DONTFREE; 37885587Sobrien } 37985587Sobrien} 38085587Sobrien 38185587Sobrienvoid newfld(int n) /* add field n after end of existing lastfld */ 38285587Sobrien{ 38385587Sobrien if (n > nfields) 38485587Sobrien growfldtab(n); 38585587Sobrien cleanfld(lastfld+1, n); 38685587Sobrien lastfld = n; 38785587Sobrien setfval(nfloc, (Awkfloat) n); 38885587Sobrien} 38985587Sobrien 39085587SobrienCell *fieldadr(int n) /* get nth field */ 39185587Sobrien{ 39285587Sobrien if (n < 0) 393146299Sru FATAL("trying to access out of range field %d", n); 39485587Sobrien if (n > nfields) /* fields after NF are empty */ 39585587Sobrien growfldtab(n); /* but does not increase NF */ 39685587Sobrien return(fldtab[n]); 39785587Sobrien} 39885587Sobrien 39985587Sobrienvoid growfldtab(int n) /* make new fields up to at least $n */ 40085587Sobrien{ 40185587Sobrien int nf = 2 * nfields; 402146299Sru size_t s; 40385587Sobrien 40485587Sobrien if (n > nf) 40585587Sobrien nf = n; 406146299Sru s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */ 407146299Sru if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */ 408146299Sru fldtab = (Cell **) realloc(fldtab, s); 409146299Sru else /* overflow sizeof int */ 410146299Sru xfree(fldtab); /* make it null */ 41185587Sobrien if (fldtab == NULL) 41285587Sobrien FATAL("out of space creating %d fields", nf); 41385587Sobrien makefields(nfields+1, nf); 41485587Sobrien nfields = nf; 41585587Sobrien} 41685587Sobrien 417107806Sobrienint refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */ 41885587Sobrien{ 41985587Sobrien /* this relies on having fields[] the same length as $0 */ 42085587Sobrien /* the fields are all stored in this one array with \0's */ 42185587Sobrien char *fr; 42285587Sobrien int i, tempstat, n; 42385587Sobrien fa *pfa; 42485587Sobrien 42585587Sobrien n = strlen(rec); 42685587Sobrien if (n > fieldssize) { 42785587Sobrien xfree(fields); 42885587Sobrien if ((fields = (char *) malloc(n+1)) == NULL) 42985587Sobrien FATAL("out of space for fields in refldbld %d", n); 43085587Sobrien fieldssize = n; 43185587Sobrien } 43285587Sobrien fr = fields; 43385587Sobrien *fr = '\0'; 43485587Sobrien if (*rec == '\0') 43585587Sobrien return 0; 43685587Sobrien pfa = makedfa(fs, 1); 43785587Sobrien dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) ); 43885587Sobrien tempstat = pfa->initstat; 43985587Sobrien for (i = 1; ; i++) { 44085587Sobrien if (i > nfields) 44185587Sobrien growfldtab(i); 44285587Sobrien if (freeable(fldtab[i])) 44385587Sobrien xfree(fldtab[i]->sval); 44485587Sobrien fldtab[i]->tval = FLD | STR | DONTFREE; 44585587Sobrien fldtab[i]->sval = fr; 44685587Sobrien dprintf( ("refldbld: i=%d\n", i) ); 44785587Sobrien if (nematch(pfa, rec)) { 44885587Sobrien pfa->initstat = 2; /* horrible coupling to b.c */ 44985587Sobrien dprintf( ("match %s (%d chars)\n", patbeg, patlen) ); 45085587Sobrien strncpy(fr, rec, patbeg-rec); 45185587Sobrien fr += patbeg - rec + 1; 45285587Sobrien *(fr-1) = '\0'; 45385587Sobrien rec = patbeg + patlen; 45485587Sobrien } else { 45585587Sobrien dprintf( ("no match %s\n", rec) ); 45685587Sobrien strcpy(fr, rec); 45785587Sobrien pfa->initstat = tempstat; 45885587Sobrien break; 45985587Sobrien } 46085587Sobrien } 46185587Sobrien return i; 46285587Sobrien} 46385587Sobrien 46485587Sobrienvoid recbld(void) /* create $0 from $1..$NF if necessary */ 46585587Sobrien{ 46685587Sobrien int i; 46785587Sobrien char *r, *p; 46885587Sobrien 46985587Sobrien if (donerec == 1) 47085587Sobrien return; 47185587Sobrien r = record; 47285587Sobrien for (i = 1; i <= *NF; i++) { 47385587Sobrien p = getsval(fldtab[i]); 47485587Sobrien if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1")) 47585587Sobrien FATAL("created $0 `%.30s...' too long", record); 47685587Sobrien while ((*r = *p++) != 0) 47785587Sobrien r++; 47885587Sobrien if (i < *NF) { 47985587Sobrien if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2")) 48085587Sobrien FATAL("created $0 `%.30s...' too long", record); 48185587Sobrien for (p = *OFS; (*r = *p++) != 0; ) 48285587Sobrien r++; 48385587Sobrien } 48485587Sobrien } 48585587Sobrien if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3")) 48685587Sobrien FATAL("built giant record `%.30s...'", record); 48785587Sobrien *r = '\0'; 488224731Sru dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) ); 48985587Sobrien 49085587Sobrien if (freeable(fldtab[0])) 49185587Sobrien xfree(fldtab[0]->sval); 49285587Sobrien fldtab[0]->tval = REC | STR | DONTFREE; 49385587Sobrien fldtab[0]->sval = record; 49485587Sobrien 495224731Sru dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) ); 49685587Sobrien dprintf( ("recbld = |%s|\n", record) ); 49785587Sobrien donerec = 1; 49885587Sobrien} 49985587Sobrien 50085587Sobrienint errorflag = 0; 50185587Sobrien 502107806Sobrienvoid yyerror(const char *s) 50385587Sobrien{ 504146299Sru SYNTAX("%s", s); 50585587Sobrien} 50685587Sobrien 507107806Sobrienvoid SYNTAX(const char *fmt, ...) 50885587Sobrien{ 50985587Sobrien extern char *cmdname, *curfname; 51085587Sobrien static int been_here = 0; 51185587Sobrien va_list varg; 51285587Sobrien 51385587Sobrien if (been_here++ > 2) 51485587Sobrien return; 51585587Sobrien fprintf(stderr, "%s: ", cmdname); 51685587Sobrien va_start(varg, fmt); 51785587Sobrien vfprintf(stderr, fmt, varg); 51885587Sobrien va_end(varg); 51985587Sobrien fprintf(stderr, " at source line %d", lineno); 52085587Sobrien if (curfname != NULL) 52185587Sobrien fprintf(stderr, " in function %s", curfname); 52285587Sobrien if (compile_time == 1 && cursource() != NULL) 52385587Sobrien fprintf(stderr, " source file %s", cursource()); 52485587Sobrien fprintf(stderr, "\n"); 52585587Sobrien errorflag = 2; 52685587Sobrien eprint(); 52785587Sobrien} 52885587Sobrien 52985587Sobrienvoid fpecatch(int n) 53085587Sobrien{ 53185587Sobrien FATAL("floating point exception %d", n); 53285587Sobrien} 53385587Sobrien 53485587Sobrienextern int bracecnt, brackcnt, parencnt; 53585587Sobrien 53685587Sobrienvoid bracecheck(void) 53785587Sobrien{ 53885587Sobrien int c; 53985587Sobrien static int beenhere = 0; 54085587Sobrien 54185587Sobrien if (beenhere++) 54285587Sobrien return; 54385587Sobrien while ((c = input()) != EOF && c != '\0') 54485587Sobrien bclass(c); 54585587Sobrien bcheck2(bracecnt, '{', '}'); 54685587Sobrien bcheck2(brackcnt, '[', ']'); 54785587Sobrien bcheck2(parencnt, '(', ')'); 54885587Sobrien} 54985587Sobrien 55085587Sobrienvoid bcheck2(int n, int c1, int c2) 55185587Sobrien{ 55285587Sobrien if (n == 1) 55385587Sobrien fprintf(stderr, "\tmissing %c\n", c2); 55485587Sobrien else if (n > 1) 55585587Sobrien fprintf(stderr, "\t%d missing %c's\n", n, c2); 55685587Sobrien else if (n == -1) 55785587Sobrien fprintf(stderr, "\textra %c\n", c2); 55885587Sobrien else if (n < -1) 55985587Sobrien fprintf(stderr, "\t%d extra %c's\n", -n, c2); 56085587Sobrien} 56185587Sobrien 562107806Sobrienvoid FATAL(const char *fmt, ...) 56385587Sobrien{ 56485587Sobrien extern char *cmdname; 56585587Sobrien va_list varg; 56685587Sobrien 56785587Sobrien fflush(stdout); 56885587Sobrien fprintf(stderr, "%s: ", cmdname); 56985587Sobrien va_start(varg, fmt); 57085587Sobrien vfprintf(stderr, fmt, varg); 57185587Sobrien va_end(varg); 57285587Sobrien error(); 57385587Sobrien if (dbg > 1) /* core dump if serious debugging on */ 57485587Sobrien abort(); 57585587Sobrien exit(2); 57685587Sobrien} 57785587Sobrien 578107806Sobrienvoid WARNING(const char *fmt, ...) 57985587Sobrien{ 58085587Sobrien extern char *cmdname; 58185587Sobrien va_list varg; 58285587Sobrien 58385587Sobrien fflush(stdout); 58485587Sobrien fprintf(stderr, "%s: ", cmdname); 58585587Sobrien va_start(varg, fmt); 58685587Sobrien vfprintf(stderr, fmt, varg); 58785587Sobrien va_end(varg); 58885587Sobrien error(); 58985587Sobrien} 59085587Sobrien 59185587Sobrienvoid error() 59285587Sobrien{ 59385587Sobrien extern Node *curnode; 59485587Sobrien 59585587Sobrien fprintf(stderr, "\n"); 59685587Sobrien if (compile_time != 2 && NR && *NR > 0) { 59785587Sobrien fprintf(stderr, " input record number %d", (int) (*FNR)); 59885587Sobrien if (strcmp(*FILENAME, "-") != 0) 59985587Sobrien fprintf(stderr, ", file %s", *FILENAME); 60085587Sobrien fprintf(stderr, "\n"); 60185587Sobrien } 60285587Sobrien if (compile_time != 2 && curnode) 60385587Sobrien fprintf(stderr, " source line number %d", curnode->lineno); 60485587Sobrien else if (compile_time != 2 && lineno) 60585587Sobrien fprintf(stderr, " source line number %d", lineno); 60685587Sobrien if (compile_time == 1 && cursource() != NULL) 60785587Sobrien fprintf(stderr, " source file %s", cursource()); 60885587Sobrien fprintf(stderr, "\n"); 60985587Sobrien eprint(); 61085587Sobrien} 61185587Sobrien 61285587Sobrienvoid eprint(void) /* try to print context around error */ 61385587Sobrien{ 61485587Sobrien char *p, *q; 61585587Sobrien int c; 61685587Sobrien static int been_here = 0; 61785587Sobrien extern char ebuf[], *ep; 61885587Sobrien 61985587Sobrien if (compile_time == 2 || compile_time == 0 || been_here++ > 0) 62085587Sobrien return; 62185587Sobrien p = ep - 1; 62285587Sobrien if (p > ebuf && *p == '\n') 62385587Sobrien p--; 62485587Sobrien for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--) 62585587Sobrien ; 62685587Sobrien while (*p == '\n') 62785587Sobrien p++; 62885587Sobrien fprintf(stderr, " context is\n\t"); 62985587Sobrien for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) 63085587Sobrien ; 63185587Sobrien for ( ; p < q; p++) 63285587Sobrien if (*p) 63385587Sobrien putc(*p, stderr); 63485587Sobrien fprintf(stderr, " >>> "); 63585587Sobrien for ( ; p < ep; p++) 63685587Sobrien if (*p) 63785587Sobrien putc(*p, stderr); 63885587Sobrien fprintf(stderr, " <<< "); 63985587Sobrien if (*ep) 64085587Sobrien while ((c = input()) != '\n' && c != '\0' && c != EOF) { 64185587Sobrien putc(c, stderr); 64285587Sobrien bclass(c); 64385587Sobrien } 64485587Sobrien putc('\n', stderr); 64585587Sobrien ep = ebuf; 64685587Sobrien} 64785587Sobrien 64885587Sobrienvoid bclass(int c) 64985587Sobrien{ 65085587Sobrien switch (c) { 65185587Sobrien case '{': bracecnt++; break; 65285587Sobrien case '}': bracecnt--; break; 65385587Sobrien case '[': brackcnt++; break; 65485587Sobrien case ']': brackcnt--; break; 65585587Sobrien case '(': parencnt++; break; 65685587Sobrien case ')': parencnt--; break; 65785587Sobrien } 65885587Sobrien} 65985587Sobrien 660107806Sobriendouble errcheck(double x, const char *s) 66185587Sobrien{ 66285587Sobrien 66385587Sobrien if (errno == EDOM) { 66485587Sobrien errno = 0; 66585587Sobrien WARNING("%s argument out of domain", s); 66685587Sobrien x = 1; 66785587Sobrien } else if (errno == ERANGE) { 66885587Sobrien errno = 0; 66985587Sobrien WARNING("%s result out of range", s); 67085587Sobrien x = 1; 67185587Sobrien } 67285587Sobrien return x; 67385587Sobrien} 67485587Sobrien 675107806Sobrienint isclvar(const char *s) /* is s of form var=something ? */ 67685587Sobrien{ 677107806Sobrien const char *os = s; 67885587Sobrien 67985587Sobrien if (!isalpha((uschar) *s) && *s != '_') 68085587Sobrien return 0; 68185587Sobrien for ( ; *s; s++) 68285587Sobrien if (!(isalnum((uschar) *s) || *s == '_')) 68385587Sobrien break; 68485587Sobrien return *s == '=' && s > os && *(s+1) != '='; 68585587Sobrien} 68685587Sobrien 68785587Sobrien/* strtod is supposed to be a proper test of what's a valid number */ 68885587Sobrien/* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */ 68985587Sobrien/* wrong: violates 4.10.1.4 of ansi C standard */ 69085587Sobrien 69185587Sobrien#include <math.h> 692107806Sobrienint is_number(const char *s) 69385587Sobrien{ 69485587Sobrien double r; 69585587Sobrien char *ep; 69685587Sobrien errno = 0; 69785587Sobrien r = strtod(s, &ep); 69885587Sobrien if (ep == s || r == HUGE_VAL || errno == ERANGE) 69985587Sobrien return 0; 70085587Sobrien while (*ep == ' ' || *ep == '\t' || *ep == '\n') 70185587Sobrien ep++; 70285587Sobrien if (*ep == '\0') 70385587Sobrien return 1; 70485587Sobrien else 70585587Sobrien return 0; 70685587Sobrien} 707