home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / sed / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-02  |  7.9 KB  |  353 lines

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