Annotation of src/usr.bin/sed/main.c, Revision 1.1
1.1 ! deraadt 1: /*-
! 2: * Copyright (c) 1992 Diomidis Spinellis.
! 3: * Copyright (c) 1992, 1993
! 4: * The Regents of the University of California. 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: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. All advertising materials mentioning features or use of this software
! 18: * must display the following acknowledgement:
! 19: * This product includes software developed by the University of
! 20: * California, Berkeley and its contributors.
! 21: * 4. Neither the name of the University nor the names of its contributors
! 22: * may be used to endorse or promote products derived from this software
! 23: * without specific prior written permission.
! 24: *
! 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 35: * SUCH DAMAGE.
! 36: */
! 37:
! 38: #ifndef lint
! 39: static char copyright[] =
! 40: "@(#) Copyright (c) 1992, 1993\n\
! 41: The Regents of the University of California. All rights reserved.\n";
! 42: #endif /* not lint */
! 43:
! 44: #ifndef lint
! 45: /* from: static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94"; */
! 46: static char *rcsid = "$Id: main.c,v 1.7 1995/02/23 17:25:23 jtc Exp $";
! 47: #endif /* not lint */
! 48:
! 49: #include <sys/types.h>
! 50:
! 51: #include <ctype.h>
! 52: #include <errno.h>
! 53: #include <fcntl.h>
! 54: #include <regex.h>
! 55: #include <stddef.h>
! 56: #include <stdio.h>
! 57: #include <stdlib.h>
! 58: #include <string.h>
! 59: #include <unistd.h>
! 60:
! 61: #include "defs.h"
! 62: #include "extern.h"
! 63:
! 64: /*
! 65: * Linked list of units (strings and files) to be compiled
! 66: */
! 67: struct s_compunit {
! 68: struct s_compunit *next;
! 69: enum e_cut {CU_FILE, CU_STRING} type;
! 70: char *s; /* Pointer to string or fname */
! 71: };
! 72:
! 73: /*
! 74: * Linked list pointer to compilation units and pointer to current
! 75: * next pointer.
! 76: */
! 77: static struct s_compunit *script, **cu_nextp = &script;
! 78:
! 79: /*
! 80: * Linked list of files to be processed
! 81: */
! 82: struct s_flist {
! 83: char *fname;
! 84: struct s_flist *next;
! 85: };
! 86:
! 87: /*
! 88: * Linked list pointer to files and pointer to current
! 89: * next pointer.
! 90: */
! 91: static struct s_flist *files, **fl_nextp = &files;
! 92:
! 93: int aflag, eflag, nflag;
! 94:
! 95: /*
! 96: * Current file and line number; line numbers restart across compilation
! 97: * units, but span across input files.
! 98: */
! 99: char *fname; /* File name. */
! 100: u_long linenum;
! 101: int lastline; /* TRUE on the last line of the last file */
! 102:
! 103: static void add_compunit __P((enum e_cut, char *));
! 104: static void add_file __P((char *));
! 105:
! 106: int
! 107: main(argc, argv)
! 108: int argc;
! 109: char *argv[];
! 110: {
! 111: int c, fflag;
! 112:
! 113: fflag = 0;
! 114: while ((c = getopt(argc, argv, "ae:f:n")) != EOF)
! 115: switch (c) {
! 116: case 'a':
! 117: aflag = 1;
! 118: break;
! 119: case 'e':
! 120: eflag = 1;
! 121: add_compunit(CU_STRING, optarg);
! 122: break;
! 123: case 'f':
! 124: fflag = 1;
! 125: add_compunit(CU_FILE, optarg);
! 126: break;
! 127: case 'n':
! 128: nflag = 1;
! 129: break;
! 130: default:
! 131: case '?':
! 132: (void)fprintf(stderr,
! 133: "usage:\tsed script [-an] [file ...]\n\tsed [-an] [-e script] ... [-f script_file] ... [file ...]\n");
! 134: exit(1);
! 135: }
! 136: argc -= optind;
! 137: argv += optind;
! 138:
! 139: /* First usage case; script is the first arg */
! 140: if (!eflag && !fflag && *argv) {
! 141: add_compunit(CU_STRING, *argv);
! 142: argv++;
! 143: }
! 144:
! 145: compile();
! 146:
! 147: /* Continue with first and start second usage */
! 148: if (*argv)
! 149: for (; *argv; argv++)
! 150: add_file(*argv);
! 151: else
! 152: add_file(NULL);
! 153: process();
! 154: cfclose(prog, NULL);
! 155: if (fclose(stdout))
! 156: err(FATAL, "stdout: %s", strerror(errno));
! 157: exit (0);
! 158: }
! 159:
! 160: /*
! 161: * Like fgets, but go through the chain of compilation units chaining them
! 162: * together. Empty strings and files are ignored.
! 163: */
! 164: char *
! 165: cu_fgets(buf, n)
! 166: char *buf;
! 167: int n;
! 168: {
! 169: static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
! 170: static FILE *f; /* Current open file */
! 171: static char *s; /* Current pointer inside string */
! 172: static char string_ident[30];
! 173: char *p;
! 174:
! 175: again:
! 176: switch (state) {
! 177: case ST_EOF:
! 178: if (script == NULL)
! 179: return (NULL);
! 180: linenum = 0;
! 181: switch (script->type) {
! 182: case CU_FILE:
! 183: if ((f = fopen(script->s, "r")) == NULL)
! 184: err(FATAL,
! 185: "%s: %s", script->s, strerror(errno));
! 186: fname = script->s;
! 187: state = ST_FILE;
! 188: goto again;
! 189: case CU_STRING:
! 190: if ((snprintf(string_ident,
! 191: sizeof(string_ident), "\"%s\"", script->s)) >=
! 192: sizeof(string_ident) - 1)
! 193: (void)strcpy(string_ident +
! 194: sizeof(string_ident) - 6, " ...\"");
! 195: fname = string_ident;
! 196: s = script->s;
! 197: state = ST_STRING;
! 198: goto again;
! 199: }
! 200: case ST_FILE:
! 201: if ((p = fgets(buf, n, f)) != NULL) {
! 202: linenum++;
! 203: if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
! 204: nflag = 1;
! 205: return (p);
! 206: }
! 207: script = script->next;
! 208: (void)fclose(f);
! 209: state = ST_EOF;
! 210: goto again;
! 211: case ST_STRING:
! 212: if (linenum == 0 && s[0] == '#' && s[1] == 'n')
! 213: nflag = 1;
! 214: p = buf;
! 215: for (;;) {
! 216: if (n-- <= 1) {
! 217: *p = '\0';
! 218: linenum++;
! 219: return (buf);
! 220: }
! 221: switch (*s) {
! 222: case '\0':
! 223: state = ST_EOF;
! 224: if (s == script->s) {
! 225: script = script->next;
! 226: goto again;
! 227: } else {
! 228: script = script->next;
! 229: *p = '\0';
! 230: linenum++;
! 231: return (buf);
! 232: }
! 233: case '\n':
! 234: *p++ = '\n';
! 235: *p = '\0';
! 236: s++;
! 237: linenum++;
! 238: return (buf);
! 239: default:
! 240: *p++ = *s++;
! 241: }
! 242: }
! 243: }
! 244: /* NOTREACHED */
! 245: }
! 246:
! 247: /*
! 248: * Like fgets, but go through the list of files chaining them together.
! 249: * Set len to the length of the line.
! 250: */
! 251: int
! 252: mf_fgets(sp, spflag)
! 253: SPACE *sp;
! 254: enum e_spflag spflag;
! 255: {
! 256: static FILE *f; /* Current open file */
! 257: size_t len;
! 258: char c, *p;
! 259:
! 260: if (f == NULL)
! 261: /* Advance to first non-empty file */
! 262: for (;;) {
! 263: if (files == NULL) {
! 264: lastline = 1;
! 265: return (0);
! 266: }
! 267: if (files->fname == NULL) {
! 268: f = stdin;
! 269: fname = "stdin";
! 270: } else {
! 271: fname = files->fname;
! 272: if ((f = fopen(fname, "r")) == NULL)
! 273: err(FATAL, "%s: %s",
! 274: fname, strerror(errno));
! 275: }
! 276: if ((c = getc(f)) != EOF) {
! 277: (void)ungetc(c, f);
! 278: break;
! 279: }
! 280: (void)fclose(f);
! 281: files = files->next;
! 282: }
! 283:
! 284: if (lastline) {
! 285: sp->len = 0;
! 286: return (0);
! 287: }
! 288:
! 289: /*
! 290: * Use fgetln so that we can handle essentially infinite input data.
! 291: * Can't use the pointer into the stdio buffer as the process space
! 292: * because the ungetc() can cause it to move.
! 293: */
! 294: p = fgetln(f, &len);
! 295: if (ferror(f))
! 296: err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO));
! 297: cspace(sp, p, len, spflag);
! 298:
! 299: linenum++;
! 300: /* Advance to next non-empty file */
! 301: while ((c = getc(f)) == EOF) {
! 302: (void)fclose(f);
! 303: files = files->next;
! 304: if (files == NULL) {
! 305: lastline = 1;
! 306: return (1);
! 307: }
! 308: if (files->fname == NULL) {
! 309: f = stdin;
! 310: fname = "stdin";
! 311: } else {
! 312: fname = files->fname;
! 313: if ((f = fopen(fname, "r")) == NULL)
! 314: err(FATAL, "%s: %s", fname, strerror(errno));
! 315: }
! 316: }
! 317: (void)ungetc(c, f);
! 318: return (1);
! 319: }
! 320:
! 321: /*
! 322: * Add a compilation unit to the linked list
! 323: */
! 324: static void
! 325: add_compunit(type, s)
! 326: enum e_cut type;
! 327: char *s;
! 328: {
! 329: struct s_compunit *cu;
! 330:
! 331: cu = xmalloc(sizeof(struct s_compunit));
! 332: cu->type = type;
! 333: cu->s = s;
! 334: cu->next = NULL;
! 335: *cu_nextp = cu;
! 336: cu_nextp = &cu->next;
! 337: }
! 338:
! 339: /*
! 340: * Add a file to the linked list
! 341: */
! 342: static void
! 343: add_file(s)
! 344: char *s;
! 345: {
! 346: struct s_flist *fp;
! 347:
! 348: fp = xmalloc(sizeof(struct s_flist));
! 349: fp->next = NULL;
! 350: *fl_nextp = fp;
! 351: fp->fname = s;
! 352: fl_nextp = &fp->next;
! 353: }