xref: /titanic_41/usr/src/cmd/sed/main.c (revision ab15e531679da9ab75e52c1c16011e74e3664a23)
184441f85SGarrett D'Amore /*
2*9384cec6SJohann 'Myrkraverk' Oskarsson  * Copyright (c) 2013 Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.com>
3d15978eaSGary Mills  * Copyright (c) 2011 Gary Mills
4e50226ecSYuri Pankov  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
584441f85SGarrett D'Amore  * Copyright (c) 1992 Diomidis Spinellis.
684441f85SGarrett D'Amore  * Copyright (c) 1992, 1993
784441f85SGarrett D'Amore  *	The Regents of the University of California.  All rights reserved.
884441f85SGarrett D'Amore  *
984441f85SGarrett D'Amore  * This code is derived from software contributed to Berkeley by
1084441f85SGarrett D'Amore  * Diomidis Spinellis of Imperial College, University of London.
1184441f85SGarrett D'Amore  *
1284441f85SGarrett D'Amore  * Redistribution and use in source and binary forms, with or without
1384441f85SGarrett D'Amore  * modification, are permitted provided that the following conditions
1484441f85SGarrett D'Amore  * are met:
1584441f85SGarrett D'Amore  * 1. Redistributions of source code must retain the above copyright
1684441f85SGarrett D'Amore  *    notice, this list of conditions and the following disclaimer.
1784441f85SGarrett D'Amore  * 2. Redistributions in binary form must reproduce the above copyright
1884441f85SGarrett D'Amore  *    notice, this list of conditions and the following disclaimer in the
1984441f85SGarrett D'Amore  *    documentation and/or other materials provided with the distribution.
2084441f85SGarrett D'Amore  * 4. Neither the name of the University nor the names of its contributors
2184441f85SGarrett D'Amore  *    may be used to endorse or promote products derived from this software
2284441f85SGarrett D'Amore  *    without specific prior written permission.
2384441f85SGarrett D'Amore  *
2484441f85SGarrett D'Amore  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2584441f85SGarrett D'Amore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2684441f85SGarrett D'Amore  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2784441f85SGarrett D'Amore  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2884441f85SGarrett D'Amore  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2984441f85SGarrett D'Amore  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3084441f85SGarrett D'Amore  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3184441f85SGarrett D'Amore  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3284441f85SGarrett D'Amore  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3384441f85SGarrett D'Amore  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3484441f85SGarrett D'Amore  * SUCH DAMAGE.
3584441f85SGarrett D'Amore  */
3684441f85SGarrett D'Amore 
3784441f85SGarrett D'Amore #include <sys/types.h>
3884441f85SGarrett D'Amore #include <sys/mman.h>
3984441f85SGarrett D'Amore #include <sys/param.h>
4084441f85SGarrett D'Amore #include <sys/stat.h>
4184441f85SGarrett D'Amore 
4284441f85SGarrett D'Amore #include <err.h>
4384441f85SGarrett D'Amore #include <errno.h>
4484441f85SGarrett D'Amore #include <fcntl.h>
45e50226ecSYuri Pankov #include <getopt.h>
4684441f85SGarrett D'Amore #include <libgen.h>
47e50226ecSYuri Pankov #include <libintl.h>
4884441f85SGarrett D'Amore #include <limits.h>
4984441f85SGarrett D'Amore #include <locale.h>
5084441f85SGarrett D'Amore #include <regex.h>
5184441f85SGarrett D'Amore #include <stddef.h>
5284441f85SGarrett D'Amore #include <stdio.h>
5384441f85SGarrett D'Amore #include <stdlib.h>
5484441f85SGarrett D'Amore #include <string.h>
5584441f85SGarrett D'Amore #include <unistd.h>
5684441f85SGarrett D'Amore 
5784441f85SGarrett D'Amore #include "defs.h"
5884441f85SGarrett D'Amore #include "extern.h"
5984441f85SGarrett D'Amore 
6084441f85SGarrett D'Amore /*
6184441f85SGarrett D'Amore  * Linked list of units (strings and files) to be compiled
6284441f85SGarrett D'Amore  */
6384441f85SGarrett D'Amore struct s_compunit {
6484441f85SGarrett D'Amore 	struct s_compunit *next;
6584441f85SGarrett D'Amore 	enum e_cut {CU_FILE, CU_STRING} type;
6684441f85SGarrett D'Amore 	char *s;			/* Pointer to string or fname */
6784441f85SGarrett D'Amore };
6884441f85SGarrett D'Amore 
6984441f85SGarrett D'Amore /*
7084441f85SGarrett D'Amore  * Linked list pointer to compilation units and pointer to current
7184441f85SGarrett D'Amore  * next pointer.
7284441f85SGarrett D'Amore  */
7384441f85SGarrett D'Amore static struct s_compunit *script, **cu_nextp = &script;
7484441f85SGarrett D'Amore 
7584441f85SGarrett D'Amore /*
7684441f85SGarrett D'Amore  * Linked list of files to be processed
7784441f85SGarrett D'Amore  */
7884441f85SGarrett D'Amore struct s_flist {
7984441f85SGarrett D'Amore 	char *fname;
8084441f85SGarrett D'Amore 	struct s_flist *next;
8184441f85SGarrett D'Amore };
8284441f85SGarrett D'Amore 
8384441f85SGarrett D'Amore /*
8484441f85SGarrett D'Amore  * Linked list pointer to files and pointer to current
8584441f85SGarrett D'Amore  * next pointer.
8684441f85SGarrett D'Amore  */
8784441f85SGarrett D'Amore static struct s_flist *files, **fl_nextp = &files;
8884441f85SGarrett D'Amore 
8984441f85SGarrett D'Amore FILE *infile;			/* Current input file */
9084441f85SGarrett D'Amore FILE *outfile;			/* Current output file */
9184441f85SGarrett D'Amore 
9284441f85SGarrett D'Amore int aflag, eflag, nflag;
9384441f85SGarrett D'Amore int rflags = 0;
9484441f85SGarrett D'Amore static int rval;		/* Exit status */
9584441f85SGarrett D'Amore 
9684441f85SGarrett D'Amore static int ispan;		/* Whether inplace editing spans across files */
9784441f85SGarrett D'Amore 
9884441f85SGarrett D'Amore /*
9984441f85SGarrett D'Amore  * Current file and line number; line numbers restart across compilation
10084441f85SGarrett D'Amore  * units, but span across input files.  The latter is optional if editing
10184441f85SGarrett D'Amore  * in place.
10284441f85SGarrett D'Amore  */
10384441f85SGarrett D'Amore const char *fname;		/* File name. */
10484441f85SGarrett D'Amore const char *outfname;		/* Output file name */
10584441f85SGarrett D'Amore static char oldfname[PATH_MAX];	/* Old file name (for in-place editing) */
10684441f85SGarrett D'Amore static char tmpfname[PATH_MAX];	/* Temporary file name (for in-place editing) */
10784441f85SGarrett D'Amore static const char *inplace;	/* Inplace edit file extension. */
10884441f85SGarrett D'Amore ulong_t linenum;
10984441f85SGarrett D'Amore 
110e50226ecSYuri Pankov static const struct option lopts[] = {
111e50226ecSYuri Pankov 	{"in-place",	optional_argument,	NULL,	'i'},
112e50226ecSYuri Pankov 	{NULL,		0,			NULL,	0}
113e50226ecSYuri Pankov };
114e50226ecSYuri Pankov 
11584441f85SGarrett D'Amore static void add_compunit(enum e_cut, char *);
11684441f85SGarrett D'Amore static void add_file(char *);
11784441f85SGarrett D'Amore static void usage(void);
11884441f85SGarrett D'Amore 
11984441f85SGarrett D'Amore 
12084441f85SGarrett D'Amore int
main(int argc,char * argv[])12184441f85SGarrett D'Amore main(int argc, char *argv[])
12284441f85SGarrett D'Amore {
12384441f85SGarrett D'Amore 	int c, fflag;
12484441f85SGarrett D'Amore 	char *temp_arg;
12584441f85SGarrett D'Amore 
12684441f85SGarrett D'Amore 	(void) setlocale(LC_ALL, "");
12784441f85SGarrett D'Amore 
12884441f85SGarrett D'Amore #ifndef TEXT_DOMAIN
12984441f85SGarrett D'Amore #define	TEXT_DOMAIN	"SYS_TEST"
13084441f85SGarrett D'Amore #endif
13184441f85SGarrett D'Amore 	(void) textdomain(TEXT_DOMAIN);
13284441f85SGarrett D'Amore 
13384441f85SGarrett D'Amore 	fflag = 0;
13484441f85SGarrett D'Amore 	inplace = NULL;
13584441f85SGarrett D'Amore 
136e50226ecSYuri Pankov 	while ((c = getopt_long(argc, argv, "EI::ae:f:i::lnr", lopts, NULL)) !=
137e50226ecSYuri Pankov 	    -1)
13884441f85SGarrett D'Amore 		switch (c) {
13984441f85SGarrett D'Amore 		case 'r':		/* Gnu sed compat */
14084441f85SGarrett D'Amore 		case 'E':
14184441f85SGarrett D'Amore 			rflags = REG_EXTENDED;
14284441f85SGarrett D'Amore 			break;
14384441f85SGarrett D'Amore 		case 'I':
144e50226ecSYuri Pankov 			if (optarg != NULL)
14584441f85SGarrett D'Amore 				inplace = optarg;
146e50226ecSYuri Pankov 			else
147e50226ecSYuri Pankov 				inplace = "";
14884441f85SGarrett D'Amore 			ispan = 1;	/* span across input files */
14984441f85SGarrett D'Amore 			break;
15084441f85SGarrett D'Amore 		case 'a':
15184441f85SGarrett D'Amore 			aflag = 1;
15284441f85SGarrett D'Amore 			break;
15384441f85SGarrett D'Amore 		case 'e':
15484441f85SGarrett D'Amore 			eflag = 1;
155d15978eaSGary Mills 			if (asprintf(&temp_arg, "%s\n", optarg) < 1)
15684441f85SGarrett D'Amore 				err(1, "asprintf");
15784441f85SGarrett D'Amore 			add_compunit(CU_STRING, temp_arg);
15884441f85SGarrett D'Amore 			break;
15984441f85SGarrett D'Amore 		case 'f':
16084441f85SGarrett D'Amore 			fflag = 1;
16184441f85SGarrett D'Amore 			add_compunit(CU_FILE, optarg);
16284441f85SGarrett D'Amore 			break;
16384441f85SGarrett D'Amore 		case 'i':
164e50226ecSYuri Pankov 			if (optarg != NULL)
16584441f85SGarrett D'Amore 				inplace = optarg;
166e50226ecSYuri Pankov 			else
167e50226ecSYuri Pankov 				inplace = "";
16884441f85SGarrett D'Amore 			ispan = 0;	/* don't span across input files */
16984441f85SGarrett D'Amore 			break;
17084441f85SGarrett D'Amore 		case 'l':
17184441f85SGarrett D'Amore 			/* On SunOS, setlinebuf "returns no useful value */
17284441f85SGarrett D'Amore 			(void) setlinebuf(stdout);
17384441f85SGarrett D'Amore 			break;
17484441f85SGarrett D'Amore 		case 'n':
17584441f85SGarrett D'Amore 			nflag = 1;
17684441f85SGarrett D'Amore 			break;
17784441f85SGarrett D'Amore 		default:
17884441f85SGarrett D'Amore 		case '?':
17984441f85SGarrett D'Amore 			usage();
18084441f85SGarrett D'Amore 		}
18184441f85SGarrett D'Amore 	argc -= optind;
18284441f85SGarrett D'Amore 	argv += optind;
18384441f85SGarrett D'Amore 
18484441f85SGarrett D'Amore 	/* First usage case; script is the first arg */
18584441f85SGarrett D'Amore 	if (!eflag && !fflag && *argv) {
18684441f85SGarrett D'Amore 		add_compunit(CU_STRING, *argv);
18784441f85SGarrett D'Amore 		argv++;
18884441f85SGarrett D'Amore 	}
18984441f85SGarrett D'Amore 
19084441f85SGarrett D'Amore 	compile();
19184441f85SGarrett D'Amore 
19284441f85SGarrett D'Amore 	/* Continue with first and start second usage */
19384441f85SGarrett D'Amore 	if (*argv)
19484441f85SGarrett D'Amore 		for (; *argv; argv++)
19584441f85SGarrett D'Amore 			add_file(*argv);
19684441f85SGarrett D'Amore 	else
19784441f85SGarrett D'Amore 		add_file(NULL);
19884441f85SGarrett D'Amore 	process();
19984441f85SGarrett D'Amore 	cfclose(prog, NULL);
20084441f85SGarrett D'Amore 	if (fclose(stdout))
20184441f85SGarrett D'Amore 		err(1, "stdout");
20284441f85SGarrett D'Amore 	return (rval);
20384441f85SGarrett D'Amore }
20484441f85SGarrett D'Amore 
20584441f85SGarrett D'Amore static void
usage(void)20684441f85SGarrett D'Amore usage(void)
20784441f85SGarrett D'Amore {
208e50226ecSYuri Pankov 	(void) fputs(_("usage: sed script [-Ealn] [-i[extension]] [file...]\n"
209e50226ecSYuri Pankov 	    "       sed [-Ealn] [-i[extension]] [-e script]... "
210da17b20bSDamian Wojslaw 	    "[-f script_file]... [file...]\n"),
21184441f85SGarrett D'Amore 	    stderr);
21284441f85SGarrett D'Amore 	exit(1);
21384441f85SGarrett D'Amore }
21484441f85SGarrett D'Amore 
21584441f85SGarrett D'Amore /*
21684441f85SGarrett D'Amore  * Like fgets, but go through the chain of compilation units chaining them
21784441f85SGarrett D'Amore  * together.  Empty strings and files are ignored.
21884441f85SGarrett D'Amore  */
21984441f85SGarrett D'Amore char *
cu_fgets(char * buf,int n,int * more)22084441f85SGarrett D'Amore cu_fgets(char *buf, int n, int *more)
22184441f85SGarrett D'Amore {
22284441f85SGarrett D'Amore 	static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
22384441f85SGarrett D'Amore 	static FILE *f;		/* Current open file */
22484441f85SGarrett D'Amore 	static char *s;		/* Current pointer inside string */
22584441f85SGarrett D'Amore 	static char string_ident[30];
22684441f85SGarrett D'Amore 	char *p;
22784441f85SGarrett D'Amore 
22884441f85SGarrett D'Amore again:
22984441f85SGarrett D'Amore 	switch (state) {
23084441f85SGarrett D'Amore 	case ST_EOF:
23184441f85SGarrett D'Amore 		if (script == NULL) {
23284441f85SGarrett D'Amore 			if (more != NULL)
23384441f85SGarrett D'Amore 				*more = 0;
23484441f85SGarrett D'Amore 			return (NULL);
23584441f85SGarrett D'Amore 		}
23684441f85SGarrett D'Amore 		linenum = 0;
23784441f85SGarrett D'Amore 		switch (script->type) {
23884441f85SGarrett D'Amore 		case CU_FILE:
23984441f85SGarrett D'Amore 			if ((f = fopen(script->s, "r")) == NULL)
24084441f85SGarrett D'Amore 				err(1, "%s", script->s);
24184441f85SGarrett D'Amore 			fname = script->s;
24284441f85SGarrett D'Amore 			state = ST_FILE;
24384441f85SGarrett D'Amore 			goto again;
24484441f85SGarrett D'Amore 		case CU_STRING:
24584441f85SGarrett D'Amore 			if (((size_t)snprintf(string_ident,
24684441f85SGarrett D'Amore 			    sizeof (string_ident), "\"%s\"", script->s)) >=
24784441f85SGarrett D'Amore 			    sizeof (string_ident) - 1)
24884441f85SGarrett D'Amore 				(void) strcpy(string_ident +
24984441f85SGarrett D'Amore 				    sizeof (string_ident) - 6, " ...\"");
25084441f85SGarrett D'Amore 			fname = string_ident;
25184441f85SGarrett D'Amore 			s = script->s;
25284441f85SGarrett D'Amore 			state = ST_STRING;
25384441f85SGarrett D'Amore 			goto again;
25484441f85SGarrett D'Amore 		}
25584441f85SGarrett D'Amore 		/*NOTREACHED*/
25684441f85SGarrett D'Amore 
25784441f85SGarrett D'Amore 	case ST_FILE:
25884441f85SGarrett D'Amore 		if ((p = fgets(buf, n, f)) != NULL) {
25984441f85SGarrett D'Amore 			linenum++;
26084441f85SGarrett D'Amore 			if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
26184441f85SGarrett D'Amore 				nflag = 1;
26284441f85SGarrett D'Amore 			if (more != NULL)
26384441f85SGarrett D'Amore 				*more = !feof(f);
26484441f85SGarrett D'Amore 			return (p);
26584441f85SGarrett D'Amore 		}
26684441f85SGarrett D'Amore 		script = script->next;
26784441f85SGarrett D'Amore 		(void) fclose(f);
26884441f85SGarrett D'Amore 		state = ST_EOF;
26984441f85SGarrett D'Amore 		goto again;
27084441f85SGarrett D'Amore 	case ST_STRING:
27184441f85SGarrett D'Amore 		if (linenum == 0 && s[0] == '#' && s[1] == 'n')
27284441f85SGarrett D'Amore 			nflag = 1;
27384441f85SGarrett D'Amore 		p = buf;
27484441f85SGarrett D'Amore 		for (;;) {
27584441f85SGarrett D'Amore 			if (n-- <= 1) {
27684441f85SGarrett D'Amore 				*p = '\0';
27784441f85SGarrett D'Amore 				linenum++;
27884441f85SGarrett D'Amore 				if (more != NULL)
27984441f85SGarrett D'Amore 					*more = 1;
28084441f85SGarrett D'Amore 				return (buf);
28184441f85SGarrett D'Amore 			}
28284441f85SGarrett D'Amore 			switch (*s) {
28384441f85SGarrett D'Amore 			case '\0':
28484441f85SGarrett D'Amore 				state = ST_EOF;
28584441f85SGarrett D'Amore 				if (s == script->s) {
28684441f85SGarrett D'Amore 					script = script->next;
28784441f85SGarrett D'Amore 					goto again;
28884441f85SGarrett D'Amore 				} else {
28984441f85SGarrett D'Amore 					script = script->next;
29084441f85SGarrett D'Amore 					*p = '\0';
29184441f85SGarrett D'Amore 					linenum++;
29284441f85SGarrett D'Amore 					if (more != NULL)
29384441f85SGarrett D'Amore 						*more = 0;
29484441f85SGarrett D'Amore 					return (buf);
29584441f85SGarrett D'Amore 				}
29684441f85SGarrett D'Amore 			case '\n':
29784441f85SGarrett D'Amore 				*p++ = '\n';
29884441f85SGarrett D'Amore 				*p = '\0';
29984441f85SGarrett D'Amore 				s++;
30084441f85SGarrett D'Amore 				linenum++;
30184441f85SGarrett D'Amore 				if (more != NULL)
30284441f85SGarrett D'Amore 					*more = 0;
30384441f85SGarrett D'Amore 				return (buf);
30484441f85SGarrett D'Amore 			default:
30584441f85SGarrett D'Amore 				*p++ = *s++;
30684441f85SGarrett D'Amore 			}
30784441f85SGarrett D'Amore 		}
30884441f85SGarrett D'Amore 	}
30984441f85SGarrett D'Amore 	/* NOTREACHED */
31084441f85SGarrett D'Amore 	return (NULL);
31184441f85SGarrett D'Amore }
31284441f85SGarrett D'Amore 
31384441f85SGarrett D'Amore /*
31484441f85SGarrett D'Amore  * Like fgets, but go through the list of files chaining them together.
31584441f85SGarrett D'Amore  * Set len to the length of the line.
31684441f85SGarrett D'Amore  */
31784441f85SGarrett D'Amore int
mf_fgets(SPACE * sp,enum e_spflag spflag)31884441f85SGarrett D'Amore mf_fgets(SPACE *sp, enum e_spflag spflag)
31984441f85SGarrett D'Amore {
320c530934aSGarrett D'Amore 	struct stat sb, nsb;
321*9384cec6SJohann 'Myrkraverk' Oskarsson 	ssize_t len;
322*9384cec6SJohann 'Myrkraverk' Oskarsson 	static char *p = NULL;
323*9384cec6SJohann 'Myrkraverk' Oskarsson 	static size_t plen = 0;
32484441f85SGarrett D'Amore 	int c;
32584441f85SGarrett D'Amore 	static int firstfile;
32684441f85SGarrett D'Amore 
32784441f85SGarrett D'Amore 	if (infile == NULL) {
32884441f85SGarrett D'Amore 		/* stdin? */
32984441f85SGarrett D'Amore 		if (files->fname == NULL) {
33084441f85SGarrett D'Amore 			if (inplace != NULL)
33184441f85SGarrett D'Amore 				errx(1,
33284441f85SGarrett D'Amore 				    _("-I or -i may not be used with stdin"));
33384441f85SGarrett D'Amore 			infile = stdin;
33484441f85SGarrett D'Amore 			fname = "stdin";
33584441f85SGarrett D'Amore 			outfile = stdout;
33684441f85SGarrett D'Amore 			outfname = "stdout";
33784441f85SGarrett D'Amore 		}
33884441f85SGarrett D'Amore 		firstfile = 1;
33984441f85SGarrett D'Amore 	}
34084441f85SGarrett D'Amore 
34184441f85SGarrett D'Amore 	for (;;) {
34284441f85SGarrett D'Amore 		if (infile != NULL && (c = getc(infile)) != EOF) {
34384441f85SGarrett D'Amore 			(void) ungetc(c, infile);
34484441f85SGarrett D'Amore 			break;
34584441f85SGarrett D'Amore 		}
34684441f85SGarrett D'Amore 		/* If we are here then either eof or no files are open yet */
34784441f85SGarrett D'Amore 		if (infile == stdin) {
34884441f85SGarrett D'Amore 			sp->len = 0;
34984441f85SGarrett D'Amore 			return (0);
35084441f85SGarrett D'Amore 		}
35184441f85SGarrett D'Amore 		if (infile != NULL) {
35284441f85SGarrett D'Amore 			(void) fclose(infile);
35384441f85SGarrett D'Amore 			if (*oldfname != '\0') {
354429d0af2SGarrett D'Amore 				/* if there was a backup file, remove it */
355429d0af2SGarrett D'Amore 				(void) unlink(oldfname);
356c530934aSGarrett D'Amore 				/*
357c530934aSGarrett D'Amore 				 * Backup the original.  Note that hard links
358c530934aSGarrett D'Amore 				 * are not supported on all filesystems.
359c530934aSGarrett D'Amore 				 */
360c530934aSGarrett D'Amore 				if ((link(fname, oldfname) != 0) &&
361c530934aSGarrett D'Amore 				    (rename(fname, oldfname) != 0)) {
362c530934aSGarrett D'Amore 					warn("rename()");
363c530934aSGarrett D'Amore 					if (*tmpfname)
36484441f85SGarrett D'Amore 						(void) unlink(tmpfname);
36584441f85SGarrett D'Amore 					exit(1);
36684441f85SGarrett D'Amore 				}
36784441f85SGarrett D'Amore 				*oldfname = '\0';
36884441f85SGarrett D'Amore 			}
36984441f85SGarrett D'Amore 			if (*tmpfname != '\0') {
37084441f85SGarrett D'Amore 				if (outfile != NULL && outfile != stdout)
37184441f85SGarrett D'Amore 					if (fclose(outfile) != 0) {
37284441f85SGarrett D'Amore 						warn("fclose()");
37384441f85SGarrett D'Amore 						(void) unlink(tmpfname);
37484441f85SGarrett D'Amore 						exit(1);
37584441f85SGarrett D'Amore 					}
37684441f85SGarrett D'Amore 				outfile = NULL;
37784441f85SGarrett D'Amore 				if (rename(tmpfname, fname) != 0) {
37884441f85SGarrett D'Amore 					/* this should not happen really! */
37984441f85SGarrett D'Amore 					warn("rename()");
38084441f85SGarrett D'Amore 					(void) unlink(tmpfname);
38184441f85SGarrett D'Amore 					exit(1);
38284441f85SGarrett D'Amore 				}
38384441f85SGarrett D'Amore 				*tmpfname = '\0';
38484441f85SGarrett D'Amore 			}
38584441f85SGarrett D'Amore 			outfname = NULL;
38684441f85SGarrett D'Amore 		}
38784441f85SGarrett D'Amore 		if (firstfile == 0)
38884441f85SGarrett D'Amore 			files = files->next;
38984441f85SGarrett D'Amore 		else
39084441f85SGarrett D'Amore 			firstfile = 0;
39184441f85SGarrett D'Amore 		if (files == NULL) {
39284441f85SGarrett D'Amore 			sp->len = 0;
39384441f85SGarrett D'Amore 			return (0);
39484441f85SGarrett D'Amore 		}
39584441f85SGarrett D'Amore 		fname = files->fname;
39684441f85SGarrett D'Amore 		if (inplace != NULL) {
39784441f85SGarrett D'Amore 			char bn[PATH_MAX];
39884441f85SGarrett D'Amore 			char dn[PATH_MAX];
39984441f85SGarrett D'Amore 			(void) strlcpy(bn, fname, sizeof (bn));
40084441f85SGarrett D'Amore 			(void) strlcpy(dn, fname, sizeof (dn));
40184441f85SGarrett D'Amore 			if (lstat(fname, &sb) != 0)
40284441f85SGarrett D'Amore 				err(1, "%s", fname);
40384441f85SGarrett D'Amore 			if (!(sb.st_mode & S_IFREG))
40484441f85SGarrett D'Amore 				fatal(_("in-place editing only "
40584441f85SGarrett D'Amore 				    "works for regular files"));
40684441f85SGarrett D'Amore 			if (*inplace != '\0') {
40784441f85SGarrett D'Amore 				(void) strlcpy(oldfname, fname,
40884441f85SGarrett D'Amore 				    sizeof (oldfname));
40984441f85SGarrett D'Amore 				len = strlcat(oldfname, inplace,
41084441f85SGarrett D'Amore 				    sizeof (oldfname));
41184441f85SGarrett D'Amore 				if (len > sizeof (oldfname))
41284441f85SGarrett D'Amore 					fatal(_("name too long"));
41384441f85SGarrett D'Amore 			}
41484441f85SGarrett D'Amore 			len = snprintf(tmpfname, sizeof (tmpfname),
41584441f85SGarrett D'Amore 			    "%s/.!%ld!%s", dirname(dn), (long)getpid(),
41684441f85SGarrett D'Amore 			    basename(bn));
41784441f85SGarrett D'Amore 			if (len >= sizeof (tmpfname))
41884441f85SGarrett D'Amore 				fatal(_("name too long"));
41984441f85SGarrett D'Amore 			(void) unlink(tmpfname);
42084441f85SGarrett D'Amore 			if ((outfile = fopen(tmpfname, "w")) == NULL)
42184441f85SGarrett D'Amore 				err(1, "%s", fname);
422c530934aSGarrett D'Amore 			/*
423c530934aSGarrett D'Amore 			 * Some file systems don't support chown or
424c530934aSGarrett D'Amore 			 * chmod fully.  On those, the owner/group and
425c530934aSGarrett D'Amore 			 * permissions will already be set to what
426c530934aSGarrett D'Amore 			 * they need to be.
427c530934aSGarrett D'Amore 			 */
428c530934aSGarrett D'Amore 			if (fstat(fileno(outfile), &nsb) != 0) {
429c530934aSGarrett D'Amore 				warn("fstat()");
430c530934aSGarrett D'Amore 			}
431c530934aSGarrett D'Amore 			if (((sb.st_uid != nsb.st_uid) ||
432c530934aSGarrett D'Amore 			    (sb.st_gid != nsb.st_gid)) &&
433c530934aSGarrett D'Amore 			    (fchown(fileno(outfile), sb.st_uid, sb.st_gid)
434c530934aSGarrett D'Amore 			    != 0))
43584441f85SGarrett D'Amore 				warn("fchown()");
436c530934aSGarrett D'Amore 			if ((sb.st_mode != nsb.st_mode) &&
437c530934aSGarrett D'Amore 			    (fchmod(fileno(outfile), sb.st_mode & 07777) != 0))
43884441f85SGarrett D'Amore 				warn("fchmod()");
43984441f85SGarrett D'Amore 			outfname = tmpfname;
44084441f85SGarrett D'Amore 			if (!ispan) {
44184441f85SGarrett D'Amore 				linenum = 0;
44284441f85SGarrett D'Amore 				resetstate();
44384441f85SGarrett D'Amore 			}
44484441f85SGarrett D'Amore 		} else {
44584441f85SGarrett D'Amore 			outfile = stdout;
44684441f85SGarrett D'Amore 			outfname = "stdout";
44784441f85SGarrett D'Amore 		}
44884441f85SGarrett D'Amore 		if ((infile = fopen(fname, "r")) == NULL) {
44984441f85SGarrett D'Amore 			warn("%s", fname);
45084441f85SGarrett D'Amore 			rval = 1;
45184441f85SGarrett D'Amore 			continue;
45284441f85SGarrett D'Amore 		}
45384441f85SGarrett D'Amore 	}
45484441f85SGarrett D'Amore 	/*
45584441f85SGarrett D'Amore 	 * We are here only when infile is open and we still have something
45684441f85SGarrett D'Amore 	 * to read from it.
45784441f85SGarrett D'Amore 	 *
458*9384cec6SJohann 'Myrkraverk' Oskarsson 	 * Use getline() so that we can handle essentially infinite
459*9384cec6SJohann 'Myrkraverk' Oskarsson 	 * input data.  The p and plen are static so each invocation gives
460*9384cec6SJohann 'Myrkraverk' Oskarsson 	 * getline() the same buffer which is expanded as needed.
46184441f85SGarrett D'Amore 	 */
462*9384cec6SJohann 'Myrkraverk' Oskarsson 	len = getline(&p, &plen, infile);
463*9384cec6SJohann 'Myrkraverk' Oskarsson 	if (len == -1)
464*9384cec6SJohann 'Myrkraverk' Oskarsson 		err(1, "%s", fname);
46584441f85SGarrett D'Amore 	if (len != 0 && p[len - 1] == '\n')
46684441f85SGarrett D'Amore 		len--;
46784441f85SGarrett D'Amore 	cspace(sp, p, len, spflag);
46884441f85SGarrett D'Amore 
46984441f85SGarrett D'Amore 	linenum++;
47084441f85SGarrett D'Amore 
47184441f85SGarrett D'Amore 	return (1);
47284441f85SGarrett D'Amore }
47384441f85SGarrett D'Amore 
47484441f85SGarrett D'Amore /*
47584441f85SGarrett D'Amore  * Add a compilation unit to the linked list
47684441f85SGarrett D'Amore  */
47784441f85SGarrett D'Amore static void
add_compunit(enum e_cut type,char * s)47884441f85SGarrett D'Amore add_compunit(enum e_cut type, char *s)
47984441f85SGarrett D'Amore {
48084441f85SGarrett D'Amore 	struct s_compunit *cu;
48184441f85SGarrett D'Amore 
48284441f85SGarrett D'Amore 	if ((cu = malloc(sizeof (struct s_compunit))) == NULL)
48384441f85SGarrett D'Amore 		err(1, "malloc");
48484441f85SGarrett D'Amore 	cu->type = type;
48584441f85SGarrett D'Amore 	cu->s = s;
48684441f85SGarrett D'Amore 	cu->next = NULL;
48784441f85SGarrett D'Amore 	*cu_nextp = cu;
48884441f85SGarrett D'Amore 	cu_nextp = &cu->next;
48984441f85SGarrett D'Amore }
49084441f85SGarrett D'Amore 
49184441f85SGarrett D'Amore /*
49284441f85SGarrett D'Amore  * Add a file to the linked list
49384441f85SGarrett D'Amore  */
49484441f85SGarrett D'Amore static void
add_file(char * s)49584441f85SGarrett D'Amore add_file(char *s)
49684441f85SGarrett D'Amore {
49784441f85SGarrett D'Amore 	struct s_flist *fp;
49884441f85SGarrett D'Amore 
49984441f85SGarrett D'Amore 	if ((fp = malloc(sizeof (struct s_flist))) == NULL)
50084441f85SGarrett D'Amore 		err(1, "malloc");
50184441f85SGarrett D'Amore 	fp->next = NULL;
50284441f85SGarrett D'Amore 	*fl_nextp = fp;
50384441f85SGarrett D'Amore 	fp->fname = s;
50484441f85SGarrett D'Amore 	fl_nextp = &fp->next;
50584441f85SGarrett D'Amore }
50684441f85SGarrett D'Amore 
50784441f85SGarrett D'Amore int
lastline(void)50884441f85SGarrett D'Amore lastline(void)
50984441f85SGarrett D'Amore {
51084441f85SGarrett D'Amore 	int ch;
51184441f85SGarrett D'Amore 
51284441f85SGarrett D'Amore 	if (files->next != NULL && (inplace == NULL || ispan))
51384441f85SGarrett D'Amore 		return (0);
51484441f85SGarrett D'Amore 	if ((ch = getc(infile)) == EOF)
51584441f85SGarrett D'Amore 		return (1);
51684441f85SGarrett D'Amore 	(void) ungetc(ch, infile);
51784441f85SGarrett D'Amore 	return (0);
51884441f85SGarrett D'Amore }
519