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