xref: /csrg-svn/old/awk/lib.c (revision 48236)
1*48236Sbostic /*-
2*48236Sbostic  * Copyright (c) 1991 The Regents of the University of California.
3*48236Sbostic  * All rights reserved.
4*48236Sbostic  *
5*48236Sbostic  * %sccs.include.proprietary.c%
6*48236Sbostic  */
7*48236Sbostic 
814473Ssam #ifndef lint
9*48236Sbostic static char sccsid[] = "@(#)lib.c	4.9 (Berkeley) 04/17/91";
10*48236Sbostic #endif /* not lint */
116671Smckusick 
1246819Sbostic #include <stdarg.h>
136671Smckusick #include "stdio.h"
146671Smckusick #include "awk.def"
156671Smckusick #include "awk.h"
166671Smckusick #include "ctype.h"
176671Smckusick 
1832354Sbostic extern FILE	*yyin;	/* lex input file */
1944021Sbostic extern char	*lexprog;	/* points to program argument if it exists */
206671Smckusick FILE	*infile	= NULL;
216671Smckusick char	*file;
226671Smckusick #define	RECSIZE	(5 * 512)
236671Smckusick char	record[RECSIZE];
246671Smckusick char	fields[RECSIZE];
2510794Ssam char	EMPTY[] = "";
266671Smckusick 
276671Smckusick #define	MAXFLD	100
286671Smckusick int	donefld;	/* 1 = implies rec broken into fields */
296671Smckusick int	donerec;	/* 1 = record is valid (no flds have changed) */
306671Smckusick int	mustfld;	/* 1 = NF seen, so always break*/
316671Smckusick 
3210794Ssam #define	FINIT	{EMPTY, EMPTY, 0.0, FLD|STR}
336671Smckusick cell fldtab[MAXFLD] = {	/*room for fields */
346671Smckusick 	{ "$record", record, 0.0, STR|FLD},
3531035Sbostic 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
3631035Sbostic 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
3731035Sbostic 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
3831035Sbostic 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
3931035Sbostic 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
4031035Sbostic 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
4131035Sbostic 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
4231035Sbostic 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
4331035Sbostic 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
446671Smckusick };
456671Smckusick int	maxfld	= 0;	/* last used field */
466671Smckusick 
476671Smckusick 
486671Smckusick getrec()
496671Smckusick {
506671Smckusick 	register char *rr;
516671Smckusick 	extern int svargc;
526671Smckusick 	extern char **svargv;
536671Smckusick 	register c, sep;
546671Smckusick 
556671Smckusick 	dprintf("**RS=%o, **FS=%o\n", **RS, **FS, NULL);
566671Smckusick 	donefld = 0;
576671Smckusick 	donerec = 1;
586671Smckusick 	record[0] = 0;
596671Smckusick 	while (svargc > 0) {
606671Smckusick 		dprintf("svargc=%d, *svargv=%s\n", svargc, *svargv, NULL);
616671Smckusick 		if (infile == NULL) {	/* have to open a new file */
626671Smckusick 			if (member('=', *svargv)) {	/* it's a var=value argument */
636671Smckusick 				setclvar(*svargv);
646671Smckusick 				svargv++;
656671Smckusick 				svargc--;
666671Smckusick 				continue;
676671Smckusick 			}
686671Smckusick 			*FILENAME = file = *svargv;
696671Smckusick 			dprintf("opening file %s\n", file, NULL, NULL);
7032354Sbostic 			if (*file == '-') {
7144021Sbostic 				if (yyin == stdin && ! lexprog)
7232354Sbostic 					error(FATAL, "standard input already used for reading commands");
7332354Sbostic 				else
7432354Sbostic 					infile = stdin;
7532354Sbostic 			}
766671Smckusick 			else if ((infile = fopen(file, "r")) == NULL)
776671Smckusick 				error(FATAL, "can't open %s", file);
786671Smckusick 		}
796671Smckusick 		if ((sep = **RS) == 0)
806671Smckusick 			sep = '\n';
816671Smckusick 		for (rr = record; ; ) {
826671Smckusick 			for (; (c=getc(infile)) != sep && c != EOF; *rr++ = c)
836671Smckusick 				;
846671Smckusick 			if (**RS == sep || c == EOF)
856671Smckusick 				break;
866671Smckusick 			if ((c = getc(infile)) == '\n' || c == EOF)	/* 2 in a row */
876671Smckusick 				break;
886671Smckusick 			*rr++ = '\n';
896671Smckusick 			*rr++ = c;
906671Smckusick 		}
916671Smckusick 		if (rr > record+RECSIZE)
926671Smckusick 			error(FATAL, "record `%.20s...' too long", record);
936671Smckusick 		*rr = 0;
946671Smckusick 		if (mustfld)
956671Smckusick 			fldbld();
966671Smckusick 		if (c != EOF || rr > record) {	/* normal record */
976671Smckusick 			recloc->tval &= ~NUM;
986671Smckusick 			recloc->tval |= STR;
996671Smckusick 			++nrloc->fval;
1006671Smckusick 			nrloc->tval &= ~STR;
1016671Smckusick 			nrloc->tval |= NUM;
1026671Smckusick 			return(1);
1036671Smckusick 		}
1046671Smckusick 		/* EOF arrived on this file; set up next */
1056671Smckusick 		if (infile != stdin)
1066671Smckusick 			fclose(infile);
1076671Smckusick 		infile = NULL;
1086671Smckusick 		svargc--;
1096671Smckusick 		svargv++;
1106671Smckusick 	}
1116671Smckusick 	return(0);	/* true end of file */
1126671Smckusick }
1136671Smckusick 
1146671Smckusick setclvar(s)	/* set var=value from s */
1156671Smckusick char *s;
1166671Smckusick {
1176671Smckusick 	char *p;
1186671Smckusick 	cell *q;
1196671Smckusick 
1206671Smckusick 	for (p=s; *p != '='; p++)
1216671Smckusick 		;
1226671Smckusick 	*p++ = 0;
1236671Smckusick 	q = setsymtab(s, tostring(p), 0.0, STR, symtab);
1246671Smckusick 	setsval(q, p);
1256671Smckusick 	dprintf("command line set %s to |%s|\n", s, p, NULL);
1266671Smckusick }
1276671Smckusick 
1286671Smckusick fldbld()
1296671Smckusick {
1306671Smckusick 	register char *r, *fr, sep;
1316671Smckusick 	int i, j;
1326671Smckusick 
1336671Smckusick 	r = record;
1346671Smckusick 	fr = fields;
1356671Smckusick 	i = 0;	/* number of fields accumulated here */
1366671Smckusick 	if ((sep = **FS) == ' ')
1376671Smckusick 		for (i = 0; ; ) {
1386671Smckusick 			while (*r == ' ' || *r == '\t' || *r == '\n')
1396671Smckusick 				r++;
1406671Smckusick 			if (*r == 0)
1416671Smckusick 				break;
1426671Smckusick 			i++;
1436671Smckusick 			if (i >= MAXFLD)
1446671Smckusick 				error(FATAL, "record `%.20s...' has too many fields", record);
1456671Smckusick 			if (!(fldtab[i].tval&FLD))
14610794Ssam 				strfree(fldtab[i].sval);
1476671Smckusick 			fldtab[i].sval = fr;
1486671Smckusick 			fldtab[i].tval = FLD | STR;
1496671Smckusick 			do
1506671Smckusick 				*fr++ = *r++;
1516671Smckusick 			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
1526671Smckusick 			*fr++ = 0;
1536671Smckusick 		}
1546671Smckusick 	else if (*r != 0)	/* if 0, it's a null field */
1556671Smckusick 		for (;;) {
1566671Smckusick 			i++;
1576671Smckusick 			if (i >= MAXFLD)
1586671Smckusick 				error(FATAL, "record `%.20s...' has too many fields", record);
1596671Smckusick 			if (!(fldtab[i].tval&FLD))
16010794Ssam 				strfree(fldtab[i].sval);
1616671Smckusick 			fldtab[i].sval = fr;
1626671Smckusick 			fldtab[i].tval = FLD | STR;
1636671Smckusick 			while (*r != sep && *r != '\n' && *r != '\0')	/* \n always a separator */
1646671Smckusick 				*fr++ = *r++;
1656671Smckusick 			*fr++ = 0;
1666671Smckusick 			if (*r++ == 0)
1676671Smckusick 				break;
1686671Smckusick 		}
1696671Smckusick 	*fr = 0;
1706671Smckusick 	for (j=MAXFLD-1; j>i; j--) {	/* clean out junk from previous record */
1716671Smckusick 		if (!(fldtab[j].tval&FLD))
17210794Ssam 			strfree(fldtab[j].sval);
1736671Smckusick 		fldtab[j].tval = STR | FLD;
17410794Ssam 		fldtab[j].sval = EMPTY;
1756671Smckusick 	}
1766671Smckusick 	maxfld = i;
1776671Smckusick 	donefld = 1;
1786671Smckusick 	for(i=1; i<=maxfld; i++)
1796671Smckusick 		if(isnumber(fldtab[i].sval)) {
1806671Smckusick 			fldtab[i].fval = atof(fldtab[i].sval);
1816671Smckusick 			fldtab[i].tval |= NUM;
1826671Smckusick 		}
1836671Smckusick 	setfval(lookup("NF", symtab, 0), (awkfloat) maxfld);
1846671Smckusick 	if (dbg)
1856671Smckusick 		for (i = 0; i <= maxfld; i++)
1866671Smckusick 			printf("field %d: |%s|\n", i, fldtab[i].sval);
1876671Smckusick }
1886671Smckusick 
1896671Smckusick recbld()
1906671Smckusick {
1916671Smckusick 	int i;
1926671Smckusick 	register char *r, *p;
1936671Smckusick 
1946671Smckusick 	if (donefld == 0 || donerec == 1)
1956671Smckusick 		return;
1966671Smckusick 	r = record;
1976671Smckusick 	for (i = 1; i <= *NF; i++) {
1986671Smckusick 		p = getsval(&fldtab[i]);
1996671Smckusick 		while (*r++ = *p++)
2006671Smckusick 			;
2016671Smckusick 		*(r-1) = **OFS;
2026671Smckusick 	}
2036671Smckusick 	*(r-1) = '\0';
2046671Smckusick 	dprintf("in recbld FS=%o, recloc=%o\n", **FS, recloc, NULL);
2056671Smckusick 	recloc->tval = STR | FLD;
2066671Smckusick 	dprintf("in recbld FS=%o, recloc=%o\n", **FS, recloc, NULL);
2076671Smckusick 	if (r > record+RECSIZE)
2086671Smckusick 		error(FATAL, "built giant record `%.20s...'", record);
2096671Smckusick 	dprintf("recbld = |%s|\n", record, NULL, NULL);
2106671Smckusick }
2116671Smckusick 
2126671Smckusick cell *fieldadr(n)
2136671Smckusick {
2146671Smckusick 	if (n >= MAXFLD)
2156671Smckusick 		error(FATAL, "trying to access field %d", n);
2166671Smckusick 	return(&fldtab[n]);
2176671Smckusick }
2186671Smckusick 
2196671Smckusick int	errorflag	= 0;
2206671Smckusick 
2216671Smckusick yyerror(s) char *s; {
2226671Smckusick 	fprintf(stderr, "awk: %s near line %d\n", s, lineno);
2236671Smckusick 	errorflag = 2;
2246671Smckusick }
2256671Smckusick 
22646819Sbostic error(isfatal, fmt)
22746819Sbostic 	int isfatal;
22846819Sbostic 	char *fmt;
22946819Sbostic {
23046819Sbostic 	va_list ap;
23146819Sbostic 
23246819Sbostic 	va_start(ap, fmt);
23346819Sbostic 	(void)fprintf(stderr, "awk: ");
23446819Sbostic 	(void)vfprintf(stderr, fmt, ap);
23546819Sbostic 	va_end(ap);
23646819Sbostic 	(void)fprintf(stderr, "\n");
23717190Sralph 	if (NR && *NR > 0)
23846819Sbostic 		(void)fprintf(stderr, " record number %g\n", *NR);
23946819Sbostic 	if (isfatal)
2406671Smckusick 		exit(2);
2416671Smckusick }
2426671Smckusick 
2436671Smckusick PUTS(s) char *s; {
2446671Smckusick 	dprintf("%s\n", s, NULL, NULL);
2456671Smckusick }
2466671Smckusick 
2476671Smckusick #define	MAXEXPON	38	/* maximum exponenet for fp number */
2486671Smckusick 
2496671Smckusick isnumber(s)
2506671Smckusick register char *s;
2516671Smckusick {
2526671Smckusick 	register d1, d2;
2536671Smckusick 	int point;
2546671Smckusick 	char *es;
2556671Smckusick 
25610794Ssam 	if (s == NULL)
25710794Ssam 		return (0);
2586671Smckusick 	d1 = d2 = point = 0;
2596671Smckusick 	while (*s == ' ' || *s == '\t' || *s == '\n')
2606671Smckusick 		s++;
2616671Smckusick 	if (*s == '\0')
2626671Smckusick 		return(0);	/* empty stuff isn't number */
2636671Smckusick 	if (*s == '+' || *s == '-')
2646671Smckusick 		s++;
2656671Smckusick 	if (!isdigit(*s) && *s != '.')
2666671Smckusick 		return(0);
2676671Smckusick 	if (isdigit(*s)) {
2686671Smckusick 		do {
2696671Smckusick 			d1++;
2706671Smckusick 			s++;
2716671Smckusick 		} while (isdigit(*s));
2726671Smckusick 	}
2736671Smckusick 	if(d1 >= MAXEXPON)
2746671Smckusick 		return(0);	/* too many digits to convert */
2756671Smckusick 	if (*s == '.') {
2766671Smckusick 		point++;
2776671Smckusick 		s++;
2786671Smckusick 	}
2796671Smckusick 	if (isdigit(*s)) {
2806671Smckusick 		d2++;
2816671Smckusick 		do {
2826671Smckusick 			s++;
2836671Smckusick 		} while (isdigit(*s));
2846671Smckusick 	}
2856671Smckusick 	if (!(d1 || point && d2))
2866671Smckusick 		return(0);
2876671Smckusick 	if (*s == 'e' || *s == 'E') {
2886671Smckusick 		s++;
2896671Smckusick 		if (*s == '+' || *s == '-')
2906671Smckusick 			s++;
2916671Smckusick 		if (!isdigit(*s))
2926671Smckusick 			return(0);
2936671Smckusick 		es = s;
2946671Smckusick 		do {
2956671Smckusick 			s++;
2966671Smckusick 		} while (isdigit(*s));
2976671Smckusick 		if (s - es > 2)
2986671Smckusick 			return(0);
2996671Smckusick 		else if (s - es == 2 && 10 * (*es-'0') + *(es+1)-'0' >= MAXEXPON)
3006671Smckusick 			return(0);
3016671Smckusick 	}
3026671Smckusick 	while (*s == ' ' || *s == '\t' || *s == '\n')
3036671Smckusick 		s++;
3046671Smckusick 	if (*s == '\0')
3056671Smckusick 		return(1);
3066671Smckusick 	else
3076671Smckusick 		return(0);
3086671Smckusick }
3096671Smckusick /*
3106671Smckusick isnumber(s) char *s; {return(0);}
3116671Smckusick */
312