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