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