main.c revision 1.18
1/*	$NetBSD: main.c,v 1.18 2008/07/21 14:19:26 lukem 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#if HAVE_NBTOOL_CONFIG_H
71#include "nbtool_config.h"
72#endif
73
74#include <sys/cdefs.h>
75#ifndef lint
76__COPYRIGHT("@(#) Copyright (c) 1992, 1993\
77 The Regents of the University of California.  All rights reserved.");
78#endif /* not lint */
79
80#ifndef lint
81#if 0
82static char sccsid[] = "@(#)main.c	8.2 (Berkeley) 1/3/94";
83#else
84__RCSID("$NetBSD: main.c,v 1.18 2008/07/21 14:19:26 lukem Exp $");
85#endif
86#endif /* not lint */
87
88#include <sys/types.h>
89
90#include <ctype.h>
91#include <errno.h>
92#include <fcntl.h>
93#include <regex.h>
94#include <stddef.h>
95#include <stdio.h>
96#include <stdlib.h>
97#include <string.h>
98#include <unistd.h>
99
100#include "defs.h"
101#include "extern.h"
102
103/*
104 * Linked list of units (strings and files) to be compiled
105 */
106struct s_compunit {
107	struct s_compunit *next;
108	enum e_cut {CU_FILE, CU_STRING} type;
109	char *s;			/* Pointer to string or fname */
110};
111
112/*
113 * Linked list pointer to compilation units and pointer to current
114 * next pointer.
115 */
116static struct s_compunit *script, **cu_nextp = &script;
117
118/*
119 * Linked list of files to be processed
120 */
121struct s_flist {
122	char *fname;
123	struct s_flist *next;
124};
125
126/*
127 * Linked list pointer to files and pointer to current
128 * next pointer.
129 */
130static struct s_flist *files, **fl_nextp = &files;
131
132int aflag, eflag, nflag, ere;
133
134/*
135 * Current file and line number; line numbers restart across compilation
136 * units, but span across input files.
137 */
138char *fname;			/* File name. */
139u_long linenum;
140int lastline;			/* TRUE on the last line of the last file */
141
142static void add_compunit(enum e_cut, char *);
143static void add_file(char *);
144int	main(int, char **);
145
146int
147main(int argc, char *argv[])
148{
149	int c, fflag;
150
151	setprogname(*argv);
152	fflag = 0;
153	while ((c = getopt(argc, argv, "ae:f:nE")) != -1)
154		switch (c) {
155		case 'a':
156			aflag = 1;
157			break;
158		case 'e':
159			eflag = 1;
160			add_compunit(CU_STRING, optarg);
161			break;
162		case 'f':
163			fflag = 1;
164			add_compunit(CU_FILE, optarg);
165			break;
166		case 'n':
167			nflag = 1;
168			break;
169		case 'E':
170			ere = REG_EXTENDED;
171			break;
172		default:
173		case '?':
174			(void)fprintf(stderr,
175"usage:\t%s [-aEn] script [file ...]\n\t%s [-aEn] [-e script] ... [-f script_file] ... [file ...]\n",
176			    getprogname(), getprogname());
177			exit(1);
178		}
179	argc -= optind;
180	argv += optind;
181
182	/* First usage case; script is the first arg */
183	if (!eflag && !fflag && *argv) {
184		add_compunit(CU_STRING, *argv);
185		argv++;
186	}
187
188	compile();
189
190	/* Continue with first and start second usage */
191	if (*argv)
192		for (; *argv; argv++)
193			add_file(*argv);
194	else
195		add_file(NULL);
196	process();
197	cfclose(prog, NULL);
198	if (fclose(stdout))
199		err(FATAL, "stdout: %s", strerror(errno));
200	exit (0);
201}
202
203/*
204 * Like fgets, but go through the chain of compilation units chaining them
205 * together.  Empty strings and files are ignored.
206 */
207char *
208cu_fgets(char *buf, int n)
209{
210	static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
211	static FILE *f;		/* Current open file */
212	static char *s;		/* Current pointer inside string */
213	static char string_ident[30];
214	char *p;
215
216again:
217	switch (state) {
218	case ST_EOF:
219		if (script == NULL)
220			return (NULL);
221		linenum = 0;
222		switch (script->type) {
223		case CU_FILE:
224			if ((f = fopen(script->s, "r")) == NULL)
225				err(FATAL,
226				    "%s: %s", script->s, strerror(errno));
227			fname = script->s;
228			state = ST_FILE;
229			goto again;
230		case CU_STRING:
231			if ((snprintf(string_ident,
232			    sizeof(string_ident), "\"%s\"", script->s)) >=
233			    sizeof(string_ident) - 1)
234				(void)strcpy(string_ident +
235				    sizeof(string_ident) - 6, " ...\"");
236			fname = string_ident;
237			s = script->s;
238			state = ST_STRING;
239			goto again;
240		}
241	case ST_FILE:
242		if ((p = fgets(buf, n, f)) != NULL) {
243			linenum++;
244			if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
245				nflag = 1;
246			return (p);
247		}
248		script = script->next;
249		(void)fclose(f);
250		state = ST_EOF;
251		goto again;
252	case ST_STRING:
253		if (linenum == 0 && s[0] == '#' && s[1] == 'n')
254			nflag = 1;
255		p = buf;
256		for (;;) {
257			if (n-- <= 1) {
258				*p = '\0';
259				linenum++;
260				return (buf);
261			}
262			switch (*s) {
263			case '\0':
264				state = ST_EOF;
265				if (s == script->s) {
266					script = script->next;
267					goto again;
268				} else {
269					script = script->next;
270					*p = '\0';
271					linenum++;
272					return (buf);
273				}
274			case '\n':
275				*p++ = '\n';
276				*p = '\0';
277				s++;
278				linenum++;
279				return (buf);
280			default:
281				*p++ = *s++;
282			}
283		}
284	}
285	/* NOTREACHED */
286	return (NULL);
287}
288
289/*
290 * Like fgets, but go through the list of files chaining them together.
291 * Set len to the length of the line.
292 */
293int
294mf_fgets(SPACE *sp, enum e_spflag spflag)
295{
296	static FILE *f;		/* Current open file */
297	size_t len;
298	char *p;
299	int c;
300
301	if (f == NULL)
302		/* Advance to first non-empty file */
303		for (;;) {
304			if (files == NULL) {
305				lastline = 1;
306				return (0);
307			}
308			if (files->fname == NULL) {
309				f = stdin;
310				fname = "stdin";
311			} else {
312				fname = files->fname;
313				if ((f = fopen(fname, "r")) == NULL)
314					err(FATAL, "%s: %s",
315					    fname, strerror(errno));
316			}
317			if ((c = getc(f)) != EOF) {
318				(void)ungetc(c, f);
319				break;
320			}
321			(void)fclose(f);
322			files = files->next;
323		}
324
325	if (lastline) {
326		sp->len = 0;
327		return (0);
328	}
329
330	/*
331	 * Use fgetln so that we can handle essentially infinite input data.
332	 * Can't use the pointer into the stdio buffer as the process space
333	 * because the ungetc() can cause it to move.
334	 */
335	p = fgetln(f, &len);
336	if (ferror(f))
337		err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO));
338	cspace(sp, p, len, spflag);
339
340	linenum++;
341	/* Advance to next non-empty file */
342	while ((c = getc(f)) == EOF) {
343		(void)fclose(f);
344		files = files->next;
345		if (files == NULL) {
346			lastline = 1;
347			return (1);
348		}
349		if (files->fname == NULL) {
350			f = stdin;
351			fname = "stdin";
352		} else {
353			fname = files->fname;
354			if ((f = fopen(fname, "r")) == NULL)
355				err(FATAL, "%s: %s", fname, strerror(errno));
356		}
357	}
358	(void)ungetc(c, f);
359	return (1);
360}
361
362/*
363 * Add a compilation unit to the linked list
364 */
365static void
366add_compunit(enum e_cut type, char *s)
367{
368	struct s_compunit *cu;
369
370	cu = xmalloc(sizeof(struct s_compunit));
371	cu->type = type;
372	cu->s = s;
373	cu->next = NULL;
374	*cu_nextp = cu;
375	cu_nextp = &cu->next;
376}
377
378/*
379 * Add a file to the linked list
380 */
381static void
382add_file(char *s)
383{
384	struct s_flist *fp;
385
386	fp = xmalloc(sizeof(struct s_flist));
387	fp->next = NULL;
388	*fl_nextp = fp;
389	fp->fname = s;
390	fl_nextp = &fp->next;
391}
392