main.c revision 1.19
1/*	$NetBSD: main.c,v 1.19 2008/09/16 13:32:04 perry 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.19 2008/09/16 13:32:04 perry 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:nrE")) != -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 'r':
170		case 'E':
171			ere = REG_EXTENDED;
172			break;
173		default:
174		case '?':
175			(void)fprintf(stderr,
176"usage:\t%s [-aEnr] script [file ...]\n\t%s [-aEnr] [-e script] ... [-f script_file] ... [file ...]\n",
177			    getprogname(), getprogname());
178			exit(1);
179		}
180	argc -= optind;
181	argv += optind;
182
183	/* First usage case; script is the first arg */
184	if (!eflag && !fflag && *argv) {
185		add_compunit(CU_STRING, *argv);
186		argv++;
187	}
188
189	compile();
190
191	/* Continue with first and start second usage */
192	if (*argv)
193		for (; *argv; argv++)
194			add_file(*argv);
195	else
196		add_file(NULL);
197	process();
198	cfclose(prog, NULL);
199	if (fclose(stdout))
200		err(FATAL, "stdout: %s", strerror(errno));
201	exit (0);
202}
203
204/*
205 * Like fgets, but go through the chain of compilation units chaining them
206 * together.  Empty strings and files are ignored.
207 */
208char *
209cu_fgets(char *buf, int n)
210{
211	static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
212	static FILE *f;		/* Current open file */
213	static char *s;		/* Current pointer inside string */
214	static char string_ident[30];
215	char *p;
216
217again:
218	switch (state) {
219	case ST_EOF:
220		if (script == NULL)
221			return (NULL);
222		linenum = 0;
223		switch (script->type) {
224		case CU_FILE:
225			if ((f = fopen(script->s, "r")) == NULL)
226				err(FATAL,
227				    "%s: %s", script->s, strerror(errno));
228			fname = script->s;
229			state = ST_FILE;
230			goto again;
231		case CU_STRING:
232			if ((snprintf(string_ident,
233			    sizeof(string_ident), "\"%s\"", script->s)) >=
234			    sizeof(string_ident) - 1)
235				(void)strcpy(string_ident +
236				    sizeof(string_ident) - 6, " ...\"");
237			fname = string_ident;
238			s = script->s;
239			state = ST_STRING;
240			goto again;
241		}
242	case ST_FILE:
243		if ((p = fgets(buf, n, f)) != NULL) {
244			linenum++;
245			if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
246				nflag = 1;
247			return (p);
248		}
249		script = script->next;
250		(void)fclose(f);
251		state = ST_EOF;
252		goto again;
253	case ST_STRING:
254		if (linenum == 0 && s[0] == '#' && s[1] == 'n')
255			nflag = 1;
256		p = buf;
257		for (;;) {
258			if (n-- <= 1) {
259				*p = '\0';
260				linenum++;
261				return (buf);
262			}
263			switch (*s) {
264			case '\0':
265				state = ST_EOF;
266				if (s == script->s) {
267					script = script->next;
268					goto again;
269				} else {
270					script = script->next;
271					*p = '\0';
272					linenum++;
273					return (buf);
274				}
275			case '\n':
276				*p++ = '\n';
277				*p = '\0';
278				s++;
279				linenum++;
280				return (buf);
281			default:
282				*p++ = *s++;
283			}
284		}
285	}
286	/* NOTREACHED */
287	return (NULL);
288}
289
290/*
291 * Like fgets, but go through the list of files chaining them together.
292 * Set len to the length of the line.
293 */
294int
295mf_fgets(SPACE *sp, enum e_spflag spflag)
296{
297	static FILE *f;		/* Current open file */
298	size_t len;
299	char *p;
300	int c;
301
302	if (f == NULL)
303		/* Advance to first non-empty file */
304		for (;;) {
305			if (files == NULL) {
306				lastline = 1;
307				return (0);
308			}
309			if (files->fname == NULL) {
310				f = stdin;
311				fname = "stdin";
312			} else {
313				fname = files->fname;
314				if ((f = fopen(fname, "r")) == NULL)
315					err(FATAL, "%s: %s",
316					    fname, strerror(errno));
317			}
318			if ((c = getc(f)) != EOF) {
319				(void)ungetc(c, f);
320				break;
321			}
322			(void)fclose(f);
323			files = files->next;
324		}
325
326	if (lastline) {
327		sp->len = 0;
328		return (0);
329	}
330
331	/*
332	 * Use fgetln so that we can handle essentially infinite input data.
333	 * Can't use the pointer into the stdio buffer as the process space
334	 * because the ungetc() can cause it to move.
335	 */
336	p = fgetln(f, &len);
337	if (ferror(f))
338		err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO));
339	cspace(sp, p, len, spflag);
340
341	linenum++;
342	/* Advance to next non-empty file */
343	while ((c = getc(f)) == EOF) {
344		(void)fclose(f);
345		files = files->next;
346		if (files == NULL) {
347			lastline = 1;
348			return (1);
349		}
350		if (files->fname == NULL) {
351			f = stdin;
352			fname = "stdin";
353		} else {
354			fname = files->fname;
355			if ((f = fopen(fname, "r")) == NULL)
356				err(FATAL, "%s: %s", fname, strerror(errno));
357		}
358	}
359	(void)ungetc(c, f);
360	return (1);
361}
362
363/*
364 * Add a compilation unit to the linked list
365 */
366static void
367add_compunit(enum e_cut type, char *s)
368{
369	struct s_compunit *cu;
370
371	cu = xmalloc(sizeof(struct s_compunit));
372	cu->type = type;
373	cu->s = s;
374	cu->next = NULL;
375	*cu_nextp = cu;
376	cu_nextp = &cu->next;
377}
378
379/*
380 * Add a file to the linked list
381 */
382static void
383add_file(char *s)
384{
385	struct s_flist *fp;
386
387	fp = xmalloc(sizeof(struct s_flist));
388	fp->next = NULL;
389	*fl_nextp = fp;
390	fp->fname = s;
391	fl_nextp = &fp->next;
392}
393