155995Sbostic /*- 255995Sbostic * Copyright (c) 1992 Diomidis Spinellis. 355995Sbostic * Copyright (c) 1992 The Regents of the University of California. 455995Sbostic * 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 1355995Sbostic char copyright[] = 1455995Sbostic "@(#) Copyright (c) 1992 The Regents of the University of California.\n\ 1555995Sbostic All rights reserved.\n"; 1655995Sbostic #endif /* not lint */ 1755995Sbostic 1855995Sbostic #ifndef lint 19*56093Sbostic static char sccsid[] = "@(#)main.c 5.6 (Berkeley) 08/30/92"; 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 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(); 127*56093Sbostic 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 * 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 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 /* 26356078Sbostic * Use fgetline so that we can handle essentially infinite input 26456078Sbostic * data. Can't use the pointer into the stdio buffer as the process 26556078Sbostic * space because the ungetc() can cause it to move. 26656078Sbostic */ 26756078Sbostic p = fgetline(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 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 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