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 }