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