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