xref: /freebsd/usr.bin/sed/main.c (revision 9b50d9027575220cb6dd09b3e62f03f511e908b8)
19b50d902SRodney W. Grimes /*-
29b50d902SRodney W. Grimes  * Copyright (c) 1992 Diomidis Spinellis.
39b50d902SRodney W. Grimes  * Copyright (c) 1992, 1993
49b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
59b50d902SRodney W. Grimes  *
69b50d902SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
79b50d902SRodney W. Grimes  * Diomidis Spinellis of Imperial College, University of London.
89b50d902SRodney W. Grimes  *
99b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
109b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
119b50d902SRodney W. Grimes  * are met:
129b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
139b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
149b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
159b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
169b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
179b50d902SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
189b50d902SRodney W. Grimes  *    must display the following acknowledgement:
199b50d902SRodney W. Grimes  *	This product includes software developed by the University of
209b50d902SRodney W. Grimes  *	California, Berkeley and its contributors.
219b50d902SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
229b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
239b50d902SRodney W. Grimes  *    without specific prior written permission.
249b50d902SRodney W. Grimes  *
259b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
269b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
279b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
289b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
299b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
309b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
319b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
329b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
339b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
349b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
359b50d902SRodney W. Grimes  * SUCH DAMAGE.
369b50d902SRodney W. Grimes  */
379b50d902SRodney W. Grimes 
389b50d902SRodney W. Grimes #ifndef lint
399b50d902SRodney W. Grimes static char copyright[] =
409b50d902SRodney W. Grimes "@(#) Copyright (c) 1992, 1993\n\
419b50d902SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
429b50d902SRodney W. Grimes #endif /* not lint */
439b50d902SRodney W. Grimes 
449b50d902SRodney W. Grimes #ifndef lint
459b50d902SRodney W. Grimes static char sccsid[] = "@(#)main.c	8.2 (Berkeley) 1/3/94";
469b50d902SRodney W. Grimes #endif /* not lint */
479b50d902SRodney W. Grimes 
489b50d902SRodney W. Grimes #include <sys/types.h>
499b50d902SRodney W. Grimes 
509b50d902SRodney W. Grimes #include <ctype.h>
519b50d902SRodney W. Grimes #include <errno.h>
529b50d902SRodney W. Grimes #include <fcntl.h>
539b50d902SRodney W. Grimes #include <regex.h>
549b50d902SRodney W. Grimes #include <stddef.h>
559b50d902SRodney W. Grimes #include <stdio.h>
569b50d902SRodney W. Grimes #include <stdlib.h>
579b50d902SRodney W. Grimes #include <string.h>
589b50d902SRodney W. Grimes #include <unistd.h>
599b50d902SRodney W. Grimes 
609b50d902SRodney W. Grimes #include "defs.h"
619b50d902SRodney W. Grimes #include "extern.h"
629b50d902SRodney W. Grimes 
639b50d902SRodney W. Grimes /*
649b50d902SRodney W. Grimes  * Linked list of units (strings and files) to be compiled
659b50d902SRodney W. Grimes  */
669b50d902SRodney W. Grimes struct s_compunit {
679b50d902SRodney W. Grimes 	struct s_compunit *next;
689b50d902SRodney W. Grimes 	enum e_cut {CU_FILE, CU_STRING} type;
699b50d902SRodney W. Grimes 	char *s;			/* Pointer to string or fname */
709b50d902SRodney W. Grimes };
719b50d902SRodney W. Grimes 
729b50d902SRodney W. Grimes /*
739b50d902SRodney W. Grimes  * Linked list pointer to compilation units and pointer to current
749b50d902SRodney W. Grimes  * next pointer.
759b50d902SRodney W. Grimes  */
769b50d902SRodney W. Grimes static struct s_compunit *script, **cu_nextp = &script;
779b50d902SRodney W. Grimes 
789b50d902SRodney W. Grimes /*
799b50d902SRodney W. Grimes  * Linked list of files to be processed
809b50d902SRodney W. Grimes  */
819b50d902SRodney W. Grimes struct s_flist {
829b50d902SRodney W. Grimes 	char *fname;
839b50d902SRodney W. Grimes 	struct s_flist *next;
849b50d902SRodney W. Grimes };
859b50d902SRodney W. Grimes 
869b50d902SRodney W. Grimes /*
879b50d902SRodney W. Grimes  * Linked list pointer to files and pointer to current
889b50d902SRodney W. Grimes  * next pointer.
899b50d902SRodney W. Grimes  */
909b50d902SRodney W. Grimes static struct s_flist *files, **fl_nextp = &files;
919b50d902SRodney W. Grimes 
929b50d902SRodney W. Grimes int aflag, eflag, nflag;
939b50d902SRodney W. Grimes 
949b50d902SRodney W. Grimes /*
959b50d902SRodney W. Grimes  * Current file and line number; line numbers restart across compilation
969b50d902SRodney W. Grimes  * units, but span across input files.
979b50d902SRodney W. Grimes  */
989b50d902SRodney W. Grimes char *fname;			/* File name. */
999b50d902SRodney W. Grimes u_long linenum;
1009b50d902SRodney W. Grimes int lastline;			/* TRUE on the last line of the last file */
1019b50d902SRodney W. Grimes 
1029b50d902SRodney W. Grimes static void add_compunit __P((enum e_cut, char *));
1039b50d902SRodney W. Grimes static void add_file __P((char *));
1049b50d902SRodney W. Grimes 
1059b50d902SRodney W. Grimes int
1069b50d902SRodney W. Grimes main(argc, argv)
1079b50d902SRodney W. Grimes 	int argc;
1089b50d902SRodney W. Grimes 	char *argv[];
1099b50d902SRodney W. Grimes {
1109b50d902SRodney W. Grimes 	int c, fflag;
1119b50d902SRodney W. Grimes 
1129b50d902SRodney W. Grimes 	fflag = 0;
1139b50d902SRodney W. Grimes 	while ((c = getopt(argc, argv, "ae:f:n")) != EOF)
1149b50d902SRodney W. Grimes 		switch (c) {
1159b50d902SRodney W. Grimes 		case 'a':
1169b50d902SRodney W. Grimes 			aflag = 1;
1179b50d902SRodney W. Grimes 			break;
1189b50d902SRodney W. Grimes 		case 'e':
1199b50d902SRodney W. Grimes 			eflag = 1;
1209b50d902SRodney W. Grimes 			add_compunit(CU_STRING, optarg);
1219b50d902SRodney W. Grimes 			break;
1229b50d902SRodney W. Grimes 		case 'f':
1239b50d902SRodney W. Grimes 			fflag = 1;
1249b50d902SRodney W. Grimes 			add_compunit(CU_FILE, optarg);
1259b50d902SRodney W. Grimes 			break;
1269b50d902SRodney W. Grimes 		case 'n':
1279b50d902SRodney W. Grimes 			nflag = 1;
1289b50d902SRodney W. Grimes 			break;
1299b50d902SRodney W. Grimes 		default:
1309b50d902SRodney W. Grimes 		case '?':
1319b50d902SRodney W. Grimes 			(void)fprintf(stderr,
1329b50d902SRodney W. Grimes "usage:\tsed script [-an] [file ...]\n\tsed [-an] [-e script] ... [-f scipt_file] ... [file ...]\n");
1339b50d902SRodney W. Grimes 			exit(1);
1349b50d902SRodney W. Grimes 		}
1359b50d902SRodney W. Grimes 	argc -= optind;
1369b50d902SRodney W. Grimes 	argv += optind;
1379b50d902SRodney W. Grimes 
1389b50d902SRodney W. Grimes 	/* First usage case; script is the first arg */
1399b50d902SRodney W. Grimes 	if (!eflag && !fflag && *argv) {
1409b50d902SRodney W. Grimes 		add_compunit(CU_STRING, *argv);
1419b50d902SRodney W. Grimes 		argv++;
1429b50d902SRodney W. Grimes 	}
1439b50d902SRodney W. Grimes 
1449b50d902SRodney W. Grimes 	compile();
1459b50d902SRodney W. Grimes 
1469b50d902SRodney W. Grimes 	/* Continue with first and start second usage */
1479b50d902SRodney W. Grimes 	if (*argv)
1489b50d902SRodney W. Grimes 		for (; *argv; argv++)
1499b50d902SRodney W. Grimes 			add_file(*argv);
1509b50d902SRodney W. Grimes 	else
1519b50d902SRodney W. Grimes 		add_file(NULL);
1529b50d902SRodney W. Grimes 	process();
1539b50d902SRodney W. Grimes 	cfclose(prog, NULL);
1549b50d902SRodney W. Grimes 	if (fclose(stdout))
1559b50d902SRodney W. Grimes 		err(FATAL, "stdout: %s", strerror(errno));
1569b50d902SRodney W. Grimes 	exit (0);
1579b50d902SRodney W. Grimes }
1589b50d902SRodney W. Grimes 
1599b50d902SRodney W. Grimes /*
1609b50d902SRodney W. Grimes  * Like fgets, but go through the chain of compilation units chaining them
1619b50d902SRodney W. Grimes  * together.  Empty strings and files are ignored.
1629b50d902SRodney W. Grimes  */
1639b50d902SRodney W. Grimes char *
1649b50d902SRodney W. Grimes cu_fgets(buf, n)
1659b50d902SRodney W. Grimes 	char *buf;
1669b50d902SRodney W. Grimes 	int n;
1679b50d902SRodney W. Grimes {
1689b50d902SRodney W. Grimes 	static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
1699b50d902SRodney W. Grimes 	static FILE *f;		/* Current open file */
1709b50d902SRodney W. Grimes 	static char *s;		/* Current pointer inside string */
1719b50d902SRodney W. Grimes 	static char string_ident[30];
1729b50d902SRodney W. Grimes 	char *p;
1739b50d902SRodney W. Grimes 
1749b50d902SRodney W. Grimes again:
1759b50d902SRodney W. Grimes 	switch (state) {
1769b50d902SRodney W. Grimes 	case ST_EOF:
1779b50d902SRodney W. Grimes 		if (script == NULL)
1789b50d902SRodney W. Grimes 			return (NULL);
1799b50d902SRodney W. Grimes 		linenum = 0;
1809b50d902SRodney W. Grimes 		switch (script->type) {
1819b50d902SRodney W. Grimes 		case CU_FILE:
1829b50d902SRodney W. Grimes 			if ((f = fopen(script->s, "r")) == NULL)
1839b50d902SRodney W. Grimes 				err(FATAL,
1849b50d902SRodney W. Grimes 				    "%s: %s", script->s, strerror(errno));
1859b50d902SRodney W. Grimes 			fname = script->s;
1869b50d902SRodney W. Grimes 			state = ST_FILE;
1879b50d902SRodney W. Grimes 			goto again;
1889b50d902SRodney W. Grimes 		case CU_STRING:
1899b50d902SRodney W. Grimes 			if ((snprintf(string_ident,
1909b50d902SRodney W. Grimes 			    sizeof(string_ident), "\"%s\"", script->s)) >=
1919b50d902SRodney W. Grimes 			    sizeof(string_ident) - 1)
1929b50d902SRodney W. Grimes 				(void)strcpy(string_ident +
1939b50d902SRodney W. Grimes 				    sizeof(string_ident) - 6, " ...\"");
1949b50d902SRodney W. Grimes 			fname = string_ident;
1959b50d902SRodney W. Grimes 			s = script->s;
1969b50d902SRodney W. Grimes 			state = ST_STRING;
1979b50d902SRodney W. Grimes 			goto again;
1989b50d902SRodney W. Grimes 		}
1999b50d902SRodney W. Grimes 	case ST_FILE:
2009b50d902SRodney W. Grimes 		if ((p = fgets(buf, n, f)) != NULL) {
2019b50d902SRodney W. Grimes 			linenum++;
2029b50d902SRodney W. Grimes 			if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
2039b50d902SRodney W. Grimes 				nflag = 1;
2049b50d902SRodney W. Grimes 			return (p);
2059b50d902SRodney W. Grimes 		}
2069b50d902SRodney W. Grimes 		script = script->next;
2079b50d902SRodney W. Grimes 		(void)fclose(f);
2089b50d902SRodney W. Grimes 		state = ST_EOF;
2099b50d902SRodney W. Grimes 		goto again;
2109b50d902SRodney W. Grimes 	case ST_STRING:
2119b50d902SRodney W. Grimes 		if (linenum == 0 && s[0] == '#' && s[1] == 'n')
2129b50d902SRodney W. Grimes 			nflag = 1;
2139b50d902SRodney W. Grimes 		p = buf;
2149b50d902SRodney W. Grimes 		for (;;) {
2159b50d902SRodney W. Grimes 			if (n-- <= 1) {
2169b50d902SRodney W. Grimes 				*p = '\0';
2179b50d902SRodney W. Grimes 				linenum++;
2189b50d902SRodney W. Grimes 				return (buf);
2199b50d902SRodney W. Grimes 			}
2209b50d902SRodney W. Grimes 			switch (*s) {
2219b50d902SRodney W. Grimes 			case '\0':
2229b50d902SRodney W. Grimes 				state = ST_EOF;
2239b50d902SRodney W. Grimes 				if (s == script->s) {
2249b50d902SRodney W. Grimes 					script = script->next;
2259b50d902SRodney W. Grimes 					goto again;
2269b50d902SRodney W. Grimes 				} else {
2279b50d902SRodney W. Grimes 					script = script->next;
2289b50d902SRodney W. Grimes 					*p = '\0';
2299b50d902SRodney W. Grimes 					linenum++;
2309b50d902SRodney W. Grimes 					return (buf);
2319b50d902SRodney W. Grimes 				}
2329b50d902SRodney W. Grimes 			case '\n':
2339b50d902SRodney W. Grimes 				*p++ = '\n';
2349b50d902SRodney W. Grimes 				*p = '\0';
2359b50d902SRodney W. Grimes 				s++;
2369b50d902SRodney W. Grimes 				linenum++;
2379b50d902SRodney W. Grimes 				return (buf);
2389b50d902SRodney W. Grimes 			default:
2399b50d902SRodney W. Grimes 				*p++ = *s++;
2409b50d902SRodney W. Grimes 			}
2419b50d902SRodney W. Grimes 		}
2429b50d902SRodney W. Grimes 	}
2439b50d902SRodney W. Grimes 	/* NOTREACHED */
2449b50d902SRodney W. Grimes }
2459b50d902SRodney W. Grimes 
2469b50d902SRodney W. Grimes /*
2479b50d902SRodney W. Grimes  * Like fgets, but go through the list of files chaining them together.
2489b50d902SRodney W. Grimes  * Set len to the length of the line.
2499b50d902SRodney W. Grimes  */
2509b50d902SRodney W. Grimes int
2519b50d902SRodney W. Grimes mf_fgets(sp, spflag)
2529b50d902SRodney W. Grimes 	SPACE *sp;
2539b50d902SRodney W. Grimes 	enum e_spflag spflag;
2549b50d902SRodney W. Grimes {
2559b50d902SRodney W. Grimes 	static FILE *f;		/* Current open file */
2569b50d902SRodney W. Grimes 	size_t len;
2579b50d902SRodney W. Grimes 	char c, *p;
2589b50d902SRodney W. Grimes 
2599b50d902SRodney W. Grimes 	if (f == NULL)
2609b50d902SRodney W. Grimes 		/* Advance to first non-empty file */
2619b50d902SRodney W. Grimes 		for (;;) {
2629b50d902SRodney W. Grimes 			if (files == NULL) {
2639b50d902SRodney W. Grimes 				lastline = 1;
2649b50d902SRodney W. Grimes 				return (0);
2659b50d902SRodney W. Grimes 			}
2669b50d902SRodney W. Grimes 			if (files->fname == NULL) {
2679b50d902SRodney W. Grimes 				f = stdin;
2689b50d902SRodney W. Grimes 				fname = "stdin";
2699b50d902SRodney W. Grimes 			} else {
2709b50d902SRodney W. Grimes 				fname = files->fname;
2719b50d902SRodney W. Grimes 				if ((f = fopen(fname, "r")) == NULL)
2729b50d902SRodney W. Grimes 					err(FATAL, "%s: %s",
2739b50d902SRodney W. Grimes 					    fname, strerror(errno));
2749b50d902SRodney W. Grimes 			}
2759b50d902SRodney W. Grimes 			if ((c = getc(f)) != EOF) {
2769b50d902SRodney W. Grimes 				(void)ungetc(c, f);
2779b50d902SRodney W. Grimes 				break;
2789b50d902SRodney W. Grimes 			}
2799b50d902SRodney W. Grimes 			(void)fclose(f);
2809b50d902SRodney W. Grimes 			files = files->next;
2819b50d902SRodney W. Grimes 		}
2829b50d902SRodney W. Grimes 
2839b50d902SRodney W. Grimes 	if (lastline) {
2849b50d902SRodney W. Grimes 		sp->len = 0;
2859b50d902SRodney W. Grimes 		return (0);
2869b50d902SRodney W. Grimes 	}
2879b50d902SRodney W. Grimes 
2889b50d902SRodney W. Grimes 	/*
2899b50d902SRodney W. Grimes 	 * Use fgetln so that we can handle essentially infinite input data.
2909b50d902SRodney W. Grimes 	 * Can't use the pointer into the stdio buffer as the process space
2919b50d902SRodney W. Grimes 	 * because the ungetc() can cause it to move.
2929b50d902SRodney W. Grimes 	 */
2939b50d902SRodney W. Grimes 	p = fgetln(f, &len);
2949b50d902SRodney W. Grimes 	if (ferror(f))
2959b50d902SRodney W. Grimes 		err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO));
2969b50d902SRodney W. Grimes 	cspace(sp, p, len, spflag);
2979b50d902SRodney W. Grimes 
2989b50d902SRodney W. Grimes 	linenum++;
2999b50d902SRodney W. Grimes 	/* Advance to next non-empty file */
3009b50d902SRodney W. Grimes 	while ((c = getc(f)) == EOF) {
3019b50d902SRodney W. Grimes 		(void)fclose(f);
3029b50d902SRodney W. Grimes 		files = files->next;
3039b50d902SRodney W. Grimes 		if (files == NULL) {
3049b50d902SRodney W. Grimes 			lastline = 1;
3059b50d902SRodney W. Grimes 			return (1);
3069b50d902SRodney W. Grimes 		}
3079b50d902SRodney W. Grimes 		if (files->fname == NULL) {
3089b50d902SRodney W. Grimes 			f = stdin;
3099b50d902SRodney W. Grimes 			fname = "stdin";
3109b50d902SRodney W. Grimes 		} else {
3119b50d902SRodney W. Grimes 			fname = files->fname;
3129b50d902SRodney W. Grimes 			if ((f = fopen(fname, "r")) == NULL)
3139b50d902SRodney W. Grimes 				err(FATAL, "%s: %s", fname, strerror(errno));
3149b50d902SRodney W. Grimes 		}
3159b50d902SRodney W. Grimes 	}
3169b50d902SRodney W. Grimes 	(void)ungetc(c, f);
3179b50d902SRodney W. Grimes 	return (1);
3189b50d902SRodney W. Grimes }
3199b50d902SRodney W. Grimes 
3209b50d902SRodney W. Grimes /*
3219b50d902SRodney W. Grimes  * Add a compilation unit to the linked list
3229b50d902SRodney W. Grimes  */
3239b50d902SRodney W. Grimes static void
3249b50d902SRodney W. Grimes add_compunit(type, s)
3259b50d902SRodney W. Grimes 	enum e_cut type;
3269b50d902SRodney W. Grimes 	char *s;
3279b50d902SRodney W. Grimes {
3289b50d902SRodney W. Grimes 	struct s_compunit *cu;
3299b50d902SRodney W. Grimes 
3309b50d902SRodney W. Grimes 	cu = xmalloc(sizeof(struct s_compunit));
3319b50d902SRodney W. Grimes 	cu->type = type;
3329b50d902SRodney W. Grimes 	cu->s = s;
3339b50d902SRodney W. Grimes 	cu->next = NULL;
3349b50d902SRodney W. Grimes 	*cu_nextp = cu;
3359b50d902SRodney W. Grimes 	cu_nextp = &cu->next;
3369b50d902SRodney W. Grimes }
3379b50d902SRodney W. Grimes 
3389b50d902SRodney W. Grimes /*
3399b50d902SRodney W. Grimes  * Add a file to the linked list
3409b50d902SRodney W. Grimes  */
3419b50d902SRodney W. Grimes static void
3429b50d902SRodney W. Grimes add_file(s)
3439b50d902SRodney W. Grimes 	char *s;
3449b50d902SRodney W. Grimes {
3459b50d902SRodney W. Grimes 	struct s_flist *fp;
3469b50d902SRodney W. Grimes 
3479b50d902SRodney W. Grimes 	fp = xmalloc(sizeof(struct s_flist));
3489b50d902SRodney W. Grimes 	fp->next = NULL;
3499b50d902SRodney W. Grimes 	*fl_nextp = fp;
3509b50d902SRodney W. Grimes 	fp->fname = s;
3519b50d902SRodney W. Grimes 	fl_nextp = &fp->next;
3529b50d902SRodney W. Grimes }
353