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