xref: /csrg-svn/usr.bin/sed/main.c (revision 65363)
155995Sbostic /*-
255995Sbostic  * Copyright (c) 1992 Diomidis Spinellis.
362229Sbostic  * Copyright (c) 1992, 1993
462229Sbostic  *	The Regents of the University of California.  All rights reserved.
555995Sbostic  *
655995Sbostic  * This code is derived from software contributed to Berkeley by
755995Sbostic  * Diomidis Spinellis of Imperial College, University of London.
855995Sbostic  *
955995Sbostic  * %sccs.include.redist.c%
1055995Sbostic  */
1155995Sbostic 
1255995Sbostic #ifndef lint
1362229Sbostic static char copyright[] =
1462229Sbostic "@(#) Copyright (c) 1992, 1993\n\
1562229Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1655995Sbostic #endif /* not lint */
1755995Sbostic 
1855995Sbostic #ifndef lint
19*65363Sbostic static char sccsid[] = "@(#)main.c	8.2 (Berkeley) 01/03/94";
2055995Sbostic #endif /* not lint */
2155995Sbostic 
2255995Sbostic #include <sys/types.h>
2355995Sbostic 
2455995Sbostic #include <ctype.h>
2555995Sbostic #include <errno.h>
2655995Sbostic #include <fcntl.h>
2755995Sbostic #include <regex.h>
2855995Sbostic #include <stddef.h>
2955995Sbostic #include <stdio.h>
3055995Sbostic #include <stdlib.h>
3155995Sbostic #include <string.h>
3255995Sbostic #include <unistd.h>
3355995Sbostic 
3455995Sbostic #include "defs.h"
3555995Sbostic #include "extern.h"
3655995Sbostic 
3755995Sbostic /*
3855995Sbostic  * Linked list of units (strings and files) to be compiled
3955995Sbostic  */
4055995Sbostic struct s_compunit {
4155995Sbostic 	struct s_compunit *next;
4255995Sbostic 	enum e_cut {CU_FILE, CU_STRING} type;
4355995Sbostic 	char *s;			/* Pointer to string or fname */
4455995Sbostic };
4555995Sbostic 
4655995Sbostic /*
4755995Sbostic  * Linked list pointer to compilation units and pointer to current
4855995Sbostic  * next pointer.
4955995Sbostic  */
5055995Sbostic static struct s_compunit *script, **cu_nextp = &script;
5155995Sbostic 
5255995Sbostic /*
5355995Sbostic  * Linked list of files to be processed
5455995Sbostic  */
5555995Sbostic struct s_flist {
5655995Sbostic 	char *fname;
5755995Sbostic 	struct s_flist *next;
5855995Sbostic };
5955995Sbostic 
6055995Sbostic /*
6155995Sbostic  * Linked list pointer to files and pointer to current
6255995Sbostic  * next pointer.
6355995Sbostic  */
6455995Sbostic static struct s_flist *files, **fl_nextp = &files;
6555995Sbostic 
6655995Sbostic int aflag, eflag, nflag;
6755995Sbostic 
6855995Sbostic /*
6955995Sbostic  * Current file and line number; line numbers restart across compilation
7055995Sbostic  * units, but span across input files.
7155995Sbostic  */
7255995Sbostic char *fname;			/* File name. */
7355995Sbostic u_long linenum;
7455995Sbostic int lastline;			/* TRUE on the last line of the last file */
7555995Sbostic 
7655995Sbostic static void add_compunit __P((enum e_cut, char *));
7755995Sbostic static void add_file __P((char *));
7855995Sbostic 
7955995Sbostic int
main(argc,argv)8055995Sbostic main(argc, argv)
8155995Sbostic 	int argc;
8255995Sbostic 	char *argv[];
8355995Sbostic {
8455995Sbostic 	int c, fflag;
8555995Sbostic 
8655995Sbostic 	fflag = 0;
8755995Sbostic 	while ((c = getopt(argc, argv, "ae:f:n")) != EOF)
8855995Sbostic 		switch (c) {
8955995Sbostic 		case 'a':
9055995Sbostic 			aflag = 1;
9155995Sbostic 			break;
9255995Sbostic 		case 'e':
9355995Sbostic 			eflag = 1;
9455995Sbostic 			add_compunit(CU_STRING, optarg);
9555995Sbostic 			break;
9655995Sbostic 		case 'f':
9755995Sbostic 			fflag = 1;
9855995Sbostic 			add_compunit(CU_FILE, optarg);
9955995Sbostic 			break;
10055995Sbostic 		case 'n':
10155995Sbostic 			nflag = 1;
10255995Sbostic 			break;
10355995Sbostic 		default:
10455995Sbostic 		case '?':
10555995Sbostic 			(void)fprintf(stderr,
10655995Sbostic "usage:\tsed script [-an] [file ...]\n\tsed [-an] [-e script] ... [-f scipt_file] ... [file ...]\n");
10755995Sbostic 			exit(1);
10855995Sbostic 		}
10955995Sbostic 	argc -= optind;
11055995Sbostic 	argv += optind;
11155995Sbostic 
11255995Sbostic 	/* First usage case; script is the first arg */
11355995Sbostic 	if (!eflag && !fflag && *argv) {
11455995Sbostic 		add_compunit(CU_STRING, *argv);
11555995Sbostic 		argv++;
11655995Sbostic 	}
11755995Sbostic 
11855995Sbostic 	compile();
11955995Sbostic 
12055995Sbostic 	/* Continue with first and start second usage */
12155995Sbostic 	if (*argv)
12255995Sbostic 		for (; *argv; argv++)
12355995Sbostic 			add_file(*argv);
12455995Sbostic 	else
12555995Sbostic 		add_file(NULL);
12655995Sbostic 	process();
12756093Sbostic 	cfclose(prog, NULL);
12855995Sbostic 	if (fclose(stdout))
12955995Sbostic 		err(FATAL, "stdout: %s", strerror(errno));
13055995Sbostic 	exit (0);
13155995Sbostic }
13255995Sbostic 
13355995Sbostic /*
13455995Sbostic  * Like fgets, but go through the chain of compilation units chaining them
13555995Sbostic  * together.  Empty strings and files are ignored.
13655995Sbostic  */
13755995Sbostic char *
cu_fgets(buf,n)13855995Sbostic cu_fgets(buf, n)
13955995Sbostic 	char *buf;
14055995Sbostic 	int n;
14155995Sbostic {
14255995Sbostic 	static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
14355995Sbostic 	static FILE *f;		/* Current open file */
14455995Sbostic 	static char *s;		/* Current pointer inside string */
14556044Sbostic 	static char string_ident[30];
14655995Sbostic 	char *p;
14755995Sbostic 
14855995Sbostic again:
14955995Sbostic 	switch (state) {
15055995Sbostic 	case ST_EOF:
15155995Sbostic 		if (script == NULL)
15255995Sbostic 			return (NULL);
15355995Sbostic 		linenum = 0;
15455995Sbostic 		switch (script->type) {
15555995Sbostic 		case CU_FILE:
15655995Sbostic 			if ((f = fopen(script->s, "r")) == NULL)
15755995Sbostic 				err(FATAL,
15855995Sbostic 				    "%s: %s", script->s, strerror(errno));
15955995Sbostic 			fname = script->s;
16055995Sbostic 			state = ST_FILE;
16155995Sbostic 			goto again;
16255995Sbostic 		case CU_STRING:
16356044Sbostic 			if ((snprintf(string_ident,
16456044Sbostic 			    sizeof(string_ident), "\"%s\"", script->s)) >=
16556044Sbostic 			    sizeof(string_ident) - 1)
16656044Sbostic 				(void)strcpy(string_ident +
16756044Sbostic 				    sizeof(string_ident) - 6, " ...\"");
16855995Sbostic 			fname = string_ident;
16955995Sbostic 			s = script->s;
17055995Sbostic 			state = ST_STRING;
17155995Sbostic 			goto again;
17255995Sbostic 		}
17355995Sbostic 	case ST_FILE:
17455995Sbostic 		if ((p = fgets(buf, n, f)) != NULL) {
17555995Sbostic 			linenum++;
17655995Sbostic 			if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
17755995Sbostic 				nflag = 1;
17855995Sbostic 			return (p);
17955995Sbostic 		}
18055995Sbostic 		script = script->next;
18155995Sbostic 		(void)fclose(f);
18255995Sbostic 		state = ST_EOF;
18355995Sbostic 		goto again;
18455995Sbostic 	case ST_STRING:
18555995Sbostic 		if (linenum == 0 && s[0] == '#' && s[1] == 'n')
18655995Sbostic 			nflag = 1;
18755995Sbostic 		p = buf;
18855995Sbostic 		for (;;) {
18955995Sbostic 			if (n-- <= 1) {
19055995Sbostic 				*p = '\0';
19155995Sbostic 				linenum++;
19255995Sbostic 				return (buf);
19355995Sbostic 			}
19455995Sbostic 			switch (*s) {
19555995Sbostic 			case '\0':
19655995Sbostic 				state = ST_EOF;
19755995Sbostic 				if (s == script->s) {
19855995Sbostic 					script = script->next;
19955995Sbostic 					goto again;
20055995Sbostic 				} else {
20155995Sbostic 					script = script->next;
20255995Sbostic 					*p = '\0';
20355995Sbostic 					linenum++;
20455995Sbostic 					return (buf);
20555995Sbostic 				}
20655995Sbostic 			case '\n':
20755995Sbostic 				*p++ = '\n';
20855995Sbostic 				*p = '\0';
20955995Sbostic 				s++;
21055995Sbostic 				linenum++;
21155995Sbostic 				return (buf);
21255995Sbostic 			default:
21355995Sbostic 				*p++ = *s++;
21455995Sbostic 			}
21555995Sbostic 		}
21655995Sbostic 	}
21755995Sbostic 	/* NOTREACHED */
21855995Sbostic }
21955995Sbostic 
22055995Sbostic /*
22155995Sbostic  * Like fgets, but go through the list of files chaining them together.
22255995Sbostic  * Set len to the length of the line.
22355995Sbostic  */
22456078Sbostic int
mf_fgets(sp,spflag)22556078Sbostic mf_fgets(sp, spflag)
22656078Sbostic 	SPACE *sp;
22756078Sbostic 	enum e_spflag spflag;
22855995Sbostic {
22955995Sbostic 	static FILE *f;		/* Current open file */
23056078Sbostic 	size_t len;
23155995Sbostic 	char c, *p;
23255995Sbostic 
23355995Sbostic 	if (f == NULL)
23455995Sbostic 		/* Advance to first non-empty file */
23555995Sbostic 		for (;;) {
23655995Sbostic 			if (files == NULL) {
23755995Sbostic 				lastline = 1;
23856078Sbostic 				return (0);
23955995Sbostic 			}
24055995Sbostic 			if (files->fname == NULL) {
24155995Sbostic 				f = stdin;
24255995Sbostic 				fname = "stdin";
24355995Sbostic 			} else {
24455995Sbostic 				fname = files->fname;
24555995Sbostic 				if ((f = fopen(fname, "r")) == NULL)
24655995Sbostic 					err(FATAL, "%s: %s",
24755995Sbostic 					    fname, strerror(errno));
24855995Sbostic 			}
24955995Sbostic 			if ((c = getc(f)) != EOF) {
25055995Sbostic 				(void)ungetc(c, f);
25155995Sbostic 				break;
25255995Sbostic 			}
25355995Sbostic 			(void)fclose(f);
25455995Sbostic 			files = files->next;
25555995Sbostic 		}
25655995Sbostic 
25755995Sbostic 	if (lastline) {
25856078Sbostic 		sp->len = 0;
25956078Sbostic 		return (0);
26055995Sbostic 	}
26155995Sbostic 
26256078Sbostic 	/*
263*65363Sbostic 	 * Use fgetln so that we can handle essentially infinite input data.
264*65363Sbostic 	 * Can't use the pointer into the stdio buffer as the process space
265*65363Sbostic 	 * because the ungetc() can cause it to move.
26656078Sbostic 	 */
267*65363Sbostic 	p = fgetln(f, &len);
26855995Sbostic 	if (ferror(f))
26955995Sbostic 		err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO));
27056078Sbostic 	cspace(sp, p, len, spflag);
27155995Sbostic 
27255995Sbostic 	linenum++;
27355995Sbostic 	/* Advance to next non-empty file */
27455995Sbostic 	while ((c = getc(f)) == EOF) {
27555995Sbostic 		(void)fclose(f);
27655995Sbostic 		files = files->next;
27755995Sbostic 		if (files == NULL) {
27855995Sbostic 			lastline = 1;
27956078Sbostic 			return (1);
28055995Sbostic 		}
28155995Sbostic 		if (files->fname == NULL) {
28255995Sbostic 			f = stdin;
28355995Sbostic 			fname = "stdin";
28455995Sbostic 		} else {
28555995Sbostic 			fname = files->fname;
28655995Sbostic 			if ((f = fopen(fname, "r")) == NULL)
28755995Sbostic 				err(FATAL, "%s: %s", fname, strerror(errno));
28855995Sbostic 		}
28955995Sbostic 	}
29055995Sbostic 	(void)ungetc(c, f);
29156078Sbostic 	return (1);
29255995Sbostic }
29355995Sbostic 
29455995Sbostic /*
29555995Sbostic  * Add a compilation unit to the linked list
29655995Sbostic  */
29755995Sbostic static void
add_compunit(type,s)29855995Sbostic add_compunit(type, s)
29955995Sbostic 	enum e_cut type;
30055995Sbostic 	char *s;
30155995Sbostic {
30255995Sbostic 	struct s_compunit *cu;
30355995Sbostic 
30455995Sbostic 	cu = xmalloc(sizeof(struct s_compunit));
30555995Sbostic 	cu->type = type;
30655995Sbostic 	cu->s = s;
30755995Sbostic 	cu->next = NULL;
30855995Sbostic 	*cu_nextp = cu;
30955995Sbostic 	cu_nextp = &cu->next;
31055995Sbostic }
31155995Sbostic 
31255995Sbostic /*
31355995Sbostic  * Add a file to the linked list
31455995Sbostic  */
31555995Sbostic static void
add_file(s)31655995Sbostic add_file(s)
31755995Sbostic 	char *s;
31855995Sbostic {
31955995Sbostic 	struct s_flist *fp;
32055995Sbostic 
32155995Sbostic 	fp = xmalloc(sizeof(struct s_flist));
32255995Sbostic 	fp->next = NULL;
32355995Sbostic 	*fl_nextp = fp;
32455995Sbostic 	fp->fname = s;
32555995Sbostic 	fl_nextp = &fp->next;
32655995Sbostic }
327