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