2 * Copyright (c) 1992 Diomidis Spinellis.
3 * Copyright (c) 1992, 1993
4 * The Regents of the University of California. All rights reserved.
6 * This code is derived from software contributed to Berkeley by
7 * Diomidis Spinellis of Imperial College, University of London.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
42 static const char copyright[] =
43 "@(#) Copyright (c) 1992, 1993\n\
44 The Regents of the University of California. All rights reserved.\n";
48 static const char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94";
51 #include <sys/types.h>
53 #include <sys/param.h>
71 * Linked list of units (strings and files) to be compiled
74 struct s_compunit *next;
75 enum e_cut {CU_FILE, CU_STRING} type;
76 char *s; /* Pointer to string or fname */
80 * Linked list pointer to compilation units and pointer to current
83 static struct s_compunit *script, **cu_nextp = &script;
86 * Linked list of files to be processed
94 * Linked list pointer to files and pointer to current
97 static struct s_flist *files, **fl_nextp = &files;
99 static FILE *curfile; /* Current open file */
101 int aflag, eflag, nflag;
103 static int rval; /* Exit status */
106 * Current file and line number; line numbers restart across compilation
107 * units, but span across input files.
109 const char *fname; /* File name. */
110 const char *inplace; /* Inplace edit file extension. */
113 static void add_compunit(enum e_cut, char *);
114 static void add_file(char *);
115 static int inplace_edit(char **);
116 static void usage(void);
126 (void) setlocale(LC_ALL, "");
131 while ((c = getopt(argc, argv, "Eae:f:i:n")) != -1)
134 rflags = REG_EXTENDED;
141 if ((temp_arg = malloc(strlen(optarg) + 2)) == NULL)
143 strcpy(temp_arg, optarg);
144 strcat(temp_arg, "\n");
145 add_compunit(CU_STRING, temp_arg);
149 add_compunit(CU_FILE, optarg);
164 /* First usage case; script is the first arg */
165 if (!eflag && !fflag && *argv) {
166 add_compunit(CU_STRING, *argv);
172 /* Continue with first and start second usage */
174 for (; *argv; argv++)
188 (void)fprintf(stderr, "%s\n%s\n",
189 "usage: sed script [-Ean] [-i extension] [file ...]",
190 " sed [-an] [-i extension] [-e script] ... [-f script_file] ... [file ...]");
195 * Like fgets, but go through the chain of compilation units chaining them
196 * together. Empty strings and files are ignored.
199 cu_fgets(buf, n, more)
204 static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
205 static FILE *f; /* Current open file */
206 static char *s; /* Current pointer inside string */
207 static char string_ident[30];
213 if (script == NULL) {
219 switch (script->type) {
221 if ((f = fopen(script->s, "r")) == NULL)
222 err(1, "%s", script->s);
227 if ((snprintf(string_ident,
228 sizeof(string_ident), "\"%s\"", script->s)) >=
229 sizeof(string_ident) - 1)
230 (void)strcpy(string_ident +
231 sizeof(string_ident) - 6, " ...\"");
232 fname = string_ident;
238 if ((p = fgets(buf, n, f)) != NULL) {
240 if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
246 script = script->next;
251 if (linenum == 0 && s[0] == '#' && s[1] == 'n')
265 if (s == script->s) {
266 script = script->next;
269 script = script->next;
294 * Like fgets, but go through the list of files chaining them together.
295 * Set len to the length of the line.
300 enum e_spflag spflag;
305 static int firstfile;
307 if (curfile == NULL) {
309 if (files->fname == NULL) {
311 errx(1, "-i may not be used with stdin");
319 if (curfile != NULL && (c = getc(curfile)) != EOF) {
320 (void)ungetc(c, curfile);
323 /* If we are here then either eof or no files are open yet */
324 if (curfile == stdin) {
328 if (curfile != NULL) {
331 if (firstfile == 0) {
339 if (inplace != NULL) {
340 if (inplace_edit(&files->fname) == -1)
343 fname = files->fname;
344 if ((curfile = fopen(fname, "r")) == NULL) {
349 if (inplace != NULL && *inplace == '\0')
353 * We are here only when curfile is open and we still have something
356 * Use fgetln so that we can handle essentially infinite input data.
357 * Can't use the pointer into the stdio buffer as the process space
358 * because the ungetc() can cause it to move.
360 p = fgetln(curfile, &len);
362 errx(1, "%s: %s", fname, strerror(errno ? errno : EIO));
363 if (len != 0 && p[len - 1] == '\n')
365 cspace(sp, p, len, spflag);
373 * Add a compilation unit to the linked list
376 add_compunit(type, s)
380 struct s_compunit *cu;
382 if ((cu = malloc(sizeof(struct s_compunit))) == NULL)
388 cu_nextp = &cu->next;
392 * Add a file to the linked list
400 if ((fp = malloc(sizeof(struct s_flist))) == NULL)
405 fl_nextp = &fp->next;
409 * Modify a pointer to a filename for inplace editing and reopen stdout
412 inplace_edit(filename)
417 char backup[MAXPATHLEN];
420 if (lstat(*filename, &orig) == -1)
422 if ((orig.st_mode & S_IFREG) == 0) {
423 warnx("cannot inplace edit %s, not a regular file", *filename);
427 if (*inplace == '\0') {
428 char template[] = "/tmp/sed.XXXXXXXXXX";
430 output = mkstemp(template);
433 strlcpy(backup, template, MAXPATHLEN);
435 strlcpy(backup, *filename, MAXPATHLEN);
436 strlcat(backup, inplace, MAXPATHLEN);
437 output = open(backup, O_WRONLY | O_CREAT | O_TRUNC);
439 err(1, "open(%s)", backup);
442 input = open(*filename, O_RDONLY);
444 err(1, "open(%s)", *filename);
445 if (fchmod(output, orig.st_mode & ~S_IFMT) == -1)
447 buffer = (char *)mmap(0, orig.st_size, PROT_READ, MAP_SHARED, input, 0);
448 if (buffer == MAP_FAILED)
449 err(1, "mmap(%s)", *filename);
450 if (write(output, buffer, orig.st_size) == -1)
451 err(1, "write(%s)", backup);
452 if (munmap(buffer, orig.st_size) == -1)
453 err(1, "munmap(%s)", *filename);
456 freopen(*filename, "w", stdout);
457 *filename = strdup(backup);
466 if (files->next != NULL)
468 if ((ch = getc(curfile)) == EOF)