xref: /csrg-svn/usr.bin/sed/main.c (revision 55995)
1*55995Sbostic /*-
2*55995Sbostic  * Copyright (c) 1992 Diomidis Spinellis.
3*55995Sbostic  * Copyright (c) 1992 The Regents of the University of California.
4*55995Sbostic  * All rights reserved.
5*55995Sbostic  *
6*55995Sbostic  * This code is derived from software contributed to Berkeley by
7*55995Sbostic  * Diomidis Spinellis of Imperial College, University of London.
8*55995Sbostic  *
9*55995Sbostic  * %sccs.include.redist.c%
10*55995Sbostic  */
11*55995Sbostic 
12*55995Sbostic #ifndef lint
13*55995Sbostic char copyright[] =
14*55995Sbostic "@(#) Copyright (c) 1992 The Regents of the University of California.\n\
15*55995Sbostic  All rights reserved.\n";
16*55995Sbostic #endif /* not lint */
17*55995Sbostic 
18*55995Sbostic #ifndef lint
19*55995Sbostic static char sccsid[] = "@(#)main.c	5.1 (Berkeley) 08/23/92";
20*55995Sbostic #endif /* not lint */
21*55995Sbostic 
22*55995Sbostic #include <sys/types.h>
23*55995Sbostic 
24*55995Sbostic #include <ctype.h>
25*55995Sbostic #include <errno.h>
26*55995Sbostic #include <fcntl.h>
27*55995Sbostic #include <regex.h>
28*55995Sbostic #include <stddef.h>
29*55995Sbostic #include <stdio.h>
30*55995Sbostic #include <stdlib.h>
31*55995Sbostic #include <string.h>
32*55995Sbostic #include <unistd.h>
33*55995Sbostic 
34*55995Sbostic #include "defs.h"
35*55995Sbostic #include "extern.h"
36*55995Sbostic 
37*55995Sbostic /*
38*55995Sbostic  * Linked list of units (strings and files) to be compiled
39*55995Sbostic  */
40*55995Sbostic struct s_compunit {
41*55995Sbostic 	struct s_compunit *next;
42*55995Sbostic 	enum e_cut {CU_FILE, CU_STRING} type;
43*55995Sbostic 	char *s;			/* Pointer to string or fname */
44*55995Sbostic };
45*55995Sbostic 
46*55995Sbostic /*
47*55995Sbostic  * Linked list pointer to compilation units and pointer to current
48*55995Sbostic  * next pointer.
49*55995Sbostic  */
50*55995Sbostic static struct s_compunit *script, **cu_nextp = &script;
51*55995Sbostic 
52*55995Sbostic /*
53*55995Sbostic  * Linked list of files to be processed
54*55995Sbostic  */
55*55995Sbostic struct s_flist {
56*55995Sbostic 	char *fname;
57*55995Sbostic 	struct s_flist *next;
58*55995Sbostic };
59*55995Sbostic 
60*55995Sbostic /*
61*55995Sbostic  * Linked list pointer to files and pointer to current
62*55995Sbostic  * next pointer.
63*55995Sbostic  */
64*55995Sbostic static struct s_flist *files, **fl_nextp = &files;
65*55995Sbostic 
66*55995Sbostic int compile_errors;		/* Compile error count. */
67*55995Sbostic int aflag, eflag, nflag;
68*55995Sbostic 
69*55995Sbostic /*
70*55995Sbostic  * Current file and line number; line numbers restart across compilation
71*55995Sbostic  * units, but span across input files.
72*55995Sbostic  */
73*55995Sbostic char *fname;			/* File name. */
74*55995Sbostic u_long linenum;
75*55995Sbostic int lastline;			/* TRUE on the last line of the last file */
76*55995Sbostic 
77*55995Sbostic static void add_compunit __P((enum e_cut, char *));
78*55995Sbostic static void add_file __P((char *));
79*55995Sbostic 
80*55995Sbostic int
81*55995Sbostic main(argc, argv)
82*55995Sbostic 	int argc;
83*55995Sbostic 	char *argv[];
84*55995Sbostic {
85*55995Sbostic 	int c, fflag;
86*55995Sbostic 
87*55995Sbostic 	fflag = 0;
88*55995Sbostic 	while ((c = getopt(argc, argv, "ae:f:n")) != EOF)
89*55995Sbostic 		switch (c) {
90*55995Sbostic 		case 'a':
91*55995Sbostic 			aflag = 1;
92*55995Sbostic 			break;
93*55995Sbostic 		case 'e':
94*55995Sbostic 			eflag = 1;
95*55995Sbostic 			add_compunit(CU_STRING, optarg);
96*55995Sbostic 			break;
97*55995Sbostic 		case 'f':
98*55995Sbostic 			fflag = 1;
99*55995Sbostic 			add_compunit(CU_FILE, optarg);
100*55995Sbostic 			break;
101*55995Sbostic 		case 'n':
102*55995Sbostic 			nflag = 1;
103*55995Sbostic 			break;
104*55995Sbostic 		default:
105*55995Sbostic 		case '?':
106*55995Sbostic 			(void)fprintf(stderr,
107*55995Sbostic "usage:\tsed script [-an] [file ...]\n\tsed [-an] [-e script] ... [-f scipt_file] ... [file ...]\n");
108*55995Sbostic 			exit(1);
109*55995Sbostic 		}
110*55995Sbostic 	argc -= optind;
111*55995Sbostic 	argv += optind;
112*55995Sbostic 
113*55995Sbostic 	/* First usage case; script is the first arg */
114*55995Sbostic 	if (!eflag && !fflag && *argv) {
115*55995Sbostic 		add_compunit(CU_STRING, *argv);
116*55995Sbostic 		argv++;
117*55995Sbostic 	}
118*55995Sbostic 
119*55995Sbostic 	compile();
120*55995Sbostic 	if (compile_errors)
121*55995Sbostic 		exit(1);
122*55995Sbostic 
123*55995Sbostic 	/* Continue with first and start second usage */
124*55995Sbostic 	if (*argv)
125*55995Sbostic 		for (; *argv; argv++)
126*55995Sbostic 			add_file(*argv);
127*55995Sbostic 	else
128*55995Sbostic 		add_file(NULL);
129*55995Sbostic 	process();
130*55995Sbostic 	cfclose(prog);
131*55995Sbostic 	if (fclose(stdout))
132*55995Sbostic 		err(FATAL, "stdout: %s", strerror(errno));
133*55995Sbostic 	exit (0);
134*55995Sbostic }
135*55995Sbostic 
136*55995Sbostic /*
137*55995Sbostic  * Like fgets, but go through the chain of compilation units chaining them
138*55995Sbostic  * together.  Empty strings and files are ignored.
139*55995Sbostic  */
140*55995Sbostic char *
141*55995Sbostic cu_fgets(buf, n)
142*55995Sbostic 	char *buf;
143*55995Sbostic 	int n;
144*55995Sbostic {
145*55995Sbostic 	static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
146*55995Sbostic 	static FILE *f;		/* Current open file */
147*55995Sbostic 	static char *s;		/* Current pointer inside string */
148*55995Sbostic 	static char string_ident[20];
149*55995Sbostic 	char *p;
150*55995Sbostic 
151*55995Sbostic again:
152*55995Sbostic 	switch (state) {
153*55995Sbostic 	case ST_EOF:
154*55995Sbostic 		if (script == NULL)
155*55995Sbostic 			return (NULL);
156*55995Sbostic 		linenum = 0;
157*55995Sbostic 		switch (script->type) {
158*55995Sbostic 		case CU_FILE:
159*55995Sbostic 			if ((f = fopen(script->s, "r")) == NULL)
160*55995Sbostic 				err(FATAL,
161*55995Sbostic 				    "%s: %s", script->s, strerror(errno));
162*55995Sbostic 			fname = script->s;
163*55995Sbostic 			state = ST_FILE;
164*55995Sbostic 			goto again;
165*55995Sbostic 		case CU_STRING:
166*55995Sbostic 			/* Have better handling here */
167*55995Sbostic 			(void)strncpy(string_ident,
168*55995Sbostic 			    script->s, sizeof(string_ident));
169*55995Sbostic 			(void)strcpy(string_ident + sizeof(string_ident) - 5,
170*55995Sbostic 			    "...");
171*55995Sbostic 			fname = string_ident;
172*55995Sbostic 			s = script->s;
173*55995Sbostic 			state = ST_STRING;
174*55995Sbostic 			goto again;
175*55995Sbostic 		}
176*55995Sbostic 	case ST_FILE:
177*55995Sbostic 		if ((p = fgets(buf, n, f)) != NULL) {
178*55995Sbostic 			linenum++;
179*55995Sbostic 			if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
180*55995Sbostic 				nflag = 1;
181*55995Sbostic 			return (p);
182*55995Sbostic 		}
183*55995Sbostic 		script = script->next;
184*55995Sbostic 		(void)fclose(f);
185*55995Sbostic 		state = ST_EOF;
186*55995Sbostic 		goto again;
187*55995Sbostic 	case ST_STRING:
188*55995Sbostic 		if (linenum == 0 && s[0] == '#' && s[1] == 'n')
189*55995Sbostic 			nflag = 1;
190*55995Sbostic 		p = buf;
191*55995Sbostic 		for (;;) {
192*55995Sbostic 			if (n-- <= 1) {
193*55995Sbostic 				*p = '\0';
194*55995Sbostic 				linenum++;
195*55995Sbostic 				return (buf);
196*55995Sbostic 			}
197*55995Sbostic 			switch (*s) {
198*55995Sbostic 			case '\0':
199*55995Sbostic 				state = ST_EOF;
200*55995Sbostic 				if (s == script->s) {
201*55995Sbostic 					script = script->next;
202*55995Sbostic 					goto again;
203*55995Sbostic 				} else {
204*55995Sbostic 					script = script->next;
205*55995Sbostic 					*p = '\0';
206*55995Sbostic 					linenum++;
207*55995Sbostic 					return (buf);
208*55995Sbostic 				}
209*55995Sbostic 			case '\n':
210*55995Sbostic 				*p++ = '\n';
211*55995Sbostic 				*p = '\0';
212*55995Sbostic 				s++;
213*55995Sbostic 				linenum++;
214*55995Sbostic 				return (buf);
215*55995Sbostic 			default:
216*55995Sbostic 				*p++ = *s++;
217*55995Sbostic 			}
218*55995Sbostic 		}
219*55995Sbostic 	}
220*55995Sbostic 	/* NOTREACHED */
221*55995Sbostic }
222*55995Sbostic 
223*55995Sbostic /*
224*55995Sbostic  * Like fgets, but go through the list of files chaining them together.
225*55995Sbostic  * Set len to the length of the line.
226*55995Sbostic  */
227*55995Sbostic char *
228*55995Sbostic mf_fgets(lenp)
229*55995Sbostic 	size_t *lenp;
230*55995Sbostic {
231*55995Sbostic 	static FILE *f;		/* Current open file */
232*55995Sbostic 	char c, *p;
233*55995Sbostic 
234*55995Sbostic 	if (f == NULL)
235*55995Sbostic 		/* Advance to first non-empty file */
236*55995Sbostic 		for (;;) {
237*55995Sbostic 			if (files == NULL) {
238*55995Sbostic 				lastline = 1;
239*55995Sbostic 				return (NULL);
240*55995Sbostic 			}
241*55995Sbostic 			if (files->fname == NULL) {
242*55995Sbostic 				f = stdin;
243*55995Sbostic 				fname = "stdin";
244*55995Sbostic 			} else {
245*55995Sbostic 				fname = files->fname;
246*55995Sbostic 				if ((f = fopen(fname, "r")) == NULL)
247*55995Sbostic 					err(FATAL, "%s: %s",
248*55995Sbostic 					    fname, strerror(errno));
249*55995Sbostic 			}
250*55995Sbostic 			if ((c = getc(f)) != EOF) {
251*55995Sbostic 				(void)ungetc(c, f);
252*55995Sbostic 				break;
253*55995Sbostic 			}
254*55995Sbostic 			(void)fclose(f);
255*55995Sbostic 			files = files->next;
256*55995Sbostic 		}
257*55995Sbostic 
258*55995Sbostic 	if (lastline) {
259*55995Sbostic 		*lenp = 0;
260*55995Sbostic 		return (NULL);
261*55995Sbostic 	}
262*55995Sbostic 
263*55995Sbostic 	p = fgetline(f, lenp);
264*55995Sbostic 	if (ferror(f))
265*55995Sbostic 		err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO));
266*55995Sbostic 
267*55995Sbostic 	linenum++;
268*55995Sbostic 	/* Advance to next non-empty file */
269*55995Sbostic 	while ((c = getc(f)) == EOF) {
270*55995Sbostic 		(void)fclose(f);
271*55995Sbostic 		files = files->next;
272*55995Sbostic 		if (files == NULL) {
273*55995Sbostic 			lastline = 1;
274*55995Sbostic 			return (p);
275*55995Sbostic 		}
276*55995Sbostic 		if (files->fname == NULL) {
277*55995Sbostic 			f = stdin;
278*55995Sbostic 			fname = "stdin";
279*55995Sbostic 		} else {
280*55995Sbostic 			fname = files->fname;
281*55995Sbostic 			if ((f = fopen(fname, "r")) == NULL)
282*55995Sbostic 				err(FATAL, "%s: %s", fname, strerror(errno));
283*55995Sbostic 		}
284*55995Sbostic 	}
285*55995Sbostic 	(void)ungetc(c, f);
286*55995Sbostic 	return (p);
287*55995Sbostic }
288*55995Sbostic 
289*55995Sbostic /*
290*55995Sbostic  * Add a compilation unit to the linked list
291*55995Sbostic  */
292*55995Sbostic static void
293*55995Sbostic add_compunit(type, s)
294*55995Sbostic 	enum e_cut type;
295*55995Sbostic 	char *s;
296*55995Sbostic {
297*55995Sbostic 	struct s_compunit *cu;
298*55995Sbostic 
299*55995Sbostic 	cu = xmalloc(sizeof(struct s_compunit));
300*55995Sbostic 	cu->type = type;
301*55995Sbostic 	cu->s = s;
302*55995Sbostic 	cu->next = NULL;
303*55995Sbostic 	*cu_nextp = cu;
304*55995Sbostic 	cu_nextp = &cu->next;
305*55995Sbostic }
306*55995Sbostic 
307*55995Sbostic /*
308*55995Sbostic  * Add a file to the linked list
309*55995Sbostic  */
310*55995Sbostic static void
311*55995Sbostic add_file(s)
312*55995Sbostic 	char *s;
313*55995Sbostic {
314*55995Sbostic 	struct s_flist *fp;
315*55995Sbostic 
316*55995Sbostic 	fp = xmalloc(sizeof(struct s_flist));
317*55995Sbostic 	fp->next = NULL;
318*55995Sbostic 	*fl_nextp = fp;
319*55995Sbostic 	fp->fname = s;
320*55995Sbostic 	fl_nextp = &fp->next;
321*55995Sbostic }
322