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 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 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 * 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 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 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 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 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