xref: /illumos-gate/usr/src/cmd/sed/main.c (revision 84441f85)
1*84441f85SGarrett D'Amore /*
2*84441f85SGarrett D'Amore  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
3*84441f85SGarrett D'Amore  * Copyright (c) 1992 Diomidis Spinellis.
4*84441f85SGarrett D'Amore  * Copyright (c) 1992, 1993
5*84441f85SGarrett D'Amore  *	The Regents of the University of California.  All rights reserved.
6*84441f85SGarrett D'Amore  *
7*84441f85SGarrett D'Amore  * This code is derived from software contributed to Berkeley by
8*84441f85SGarrett D'Amore  * Diomidis Spinellis of Imperial College, University of London.
9*84441f85SGarrett D'Amore  *
10*84441f85SGarrett D'Amore  * Redistribution and use in source and binary forms, with or without
11*84441f85SGarrett D'Amore  * modification, are permitted provided that the following conditions
12*84441f85SGarrett D'Amore  * are met:
13*84441f85SGarrett D'Amore  * 1. Redistributions of source code must retain the above copyright
14*84441f85SGarrett D'Amore  *    notice, this list of conditions and the following disclaimer.
15*84441f85SGarrett D'Amore  * 2. Redistributions in binary form must reproduce the above copyright
16*84441f85SGarrett D'Amore  *    notice, this list of conditions and the following disclaimer in the
17*84441f85SGarrett D'Amore  *    documentation and/or other materials provided with the distribution.
18*84441f85SGarrett D'Amore  * 4. Neither the name of the University nor the names of its contributors
19*84441f85SGarrett D'Amore  *    may be used to endorse or promote products derived from this software
20*84441f85SGarrett D'Amore  *    without specific prior written permission.
21*84441f85SGarrett D'Amore  *
22*84441f85SGarrett D'Amore  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23*84441f85SGarrett D'Amore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24*84441f85SGarrett D'Amore  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25*84441f85SGarrett D'Amore  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26*84441f85SGarrett D'Amore  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27*84441f85SGarrett D'Amore  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28*84441f85SGarrett D'Amore  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29*84441f85SGarrett D'Amore  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30*84441f85SGarrett D'Amore  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31*84441f85SGarrett D'Amore  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*84441f85SGarrett D'Amore  * SUCH DAMAGE.
33*84441f85SGarrett D'Amore  */
34*84441f85SGarrett D'Amore 
35*84441f85SGarrett D'Amore #include <sys/types.h>
36*84441f85SGarrett D'Amore #include <sys/mman.h>
37*84441f85SGarrett D'Amore #include <sys/param.h>
38*84441f85SGarrett D'Amore #include <sys/stat.h>
39*84441f85SGarrett D'Amore 
40*84441f85SGarrett D'Amore #include <err.h>
41*84441f85SGarrett D'Amore #include <errno.h>
42*84441f85SGarrett D'Amore #include <fcntl.h>
43*84441f85SGarrett D'Amore #include <libgen.h>
44*84441f85SGarrett D'Amore #include <limits.h>
45*84441f85SGarrett D'Amore #include <locale.h>
46*84441f85SGarrett D'Amore #include <regex.h>
47*84441f85SGarrett D'Amore #include <stddef.h>
48*84441f85SGarrett D'Amore #include <stdio.h>
49*84441f85SGarrett D'Amore #include <stdlib.h>
50*84441f85SGarrett D'Amore #include <string.h>
51*84441f85SGarrett D'Amore #include <unistd.h>
52*84441f85SGarrett D'Amore #include <libintl.h>
53*84441f85SGarrett D'Amore 
54*84441f85SGarrett D'Amore #include "defs.h"
55*84441f85SGarrett D'Amore #include "extern.h"
56*84441f85SGarrett D'Amore 
57*84441f85SGarrett D'Amore /*
58*84441f85SGarrett D'Amore  * Linked list of units (strings and files) to be compiled
59*84441f85SGarrett D'Amore  */
60*84441f85SGarrett D'Amore struct s_compunit {
61*84441f85SGarrett D'Amore 	struct s_compunit *next;
62*84441f85SGarrett D'Amore 	enum e_cut {CU_FILE, CU_STRING} type;
63*84441f85SGarrett D'Amore 	char *s;			/* Pointer to string or fname */
64*84441f85SGarrett D'Amore };
65*84441f85SGarrett D'Amore 
66*84441f85SGarrett D'Amore /*
67*84441f85SGarrett D'Amore  * Linked list pointer to compilation units and pointer to current
68*84441f85SGarrett D'Amore  * next pointer.
69*84441f85SGarrett D'Amore  */
70*84441f85SGarrett D'Amore static struct s_compunit *script, **cu_nextp = &script;
71*84441f85SGarrett D'Amore 
72*84441f85SGarrett D'Amore /*
73*84441f85SGarrett D'Amore  * Linked list of files to be processed
74*84441f85SGarrett D'Amore  */
75*84441f85SGarrett D'Amore struct s_flist {
76*84441f85SGarrett D'Amore 	char *fname;
77*84441f85SGarrett D'Amore 	struct s_flist *next;
78*84441f85SGarrett D'Amore };
79*84441f85SGarrett D'Amore 
80*84441f85SGarrett D'Amore /*
81*84441f85SGarrett D'Amore  * Linked list pointer to files and pointer to current
82*84441f85SGarrett D'Amore  * next pointer.
83*84441f85SGarrett D'Amore  */
84*84441f85SGarrett D'Amore static struct s_flist *files, **fl_nextp = &files;
85*84441f85SGarrett D'Amore 
86*84441f85SGarrett D'Amore FILE *infile;			/* Current input file */
87*84441f85SGarrett D'Amore FILE *outfile;			/* Current output file */
88*84441f85SGarrett D'Amore 
89*84441f85SGarrett D'Amore int aflag, eflag, nflag;
90*84441f85SGarrett D'Amore int rflags = 0;
91*84441f85SGarrett D'Amore static int rval;		/* Exit status */
92*84441f85SGarrett D'Amore 
93*84441f85SGarrett D'Amore static int ispan;		/* Whether inplace editing spans across files */
94*84441f85SGarrett D'Amore 
95*84441f85SGarrett D'Amore /*
96*84441f85SGarrett D'Amore  * Current file and line number; line numbers restart across compilation
97*84441f85SGarrett D'Amore  * units, but span across input files.  The latter is optional if editing
98*84441f85SGarrett D'Amore  * in place.
99*84441f85SGarrett D'Amore  */
100*84441f85SGarrett D'Amore const char *fname;		/* File name. */
101*84441f85SGarrett D'Amore const char *outfname;		/* Output file name */
102*84441f85SGarrett D'Amore static char oldfname[PATH_MAX];	/* Old file name (for in-place editing) */
103*84441f85SGarrett D'Amore static char tmpfname[PATH_MAX];	/* Temporary file name (for in-place editing) */
104*84441f85SGarrett D'Amore static const char *inplace;	/* Inplace edit file extension. */
105*84441f85SGarrett D'Amore ulong_t linenum;
106*84441f85SGarrett D'Amore 
107*84441f85SGarrett D'Amore static void add_compunit(enum e_cut, char *);
108*84441f85SGarrett D'Amore static void add_file(char *);
109*84441f85SGarrett D'Amore static void usage(void);
110*84441f85SGarrett D'Amore static char *getln(FILE *, size_t *);
111*84441f85SGarrett D'Amore 
112*84441f85SGarrett D'Amore 
113*84441f85SGarrett D'Amore int
114*84441f85SGarrett D'Amore main(int argc, char *argv[])
115*84441f85SGarrett D'Amore {
116*84441f85SGarrett D'Amore 	int c, fflag;
117*84441f85SGarrett D'Amore 	char *temp_arg;
118*84441f85SGarrett D'Amore 
119*84441f85SGarrett D'Amore 	(void) setlocale(LC_ALL, "");
120*84441f85SGarrett D'Amore 
121*84441f85SGarrett D'Amore #ifndef TEXT_DOMAIN
122*84441f85SGarrett D'Amore #define	TEXT_DOMAIN	"SYS_TEST"
123*84441f85SGarrett D'Amore #endif
124*84441f85SGarrett D'Amore 	(void) textdomain(TEXT_DOMAIN);
125*84441f85SGarrett D'Amore 
126*84441f85SGarrett D'Amore 	fflag = 0;
127*84441f85SGarrett D'Amore 	inplace = NULL;
128*84441f85SGarrett D'Amore 
129*84441f85SGarrett D'Amore 	while ((c = getopt(argc, argv, "EI:ae:f:i:lnr")) != -1)
130*84441f85SGarrett D'Amore 		switch (c) {
131*84441f85SGarrett D'Amore 		case 'r':		/* Gnu sed compat */
132*84441f85SGarrett D'Amore 		case 'E':
133*84441f85SGarrett D'Amore 			rflags = REG_EXTENDED;
134*84441f85SGarrett D'Amore 			break;
135*84441f85SGarrett D'Amore 		case 'I':
136*84441f85SGarrett D'Amore 			inplace = optarg;
137*84441f85SGarrett D'Amore 			ispan = 1;	/* span across input files */
138*84441f85SGarrett D'Amore 			break;
139*84441f85SGarrett D'Amore 		case 'a':
140*84441f85SGarrett D'Amore 			aflag = 1;
141*84441f85SGarrett D'Amore 			break;
142*84441f85SGarrett D'Amore 		case 'e':
143*84441f85SGarrett D'Amore 			eflag = 1;
144*84441f85SGarrett D'Amore 			if (asprintf(&temp_arg, "%s\n", optarg) <= 1)
145*84441f85SGarrett D'Amore 				err(1, "asprintf");
146*84441f85SGarrett D'Amore 			add_compunit(CU_STRING, temp_arg);
147*84441f85SGarrett D'Amore 			break;
148*84441f85SGarrett D'Amore 		case 'f':
149*84441f85SGarrett D'Amore 			fflag = 1;
150*84441f85SGarrett D'Amore 			add_compunit(CU_FILE, optarg);
151*84441f85SGarrett D'Amore 			break;
152*84441f85SGarrett D'Amore 		case 'i':
153*84441f85SGarrett D'Amore 			inplace = optarg;
154*84441f85SGarrett D'Amore 			ispan = 0;	/* don't span across input files */
155*84441f85SGarrett D'Amore 			break;
156*84441f85SGarrett D'Amore 		case 'l':
157*84441f85SGarrett D'Amore 			/* On SunOS, setlinebuf "returns no useful value */
158*84441f85SGarrett D'Amore 			(void) setlinebuf(stdout);
159*84441f85SGarrett D'Amore 			break;
160*84441f85SGarrett D'Amore 		case 'n':
161*84441f85SGarrett D'Amore 			nflag = 1;
162*84441f85SGarrett D'Amore 			break;
163*84441f85SGarrett D'Amore 		default:
164*84441f85SGarrett D'Amore 		case '?':
165*84441f85SGarrett D'Amore 			usage();
166*84441f85SGarrett D'Amore 		}
167*84441f85SGarrett D'Amore 	argc -= optind;
168*84441f85SGarrett D'Amore 	argv += optind;
169*84441f85SGarrett D'Amore 
170*84441f85SGarrett D'Amore 	/* First usage case; script is the first arg */
171*84441f85SGarrett D'Amore 	if (!eflag && !fflag && *argv) {
172*84441f85SGarrett D'Amore 		add_compunit(CU_STRING, *argv);
173*84441f85SGarrett D'Amore 		argv++;
174*84441f85SGarrett D'Amore 	}
175*84441f85SGarrett D'Amore 
176*84441f85SGarrett D'Amore 	compile();
177*84441f85SGarrett D'Amore 
178*84441f85SGarrett D'Amore 	/* Continue with first and start second usage */
179*84441f85SGarrett D'Amore 	if (*argv)
180*84441f85SGarrett D'Amore 		for (; *argv; argv++)
181*84441f85SGarrett D'Amore 			add_file(*argv);
182*84441f85SGarrett D'Amore 	else
183*84441f85SGarrett D'Amore 		add_file(NULL);
184*84441f85SGarrett D'Amore 	process();
185*84441f85SGarrett D'Amore 	cfclose(prog, NULL);
186*84441f85SGarrett D'Amore 	if (fclose(stdout))
187*84441f85SGarrett D'Amore 		err(1, "stdout");
188*84441f85SGarrett D'Amore 	return (rval);
189*84441f85SGarrett D'Amore }
190*84441f85SGarrett D'Amore 
191*84441f85SGarrett D'Amore static void
192*84441f85SGarrett D'Amore usage(void)
193*84441f85SGarrett D'Amore {
194*84441f85SGarrett D'Amore 	(void) fputs(_("usage: sed script [-Ealn] [-i extension] [file ...]\n"
195*84441f85SGarrett D'Amore 	    "       sed [-Ealn] [-i extension] [-e script] ... "
196*84441f85SGarrett D'Amore 	    "[-f script_file] ... [file ...]"),
197*84441f85SGarrett D'Amore 	    stderr);
198*84441f85SGarrett D'Amore 	exit(1);
199*84441f85SGarrett D'Amore }
200*84441f85SGarrett D'Amore 
201*84441f85SGarrett D'Amore /*
202*84441f85SGarrett D'Amore  * Like fgets, but go through the chain of compilation units chaining them
203*84441f85SGarrett D'Amore  * together.  Empty strings and files are ignored.
204*84441f85SGarrett D'Amore  */
205*84441f85SGarrett D'Amore char *
206*84441f85SGarrett D'Amore cu_fgets(char *buf, int n, int *more)
207*84441f85SGarrett D'Amore {
208*84441f85SGarrett D'Amore 	static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
209*84441f85SGarrett D'Amore 	static FILE *f;		/* Current open file */
210*84441f85SGarrett D'Amore 	static char *s;		/* Current pointer inside string */
211*84441f85SGarrett D'Amore 	static char string_ident[30];
212*84441f85SGarrett D'Amore 	char *p;
213*84441f85SGarrett D'Amore 
214*84441f85SGarrett D'Amore again:
215*84441f85SGarrett D'Amore 	switch (state) {
216*84441f85SGarrett D'Amore 	case ST_EOF:
217*84441f85SGarrett D'Amore 		if (script == NULL) {
218*84441f85SGarrett D'Amore 			if (more != NULL)
219*84441f85SGarrett D'Amore 				*more = 0;
220*84441f85SGarrett D'Amore 			return (NULL);
221*84441f85SGarrett D'Amore 		}
222*84441f85SGarrett D'Amore 		linenum = 0;
223*84441f85SGarrett D'Amore 		switch (script->type) {
224*84441f85SGarrett D'Amore 		case CU_FILE:
225*84441f85SGarrett D'Amore 			if ((f = fopen(script->s, "r")) == NULL)
226*84441f85SGarrett D'Amore 				err(1, "%s", script->s);
227*84441f85SGarrett D'Amore 			fname = script->s;
228*84441f85SGarrett D'Amore 			state = ST_FILE;
229*84441f85SGarrett D'Amore 			goto again;
230*84441f85SGarrett D'Amore 		case CU_STRING:
231*84441f85SGarrett D'Amore 			if (((size_t)snprintf(string_ident,
232*84441f85SGarrett D'Amore 			    sizeof (string_ident), "\"%s\"", script->s)) >=
233*84441f85SGarrett D'Amore 			    sizeof (string_ident) - 1)
234*84441f85SGarrett D'Amore 				(void) strcpy(string_ident +
235*84441f85SGarrett D'Amore 				    sizeof (string_ident) - 6, " ...\"");
236*84441f85SGarrett D'Amore 			fname = string_ident;
237*84441f85SGarrett D'Amore 			s = script->s;
238*84441f85SGarrett D'Amore 			state = ST_STRING;
239*84441f85SGarrett D'Amore 			goto again;
240*84441f85SGarrett D'Amore 		}
241*84441f85SGarrett D'Amore 		/*NOTREACHED*/
242*84441f85SGarrett D'Amore 
243*84441f85SGarrett D'Amore 	case ST_FILE:
244*84441f85SGarrett D'Amore 		if ((p = fgets(buf, n, f)) != NULL) {
245*84441f85SGarrett D'Amore 			linenum++;
246*84441f85SGarrett D'Amore 			if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
247*84441f85SGarrett D'Amore 				nflag = 1;
248*84441f85SGarrett D'Amore 			if (more != NULL)
249*84441f85SGarrett D'Amore 				*more = !feof(f);
250*84441f85SGarrett D'Amore 			return (p);
251*84441f85SGarrett D'Amore 		}
252*84441f85SGarrett D'Amore 		script = script->next;
253*84441f85SGarrett D'Amore 		(void) fclose(f);
254*84441f85SGarrett D'Amore 		state = ST_EOF;
255*84441f85SGarrett D'Amore 		goto again;
256*84441f85SGarrett D'Amore 	case ST_STRING:
257*84441f85SGarrett D'Amore 		if (linenum == 0 && s[0] == '#' && s[1] == 'n')
258*84441f85SGarrett D'Amore 			nflag = 1;
259*84441f85SGarrett D'Amore 		p = buf;
260*84441f85SGarrett D'Amore 		for (;;) {
261*84441f85SGarrett D'Amore 			if (n-- <= 1) {
262*84441f85SGarrett D'Amore 				*p = '\0';
263*84441f85SGarrett D'Amore 				linenum++;
264*84441f85SGarrett D'Amore 				if (more != NULL)
265*84441f85SGarrett D'Amore 					*more = 1;
266*84441f85SGarrett D'Amore 				return (buf);
267*84441f85SGarrett D'Amore 			}
268*84441f85SGarrett D'Amore 			switch (*s) {
269*84441f85SGarrett D'Amore 			case '\0':
270*84441f85SGarrett D'Amore 				state = ST_EOF;
271*84441f85SGarrett D'Amore 				if (s == script->s) {
272*84441f85SGarrett D'Amore 					script = script->next;
273*84441f85SGarrett D'Amore 					goto again;
274*84441f85SGarrett D'Amore 				} else {
275*84441f85SGarrett D'Amore 					script = script->next;
276*84441f85SGarrett D'Amore 					*p = '\0';
277*84441f85SGarrett D'Amore 					linenum++;
278*84441f85SGarrett D'Amore 					if (more != NULL)
279*84441f85SGarrett D'Amore 						*more = 0;
280*84441f85SGarrett D'Amore 					return (buf);
281*84441f85SGarrett D'Amore 				}
282*84441f85SGarrett D'Amore 			case '\n':
283*84441f85SGarrett D'Amore 				*p++ = '\n';
284*84441f85SGarrett D'Amore 				*p = '\0';
285*84441f85SGarrett D'Amore 				s++;
286*84441f85SGarrett D'Amore 				linenum++;
287*84441f85SGarrett D'Amore 				if (more != NULL)
288*84441f85SGarrett D'Amore 					*more = 0;
289*84441f85SGarrett D'Amore 				return (buf);
290*84441f85SGarrett D'Amore 			default:
291*84441f85SGarrett D'Amore 				*p++ = *s++;
292*84441f85SGarrett D'Amore 			}
293*84441f85SGarrett D'Amore 		}
294*84441f85SGarrett D'Amore 	}
295*84441f85SGarrett D'Amore 	/* NOTREACHED */
296*84441f85SGarrett D'Amore 	return (NULL);
297*84441f85SGarrett D'Amore }
298*84441f85SGarrett D'Amore 
299*84441f85SGarrett D'Amore /*
300*84441f85SGarrett D'Amore  * Like fgets, but go through the list of files chaining them together.
301*84441f85SGarrett D'Amore  * Set len to the length of the line.
302*84441f85SGarrett D'Amore  */
303*84441f85SGarrett D'Amore int
304*84441f85SGarrett D'Amore mf_fgets(SPACE *sp, enum e_spflag spflag)
305*84441f85SGarrett D'Amore {
306*84441f85SGarrett D'Amore 	struct stat sb;
307*84441f85SGarrett D'Amore 	size_t len;
308*84441f85SGarrett D'Amore 	char *p;
309*84441f85SGarrett D'Amore 	int c;
310*84441f85SGarrett D'Amore 	static int firstfile;
311*84441f85SGarrett D'Amore 
312*84441f85SGarrett D'Amore 	if (infile == NULL) {
313*84441f85SGarrett D'Amore 		/* stdin? */
314*84441f85SGarrett D'Amore 		if (files->fname == NULL) {
315*84441f85SGarrett D'Amore 			if (inplace != NULL)
316*84441f85SGarrett D'Amore 				errx(1,
317*84441f85SGarrett D'Amore 				    _("-I or -i may not be used with stdin"));
318*84441f85SGarrett D'Amore 			infile = stdin;
319*84441f85SGarrett D'Amore 			fname = "stdin";
320*84441f85SGarrett D'Amore 			outfile = stdout;
321*84441f85SGarrett D'Amore 			outfname = "stdout";
322*84441f85SGarrett D'Amore 		}
323*84441f85SGarrett D'Amore 		firstfile = 1;
324*84441f85SGarrett D'Amore 	}
325*84441f85SGarrett D'Amore 
326*84441f85SGarrett D'Amore 	for (;;) {
327*84441f85SGarrett D'Amore 		if (infile != NULL && (c = getc(infile)) != EOF) {
328*84441f85SGarrett D'Amore 			(void) ungetc(c, infile);
329*84441f85SGarrett D'Amore 			break;
330*84441f85SGarrett D'Amore 		}
331*84441f85SGarrett D'Amore 		/* If we are here then either eof or no files are open yet */
332*84441f85SGarrett D'Amore 		if (infile == stdin) {
333*84441f85SGarrett D'Amore 			sp->len = 0;
334*84441f85SGarrett D'Amore 			return (0);
335*84441f85SGarrett D'Amore 		}
336*84441f85SGarrett D'Amore 		if (infile != NULL) {
337*84441f85SGarrett D'Amore 			(void) fclose(infile);
338*84441f85SGarrett D'Amore 			if (*oldfname != '\0') {
339*84441f85SGarrett D'Amore 				if (link(fname, oldfname) != 0) {
340*84441f85SGarrett D'Amore 					warn("link()");
341*84441f85SGarrett D'Amore 					(void) unlink(tmpfname);
342*84441f85SGarrett D'Amore 					exit(1);
343*84441f85SGarrett D'Amore 				}
344*84441f85SGarrett D'Amore 				*oldfname = '\0';
345*84441f85SGarrett D'Amore 			}
346*84441f85SGarrett D'Amore 			if (*tmpfname != '\0') {
347*84441f85SGarrett D'Amore 				if (outfile != NULL && outfile != stdout)
348*84441f85SGarrett D'Amore 					if (fclose(outfile) != 0) {
349*84441f85SGarrett D'Amore 						warn("fclose()");
350*84441f85SGarrett D'Amore 						(void) unlink(tmpfname);
351*84441f85SGarrett D'Amore 						exit(1);
352*84441f85SGarrett D'Amore 					}
353*84441f85SGarrett D'Amore 				outfile = NULL;
354*84441f85SGarrett D'Amore 				if (rename(tmpfname, fname) != 0) {
355*84441f85SGarrett D'Amore 					/* this should not happen really! */
356*84441f85SGarrett D'Amore 					warn("rename()");
357*84441f85SGarrett D'Amore 					(void) unlink(tmpfname);
358*84441f85SGarrett D'Amore 					exit(1);
359*84441f85SGarrett D'Amore 				}
360*84441f85SGarrett D'Amore 				*tmpfname = '\0';
361*84441f85SGarrett D'Amore 			}
362*84441f85SGarrett D'Amore 			outfname = NULL;
363*84441f85SGarrett D'Amore 		}
364*84441f85SGarrett D'Amore 		if (firstfile == 0)
365*84441f85SGarrett D'Amore 			files = files->next;
366*84441f85SGarrett D'Amore 		else
367*84441f85SGarrett D'Amore 			firstfile = 0;
368*84441f85SGarrett D'Amore 		if (files == NULL) {
369*84441f85SGarrett D'Amore 			sp->len = 0;
370*84441f85SGarrett D'Amore 			return (0);
371*84441f85SGarrett D'Amore 		}
372*84441f85SGarrett D'Amore 		fname = files->fname;
373*84441f85SGarrett D'Amore 		if (inplace != NULL) {
374*84441f85SGarrett D'Amore 			char bn[PATH_MAX];
375*84441f85SGarrett D'Amore 			char dn[PATH_MAX];
376*84441f85SGarrett D'Amore 			(void) strlcpy(bn, fname, sizeof (bn));
377*84441f85SGarrett D'Amore 			(void) strlcpy(dn, fname, sizeof (dn));
378*84441f85SGarrett D'Amore 			if (lstat(fname, &sb) != 0)
379*84441f85SGarrett D'Amore 				err(1, "%s", fname);
380*84441f85SGarrett D'Amore 			if (!(sb.st_mode & S_IFREG))
381*84441f85SGarrett D'Amore 				fatal(_("in-place editing only "
382*84441f85SGarrett D'Amore 				    "works for regular files"));
383*84441f85SGarrett D'Amore 			if (*inplace != '\0') {
384*84441f85SGarrett D'Amore 				(void) strlcpy(oldfname, fname,
385*84441f85SGarrett D'Amore 				    sizeof (oldfname));
386*84441f85SGarrett D'Amore 				len = strlcat(oldfname, inplace,
387*84441f85SGarrett D'Amore 				    sizeof (oldfname));
388*84441f85SGarrett D'Amore 				if (len > sizeof (oldfname))
389*84441f85SGarrett D'Amore 					fatal(_("name too long"));
390*84441f85SGarrett D'Amore 			}
391*84441f85SGarrett D'Amore 			len = snprintf(tmpfname, sizeof (tmpfname),
392*84441f85SGarrett D'Amore 			    "%s/.!%ld!%s", dirname(dn), (long)getpid(),
393*84441f85SGarrett D'Amore 			    basename(bn));
394*84441f85SGarrett D'Amore 			if (len >= sizeof (tmpfname))
395*84441f85SGarrett D'Amore 				fatal(_("name too long"));
396*84441f85SGarrett D'Amore 			(void) unlink(tmpfname);
397*84441f85SGarrett D'Amore 			if ((outfile = fopen(tmpfname, "w")) == NULL)
398*84441f85SGarrett D'Amore 				err(1, "%s", fname);
399*84441f85SGarrett D'Amore 			if (fchown(fileno(outfile), sb.st_uid, sb.st_gid) != 0)
400*84441f85SGarrett D'Amore 				warn("fchown()");
401*84441f85SGarrett D'Amore 			if (fchmod(fileno(outfile), sb.st_mode & 07777) != 0)
402*84441f85SGarrett D'Amore 				warn("fchmod()");
403*84441f85SGarrett D'Amore 			outfname = tmpfname;
404*84441f85SGarrett D'Amore 			if (!ispan) {
405*84441f85SGarrett D'Amore 				linenum = 0;
406*84441f85SGarrett D'Amore 				resetstate();
407*84441f85SGarrett D'Amore 			}
408*84441f85SGarrett D'Amore 		} else {
409*84441f85SGarrett D'Amore 			outfile = stdout;
410*84441f85SGarrett D'Amore 			outfname = "stdout";
411*84441f85SGarrett D'Amore 		}
412*84441f85SGarrett D'Amore 		if ((infile = fopen(fname, "r")) == NULL) {
413*84441f85SGarrett D'Amore 			warn("%s", fname);
414*84441f85SGarrett D'Amore 			rval = 1;
415*84441f85SGarrett D'Amore 			continue;
416*84441f85SGarrett D'Amore 		}
417*84441f85SGarrett D'Amore 	}
418*84441f85SGarrett D'Amore 	/*
419*84441f85SGarrett D'Amore 	 * We are here only when infile is open and we still have something
420*84441f85SGarrett D'Amore 	 * to read from it.
421*84441f85SGarrett D'Amore 	 *
422*84441f85SGarrett D'Amore 	 * Use fgetln so that we can handle essentially infinite input data.
423*84441f85SGarrett D'Amore 	 * Can't use the pointer into the stdio buffer as the process space
424*84441f85SGarrett D'Amore 	 * because the ungetc() can cause it to move.
425*84441f85SGarrett D'Amore 	 */
426*84441f85SGarrett D'Amore 	p = getln(infile, &len);
427*84441f85SGarrett D'Amore 	if (ferror(infile))
428*84441f85SGarrett D'Amore 		errx(1, "%s: %s", fname, strerror(errno ? errno : EIO));
429*84441f85SGarrett D'Amore 	if (len != 0 && p[len - 1] == '\n')
430*84441f85SGarrett D'Amore 		len--;
431*84441f85SGarrett D'Amore 	cspace(sp, p, len, spflag);
432*84441f85SGarrett D'Amore 
433*84441f85SGarrett D'Amore 	linenum++;
434*84441f85SGarrett D'Amore 
435*84441f85SGarrett D'Amore 	return (1);
436*84441f85SGarrett D'Amore }
437*84441f85SGarrett D'Amore 
438*84441f85SGarrett D'Amore /*
439*84441f85SGarrett D'Amore  * Add a compilation unit to the linked list
440*84441f85SGarrett D'Amore  */
441*84441f85SGarrett D'Amore static void
442*84441f85SGarrett D'Amore add_compunit(enum e_cut type, char *s)
443*84441f85SGarrett D'Amore {
444*84441f85SGarrett D'Amore 	struct s_compunit *cu;
445*84441f85SGarrett D'Amore 
446*84441f85SGarrett D'Amore 	if ((cu = malloc(sizeof (struct s_compunit))) == NULL)
447*84441f85SGarrett D'Amore 		err(1, "malloc");
448*84441f85SGarrett D'Amore 	cu->type = type;
449*84441f85SGarrett D'Amore 	cu->s = s;
450*84441f85SGarrett D'Amore 	cu->next = NULL;
451*84441f85SGarrett D'Amore 	*cu_nextp = cu;
452*84441f85SGarrett D'Amore 	cu_nextp = &cu->next;
453*84441f85SGarrett D'Amore }
454*84441f85SGarrett D'Amore 
455*84441f85SGarrett D'Amore /*
456*84441f85SGarrett D'Amore  * Add a file to the linked list
457*84441f85SGarrett D'Amore  */
458*84441f85SGarrett D'Amore static void
459*84441f85SGarrett D'Amore add_file(char *s)
460*84441f85SGarrett D'Amore {
461*84441f85SGarrett D'Amore 	struct s_flist *fp;
462*84441f85SGarrett D'Amore 
463*84441f85SGarrett D'Amore 	if ((fp = malloc(sizeof (struct s_flist))) == NULL)
464*84441f85SGarrett D'Amore 		err(1, "malloc");
465*84441f85SGarrett D'Amore 	fp->next = NULL;
466*84441f85SGarrett D'Amore 	*fl_nextp = fp;
467*84441f85SGarrett D'Amore 	fp->fname = s;
468*84441f85SGarrett D'Amore 	fl_nextp = &fp->next;
469*84441f85SGarrett D'Amore }
470*84441f85SGarrett D'Amore 
471*84441f85SGarrett D'Amore int
472*84441f85SGarrett D'Amore lastline(void)
473*84441f85SGarrett D'Amore {
474*84441f85SGarrett D'Amore 	int ch;
475*84441f85SGarrett D'Amore 
476*84441f85SGarrett D'Amore 	if (files->next != NULL && (inplace == NULL || ispan))
477*84441f85SGarrett D'Amore 		return (0);
478*84441f85SGarrett D'Amore 	if ((ch = getc(infile)) == EOF)
479*84441f85SGarrett D'Amore 		return (1);
480*84441f85SGarrett D'Amore 	(void) ungetc(ch, infile);
481*84441f85SGarrett D'Amore 	return (0);
482*84441f85SGarrett D'Amore }
483*84441f85SGarrett D'Amore 
484*84441f85SGarrett D'Amore char *
485*84441f85SGarrett D'Amore getln(FILE *in, size_t *lenp)
486*84441f85SGarrett D'Amore {
487*84441f85SGarrett D'Amore 	static char	*buffer = NULL;
488*84441f85SGarrett D'Amore 	static size_t	sz = 0;
489*84441f85SGarrett D'Amore 
490*84441f85SGarrett D'Amore 	size_t		len = 0;
491*84441f85SGarrett D'Amore 
492*84441f85SGarrett D'Amore 	for (;;) {
493*84441f85SGarrett D'Amore 		if (sz <= (len + 1)) {
494*84441f85SGarrett D'Amore 			char *nb;
495*84441f85SGarrett D'Amore 			if ((nb = realloc(buffer, sz + LINE_MAX)) == NULL) {
496*84441f85SGarrett D'Amore 				err(1, "realloc");
497*84441f85SGarrett D'Amore 			}
498*84441f85SGarrett D'Amore 			buffer = nb;
499*84441f85SGarrett D'Amore 			sz += LINE_MAX;
500*84441f85SGarrett D'Amore 		}
501*84441f85SGarrett D'Amore 
502*84441f85SGarrett D'Amore 		buffer[len] = 0;
503*84441f85SGarrett D'Amore 
504*84441f85SGarrett D'Amore 		if (fgets(buffer + len, sz - len, in) == NULL) {
505*84441f85SGarrett D'Amore 			/* END OF FILE */
506*84441f85SGarrett D'Amore 			*lenp = len;
507*84441f85SGarrett D'Amore 			break;
508*84441f85SGarrett D'Amore 		}
509*84441f85SGarrett D'Amore 
510*84441f85SGarrett D'Amore 		len += strlen(buffer + len);
511*84441f85SGarrett D'Amore 
512*84441f85SGarrett D'Amore 		if (buffer[len - 1] == '\n') {
513*84441f85SGarrett D'Amore 			/* got the new line */
514*84441f85SGarrett D'Amore 			*lenp = len;
515*84441f85SGarrett D'Amore 			break;
516*84441f85SGarrett D'Amore 		}
517*84441f85SGarrett D'Amore 	}
518*84441f85SGarrett D'Amore 
519*84441f85SGarrett D'Amore 	return (buffer);
520*84441f85SGarrett D'Amore }
521