No empty .Rs/.Re
[netbsd-mini2440.git] / usr.bin / sed / main.c
blob7afb8361c8850d9d93757952c26f0af38ee2da07
1 /* $NetBSD: main.c,v 1.19 2008/09/16 13:32:04 perry Exp $ */
3 /*-
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Diomidis Spinellis of Imperial College, University of London.
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.
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.
35 /*-
36 * Copyright (c) 1992 Diomidis Spinellis.
38 * This code is derived from software contributed to Berkeley by
39 * Diomidis Spinellis of Imperial College, University of London.
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.
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.
70 #if HAVE_NBTOOL_CONFIG_H
71 #include "nbtool_config.h"
72 #endif
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 */
80 #ifndef lint
81 #if 0
82 static 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 */
88 #include <sys/types.h>
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>
100 #include "defs.h"
101 #include "extern.h"
104 * Linked list of units (strings and files) to be compiled
106 struct s_compunit {
107 struct s_compunit *next;
108 enum e_cut {CU_FILE, CU_STRING} type;
109 char *s; /* Pointer to string or fname */
113 * Linked list pointer to compilation units and pointer to current
114 * next pointer.
116 static struct s_compunit *script, **cu_nextp = &script;
119 * Linked list of files to be processed
121 struct s_flist {
122 char *fname;
123 struct s_flist *next;
127 * Linked list pointer to files and pointer to current
128 * next pointer.
130 static struct s_flist *files, **fl_nextp = &files;
132 int aflag, eflag, nflag, ere;
135 * Current file and line number; line numbers restart across compilation
136 * units, but span across input files.
138 const char *fname; /* File name. */
139 u_long linenum;
140 int lastline; /* TRUE on the last line of the last file */
142 static void add_compunit(enum e_cut, char *);
143 static void add_file(char *);
144 int main(int, char **);
147 main(int argc, char *argv[])
149 int c, fflag;
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);
180 argc -= optind;
181 argv += optind;
183 /* First usage case; script is the first arg */
184 if (!eflag && !fflag && *argv) {
185 add_compunit(CU_STRING, *argv);
186 argv++;
189 compile();
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);
205 * Like fgets, but go through the chain of compilation units chaining them
206 * together. Empty strings and files are ignored.
208 char *
209 cu_fgets(char *buf, int n)
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;
217 again:
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 (int)(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;
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);
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);
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);
275 case '\n':
276 *p++ = '\n';
277 *p = '\0';
278 s++;
279 linenum++;
280 return (buf);
281 default:
282 *p++ = *s++;
286 /* NOTREACHED */
287 return (NULL);
291 * Like fgets, but go through the list of files chaining them together.
292 * Set len to the length of the line.
295 mf_fgets(SPACE *sp, enum e_spflag spflag)
297 static FILE *f; /* Current open file */
298 size_t len;
299 char *p;
300 int c;
302 if (f == NULL)
303 /* Advance to first non-empty file */
304 for (;;) {
305 if (files == NULL) {
306 lastline = 1;
307 return (0);
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));
318 if ((c = getc(f)) != EOF) {
319 (void)ungetc(c, f);
320 break;
322 (void)fclose(f);
323 files = files->next;
326 if (lastline) {
327 sp->len = 0;
328 return (0);
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.
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);
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);
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));
359 (void)ungetc(c, f);
360 return (1);
364 * Add a compilation unit to the linked list
366 static void
367 add_compunit(enum e_cut type, char *s)
369 struct s_compunit *cu;
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;
380 * Add a file to the linked list
382 static void
383 add_file(char *s)
385 struct s_flist *fp;
387 fp = xmalloc(sizeof(struct s_flist));
388 fp->next = NULL;
389 *fl_nextp = fp;
390 fp->fname = s;
391 fl_nextp = &fp->next;