main.c revision 60394
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 * 3. All advertising materials mentioning features or use of this software 181590Srgrimes * must display the following acknowledgement: 191590Srgrimes * This product includes software developed by the University of 201590Srgrimes * California, Berkeley and its contributors. 211590Srgrimes * 4. Neither the name of the University nor the names of its contributors 221590Srgrimes * may be used to endorse or promote products derived from this software 231590Srgrimes * without specific prior written permission. 241590Srgrimes * 251590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 261590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 271590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 281590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 291590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 301590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 311590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 321590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 331590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 341590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 351590Srgrimes * SUCH DAMAGE. 361590Srgrimes */ 371590Srgrimes 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"; 421590Srgrimes#endif /* not lint */ 431590Srgrimes 441590Srgrimes#ifndef lint 4528066Scharnier#if 0 461590Srgrimesstatic char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94"; 4728066Scharnier#endif 4828066Scharnierstatic const char rcsid[] = 4950477Speter "$FreeBSD: head/usr.bin/sed/main.c 60394 2000-05-11 17:01:52Z nsayer $"; 501590Srgrimes#endif /* not lint */ 511590Srgrimes 521590Srgrimes#include <sys/types.h> 531590Srgrimes 5428066Scharnier#include <err.h> 551590Srgrimes#include <errno.h> 561590Srgrimes#include <fcntl.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 971590Srgrimesint aflag, eflag, nflag; 9858309Sgreenint rflags = 0; 991590Srgrimes 1001590Srgrimes/* 1011590Srgrimes * Current file and line number; line numbers restart across compilation 1021590Srgrimes * units, but span across input files. 1031590Srgrimes */ 1041590Srgrimeschar *fname; /* File name. */ 1051590Srgrimesu_long linenum; 1061590Srgrimesint lastline; /* TRUE on the last line of the last file */ 1071590Srgrimes 1081590Srgrimesstatic void add_compunit __P((enum e_cut, char *)); 1091590Srgrimesstatic void add_file __P((char *)); 11028066Scharnierstatic void usage __P((void)); 1111590Srgrimes 1121590Srgrimesint 1131590Srgrimesmain(argc, argv) 1141590Srgrimes int argc; 1151590Srgrimes char *argv[]; 1161590Srgrimes{ 1171590Srgrimes int c, fflag; 11860394Snsayer char *temp_arg; 1191590Srgrimes 12017522Sache (void) setlocale(LC_ALL, ""); 12117522Sache 1221590Srgrimes fflag = 0; 12358309Sgreen while ((c = getopt(argc, argv, "Eae:f:n")) != -1) 1241590Srgrimes switch (c) { 12558309Sgreen case 'E': 12658309Sgreen rflags = REG_EXTENDED; 12758309Sgreen break; 1281590Srgrimes case 'a': 1291590Srgrimes aflag = 1; 1301590Srgrimes break; 1311590Srgrimes case 'e': 1321590Srgrimes eflag = 1; 13360394Snsayer temp_arg=xmalloc(strlen(optarg) + 2); 13460394Snsayer strcpy(temp_arg, optarg); 13560394Snsayer strcat(temp_arg, "\n"); 13660394Snsayer add_compunit(CU_STRING, temp_arg); 1371590Srgrimes break; 1381590Srgrimes case 'f': 1391590Srgrimes fflag = 1; 1401590Srgrimes add_compunit(CU_FILE, optarg); 1411590Srgrimes break; 1421590Srgrimes case 'n': 1431590Srgrimes nflag = 1; 1441590Srgrimes break; 1451590Srgrimes default: 1461590Srgrimes case '?': 14728066Scharnier usage(); 1481590Srgrimes } 1491590Srgrimes argc -= optind; 1501590Srgrimes argv += optind; 1511590Srgrimes 1521590Srgrimes /* First usage case; script is the first arg */ 1531590Srgrimes if (!eflag && !fflag && *argv) { 1541590Srgrimes add_compunit(CU_STRING, *argv); 1551590Srgrimes argv++; 1561590Srgrimes } 1571590Srgrimes 1581590Srgrimes compile(); 1591590Srgrimes 1601590Srgrimes /* Continue with first and start second usage */ 1611590Srgrimes if (*argv) 1621590Srgrimes for (; *argv; argv++) 1631590Srgrimes add_file(*argv); 1641590Srgrimes else 1651590Srgrimes add_file(NULL); 1661590Srgrimes process(); 1671590Srgrimes cfclose(prog, NULL); 1681590Srgrimes if (fclose(stdout)) 16928066Scharnier err(1, "stdout"); 1701590Srgrimes exit (0); 1711590Srgrimes} 1721590Srgrimes 17328066Scharnierstatic void 17428066Scharnierusage() 17528066Scharnier{ 17628066Scharnier (void)fprintf(stderr, "%s\n%s\n", 17758309Sgreen "usage: sed script [-Ean] [file ...]", 17828066Scharnier " sed [-an] [-e script] ... [-f script_file] ... [file ...]"); 17928066Scharnier exit(1); 18028066Scharnier} 18128066Scharnier 1821590Srgrimes/* 1831590Srgrimes * Like fgets, but go through the chain of compilation units chaining them 1841590Srgrimes * together. Empty strings and files are ignored. 1851590Srgrimes */ 1861590Srgrimeschar * 18741602Sarchiecu_fgets(buf, n, more) 1881590Srgrimes char *buf; 1891590Srgrimes int n; 19041602Sarchie int *more; 1911590Srgrimes{ 1921590Srgrimes static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF; 1931590Srgrimes static FILE *f; /* Current open file */ 1941590Srgrimes static char *s; /* Current pointer inside string */ 1951590Srgrimes static char string_ident[30]; 1961590Srgrimes char *p; 1971590Srgrimes 1981590Srgrimesagain: 1991590Srgrimes switch (state) { 2001590Srgrimes case ST_EOF: 20141602Sarchie if (script == NULL) { 20241602Sarchie if (more != NULL) 20341602Sarchie *more = 0; 2041590Srgrimes return (NULL); 20541602Sarchie } 2061590Srgrimes linenum = 0; 2071590Srgrimes switch (script->type) { 2081590Srgrimes case CU_FILE: 2091590Srgrimes if ((f = fopen(script->s, "r")) == NULL) 21028066Scharnier err(1, "%s", script->s); 2111590Srgrimes fname = script->s; 2121590Srgrimes state = ST_FILE; 2131590Srgrimes goto again; 2141590Srgrimes case CU_STRING: 2151590Srgrimes if ((snprintf(string_ident, 2161590Srgrimes sizeof(string_ident), "\"%s\"", script->s)) >= 2171590Srgrimes sizeof(string_ident) - 1) 2181590Srgrimes (void)strcpy(string_ident + 2191590Srgrimes sizeof(string_ident) - 6, " ...\""); 2201590Srgrimes fname = string_ident; 2211590Srgrimes s = script->s; 2221590Srgrimes state = ST_STRING; 2231590Srgrimes goto again; 2241590Srgrimes } 2251590Srgrimes case ST_FILE: 2261590Srgrimes if ((p = fgets(buf, n, f)) != NULL) { 2271590Srgrimes linenum++; 2281590Srgrimes if (linenum == 1 && buf[0] == '#' && buf[1] == 'n') 2291590Srgrimes nflag = 1; 23041602Sarchie if (more != NULL) 23141602Sarchie *more = !feof(f); 2321590Srgrimes return (p); 2331590Srgrimes } 2341590Srgrimes script = script->next; 2351590Srgrimes (void)fclose(f); 2361590Srgrimes state = ST_EOF; 2371590Srgrimes goto again; 2381590Srgrimes case ST_STRING: 2391590Srgrimes if (linenum == 0 && s[0] == '#' && s[1] == 'n') 2401590Srgrimes nflag = 1; 2411590Srgrimes p = buf; 2421590Srgrimes for (;;) { 2431590Srgrimes if (n-- <= 1) { 2441590Srgrimes *p = '\0'; 2451590Srgrimes linenum++; 24641602Sarchie if (more != NULL) 24741602Sarchie *more = 1; 2481590Srgrimes return (buf); 2491590Srgrimes } 2501590Srgrimes switch (*s) { 2511590Srgrimes case '\0': 2521590Srgrimes state = ST_EOF; 2531590Srgrimes if (s == script->s) { 2541590Srgrimes script = script->next; 2551590Srgrimes goto again; 2561590Srgrimes } else { 2571590Srgrimes script = script->next; 2581590Srgrimes *p = '\0'; 2591590Srgrimes linenum++; 26041602Sarchie if (more != NULL) 26141602Sarchie *more = 0; 2621590Srgrimes return (buf); 2631590Srgrimes } 2641590Srgrimes case '\n': 2651590Srgrimes *p++ = '\n'; 2661590Srgrimes *p = '\0'; 2671590Srgrimes s++; 2681590Srgrimes linenum++; 26941602Sarchie if (more != NULL) 27041602Sarchie *more = 0; 2711590Srgrimes return (buf); 2721590Srgrimes default: 2731590Srgrimes *p++ = *s++; 2741590Srgrimes } 2751590Srgrimes } 2761590Srgrimes } 2771590Srgrimes /* NOTREACHED */ 27828066Scharnier return (NULL); 2791590Srgrimes} 2801590Srgrimes 2811590Srgrimes/* 2821590Srgrimes * Like fgets, but go through the list of files chaining them together. 2831590Srgrimes * Set len to the length of the line. 2841590Srgrimes */ 2851590Srgrimesint 2861590Srgrimesmf_fgets(sp, spflag) 2871590Srgrimes SPACE *sp; 2881590Srgrimes enum e_spflag spflag; 2891590Srgrimes{ 2901590Srgrimes static FILE *f; /* Current open file */ 2911590Srgrimes size_t len; 29219829Swosch char *p; 29319829Swosch int c; 2941590Srgrimes 2951590Srgrimes if (f == NULL) 2961590Srgrimes /* Advance to first non-empty file */ 2971590Srgrimes for (;;) { 2981590Srgrimes if (files == NULL) { 2991590Srgrimes lastline = 1; 3001590Srgrimes return (0); 3011590Srgrimes } 3021590Srgrimes if (files->fname == NULL) { 3031590Srgrimes f = stdin; 3041590Srgrimes fname = "stdin"; 3051590Srgrimes } else { 3061590Srgrimes fname = files->fname; 3071590Srgrimes if ((f = fopen(fname, "r")) == NULL) 30828066Scharnier err(1, "%s", fname); 3091590Srgrimes } 31019829Swosch if ((c = getc(f)) != EOF) { 31119829Swosch (void)ungetc(c, f); 3121590Srgrimes break; 3131590Srgrimes } 3141590Srgrimes (void)fclose(f); 3151590Srgrimes files = files->next; 3161590Srgrimes } 3171590Srgrimes 3181590Srgrimes if (lastline) { 3191590Srgrimes sp->len = 0; 3201590Srgrimes return (0); 3211590Srgrimes } 3221590Srgrimes 3231590Srgrimes /* 3241590Srgrimes * Use fgetln so that we can handle essentially infinite input data. 32519829Swosch * Can't use the pointer into the stdio buffer as the process space 32619829Swosch * because the ungetc() can cause it to move. 3271590Srgrimes */ 3281590Srgrimes p = fgetln(f, &len); 3291590Srgrimes if (ferror(f)) 33028066Scharnier errx(1, "%s: %s", fname, strerror(errno ? errno : EIO)); 3311590Srgrimes cspace(sp, p, len, spflag); 3321590Srgrimes 3331590Srgrimes linenum++; 3341590Srgrimes /* Advance to next non-empty file */ 33519829Swosch while ((c = getc(f)) == EOF) { 3361590Srgrimes (void)fclose(f); 3371590Srgrimes files = files->next; 3381590Srgrimes if (files == NULL) { 3391590Srgrimes lastline = 1; 3401590Srgrimes return (1); 3411590Srgrimes } 3421590Srgrimes if (files->fname == NULL) { 3431590Srgrimes f = stdin; 3441590Srgrimes fname = "stdin"; 3451590Srgrimes } else { 3461590Srgrimes fname = files->fname; 3471590Srgrimes if ((f = fopen(fname, "r")) == NULL) 34828066Scharnier err(1, "%s", fname); 3491590Srgrimes } 3501590Srgrimes } 35119829Swosch (void)ungetc(c, f); 3521590Srgrimes return (1); 3531590Srgrimes} 3541590Srgrimes 3551590Srgrimes/* 3561590Srgrimes * Add a compilation unit to the linked list 3571590Srgrimes */ 3581590Srgrimesstatic void 3591590Srgrimesadd_compunit(type, s) 3601590Srgrimes enum e_cut type; 3611590Srgrimes char *s; 3621590Srgrimes{ 3631590Srgrimes struct s_compunit *cu; 3641590Srgrimes 3651590Srgrimes cu = xmalloc(sizeof(struct s_compunit)); 3661590Srgrimes cu->type = type; 3671590Srgrimes cu->s = s; 3681590Srgrimes cu->next = NULL; 3691590Srgrimes *cu_nextp = cu; 3701590Srgrimes cu_nextp = &cu->next; 3711590Srgrimes} 3721590Srgrimes 3731590Srgrimes/* 3741590Srgrimes * Add a file to the linked list 3751590Srgrimes */ 3761590Srgrimesstatic void 3771590Srgrimesadd_file(s) 3781590Srgrimes char *s; 3791590Srgrimes{ 3801590Srgrimes struct s_flist *fp; 3811590Srgrimes 3821590Srgrimes fp = xmalloc(sizeof(struct s_flist)); 3831590Srgrimes fp->next = NULL; 3841590Srgrimes *fl_nextp = fp; 3851590Srgrimes fp->fname = s; 3861590Srgrimes fl_nextp = &fp->next; 3871590Srgrimes} 388