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