xref: /onnv-gate/usr/src/cmd/awk/lib.c (revision 2615:71e502f72e48)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*2615Snakanon  * Common Development and Distribution License (the "License").
6*2615Snakanon  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21289Snakanon 
22289Snakanon /*
23*2615Snakanon  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24289Snakanon  * Use is subject to license terms.
25289Snakanon  */
26289Snakanon 
270Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
30289Snakanon #pragma ident	"%Z%%M%	%I%	%E% SMI"
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <errno.h>
330Sstevel@tonic-gate #include "awk.h"
340Sstevel@tonic-gate #include "y.tab.h"
350Sstevel@tonic-gate 
36289Snakanon uchar	*record;
37289Snakanon size_t	record_size;
380Sstevel@tonic-gate 
390Sstevel@tonic-gate int	donefld;	/* 1 = implies rec broken into fields */
400Sstevel@tonic-gate int	donerec;	/* 1 = record is valid (no flds have changed) */
410Sstevel@tonic-gate 
42289Snakanon static struct fldtab_chunk {
43289Snakanon 	struct fldtab_chunk	*next;
44289Snakanon 	Cell			fields[FLD_INCR];
45289Snakanon } *fldtab_head, *fldtab_tail;
46289Snakanon 
47289Snakanon static	size_t	fldtab_maxidx;
48289Snakanon 
49289Snakanon static FILE	*infile	= NULL;
50289Snakanon static uchar	*file	= (uchar*) "";
51289Snakanon static uchar	*fields;
52289Snakanon static size_t	fields_size = LINE_INCR;
530Sstevel@tonic-gate 
54289Snakanon static int	maxfld	= 0;	/* last used field */
55289Snakanon static int	argno	= 1;	/* current input argument number */
560Sstevel@tonic-gate 
57289Snakanon static	uchar	*getargv(int);
58289Snakanon static	void	cleanfld(int, int);
59289Snakanon static	int	refldbld(uchar *, uchar *);
60289Snakanon static	void	bcheck2(int, int, int);
61289Snakanon static	void	eprint(void);
62289Snakanon static	void	bclass(int);
63289Snakanon 
64289Snakanon static void
initgetrec(void)65289Snakanon initgetrec(void)
660Sstevel@tonic-gate {
670Sstevel@tonic-gate 	int i;
680Sstevel@tonic-gate 	uchar *p;
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	for (i = 1; i < *ARGC; i++) {
710Sstevel@tonic-gate 		if (!isclvar(p = getargv(i)))	/* find 1st real filename */
720Sstevel@tonic-gate 			return;
730Sstevel@tonic-gate 		setclvar(p);	/* a commandline assignment before filename */
740Sstevel@tonic-gate 		argno++;
750Sstevel@tonic-gate 	}
760Sstevel@tonic-gate 	infile = stdin;		/* no filenames, so use stdin */
770Sstevel@tonic-gate 	/* *FILENAME = file = (uchar*) "-"; */
780Sstevel@tonic-gate }
790Sstevel@tonic-gate 
80289Snakanon int
getrec(uchar ** bufp,size_t * bufsizep)81289Snakanon getrec(uchar **bufp, size_t *bufsizep)
820Sstevel@tonic-gate {
830Sstevel@tonic-gate 	int c;
840Sstevel@tonic-gate 	static int firsttime = 1;
85289Snakanon 	uchar_t	*buf, *nbuf;
86289Snakanon 	size_t	len;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	if (firsttime) {
890Sstevel@tonic-gate 		firsttime = 0;
900Sstevel@tonic-gate 		initgetrec();
910Sstevel@tonic-gate 	}
920Sstevel@tonic-gate 	dprintf(("RS=<%s>, FS=<%s>, ARGC=%f, FILENAME=%s\n",
93289Snakanon 	    *RS, *FS, *ARGC, *FILENAME));
940Sstevel@tonic-gate 	donefld = 0;
950Sstevel@tonic-gate 	donerec = 1;
960Sstevel@tonic-gate 	while (argno < *ARGC || infile == stdin) {
970Sstevel@tonic-gate 		dprintf(("argno=%d, file=|%s|\n", argno, file));
980Sstevel@tonic-gate 		if (infile == NULL) {	/* have to open a new file */
990Sstevel@tonic-gate 			file = getargv(argno);
1000Sstevel@tonic-gate 			if (*file == '\0') {	/* it's been zapped */
1010Sstevel@tonic-gate 				argno++;
1020Sstevel@tonic-gate 				continue;
1030Sstevel@tonic-gate 			}
1040Sstevel@tonic-gate 			if (isclvar(file)) {	/* a var=value arg */
1050Sstevel@tonic-gate 				setclvar(file);
1060Sstevel@tonic-gate 				argno++;
1070Sstevel@tonic-gate 				continue;
1080Sstevel@tonic-gate 			}
1090Sstevel@tonic-gate 			*FILENAME = file;
1100Sstevel@tonic-gate 			dprintf(("opening file %s\n", file));
1110Sstevel@tonic-gate 			if (*file == '-' && *(file+1) == '\0')
1120Sstevel@tonic-gate 				infile = stdin;
1130Sstevel@tonic-gate 			else if ((infile = fopen((char *)file, "r")) == NULL)
1140Sstevel@tonic-gate 				ERROR "can't open file %s", file FATAL;
115289Snakanon 			(void) setfval(fnrloc, 0.0);
1160Sstevel@tonic-gate 		}
117289Snakanon 		c = readrec(&nbuf, &len, infile);
118289Snakanon 		expand_buf(bufp, bufsizep, len);
119289Snakanon 		buf = *bufp;
120289Snakanon 		(void) memcpy(buf, nbuf, len);
121289Snakanon 		buf[len] = '\0';
122289Snakanon 		free(nbuf);
123289Snakanon 
1240Sstevel@tonic-gate 		if (c != 0 || buf[0] != '\0') {	/* normal record */
125*2615Snakanon 			if (bufp == &record) {
1260Sstevel@tonic-gate 				if (!(recloc->tval & DONTFREE))
1270Sstevel@tonic-gate 					xfree(recloc->sval);
1280Sstevel@tonic-gate 				recloc->sval = record;
1290Sstevel@tonic-gate 				recloc->tval = REC | STR | DONTFREE;
130289Snakanon 				if (is_number(recloc->sval)) {
131289Snakanon 					recloc->fval =
132289Snakanon 					    atof((const char *)recloc->sval);
1330Sstevel@tonic-gate 					recloc->tval |= NUM;
1340Sstevel@tonic-gate 				}
1350Sstevel@tonic-gate 			}
136289Snakanon 			(void) setfval(nrloc, nrloc->fval+1);
137289Snakanon 			(void) setfval(fnrloc, fnrloc->fval+1);
1380Sstevel@tonic-gate 			return (1);
1390Sstevel@tonic-gate 		}
1400Sstevel@tonic-gate 		/* EOF arrived on this file; set up next */
1410Sstevel@tonic-gate 		if (infile != stdin)
142289Snakanon 			(void) fclose(infile);
1430Sstevel@tonic-gate 		infile = NULL;
1440Sstevel@tonic-gate 		argno++;
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate 	return (0);	/* true end of file */
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate 
149289Snakanon int
readrec(uchar ** bufp,size_t * sizep,FILE * inf)150289Snakanon readrec(uchar **bufp, size_t *sizep, FILE *inf)	/* read one record into buf */
1510Sstevel@tonic-gate {
152648Sceastha 	int sep, c;
153289Snakanon 	uchar	*buf;
1540Sstevel@tonic-gate 	int	count;
155289Snakanon 	size_t	bufsize;
1560Sstevel@tonic-gate 
157289Snakanon 	init_buf(&buf, &bufsize, LINE_INCR);
1580Sstevel@tonic-gate 	if ((sep = **RS) == 0) {
1590Sstevel@tonic-gate 		sep = '\n';
1600Sstevel@tonic-gate 		/* skip leading \n's */
1610Sstevel@tonic-gate 		while ((c = getc(inf)) == '\n' && c != EOF)
1620Sstevel@tonic-gate 			;
1630Sstevel@tonic-gate 		if (c != EOF)
164289Snakanon 			(void) ungetc(c, inf);
1650Sstevel@tonic-gate 	}
166289Snakanon 	count = 0;
167289Snakanon 	for (;;) {
1680Sstevel@tonic-gate 		while ((c = getc(inf)) != sep && c != EOF) {
169289Snakanon 			expand_buf(&buf, &bufsize, count);
170289Snakanon 			buf[count++] = c;
1710Sstevel@tonic-gate 		}
1720Sstevel@tonic-gate 		if (**RS == sep || c == EOF)
1730Sstevel@tonic-gate 			break;
1740Sstevel@tonic-gate 		if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
1750Sstevel@tonic-gate 			break;
176289Snakanon 		expand_buf(&buf, &bufsize, count + 1);
177289Snakanon 		buf[count++] = '\n';
178289Snakanon 		buf[count++] = c;
1790Sstevel@tonic-gate 	}
180289Snakanon 	buf[count] = '\0';
1810Sstevel@tonic-gate 	dprintf(("readrec saw <%s>, returns %d\n",
182289Snakanon 	    buf, c == EOF && count == 0 ? 0 : 1));
183289Snakanon 	*bufp = buf;
184289Snakanon 	*sizep = count;
185289Snakanon 	return (c == EOF && count == 0 ? 0 : 1);
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate /* get ARGV[n] */
189289Snakanon static uchar *
getargv(int n)190289Snakanon getargv(int n)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	Cell *x;
193289Snakanon 	uchar *s, temp[11];
1940Sstevel@tonic-gate 	extern Array *ARGVtab;
1950Sstevel@tonic-gate 
196289Snakanon 	(void) sprintf((char *)temp, "%d", n);
197289Snakanon 	x = setsymtab(temp, (uchar *)"", 0.0, STR, ARGVtab);
1980Sstevel@tonic-gate 	s = getsval(x);
1990Sstevel@tonic-gate 	dprintf(("getargv(%d) returns |%s|\n", n, s));
2000Sstevel@tonic-gate 	return (s);
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate 
203289Snakanon void
setclvar(uchar * s)204289Snakanon setclvar(uchar *s)	/* set var=value from s */
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate 	uchar *p;
2070Sstevel@tonic-gate 	Cell *q;
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	for (p = s; *p != '='; p++)
2100Sstevel@tonic-gate 		;
2110Sstevel@tonic-gate 	*p++ = 0;
2120Sstevel@tonic-gate 	p = qstring(p, '\0');
2130Sstevel@tonic-gate 	q = setsymtab(s, p, 0.0, STR, symtab);
214289Snakanon 	(void) setsval(q, p);
215289Snakanon 	if (is_number(q->sval)) {
216289Snakanon 		q->fval = atof((const char *)q->sval);
2170Sstevel@tonic-gate 		q->tval |= NUM;
2180Sstevel@tonic-gate 	}
2190Sstevel@tonic-gate 	dprintf(("command line set %s to |%s|\n", s, p));
220289Snakanon 	free(p);
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate 
223289Snakanon void
fldbld(void)224289Snakanon fldbld(void)
2250Sstevel@tonic-gate {
226648Sceastha 	uchar *r, *fr, sep;
2270Sstevel@tonic-gate 	Cell *p;
2280Sstevel@tonic-gate 	int i;
229289Snakanon 	size_t	len;
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	if (donefld)
2320Sstevel@tonic-gate 		return;
2330Sstevel@tonic-gate 	if (!(recloc->tval & STR))
234289Snakanon 		(void) getsval(recloc);
2350Sstevel@tonic-gate 	r = recloc->sval;	/* was record! */
236289Snakanon 
237289Snakanon 	/* make sure fields is always allocated */
238289Snakanon 	adjust_buf(&fields, fields_size);
239289Snakanon 
240289Snakanon 	/*
241289Snakanon 	 * make sure fields has enough size. We don't expand the buffer
242289Snakanon 	 * in the middle of the loop, since p->sval has already pointed
243289Snakanon 	 * the address in the fields.
244289Snakanon 	 */
245289Snakanon 	len = strlen((char *)r) + 1;
246289Snakanon 	expand_buf(&fields, &fields_size, len);
2470Sstevel@tonic-gate 	fr = fields;
248289Snakanon 
2490Sstevel@tonic-gate 	i = 0;	/* number of fields accumulated here */
250289Snakanon 	if (strlen((char *)*FS) > 1) {	/* it's a regular expression */
2510Sstevel@tonic-gate 		i = refldbld(r, *FS);
2520Sstevel@tonic-gate 	} else if ((sep = **FS) == ' ') {
2530Sstevel@tonic-gate 		for (i = 0; ; ) {
2540Sstevel@tonic-gate 			while (*r == ' ' || *r == '\t' || *r == '\n')
2550Sstevel@tonic-gate 				r++;
2560Sstevel@tonic-gate 			if (*r == 0)
2570Sstevel@tonic-gate 				break;
2580Sstevel@tonic-gate 			i++;
259289Snakanon 			p = getfld(i);
260289Snakanon 			if (!(p->tval & DONTFREE))
261289Snakanon 				xfree(p->sval);
262289Snakanon 			p->sval = fr;
263289Snakanon 			p->tval = FLD | STR | DONTFREE;
2640Sstevel@tonic-gate 			do
2650Sstevel@tonic-gate 				*fr++ = *r++;
2660Sstevel@tonic-gate 			while (*r != ' ' && *r != '\t' && *r != '\n' &&
267289Snakanon 			    *r != '\0')
268289Snakanon 				;
2690Sstevel@tonic-gate 			*fr++ = 0;
2700Sstevel@tonic-gate 		}
2710Sstevel@tonic-gate 		*fr = 0;
2720Sstevel@tonic-gate 	} else if (*r != 0) {	/* if 0, it's a null field */
2730Sstevel@tonic-gate 		for (;;) {
2740Sstevel@tonic-gate 			i++;
275289Snakanon 			p = getfld(i);
276289Snakanon 			if (!(p->tval & DONTFREE))
277289Snakanon 				xfree(p->sval);
278289Snakanon 			p->sval = fr;
279289Snakanon 			p->tval = FLD | STR | DONTFREE;
2800Sstevel@tonic-gate 			/* \n always a separator */
2810Sstevel@tonic-gate 			while (*r != sep && *r != '\n' && *r != '\0')
2820Sstevel@tonic-gate 				*fr++ = *r++;
2830Sstevel@tonic-gate 			*fr++ = 0;
2840Sstevel@tonic-gate 			if (*r++ == 0)
2850Sstevel@tonic-gate 				break;
2860Sstevel@tonic-gate 		}
2870Sstevel@tonic-gate 		*fr = 0;
2880Sstevel@tonic-gate 	}
2890Sstevel@tonic-gate 	/* clean out junk from previous record */
2900Sstevel@tonic-gate 	cleanfld(i, maxfld);
2910Sstevel@tonic-gate 	maxfld = i;
2920Sstevel@tonic-gate 	donefld = 1;
293289Snakanon 	for (i = 1; i <= maxfld; i++) {
294289Snakanon 		p = getfld(i);
295289Snakanon 		if (is_number(p->sval)) {
296289Snakanon 			p->fval = atof((const char *)p->sval);
2970Sstevel@tonic-gate 			p->tval |= NUM;
2980Sstevel@tonic-gate 		}
2990Sstevel@tonic-gate 	}
300289Snakanon 
301289Snakanon 	(void) setfval(nfloc, (Awkfloat) maxfld);
302289Snakanon 	if (dbg) {
303289Snakanon 		for (i = 0; i <= maxfld; i++) {
304289Snakanon 			p = getfld(i);
305289Snakanon 			(void) printf("field %d: |%s|\n", i, p->sval);
306289Snakanon 		}
307289Snakanon 	}
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate 
310289Snakanon static void
cleanfld(int n1,int n2)311289Snakanon cleanfld(int n1, int n2)	/* clean out fields n1..n2 inclusive */
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate 	static uchar *nullstat = (uchar *) "";
314648Sceastha 	Cell *p;
315289Snakanon 	int	i;
3160Sstevel@tonic-gate 
317289Snakanon 	for (i = n2; i > n1; i--) {
318289Snakanon 		p = getfld(i);
3190Sstevel@tonic-gate 		if (!(p->tval & DONTFREE))
3200Sstevel@tonic-gate 			xfree(p->sval);
3210Sstevel@tonic-gate 		p->tval = FLD | STR | DONTFREE;
3220Sstevel@tonic-gate 		p->sval = nullstat;
3230Sstevel@tonic-gate 	}
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate 
326289Snakanon void
newfld(int n)327289Snakanon newfld(int n)	/* add field n (after end) */
3280Sstevel@tonic-gate {
329289Snakanon 	if (n < 0)
330289Snakanon 		ERROR "accessing invalid field", record FATAL;
331289Snakanon 	(void) getfld(n);
3320Sstevel@tonic-gate 	cleanfld(maxfld, n);
3330Sstevel@tonic-gate 	maxfld = n;
334289Snakanon 	(void) setfval(nfloc, (Awkfloat) n);
335289Snakanon }
336289Snakanon 
337289Snakanon /*
338289Snakanon  * allocate field table. We don't reallocate the table since there
339289Snakanon  * might be somewhere recording the address of the table.
340289Snakanon  */
341289Snakanon static void
morefld(void)342289Snakanon morefld(void)
343289Snakanon {
344289Snakanon 	int	i;
345289Snakanon 	struct fldtab_chunk *fldcp;
346289Snakanon 	Cell	*newfld;
347289Snakanon 
348289Snakanon 	if ((fldcp = calloc(sizeof (struct fldtab_chunk), 1)) == NULL)
349289Snakanon 		ERROR "out of space in morefld" FATAL;
350289Snakanon 
351289Snakanon 	newfld = &fldcp->fields[0];
352289Snakanon 	for (i = 0; i < FLD_INCR; i++) {
353289Snakanon 		newfld[i].ctype = OCELL;
354289Snakanon 		newfld[i].csub = CFLD;
355289Snakanon 		newfld[i].nval = NULL;
356289Snakanon 		newfld[i].sval = (uchar *)"";
357289Snakanon 		newfld[i].fval = 0.0;
358289Snakanon 		newfld[i].tval = FLD|STR|DONTFREE;
359289Snakanon 		newfld[i].cnext = NULL;
360289Snakanon 	}
361289Snakanon 	/*
362289Snakanon 	 * link this field chunk
363289Snakanon 	 */
364289Snakanon 	if (fldtab_head == NULL)
365289Snakanon 		fldtab_head = fldcp;
366289Snakanon 	else
367289Snakanon 		fldtab_tail->next = fldcp;
368289Snakanon 	fldtab_tail = fldcp;
369289Snakanon 	fldcp->next = NULL;
370289Snakanon 
371289Snakanon 	fldtab_maxidx += FLD_INCR;
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate 
374289Snakanon Cell *
getfld(int idx)375289Snakanon getfld(int idx)
3760Sstevel@tonic-gate {
377289Snakanon 	struct fldtab_chunk *fldcp;
378289Snakanon 	int	cbase;
379289Snakanon 
380289Snakanon 	if (idx < 0)
381289Snakanon 		ERROR "trying to access field %d", idx FATAL;
382289Snakanon 	while (idx >= fldtab_maxidx)
383289Snakanon 		morefld();
384289Snakanon 	cbase = 0;
385289Snakanon 	for (fldcp = fldtab_head; fldcp != NULL; fldcp = fldcp->next) {
386289Snakanon 		if (idx < (cbase + FLD_INCR))
387289Snakanon 			return (&fldcp->fields[idx - cbase]);
388289Snakanon 		cbase += FLD_INCR;
389289Snakanon 	}
390289Snakanon 	/* should never happen */
391289Snakanon 	ERROR "trying to access invalid field %d", idx FATAL;
392289Snakanon 	return (NULL);
393289Snakanon }
394289Snakanon 
395289Snakanon int
fldidx(Cell * vp)396289Snakanon fldidx(Cell *vp)
397289Snakanon {
398289Snakanon 	struct fldtab_chunk *fldcp;
399289Snakanon 	Cell	*tbl;
400289Snakanon 	int	cbase;
401289Snakanon 
402289Snakanon 	cbase = 0;
403289Snakanon 	for (fldcp = fldtab_head; fldcp != NULL; fldcp = fldcp->next) {
404289Snakanon 		tbl = &fldcp->fields[0];
405289Snakanon 		if (vp >= tbl && vp < (tbl + FLD_INCR))
406289Snakanon 			return (cbase + (vp - tbl));
407289Snakanon 		cbase += FLD_INCR;
408289Snakanon 	}
409289Snakanon 	/* should never happen */
410289Snakanon 	ERROR "trying to access unknown field" FATAL;
411289Snakanon 	return (0);
412289Snakanon }
413289Snakanon 
414289Snakanon static int
refldbld(uchar * rec,uchar * fs)415289Snakanon refldbld(uchar *rec, uchar *fs)	/* build fields from reg expr in FS */
416289Snakanon {
4170Sstevel@tonic-gate 	uchar *fr;
4180Sstevel@tonic-gate 	int i, tempstat;
4190Sstevel@tonic-gate 	fa *pfa;
420289Snakanon 	Cell	*p;
421289Snakanon 	size_t	len;
4220Sstevel@tonic-gate 
423289Snakanon 	/* make sure fields is allocated */
424289Snakanon 	adjust_buf(&fields, fields_size);
4250Sstevel@tonic-gate 	fr = fields;
4260Sstevel@tonic-gate 	*fr = '\0';
4270Sstevel@tonic-gate 	if (*rec == '\0')
4280Sstevel@tonic-gate 		return (0);
429289Snakanon 
430289Snakanon 	len = strlen((char *)rec) + 1;
431289Snakanon 	expand_buf(&fields, &fields_size, len);
432289Snakanon 	fr = fields;
433289Snakanon 
4340Sstevel@tonic-gate 	pfa = makedfa(fs, 1);
4350Sstevel@tonic-gate 	dprintf(("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs));
4360Sstevel@tonic-gate 	tempstat = pfa->initstat;
437289Snakanon 	for (i = 1; ; i++) {
438289Snakanon 		p = getfld(i);
439289Snakanon 		if (!(p->tval & DONTFREE))
440289Snakanon 			xfree(p->sval);
441289Snakanon 		p->tval = FLD | STR | DONTFREE;
442289Snakanon 		p->sval = fr;
4430Sstevel@tonic-gate 		dprintf(("refldbld: i=%d\n", i));
4440Sstevel@tonic-gate 		if (nematch(pfa, rec)) {
4450Sstevel@tonic-gate 			pfa->initstat = 2;
4460Sstevel@tonic-gate 			dprintf(("match %s (%d chars)\n", patbeg, patlen));
447289Snakanon 			(void) strncpy((char *)fr, (char *)rec, patbeg-rec);
4480Sstevel@tonic-gate 			fr += patbeg - rec + 1;
4490Sstevel@tonic-gate 			*(fr-1) = '\0';
4500Sstevel@tonic-gate 			rec = patbeg + patlen;
4510Sstevel@tonic-gate 		} else {
4520Sstevel@tonic-gate 			dprintf(("no match %s\n", rec));
453289Snakanon 			(void) strcpy((char *)fr, (char *)rec);
4540Sstevel@tonic-gate 			pfa->initstat = tempstat;
4550Sstevel@tonic-gate 			break;
4560Sstevel@tonic-gate 		}
4570Sstevel@tonic-gate 	}
4580Sstevel@tonic-gate 	return (i);
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate 
461289Snakanon void
recbld(void)462289Snakanon recbld(void)
4630Sstevel@tonic-gate {
4640Sstevel@tonic-gate 	int i;
465648Sceastha 	uchar *p;
466289Snakanon 	size_t cnt, len, olen;
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	if (donerec == 1)
4690Sstevel@tonic-gate 		return;
470289Snakanon 	cnt = 0;
471289Snakanon 	olen = strlen((char *)*OFS);
4720Sstevel@tonic-gate 	for (i = 1; i <= *NF; i++) {
473289Snakanon 		p = getsval(getfld(i));
474289Snakanon 		len = strlen((char *)p);
475*2615Snakanon 		expand_buf(&record, &record_size, cnt + len + olen);
476*2615Snakanon 		(void) memcpy(&record[cnt], p, len);
477289Snakanon 		cnt += len;
478289Snakanon 		if (i < *NF) {
479*2615Snakanon 			(void) memcpy(&record[cnt], *OFS, olen);
480289Snakanon 			cnt += olen;
481289Snakanon 		}
4820Sstevel@tonic-gate 	}
483*2615Snakanon 	record[cnt] = '\0';
484289Snakanon 	dprintf(("in recbld FS=%o, recloc=%p\n", **FS, (void *)recloc));
485*2615Snakanon 	if (!(recloc->tval & DONTFREE))
486*2615Snakanon 		xfree(recloc->sval);
4870Sstevel@tonic-gate 	recloc->tval = REC | STR | DONTFREE;
488*2615Snakanon 	recloc->sval = record;
489289Snakanon 	dprintf(("in recbld FS=%o, recloc=%p\n", **FS, (void *)recloc));
4900Sstevel@tonic-gate 	dprintf(("recbld = |%s|\n", record));
4910Sstevel@tonic-gate 	donerec = 1;
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate Cell *
fieldadr(int n)495289Snakanon fieldadr(int n)
4960Sstevel@tonic-gate {
497289Snakanon 	if (n < 0)
4980Sstevel@tonic-gate 		ERROR "trying to access field %d", n FATAL;
499289Snakanon 	return (getfld(n));
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate int	errorflag	= 0;
5030Sstevel@tonic-gate char	errbuf[200];
5040Sstevel@tonic-gate 
505289Snakanon void
yyerror(char * s)506289Snakanon yyerror(char *s)
5070Sstevel@tonic-gate {
5080Sstevel@tonic-gate 	extern uchar *cmdname, *curfname;
5090Sstevel@tonic-gate 	static int been_here = 0;
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	if (been_here++ > 2)
5120Sstevel@tonic-gate 		return;
513289Snakanon 	(void) fprintf(stderr, "%s: %s", cmdname, s);
514289Snakanon 	(void) fprintf(stderr, gettext(" at source line %lld"), lineno);
5150Sstevel@tonic-gate 	if (curfname != NULL)
516289Snakanon 		(void) fprintf(stderr, gettext(" in function %s"), curfname);
517289Snakanon 	(void) fprintf(stderr, "\n");
5180Sstevel@tonic-gate 	errorflag = 2;
5190Sstevel@tonic-gate 	eprint();
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate 
522289Snakanon /*ARGSUSED*/
523289Snakanon void
fpecatch(int sig)524289Snakanon fpecatch(int sig)
5250Sstevel@tonic-gate {
5260Sstevel@tonic-gate 	ERROR "floating point exception" FATAL;
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate extern int bracecnt, brackcnt, parencnt;
5300Sstevel@tonic-gate 
531289Snakanon void
bracecheck(void)532289Snakanon bracecheck(void)
5330Sstevel@tonic-gate {
5340Sstevel@tonic-gate 	int c;
5350Sstevel@tonic-gate 	static int beenhere = 0;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	if (beenhere++)
5380Sstevel@tonic-gate 		return;
5390Sstevel@tonic-gate 	while ((c = input()) != EOF && c != '\0')
5400Sstevel@tonic-gate 		bclass(c);
5410Sstevel@tonic-gate 	bcheck2(bracecnt, '{', '}');
5420Sstevel@tonic-gate 	bcheck2(brackcnt, '[', ']');
5430Sstevel@tonic-gate 	bcheck2(parencnt, '(', ')');
5440Sstevel@tonic-gate }
5450Sstevel@tonic-gate 
546289Snakanon /*ARGSUSED*/
547289Snakanon static void
bcheck2(int n,int c1,int c2)548289Snakanon bcheck2(int n, int c1, int c2)
5490Sstevel@tonic-gate {
5500Sstevel@tonic-gate 	if (n == 1)
551289Snakanon 		(void) fprintf(stderr, gettext("\tmissing %c\n"), c2);
5520Sstevel@tonic-gate 	else if (n > 1)
553289Snakanon 		(void) fprintf(stderr, gettext("\t%d missing %c's\n"), n, c2);
5540Sstevel@tonic-gate 	else if (n == -1)
555289Snakanon 		(void) fprintf(stderr, gettext("\textra %c\n"), c2);
5560Sstevel@tonic-gate 	else if (n < -1)
557289Snakanon 		(void) fprintf(stderr, gettext("\t%d extra %c's\n"), -n, c2);
5580Sstevel@tonic-gate }
5590Sstevel@tonic-gate 
560289Snakanon void
error(int f,char * s)561289Snakanon error(int f, char *s)
5620Sstevel@tonic-gate {
5630Sstevel@tonic-gate 	extern Node *curnode;
5640Sstevel@tonic-gate 	extern uchar *cmdname;
5650Sstevel@tonic-gate 
566289Snakanon 	(void) fflush(stdout);
567289Snakanon 	(void) fprintf(stderr, "%s: ", cmdname);
568289Snakanon 	(void) fprintf(stderr, "%s", s);
569289Snakanon 	(void) fprintf(stderr, "\n");
5700Sstevel@tonic-gate 	if (compile_time != 2 && NR && *NR > 0) {
571289Snakanon 		(void) fprintf(stderr,
572289Snakanon 		    gettext(" input record number %g"), *FNR);
573289Snakanon 		if (strcmp((char *)*FILENAME, "-") != 0)
574289Snakanon 			(void) fprintf(stderr, gettext(", file %s"), *FILENAME);
575289Snakanon 		(void) fprintf(stderr, "\n");
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 	if (compile_time != 2 && curnode)
578289Snakanon 		(void) fprintf(stderr, gettext(" source line number %lld\n"),
5790Sstevel@tonic-gate 		    curnode->lineno);
580289Snakanon 	else if (compile_time != 2 && lineno) {
581289Snakanon 		(void) fprintf(stderr,
582289Snakanon 		    gettext(" source line number %lld\n"), lineno);
583289Snakanon 	}
5840Sstevel@tonic-gate 	eprint();
5850Sstevel@tonic-gate 	if (f) {
5860Sstevel@tonic-gate 		if (dbg)
5870Sstevel@tonic-gate 			abort();
5880Sstevel@tonic-gate 		exit(2);
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate 
592289Snakanon static void
eprint(void)593289Snakanon eprint(void)	/* try to print context around error */
5940Sstevel@tonic-gate {
5950Sstevel@tonic-gate 	uchar *p, *q;
5960Sstevel@tonic-gate 	int c;
5970Sstevel@tonic-gate 	static int been_here = 0;
5980Sstevel@tonic-gate 	extern uchar ebuf[300], *ep;
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
6010Sstevel@tonic-gate 		return;
6020Sstevel@tonic-gate 	p = ep - 1;
6030Sstevel@tonic-gate 	if (p > ebuf && *p == '\n')
6040Sstevel@tonic-gate 		p--;
6050Sstevel@tonic-gate 	for (; p > ebuf && *p != '\n' && *p != '\0'; p--)
6060Sstevel@tonic-gate 		;
6070Sstevel@tonic-gate 	while (*p == '\n')
6080Sstevel@tonic-gate 		p++;
609289Snakanon 	(void) fprintf(stderr, gettext(" context is\n\t"));
610289Snakanon 	for (q = ep-1; q >= p && *q != ' ' && *q != '\t' && *q != '\n'; q--)
6110Sstevel@tonic-gate 		;
6120Sstevel@tonic-gate 	for (; p < q; p++)
6130Sstevel@tonic-gate 		if (*p)
614289Snakanon 			(void) putc(*p, stderr);
615289Snakanon 	(void) fprintf(stderr, " >>> ");
6160Sstevel@tonic-gate 	for (; p < ep; p++)
6170Sstevel@tonic-gate 		if (*p)
618289Snakanon 			(void) putc(*p, stderr);
619289Snakanon 	(void) fprintf(stderr, " <<< ");
6200Sstevel@tonic-gate 	if (*ep)
6210Sstevel@tonic-gate 		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
622289Snakanon 			(void) putc(c, stderr);
6230Sstevel@tonic-gate 			bclass(c);
6240Sstevel@tonic-gate 		}
625289Snakanon 	(void) putc('\n', stderr);
6260Sstevel@tonic-gate 	ep = ebuf;
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate 
629289Snakanon static void
bclass(int c)630289Snakanon bclass(int c)
6310Sstevel@tonic-gate {
6320Sstevel@tonic-gate 	switch (c) {
6330Sstevel@tonic-gate 	case '{': bracecnt++; break;
6340Sstevel@tonic-gate 	case '}': bracecnt--; break;
6350Sstevel@tonic-gate 	case '[': brackcnt++; break;
6360Sstevel@tonic-gate 	case ']': brackcnt--; break;
6370Sstevel@tonic-gate 	case '(': parencnt++; break;
6380Sstevel@tonic-gate 	case ')': parencnt--; break;
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate }
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate double
errcheck(double x,char * s)643289Snakanon errcheck(double x, char *s)
6440Sstevel@tonic-gate {
6450Sstevel@tonic-gate 	extern int errno;
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	if (errno == EDOM) {
6480Sstevel@tonic-gate 		errno = 0;
6490Sstevel@tonic-gate 		ERROR "%s argument out of domain", s WARNING;
6500Sstevel@tonic-gate 		x = 1;
6510Sstevel@tonic-gate 	} else if (errno == ERANGE) {
6520Sstevel@tonic-gate 		errno = 0;
6530Sstevel@tonic-gate 		ERROR "%s result out of range", s WARNING;
6540Sstevel@tonic-gate 		x = 1;
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 	return (x);
6570Sstevel@tonic-gate }
6580Sstevel@tonic-gate 
659289Snakanon void
PUTS(uchar * s)660289Snakanon PUTS(uchar *s)
661289Snakanon {
6620Sstevel@tonic-gate 	dprintf(("%s\n", s));
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate 
665289Snakanon int
isclvar(uchar * s)666289Snakanon isclvar(uchar *s)	/* is s of form var=something? */
6670Sstevel@tonic-gate {
668648Sceastha 	if (s != NULL) {
669648Sceastha 
670648Sceastha 		/* Must begin with an underscore or alphabetic character */
671648Sceastha 		if (isalpha(*s) || (*s == '_')) {
6720Sstevel@tonic-gate 
673648Sceastha 			for (s++; *s; s++) {
674648Sceastha 				/*
675648Sceastha 				 * followed by a sequence of underscores,
676648Sceastha 				 * digits, and alphabetics
677648Sceastha 				 */
678648Sceastha 				if (!(isalnum(*s) || *s == '_')) {
679648Sceastha 					break;
680648Sceastha 				}
681648Sceastha 			}
682648Sceastha 			return (*s == '=' && *(s + 1) != '=');
683648Sceastha 		}
684648Sceastha 	}
685648Sceastha 
686648Sceastha 	return (0);
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate #define	MAXEXPON	38	/* maximum exponent for fp number */
6900Sstevel@tonic-gate 
691289Snakanon int
is_number(uchar * s)692289Snakanon is_number(uchar *s)
6930Sstevel@tonic-gate {
694648Sceastha 	int d1, d2;
6950Sstevel@tonic-gate 	int point;
6960Sstevel@tonic-gate 	uchar *es;
6970Sstevel@tonic-gate 	extern char	radixpoint;
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	d1 = d2 = point = 0;
7000Sstevel@tonic-gate 	while (*s == ' ' || *s == '\t' || *s == '\n')
7010Sstevel@tonic-gate 		s++;
7020Sstevel@tonic-gate 	if (*s == '\0')
7030Sstevel@tonic-gate 		return (0);	/* empty stuff isn't number */
7040Sstevel@tonic-gate 	if (*s == '+' || *s == '-')
7050Sstevel@tonic-gate 		s++;
7060Sstevel@tonic-gate 	if (!isdigit(*s) && *s != radixpoint)
7070Sstevel@tonic-gate 		return (0);
7080Sstevel@tonic-gate 	if (isdigit(*s)) {
7090Sstevel@tonic-gate 		do {
7100Sstevel@tonic-gate 			d1++;
7110Sstevel@tonic-gate 			s++;
7120Sstevel@tonic-gate 		} while (isdigit(*s));
7130Sstevel@tonic-gate 	}
7140Sstevel@tonic-gate 	if (d1 >= MAXEXPON)
7150Sstevel@tonic-gate 		return (0);	/* too many digits to convert */
7160Sstevel@tonic-gate 	if (*s == radixpoint) {
7170Sstevel@tonic-gate 		point++;
7180Sstevel@tonic-gate 		s++;
7190Sstevel@tonic-gate 	}
7200Sstevel@tonic-gate 	if (isdigit(*s)) {
7210Sstevel@tonic-gate 		d2++;
7220Sstevel@tonic-gate 		do {
7230Sstevel@tonic-gate 			s++;
7240Sstevel@tonic-gate 		} while (isdigit(*s));
7250Sstevel@tonic-gate 	}
7260Sstevel@tonic-gate 	if (!(d1 || point && d2))
7270Sstevel@tonic-gate 		return (0);
7280Sstevel@tonic-gate 	if (*s == 'e' || *s == 'E') {
7290Sstevel@tonic-gate 		s++;
7300Sstevel@tonic-gate 		if (*s == '+' || *s == '-')
7310Sstevel@tonic-gate 			s++;
7320Sstevel@tonic-gate 		if (!isdigit(*s))
7330Sstevel@tonic-gate 			return (0);
7340Sstevel@tonic-gate 		es = s;
7350Sstevel@tonic-gate 		do {
7360Sstevel@tonic-gate 			s++;
7370Sstevel@tonic-gate 		} while (isdigit(*s));
738289Snakanon 		if (s - es > 2) {
7390Sstevel@tonic-gate 			return (0);
740289Snakanon 		} else if (s - es == 2 &&
741289Snakanon 		    (int)(10 * (*es-'0') + *(es+1)-'0') >= MAXEXPON) {
7420Sstevel@tonic-gate 			return (0);
743289Snakanon 		}
7440Sstevel@tonic-gate 	}
7450Sstevel@tonic-gate 	while (*s == ' ' || *s == '\t' || *s == '\n')
7460Sstevel@tonic-gate 		s++;
7470Sstevel@tonic-gate 	if (*s == '\0')
7480Sstevel@tonic-gate 		return (1);
7490Sstevel@tonic-gate 	else
7500Sstevel@tonic-gate 		return (0);
7510Sstevel@tonic-gate }
752289Snakanon 
753289Snakanon void
init_buf(uchar ** optr,size_t * sizep,size_t amt)754289Snakanon init_buf(uchar **optr, size_t *sizep, size_t amt)
755289Snakanon {
756289Snakanon 	uchar	*nptr = NULL;
757289Snakanon 
758289Snakanon 	if ((nptr = malloc(amt)) == NULL)
759289Snakanon 		ERROR "out of space in init_buf" FATAL;
760289Snakanon 	/* initial buffer should have NULL terminated */
761289Snakanon 	*nptr = '\0';
762289Snakanon 	if (sizep != NULL)
763289Snakanon 		*sizep = amt;
764289Snakanon 	*optr = nptr;
765289Snakanon }
766289Snakanon 
767289Snakanon void
r_expand_buf(uchar ** optr,size_t * sizep,size_t req)768289Snakanon r_expand_buf(uchar **optr, size_t *sizep, size_t req)
769289Snakanon {
770289Snakanon 	uchar	*nptr;
771289Snakanon 	size_t	amt, size = *sizep;
772289Snakanon 
773289Snakanon 	if (size != 0 && req < (size - 1))
774289Snakanon 		return;
775289Snakanon 	amt = req + 1 - size;
776289Snakanon 	amt = (amt / LINE_INCR + 1) * LINE_INCR;
777289Snakanon 
778289Snakanon 	if ((nptr = realloc(*optr, size + amt)) == NULL)
779289Snakanon 		ERROR "out of space in expand_buf" FATAL;
780289Snakanon 	/* initial buffer should have NULL terminated */
781289Snakanon 	if (size == 0)
782289Snakanon 		*nptr = '\0';
783289Snakanon 	*sizep += amt;
784289Snakanon 	*optr = nptr;
785289Snakanon }
786289Snakanon 
787289Snakanon void
adjust_buf(uchar ** optr,size_t size)788289Snakanon adjust_buf(uchar **optr, size_t size)
789289Snakanon {
790289Snakanon 	uchar	*nptr;
791289Snakanon 
792289Snakanon 	if ((nptr = realloc(*optr, size)) == NULL)
793289Snakanon 		ERROR "out of space in adjust_buf" FATAL;
794289Snakanon 	*optr = nptr;
795289Snakanon }
796