main.c revision 1.16
1/*	$NetBSD: main.c,v 1.16 2004/07/13 12:11:06 wiz Exp $	*/
2
3/*-
4 * Copyright (c) 1992, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Diomidis Spinellis of Imperial College, University of London.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35/*-
36 * Copyright (c) 1992 Diomidis Spinellis.
37 *
38 * This code is derived from software contributed to Berkeley by
39 * Diomidis Spinellis of Imperial College, University of London.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 *    notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 *    notice, this list of conditions and the following disclaimer in the
48 *    documentation and/or other materials provided with the distribution.
49 * 3. All advertising materials mentioning features or use of this software
50 *    must display the following acknowledgement:
51 *	This product includes software developed by the University of
52 *	California, Berkeley and its contributors.
53 * 4. Neither the name of the University nor the names of its contributors
54 *    may be used to endorse or promote products derived from this software
55 *    without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67 * SUCH DAMAGE.
68 */
69
70#include <sys/cdefs.h>
71#ifndef lint
72__COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\
73	The Regents of the University of California.  All rights reserved.\n");
74#endif /* not lint */
75
76#ifndef lint
77#if 0
78static char sccsid[] = "@(#)main.c	8.2 (Berkeley) 1/3/94";
79#else
80__RCSID("$NetBSD: main.c,v 1.16 2004/07/13 12:11:06 wiz Exp $");
81#endif
82#endif /* not lint */
83
84#include <sys/types.h>
85
86#include <ctype.h>
87#include <errno.h>
88#include <fcntl.h>
89#include <regex.h>
90#include <stddef.h>
91#include <stdio.h>
92#include <stdlib.h>
93#include <string.h>
94#include <unistd.h>
95
96#include "defs.h"
97#include "extern.h"
98
99/*
100 * Linked list of units (strings and files) to be compiled
101 */
102struct s_compunit {
103	struct s_compunit *next;
104	enum e_cut {CU_FILE, CU_STRING} type;
105	char *s;			/* Pointer to string or fname */
106};
107
108/*
109 * Linked list pointer to compilation units and pointer to current
110 * next pointer.
111 */
112static struct s_compunit *script, **cu_nextp = &script;
113
114/*
115 * Linked list of files to be processed
116 */
117struct s_flist {
118	char *fname;
119	struct s_flist *next;
120};
121
122/*
123 * Linked list pointer to files and pointer to current
124 * next pointer.
125 */
126static struct s_flist *files, **fl_nextp = &files;
127
128int aflag, eflag, nflag, ere;
129
130/*
131 * Current file and line number; line numbers restart across compilation
132 * units, but span across input files.
133 */
134char *fname;			/* File name. */
135u_long linenum;
136int lastline;			/* TRUE on the last line of the last file */
137
138static void add_compunit(enum e_cut, char *);
139static void add_file(char *);
140int	main(int, char **);
141
142int
143main(int argc, char *argv[])
144{
145	int c, fflag;
146
147	setprogname(*argv);
148	fflag = 0;
149	while ((c = getopt(argc, argv, "ae:f:nE")) != -1)
150		switch (c) {
151		case 'a':
152			aflag = 1;
153			break;
154		case 'e':
155			eflag = 1;
156			add_compunit(CU_STRING, optarg);
157			break;
158		case 'f':
159			fflag = 1;
160			add_compunit(CU_FILE, optarg);
161			break;
162		case 'n':
163			nflag = 1;
164			break;
165		case 'E':
166			ere = REG_EXTENDED;
167			break;
168		default:
169		case '?':
170			(void)fprintf(stderr,
171"usage:\t%s [-aEn] script [file ...]\n\t%s [-aEn] [-e script] ... [-f script_file] ... [file ...]\n",
172			    getprogname(), getprogname());
173			exit(1);
174		}
175	argc -= optind;
176	argv += optind;
177
178	/* First usage case; script is the first arg */
179	if (!eflag && !fflag && *argv) {
180		add_compunit(CU_STRING, *argv);
181		argv++;
182	}
183
184	compile();
185
186	/* Continue with first and start second usage */
187	if (*argv)
188		for (; *argv; argv++)
189			add_file(*argv);
190	else
191		add_file(NULL);
192	process();
193	cfclose(prog, NULL);
194	if (fclose(stdout))
195		err(FATAL, "stdout: %s", strerror(errno));
196	exit (0);
197}
198
199/*
200 * Like fgets, but go through the chain of compilation units chaining them
201 * together.  Empty strings and files are ignored.
202 */
203char *
204cu_fgets(char *buf, int n)
205{
206	static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
207	static FILE *f;		/* Current open file */
208	static char *s;		/* Current pointer inside string */
209	static char string_ident[30];
210	char *p;
211
212again:
213	switch (state) {
214	case ST_EOF:
215		if (script == NULL)
216			return (NULL);
217		linenum = 0;
218		switch (script->type) {
219		case CU_FILE:
220			if ((f = fopen(script->s, "r")) == NULL)
221				err(FATAL,
222				    "%s: %s", script->s, strerror(errno));
223			fname = script->s;
224			state = ST_FILE;
225			goto again;
226		case CU_STRING:
227			if ((snprintf(string_ident,
228			    sizeof(string_ident), "\"%s\"", script->s)) >=
229			    sizeof(string_ident) - 1)
230				(void)strcpy(string_ident +
231				    sizeof(string_ident) - 6, " ...\"");
232			fname = string_ident;
233			s = script->s;
234			state = ST_STRING;
235			goto again;
236		}
237	case ST_FILE:
238		if ((p = fgets(buf, n, f)) != NULL) {
239			linenum++;
240			if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
241				nflag = 1;
242			return (p);
243		}
244		script = script->next;
245		(void)fclose(f);
246		state = ST_EOF;
247		goto again;
248	case ST_STRING:
249		if (linenum == 0 && s[0] == '#' && s[1] == 'n')
250			nflag = 1;
251		p = buf;
252		for (;;) {
253			if (n-- <= 1) {
254				*p = '\0';
255				linenum++;
256				return (buf);
257			}
258			switch (*s) {
259			case '\0':
260				state = ST_EOF;
261				if (s == script->s) {
262					script = script->next;
263					goto again;
264				} else {
265					script = script->next;
266					*p = '\0';
267					linenum++;
268					return (buf);
269				}
270			case '\n':
271				*p++ = '\n';
272				*p = '\0';
273				s++;
274				linenum++;
275				return (buf);
276			default:
277				*p++ = *s++;
278			}
279		}
280	}
281	/* NOTREACHED */
282	return (NULL);
283}
284
285/*
286 * Like fgets, but go through the list of files chaining them together.
287 * Set len to the length of the line.
288 */
289int
290mf_fgets(SPACE *sp, enum e_spflag spflag)
291{
292	static FILE *f;		/* Current open file */
293	size_t len;
294	char *p;
295	int c;
296
297	if (f == NULL)
298		/* Advance to first non-empty file */
299		for (;;) {
300			if (files == NULL) {
301				lastline = 1;
302				return (0);
303			}
304			if (files->fname == NULL) {
305				f = stdin;
306				fname = "stdin";
307			} else {
308				fname = files->fname;
309				if ((f = fopen(fname, "r")) == NULL)
310					err(FATAL, "%s: %s",
311					    fname, strerror(errno));
312			}
313			if ((c = getc(f)) != EOF) {
314				(void)ungetc(c, f);
315				break;
316			}
317			(void)fclose(f);
318			files = files->next;
319		}
320
321	if (lastline) {
322		sp->len = 0;
323		return (0);
324	}
325
326	/*
327	 * Use fgetln so that we can handle essentially infinite input data.
328	 * Can't use the pointer into the stdio buffer as the process space
329	 * because the ungetc() can cause it to move.
330	 */
331	p = fgetln(f, &len);
332	if (ferror(f))
333		err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO));
334	cspace(sp, p, len, spflag);
335
336	linenum++;
337	/* Advance to next non-empty file */
338	while ((c = getc(f)) == EOF) {
339		(void)fclose(f);
340		files = files->next;
341		if (files == NULL) {
342			lastline = 1;
343			return (1);
344		}
345		if (files->fname == NULL) {
346			f = stdin;
347			fname = "stdin";
348		} else {
349			fname = files->fname;
350			if ((f = fopen(fname, "r")) == NULL)
351				err(FATAL, "%s: %s", fname, strerror(errno));
352		}
353	}
354	(void)ungetc(c, f);
355	return (1);
356}
357
358/*
359 * Add a compilation unit to the linked list
360 */
361static void
362add_compunit(enum e_cut type, char *s)
363{
364	struct s_compunit *cu;
365
366	cu = xmalloc(sizeof(struct s_compunit));
367	cu->type = type;
368	cu->s = s;
369	cu->next = NULL;
370	*cu_nextp = cu;
371	cu_nextp = &cu->next;
372}
373
374/*
375 * Add a file to the linked list
376 */
377static void
378add_file(char *s)
379{
380	struct s_flist *fp;
381
382	fp = xmalloc(sizeof(struct s_flist));
383	fp->next = NULL;
384	*fl_nextp = fp;
385	fp->fname = s;
386	fl_nextp = &fp->next;
387}
388