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.3 (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 aflag, eflag, nflag; 67 68 /* 69 * Current file and line number; line numbers restart across compilation 70 * units, but span across input files. 71 */ 72 char *fname; /* File name. */ 73 u_long linenum; 74 int lastline; /* TRUE on the last line of the last file */ 75 76 static void add_compunit __P((enum e_cut, char *)); 77 static void add_file __P((char *)); 78 79 int 80 main(argc, argv) 81 int argc; 82 char *argv[]; 83 { 84 int c, fflag; 85 86 fflag = 0; 87 while ((c = getopt(argc, argv, "ae:f:n")) != EOF) 88 switch (c) { 89 case 'a': 90 aflag = 1; 91 break; 92 case 'e': 93 eflag = 1; 94 add_compunit(CU_STRING, optarg); 95 break; 96 case 'f': 97 fflag = 1; 98 add_compunit(CU_FILE, optarg); 99 break; 100 case 'n': 101 nflag = 1; 102 break; 103 default: 104 case '?': 105 (void)fprintf(stderr, 106 "usage:\tsed script [-an] [file ...]\n\tsed [-an] [-e script] ... [-f scipt_file] ... [file ...]\n"); 107 exit(1); 108 } 109 argc -= optind; 110 argv += optind; 111 112 /* First usage case; script is the first arg */ 113 if (!eflag && !fflag && *argv) { 114 add_compunit(CU_STRING, *argv); 115 argv++; 116 } 117 118 compile(); 119 120 /* Continue with first and start second usage */ 121 if (*argv) 122 for (; *argv; argv++) 123 add_file(*argv); 124 else 125 add_file(NULL); 126 process(); 127 cfclose(prog); 128 if (fclose(stdout)) 129 err(FATAL, "stdout: %s", strerror(errno)); 130 exit (0); 131 } 132 133 /* 134 * Like fgets, but go through the chain of compilation units chaining them 135 * together. Empty strings and files are ignored. 136 */ 137 char * 138 cu_fgets(buf, n) 139 char *buf; 140 int n; 141 { 142 static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF; 143 static FILE *f; /* Current open file */ 144 static char *s; /* Current pointer inside string */ 145 static char string_ident[60]; 146 char *p; 147 148 again: 149 switch (state) { 150 case ST_EOF: 151 if (script == NULL) 152 return (NULL); 153 linenum = 0; 154 switch (script->type) { 155 case CU_FILE: 156 if ((f = fopen(script->s, "r")) == NULL) 157 err(FATAL, 158 "%s: %s", script->s, strerror(errno)); 159 fname = script->s; 160 state = ST_FILE; 161 goto again; 162 case CU_STRING: 163 (void)sprintf(string_ident, "\"%.50s%s\"", script->s, 164 strlen(script->s) > 50 ? "..." : ""); 165 fname = string_ident; 166 s = script->s; 167 state = ST_STRING; 168 goto again; 169 } 170 case ST_FILE: 171 if ((p = fgets(buf, n, f)) != NULL) { 172 linenum++; 173 if (linenum == 1 && buf[0] == '#' && buf[1] == 'n') 174 nflag = 1; 175 return (p); 176 } 177 script = script->next; 178 (void)fclose(f); 179 state = ST_EOF; 180 goto again; 181 case ST_STRING: 182 if (linenum == 0 && s[0] == '#' && s[1] == 'n') 183 nflag = 1; 184 p = buf; 185 for (;;) { 186 if (n-- <= 1) { 187 *p = '\0'; 188 linenum++; 189 return (buf); 190 } 191 switch (*s) { 192 case '\0': 193 state = ST_EOF; 194 if (s == script->s) { 195 script = script->next; 196 goto again; 197 } else { 198 script = script->next; 199 *p = '\0'; 200 linenum++; 201 return (buf); 202 } 203 case '\n': 204 *p++ = '\n'; 205 *p = '\0'; 206 s++; 207 linenum++; 208 return (buf); 209 default: 210 *p++ = *s++; 211 } 212 } 213 } 214 /* NOTREACHED */ 215 } 216 217 /* 218 * Like fgets, but go through the list of files chaining them together. 219 * Set len to the length of the line. 220 */ 221 char * 222 mf_fgets(lenp) 223 size_t *lenp; 224 { 225 static FILE *f; /* Current open file */ 226 char c, *p; 227 228 if (f == NULL) 229 /* Advance to first non-empty file */ 230 for (;;) { 231 if (files == NULL) { 232 lastline = 1; 233 return (NULL); 234 } 235 if (files->fname == NULL) { 236 f = stdin; 237 fname = "stdin"; 238 } else { 239 fname = files->fname; 240 if ((f = fopen(fname, "r")) == NULL) 241 err(FATAL, "%s: %s", 242 fname, strerror(errno)); 243 } 244 if ((c = getc(f)) != EOF) { 245 (void)ungetc(c, f); 246 break; 247 } 248 (void)fclose(f); 249 files = files->next; 250 } 251 252 if (lastline) { 253 *lenp = 0; 254 return (NULL); 255 } 256 257 p = fgetline(f, lenp); 258 if (ferror(f)) 259 err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO)); 260 261 linenum++; 262 /* Advance to next non-empty file */ 263 while ((c = getc(f)) == EOF) { 264 (void)fclose(f); 265 files = files->next; 266 if (files == NULL) { 267 lastline = 1; 268 return (p); 269 } 270 if (files->fname == NULL) { 271 f = stdin; 272 fname = "stdin"; 273 } else { 274 fname = files->fname; 275 if ((f = fopen(fname, "r")) == NULL) 276 err(FATAL, "%s: %s", fname, strerror(errno)); 277 } 278 } 279 (void)ungetc(c, f); 280 return (p); 281 } 282 283 /* 284 * Add a compilation unit to the linked list 285 */ 286 static void 287 add_compunit(type, s) 288 enum e_cut type; 289 char *s; 290 { 291 struct s_compunit *cu; 292 293 cu = xmalloc(sizeof(struct s_compunit)); 294 cu->type = type; 295 cu->s = s; 296 cu->next = NULL; 297 *cu_nextp = cu; 298 cu_nextp = &cu->next; 299 } 300 301 /* 302 * Add a file to the linked list 303 */ 304 static void 305 add_file(s) 306 char *s; 307 { 308 struct s_flist *fp; 309 310 fp = xmalloc(sizeof(struct s_flist)); 311 fp->next = NULL; 312 *fl_nextp = fp; 313 fp->fname = s; 314 fl_nextp = &fp->next; 315 } 316