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