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