xref: /original-bsd/old/awk/lib.c (revision b366b3c1)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)lib.c	4.11 (Berkeley) 05/26/93";
10 #endif /* not lint */
11 
12 #ifdef __STDC__
13 #include <stdarg.h>
14 #else
15 #include <varargs.h>
16 #endif
17 #include "stdio.h"
18 #include "awk.def"
19 #include "awk.h"
20 #include "ctype.h"
21 
22 int	error __P((int, const char *, ...));
23 
24 extern FILE	*yyin;	/* lex input file */
25 extern char	*lexprog;	/* points to program argument if it exists */
26 FILE	*infile	= NULL;
27 char	*file;
28 #define	RECSIZE	(5 * 512)
29 char	record[RECSIZE];
30 char	fields[RECSIZE];
31 char	EMPTY[] = "";
32 
33 #define	MAXFLD	100
34 int	donefld;	/* 1 = implies rec broken into fields */
35 int	donerec;	/* 1 = record is valid (no flds have changed) */
36 int	mustfld;	/* 1 = NF seen, so always break*/
37 
38 #define	FINIT	{EMPTY, EMPTY, 0.0, FLD|STR}
39 cell fldtab[MAXFLD] = {	/*room for fields */
40 	{ "$record", record, 0.0, STR|FLD},
41 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
42 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
43 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
44 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
45 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
46 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
47 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
48 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
49 	FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
50 };
51 int	maxfld	= 0;	/* last used field */
52 
53 
54 getrec()
55 {
56 	register char *rr;
57 	extern int svargc;
58 	extern char **svargv;
59 	register c, sep;
60 
61 	dprintf("**RS=%o, **FS=%o\n", **RS, **FS, NULL);
62 	donefld = 0;
63 	donerec = 1;
64 	record[0] = 0;
65 	while (svargc > 0) {
66 		dprintf("svargc=%d, *svargv=%s\n", svargc, *svargv, NULL);
67 		if (infile == NULL) {	/* have to open a new file */
68 			if (member('=', *svargv)) {	/* it's a var=value argument */
69 				setclvar(*svargv);
70 				svargv++;
71 				svargc--;
72 				continue;
73 			}
74 			*FILENAME = file = *svargv;
75 			dprintf("opening file %s\n", file, NULL, NULL);
76 			if (*file == '-') {
77 				if (yyin == stdin && ! lexprog)
78 					error(FATAL, "standard input already used for reading commands");
79 				else
80 					infile = stdin;
81 			}
82 			else if ((infile = fopen(file, "r")) == NULL)
83 				error(FATAL, "can't open %s", file);
84 		}
85 		if ((sep = **RS) == 0)
86 			sep = '\n';
87 		for (rr = record; ; ) {
88 			for (; (c=getc(infile)) != sep && c != EOF; *rr++ = c)
89 				;
90 			if (**RS == sep || c == EOF)
91 				break;
92 			if ((c = getc(infile)) == '\n' || c == EOF)	/* 2 in a row */
93 				break;
94 			*rr++ = '\n';
95 			*rr++ = c;
96 		}
97 		if (rr > record+RECSIZE)
98 			error(FATAL, "record `%.20s...' too long", record);
99 		*rr = 0;
100 		if (mustfld)
101 			fldbld();
102 		if (c != EOF || rr > record) {	/* normal record */
103 			recloc->tval &= ~NUM;
104 			recloc->tval |= STR;
105 			++nrloc->fval;
106 			nrloc->tval &= ~STR;
107 			nrloc->tval |= NUM;
108 			return(1);
109 		}
110 		/* EOF arrived on this file; set up next */
111 		if (infile != stdin)
112 			fclose(infile);
113 		infile = NULL;
114 		svargc--;
115 		svargv++;
116 	}
117 	return(0);	/* true end of file */
118 }
119 
120 setclvar(s)	/* set var=value from s */
121 char *s;
122 {
123 	char *p;
124 	cell *q;
125 
126 	for (p=s; *p != '='; p++)
127 		;
128 	*p++ = 0;
129 	q = setsymtab(s, tostring(p), 0.0, STR, symtab);
130 	setsval(q, p);
131 	dprintf("command line set %s to |%s|\n", s, p, NULL);
132 }
133 
134 fldbld()
135 {
136 	register char *r, *fr, sep;
137 	int i, j;
138 
139 	r = record;
140 	fr = fields;
141 	i = 0;	/* number of fields accumulated here */
142 	if ((sep = **FS) == ' ')
143 		for (i = 0; ; ) {
144 			while (*r == ' ' || *r == '\t' || *r == '\n')
145 				r++;
146 			if (*r == 0)
147 				break;
148 			i++;
149 			if (i >= MAXFLD)
150 				error(FATAL, "record `%.20s...' has too many fields", record);
151 			if (!(fldtab[i].tval&FLD))
152 				strfree(fldtab[i].sval);
153 			fldtab[i].sval = fr;
154 			fldtab[i].tval = FLD | STR;
155 			do
156 				*fr++ = *r++;
157 			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
158 			*fr++ = 0;
159 		}
160 	else if (*r != 0)	/* if 0, it's a null field */
161 		for (;;) {
162 			i++;
163 			if (i >= MAXFLD)
164 				error(FATAL, "record `%.20s...' has too many fields", record);
165 			if (!(fldtab[i].tval&FLD))
166 				strfree(fldtab[i].sval);
167 			fldtab[i].sval = fr;
168 			fldtab[i].tval = FLD | STR;
169 			while (*r != sep && *r != '\n' && *r != '\0')	/* \n always a separator */
170 				*fr++ = *r++;
171 			*fr++ = 0;
172 			if (*r++ == 0)
173 				break;
174 		}
175 	*fr = 0;
176 	for (j=MAXFLD-1; j>i; j--) {	/* clean out junk from previous record */
177 		if (!(fldtab[j].tval&FLD))
178 			strfree(fldtab[j].sval);
179 		fldtab[j].tval = STR | FLD;
180 		fldtab[j].sval = EMPTY;
181 	}
182 	maxfld = i;
183 	donefld = 1;
184 	for(i=1; i<=maxfld; i++)
185 		if(isanumber(fldtab[i].sval)) {
186 			fldtab[i].fval = atof(fldtab[i].sval);
187 			fldtab[i].tval |= NUM;
188 		}
189 	setfval(lookup("NF", symtab, 0), (awkfloat) maxfld);
190 	if (dbg)
191 		for (i = 0; i <= maxfld; i++)
192 			printf("field %d: |%s|\n", i, fldtab[i].sval);
193 }
194 
195 recbld()
196 {
197 	int i;
198 	register char *r, *p;
199 
200 	if (donefld == 0 || donerec == 1)
201 		return;
202 	r = record;
203 	for (i = 1; i <= *NF; i++) {
204 		p = getsval(&fldtab[i]);
205 		while (*r++ = *p++)
206 			;
207 		*(r-1) = **OFS;
208 	}
209 	*(r-1) = '\0';
210 	dprintf("in recbld FS=%o, recloc=%o\n", **FS, recloc, NULL);
211 	recloc->tval = STR | FLD;
212 	dprintf("in recbld FS=%o, recloc=%o\n", **FS, recloc, NULL);
213 	if (r > record+RECSIZE)
214 		error(FATAL, "built giant record `%.20s...'", record);
215 	dprintf("recbld = |%s|\n", record, NULL, NULL);
216 }
217 
218 cell *fieldadr(n)
219 {
220 	if (n >= MAXFLD)
221 		error(FATAL, "trying to access field %d", n);
222 	return(&fldtab[n]);
223 }
224 
225 int	errorflag	= 0;
226 
227 yyerror(s) char *s; {
228 	fprintf(stderr, "awk: %s near line %d\n", s, lineno);
229 	errorflag = 2;
230 }
231 
232 int
233 #ifdef __STDC__
234 error(int isfatal, const char *fmt, ...)
235 #else
236 error(isfatal, fmt, va_alist)
237 	int isfatal;
238 	char *fmt;
239 	va_dcl
240 #endif
241 {
242 	va_list ap;
243 
244 #ifdef __STDC__
245 	va_start(ap, fmt);
246 #else
247 	va_start(ap);
248 #endif
249 	(void)fprintf(stderr, "awk: ");
250 	(void)vfprintf(stderr, fmt, ap);
251 	va_end(ap);
252 	(void)fprintf(stderr, "\n");
253 	if (NR && *NR > 0)
254 		(void)fprintf(stderr, " record number %g\n", *NR);
255 	if (isfatal)
256 		exit(2);
257 }
258 
259 PUTS(s) char *s; {
260 	dprintf("%s\n", s, NULL, NULL);
261 }
262 
263 #define	MAXEXPON	38	/* maximum exponenet for fp number */
264 
265 isanumber(s)
266 register char *s;
267 {
268 	register d1, d2;
269 	int point;
270 	char *es;
271 
272 	if (s == NULL)
273 		return (0);
274 	d1 = d2 = point = 0;
275 	while (*s == ' ' || *s == '\t' || *s == '\n')
276 		s++;
277 	if (*s == '\0')
278 		return(0);	/* empty stuff isn't number */
279 	if (*s == '+' || *s == '-')
280 		s++;
281 	if (!isdigit(*s) && *s != '.')
282 		return(0);
283 	if (isdigit(*s)) {
284 		do {
285 			d1++;
286 			s++;
287 		} while (isdigit(*s));
288 	}
289 	if(d1 >= MAXEXPON)
290 		return(0);	/* too many digits to convert */
291 	if (*s == '.') {
292 		point++;
293 		s++;
294 	}
295 	if (isdigit(*s)) {
296 		d2++;
297 		do {
298 			s++;
299 		} while (isdigit(*s));
300 	}
301 	if (!(d1 || point && d2))
302 		return(0);
303 	if (*s == 'e' || *s == 'E') {
304 		s++;
305 		if (*s == '+' || *s == '-')
306 			s++;
307 		if (!isdigit(*s))
308 			return(0);
309 		es = s;
310 		do {
311 			s++;
312 		} while (isdigit(*s));
313 		if (s - es > 2)
314 			return(0);
315 		else if (s - es == 2 && 10 * (*es-'0') + *(es+1)-'0' >= MAXEXPON)
316 			return(0);
317 	}
318 	while (*s == ' ' || *s == '\t' || *s == '\n')
319 		s++;
320 	if (*s == '\0')
321 		return(1);
322 	else
323 		return(0);
324 }
325 /*
326 isanumber(s) char *s; {return(0);}
327 */
328