main.c revision 173437
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1992 Diomidis Spinellis. 31590Srgrimes * Copyright (c) 1992, 1993 41590Srgrimes * The Regents of the University of California. All rights reserved. 51590Srgrimes * 61590Srgrimes * This code is derived from software contributed to Berkeley by 71590Srgrimes * Diomidis Spinellis of Imperial College, University of London. 81590Srgrimes * 91590Srgrimes * Redistribution and use in source and binary forms, with or without 101590Srgrimes * modification, are permitted provided that the following conditions 111590Srgrimes * are met: 121590Srgrimes * 1. Redistributions of source code must retain the above copyright 131590Srgrimes * notice, this list of conditions and the following disclaimer. 141590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151590Srgrimes * notice, this list of conditions and the following disclaimer in the 161590Srgrimes * documentation and/or other materials provided with the distribution. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 3487766Smarkm#include <sys/cdefs.h> 3587766Smarkm__FBSDID("$FreeBSD: head/usr.bin/sed/main.c 173437 2007-11-08 08:57:51Z dds $"); 3687766Smarkm 371590Srgrimes#ifndef lint 3828066Scharnierstatic const char copyright[] = 391590Srgrimes"@(#) Copyright (c) 1992, 1993\n\ 401590Srgrimes The Regents of the University of California. All rights reserved.\n"; 4187766Smarkm#endif 421590Srgrimes 431590Srgrimes#ifndef lint 4487766Smarkmstatic const char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94"; 4528066Scharnier#endif 461590Srgrimes 4798200Ssobomax#include <sys/types.h> 4898200Ssobomax#include <sys/mman.h> 4996175Sjmallett#include <sys/param.h> 5096175Sjmallett#include <sys/stat.h> 511590Srgrimes 5228066Scharnier#include <err.h> 531590Srgrimes#include <errno.h> 541590Srgrimes#include <fcntl.h> 55141563Sstefanf#include <libgen.h> 56132145Stjr#include <limits.h> 5717522Sache#include <locale.h> 581590Srgrimes#include <regex.h> 591590Srgrimes#include <stddef.h> 601590Srgrimes#include <stdio.h> 611590Srgrimes#include <stdlib.h> 621590Srgrimes#include <string.h> 631590Srgrimes#include <unistd.h> 641590Srgrimes 651590Srgrimes#include "defs.h" 661590Srgrimes#include "extern.h" 671590Srgrimes 681590Srgrimes/* 691590Srgrimes * Linked list of units (strings and files) to be compiled 701590Srgrimes */ 711590Srgrimesstruct s_compunit { 721590Srgrimes struct s_compunit *next; 731590Srgrimes enum e_cut {CU_FILE, CU_STRING} type; 741590Srgrimes char *s; /* Pointer to string or fname */ 751590Srgrimes}; 761590Srgrimes 771590Srgrimes/* 781590Srgrimes * Linked list pointer to compilation units and pointer to current 791590Srgrimes * next pointer. 801590Srgrimes */ 811590Srgrimesstatic struct s_compunit *script, **cu_nextp = &script; 821590Srgrimes 831590Srgrimes/* 841590Srgrimes * Linked list of files to be processed 851590Srgrimes */ 861590Srgrimesstruct s_flist { 871590Srgrimes char *fname; 881590Srgrimes struct s_flist *next; 891590Srgrimes}; 901590Srgrimes 911590Srgrimes/* 921590Srgrimes * Linked list pointer to files and pointer to current 931590Srgrimes * next pointer. 941590Srgrimes */ 951590Srgrimesstatic struct s_flist *files, **fl_nextp = &files; 961590Srgrimes 97122049SdesFILE *infile; /* Current input file */ 98122049SdesFILE *outfile; /* Current output file */ 9999352Stjr 1001590Srgrimesint aflag, eflag, nflag; 10158309Sgreenint rflags = 0; 10297238Stjrstatic int rval; /* Exit status */ 1031590Srgrimes 104168921Syarstatic int ispan; /* Whether inplace editing spans across files */ 105168921Syar 1061590Srgrimes/* 1071590Srgrimes * Current file and line number; line numbers restart across compilation 108168921Syar * units, but span across input files. The latter is optional if editing 109168921Syar * in place. 1101590Srgrimes */ 11187766Smarkmconst char *fname; /* File name. */ 112122049Sdesconst char *outfname; /* Output file name */ 113122049Sdesstatic char oldfname[PATH_MAX]; /* Old file name (for in-place editing) */ 114122049Sdesstatic char tmpfname[PATH_MAX]; /* Temporary file name (for in-place editing) */ 115173437Sddsstatic const char *inplace; /* Inplace edit file extension. */ 1161590Srgrimesu_long linenum; 1171590Srgrimes 11892922Simpstatic void add_compunit(enum e_cut, char *); 11992922Simpstatic void add_file(char *); 12092922Simpstatic void usage(void); 1211590Srgrimes 1221590Srgrimesint 123122044Sdesmain(int argc, char *argv[]) 1241590Srgrimes{ 1251590Srgrimes int c, fflag; 12660394Snsayer char *temp_arg; 1271590Srgrimes 12817522Sache (void) setlocale(LC_ALL, ""); 12917522Sache 1301590Srgrimes fflag = 0; 13196175Sjmallett inplace = NULL; 13296175Sjmallett 133168921Syar while ((c = getopt(argc, argv, "EI:ae:f:i:ln")) != -1) 1341590Srgrimes switch (c) { 13558309Sgreen case 'E': 13658309Sgreen rflags = REG_EXTENDED; 13758309Sgreen break; 138168921Syar case 'I': 139168921Syar inplace = optarg; 140168921Syar ispan = 1; /* span across input files */ 141168921Syar break; 1421590Srgrimes case 'a': 1431590Srgrimes aflag = 1; 1441590Srgrimes break; 1451590Srgrimes case 'e': 1461590Srgrimes eflag = 1; 14780286Sobrien if ((temp_arg = malloc(strlen(optarg) + 2)) == NULL) 14880286Sobrien err(1, "malloc"); 14960394Snsayer strcpy(temp_arg, optarg); 15060394Snsayer strcat(temp_arg, "\n"); 15160394Snsayer add_compunit(CU_STRING, temp_arg); 1521590Srgrimes break; 1531590Srgrimes case 'f': 1541590Srgrimes fflag = 1; 1551590Srgrimes add_compunit(CU_FILE, optarg); 1561590Srgrimes break; 15796175Sjmallett case 'i': 15896175Sjmallett inplace = optarg; 159168921Syar ispan = 0; /* don't span across input files */ 16096175Sjmallett break; 161146055Sglebius case 'l': 162146055Sglebius if(setlinebuf(stdout) != 0) 163146055Sglebius warnx("setlinebuf() failed"); 164146055Sglebius break; 1651590Srgrimes case 'n': 1661590Srgrimes nflag = 1; 1671590Srgrimes break; 1681590Srgrimes default: 1691590Srgrimes case '?': 17028066Scharnier usage(); 1711590Srgrimes } 1721590Srgrimes argc -= optind; 1731590Srgrimes argv += optind; 1741590Srgrimes 1751590Srgrimes /* First usage case; script is the first arg */ 1761590Srgrimes if (!eflag && !fflag && *argv) { 1771590Srgrimes add_compunit(CU_STRING, *argv); 1781590Srgrimes argv++; 1791590Srgrimes } 1801590Srgrimes 1811590Srgrimes compile(); 1821590Srgrimes 1831590Srgrimes /* Continue with first and start second usage */ 1841590Srgrimes if (*argv) 1851590Srgrimes for (; *argv; argv++) 1861590Srgrimes add_file(*argv); 1871590Srgrimes else 1881590Srgrimes add_file(NULL); 1891590Srgrimes process(); 1901590Srgrimes cfclose(prog, NULL); 1911590Srgrimes if (fclose(stdout)) 19228066Scharnier err(1, "stdout"); 19397238Stjr exit(rval); 1941590Srgrimes} 1951590Srgrimes 19628066Scharnierstatic void 197122044Sdesusage(void) 19828066Scharnier{ 19928066Scharnier (void)fprintf(stderr, "%s\n%s\n", 200146055Sglebius "usage: sed script [-Ealn] [-i extension] [file ...]", 201146055Sglebius " sed [-Ealn] [-i extension] [-e script] ... [-f script_file] ... [file ...]"); 20228066Scharnier exit(1); 20328066Scharnier} 20428066Scharnier 2051590Srgrimes/* 2061590Srgrimes * Like fgets, but go through the chain of compilation units chaining them 2071590Srgrimes * together. Empty strings and files are ignored. 2081590Srgrimes */ 2091590Srgrimeschar * 210122044Sdescu_fgets(char *buf, int n, int *more) 2111590Srgrimes{ 2121590Srgrimes static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF; 2131590Srgrimes static FILE *f; /* Current open file */ 2141590Srgrimes static char *s; /* Current pointer inside string */ 2151590Srgrimes static char string_ident[30]; 2161590Srgrimes char *p; 2171590Srgrimes 2181590Srgrimesagain: 2191590Srgrimes switch (state) { 2201590Srgrimes case ST_EOF: 22141602Sarchie if (script == NULL) { 22241602Sarchie if (more != NULL) 22341602Sarchie *more = 0; 2241590Srgrimes return (NULL); 22541602Sarchie } 2261590Srgrimes linenum = 0; 2271590Srgrimes switch (script->type) { 2281590Srgrimes case CU_FILE: 2291590Srgrimes if ((f = fopen(script->s, "r")) == NULL) 23028066Scharnier err(1, "%s", script->s); 2311590Srgrimes fname = script->s; 2321590Srgrimes state = ST_FILE; 2331590Srgrimes goto again; 2341590Srgrimes case CU_STRING: 2351590Srgrimes if ((snprintf(string_ident, 2361590Srgrimes sizeof(string_ident), "\"%s\"", script->s)) >= 2371590Srgrimes sizeof(string_ident) - 1) 2381590Srgrimes (void)strcpy(string_ident + 2391590Srgrimes sizeof(string_ident) - 6, " ...\""); 2401590Srgrimes fname = string_ident; 2411590Srgrimes s = script->s; 2421590Srgrimes state = ST_STRING; 2431590Srgrimes goto again; 2441590Srgrimes } 2451590Srgrimes case ST_FILE: 2461590Srgrimes if ((p = fgets(buf, n, f)) != NULL) { 2471590Srgrimes linenum++; 2481590Srgrimes if (linenum == 1 && buf[0] == '#' && buf[1] == 'n') 2491590Srgrimes nflag = 1; 25041602Sarchie if (more != NULL) 25141602Sarchie *more = !feof(f); 2521590Srgrimes return (p); 2531590Srgrimes } 2541590Srgrimes script = script->next; 2551590Srgrimes (void)fclose(f); 2561590Srgrimes state = ST_EOF; 2571590Srgrimes goto again; 2581590Srgrimes case ST_STRING: 2591590Srgrimes if (linenum == 0 && s[0] == '#' && s[1] == 'n') 2601590Srgrimes nflag = 1; 2611590Srgrimes p = buf; 2621590Srgrimes for (;;) { 2631590Srgrimes if (n-- <= 1) { 2641590Srgrimes *p = '\0'; 2651590Srgrimes linenum++; 26641602Sarchie if (more != NULL) 26741602Sarchie *more = 1; 2681590Srgrimes return (buf); 2691590Srgrimes } 2701590Srgrimes switch (*s) { 2711590Srgrimes case '\0': 2721590Srgrimes state = ST_EOF; 2731590Srgrimes if (s == script->s) { 2741590Srgrimes script = script->next; 2751590Srgrimes goto again; 2761590Srgrimes } else { 2771590Srgrimes script = script->next; 2781590Srgrimes *p = '\0'; 2791590Srgrimes linenum++; 28041602Sarchie if (more != NULL) 28141602Sarchie *more = 0; 2821590Srgrimes return (buf); 2831590Srgrimes } 2841590Srgrimes case '\n': 2851590Srgrimes *p++ = '\n'; 2861590Srgrimes *p = '\0'; 2871590Srgrimes s++; 2881590Srgrimes linenum++; 28941602Sarchie if (more != NULL) 29041602Sarchie *more = 0; 2911590Srgrimes return (buf); 2921590Srgrimes default: 2931590Srgrimes *p++ = *s++; 2941590Srgrimes } 2951590Srgrimes } 2961590Srgrimes } 2971590Srgrimes /* NOTREACHED */ 29828066Scharnier return (NULL); 2991590Srgrimes} 3001590Srgrimes 3011590Srgrimes/* 3021590Srgrimes * Like fgets, but go through the list of files chaining them together. 3031590Srgrimes * Set len to the length of the line. 3041590Srgrimes */ 3051590Srgrimesint 306122044Sdesmf_fgets(SPACE *sp, enum e_spflag spflag) 3071590Srgrimes{ 308122049Sdes struct stat sb; 3091590Srgrimes size_t len; 31019829Swosch char *p; 31119829Swosch int c; 31298200Ssobomax static int firstfile; 3131590Srgrimes 314122049Sdes if (infile == NULL) { 31598200Ssobomax /* stdin? */ 31698200Ssobomax if (files->fname == NULL) { 31798200Ssobomax if (inplace != NULL) 318168921Syar errx(1, "-I or -i may not be used with stdin"); 319122049Sdes infile = stdin; 32098200Ssobomax fname = "stdin"; 321122049Sdes outfile = stdout; 322122049Sdes outfname = "stdout"; 32398200Ssobomax } 32498200Ssobomax firstfile = 1; 32598200Ssobomax } 32698200Ssobomax 32798200Ssobomax for (;;) { 328122049Sdes if (infile != NULL && (c = getc(infile)) != EOF) { 329122049Sdes (void)ungetc(c, infile); 33098200Ssobomax break; 33198200Ssobomax } 33298200Ssobomax /* If we are here then either eof or no files are open yet */ 333122049Sdes if (infile == stdin) { 33498294Stjr sp->len = 0; 33598200Ssobomax return (0); 33698200Ssobomax } 337122049Sdes if (infile != NULL) { 338122049Sdes fclose(infile); 339130039Sbrian if (*oldfname != '\0') { 340130039Sbrian if (rename(fname, oldfname) != 0) { 341130039Sbrian warn("rename()"); 342130039Sbrian unlink(tmpfname); 343130039Sbrian exit(1); 344130039Sbrian } 345130039Sbrian *oldfname = '\0'; 346122049Sdes } 347130039Sbrian if (*tmpfname != '\0') { 348130039Sbrian if (outfile != NULL && outfile != stdout) 349130039Sbrian fclose(outfile); 350130039Sbrian outfile = NULL; 351122049Sdes rename(tmpfname, fname); 352130039Sbrian *tmpfname = '\0'; 353130039Sbrian } 354122049Sdes outfname = NULL; 35598200Ssobomax } 356122049Sdes if (firstfile == 0) 3571590Srgrimes files = files->next; 358122049Sdes else 35998200Ssobomax firstfile = 0; 36098200Ssobomax if (files == NULL) { 36198294Stjr sp->len = 0; 36298200Ssobomax return (0); 3631590Srgrimes } 364122049Sdes fname = files->fname; 36598200Ssobomax if (inplace != NULL) { 366122049Sdes if (lstat(fname, &sb) != 0) 367122049Sdes err(1, "%s", fname); 368122049Sdes if (!(sb.st_mode & S_IFREG)) 369122049Sdes errx(1, "%s: %s %s", fname, 370122049Sdes "in-place editing only", 371122049Sdes "works for regular files"); 372122049Sdes if (*inplace != '\0') { 373122049Sdes strlcpy(oldfname, fname, 374122049Sdes sizeof(oldfname)); 375122049Sdes len = strlcat(oldfname, inplace, 376122049Sdes sizeof(oldfname)); 377122049Sdes if (len > sizeof(oldfname)) 378122049Sdes errx(1, "%s: name too long", fname); 379122049Sdes } 380122049Sdes len = snprintf(tmpfname, sizeof(tmpfname), 381122084Sdes "%s/.!%ld!%s", dirname(fname), (long)getpid(), 382122084Sdes basename(fname)); 383122049Sdes if (len >= sizeof(tmpfname)) 384122049Sdes errx(1, "%s: name too long", fname); 385122049Sdes unlink(tmpfname); 386122049Sdes if ((outfile = fopen(tmpfname, "w")) == NULL) 387122049Sdes err(1, "%s", fname); 388122049Sdes fchown(fileno(outfile), sb.st_uid, sb.st_gid); 389122049Sdes fchmod(fileno(outfile), sb.st_mode & ALLPERMS); 390122049Sdes outfname = tmpfname; 391168921Syar if (!ispan) { 392168921Syar linenum = 0; 393170608Syar resetstate(); 394168921Syar } 395122049Sdes } else { 396122049Sdes outfile = stdout; 397122049Sdes outfname = "stdout"; 39898200Ssobomax } 399122049Sdes if ((infile = fopen(fname, "r")) == NULL) { 40098200Ssobomax warn("%s", fname); 40198201Stjr rval = 1; 40298200Ssobomax continue; 40398200Ssobomax } 4041590Srgrimes } 4051590Srgrimes /* 406122049Sdes * We are here only when infile is open and we still have something 40799352Stjr * to read from it. 40898200Ssobomax * 4091590Srgrimes * Use fgetln so that we can handle essentially infinite input data. 41019829Swosch * Can't use the pointer into the stdio buffer as the process space 41119829Swosch * because the ungetc() can cause it to move. 4121590Srgrimes */ 413122049Sdes p = fgetln(infile, &len); 414122049Sdes if (ferror(infile)) 41528066Scharnier errx(1, "%s: %s", fname, strerror(errno ? errno : EIO)); 41698601Stjr if (len != 0 && p[len - 1] == '\n') 41798601Stjr len--; 4181590Srgrimes cspace(sp, p, len, spflag); 4191590Srgrimes 4201590Srgrimes linenum++; 42198200Ssobomax 4221590Srgrimes return (1); 4231590Srgrimes} 4241590Srgrimes 4251590Srgrimes/* 4261590Srgrimes * Add a compilation unit to the linked list 4271590Srgrimes */ 4281590Srgrimesstatic void 429122044Sdesadd_compunit(enum e_cut type, char *s) 4301590Srgrimes{ 4311590Srgrimes struct s_compunit *cu; 4321590Srgrimes 43380286Sobrien if ((cu = malloc(sizeof(struct s_compunit))) == NULL) 43480286Sobrien err(1, "malloc"); 4351590Srgrimes cu->type = type; 4361590Srgrimes cu->s = s; 4371590Srgrimes cu->next = NULL; 4381590Srgrimes *cu_nextp = cu; 4391590Srgrimes cu_nextp = &cu->next; 4401590Srgrimes} 4411590Srgrimes 4421590Srgrimes/* 4431590Srgrimes * Add a file to the linked list 4441590Srgrimes */ 4451590Srgrimesstatic void 446122044Sdesadd_file(char *s) 4471590Srgrimes{ 4481590Srgrimes struct s_flist *fp; 4491590Srgrimes 45080286Sobrien if ((fp = malloc(sizeof(struct s_flist))) == NULL) 45180286Sobrien err(1, "malloc"); 4521590Srgrimes fp->next = NULL; 4531590Srgrimes *fl_nextp = fp; 4541590Srgrimes fp->fname = s; 4551590Srgrimes fl_nextp = &fp->next; 4561590Srgrimes} 45796175Sjmallett 45899352Stjrint 45999352Stjrlastline(void) 46099352Stjr{ 46199352Stjr int ch; 46299352Stjr 463168921Syar if (files->next != NULL && (inplace == NULL || ispan)) 46499352Stjr return (0); 465122049Sdes if ((ch = getc(infile)) == EOF) 46699352Stjr return (1); 467122049Sdes ungetc(ch, infile); 46899352Stjr return (0); 46999352Stjr} 470