1*55995Sbostic /*- 2*55995Sbostic * Copyright (c) 1992 Diomidis Spinellis. 3*55995Sbostic * Copyright (c) 1992 The Regents of the University of California. 4*55995Sbostic * All rights reserved. 5*55995Sbostic * 6*55995Sbostic * This code is derived from software contributed to Berkeley by 7*55995Sbostic * Diomidis Spinellis of Imperial College, University of London. 8*55995Sbostic * 9*55995Sbostic * %sccs.include.redist.c% 10*55995Sbostic */ 11*55995Sbostic 12*55995Sbostic #ifndef lint 13*55995Sbostic char copyright[] = 14*55995Sbostic "@(#) Copyright (c) 1992 The Regents of the University of California.\n\ 15*55995Sbostic All rights reserved.\n"; 16*55995Sbostic #endif /* not lint */ 17*55995Sbostic 18*55995Sbostic #ifndef lint 19*55995Sbostic static char sccsid[] = "@(#)main.c 5.1 (Berkeley) 08/23/92"; 20*55995Sbostic #endif /* not lint */ 21*55995Sbostic 22*55995Sbostic #include <sys/types.h> 23*55995Sbostic 24*55995Sbostic #include <ctype.h> 25*55995Sbostic #include <errno.h> 26*55995Sbostic #include <fcntl.h> 27*55995Sbostic #include <regex.h> 28*55995Sbostic #include <stddef.h> 29*55995Sbostic #include <stdio.h> 30*55995Sbostic #include <stdlib.h> 31*55995Sbostic #include <string.h> 32*55995Sbostic #include <unistd.h> 33*55995Sbostic 34*55995Sbostic #include "defs.h" 35*55995Sbostic #include "extern.h" 36*55995Sbostic 37*55995Sbostic /* 38*55995Sbostic * Linked list of units (strings and files) to be compiled 39*55995Sbostic */ 40*55995Sbostic struct s_compunit { 41*55995Sbostic struct s_compunit *next; 42*55995Sbostic enum e_cut {CU_FILE, CU_STRING} type; 43*55995Sbostic char *s; /* Pointer to string or fname */ 44*55995Sbostic }; 45*55995Sbostic 46*55995Sbostic /* 47*55995Sbostic * Linked list pointer to compilation units and pointer to current 48*55995Sbostic * next pointer. 49*55995Sbostic */ 50*55995Sbostic static struct s_compunit *script, **cu_nextp = &script; 51*55995Sbostic 52*55995Sbostic /* 53*55995Sbostic * Linked list of files to be processed 54*55995Sbostic */ 55*55995Sbostic struct s_flist { 56*55995Sbostic char *fname; 57*55995Sbostic struct s_flist *next; 58*55995Sbostic }; 59*55995Sbostic 60*55995Sbostic /* 61*55995Sbostic * Linked list pointer to files and pointer to current 62*55995Sbostic * next pointer. 63*55995Sbostic */ 64*55995Sbostic static struct s_flist *files, **fl_nextp = &files; 65*55995Sbostic 66*55995Sbostic int compile_errors; /* Compile error count. */ 67*55995Sbostic int aflag, eflag, nflag; 68*55995Sbostic 69*55995Sbostic /* 70*55995Sbostic * Current file and line number; line numbers restart across compilation 71*55995Sbostic * units, but span across input files. 72*55995Sbostic */ 73*55995Sbostic char *fname; /* File name. */ 74*55995Sbostic u_long linenum; 75*55995Sbostic int lastline; /* TRUE on the last line of the last file */ 76*55995Sbostic 77*55995Sbostic static void add_compunit __P((enum e_cut, char *)); 78*55995Sbostic static void add_file __P((char *)); 79*55995Sbostic 80*55995Sbostic int 81*55995Sbostic main(argc, argv) 82*55995Sbostic int argc; 83*55995Sbostic char *argv[]; 84*55995Sbostic { 85*55995Sbostic int c, fflag; 86*55995Sbostic 87*55995Sbostic fflag = 0; 88*55995Sbostic while ((c = getopt(argc, argv, "ae:f:n")) != EOF) 89*55995Sbostic switch (c) { 90*55995Sbostic case 'a': 91*55995Sbostic aflag = 1; 92*55995Sbostic break; 93*55995Sbostic case 'e': 94*55995Sbostic eflag = 1; 95*55995Sbostic add_compunit(CU_STRING, optarg); 96*55995Sbostic break; 97*55995Sbostic case 'f': 98*55995Sbostic fflag = 1; 99*55995Sbostic add_compunit(CU_FILE, optarg); 100*55995Sbostic break; 101*55995Sbostic case 'n': 102*55995Sbostic nflag = 1; 103*55995Sbostic break; 104*55995Sbostic default: 105*55995Sbostic case '?': 106*55995Sbostic (void)fprintf(stderr, 107*55995Sbostic "usage:\tsed script [-an] [file ...]\n\tsed [-an] [-e script] ... [-f scipt_file] ... [file ...]\n"); 108*55995Sbostic exit(1); 109*55995Sbostic } 110*55995Sbostic argc -= optind; 111*55995Sbostic argv += optind; 112*55995Sbostic 113*55995Sbostic /* First usage case; script is the first arg */ 114*55995Sbostic if (!eflag && !fflag && *argv) { 115*55995Sbostic add_compunit(CU_STRING, *argv); 116*55995Sbostic argv++; 117*55995Sbostic } 118*55995Sbostic 119*55995Sbostic compile(); 120*55995Sbostic if (compile_errors) 121*55995Sbostic exit(1); 122*55995Sbostic 123*55995Sbostic /* Continue with first and start second usage */ 124*55995Sbostic if (*argv) 125*55995Sbostic for (; *argv; argv++) 126*55995Sbostic add_file(*argv); 127*55995Sbostic else 128*55995Sbostic add_file(NULL); 129*55995Sbostic process(); 130*55995Sbostic cfclose(prog); 131*55995Sbostic if (fclose(stdout)) 132*55995Sbostic err(FATAL, "stdout: %s", strerror(errno)); 133*55995Sbostic exit (0); 134*55995Sbostic } 135*55995Sbostic 136*55995Sbostic /* 137*55995Sbostic * Like fgets, but go through the chain of compilation units chaining them 138*55995Sbostic * together. Empty strings and files are ignored. 139*55995Sbostic */ 140*55995Sbostic char * 141*55995Sbostic cu_fgets(buf, n) 142*55995Sbostic char *buf; 143*55995Sbostic int n; 144*55995Sbostic { 145*55995Sbostic static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF; 146*55995Sbostic static FILE *f; /* Current open file */ 147*55995Sbostic static char *s; /* Current pointer inside string */ 148*55995Sbostic static char string_ident[20]; 149*55995Sbostic char *p; 150*55995Sbostic 151*55995Sbostic again: 152*55995Sbostic switch (state) { 153*55995Sbostic case ST_EOF: 154*55995Sbostic if (script == NULL) 155*55995Sbostic return (NULL); 156*55995Sbostic linenum = 0; 157*55995Sbostic switch (script->type) { 158*55995Sbostic case CU_FILE: 159*55995Sbostic if ((f = fopen(script->s, "r")) == NULL) 160*55995Sbostic err(FATAL, 161*55995Sbostic "%s: %s", script->s, strerror(errno)); 162*55995Sbostic fname = script->s; 163*55995Sbostic state = ST_FILE; 164*55995Sbostic goto again; 165*55995Sbostic case CU_STRING: 166*55995Sbostic /* Have better handling here */ 167*55995Sbostic (void)strncpy(string_ident, 168*55995Sbostic script->s, sizeof(string_ident)); 169*55995Sbostic (void)strcpy(string_ident + sizeof(string_ident) - 5, 170*55995Sbostic "..."); 171*55995Sbostic fname = string_ident; 172*55995Sbostic s = script->s; 173*55995Sbostic state = ST_STRING; 174*55995Sbostic goto again; 175*55995Sbostic } 176*55995Sbostic case ST_FILE: 177*55995Sbostic if ((p = fgets(buf, n, f)) != NULL) { 178*55995Sbostic linenum++; 179*55995Sbostic if (linenum == 1 && buf[0] == '#' && buf[1] == 'n') 180*55995Sbostic nflag = 1; 181*55995Sbostic return (p); 182*55995Sbostic } 183*55995Sbostic script = script->next; 184*55995Sbostic (void)fclose(f); 185*55995Sbostic state = ST_EOF; 186*55995Sbostic goto again; 187*55995Sbostic case ST_STRING: 188*55995Sbostic if (linenum == 0 && s[0] == '#' && s[1] == 'n') 189*55995Sbostic nflag = 1; 190*55995Sbostic p = buf; 191*55995Sbostic for (;;) { 192*55995Sbostic if (n-- <= 1) { 193*55995Sbostic *p = '\0'; 194*55995Sbostic linenum++; 195*55995Sbostic return (buf); 196*55995Sbostic } 197*55995Sbostic switch (*s) { 198*55995Sbostic case '\0': 199*55995Sbostic state = ST_EOF; 200*55995Sbostic if (s == script->s) { 201*55995Sbostic script = script->next; 202*55995Sbostic goto again; 203*55995Sbostic } else { 204*55995Sbostic script = script->next; 205*55995Sbostic *p = '\0'; 206*55995Sbostic linenum++; 207*55995Sbostic return (buf); 208*55995Sbostic } 209*55995Sbostic case '\n': 210*55995Sbostic *p++ = '\n'; 211*55995Sbostic *p = '\0'; 212*55995Sbostic s++; 213*55995Sbostic linenum++; 214*55995Sbostic return (buf); 215*55995Sbostic default: 216*55995Sbostic *p++ = *s++; 217*55995Sbostic } 218*55995Sbostic } 219*55995Sbostic } 220*55995Sbostic /* NOTREACHED */ 221*55995Sbostic } 222*55995Sbostic 223*55995Sbostic /* 224*55995Sbostic * Like fgets, but go through the list of files chaining them together. 225*55995Sbostic * Set len to the length of the line. 226*55995Sbostic */ 227*55995Sbostic char * 228*55995Sbostic mf_fgets(lenp) 229*55995Sbostic size_t *lenp; 230*55995Sbostic { 231*55995Sbostic static FILE *f; /* Current open file */ 232*55995Sbostic char c, *p; 233*55995Sbostic 234*55995Sbostic if (f == NULL) 235*55995Sbostic /* Advance to first non-empty file */ 236*55995Sbostic for (;;) { 237*55995Sbostic if (files == NULL) { 238*55995Sbostic lastline = 1; 239*55995Sbostic return (NULL); 240*55995Sbostic } 241*55995Sbostic if (files->fname == NULL) { 242*55995Sbostic f = stdin; 243*55995Sbostic fname = "stdin"; 244*55995Sbostic } else { 245*55995Sbostic fname = files->fname; 246*55995Sbostic if ((f = fopen(fname, "r")) == NULL) 247*55995Sbostic err(FATAL, "%s: %s", 248*55995Sbostic fname, strerror(errno)); 249*55995Sbostic } 250*55995Sbostic if ((c = getc(f)) != EOF) { 251*55995Sbostic (void)ungetc(c, f); 252*55995Sbostic break; 253*55995Sbostic } 254*55995Sbostic (void)fclose(f); 255*55995Sbostic files = files->next; 256*55995Sbostic } 257*55995Sbostic 258*55995Sbostic if (lastline) { 259*55995Sbostic *lenp = 0; 260*55995Sbostic return (NULL); 261*55995Sbostic } 262*55995Sbostic 263*55995Sbostic p = fgetline(f, lenp); 264*55995Sbostic if (ferror(f)) 265*55995Sbostic err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO)); 266*55995Sbostic 267*55995Sbostic linenum++; 268*55995Sbostic /* Advance to next non-empty file */ 269*55995Sbostic while ((c = getc(f)) == EOF) { 270*55995Sbostic (void)fclose(f); 271*55995Sbostic files = files->next; 272*55995Sbostic if (files == NULL) { 273*55995Sbostic lastline = 1; 274*55995Sbostic return (p); 275*55995Sbostic } 276*55995Sbostic if (files->fname == NULL) { 277*55995Sbostic f = stdin; 278*55995Sbostic fname = "stdin"; 279*55995Sbostic } else { 280*55995Sbostic fname = files->fname; 281*55995Sbostic if ((f = fopen(fname, "r")) == NULL) 282*55995Sbostic err(FATAL, "%s: %s", fname, strerror(errno)); 283*55995Sbostic } 284*55995Sbostic } 285*55995Sbostic (void)ungetc(c, f); 286*55995Sbostic return (p); 287*55995Sbostic } 288*55995Sbostic 289*55995Sbostic /* 290*55995Sbostic * Add a compilation unit to the linked list 291*55995Sbostic */ 292*55995Sbostic static void 293*55995Sbostic add_compunit(type, s) 294*55995Sbostic enum e_cut type; 295*55995Sbostic char *s; 296*55995Sbostic { 297*55995Sbostic struct s_compunit *cu; 298*55995Sbostic 299*55995Sbostic cu = xmalloc(sizeof(struct s_compunit)); 300*55995Sbostic cu->type = type; 301*55995Sbostic cu->s = s; 302*55995Sbostic cu->next = NULL; 303*55995Sbostic *cu_nextp = cu; 304*55995Sbostic cu_nextp = &cu->next; 305*55995Sbostic } 306*55995Sbostic 307*55995Sbostic /* 308*55995Sbostic * Add a file to the linked list 309*55995Sbostic */ 310*55995Sbostic static void 311*55995Sbostic add_file(s) 312*55995Sbostic char *s; 313*55995Sbostic { 314*55995Sbostic struct s_flist *fp; 315*55995Sbostic 316*55995Sbostic fp = xmalloc(sizeof(struct s_flist)); 317*55995Sbostic fp->next = NULL; 318*55995Sbostic *fl_nextp = fp; 319*55995Sbostic fp->fname = s; 320*55995Sbostic fl_nextp = &fp->next; 321*55995Sbostic } 322