1*84441f85SGarrett D'Amore /* 2*84441f85SGarrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 3*84441f85SGarrett D'Amore * Copyright (c) 1992 Diomidis Spinellis. 4*84441f85SGarrett D'Amore * Copyright (c) 1992, 1993 5*84441f85SGarrett D'Amore * The Regents of the University of California. All rights reserved. 6*84441f85SGarrett D'Amore * 7*84441f85SGarrett D'Amore * This code is derived from software contributed to Berkeley by 8*84441f85SGarrett D'Amore * Diomidis Spinellis of Imperial College, University of London. 9*84441f85SGarrett D'Amore * 10*84441f85SGarrett D'Amore * Redistribution and use in source and binary forms, with or without 11*84441f85SGarrett D'Amore * modification, are permitted provided that the following conditions 12*84441f85SGarrett D'Amore * are met: 13*84441f85SGarrett D'Amore * 1. Redistributions of source code must retain the above copyright 14*84441f85SGarrett D'Amore * notice, this list of conditions and the following disclaimer. 15*84441f85SGarrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright 16*84441f85SGarrett D'Amore * notice, this list of conditions and the following disclaimer in the 17*84441f85SGarrett D'Amore * documentation and/or other materials provided with the distribution. 18*84441f85SGarrett D'Amore * 4. Neither the name of the University nor the names of its contributors 19*84441f85SGarrett D'Amore * may be used to endorse or promote products derived from this software 20*84441f85SGarrett D'Amore * without specific prior written permission. 21*84441f85SGarrett D'Amore * 22*84441f85SGarrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23*84441f85SGarrett D'Amore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24*84441f85SGarrett D'Amore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25*84441f85SGarrett D'Amore * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26*84441f85SGarrett D'Amore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27*84441f85SGarrett D'Amore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28*84441f85SGarrett D'Amore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29*84441f85SGarrett D'Amore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30*84441f85SGarrett D'Amore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31*84441f85SGarrett D'Amore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32*84441f85SGarrett D'Amore * SUCH DAMAGE. 33*84441f85SGarrett D'Amore */ 34*84441f85SGarrett D'Amore 35*84441f85SGarrett D'Amore #include <sys/types.h> 36*84441f85SGarrett D'Amore #include <sys/mman.h> 37*84441f85SGarrett D'Amore #include <sys/param.h> 38*84441f85SGarrett D'Amore #include <sys/stat.h> 39*84441f85SGarrett D'Amore 40*84441f85SGarrett D'Amore #include <err.h> 41*84441f85SGarrett D'Amore #include <errno.h> 42*84441f85SGarrett D'Amore #include <fcntl.h> 43*84441f85SGarrett D'Amore #include <libgen.h> 44*84441f85SGarrett D'Amore #include <limits.h> 45*84441f85SGarrett D'Amore #include <locale.h> 46*84441f85SGarrett D'Amore #include <regex.h> 47*84441f85SGarrett D'Amore #include <stddef.h> 48*84441f85SGarrett D'Amore #include <stdio.h> 49*84441f85SGarrett D'Amore #include <stdlib.h> 50*84441f85SGarrett D'Amore #include <string.h> 51*84441f85SGarrett D'Amore #include <unistd.h> 52*84441f85SGarrett D'Amore #include <libintl.h> 53*84441f85SGarrett D'Amore 54*84441f85SGarrett D'Amore #include "defs.h" 55*84441f85SGarrett D'Amore #include "extern.h" 56*84441f85SGarrett D'Amore 57*84441f85SGarrett D'Amore /* 58*84441f85SGarrett D'Amore * Linked list of units (strings and files) to be compiled 59*84441f85SGarrett D'Amore */ 60*84441f85SGarrett D'Amore struct s_compunit { 61*84441f85SGarrett D'Amore struct s_compunit *next; 62*84441f85SGarrett D'Amore enum e_cut {CU_FILE, CU_STRING} type; 63*84441f85SGarrett D'Amore char *s; /* Pointer to string or fname */ 64*84441f85SGarrett D'Amore }; 65*84441f85SGarrett D'Amore 66*84441f85SGarrett D'Amore /* 67*84441f85SGarrett D'Amore * Linked list pointer to compilation units and pointer to current 68*84441f85SGarrett D'Amore * next pointer. 69*84441f85SGarrett D'Amore */ 70*84441f85SGarrett D'Amore static struct s_compunit *script, **cu_nextp = &script; 71*84441f85SGarrett D'Amore 72*84441f85SGarrett D'Amore /* 73*84441f85SGarrett D'Amore * Linked list of files to be processed 74*84441f85SGarrett D'Amore */ 75*84441f85SGarrett D'Amore struct s_flist { 76*84441f85SGarrett D'Amore char *fname; 77*84441f85SGarrett D'Amore struct s_flist *next; 78*84441f85SGarrett D'Amore }; 79*84441f85SGarrett D'Amore 80*84441f85SGarrett D'Amore /* 81*84441f85SGarrett D'Amore * Linked list pointer to files and pointer to current 82*84441f85SGarrett D'Amore * next pointer. 83*84441f85SGarrett D'Amore */ 84*84441f85SGarrett D'Amore static struct s_flist *files, **fl_nextp = &files; 85*84441f85SGarrett D'Amore 86*84441f85SGarrett D'Amore FILE *infile; /* Current input file */ 87*84441f85SGarrett D'Amore FILE *outfile; /* Current output file */ 88*84441f85SGarrett D'Amore 89*84441f85SGarrett D'Amore int aflag, eflag, nflag; 90*84441f85SGarrett D'Amore int rflags = 0; 91*84441f85SGarrett D'Amore static int rval; /* Exit status */ 92*84441f85SGarrett D'Amore 93*84441f85SGarrett D'Amore static int ispan; /* Whether inplace editing spans across files */ 94*84441f85SGarrett D'Amore 95*84441f85SGarrett D'Amore /* 96*84441f85SGarrett D'Amore * Current file and line number; line numbers restart across compilation 97*84441f85SGarrett D'Amore * units, but span across input files. The latter is optional if editing 98*84441f85SGarrett D'Amore * in place. 99*84441f85SGarrett D'Amore */ 100*84441f85SGarrett D'Amore const char *fname; /* File name. */ 101*84441f85SGarrett D'Amore const char *outfname; /* Output file name */ 102*84441f85SGarrett D'Amore static char oldfname[PATH_MAX]; /* Old file name (for in-place editing) */ 103*84441f85SGarrett D'Amore static char tmpfname[PATH_MAX]; /* Temporary file name (for in-place editing) */ 104*84441f85SGarrett D'Amore static const char *inplace; /* Inplace edit file extension. */ 105*84441f85SGarrett D'Amore ulong_t linenum; 106*84441f85SGarrett D'Amore 107*84441f85SGarrett D'Amore static void add_compunit(enum e_cut, char *); 108*84441f85SGarrett D'Amore static void add_file(char *); 109*84441f85SGarrett D'Amore static void usage(void); 110*84441f85SGarrett D'Amore static char *getln(FILE *, size_t *); 111*84441f85SGarrett D'Amore 112*84441f85SGarrett D'Amore 113*84441f85SGarrett D'Amore int 114*84441f85SGarrett D'Amore main(int argc, char *argv[]) 115*84441f85SGarrett D'Amore { 116*84441f85SGarrett D'Amore int c, fflag; 117*84441f85SGarrett D'Amore char *temp_arg; 118*84441f85SGarrett D'Amore 119*84441f85SGarrett D'Amore (void) setlocale(LC_ALL, ""); 120*84441f85SGarrett D'Amore 121*84441f85SGarrett D'Amore #ifndef TEXT_DOMAIN 122*84441f85SGarrett D'Amore #define TEXT_DOMAIN "SYS_TEST" 123*84441f85SGarrett D'Amore #endif 124*84441f85SGarrett D'Amore (void) textdomain(TEXT_DOMAIN); 125*84441f85SGarrett D'Amore 126*84441f85SGarrett D'Amore fflag = 0; 127*84441f85SGarrett D'Amore inplace = NULL; 128*84441f85SGarrett D'Amore 129*84441f85SGarrett D'Amore while ((c = getopt(argc, argv, "EI:ae:f:i:lnr")) != -1) 130*84441f85SGarrett D'Amore switch (c) { 131*84441f85SGarrett D'Amore case 'r': /* Gnu sed compat */ 132*84441f85SGarrett D'Amore case 'E': 133*84441f85SGarrett D'Amore rflags = REG_EXTENDED; 134*84441f85SGarrett D'Amore break; 135*84441f85SGarrett D'Amore case 'I': 136*84441f85SGarrett D'Amore inplace = optarg; 137*84441f85SGarrett D'Amore ispan = 1; /* span across input files */ 138*84441f85SGarrett D'Amore break; 139*84441f85SGarrett D'Amore case 'a': 140*84441f85SGarrett D'Amore aflag = 1; 141*84441f85SGarrett D'Amore break; 142*84441f85SGarrett D'Amore case 'e': 143*84441f85SGarrett D'Amore eflag = 1; 144*84441f85SGarrett D'Amore if (asprintf(&temp_arg, "%s\n", optarg) <= 1) 145*84441f85SGarrett D'Amore err(1, "asprintf"); 146*84441f85SGarrett D'Amore add_compunit(CU_STRING, temp_arg); 147*84441f85SGarrett D'Amore break; 148*84441f85SGarrett D'Amore case 'f': 149*84441f85SGarrett D'Amore fflag = 1; 150*84441f85SGarrett D'Amore add_compunit(CU_FILE, optarg); 151*84441f85SGarrett D'Amore break; 152*84441f85SGarrett D'Amore case 'i': 153*84441f85SGarrett D'Amore inplace = optarg; 154*84441f85SGarrett D'Amore ispan = 0; /* don't span across input files */ 155*84441f85SGarrett D'Amore break; 156*84441f85SGarrett D'Amore case 'l': 157*84441f85SGarrett D'Amore /* On SunOS, setlinebuf "returns no useful value */ 158*84441f85SGarrett D'Amore (void) setlinebuf(stdout); 159*84441f85SGarrett D'Amore break; 160*84441f85SGarrett D'Amore case 'n': 161*84441f85SGarrett D'Amore nflag = 1; 162*84441f85SGarrett D'Amore break; 163*84441f85SGarrett D'Amore default: 164*84441f85SGarrett D'Amore case '?': 165*84441f85SGarrett D'Amore usage(); 166*84441f85SGarrett D'Amore } 167*84441f85SGarrett D'Amore argc -= optind; 168*84441f85SGarrett D'Amore argv += optind; 169*84441f85SGarrett D'Amore 170*84441f85SGarrett D'Amore /* First usage case; script is the first arg */ 171*84441f85SGarrett D'Amore if (!eflag && !fflag && *argv) { 172*84441f85SGarrett D'Amore add_compunit(CU_STRING, *argv); 173*84441f85SGarrett D'Amore argv++; 174*84441f85SGarrett D'Amore } 175*84441f85SGarrett D'Amore 176*84441f85SGarrett D'Amore compile(); 177*84441f85SGarrett D'Amore 178*84441f85SGarrett D'Amore /* Continue with first and start second usage */ 179*84441f85SGarrett D'Amore if (*argv) 180*84441f85SGarrett D'Amore for (; *argv; argv++) 181*84441f85SGarrett D'Amore add_file(*argv); 182*84441f85SGarrett D'Amore else 183*84441f85SGarrett D'Amore add_file(NULL); 184*84441f85SGarrett D'Amore process(); 185*84441f85SGarrett D'Amore cfclose(prog, NULL); 186*84441f85SGarrett D'Amore if (fclose(stdout)) 187*84441f85SGarrett D'Amore err(1, "stdout"); 188*84441f85SGarrett D'Amore return (rval); 189*84441f85SGarrett D'Amore } 190*84441f85SGarrett D'Amore 191*84441f85SGarrett D'Amore static void 192*84441f85SGarrett D'Amore usage(void) 193*84441f85SGarrett D'Amore { 194*84441f85SGarrett D'Amore (void) fputs(_("usage: sed script [-Ealn] [-i extension] [file ...]\n" 195*84441f85SGarrett D'Amore " sed [-Ealn] [-i extension] [-e script] ... " 196*84441f85SGarrett D'Amore "[-f script_file] ... [file ...]"), 197*84441f85SGarrett D'Amore stderr); 198*84441f85SGarrett D'Amore exit(1); 199*84441f85SGarrett D'Amore } 200*84441f85SGarrett D'Amore 201*84441f85SGarrett D'Amore /* 202*84441f85SGarrett D'Amore * Like fgets, but go through the chain of compilation units chaining them 203*84441f85SGarrett D'Amore * together. Empty strings and files are ignored. 204*84441f85SGarrett D'Amore */ 205*84441f85SGarrett D'Amore char * 206*84441f85SGarrett D'Amore cu_fgets(char *buf, int n, int *more) 207*84441f85SGarrett D'Amore { 208*84441f85SGarrett D'Amore static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF; 209*84441f85SGarrett D'Amore static FILE *f; /* Current open file */ 210*84441f85SGarrett D'Amore static char *s; /* Current pointer inside string */ 211*84441f85SGarrett D'Amore static char string_ident[30]; 212*84441f85SGarrett D'Amore char *p; 213*84441f85SGarrett D'Amore 214*84441f85SGarrett D'Amore again: 215*84441f85SGarrett D'Amore switch (state) { 216*84441f85SGarrett D'Amore case ST_EOF: 217*84441f85SGarrett D'Amore if (script == NULL) { 218*84441f85SGarrett D'Amore if (more != NULL) 219*84441f85SGarrett D'Amore *more = 0; 220*84441f85SGarrett D'Amore return (NULL); 221*84441f85SGarrett D'Amore } 222*84441f85SGarrett D'Amore linenum = 0; 223*84441f85SGarrett D'Amore switch (script->type) { 224*84441f85SGarrett D'Amore case CU_FILE: 225*84441f85SGarrett D'Amore if ((f = fopen(script->s, "r")) == NULL) 226*84441f85SGarrett D'Amore err(1, "%s", script->s); 227*84441f85SGarrett D'Amore fname = script->s; 228*84441f85SGarrett D'Amore state = ST_FILE; 229*84441f85SGarrett D'Amore goto again; 230*84441f85SGarrett D'Amore case CU_STRING: 231*84441f85SGarrett D'Amore if (((size_t)snprintf(string_ident, 232*84441f85SGarrett D'Amore sizeof (string_ident), "\"%s\"", script->s)) >= 233*84441f85SGarrett D'Amore sizeof (string_ident) - 1) 234*84441f85SGarrett D'Amore (void) strcpy(string_ident + 235*84441f85SGarrett D'Amore sizeof (string_ident) - 6, " ...\""); 236*84441f85SGarrett D'Amore fname = string_ident; 237*84441f85SGarrett D'Amore s = script->s; 238*84441f85SGarrett D'Amore state = ST_STRING; 239*84441f85SGarrett D'Amore goto again; 240*84441f85SGarrett D'Amore } 241*84441f85SGarrett D'Amore /*NOTREACHED*/ 242*84441f85SGarrett D'Amore 243*84441f85SGarrett D'Amore case ST_FILE: 244*84441f85SGarrett D'Amore if ((p = fgets(buf, n, f)) != NULL) { 245*84441f85SGarrett D'Amore linenum++; 246*84441f85SGarrett D'Amore if (linenum == 1 && buf[0] == '#' && buf[1] == 'n') 247*84441f85SGarrett D'Amore nflag = 1; 248*84441f85SGarrett D'Amore if (more != NULL) 249*84441f85SGarrett D'Amore *more = !feof(f); 250*84441f85SGarrett D'Amore return (p); 251*84441f85SGarrett D'Amore } 252*84441f85SGarrett D'Amore script = script->next; 253*84441f85SGarrett D'Amore (void) fclose(f); 254*84441f85SGarrett D'Amore state = ST_EOF; 255*84441f85SGarrett D'Amore goto again; 256*84441f85SGarrett D'Amore case ST_STRING: 257*84441f85SGarrett D'Amore if (linenum == 0 && s[0] == '#' && s[1] == 'n') 258*84441f85SGarrett D'Amore nflag = 1; 259*84441f85SGarrett D'Amore p = buf; 260*84441f85SGarrett D'Amore for (;;) { 261*84441f85SGarrett D'Amore if (n-- <= 1) { 262*84441f85SGarrett D'Amore *p = '\0'; 263*84441f85SGarrett D'Amore linenum++; 264*84441f85SGarrett D'Amore if (more != NULL) 265*84441f85SGarrett D'Amore *more = 1; 266*84441f85SGarrett D'Amore return (buf); 267*84441f85SGarrett D'Amore } 268*84441f85SGarrett D'Amore switch (*s) { 269*84441f85SGarrett D'Amore case '\0': 270*84441f85SGarrett D'Amore state = ST_EOF; 271*84441f85SGarrett D'Amore if (s == script->s) { 272*84441f85SGarrett D'Amore script = script->next; 273*84441f85SGarrett D'Amore goto again; 274*84441f85SGarrett D'Amore } else { 275*84441f85SGarrett D'Amore script = script->next; 276*84441f85SGarrett D'Amore *p = '\0'; 277*84441f85SGarrett D'Amore linenum++; 278*84441f85SGarrett D'Amore if (more != NULL) 279*84441f85SGarrett D'Amore *more = 0; 280*84441f85SGarrett D'Amore return (buf); 281*84441f85SGarrett D'Amore } 282*84441f85SGarrett D'Amore case '\n': 283*84441f85SGarrett D'Amore *p++ = '\n'; 284*84441f85SGarrett D'Amore *p = '\0'; 285*84441f85SGarrett D'Amore s++; 286*84441f85SGarrett D'Amore linenum++; 287*84441f85SGarrett D'Amore if (more != NULL) 288*84441f85SGarrett D'Amore *more = 0; 289*84441f85SGarrett D'Amore return (buf); 290*84441f85SGarrett D'Amore default: 291*84441f85SGarrett D'Amore *p++ = *s++; 292*84441f85SGarrett D'Amore } 293*84441f85SGarrett D'Amore } 294*84441f85SGarrett D'Amore } 295*84441f85SGarrett D'Amore /* NOTREACHED */ 296*84441f85SGarrett D'Amore return (NULL); 297*84441f85SGarrett D'Amore } 298*84441f85SGarrett D'Amore 299*84441f85SGarrett D'Amore /* 300*84441f85SGarrett D'Amore * Like fgets, but go through the list of files chaining them together. 301*84441f85SGarrett D'Amore * Set len to the length of the line. 302*84441f85SGarrett D'Amore */ 303*84441f85SGarrett D'Amore int 304*84441f85SGarrett D'Amore mf_fgets(SPACE *sp, enum e_spflag spflag) 305*84441f85SGarrett D'Amore { 306*84441f85SGarrett D'Amore struct stat sb; 307*84441f85SGarrett D'Amore size_t len; 308*84441f85SGarrett D'Amore char *p; 309*84441f85SGarrett D'Amore int c; 310*84441f85SGarrett D'Amore static int firstfile; 311*84441f85SGarrett D'Amore 312*84441f85SGarrett D'Amore if (infile == NULL) { 313*84441f85SGarrett D'Amore /* stdin? */ 314*84441f85SGarrett D'Amore if (files->fname == NULL) { 315*84441f85SGarrett D'Amore if (inplace != NULL) 316*84441f85SGarrett D'Amore errx(1, 317*84441f85SGarrett D'Amore _("-I or -i may not be used with stdin")); 318*84441f85SGarrett D'Amore infile = stdin; 319*84441f85SGarrett D'Amore fname = "stdin"; 320*84441f85SGarrett D'Amore outfile = stdout; 321*84441f85SGarrett D'Amore outfname = "stdout"; 322*84441f85SGarrett D'Amore } 323*84441f85SGarrett D'Amore firstfile = 1; 324*84441f85SGarrett D'Amore } 325*84441f85SGarrett D'Amore 326*84441f85SGarrett D'Amore for (;;) { 327*84441f85SGarrett D'Amore if (infile != NULL && (c = getc(infile)) != EOF) { 328*84441f85SGarrett D'Amore (void) ungetc(c, infile); 329*84441f85SGarrett D'Amore break; 330*84441f85SGarrett D'Amore } 331*84441f85SGarrett D'Amore /* If we are here then either eof or no files are open yet */ 332*84441f85SGarrett D'Amore if (infile == stdin) { 333*84441f85SGarrett D'Amore sp->len = 0; 334*84441f85SGarrett D'Amore return (0); 335*84441f85SGarrett D'Amore } 336*84441f85SGarrett D'Amore if (infile != NULL) { 337*84441f85SGarrett D'Amore (void) fclose(infile); 338*84441f85SGarrett D'Amore if (*oldfname != '\0') { 339*84441f85SGarrett D'Amore if (link(fname, oldfname) != 0) { 340*84441f85SGarrett D'Amore warn("link()"); 341*84441f85SGarrett D'Amore (void) unlink(tmpfname); 342*84441f85SGarrett D'Amore exit(1); 343*84441f85SGarrett D'Amore } 344*84441f85SGarrett D'Amore *oldfname = '\0'; 345*84441f85SGarrett D'Amore } 346*84441f85SGarrett D'Amore if (*tmpfname != '\0') { 347*84441f85SGarrett D'Amore if (outfile != NULL && outfile != stdout) 348*84441f85SGarrett D'Amore if (fclose(outfile) != 0) { 349*84441f85SGarrett D'Amore warn("fclose()"); 350*84441f85SGarrett D'Amore (void) unlink(tmpfname); 351*84441f85SGarrett D'Amore exit(1); 352*84441f85SGarrett D'Amore } 353*84441f85SGarrett D'Amore outfile = NULL; 354*84441f85SGarrett D'Amore if (rename(tmpfname, fname) != 0) { 355*84441f85SGarrett D'Amore /* this should not happen really! */ 356*84441f85SGarrett D'Amore warn("rename()"); 357*84441f85SGarrett D'Amore (void) unlink(tmpfname); 358*84441f85SGarrett D'Amore exit(1); 359*84441f85SGarrett D'Amore } 360*84441f85SGarrett D'Amore *tmpfname = '\0'; 361*84441f85SGarrett D'Amore } 362*84441f85SGarrett D'Amore outfname = NULL; 363*84441f85SGarrett D'Amore } 364*84441f85SGarrett D'Amore if (firstfile == 0) 365*84441f85SGarrett D'Amore files = files->next; 366*84441f85SGarrett D'Amore else 367*84441f85SGarrett D'Amore firstfile = 0; 368*84441f85SGarrett D'Amore if (files == NULL) { 369*84441f85SGarrett D'Amore sp->len = 0; 370*84441f85SGarrett D'Amore return (0); 371*84441f85SGarrett D'Amore } 372*84441f85SGarrett D'Amore fname = files->fname; 373*84441f85SGarrett D'Amore if (inplace != NULL) { 374*84441f85SGarrett D'Amore char bn[PATH_MAX]; 375*84441f85SGarrett D'Amore char dn[PATH_MAX]; 376*84441f85SGarrett D'Amore (void) strlcpy(bn, fname, sizeof (bn)); 377*84441f85SGarrett D'Amore (void) strlcpy(dn, fname, sizeof (dn)); 378*84441f85SGarrett D'Amore if (lstat(fname, &sb) != 0) 379*84441f85SGarrett D'Amore err(1, "%s", fname); 380*84441f85SGarrett D'Amore if (!(sb.st_mode & S_IFREG)) 381*84441f85SGarrett D'Amore fatal(_("in-place editing only " 382*84441f85SGarrett D'Amore "works for regular files")); 383*84441f85SGarrett D'Amore if (*inplace != '\0') { 384*84441f85SGarrett D'Amore (void) strlcpy(oldfname, fname, 385*84441f85SGarrett D'Amore sizeof (oldfname)); 386*84441f85SGarrett D'Amore len = strlcat(oldfname, inplace, 387*84441f85SGarrett D'Amore sizeof (oldfname)); 388*84441f85SGarrett D'Amore if (len > sizeof (oldfname)) 389*84441f85SGarrett D'Amore fatal(_("name too long")); 390*84441f85SGarrett D'Amore } 391*84441f85SGarrett D'Amore len = snprintf(tmpfname, sizeof (tmpfname), 392*84441f85SGarrett D'Amore "%s/.!%ld!%s", dirname(dn), (long)getpid(), 393*84441f85SGarrett D'Amore basename(bn)); 394*84441f85SGarrett D'Amore if (len >= sizeof (tmpfname)) 395*84441f85SGarrett D'Amore fatal(_("name too long")); 396*84441f85SGarrett D'Amore (void) unlink(tmpfname); 397*84441f85SGarrett D'Amore if ((outfile = fopen(tmpfname, "w")) == NULL) 398*84441f85SGarrett D'Amore err(1, "%s", fname); 399*84441f85SGarrett D'Amore if (fchown(fileno(outfile), sb.st_uid, sb.st_gid) != 0) 400*84441f85SGarrett D'Amore warn("fchown()"); 401*84441f85SGarrett D'Amore if (fchmod(fileno(outfile), sb.st_mode & 07777) != 0) 402*84441f85SGarrett D'Amore warn("fchmod()"); 403*84441f85SGarrett D'Amore outfname = tmpfname; 404*84441f85SGarrett D'Amore if (!ispan) { 405*84441f85SGarrett D'Amore linenum = 0; 406*84441f85SGarrett D'Amore resetstate(); 407*84441f85SGarrett D'Amore } 408*84441f85SGarrett D'Amore } else { 409*84441f85SGarrett D'Amore outfile = stdout; 410*84441f85SGarrett D'Amore outfname = "stdout"; 411*84441f85SGarrett D'Amore } 412*84441f85SGarrett D'Amore if ((infile = fopen(fname, "r")) == NULL) { 413*84441f85SGarrett D'Amore warn("%s", fname); 414*84441f85SGarrett D'Amore rval = 1; 415*84441f85SGarrett D'Amore continue; 416*84441f85SGarrett D'Amore } 417*84441f85SGarrett D'Amore } 418*84441f85SGarrett D'Amore /* 419*84441f85SGarrett D'Amore * We are here only when infile is open and we still have something 420*84441f85SGarrett D'Amore * to read from it. 421*84441f85SGarrett D'Amore * 422*84441f85SGarrett D'Amore * Use fgetln so that we can handle essentially infinite input data. 423*84441f85SGarrett D'Amore * Can't use the pointer into the stdio buffer as the process space 424*84441f85SGarrett D'Amore * because the ungetc() can cause it to move. 425*84441f85SGarrett D'Amore */ 426*84441f85SGarrett D'Amore p = getln(infile, &len); 427*84441f85SGarrett D'Amore if (ferror(infile)) 428*84441f85SGarrett D'Amore errx(1, "%s: %s", fname, strerror(errno ? errno : EIO)); 429*84441f85SGarrett D'Amore if (len != 0 && p[len - 1] == '\n') 430*84441f85SGarrett D'Amore len--; 431*84441f85SGarrett D'Amore cspace(sp, p, len, spflag); 432*84441f85SGarrett D'Amore 433*84441f85SGarrett D'Amore linenum++; 434*84441f85SGarrett D'Amore 435*84441f85SGarrett D'Amore return (1); 436*84441f85SGarrett D'Amore } 437*84441f85SGarrett D'Amore 438*84441f85SGarrett D'Amore /* 439*84441f85SGarrett D'Amore * Add a compilation unit to the linked list 440*84441f85SGarrett D'Amore */ 441*84441f85SGarrett D'Amore static void 442*84441f85SGarrett D'Amore add_compunit(enum e_cut type, char *s) 443*84441f85SGarrett D'Amore { 444*84441f85SGarrett D'Amore struct s_compunit *cu; 445*84441f85SGarrett D'Amore 446*84441f85SGarrett D'Amore if ((cu = malloc(sizeof (struct s_compunit))) == NULL) 447*84441f85SGarrett D'Amore err(1, "malloc"); 448*84441f85SGarrett D'Amore cu->type = type; 449*84441f85SGarrett D'Amore cu->s = s; 450*84441f85SGarrett D'Amore cu->next = NULL; 451*84441f85SGarrett D'Amore *cu_nextp = cu; 452*84441f85SGarrett D'Amore cu_nextp = &cu->next; 453*84441f85SGarrett D'Amore } 454*84441f85SGarrett D'Amore 455*84441f85SGarrett D'Amore /* 456*84441f85SGarrett D'Amore * Add a file to the linked list 457*84441f85SGarrett D'Amore */ 458*84441f85SGarrett D'Amore static void 459*84441f85SGarrett D'Amore add_file(char *s) 460*84441f85SGarrett D'Amore { 461*84441f85SGarrett D'Amore struct s_flist *fp; 462*84441f85SGarrett D'Amore 463*84441f85SGarrett D'Amore if ((fp = malloc(sizeof (struct s_flist))) == NULL) 464*84441f85SGarrett D'Amore err(1, "malloc"); 465*84441f85SGarrett D'Amore fp->next = NULL; 466*84441f85SGarrett D'Amore *fl_nextp = fp; 467*84441f85SGarrett D'Amore fp->fname = s; 468*84441f85SGarrett D'Amore fl_nextp = &fp->next; 469*84441f85SGarrett D'Amore } 470*84441f85SGarrett D'Amore 471*84441f85SGarrett D'Amore int 472*84441f85SGarrett D'Amore lastline(void) 473*84441f85SGarrett D'Amore { 474*84441f85SGarrett D'Amore int ch; 475*84441f85SGarrett D'Amore 476*84441f85SGarrett D'Amore if (files->next != NULL && (inplace == NULL || ispan)) 477*84441f85SGarrett D'Amore return (0); 478*84441f85SGarrett D'Amore if ((ch = getc(infile)) == EOF) 479*84441f85SGarrett D'Amore return (1); 480*84441f85SGarrett D'Amore (void) ungetc(ch, infile); 481*84441f85SGarrett D'Amore return (0); 482*84441f85SGarrett D'Amore } 483*84441f85SGarrett D'Amore 484*84441f85SGarrett D'Amore char * 485*84441f85SGarrett D'Amore getln(FILE *in, size_t *lenp) 486*84441f85SGarrett D'Amore { 487*84441f85SGarrett D'Amore static char *buffer = NULL; 488*84441f85SGarrett D'Amore static size_t sz = 0; 489*84441f85SGarrett D'Amore 490*84441f85SGarrett D'Amore size_t len = 0; 491*84441f85SGarrett D'Amore 492*84441f85SGarrett D'Amore for (;;) { 493*84441f85SGarrett D'Amore if (sz <= (len + 1)) { 494*84441f85SGarrett D'Amore char *nb; 495*84441f85SGarrett D'Amore if ((nb = realloc(buffer, sz + LINE_MAX)) == NULL) { 496*84441f85SGarrett D'Amore err(1, "realloc"); 497*84441f85SGarrett D'Amore } 498*84441f85SGarrett D'Amore buffer = nb; 499*84441f85SGarrett D'Amore sz += LINE_MAX; 500*84441f85SGarrett D'Amore } 501*84441f85SGarrett D'Amore 502*84441f85SGarrett D'Amore buffer[len] = 0; 503*84441f85SGarrett D'Amore 504*84441f85SGarrett D'Amore if (fgets(buffer + len, sz - len, in) == NULL) { 505*84441f85SGarrett D'Amore /* END OF FILE */ 506*84441f85SGarrett D'Amore *lenp = len; 507*84441f85SGarrett D'Amore break; 508*84441f85SGarrett D'Amore } 509*84441f85SGarrett D'Amore 510*84441f85SGarrett D'Amore len += strlen(buffer + len); 511*84441f85SGarrett D'Amore 512*84441f85SGarrett D'Amore if (buffer[len - 1] == '\n') { 513*84441f85SGarrett D'Amore /* got the new line */ 514*84441f85SGarrett D'Amore *lenp = len; 515*84441f85SGarrett D'Amore break; 516*84441f85SGarrett D'Amore } 517*84441f85SGarrett D'Amore } 518*84441f85SGarrett D'Amore 519*84441f85SGarrett D'Amore return (buffer); 520*84441f85SGarrett D'Amore } 521