Home | History | Annotate | Line # | Download | only in dist
lib.c revision 1.8
      1  1.1  christos /****************************************************************
      2  1.1  christos Copyright (C) Lucent Technologies 1997
      3  1.1  christos All Rights Reserved
      4  1.1  christos 
      5  1.1  christos Permission to use, copy, modify, and distribute this software and
      6  1.1  christos its documentation for any purpose and without fee is hereby
      7  1.1  christos granted, provided that the above copyright notice appear in all
      8  1.1  christos copies and that both that the copyright notice and this
      9  1.1  christos permission notice and warranty disclaimer appear in supporting
     10  1.1  christos documentation, and that the name Lucent Technologies or any of
     11  1.1  christos its entities not be used in advertising or publicity pertaining
     12  1.1  christos to distribution of the software without specific, written prior
     13  1.1  christos permission.
     14  1.1  christos 
     15  1.1  christos LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     16  1.1  christos INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
     17  1.1  christos IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
     18  1.1  christos SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     19  1.1  christos WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
     20  1.1  christos IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     21  1.1  christos ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
     22  1.1  christos THIS SOFTWARE.
     23  1.1  christos ****************************************************************/
     24  1.1  christos 
     25  1.2  christos #if HAVE_NBTOOL_CONFIG_H
     26  1.2  christos #include "nbtool_config.h"
     27  1.2  christos #endif
     28  1.2  christos 
     29  1.1  christos #define DEBUG
     30  1.1  christos #include <stdio.h>
     31  1.1  christos #include <string.h>
     32  1.1  christos #include <ctype.h>
     33  1.1  christos #include <errno.h>
     34  1.1  christos #include <stdlib.h>
     35  1.1  christos #include <stdarg.h>
     36  1.1  christos #include "awk.h"
     37  1.2  christos #include "awkgram.h"
     38  1.1  christos 
     39  1.2  christos char	EMPTY[] = { '\0' };
     40  1.1  christos FILE	*infile	= NULL;
     41  1.5  christos int	innew;		/* 1 = infile has not been read by readrec */
     42  1.2  christos char	*file	= EMPTY;
     43  1.2  christos uschar	*record;
     44  1.1  christos int	recsize	= RECSIZE;
     45  1.1  christos char	*fields;
     46  1.1  christos int	fieldssize = RECSIZE;
     47  1.1  christos 
     48  1.1  christos Cell	**fldtab;	/* pointers to Cells */
     49  1.2  christos 
     50  1.2  christos static size_t	len_inputFS = 0;
     51  1.2  christos static char	*inputFS = NULL;
     52  1.1  christos 
     53  1.1  christos #define	MAXFLD	2
     54  1.1  christos int	nfields	= MAXFLD;	/* last allocated slot for $i */
     55  1.1  christos 
     56  1.1  christos int	donefld;	/* 1 = implies rec broken into fields */
     57  1.1  christos int	donerec;	/* 1 = record is valid (no flds have changed) */
     58  1.1  christos 
     59  1.1  christos int	lastfld	= 0;	/* last used field */
     60  1.1  christos int	argno	= 1;	/* current input argument number */
     61  1.1  christos extern	Awkfloat *ARGC;
     62  1.1  christos 
     63  1.2  christos static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL };
     64  1.2  christos static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL };
     65  1.1  christos 
     66  1.1  christos void recinit(unsigned int n)
     67  1.1  christos {
     68  1.2  christos 	if ( (record = malloc(n)) == NULL
     69  1.2  christos 	  || (fields = malloc(n+1)) == NULL
     70  1.2  christos 	  || (fldtab = malloc((nfields+1) * sizeof(*fldtab))) == NULL
     71  1.2  christos 	  || (fldtab[0] = malloc(sizeof(**fldtab))) == NULL )
     72  1.1  christos 		FATAL("out of space for $0 and fields");
     73  1.1  christos 	*fldtab[0] = dollar0;
     74  1.1  christos 	fldtab[0]->sval = record;
     75  1.1  christos 	fldtab[0]->nval = tostring("0");
     76  1.1  christos 	makefields(1, nfields);
     77  1.1  christos }
     78  1.1  christos 
     79  1.1  christos void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
     80  1.1  christos {
     81  1.1  christos 	char temp[50];
     82  1.1  christos 	int i;
     83  1.1  christos 
     84  1.1  christos 	for (i = n1; i <= n2; i++) {
     85  1.2  christos 		fldtab[i] = malloc(sizeof(**fldtab));
     86  1.1  christos 		if (fldtab[i] == NULL)
     87  1.1  christos 			FATAL("out of space in makefields %d", i);
     88  1.1  christos 		*fldtab[i] = dollar1;
     89  1.2  christos 		snprintf(temp, sizeof(temp), "%d", i);
     90  1.1  christos 		fldtab[i]->nval = tostring(temp);
     91  1.1  christos 	}
     92  1.1  christos }
     93  1.1  christos 
     94  1.1  christos void initgetrec(void)
     95  1.1  christos {
     96  1.1  christos 	int i;
     97  1.1  christos 	char *p;
     98  1.1  christos 
     99  1.1  christos 	for (i = 1; i < *ARGC; i++) {
    100  1.6  christos 		p = getargv(i); /* find 1st real filename */
    101  1.6  christos 		if (p == NULL || *p == '\0') {  /* deleted or zapped */
    102  1.6  christos 			argno++;
    103  1.6  christos 			continue;
    104  1.6  christos 		}
    105  1.6  christos 		if (!isclvar(p)) {
    106  1.6  christos 			setsval(lookup("FILENAME", symtab), p);
    107  1.1  christos 			return;
    108  1.1  christos 		}
    109  1.1  christos 		setclvar(p);	/* a commandline assignment before filename */
    110  1.1  christos 		argno++;
    111  1.1  christos 	}
    112  1.1  christos 	infile = stdin;		/* no filenames, so use stdin */
    113  1.5  christos 	innew = 1;
    114  1.1  christos }
    115  1.1  christos 
    116  1.1  christos static int firsttime = 1;
    117  1.1  christos 
    118  1.2  christos int getrec(uschar **pbuf, int *pbufsize, int isrecord)	/* get next input record */
    119  1.1  christos {			/* note: cares whether buf == record */
    120  1.1  christos 	int c;
    121  1.2  christos 	uschar *buf = *pbuf;
    122  1.1  christos 	uschar saveb0;
    123  1.1  christos 	int bufsize = *pbufsize, savebufsize = bufsize;
    124  1.1  christos 
    125  1.1  christos 	if (firsttime) {
    126  1.1  christos 		firsttime = 0;
    127  1.1  christos 		initgetrec();
    128  1.1  christos 	}
    129  1.1  christos 	   dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
    130  1.1  christos 		*RS, *FS, *ARGC, *FILENAME) );
    131  1.1  christos 	if (isrecord) {
    132  1.1  christos 		donefld = 0;
    133  1.1  christos 		donerec = 1;
    134  1.1  christos 	}
    135  1.1  christos 	saveb0 = buf[0];
    136  1.1  christos 	buf[0] = 0;
    137  1.1  christos 	while (argno < *ARGC || infile == stdin) {
    138  1.1  christos 		   dprintf( ("argno=%d, file=|%s|\n", argno, file) );
    139  1.1  christos 		if (infile == NULL) {	/* have to open a new file */
    140  1.1  christos 			file = getargv(argno);
    141  1.6  christos 			if (file == NULL || *file == '\0') {	/* deleted or zapped */
    142  1.1  christos 				argno++;
    143  1.1  christos 				continue;
    144  1.1  christos 			}
    145  1.1  christos 			if (isclvar(file)) {	/* a var=value arg */
    146  1.1  christos 				setclvar(file);
    147  1.1  christos 				argno++;
    148  1.1  christos 				continue;
    149  1.1  christos 			}
    150  1.1  christos 			*FILENAME = file;
    151  1.1  christos 			   dprintf( ("opening file %s\n", file) );
    152  1.1  christos 			if (*file == '-' && *(file+1) == '\0')
    153  1.1  christos 				infile = stdin;
    154  1.1  christos 			else if ((infile = fopen(file, "r")) == NULL)
    155  1.1  christos 				FATAL("can't open file %s", file);
    156  1.5  christos 			innew = 1;
    157  1.1  christos 			setfval(fnrloc, 0.0);
    158  1.1  christos 		}
    159  1.5  christos 		c = readrec(&buf, &bufsize, infile, innew);
    160  1.5  christos 		if (innew)
    161  1.5  christos 			innew = 0;
    162  1.1  christos 		if (c != 0 || buf[0] != '\0') {	/* normal record */
    163  1.1  christos 			if (isrecord) {
    164  1.1  christos 				if (freeable(fldtab[0]))
    165  1.1  christos 					xfree(fldtab[0]->sval);
    166  1.1  christos 				fldtab[0]->sval = buf;	/* buf == record */
    167  1.1  christos 				fldtab[0]->tval = REC | STR | DONTFREE;
    168  1.1  christos 				if (is_number(fldtab[0]->sval)) {
    169  1.1  christos 					fldtab[0]->fval = atof(fldtab[0]->sval);
    170  1.1  christos 					fldtab[0]->tval |= NUM;
    171  1.1  christos 				}
    172  1.1  christos 			}
    173  1.1  christos 			setfval(nrloc, nrloc->fval+1);
    174  1.1  christos 			setfval(fnrloc, fnrloc->fval+1);
    175  1.1  christos 			*pbuf = buf;
    176  1.1  christos 			*pbufsize = bufsize;
    177  1.1  christos 			return 1;
    178  1.1  christos 		}
    179  1.1  christos 		/* EOF arrived on this file; set up next */
    180  1.1  christos 		if (infile != stdin)
    181  1.1  christos 			fclose(infile);
    182  1.1  christos 		infile = NULL;
    183  1.1  christos 		argno++;
    184  1.1  christos 	}
    185  1.1  christos 	buf[0] = saveb0;
    186  1.1  christos 	*pbuf = buf;
    187  1.1  christos 	*pbufsize = savebufsize;
    188  1.1  christos 	return 0;	/* true end of file */
    189  1.1  christos }
    190  1.1  christos 
    191  1.1  christos void nextfile(void)
    192  1.1  christos {
    193  1.1  christos 	if (infile != NULL && infile != stdin)
    194  1.1  christos 		fclose(infile);
    195  1.1  christos 	infile = NULL;
    196  1.1  christos 	argno++;
    197  1.1  christos }
    198  1.1  christos 
    199  1.5  christos int readrec(uschar **pbuf, int *pbufsize, FILE *inf, int newflag)	/* read one record into buf */
    200  1.1  christos {
    201  1.5  christos 	int sep, c, isrec, found, tempstat;
    202  1.2  christos 	uschar *rr, *buf = *pbuf;
    203  1.1  christos 	int bufsize = *pbufsize;
    204  1.2  christos 	size_t len;
    205  1.1  christos 
    206  1.2  christos 	if ((len = strlen(*FS)) < len_inputFS) {
    207  1.2  christos 		strcpy(inputFS, *FS);	/* for subsequent field splitting */
    208  1.2  christos 	} else {
    209  1.2  christos 		len_inputFS = len + 1;
    210  1.2  christos 		inputFS = realloc(inputFS, len_inputFS);
    211  1.2  christos 		if (inputFS == NULL)
    212  1.2  christos 			FATAL("field separator %.10s... is too long", *FS);
    213  1.2  christos 		memcpy(inputFS, *FS, len_inputFS);
    214  1.2  christos 	}
    215  1.6  christos 	/*fflush(stdout); avoids some buffering problem but makes it 25% slower*/
    216  1.5  christos 	if (**RS && (*RS)[1]) {
    217  1.2  christos 		fa *pfa = makedfa(*RS, 1);
    218  1.5  christos 		if (newflag)
    219  1.5  christos 			found = fnematch(pfa, inf, &buf, &bufsize, recsize);
    220  1.5  christos 		else {
    221  1.5  christos 			tempstat = pfa->initstat;
    222  1.5  christos 			pfa->initstat = 2;
    223  1.5  christos 			found = fnematch(pfa, inf, &buf, &bufsize, recsize);
    224  1.5  christos 			pfa->initstat = tempstat;
    225  1.2  christos 		}
    226  1.5  christos 		if (found)
    227  1.5  christos 			*patbeg = 0;
    228  1.2  christos 	} else {
    229  1.5  christos 		if ((sep = **RS) == 0) {
    230  1.5  christos 			sep = '\n';
    231  1.5  christos 			while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
    232  1.5  christos 				;
    233  1.5  christos 			if (c != EOF)
    234  1.5  christos 				ungetc(c, inf);
    235  1.5  christos 		}
    236  1.2  christos 		for (rr = buf; ; ) {
    237  1.2  christos 			for (; (c=getc(inf)) != sep && c != EOF; ) {
    238  1.2  christos 				if (rr-buf+1 > bufsize)
    239  1.2  christos 					if (!adjbuf(&buf, &bufsize, 1+rr-buf,
    240  1.2  christos 					    recsize, &rr, "readrec 1"))
    241  1.2  christos 						FATAL("input record `%.30s...'"
    242  1.2  christos 						    " too long", buf);
    243  1.2  christos 				*rr++ = c;
    244  1.2  christos 			}
    245  1.2  christos 			if (**RS == sep || c == EOF)
    246  1.2  christos 				break;
    247  1.2  christos 			if ((c = getc(inf)) == '\n' || c == EOF)
    248  1.2  christos 				/* 2 in a row */
    249  1.2  christos 				break;
    250  1.2  christos 			if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr,
    251  1.2  christos 			    "readrec 2"))
    252  1.2  christos 				FATAL("input record `%.30s...' too long", buf);
    253  1.2  christos 			*rr++ = '\n';
    254  1.1  christos 			*rr++ = c;
    255  1.1  christos 		}
    256  1.5  christos 		if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
    257  1.5  christos 			FATAL("input record `%.30s...' too long", buf);
    258  1.5  christos 		*rr = 0;
    259  1.1  christos 	}
    260  1.1  christos 	*pbuf = buf;
    261  1.1  christos 	*pbufsize = bufsize;
    262  1.5  christos 	isrec = *buf || !feof(inf);
    263  1.5  christos 	   dprintf( ("readrec saw <%s>, returns %d\n", buf, isrec) );
    264  1.5  christos 	return isrec;
    265  1.1  christos }
    266  1.1  christos 
    267  1.1  christos char *getargv(int n)	/* get ARGV[n] */
    268  1.1  christos {
    269  1.1  christos 	Cell *x;
    270  1.1  christos 	char *s, temp[50];
    271  1.1  christos 	extern Array *ARGVtab;
    272  1.1  christos 
    273  1.2  christos 	snprintf(temp, sizeof(temp), "%d", n);
    274  1.6  christos 	if (lookup(temp, ARGVtab) == NULL)
    275  1.6  christos 		return NULL;
    276  1.1  christos 	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
    277  1.1  christos 	s = getsval(x);
    278  1.1  christos 	   dprintf( ("getargv(%d) returns |%s|\n", n, s) );
    279  1.1  christos 	return s;
    280  1.1  christos }
    281  1.1  christos 
    282  1.1  christos void setclvar(char *s)	/* set var=value from s */
    283  1.1  christos {
    284  1.1  christos 	char *p;
    285  1.1  christos 	Cell *q;
    286  1.1  christos 
    287  1.1  christos 	for (p=s; *p != '='; p++)
    288  1.1  christos 		;
    289  1.1  christos 	*p++ = 0;
    290  1.1  christos 	p = qstring(p, '\0');
    291  1.1  christos 	q = setsymtab(s, p, 0.0, STR, symtab);
    292  1.1  christos 	setsval(q, p);
    293  1.1  christos 	if (is_number(q->sval)) {
    294  1.1  christos 		q->fval = atof(q->sval);
    295  1.1  christos 		q->tval |= NUM;
    296  1.1  christos 	}
    297  1.1  christos 	   dprintf( ("command line set %s to |%s|\n", s, p) );
    298  1.1  christos }
    299  1.1  christos 
    300  1.1  christos 
    301  1.1  christos void fldbld(void)	/* create fields from current record */
    302  1.1  christos {
    303  1.1  christos 	/* this relies on having fields[] the same length as $0 */
    304  1.1  christos 	/* the fields are all stored in this one array with \0's */
    305  1.6  christos 	/* possibly with a final trailing \0 not associated with any field */
    306  1.1  christos 	char *r, *fr, sep;
    307  1.1  christos 	Cell *p;
    308  1.1  christos 	int i, j, n;
    309  1.1  christos 
    310  1.1  christos 	if (donefld)
    311  1.1  christos 		return;
    312  1.1  christos 	if (!isstr(fldtab[0]))
    313  1.1  christos 		getsval(fldtab[0]);
    314  1.1  christos 	r = fldtab[0]->sval;
    315  1.1  christos 	n = strlen(r);
    316  1.1  christos 	if (n > fieldssize) {
    317  1.1  christos 		xfree(fields);
    318  1.6  christos 		if ((fields = malloc(n+2)) == NULL) /* possibly 2 final \0s */
    319  1.1  christos 			FATAL("out of space for fields in fldbld %d", n);
    320  1.1  christos 		fieldssize = n;
    321  1.1  christos 	}
    322  1.1  christos 	fr = fields;
    323  1.1  christos 	i = 0;	/* number of fields accumulated here */
    324  1.4  drochner 	if (!inputFS) {
    325  1.4  drochner 		/* do nothing */
    326  1.4  drochner 	} else if (inputFS[0] && inputFS[1]) {	/* it's a regular expression */
    327  1.1  christos 		i = refldbld(r, inputFS);
    328  1.1  christos 	} else if ((sep = *inputFS) == ' ') {	/* default whitespace */
    329  1.1  christos 		for (i = 0; ; ) {
    330  1.1  christos 			while (*r == ' ' || *r == '\t' || *r == '\n')
    331  1.1  christos 				r++;
    332  1.1  christos 			if (*r == 0)
    333  1.1  christos 				break;
    334  1.1  christos 			i++;
    335  1.1  christos 			if (i > nfields)
    336  1.1  christos 				growfldtab(i);
    337  1.1  christos 			if (freeable(fldtab[i]))
    338  1.1  christos 				xfree(fldtab[i]->sval);
    339  1.1  christos 			fldtab[i]->sval = fr;
    340  1.1  christos 			fldtab[i]->tval = FLD | STR | DONTFREE;
    341  1.1  christos 			do
    342  1.1  christos 				*fr++ = *r++;
    343  1.1  christos 			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
    344  1.1  christos 			*fr++ = 0;
    345  1.1  christos 		}
    346  1.1  christos 		*fr = 0;
    347  1.1  christos 	} else if ((sep = *inputFS) == 0) {		/* new: FS="" => 1 char/field */
    348  1.1  christos 		for (i = 0; *r != 0; r++) {
    349  1.1  christos 			char buf[2];
    350  1.1  christos 			i++;
    351  1.1  christos 			if (i > nfields)
    352  1.1  christos 				growfldtab(i);
    353  1.1  christos 			if (freeable(fldtab[i]))
    354  1.1  christos 				xfree(fldtab[i]->sval);
    355  1.1  christos 			buf[0] = *r;
    356  1.1  christos 			buf[1] = 0;
    357  1.1  christos 			fldtab[i]->sval = tostring(buf);
    358  1.1  christos 			fldtab[i]->tval = FLD | STR;
    359  1.1  christos 		}
    360  1.1  christos 		*fr = 0;
    361  1.1  christos 	} else if (*r != 0) {	/* if 0, it's a null field */
    362  1.1  christos 		/* subtlecase : if length(FS) == 1 && length(RS > 0)
    363  1.1  christos 		 * \n is NOT a field separator (cf awk book 61,84).
    364  1.1  christos 		 * this variable is tested in the inner while loop.
    365  1.1  christos 		 */
    366  1.1  christos 		int rtest = '\n';  /* normal case */
    367  1.1  christos 		if (strlen(*RS) > 0)
    368  1.1  christos 			rtest = '\0';
    369  1.1  christos 		for (;;) {
    370  1.1  christos 			i++;
    371  1.1  christos 			if (i > nfields)
    372  1.1  christos 				growfldtab(i);
    373  1.1  christos 			if (freeable(fldtab[i]))
    374  1.1  christos 				xfree(fldtab[i]->sval);
    375  1.1  christos 			fldtab[i]->sval = fr;
    376  1.1  christos 			fldtab[i]->tval = FLD | STR | DONTFREE;
    377  1.1  christos 			while (*r != sep && *r != rtest && *r != '\0')	/* \n is always a separator */
    378  1.1  christos 				*fr++ = *r++;
    379  1.1  christos 			*fr++ = 0;
    380  1.1  christos 			if (*r++ == 0)
    381  1.1  christos 				break;
    382  1.1  christos 		}
    383  1.1  christos 		*fr = 0;
    384  1.1  christos 	}
    385  1.1  christos 	if (i > nfields)
    386  1.1  christos 		FATAL("record `%.30s...' has too many fields; can't happen", r);
    387  1.1  christos 	cleanfld(i+1, lastfld);	/* clean out junk from previous record */
    388  1.1  christos 	lastfld = i;
    389  1.1  christos 	donefld = 1;
    390  1.1  christos 	for (j = 1; j <= lastfld; j++) {
    391  1.1  christos 		p = fldtab[j];
    392  1.1  christos 		if(is_number(p->sval)) {
    393  1.1  christos 			p->fval = atof(p->sval);
    394  1.1  christos 			p->tval |= NUM;
    395  1.1  christos 		}
    396  1.1  christos 	}
    397  1.1  christos 	setfval(nfloc, (Awkfloat) lastfld);
    398  1.3  christos 	donerec = 1; /* restore */
    399  1.1  christos 	if (dbg) {
    400  1.1  christos 		for (j = 0; j <= lastfld; j++) {
    401  1.1  christos 			p = fldtab[j];
    402  1.1  christos 			printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
    403  1.1  christos 		}
    404  1.1  christos 	}
    405  1.1  christos }
    406  1.1  christos 
    407  1.1  christos void cleanfld(int n1, int n2)	/* clean out fields n1 .. n2 inclusive */
    408  1.1  christos {				/* nvals remain intact */
    409  1.1  christos 	Cell *p;
    410  1.1  christos 	int i;
    411  1.1  christos 
    412  1.1  christos 	for (i = n1; i <= n2; i++) {
    413  1.1  christos 		p = fldtab[i];
    414  1.1  christos 		if (freeable(p))
    415  1.1  christos 			xfree(p->sval);
    416  1.2  christos 		p->sval = EMPTY;
    417  1.1  christos 		p->tval = FLD | STR | DONTFREE;
    418  1.1  christos 	}
    419  1.1  christos }
    420  1.1  christos 
    421  1.1  christos void newfld(int n)	/* add field n after end of existing lastfld */
    422  1.1  christos {
    423  1.1  christos 	if (n > nfields)
    424  1.1  christos 		growfldtab(n);
    425  1.1  christos 	cleanfld(lastfld+1, n);
    426  1.1  christos 	lastfld = n;
    427  1.1  christos 	setfval(nfloc, (Awkfloat) n);
    428  1.1  christos }
    429  1.1  christos 
    430  1.3  christos void setlastfld(int n)	/* set lastfld cleaning fldtab cells if necessary */
    431  1.3  christos {
    432  1.3  christos 	if (n > nfields)
    433  1.3  christos 		growfldtab(n);
    434  1.3  christos 
    435  1.3  christos 	if (lastfld < n)
    436  1.3  christos 	    cleanfld(lastfld+1, n);
    437  1.3  christos 	else
    438  1.3  christos 	    cleanfld(n+1, lastfld);
    439  1.3  christos 
    440  1.3  christos 	lastfld = n;
    441  1.3  christos }
    442  1.3  christos 
    443  1.1  christos Cell *fieldadr(int n)	/* get nth field */
    444  1.1  christos {
    445  1.1  christos 	if (n < 0)
    446  1.1  christos 		FATAL("trying to access out of range field %d", n);
    447  1.1  christos 	if (n > nfields)	/* fields after NF are empty */
    448  1.1  christos 		growfldtab(n);	/* but does not increase NF */
    449  1.1  christos 	return(fldtab[n]);
    450  1.1  christos }
    451  1.1  christos 
    452  1.1  christos void growfldtab(int n)	/* make new fields up to at least $n */
    453  1.1  christos {
    454  1.1  christos 	int nf = 2 * nfields;
    455  1.1  christos 	size_t s;
    456  1.1  christos 
    457  1.1  christos 	if (n > nf)
    458  1.1  christos 		nf = n;
    459  1.1  christos 	s = (nf+1) * (sizeof (struct Cell *));  /* freebsd: how much do we need? */
    460  1.2  christos 	if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
    461  1.2  christos 		fldtab = realloc(fldtab, s);
    462  1.1  christos 	else					/* overflow sizeof int */
    463  1.1  christos 		xfree(fldtab);	/* make it null */
    464  1.1  christos 	if (fldtab == NULL)
    465  1.1  christos 		FATAL("out of space creating %d fields", nf);
    466  1.1  christos 	makefields(nfields+1, nf);
    467  1.1  christos 	nfields = nf;
    468  1.1  christos }
    469  1.1  christos 
    470  1.1  christos int refldbld(const char *rec, const char *fs)	/* build fields from reg expr in FS */
    471  1.1  christos {
    472  1.1  christos 	/* this relies on having fields[] the same length as $0 */
    473  1.1  christos 	/* the fields are all stored in this one array with \0's */
    474  1.1  christos 	char *fr;
    475  1.1  christos 	int i, tempstat, n;
    476  1.1  christos 	fa *pfa;
    477  1.1  christos 
    478  1.1  christos 	n = strlen(rec);
    479  1.1  christos 	if (n > fieldssize) {
    480  1.1  christos 		xfree(fields);
    481  1.2  christos 		if ((fields = malloc(n+1)) == NULL)
    482  1.1  christos 			FATAL("out of space for fields in refldbld %d", n);
    483  1.1  christos 		fieldssize = n;
    484  1.1  christos 	}
    485  1.1  christos 	fr = fields;
    486  1.1  christos 	*fr = '\0';
    487  1.1  christos 	if (*rec == '\0')
    488  1.1  christos 		return 0;
    489  1.1  christos 	pfa = makedfa(fs, 1);
    490  1.1  christos 	   dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
    491  1.1  christos 	tempstat = pfa->initstat;
    492  1.1  christos 	for (i = 1; ; i++) {
    493  1.1  christos 		if (i > nfields)
    494  1.1  christos 			growfldtab(i);
    495  1.1  christos 		if (freeable(fldtab[i]))
    496  1.1  christos 			xfree(fldtab[i]->sval);
    497  1.1  christos 		fldtab[i]->tval = FLD | STR | DONTFREE;
    498  1.1  christos 		fldtab[i]->sval = fr;
    499  1.1  christos 		   dprintf( ("refldbld: i=%d\n", i) );
    500  1.1  christos 		if (nematch(pfa, rec)) {
    501  1.1  christos 			pfa->initstat = 2;	/* horrible coupling to b.c */
    502  1.1  christos 			   dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
    503  1.2  christos 			strncpy(fr, rec, ((const char*)patbeg)-rec);
    504  1.2  christos 			fr += ((const char*)patbeg) - rec + 1;
    505  1.1  christos 			*(fr-1) = '\0';
    506  1.1  christos 			rec = patbeg + patlen;
    507  1.1  christos 		} else {
    508  1.1  christos 			   dprintf( ("no match %s\n", rec) );
    509  1.1  christos 			strcpy(fr, rec);
    510  1.1  christos 			pfa->initstat = tempstat;
    511  1.1  christos 			break;
    512  1.1  christos 		}
    513  1.1  christos 	}
    514  1.1  christos 	return i;
    515  1.1  christos }
    516  1.1  christos 
    517  1.1  christos void recbld(void)	/* create $0 from $1..$NF if necessary */
    518  1.1  christos {
    519  1.1  christos 	int i;
    520  1.2  christos 	uschar *r;
    521  1.2  christos 	char *p;
    522  1.1  christos 
    523  1.1  christos 	if (donerec == 1)
    524  1.1  christos 		return;
    525  1.1  christos 	r = record;
    526  1.1  christos 	for (i = 1; i <= *NF; i++) {
    527  1.1  christos 		p = getsval(fldtab[i]);
    528  1.1  christos 		if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
    529  1.1  christos 			FATAL("created $0 `%.30s...' too long", record);
    530  1.1  christos 		while ((*r = *p++) != 0)
    531  1.1  christos 			r++;
    532  1.1  christos 		if (i < *NF) {
    533  1.1  christos 			if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
    534  1.1  christos 				FATAL("created $0 `%.30s...' too long", record);
    535  1.1  christos 			for (p = *OFS; (*r = *p++) != 0; )
    536  1.1  christos 				r++;
    537  1.1  christos 		}
    538  1.1  christos 	}
    539  1.1  christos 	if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
    540  1.1  christos 		FATAL("built giant record `%.30s...'", record);
    541  1.1  christos 	*r = '\0';
    542  1.1  christos 	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
    543  1.1  christos 
    544  1.1  christos 	if (freeable(fldtab[0]))
    545  1.1  christos 		xfree(fldtab[0]->sval);
    546  1.1  christos 	fldtab[0]->tval = REC | STR | DONTFREE;
    547  1.1  christos 	fldtab[0]->sval = record;
    548  1.1  christos 
    549  1.7  christos 	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
    550  1.1  christos 	   dprintf( ("recbld = |%s|\n", record) );
    551  1.1  christos 	donerec = 1;
    552  1.1  christos }
    553  1.1  christos 
    554  1.1  christos int	errorflag	= 0;
    555  1.1  christos 
    556  1.1  christos void yyerror(const char *s)
    557  1.1  christos {
    558  1.1  christos 	SYNTAX("%s", s);
    559  1.1  christos }
    560  1.1  christos 
    561  1.1  christos void SYNTAX(const char *fmt, ...)
    562  1.1  christos {
    563  1.1  christos 	extern char *cmdname, *curfname;
    564  1.1  christos 	static int been_here = 0;
    565  1.1  christos 	va_list varg;
    566  1.1  christos 
    567  1.1  christos 	if (been_here++ > 2)
    568  1.1  christos 		return;
    569  1.1  christos 	fprintf(stderr, "%s: ", cmdname);
    570  1.1  christos 	va_start(varg, fmt);
    571  1.1  christos 	vfprintf(stderr, fmt, varg);
    572  1.1  christos 	va_end(varg);
    573  1.1  christos 	fprintf(stderr, " at source line %d", lineno);
    574  1.1  christos 	if (curfname != NULL)
    575  1.1  christos 		fprintf(stderr, " in function %s", curfname);
    576  1.1  christos 	if (compile_time == 1 && cursource() != NULL)
    577  1.1  christos 		fprintf(stderr, " source file %s", cursource());
    578  1.1  christos 	fprintf(stderr, "\n");
    579  1.1  christos 	errorflag = 2;
    580  1.1  christos 	eprint();
    581  1.1  christos }
    582  1.1  christos 
    583  1.1  christos extern int bracecnt, brackcnt, parencnt;
    584  1.1  christos 
    585  1.1  christos void bracecheck(void)
    586  1.1  christos {
    587  1.1  christos 	int c;
    588  1.1  christos 	static int beenhere = 0;
    589  1.1  christos 
    590  1.1  christos 	if (beenhere++)
    591  1.1  christos 		return;
    592  1.1  christos 	while ((c = input()) != EOF && c != '\0')
    593  1.1  christos 		bclass(c);
    594  1.1  christos 	bcheck2(bracecnt, '{', '}');
    595  1.1  christos 	bcheck2(brackcnt, '[', ']');
    596  1.1  christos 	bcheck2(parencnt, '(', ')');
    597  1.1  christos }
    598  1.1  christos 
    599  1.1  christos void bcheck2(int n, int c1, int c2)
    600  1.1  christos {
    601  1.1  christos 	if (n == 1)
    602  1.1  christos 		fprintf(stderr, "\tmissing %c\n", c2);
    603  1.1  christos 	else if (n > 1)
    604  1.1  christos 		fprintf(stderr, "\t%d missing %c's\n", n, c2);
    605  1.1  christos 	else if (n == -1)
    606  1.1  christos 		fprintf(stderr, "\textra %c\n", c2);
    607  1.1  christos 	else if (n < -1)
    608  1.1  christos 		fprintf(stderr, "\t%d extra %c's\n", -n, c2);
    609  1.1  christos }
    610  1.1  christos 
    611  1.1  christos void FATAL(const char *fmt, ...)
    612  1.1  christos {
    613  1.1  christos 	extern char *cmdname;
    614  1.1  christos 	va_list varg;
    615  1.1  christos 
    616  1.1  christos 	fflush(stdout);
    617  1.1  christos 	fprintf(stderr, "%s: ", cmdname);
    618  1.1  christos 	va_start(varg, fmt);
    619  1.1  christos 	vfprintf(stderr, fmt, varg);
    620  1.1  christos 	va_end(varg);
    621  1.1  christos 	error();
    622  1.1  christos 	if (dbg > 1)		/* core dump if serious debugging on */
    623  1.1  christos 		abort();
    624  1.1  christos 	exit(2);
    625  1.1  christos }
    626  1.1  christos 
    627  1.1  christos void WARNING(const char *fmt, ...)
    628  1.1  christos {
    629  1.1  christos 	extern char *cmdname;
    630  1.1  christos 	va_list varg;
    631  1.1  christos 
    632  1.1  christos 	fflush(stdout);
    633  1.1  christos 	fprintf(stderr, "%s: ", cmdname);
    634  1.1  christos 	va_start(varg, fmt);
    635  1.1  christos 	vfprintf(stderr, fmt, varg);
    636  1.1  christos 	va_end(varg);
    637  1.1  christos 	error();
    638  1.1  christos }
    639  1.1  christos 
    640  1.1  christos void error()
    641  1.1  christos {
    642  1.1  christos 	extern Node *curnode;
    643  1.1  christos 
    644  1.1  christos 	fprintf(stderr, "\n");
    645  1.1  christos 	if (compile_time != 2 && NR && *NR > 0) {
    646  1.1  christos 		fprintf(stderr, " input record number %d", (int) (*FNR));
    647  1.1  christos 		if (strcmp(*FILENAME, "-") != 0)
    648  1.1  christos 			fprintf(stderr, ", file %s", *FILENAME);
    649  1.1  christos 		fprintf(stderr, "\n");
    650  1.1  christos 	}
    651  1.1  christos 	if (compile_time != 2 && curnode)
    652  1.1  christos 		fprintf(stderr, " source line number %d", curnode->lineno);
    653  1.1  christos 	else if (compile_time != 2 && lineno)
    654  1.1  christos 		fprintf(stderr, " source line number %d", lineno);
    655  1.1  christos 	if (compile_time == 1 && cursource() != NULL)
    656  1.1  christos 		fprintf(stderr, " source file %s", cursource());
    657  1.1  christos 	fprintf(stderr, "\n");
    658  1.1  christos 	eprint();
    659  1.1  christos }
    660  1.1  christos 
    661  1.1  christos void eprint(void)	/* try to print context around error */
    662  1.1  christos {
    663  1.1  christos 	char *p, *q;
    664  1.1  christos 	static int been_here = 0;
    665  1.1  christos 	extern char ebuf[], *ep;
    666  1.1  christos 
    667  1.1  christos 	if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
    668  1.1  christos 		return;
    669  1.1  christos 	p = ep - 1;
    670  1.1  christos 	if (p > ebuf && *p == '\n')
    671  1.1  christos 		p--;
    672  1.1  christos 	for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
    673  1.1  christos 		;
    674  1.1  christos 	while (*p == '\n')
    675  1.1  christos 		p++;
    676  1.1  christos 	fprintf(stderr, " context is\n\t");
    677  1.1  christos 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
    678  1.1  christos 		;
    679  1.1  christos 	for ( ; p < q; p++)
    680  1.1  christos 		if (*p)
    681  1.1  christos 			putc(*p, stderr);
    682  1.1  christos 	fprintf(stderr, " >>> ");
    683  1.1  christos 	for ( ; p < ep; p++)
    684  1.1  christos 		if (*p)
    685  1.1  christos 			putc(*p, stderr);
    686  1.1  christos 	fprintf(stderr, " <<< ");
    687  1.2  christos #if 0
    688  1.2  christos 	/*
    689  1.2  christos 	 * The following code was used to print the rest of the line of
    690  1.2  christos 	 * error context. It naively counts brackets, parens and braces in
    691  1.2  christos 	 * order to minimize the parsing effect of dropping the rest of the
    692  1.2  christos 	 * line but it does not work in all the cases. It is too much work
    693  1.2  christos 	 * to save the current program input point and restore it in all the
    694  1.2  christos 	 * cases just for the benefit of error printing so for now this
    695  1.2  christos 	 * code is disabled. In particular this code is confused if the
    696  1.2  christos 	 * [ { ( ) } ] is inside a quoted string or a pattern.
    697  1.2  christos 	 */
    698  1.2  christos 	if (*ep) {
    699  1.2  christos 		int c;
    700  1.1  christos 		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
    701  1.1  christos 			putc(c, stderr);
    702  1.1  christos 			bclass(c);
    703  1.1  christos 		}
    704  1.2  christos 	}
    705  1.2  christos #endif
    706  1.1  christos 	putc('\n', stderr);
    707  1.1  christos 	ep = ebuf;
    708  1.1  christos }
    709  1.1  christos 
    710  1.1  christos void bclass(int c)
    711  1.1  christos {
    712  1.1  christos 	switch (c) {
    713  1.1  christos 	case '{': bracecnt++; break;
    714  1.1  christos 	case '}': bracecnt--; break;
    715  1.1  christos 	case '[': brackcnt++; break;
    716  1.1  christos 	case ']': brackcnt--; break;
    717  1.1  christos 	case '(': parencnt++; break;
    718  1.1  christos 	case ')': parencnt--; break;
    719  1.1  christos 	}
    720  1.1  christos }
    721  1.1  christos 
    722  1.1  christos double errcheck(double x, const char *s)
    723  1.1  christos {
    724  1.1  christos 
    725  1.1  christos 	if (errno == EDOM) {
    726  1.1  christos 		errno = 0;
    727  1.1  christos 		WARNING("%s argument out of domain", s);
    728  1.1  christos 		x = 1;
    729  1.1  christos 	} else if (errno == ERANGE) {
    730  1.1  christos 		errno = 0;
    731  1.1  christos 		WARNING("%s result out of range", s);
    732  1.1  christos 		x = 1;
    733  1.1  christos 	}
    734  1.1  christos 	return x;
    735  1.1  christos }
    736  1.1  christos 
    737  1.1  christos int isclvar(const char *s)	/* is s of form var=something ? */
    738  1.1  christos {
    739  1.1  christos 	const char *os = s;
    740  1.1  christos 
    741  1.1  christos 	if (!isalpha((uschar) *s) && *s != '_')
    742  1.1  christos 		return 0;
    743  1.1  christos 	for ( ; *s; s++)
    744  1.1  christos 		if (!(isalnum((uschar) *s) || *s == '_'))
    745  1.1  christos 			break;
    746  1.1  christos 	return *s == '=' && s > os && *(s+1) != '=';
    747  1.1  christos }
    748  1.1  christos 
    749  1.1  christos /* strtod is supposed to be a proper test of what's a valid number */
    750  1.1  christos /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
    751  1.1  christos /* wrong: violates 4.10.1.4 of ansi C standard */
    752  1.1  christos 
    753  1.1  christos #include <math.h>
    754  1.1  christos int is_number(const char *s)
    755  1.1  christos {
    756  1.1  christos 	char *ep;
    757  1.1  christos 	errno = 0;
    758  1.8  christos 	(void)strtod(s, &ep);
    759  1.2  christos 	if (ep == s || errno == ERANGE)
    760  1.2  christos 		return 0;
    761  1.2  christos 	if (ep - s >= 3 && strncasecmp(ep - 3, "nan", 3) == 0)
    762  1.1  christos 		return 0;
    763  1.1  christos 	while (*ep == ' ' || *ep == '\t' || *ep == '\n')
    764  1.1  christos 		ep++;
    765  1.1  christos 	if (*ep == '\0')
    766  1.1  christos 		return 1;
    767  1.1  christos 	else
    768  1.1  christos 		return 0;
    769  1.1  christos }
    770