184441f85SGarrett D'Amore /* 284441f85SGarrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 384441f85SGarrett D'Amore * Copyright (c) 1992 Diomidis Spinellis. 484441f85SGarrett D'Amore * Copyright (c) 1992, 1993 584441f85SGarrett D'Amore * The Regents of the University of California. All rights reserved. 684441f85SGarrett D'Amore * 784441f85SGarrett D'Amore * This code is derived from software contributed to Berkeley by 884441f85SGarrett D'Amore * Diomidis Spinellis of Imperial College, University of London. 984441f85SGarrett D'Amore * 1084441f85SGarrett D'Amore * Redistribution and use in source and binary forms, with or without 1184441f85SGarrett D'Amore * modification, are permitted provided that the following conditions 1284441f85SGarrett D'Amore * are met: 1384441f85SGarrett D'Amore * 1. Redistributions of source code must retain the above copyright 1484441f85SGarrett D'Amore * notice, this list of conditions and the following disclaimer. 1584441f85SGarrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright 1684441f85SGarrett D'Amore * notice, this list of conditions and the following disclaimer in the 1784441f85SGarrett D'Amore * documentation and/or other materials provided with the distribution. 1884441f85SGarrett D'Amore * 4. Neither the name of the University nor the names of its contributors 1984441f85SGarrett D'Amore * may be used to endorse or promote products derived from this software 2084441f85SGarrett D'Amore * without specific prior written permission. 2184441f85SGarrett D'Amore * 2284441f85SGarrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2384441f85SGarrett D'Amore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2484441f85SGarrett D'Amore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2584441f85SGarrett D'Amore * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2684441f85SGarrett D'Amore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2784441f85SGarrett D'Amore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2884441f85SGarrett D'Amore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2984441f85SGarrett D'Amore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3084441f85SGarrett D'Amore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3184441f85SGarrett D'Amore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3284441f85SGarrett D'Amore * SUCH DAMAGE. 3384441f85SGarrett D'Amore */ 3484441f85SGarrett D'Amore 3584441f85SGarrett D'Amore #include <sys/types.h> 3684441f85SGarrett D'Amore #include <sys/mman.h> 3784441f85SGarrett D'Amore #include <sys/param.h> 3884441f85SGarrett D'Amore #include <sys/stat.h> 3984441f85SGarrett D'Amore 4084441f85SGarrett D'Amore #include <err.h> 4184441f85SGarrett D'Amore #include <errno.h> 4284441f85SGarrett D'Amore #include <fcntl.h> 4384441f85SGarrett D'Amore #include <libgen.h> 4484441f85SGarrett D'Amore #include <limits.h> 4584441f85SGarrett D'Amore #include <locale.h> 4684441f85SGarrett D'Amore #include <regex.h> 4784441f85SGarrett D'Amore #include <stddef.h> 4884441f85SGarrett D'Amore #include <stdio.h> 4984441f85SGarrett D'Amore #include <stdlib.h> 5084441f85SGarrett D'Amore #include <string.h> 5184441f85SGarrett D'Amore #include <unistd.h> 5284441f85SGarrett D'Amore #include <libintl.h> 5384441f85SGarrett D'Amore 5484441f85SGarrett D'Amore #include "defs.h" 5584441f85SGarrett D'Amore #include "extern.h" 5684441f85SGarrett D'Amore 5784441f85SGarrett D'Amore /* 5884441f85SGarrett D'Amore * Linked list of units (strings and files) to be compiled 5984441f85SGarrett D'Amore */ 6084441f85SGarrett D'Amore struct s_compunit { 6184441f85SGarrett D'Amore struct s_compunit *next; 6284441f85SGarrett D'Amore enum e_cut {CU_FILE, CU_STRING} type; 6384441f85SGarrett D'Amore char *s; /* Pointer to string or fname */ 6484441f85SGarrett D'Amore }; 6584441f85SGarrett D'Amore 6684441f85SGarrett D'Amore /* 6784441f85SGarrett D'Amore * Linked list pointer to compilation units and pointer to current 6884441f85SGarrett D'Amore * next pointer. 6984441f85SGarrett D'Amore */ 7084441f85SGarrett D'Amore static struct s_compunit *script, **cu_nextp = &script; 7184441f85SGarrett D'Amore 7284441f85SGarrett D'Amore /* 7384441f85SGarrett D'Amore * Linked list of files to be processed 7484441f85SGarrett D'Amore */ 7584441f85SGarrett D'Amore struct s_flist { 7684441f85SGarrett D'Amore char *fname; 7784441f85SGarrett D'Amore struct s_flist *next; 7884441f85SGarrett D'Amore }; 7984441f85SGarrett D'Amore 8084441f85SGarrett D'Amore /* 8184441f85SGarrett D'Amore * Linked list pointer to files and pointer to current 8284441f85SGarrett D'Amore * next pointer. 8384441f85SGarrett D'Amore */ 8484441f85SGarrett D'Amore static struct s_flist *files, **fl_nextp = &files; 8584441f85SGarrett D'Amore 8684441f85SGarrett D'Amore FILE *infile; /* Current input file */ 8784441f85SGarrett D'Amore FILE *outfile; /* Current output file */ 8884441f85SGarrett D'Amore 8984441f85SGarrett D'Amore int aflag, eflag, nflag; 9084441f85SGarrett D'Amore int rflags = 0; 9184441f85SGarrett D'Amore static int rval; /* Exit status */ 9284441f85SGarrett D'Amore 9384441f85SGarrett D'Amore static int ispan; /* Whether inplace editing spans across files */ 9484441f85SGarrett D'Amore 9584441f85SGarrett D'Amore /* 9684441f85SGarrett D'Amore * Current file and line number; line numbers restart across compilation 9784441f85SGarrett D'Amore * units, but span across input files. The latter is optional if editing 9884441f85SGarrett D'Amore * in place. 9984441f85SGarrett D'Amore */ 10084441f85SGarrett D'Amore const char *fname; /* File name. */ 10184441f85SGarrett D'Amore const char *outfname; /* Output file name */ 10284441f85SGarrett D'Amore static char oldfname[PATH_MAX]; /* Old file name (for in-place editing) */ 10384441f85SGarrett D'Amore static char tmpfname[PATH_MAX]; /* Temporary file name (for in-place editing) */ 10484441f85SGarrett D'Amore static const char *inplace; /* Inplace edit file extension. */ 10584441f85SGarrett D'Amore ulong_t linenum; 10684441f85SGarrett D'Amore 10784441f85SGarrett D'Amore static void add_compunit(enum e_cut, char *); 10884441f85SGarrett D'Amore static void add_file(char *); 10984441f85SGarrett D'Amore static void usage(void); 11084441f85SGarrett D'Amore static char *getln(FILE *, size_t *); 11184441f85SGarrett D'Amore 11284441f85SGarrett D'Amore 11384441f85SGarrett D'Amore int 11484441f85SGarrett D'Amore main(int argc, char *argv[]) 11584441f85SGarrett D'Amore { 11684441f85SGarrett D'Amore int c, fflag; 11784441f85SGarrett D'Amore char *temp_arg; 11884441f85SGarrett D'Amore 11984441f85SGarrett D'Amore (void) setlocale(LC_ALL, ""); 12084441f85SGarrett D'Amore 12184441f85SGarrett D'Amore #ifndef TEXT_DOMAIN 12284441f85SGarrett D'Amore #define TEXT_DOMAIN "SYS_TEST" 12384441f85SGarrett D'Amore #endif 12484441f85SGarrett D'Amore (void) textdomain(TEXT_DOMAIN); 12584441f85SGarrett D'Amore 12684441f85SGarrett D'Amore fflag = 0; 12784441f85SGarrett D'Amore inplace = NULL; 12884441f85SGarrett D'Amore 12984441f85SGarrett D'Amore while ((c = getopt(argc, argv, "EI:ae:f:i:lnr")) != -1) 13084441f85SGarrett D'Amore switch (c) { 13184441f85SGarrett D'Amore case 'r': /* Gnu sed compat */ 13284441f85SGarrett D'Amore case 'E': 13384441f85SGarrett D'Amore rflags = REG_EXTENDED; 13484441f85SGarrett D'Amore break; 13584441f85SGarrett D'Amore case 'I': 13684441f85SGarrett D'Amore inplace = optarg; 13784441f85SGarrett D'Amore ispan = 1; /* span across input files */ 13884441f85SGarrett D'Amore break; 13984441f85SGarrett D'Amore case 'a': 14084441f85SGarrett D'Amore aflag = 1; 14184441f85SGarrett D'Amore break; 14284441f85SGarrett D'Amore case 'e': 14384441f85SGarrett D'Amore eflag = 1; 14484441f85SGarrett D'Amore if (asprintf(&temp_arg, "%s\n", optarg) <= 1) 14584441f85SGarrett D'Amore err(1, "asprintf"); 14684441f85SGarrett D'Amore add_compunit(CU_STRING, temp_arg); 14784441f85SGarrett D'Amore break; 14884441f85SGarrett D'Amore case 'f': 14984441f85SGarrett D'Amore fflag = 1; 15084441f85SGarrett D'Amore add_compunit(CU_FILE, optarg); 15184441f85SGarrett D'Amore break; 15284441f85SGarrett D'Amore case 'i': 15384441f85SGarrett D'Amore inplace = optarg; 15484441f85SGarrett D'Amore ispan = 0; /* don't span across input files */ 15584441f85SGarrett D'Amore break; 15684441f85SGarrett D'Amore case 'l': 15784441f85SGarrett D'Amore /* On SunOS, setlinebuf "returns no useful value */ 15884441f85SGarrett D'Amore (void) setlinebuf(stdout); 15984441f85SGarrett D'Amore break; 16084441f85SGarrett D'Amore case 'n': 16184441f85SGarrett D'Amore nflag = 1; 16284441f85SGarrett D'Amore break; 16384441f85SGarrett D'Amore default: 16484441f85SGarrett D'Amore case '?': 16584441f85SGarrett D'Amore usage(); 16684441f85SGarrett D'Amore } 16784441f85SGarrett D'Amore argc -= optind; 16884441f85SGarrett D'Amore argv += optind; 16984441f85SGarrett D'Amore 17084441f85SGarrett D'Amore /* First usage case; script is the first arg */ 17184441f85SGarrett D'Amore if (!eflag && !fflag && *argv) { 17284441f85SGarrett D'Amore add_compunit(CU_STRING, *argv); 17384441f85SGarrett D'Amore argv++; 17484441f85SGarrett D'Amore } 17584441f85SGarrett D'Amore 17684441f85SGarrett D'Amore compile(); 17784441f85SGarrett D'Amore 17884441f85SGarrett D'Amore /* Continue with first and start second usage */ 17984441f85SGarrett D'Amore if (*argv) 18084441f85SGarrett D'Amore for (; *argv; argv++) 18184441f85SGarrett D'Amore add_file(*argv); 18284441f85SGarrett D'Amore else 18384441f85SGarrett D'Amore add_file(NULL); 18484441f85SGarrett D'Amore process(); 18584441f85SGarrett D'Amore cfclose(prog, NULL); 18684441f85SGarrett D'Amore if (fclose(stdout)) 18784441f85SGarrett D'Amore err(1, "stdout"); 18884441f85SGarrett D'Amore return (rval); 18984441f85SGarrett D'Amore } 19084441f85SGarrett D'Amore 19184441f85SGarrett D'Amore static void 19284441f85SGarrett D'Amore usage(void) 19384441f85SGarrett D'Amore { 19484441f85SGarrett D'Amore (void) fputs(_("usage: sed script [-Ealn] [-i extension] [file...]\n" 19584441f85SGarrett D'Amore " sed [-Ealn] [-i extension] [-e script]... " 196*da17b20bSDamian Wojslaw "[-f script_file]... [file...]\n"), 19784441f85SGarrett D'Amore stderr); 19884441f85SGarrett D'Amore exit(1); 19984441f85SGarrett D'Amore } 20084441f85SGarrett D'Amore 20184441f85SGarrett D'Amore /* 20284441f85SGarrett D'Amore * Like fgets, but go through the chain of compilation units chaining them 20384441f85SGarrett D'Amore * together. Empty strings and files are ignored. 20484441f85SGarrett D'Amore */ 20584441f85SGarrett D'Amore char * 20684441f85SGarrett D'Amore cu_fgets(char *buf, int n, int *more) 20784441f85SGarrett D'Amore { 20884441f85SGarrett D'Amore static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF; 20984441f85SGarrett D'Amore static FILE *f; /* Current open file */ 21084441f85SGarrett D'Amore static char *s; /* Current pointer inside string */ 21184441f85SGarrett D'Amore static char string_ident[30]; 21284441f85SGarrett D'Amore char *p; 21384441f85SGarrett D'Amore 21484441f85SGarrett D'Amore again: 21584441f85SGarrett D'Amore switch (state) { 21684441f85SGarrett D'Amore case ST_EOF: 21784441f85SGarrett D'Amore if (script == NULL) { 21884441f85SGarrett D'Amore if (more != NULL) 21984441f85SGarrett D'Amore *more = 0; 22084441f85SGarrett D'Amore return (NULL); 22184441f85SGarrett D'Amore } 22284441f85SGarrett D'Amore linenum = 0; 22384441f85SGarrett D'Amore switch (script->type) { 22484441f85SGarrett D'Amore case CU_FILE: 22584441f85SGarrett D'Amore if ((f = fopen(script->s, "r")) == NULL) 22684441f85SGarrett D'Amore err(1, "%s", script->s); 22784441f85SGarrett D'Amore fname = script->s; 22884441f85SGarrett D'Amore state = ST_FILE; 22984441f85SGarrett D'Amore goto again; 23084441f85SGarrett D'Amore case CU_STRING: 23184441f85SGarrett D'Amore if (((size_t)snprintf(string_ident, 23284441f85SGarrett D'Amore sizeof (string_ident), "\"%s\"", script->s)) >= 23384441f85SGarrett D'Amore sizeof (string_ident) - 1) 23484441f85SGarrett D'Amore (void) strcpy(string_ident + 23584441f85SGarrett D'Amore sizeof (string_ident) - 6, " ...\""); 23684441f85SGarrett D'Amore fname = string_ident; 23784441f85SGarrett D'Amore s = script->s; 23884441f85SGarrett D'Amore state = ST_STRING; 23984441f85SGarrett D'Amore goto again; 24084441f85SGarrett D'Amore } 24184441f85SGarrett D'Amore /*NOTREACHED*/ 24284441f85SGarrett D'Amore 24384441f85SGarrett D'Amore case ST_FILE: 24484441f85SGarrett D'Amore if ((p = fgets(buf, n, f)) != NULL) { 24584441f85SGarrett D'Amore linenum++; 24684441f85SGarrett D'Amore if (linenum == 1 && buf[0] == '#' && buf[1] == 'n') 24784441f85SGarrett D'Amore nflag = 1; 24884441f85SGarrett D'Amore if (more != NULL) 24984441f85SGarrett D'Amore *more = !feof(f); 25084441f85SGarrett D'Amore return (p); 25184441f85SGarrett D'Amore } 25284441f85SGarrett D'Amore script = script->next; 25384441f85SGarrett D'Amore (void) fclose(f); 25484441f85SGarrett D'Amore state = ST_EOF; 25584441f85SGarrett D'Amore goto again; 25684441f85SGarrett D'Amore case ST_STRING: 25784441f85SGarrett D'Amore if (linenum == 0 && s[0] == '#' && s[1] == 'n') 25884441f85SGarrett D'Amore nflag = 1; 25984441f85SGarrett D'Amore p = buf; 26084441f85SGarrett D'Amore for (;;) { 26184441f85SGarrett D'Amore if (n-- <= 1) { 26284441f85SGarrett D'Amore *p = '\0'; 26384441f85SGarrett D'Amore linenum++; 26484441f85SGarrett D'Amore if (more != NULL) 26584441f85SGarrett D'Amore *more = 1; 26684441f85SGarrett D'Amore return (buf); 26784441f85SGarrett D'Amore } 26884441f85SGarrett D'Amore switch (*s) { 26984441f85SGarrett D'Amore case '\0': 27084441f85SGarrett D'Amore state = ST_EOF; 27184441f85SGarrett D'Amore if (s == script->s) { 27284441f85SGarrett D'Amore script = script->next; 27384441f85SGarrett D'Amore goto again; 27484441f85SGarrett D'Amore } else { 27584441f85SGarrett D'Amore script = script->next; 27684441f85SGarrett D'Amore *p = '\0'; 27784441f85SGarrett D'Amore linenum++; 27884441f85SGarrett D'Amore if (more != NULL) 27984441f85SGarrett D'Amore *more = 0; 28084441f85SGarrett D'Amore return (buf); 28184441f85SGarrett D'Amore } 28284441f85SGarrett D'Amore case '\n': 28384441f85SGarrett D'Amore *p++ = '\n'; 28484441f85SGarrett D'Amore *p = '\0'; 28584441f85SGarrett D'Amore s++; 28684441f85SGarrett D'Amore linenum++; 28784441f85SGarrett D'Amore if (more != NULL) 28884441f85SGarrett D'Amore *more = 0; 28984441f85SGarrett D'Amore return (buf); 29084441f85SGarrett D'Amore default: 29184441f85SGarrett D'Amore *p++ = *s++; 29284441f85SGarrett D'Amore } 29384441f85SGarrett D'Amore } 29484441f85SGarrett D'Amore } 29584441f85SGarrett D'Amore /* NOTREACHED */ 29684441f85SGarrett D'Amore return (NULL); 29784441f85SGarrett D'Amore } 29884441f85SGarrett D'Amore 29984441f85SGarrett D'Amore /* 30084441f85SGarrett D'Amore * Like fgets, but go through the list of files chaining them together. 30184441f85SGarrett D'Amore * Set len to the length of the line. 30284441f85SGarrett D'Amore */ 30384441f85SGarrett D'Amore int 30484441f85SGarrett D'Amore mf_fgets(SPACE *sp, enum e_spflag spflag) 30584441f85SGarrett D'Amore { 306c530934aSGarrett D'Amore struct stat sb, nsb; 30784441f85SGarrett D'Amore size_t len; 30884441f85SGarrett D'Amore char *p; 30984441f85SGarrett D'Amore int c; 31084441f85SGarrett D'Amore static int firstfile; 31184441f85SGarrett D'Amore 31284441f85SGarrett D'Amore if (infile == NULL) { 31384441f85SGarrett D'Amore /* stdin? */ 31484441f85SGarrett D'Amore if (files->fname == NULL) { 31584441f85SGarrett D'Amore if (inplace != NULL) 31684441f85SGarrett D'Amore errx(1, 31784441f85SGarrett D'Amore _("-I or -i may not be used with stdin")); 31884441f85SGarrett D'Amore infile = stdin; 31984441f85SGarrett D'Amore fname = "stdin"; 32084441f85SGarrett D'Amore outfile = stdout; 32184441f85SGarrett D'Amore outfname = "stdout"; 32284441f85SGarrett D'Amore } 32384441f85SGarrett D'Amore firstfile = 1; 32484441f85SGarrett D'Amore } 32584441f85SGarrett D'Amore 32684441f85SGarrett D'Amore for (;;) { 32784441f85SGarrett D'Amore if (infile != NULL && (c = getc(infile)) != EOF) { 32884441f85SGarrett D'Amore (void) ungetc(c, infile); 32984441f85SGarrett D'Amore break; 33084441f85SGarrett D'Amore } 33184441f85SGarrett D'Amore /* If we are here then either eof or no files are open yet */ 33284441f85SGarrett D'Amore if (infile == stdin) { 33384441f85SGarrett D'Amore sp->len = 0; 33484441f85SGarrett D'Amore return (0); 33584441f85SGarrett D'Amore } 33684441f85SGarrett D'Amore if (infile != NULL) { 33784441f85SGarrett D'Amore (void) fclose(infile); 33884441f85SGarrett D'Amore if (*oldfname != '\0') { 339429d0af2SGarrett D'Amore /* if there was a backup file, remove it */ 340429d0af2SGarrett D'Amore (void) unlink(oldfname); 341c530934aSGarrett D'Amore /* 342c530934aSGarrett D'Amore * Backup the original. Note that hard links 343c530934aSGarrett D'Amore * are not supported on all filesystems. 344c530934aSGarrett D'Amore */ 345c530934aSGarrett D'Amore if ((link(fname, oldfname) != 0) && 346c530934aSGarrett D'Amore (rename(fname, oldfname) != 0)) { 347c530934aSGarrett D'Amore warn("rename()"); 348c530934aSGarrett D'Amore if (*tmpfname) 34984441f85SGarrett D'Amore (void) unlink(tmpfname); 35084441f85SGarrett D'Amore exit(1); 35184441f85SGarrett D'Amore } 35284441f85SGarrett D'Amore *oldfname = '\0'; 35384441f85SGarrett D'Amore } 35484441f85SGarrett D'Amore if (*tmpfname != '\0') { 35584441f85SGarrett D'Amore if (outfile != NULL && outfile != stdout) 35684441f85SGarrett D'Amore if (fclose(outfile) != 0) { 35784441f85SGarrett D'Amore warn("fclose()"); 35884441f85SGarrett D'Amore (void) unlink(tmpfname); 35984441f85SGarrett D'Amore exit(1); 36084441f85SGarrett D'Amore } 36184441f85SGarrett D'Amore outfile = NULL; 36284441f85SGarrett D'Amore if (rename(tmpfname, fname) != 0) { 36384441f85SGarrett D'Amore /* this should not happen really! */ 36484441f85SGarrett D'Amore warn("rename()"); 36584441f85SGarrett D'Amore (void) unlink(tmpfname); 36684441f85SGarrett D'Amore exit(1); 36784441f85SGarrett D'Amore } 36884441f85SGarrett D'Amore *tmpfname = '\0'; 36984441f85SGarrett D'Amore } 37084441f85SGarrett D'Amore outfname = NULL; 37184441f85SGarrett D'Amore } 37284441f85SGarrett D'Amore if (firstfile == 0) 37384441f85SGarrett D'Amore files = files->next; 37484441f85SGarrett D'Amore else 37584441f85SGarrett D'Amore firstfile = 0; 37684441f85SGarrett D'Amore if (files == NULL) { 37784441f85SGarrett D'Amore sp->len = 0; 37884441f85SGarrett D'Amore return (0); 37984441f85SGarrett D'Amore } 38084441f85SGarrett D'Amore fname = files->fname; 38184441f85SGarrett D'Amore if (inplace != NULL) { 38284441f85SGarrett D'Amore char bn[PATH_MAX]; 38384441f85SGarrett D'Amore char dn[PATH_MAX]; 38484441f85SGarrett D'Amore (void) strlcpy(bn, fname, sizeof (bn)); 38584441f85SGarrett D'Amore (void) strlcpy(dn, fname, sizeof (dn)); 38684441f85SGarrett D'Amore if (lstat(fname, &sb) != 0) 38784441f85SGarrett D'Amore err(1, "%s", fname); 38884441f85SGarrett D'Amore if (!(sb.st_mode & S_IFREG)) 38984441f85SGarrett D'Amore fatal(_("in-place editing only " 39084441f85SGarrett D'Amore "works for regular files")); 39184441f85SGarrett D'Amore if (*inplace != '\0') { 39284441f85SGarrett D'Amore (void) strlcpy(oldfname, fname, 39384441f85SGarrett D'Amore sizeof (oldfname)); 39484441f85SGarrett D'Amore len = strlcat(oldfname, inplace, 39584441f85SGarrett D'Amore sizeof (oldfname)); 39684441f85SGarrett D'Amore if (len > sizeof (oldfname)) 39784441f85SGarrett D'Amore fatal(_("name too long")); 39884441f85SGarrett D'Amore } 39984441f85SGarrett D'Amore len = snprintf(tmpfname, sizeof (tmpfname), 40084441f85SGarrett D'Amore "%s/.!%ld!%s", dirname(dn), (long)getpid(), 40184441f85SGarrett D'Amore basename(bn)); 40284441f85SGarrett D'Amore if (len >= sizeof (tmpfname)) 40384441f85SGarrett D'Amore fatal(_("name too long")); 40484441f85SGarrett D'Amore (void) unlink(tmpfname); 40584441f85SGarrett D'Amore if ((outfile = fopen(tmpfname, "w")) == NULL) 40684441f85SGarrett D'Amore err(1, "%s", fname); 407c530934aSGarrett D'Amore /* 408c530934aSGarrett D'Amore * Some file systems don't support chown or 409c530934aSGarrett D'Amore * chmod fully. On those, the owner/group and 410c530934aSGarrett D'Amore * permissions will already be set to what 411c530934aSGarrett D'Amore * they need to be. 412c530934aSGarrett D'Amore */ 413c530934aSGarrett D'Amore if (fstat(fileno(outfile), &nsb) != 0) { 414c530934aSGarrett D'Amore warn("fstat()"); 415c530934aSGarrett D'Amore } 416c530934aSGarrett D'Amore if (((sb.st_uid != nsb.st_uid) || 417c530934aSGarrett D'Amore (sb.st_gid != nsb.st_gid)) && 418c530934aSGarrett D'Amore (fchown(fileno(outfile), sb.st_uid, sb.st_gid) 419c530934aSGarrett D'Amore != 0)) 42084441f85SGarrett D'Amore warn("fchown()"); 421c530934aSGarrett D'Amore if ((sb.st_mode != nsb.st_mode) && 422c530934aSGarrett D'Amore (fchmod(fileno(outfile), sb.st_mode & 07777) != 0)) 42384441f85SGarrett D'Amore warn("fchmod()"); 42484441f85SGarrett D'Amore outfname = tmpfname; 42584441f85SGarrett D'Amore if (!ispan) { 42684441f85SGarrett D'Amore linenum = 0; 42784441f85SGarrett D'Amore resetstate(); 42884441f85SGarrett D'Amore } 42984441f85SGarrett D'Amore } else { 43084441f85SGarrett D'Amore outfile = stdout; 43184441f85SGarrett D'Amore outfname = "stdout"; 43284441f85SGarrett D'Amore } 43384441f85SGarrett D'Amore if ((infile = fopen(fname, "r")) == NULL) { 43484441f85SGarrett D'Amore warn("%s", fname); 43584441f85SGarrett D'Amore rval = 1; 43684441f85SGarrett D'Amore continue; 43784441f85SGarrett D'Amore } 43884441f85SGarrett D'Amore } 43984441f85SGarrett D'Amore /* 44084441f85SGarrett D'Amore * We are here only when infile is open and we still have something 44184441f85SGarrett D'Amore * to read from it. 44284441f85SGarrett D'Amore * 44384441f85SGarrett D'Amore * Use fgetln so that we can handle essentially infinite input data. 44484441f85SGarrett D'Amore * Can't use the pointer into the stdio buffer as the process space 44584441f85SGarrett D'Amore * because the ungetc() can cause it to move. 44684441f85SGarrett D'Amore */ 44784441f85SGarrett D'Amore p = getln(infile, &len); 44884441f85SGarrett D'Amore if (ferror(infile)) 44984441f85SGarrett D'Amore errx(1, "%s: %s", fname, strerror(errno ? errno : EIO)); 45084441f85SGarrett D'Amore if (len != 0 && p[len - 1] == '\n') 45184441f85SGarrett D'Amore len--; 45284441f85SGarrett D'Amore cspace(sp, p, len, spflag); 45384441f85SGarrett D'Amore 45484441f85SGarrett D'Amore linenum++; 45584441f85SGarrett D'Amore 45684441f85SGarrett D'Amore return (1); 45784441f85SGarrett D'Amore } 45884441f85SGarrett D'Amore 45984441f85SGarrett D'Amore /* 46084441f85SGarrett D'Amore * Add a compilation unit to the linked list 46184441f85SGarrett D'Amore */ 46284441f85SGarrett D'Amore static void 46384441f85SGarrett D'Amore add_compunit(enum e_cut type, char *s) 46484441f85SGarrett D'Amore { 46584441f85SGarrett D'Amore struct s_compunit *cu; 46684441f85SGarrett D'Amore 46784441f85SGarrett D'Amore if ((cu = malloc(sizeof (struct s_compunit))) == NULL) 46884441f85SGarrett D'Amore err(1, "malloc"); 46984441f85SGarrett D'Amore cu->type = type; 47084441f85SGarrett D'Amore cu->s = s; 47184441f85SGarrett D'Amore cu->next = NULL; 47284441f85SGarrett D'Amore *cu_nextp = cu; 47384441f85SGarrett D'Amore cu_nextp = &cu->next; 47484441f85SGarrett D'Amore } 47584441f85SGarrett D'Amore 47684441f85SGarrett D'Amore /* 47784441f85SGarrett D'Amore * Add a file to the linked list 47884441f85SGarrett D'Amore */ 47984441f85SGarrett D'Amore static void 48084441f85SGarrett D'Amore add_file(char *s) 48184441f85SGarrett D'Amore { 48284441f85SGarrett D'Amore struct s_flist *fp; 48384441f85SGarrett D'Amore 48484441f85SGarrett D'Amore if ((fp = malloc(sizeof (struct s_flist))) == NULL) 48584441f85SGarrett D'Amore err(1, "malloc"); 48684441f85SGarrett D'Amore fp->next = NULL; 48784441f85SGarrett D'Amore *fl_nextp = fp; 48884441f85SGarrett D'Amore fp->fname = s; 48984441f85SGarrett D'Amore fl_nextp = &fp->next; 49084441f85SGarrett D'Amore } 49184441f85SGarrett D'Amore 49284441f85SGarrett D'Amore int 49384441f85SGarrett D'Amore lastline(void) 49484441f85SGarrett D'Amore { 49584441f85SGarrett D'Amore int ch; 49684441f85SGarrett D'Amore 49784441f85SGarrett D'Amore if (files->next != NULL && (inplace == NULL || ispan)) 49884441f85SGarrett D'Amore return (0); 49984441f85SGarrett D'Amore if ((ch = getc(infile)) == EOF) 50084441f85SGarrett D'Amore return (1); 50184441f85SGarrett D'Amore (void) ungetc(ch, infile); 50284441f85SGarrett D'Amore return (0); 50384441f85SGarrett D'Amore } 50484441f85SGarrett D'Amore 50584441f85SGarrett D'Amore char * 50684441f85SGarrett D'Amore getln(FILE *in, size_t *lenp) 50784441f85SGarrett D'Amore { 50884441f85SGarrett D'Amore static char *buffer = NULL; 50984441f85SGarrett D'Amore static size_t sz = 0; 51084441f85SGarrett D'Amore 51184441f85SGarrett D'Amore size_t len = 0; 51284441f85SGarrett D'Amore 51384441f85SGarrett D'Amore for (;;) { 51484441f85SGarrett D'Amore if (sz <= (len + 1)) { 51584441f85SGarrett D'Amore char *nb; 51684441f85SGarrett D'Amore if ((nb = realloc(buffer, sz + LINE_MAX)) == NULL) { 51784441f85SGarrett D'Amore err(1, "realloc"); 51884441f85SGarrett D'Amore } 51984441f85SGarrett D'Amore buffer = nb; 52084441f85SGarrett D'Amore sz += LINE_MAX; 52184441f85SGarrett D'Amore } 52284441f85SGarrett D'Amore 52384441f85SGarrett D'Amore buffer[len] = 0; 52484441f85SGarrett D'Amore 52584441f85SGarrett D'Amore if (fgets(buffer + len, sz - len, in) == NULL) { 52684441f85SGarrett D'Amore /* END OF FILE */ 52784441f85SGarrett D'Amore *lenp = len; 52884441f85SGarrett D'Amore break; 52984441f85SGarrett D'Amore } 53084441f85SGarrett D'Amore 53184441f85SGarrett D'Amore len += strlen(buffer + len); 53284441f85SGarrett D'Amore 53384441f85SGarrett D'Amore if (buffer[len - 1] == '\n') { 53484441f85SGarrett D'Amore /* got the new line */ 53584441f85SGarrett D'Amore *lenp = len; 53684441f85SGarrett D'Amore break; 53784441f85SGarrett D'Amore } 53884441f85SGarrett D'Amore } 53984441f85SGarrett D'Amore 54084441f85SGarrett D'Amore return (buffer); 54184441f85SGarrett D'Amore } 542