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*56044Sbostic static char sccsid[] = "@(#)main.c 5.4 (Berkeley) 08/26/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(); 12755995Sbostic cfclose(prog); 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 */ 145*56044Sbostic 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: 163*56044Sbostic if ((snprintf(string_ident, 164*56044Sbostic sizeof(string_ident), "\"%s\"", script->s)) >= 165*56044Sbostic sizeof(string_ident) - 1) 166*56044Sbostic (void)strcpy(string_ident + 167*56044Sbostic 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 */ 22455995Sbostic char * 22555995Sbostic mf_fgets(lenp) 22655995Sbostic size_t *lenp; 22755995Sbostic { 22855995Sbostic static FILE *f; /* Current open file */ 22955995Sbostic char c, *p; 23055995Sbostic 23155995Sbostic if (f == NULL) 23255995Sbostic /* Advance to first non-empty file */ 23355995Sbostic for (;;) { 23455995Sbostic if (files == NULL) { 23555995Sbostic lastline = 1; 23655995Sbostic return (NULL); 23755995Sbostic } 23855995Sbostic if (files->fname == NULL) { 23955995Sbostic f = stdin; 24055995Sbostic fname = "stdin"; 24155995Sbostic } else { 24255995Sbostic fname = files->fname; 24355995Sbostic if ((f = fopen(fname, "r")) == NULL) 24455995Sbostic err(FATAL, "%s: %s", 24555995Sbostic fname, strerror(errno)); 24655995Sbostic } 24755995Sbostic if ((c = getc(f)) != EOF) { 24855995Sbostic (void)ungetc(c, f); 24955995Sbostic break; 25055995Sbostic } 25155995Sbostic (void)fclose(f); 25255995Sbostic files = files->next; 25355995Sbostic } 25455995Sbostic 25555995Sbostic if (lastline) { 25655995Sbostic *lenp = 0; 25755995Sbostic return (NULL); 25855995Sbostic } 25955995Sbostic 26055995Sbostic p = fgetline(f, lenp); 26155995Sbostic if (ferror(f)) 26255995Sbostic err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO)); 26355995Sbostic 26455995Sbostic linenum++; 26555995Sbostic /* Advance to next non-empty file */ 26655995Sbostic while ((c = getc(f)) == EOF) { 26755995Sbostic (void)fclose(f); 26855995Sbostic files = files->next; 26955995Sbostic if (files == NULL) { 27055995Sbostic lastline = 1; 27155995Sbostic return (p); 27255995Sbostic } 27355995Sbostic if (files->fname == NULL) { 27455995Sbostic f = stdin; 27555995Sbostic fname = "stdin"; 27655995Sbostic } else { 27755995Sbostic fname = files->fname; 27855995Sbostic if ((f = fopen(fname, "r")) == NULL) 27955995Sbostic err(FATAL, "%s: %s", fname, strerror(errno)); 28055995Sbostic } 28155995Sbostic } 28255995Sbostic (void)ungetc(c, f); 28355995Sbostic return (p); 28455995Sbostic } 28555995Sbostic 28655995Sbostic /* 28755995Sbostic * Add a compilation unit to the linked list 28855995Sbostic */ 28955995Sbostic static void 29055995Sbostic add_compunit(type, s) 29155995Sbostic enum e_cut type; 29255995Sbostic char *s; 29355995Sbostic { 29455995Sbostic struct s_compunit *cu; 29555995Sbostic 29655995Sbostic cu = xmalloc(sizeof(struct s_compunit)); 29755995Sbostic cu->type = type; 29855995Sbostic cu->s = s; 29955995Sbostic cu->next = NULL; 30055995Sbostic *cu_nextp = cu; 30155995Sbostic cu_nextp = &cu->next; 30255995Sbostic } 30355995Sbostic 30455995Sbostic /* 30555995Sbostic * Add a file to the linked list 30655995Sbostic */ 30755995Sbostic static void 30855995Sbostic add_file(s) 30955995Sbostic char *s; 31055995Sbostic { 31155995Sbostic struct s_flist *fp; 31255995Sbostic 31355995Sbostic fp = xmalloc(sizeof(struct s_flist)); 31455995Sbostic fp->next = NULL; 31555995Sbostic *fl_nextp = fp; 31655995Sbostic fp->fname = s; 31755995Sbostic fl_nextp = &fp->next; 31855995Sbostic } 319