main.c - enscript - GNU Enscript
 (HTM) git clone git://thinkerwim.org/enscript.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       main.c (9483B)
       ---
            1 /*
            2  * The main for states.
            3  * Copyright (c) 1997-2000 Markku Rossi.
            4  *
            5  * Author: Markku Rossi <mtr@iki.fi>
            6  */
            7 
            8 /*
            9  * This file is part of GNU Enscript.
           10  *
           11  * Enscript is free software: you can redistribute it and/or modify
           12  * it under the terms of the GNU General Public License as published by
           13  * the Free Software Foundation, either version 3 of the License, or
           14  * (at your option) any later version.
           15  *
           16  * Enscript is distributed in the hope that it will be useful,
           17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
           18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
           19  * GNU General Public License for more details.
           20  *
           21  * You should have received a copy of the GNU General Public License
           22  * along with Enscript.  If not, see <http://www.gnu.org/licenses/>.
           23  */
           24 
           25 #include "defs.h"
           26 #include "getopt.h"
           27 
           28 /*
           29  * Types and definitions.
           30  */
           31 
           32 #define STDIN_NAME "(stdin)"
           33 
           34 
           35 /*
           36  * Global variables.
           37  */
           38 
           39 char *program;
           40 
           41 /* Namespaces. */
           42 StringHashPtr ns_prims = NULL;
           43 StringHashPtr ns_vars = NULL;
           44 StringHashPtr ns_subs = NULL;
           45 StringHashPtr ns_states = NULL;
           46 
           47 /*
           48  * Global expressions which are evaluated after config file has been
           49  * parsed.
           50  */
           51 List *global_stmts = NULL;
           52 
           53 /* Statements from the start{} block. */
           54 List *start_stmts = NULL;
           55 
           56 /* Start and name rules. */
           57 List *startrules = NULL;
           58 List *namerules = NULL;
           59 
           60 Node *nvoid = NULL;
           61 
           62 FILE *ifp = NULL;
           63 char *inbuf = NULL;
           64 unsigned int data_in_buffer;
           65 unsigned int bufpos;
           66 int eof_seen;
           67 char *current_fname;
           68 unsigned int current_linenum;
           69 
           70 struct re_registers *current_match = NULL;
           71 char *current_match_buf = NULL;
           72 
           73 /* Options. */
           74 
           75 /*
           76  * -D VAR=VAL, --define=VAR=VAL
           77  *
           78  * Define variable VAR to have value VAL.
           79  */
           80 
           81 VariableDef *vardefs = NULL;
           82 VariableDef *vardefs_tail = NULL;
           83 
           84 /*
           85  * -f NAME, --file=NAME
           86  *
           87  * Read state definitions from file NAME.  The default is "states.st" in
           88  * the current working directory.
           89  */
           90 
           91 char *defs_file = "states.st";
           92 unsigned int linenum = 1;
           93 char *yyin_name;
           94 
           95 /*
           96  * -o FILE, --output=FILE
           97  *
           98  * Save output to file FILE, the default is stdout.
           99  */
          100 
          101 FILE *ofp = NULL;
          102 
          103 /*
          104  * -p PATH, --path=PATH
          105  *
          106  * Set the load path to PATH.
          107  */
          108 
          109 char *path = NULL;
          110 
          111 /*
          112  * -s NAME, --state=NAME
          113  *
          114  * Start from state NAME.  As a default, start date is resolved during
          115  * the program startup by using start, namerules and startrules rules.
          116  */
          117 char *start_state_arg = NULL;
          118 char *start_state;
          119 
          120 /*
          121  * -v, --verbose
          122  *
          123  * Increase the program verbosity.
          124  */
          125 unsigned int verbose = 0;
          126 
          127 /*
          128  * -V, --version
          129  *
          130  * Print the program version number.
          131  */
          132 
          133 /*
          134  * -W LEVEL, --warning=LEVEL
          135  *
          136  * Set the warning level to LEVEL.
          137  */
          138 WarningLevel warning_level = WARN_LIGHT;
          139 
          140 
          141 /*
          142  * Static variables.
          143  */
          144 
          145 static struct option long_options[] =
          146 {
          147   {"define",                required_argument,        0, 'D'},
          148   {"file",                required_argument,        0, 'f'},
          149   {"help",                no_argument,                0, 'h'},
          150   {"output",                required_argument,        0, 'o'},
          151   {"path",                required_argument,        0, 'p'},
          152   {"state",                required_argument,        0, 's'},
          153   {"verbose",                no_argument,                0, 'v'},
          154   {"version",                no_argument,                0, 'V'},
          155   {"warning",                required_argument,        0, 'W'},
          156 
          157   {NULL, 0, 0, 0},
          158 };
          159 
          160 /* Version string. */
          161 char version[256];
          162 
          163 
          164 /*
          165  * Prototypes for static functions.
          166  */
          167 
          168 static void usage ___P ((void));
          169 
          170 
          171 /*
          172  * Global functions.
          173  */
          174 
          175 int
          176 main (argc, argv)
          177      int argc;
          178      char *argv[];
          179 {
          180   int c;
          181   VariableDef *vardef;
          182 
          183   /* Set defaults for options. */
          184   ofp = stdout;
          185 
          186   /* Get program's name. */
          187   program = strrchr (argv[0], '/');
          188   if (program == NULL)
          189     program = argv[0];
          190   else
          191     program++;
          192 
          193   /* Make getopt_long() to use our modified program name. */
          194   argv[0] = program;
          195 
          196   /* Format version string. */
          197   sprintf (version, _("states for %s"), PACKAGE_STRING);
          198 
          199   /* Internationalization. */
          200 #if HAVE_SETLOCALE
          201 #if HAVE_LC_MESSAGES
          202   setlocale (LC_MESSAGES, "");
          203 #endif
          204 #endif
          205 #if ENABLE_NLS
          206   bindtextdomain (PACKAGE, LOCALEDIR);
          207   textdomain (PACKAGE);
          208 #endif
          209 
          210   /* Init namespaces. */
          211   ns_prims = strhash_init ();
          212   ns_vars = strhash_init ();
          213   ns_subs = strhash_init ();
          214   ns_states = strhash_init ();
          215 
          216   global_stmts = list ();
          217   start_stmts = list ();
          218   startrules = list ();
          219   namerules = list ();
          220 
          221   nvoid = node_alloc (nVOID);
          222   inbuf = (char *) xmalloc (INBUFSIZE);
          223 
          224   init_primitives ();
          225 
          226   re_set_syntax (RE_SYNTAX_GNU_AWK | RE_INTERVALS);
          227 
          228   /* Enter some system variables. */
          229   enter_system_variable ("program", program);
          230   enter_system_variable ("version", version);
          231 
          232   /* Parse arguments. */
          233   while (1)
          234     {
          235       int option_index = 0;
          236 
          237       c = getopt_long (argc, argv, "D:f:ho:p:s:vVW:", long_options,
          238                        &option_index);
          239       if (c == -1)
          240         break;
          241 
          242       switch (c)
          243         {
          244         case 'D':                /* define variable */
          245           vardef = (VariableDef *) xcalloc (1, sizeof (*vardef));
          246           vardef->sym = (char *) xmalloc (strlen (optarg) + 1);
          247           strcpy (vardef->sym, optarg);
          248 
          249           vardef->val = strchr (vardef->sym, '=');
          250           if (vardef->val == NULL)
          251             {
          252               fprintf (stderr, _("%s: malformed variable definition \"%s\"\n"),
          253                        program, vardef->sym);
          254               exit (1);
          255             }
          256           *vardef->val = '\0';
          257           vardef->val++;
          258 
          259           if (vardefs)
          260             vardefs_tail->next = vardef;
          261           else
          262             vardefs = vardef;
          263           vardefs_tail = vardef;
          264           break;
          265 
          266         case 'f':                /* definitions file */
          267           defs_file = optarg;
          268           break;
          269 
          270         case 'h':                /* help */
          271           usage ();
          272           exit (0);
          273           break;
          274 
          275         case 'o':                /* output file */
          276           ofp = fopen (optarg, "w");
          277           if (ofp == NULL)
          278             {
          279               fprintf (stderr,
          280                        _("%s: couldn't create output file \"%s\": %s\n"),
          281                        program, optarg, strerror (errno));
          282               exit (1);
          283             }
          284           break;
          285 
          286         case 'p':                /* path */
          287           path = optarg;
          288           break;
          289 
          290         case 's':                /* start state */
          291           start_state_arg = optarg;
          292           break;
          293 
          294         case 'v':                /* verbose */
          295           verbose++;
          296           break;
          297 
          298         case 'V':                /* version */
          299           printf ("%s\n", version);
          300           exit (0);
          301           break;
          302 
          303         case 'W':                /* warning level */
          304           if (strcmp (optarg, "light") == 0)
          305             warning_level = WARN_LIGHT;
          306           else if (strcmp (optarg, "all") == 0)
          307             warning_level = WARN_ALL;
          308           else
          309             {
          310               fprintf (stderr,
          311                        _("%s: unknown warning level `%s'\n"),
          312                        program, optarg);
          313               exit (1);
          314             }
          315           break;
          316 
          317         case '?':                /* Errors found during getopt_long(). */
          318           fprintf (stderr, _("Try `%s --help' for more information.\n"),
          319                    program);
          320           exit (1);
          321           break;
          322 
          323         default:
          324           printf ("Hey! main() didn't handle option \"%c\" (%d)", c, c);
          325           if (optarg)
          326             printf (" with arg %s", optarg);
          327           printf ("\n");
          328           abort ();
          329           break;
          330         }
          331     }
          332 
          333   /* Pass all remaining arguments to States through `argv' array. */
          334   {
          335     Node *v, *n;
          336     int i;
          337 
          338     v = node_alloc (nARRAY);
          339     v->u.array.allocated = argc - optind + 1;
          340     v->u.array.len = argc - optind;
          341     v->u.array.array = (Node **) xcalloc (v->u.array.allocated,
          342                                           sizeof (Node *));
          343     for (i = optind; i < argc; i++)
          344       {
          345         char *data;
          346 
          347         n = node_alloc (nSTRING);
          348         if (strcmp (argv[i], "-") == 0)
          349           data = STDIN_NAME;
          350         else
          351           data = argv[i];
          352 
          353         n->u.str.len = strlen (data);
          354         n->u.str.data = xstrdup (data);
          355         v->u.array.array[i - optind] = n;
          356       }
          357 
          358     if (!strhash_put (ns_vars, "argv", 4, v, (void **) &n))
          359       {
          360         fprintf (stderr, _("%s: out of memory\n"), program);
          361         exit (1);
          362       }
          363     node_free (n);
          364   }
          365 
          366   /* Set some defaults if the user didn't give them. */
          367   if (path == NULL)
          368     {
          369       char *cp;
          370       cp = strrchr (defs_file, '/');
          371       if (cp)
          372         {
          373           path = xmalloc (cp - defs_file + 3);
          374           sprintf (path, ".%c%.*s", PATH_SEPARATOR, (int)(cp - defs_file), defs_file);
          375         }
          376       else
          377         path = ".";
          378     }
          379 
          380   /* Parse config file. */
          381   load_states_file (defs_file);
          382 
          383   /* Define variables given at the command line. */
          384   for (vardef = vardefs; vardef; vardef = vardef->next)
          385     {
          386       Node *val;
          387       Node *old_val;
          388 
          389       val = node_alloc (nSTRING);
          390       val->u.str.len = strlen (vardef->val);
          391       val->u.str.data = xstrdup (vardef->val);
          392 
          393       if (!strhash_put (ns_vars, vardef->sym, strlen (vardef->sym),
          394                         val, (void **) &old_val))
          395         {
          396           fprintf (stderr, _("%s: out of memory\n"), program);
          397           exit (1);
          398         }
          399       node_free (old_val);
          400     }
          401 
          402   /* Process files. */
          403   if (optind == argc)
          404     {
          405       ifp = stdin;
          406       process_file (STDIN_NAME);
          407     }
          408   else
          409     for (; optind < argc; optind++)
          410       {
          411         if (strcmp (argv[optind], "-") == 0)
          412           {
          413             ifp = stdin;
          414             process_file (STDIN_NAME);
          415           }
          416         else
          417           {
          418             ifp = fopen (argv[optind], "r");
          419             if (ifp == NULL)
          420               {
          421                 fprintf (stderr, _("%s: couldn't open input file `%s': %s\n"),
          422                          program, argv[optind], strerror (errno));
          423                 exit (1);
          424               }
          425             process_file (argv[optind]);
          426             fclose (ifp);
          427           }
          428       }
          429 
          430   /* Close output file. */
          431   if (ofp != stdout)
          432     fclose (ofp);
          433 
          434   return 0;
          435 }
          436 
          437 
          438 /*
          439  * Static functions.
          440  */
          441 
          442 static void
          443 usage ()
          444 {
          445   printf (_("\
          446 Usage: %s [OPTION]... [FILE]...\n\
          447 Mandatory arguments to long options are mandatory for short options too.\n"),
          448           program);
          449   printf (_("\
          450   -D, --define=VAR=VAL       define variable VAR to have value VAL\n\
          451   -f, --file=NAME            read state definitions from file NAME\n\
          452   -h, --help                 print this help and exit\n\
          453   -o, --output=NAME          save output to file NAME\n\
          454   -p, --path=PATH            set the load path to PATH\n\
          455   -s, --state=NAME           start from state NAME\n\
          456   -v, --verbose              increase the program verbosity\n\
          457   -V, --version              print version number\n\
          458   -W, --warning=LEVEL        set the warning level to LEVEL\n"));
          459 }