main.c revision 268193
11590Srgrimes/*- 2252231Spfg * Copyright (c) 2013 Johann 'Myrkraverk' Oskarsson. 31590Srgrimes * Copyright (c) 1992 Diomidis Spinellis. 41590Srgrimes * Copyright (c) 1992, 1993 51590Srgrimes * The Regents of the University of California. All rights reserved. 61590Srgrimes * 71590Srgrimes * This code is derived from software contributed to Berkeley by 81590Srgrimes * Diomidis Spinellis of Imperial College, University of London. 91590Srgrimes * 101590Srgrimes * Redistribution and use in source and binary forms, with or without 111590Srgrimes * modification, are permitted provided that the following conditions 121590Srgrimes * are met: 131590Srgrimes * 1. Redistributions of source code must retain the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer. 151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161590Srgrimes * notice, this list of conditions and the following disclaimer in the 171590Srgrimes * documentation and/or other materials provided with the distribution. 181590Srgrimes * 4. Neither the name of the University nor the names of its contributors 191590Srgrimes * may be used to endorse or promote products derived from this software 201590Srgrimes * without specific prior written permission. 211590Srgrimes * 221590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321590Srgrimes * SUCH DAMAGE. 331590Srgrimes */ 341590Srgrimes 3587766Smarkm#include <sys/cdefs.h> 3687766Smarkm__FBSDID("$FreeBSD: head/usr.bin/sed/main.c 268193 2014-07-02 23:07:01Z pfg $"); 3787766Smarkm 381590Srgrimes#ifndef lint 3928066Scharnierstatic const char copyright[] = 401590Srgrimes"@(#) Copyright (c) 1992, 1993\n\ 411590Srgrimes The Regents of the University of California. All rights reserved.\n"; 4287766Smarkm#endif 431590Srgrimes 441590Srgrimes#ifndef lint 4587766Smarkmstatic const char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94"; 4628066Scharnier#endif 471590Srgrimes 4898200Ssobomax#include <sys/types.h> 4998200Ssobomax#include <sys/mman.h> 5096175Sjmallett#include <sys/param.h> 5196175Sjmallett#include <sys/stat.h> 521590Srgrimes 5328066Scharnier#include <err.h> 541590Srgrimes#include <errno.h> 55200462Sdelphij#include <fcntl.h> 56141563Sstefanf#include <libgen.h> 57132145Stjr#include <limits.h> 5817522Sache#include <locale.h> 591590Srgrimes#include <regex.h> 60200462Sdelphij#include <stddef.h> 61252231Spfg#define _WITH_GETLINE 621590Srgrimes#include <stdio.h> 631590Srgrimes#include <stdlib.h> 641590Srgrimes#include <string.h> 651590Srgrimes#include <unistd.h> 661590Srgrimes 671590Srgrimes#include "defs.h" 681590Srgrimes#include "extern.h" 691590Srgrimes 701590Srgrimes/* 711590Srgrimes * Linked list of units (strings and files) to be compiled 721590Srgrimes */ 731590Srgrimesstruct s_compunit { 741590Srgrimes struct s_compunit *next; 751590Srgrimes enum e_cut {CU_FILE, CU_STRING} type; 761590Srgrimes char *s; /* Pointer to string or fname */ 771590Srgrimes}; 781590Srgrimes 791590Srgrimes/* 801590Srgrimes * Linked list pointer to compilation units and pointer to current 811590Srgrimes * next pointer. 821590Srgrimes */ 831590Srgrimesstatic struct s_compunit *script, **cu_nextp = &script; 841590Srgrimes 851590Srgrimes/* 861590Srgrimes * Linked list of files to be processed 871590Srgrimes */ 881590Srgrimesstruct s_flist { 891590Srgrimes char *fname; 901590Srgrimes struct s_flist *next; 911590Srgrimes}; 921590Srgrimes 931590Srgrimes/* 941590Srgrimes * Linked list pointer to files and pointer to current 951590Srgrimes * next pointer. 961590Srgrimes */ 971590Srgrimesstatic struct s_flist *files, **fl_nextp = &files; 981590Srgrimes 99122049SdesFILE *infile; /* Current input file */ 100122049SdesFILE *outfile; /* Current output file */ 10199352Stjr 1021590Srgrimesint aflag, eflag, nflag; 10358309Sgreenint rflags = 0; 10497238Stjrstatic int rval; /* Exit status */ 1051590Srgrimes 106168921Syarstatic int ispan; /* Whether inplace editing spans across files */ 107168921Syar 1081590Srgrimes/* 1091590Srgrimes * Current file and line number; line numbers restart across compilation 110168921Syar * units, but span across input files. The latter is optional if editing 111168921Syar * in place. 1121590Srgrimes */ 11387766Smarkmconst char *fname; /* File name. */ 114122049Sdesconst char *outfname; /* Output file name */ 115122049Sdesstatic char oldfname[PATH_MAX]; /* Old file name (for in-place editing) */ 116122049Sdesstatic char tmpfname[PATH_MAX]; /* Temporary file name (for in-place editing) */ 117173437Sddsstatic const char *inplace; /* Inplace edit file extension. */ 1181590Srgrimesu_long linenum; 1191590Srgrimes 12092922Simpstatic void add_compunit(enum e_cut, char *); 12192922Simpstatic void add_file(char *); 12292922Simpstatic void usage(void); 1231590Srgrimes 1241590Srgrimesint 125122044Sdesmain(int argc, char *argv[]) 1261590Srgrimes{ 1271590Srgrimes int c, fflag; 12860394Snsayer char *temp_arg; 1291590Srgrimes 13017522Sache (void) setlocale(LC_ALL, ""); 13117522Sache 1321590Srgrimes fflag = 0; 13396175Sjmallett inplace = NULL; 13496175Sjmallett 135267692Spfg while ((c = getopt(argc, argv, "EI:ae:f:i:lnru")) != -1) 1361590Srgrimes switch (c) { 137205992Simp case 'r': /* Gnu sed compat */ 13858309Sgreen case 'E': 13958309Sgreen rflags = REG_EXTENDED; 14058309Sgreen break; 141168921Syar case 'I': 142168921Syar inplace = optarg; 143168921Syar ispan = 1; /* span across input files */ 144168921Syar break; 1451590Srgrimes case 'a': 1461590Srgrimes aflag = 1; 1471590Srgrimes break; 1481590Srgrimes case 'e': 1491590Srgrimes eflag = 1; 15080286Sobrien if ((temp_arg = malloc(strlen(optarg) + 2)) == NULL) 15180286Sobrien err(1, "malloc"); 15260394Snsayer strcpy(temp_arg, optarg); 15360394Snsayer strcat(temp_arg, "\n"); 15460394Snsayer add_compunit(CU_STRING, temp_arg); 1551590Srgrimes break; 1561590Srgrimes case 'f': 1571590Srgrimes fflag = 1; 1581590Srgrimes add_compunit(CU_FILE, optarg); 1591590Srgrimes break; 16096175Sjmallett case 'i': 16196175Sjmallett inplace = optarg; 162168921Syar ispan = 0; /* don't span across input files */ 16396175Sjmallett break; 164146055Sglebius case 'l': 165267703Spfg if(setvbuf(stdout, NULL, _IOLBF, 0) != 0) 166267703Spfg warnx("setting line buffered output failed"); 167146055Sglebius break; 1681590Srgrimes case 'n': 1691590Srgrimes nflag = 1; 1701590Srgrimes break; 171267692Spfg case 'u': 172267703Spfg if(setvbuf(stdout, NULL, _IONBF, 0) != 0) 173267692Spfg warnx("setting unbuffered output failed"); 174267692Spfg break; 1751590Srgrimes default: 1761590Srgrimes case '?': 17728066Scharnier usage(); 1781590Srgrimes } 1791590Srgrimes argc -= optind; 1801590Srgrimes argv += optind; 1811590Srgrimes 1821590Srgrimes /* First usage case; script is the first arg */ 1831590Srgrimes if (!eflag && !fflag && *argv) { 1841590Srgrimes add_compunit(CU_STRING, *argv); 1851590Srgrimes argv++; 1861590Srgrimes } 1871590Srgrimes 1881590Srgrimes compile(); 1891590Srgrimes 1901590Srgrimes /* Continue with first and start second usage */ 1911590Srgrimes if (*argv) 1921590Srgrimes for (; *argv; argv++) 1931590Srgrimes add_file(*argv); 1941590Srgrimes else 1951590Srgrimes add_file(NULL); 1961590Srgrimes process(); 1971590Srgrimes cfclose(prog, NULL); 1981590Srgrimes if (fclose(stdout)) 19928066Scharnier err(1, "stdout"); 20097238Stjr exit(rval); 2011590Srgrimes} 2021590Srgrimes 20328066Scharnierstatic void 204122044Sdesusage(void) 20528066Scharnier{ 206267692Spfg (void)fprintf(stderr, 207267692Spfg "usage: %s script [-Ealnru] [-i[<extension>]] [file ...]\n" 208268193Spfg "\t%s [-Ealnu] [-i extension] [-e script] ... [-f script_file]" 209267692Spfg " ... [file ...]\n", getprogname(), getprogname()); 21028066Scharnier exit(1); 21128066Scharnier} 21228066Scharnier 2131590Srgrimes/* 2141590Srgrimes * Like fgets, but go through the chain of compilation units chaining them 2151590Srgrimes * together. Empty strings and files are ignored. 2161590Srgrimes */ 2171590Srgrimeschar * 218122044Sdescu_fgets(char *buf, int n, int *more) 2191590Srgrimes{ 2201590Srgrimes static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF; 2211590Srgrimes static FILE *f; /* Current open file */ 2221590Srgrimes static char *s; /* Current pointer inside string */ 2231590Srgrimes static char string_ident[30]; 2241590Srgrimes char *p; 2251590Srgrimes 2261590Srgrimesagain: 2271590Srgrimes switch (state) { 2281590Srgrimes case ST_EOF: 22941602Sarchie if (script == NULL) { 23041602Sarchie if (more != NULL) 23141602Sarchie *more = 0; 2321590Srgrimes return (NULL); 23341602Sarchie } 2341590Srgrimes linenum = 0; 2351590Srgrimes switch (script->type) { 2361590Srgrimes case CU_FILE: 2371590Srgrimes if ((f = fopen(script->s, "r")) == NULL) 23828066Scharnier err(1, "%s", script->s); 2391590Srgrimes fname = script->s; 2401590Srgrimes state = ST_FILE; 2411590Srgrimes goto again; 2421590Srgrimes case CU_STRING: 243176126Sdwmalone if (((size_t)snprintf(string_ident, 2441590Srgrimes sizeof(string_ident), "\"%s\"", script->s)) >= 2451590Srgrimes sizeof(string_ident) - 1) 2461590Srgrimes (void)strcpy(string_ident + 2471590Srgrimes sizeof(string_ident) - 6, " ...\""); 2481590Srgrimes fname = string_ident; 2491590Srgrimes s = script->s; 2501590Srgrimes state = ST_STRING; 2511590Srgrimes goto again; 2521590Srgrimes } 2531590Srgrimes case ST_FILE: 2541590Srgrimes if ((p = fgets(buf, n, f)) != NULL) { 2551590Srgrimes linenum++; 2561590Srgrimes if (linenum == 1 && buf[0] == '#' && buf[1] == 'n') 2571590Srgrimes nflag = 1; 25841602Sarchie if (more != NULL) 25941602Sarchie *more = !feof(f); 2601590Srgrimes return (p); 2611590Srgrimes } 2621590Srgrimes script = script->next; 2631590Srgrimes (void)fclose(f); 2641590Srgrimes state = ST_EOF; 2651590Srgrimes goto again; 2661590Srgrimes case ST_STRING: 2671590Srgrimes if (linenum == 0 && s[0] == '#' && s[1] == 'n') 2681590Srgrimes nflag = 1; 2691590Srgrimes p = buf; 2701590Srgrimes for (;;) { 2711590Srgrimes if (n-- <= 1) { 2721590Srgrimes *p = '\0'; 2731590Srgrimes linenum++; 27441602Sarchie if (more != NULL) 27541602Sarchie *more = 1; 2761590Srgrimes return (buf); 2771590Srgrimes } 2781590Srgrimes switch (*s) { 2791590Srgrimes case '\0': 2801590Srgrimes state = ST_EOF; 2811590Srgrimes if (s == script->s) { 2821590Srgrimes script = script->next; 2831590Srgrimes goto again; 2841590Srgrimes } else { 2851590Srgrimes script = script->next; 2861590Srgrimes *p = '\0'; 2871590Srgrimes linenum++; 28841602Sarchie if (more != NULL) 28941602Sarchie *more = 0; 2901590Srgrimes return (buf); 2911590Srgrimes } 2921590Srgrimes case '\n': 2931590Srgrimes *p++ = '\n'; 2941590Srgrimes *p = '\0'; 2951590Srgrimes s++; 2961590Srgrimes linenum++; 29741602Sarchie if (more != NULL) 29841602Sarchie *more = 0; 2991590Srgrimes return (buf); 3001590Srgrimes default: 3011590Srgrimes *p++ = *s++; 3021590Srgrimes } 3031590Srgrimes } 3041590Srgrimes } 3051590Srgrimes /* NOTREACHED */ 30628066Scharnier return (NULL); 3071590Srgrimes} 3081590Srgrimes 3091590Srgrimes/* 3101590Srgrimes * Like fgets, but go through the list of files chaining them together. 3111590Srgrimes * Set len to the length of the line. 3121590Srgrimes */ 3131590Srgrimesint 314122044Sdesmf_fgets(SPACE *sp, enum e_spflag spflag) 3151590Srgrimes{ 316122049Sdes struct stat sb; 317252231Spfg ssize_t len; 318252231Spfg static char *p = NULL; 319252231Spfg static size_t plen = 0; 32019829Swosch int c; 32198200Ssobomax static int firstfile; 3221590Srgrimes 323122049Sdes if (infile == NULL) { 32498200Ssobomax /* stdin? */ 32598200Ssobomax if (files->fname == NULL) { 32698200Ssobomax if (inplace != NULL) 327168921Syar errx(1, "-I or -i may not be used with stdin"); 328122049Sdes infile = stdin; 32998200Ssobomax fname = "stdin"; 330122049Sdes outfile = stdout; 331122049Sdes outfname = "stdout"; 33298200Ssobomax } 33398200Ssobomax firstfile = 1; 33498200Ssobomax } 33598200Ssobomax 33698200Ssobomax for (;;) { 337122049Sdes if (infile != NULL && (c = getc(infile)) != EOF) { 338122049Sdes (void)ungetc(c, infile); 33998200Ssobomax break; 34098200Ssobomax } 34198200Ssobomax /* If we are here then either eof or no files are open yet */ 342122049Sdes if (infile == stdin) { 34398294Stjr sp->len = 0; 34498200Ssobomax return (0); 34598200Ssobomax } 346122049Sdes if (infile != NULL) { 347122049Sdes fclose(infile); 348130039Sbrian if (*oldfname != '\0') { 349217133Sjilles /* if there was a backup file, remove it */ 350217133Sjilles unlink(oldfname); 351217133Sjilles /* 352217133Sjilles * Backup the original. Note that hard links 353217133Sjilles * are not supported on all filesystems. 354217133Sjilles */ 355217133Sjilles if ((link(fname, oldfname) != 0) && 356217133Sjilles (rename(fname, oldfname) != 0)) { 357130039Sbrian warn("rename()"); 358217133Sjilles if (*tmpfname) 359217133Sjilles unlink(tmpfname); 360130039Sbrian exit(1); 361130039Sbrian } 362130039Sbrian *oldfname = '\0'; 363122049Sdes } 364130039Sbrian if (*tmpfname != '\0') { 365130039Sbrian if (outfile != NULL && outfile != stdout) 366217133Sjilles if (fclose(outfile) != 0) { 367217133Sjilles warn("fclose()"); 368217133Sjilles unlink(tmpfname); 369217133Sjilles exit(1); 370217133Sjilles } 371130039Sbrian outfile = NULL; 372217133Sjilles if (rename(tmpfname, fname) != 0) { 373217133Sjilles /* this should not happen really! */ 374217133Sjilles warn("rename()"); 375217133Sjilles unlink(tmpfname); 376217133Sjilles exit(1); 377217133Sjilles } 378130039Sbrian *tmpfname = '\0'; 379130039Sbrian } 380122049Sdes outfname = NULL; 38198200Ssobomax } 382122049Sdes if (firstfile == 0) 3831590Srgrimes files = files->next; 384122049Sdes else 38598200Ssobomax firstfile = 0; 38698200Ssobomax if (files == NULL) { 38798294Stjr sp->len = 0; 38898200Ssobomax return (0); 3891590Srgrimes } 390122049Sdes fname = files->fname; 39198200Ssobomax if (inplace != NULL) { 392122049Sdes if (lstat(fname, &sb) != 0) 393122049Sdes err(1, "%s", fname); 394122049Sdes if (!(sb.st_mode & S_IFREG)) 395122049Sdes errx(1, "%s: %s %s", fname, 396122049Sdes "in-place editing only", 397122049Sdes "works for regular files"); 398122049Sdes if (*inplace != '\0') { 399122049Sdes strlcpy(oldfname, fname, 400122049Sdes sizeof(oldfname)); 401122049Sdes len = strlcat(oldfname, inplace, 402122049Sdes sizeof(oldfname)); 403122049Sdes if (len > sizeof(oldfname)) 404122049Sdes errx(1, "%s: name too long", fname); 405122049Sdes } 406122049Sdes len = snprintf(tmpfname, sizeof(tmpfname), 407122084Sdes "%s/.!%ld!%s", dirname(fname), (long)getpid(), 408122084Sdes basename(fname)); 409122049Sdes if (len >= sizeof(tmpfname)) 410122049Sdes errx(1, "%s: name too long", fname); 411122049Sdes unlink(tmpfname); 412122049Sdes if ((outfile = fopen(tmpfname, "w")) == NULL) 413122049Sdes err(1, "%s", fname); 414122049Sdes fchown(fileno(outfile), sb.st_uid, sb.st_gid); 415122049Sdes fchmod(fileno(outfile), sb.st_mode & ALLPERMS); 416122049Sdes outfname = tmpfname; 417168921Syar if (!ispan) { 418168921Syar linenum = 0; 419170608Syar resetstate(); 420168921Syar } 421122049Sdes } else { 422122049Sdes outfile = stdout; 423122049Sdes outfname = "stdout"; 42498200Ssobomax } 425122049Sdes if ((infile = fopen(fname, "r")) == NULL) { 42698200Ssobomax warn("%s", fname); 42798201Stjr rval = 1; 42898200Ssobomax continue; 42998200Ssobomax } 4301590Srgrimes } 4311590Srgrimes /* 432122049Sdes * We are here only when infile is open and we still have something 43399352Stjr * to read from it. 43498200Ssobomax * 435252231Spfg * Use getline() so that we can handle essentially infinite input 436252231Spfg * data. The p and plen are static so each invocation gives 437252231Spfg * getline() the same buffer which is expanded as needed. 4381590Srgrimes */ 439252231Spfg len = getline(&p, &plen, infile); 440252231Spfg if (len == -1) 441252231Spfg err(1, "%s", fname); 44298601Stjr if (len != 0 && p[len - 1] == '\n') 44398601Stjr len--; 4441590Srgrimes cspace(sp, p, len, spflag); 4451590Srgrimes 4461590Srgrimes linenum++; 44798200Ssobomax 4481590Srgrimes return (1); 4491590Srgrimes} 4501590Srgrimes 4511590Srgrimes/* 4521590Srgrimes * Add a compilation unit to the linked list 4531590Srgrimes */ 4541590Srgrimesstatic void 455122044Sdesadd_compunit(enum e_cut type, char *s) 4561590Srgrimes{ 4571590Srgrimes struct s_compunit *cu; 4581590Srgrimes 45980286Sobrien if ((cu = malloc(sizeof(struct s_compunit))) == NULL) 46080286Sobrien err(1, "malloc"); 4611590Srgrimes cu->type = type; 4621590Srgrimes cu->s = s; 4631590Srgrimes cu->next = NULL; 4641590Srgrimes *cu_nextp = cu; 4651590Srgrimes cu_nextp = &cu->next; 4661590Srgrimes} 4671590Srgrimes 4681590Srgrimes/* 4691590Srgrimes * Add a file to the linked list 4701590Srgrimes */ 4711590Srgrimesstatic void 472122044Sdesadd_file(char *s) 4731590Srgrimes{ 4741590Srgrimes struct s_flist *fp; 4751590Srgrimes 47680286Sobrien if ((fp = malloc(sizeof(struct s_flist))) == NULL) 47780286Sobrien err(1, "malloc"); 4781590Srgrimes fp->next = NULL; 4791590Srgrimes *fl_nextp = fp; 4801590Srgrimes fp->fname = s; 4811590Srgrimes fl_nextp = &fp->next; 4821590Srgrimes} 48396175Sjmallett 48499352Stjrint 48599352Stjrlastline(void) 48699352Stjr{ 48799352Stjr int ch; 48899352Stjr 489168921Syar if (files->next != NULL && (inplace == NULL || ispan)) 49099352Stjr return (0); 491122049Sdes if ((ch = getc(infile)) == EOF) 49299352Stjr return (1); 493122049Sdes ungetc(ch, infile); 49499352Stjr return (0); 49599352Stjr} 496