1/* Handles parsing the Options provided to the user.
2 Copyright (C) 1989-1998 Free Software Foundation, Inc.
3 written by Douglas C. Schmidt (schmidt@ics.uci.edu)
4
5This file is part of GNU GPERF.
6
7GNU GPERF is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 1, or (at your option)
10any later version.
11
12GNU GPERF is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU GPERF; see the file COPYING. If not, write to the Free
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
20
21#include <stdio.h>
22#include <stdlib.h> /* declares atoi(), abs(), exit() */
23#include <string.h> /* declares strcmp() */
24#include "getopt.h"
25#include "options.h"
26#include "iterator.h"
27#include "trace.h"
28#include "vectors.h"
29#include "version.h"
30
31/* Global option coordinator for the entire program. */
32Options option;
33
34/* Records the program name. */
35const char *program_name;
36
37/* Size to jump on a collision. */
38static const int DEFAULT_JUMP_VALUE = 5;
39
40/* Default name for generated lookup function. */
41static const char *const DEFAULT_NAME = "in_word_set";
42
43/* Default name for the key component. */
44static const char *const DEFAULT_KEY = "name";
45
46/* Default name for the generated class. */
47static const char *const DEFAULT_CLASS_NAME = "Perfect_Hash";
48
49/* Default name for generated hash function. */
50static const char *const DEFAULT_HASH_NAME = "hash";
51
52/* Default name for generated hash table array. */
53static const char *const DEFAULT_WORDLIST_NAME = "wordlist";
54
55/* Default delimiters that separate keywords from their attributes. */
56static const char *const DEFAULT_DELIMITERS = ",\n";
57
58int Options::option_word;
59int Options::total_switches;
60int Options::total_keysig_size;
61int Options::size;
62int Options::key_pos;
63int Options::jump;
64int Options::initial_asso_value;
65int Options::argument_count;
66int Options::iterations;
67char **Options::argument_vector;
68const char *Options::function_name;
69const char *Options::key_name;
70const char *Options::class_name;
71const char *Options::hash_name;
72const char *Options::wordlist_name;
73const char *Options::delimiters;
74char Options::key_positions[MAX_KEY_POS];
75
76/* Prints program usage to given stream. */
77
78void
79Options::short_usage (FILE * strm)
80{
81 T (Trace t ("Options::short_usage");)
82 fprintf (strm, "Usage: %s [-cCdDef[num]GhHiIjkKlLnNorsStTvWZ7] [input-file]\n"
83 "Try `%s --help' for more information.\n",
84 program_name, program_name);
85}
86
87void
88Options::long_usage (FILE * strm)
89{
90 T (Trace t ("Options::long_usage");)
91 fprintf (strm,
92 "GNU `gperf' generates perfect hash functions.\n"
93 "\n"
94 "Usage: %s [OPTION]... [INPUT-FILE]\n"
95 "\n"
96 "If a long option shows an argument as mandatory, then it is mandatory\n"
97 "for the equivalent short option also.\n"
98 "\n"
99 "Input file interpretation:\n"
100 " -e, --delimiters=DELIMITER-LIST\n"
101 " Allow user to provide a string containing delimiters\n"
102 " used to separate keywords from their attributes.\n"
103 " Default is \",\\n\".\n"
104 " -t, --struct-type Allows the user to include a structured type\n"
105 " declaration for generated code. Any text before %%%%\n"
106 " is considered part of the type declaration. Key\n"
107 " words and additional fields may follow this, one\n"
108 " group of fields per line.\n"
109 "\n"
110 "Language for the output code:\n"
111 " -L, --language=LANGUAGE-NAME\n"
112 " Generates code in the specified language. Languages\n"
113 " handled are currently C++, ANSI-C, C, and KR-C. The\n"
114 " default is C.\n"
115 "\n"
116 "Details in the output code:\n"
117 " -K, --slot-name=NAME Select name of the keyword component in the keyword\n"
118 " structure.\n"
119 " -H, --hash-fn-name=NAME\n"
120 " Specify name of generated hash function. Default is\n"
121 " `hash'.\n"
122 " -N, --lookup-fn-name=NAME\n"
123 " Specify name of generated lookup function. Default\n"
124 " name is `in_word_set'.\n"
125 " -Z, --class-name=NAME Specify name of generated C++ class. Default name is\n"
126 " `Perfect_Hash'.\n"
127 " -7, --seven-bit Assume 7-bit characters.\n"
128 " -c, --compare-strncmp Generate comparison code using strncmp rather than\n"
129 " strcmp.\n"
130 " -C, --readonly-tables Make the contents of generated lookup tables\n"
131 " constant, i.e., readonly.\n"
132 " -E, --enum Define constant values using an enum local to the\n"
133 " lookup function rather than with defines.\n"
134 " -I, --includes Include the necessary system include file <string.h>\n"
135 " at the beginning of the code.\n"
136 " -G, --global Generate the static table of keywords as a static\n"
137 " global variable, rather than hiding it inside of the\n"
138 " lookup function (which is the default behavior).\n"
139 " -W, --word-array-name=NAME\n"
140 " Specify name of word list array. Default name is\n"
141 " `wordlist'.\n"
142 " -S, --switch=COUNT Causes the generated C code to use a switch\n"
143 " statement scheme, rather than an array lookup table.\n"
144 " This can lead to a reduction in both time and space\n"
145 " requirements for some keyfiles. The COUNT argument\n"
146 " determines how many switch statements are generated.\n"
147 " A value of 1 generates 1 switch containing all the\n"
148 " elements, a value of 2 generates 2 tables with 1/2\n"
149 " the elements in each table, etc. If COUNT is very\n"
150 " large, say 1000000, the generated C code does a\n"
151 " binary search.\n"
152 " -T, --omit-struct-type\n"
153 " Prevents the transfer of the type declaration to the\n"
154 " output file. Use this option if the type is already\n"
155 " defined elsewhere.\n"
156 "\n"
157 "Algorithm employed by gperf:\n"
158 " -k, --key-positions=KEYS\n"
159 " Select the key positions used in the hash function.\n"
160 " The allowable choices range between 1-%d, inclusive.\n"
161 " The positions are separated by commas, ranges may be\n"
162 " used, and key positions may occur in any order.\n"
163 " Also, the meta-character '*' causes the generated\n"
164 " hash function to consider ALL key positions, and $\n"
165 " indicates the ``final character'' of a key, e.g.,\n"
166 " $,1,2,4,6-10.\n"
167 " -l, --compare-strlen Compare key lengths before trying a string\n"
168 " comparison. This helps cut down on the number of\n"
169 " string comparisons made during the lookup.\n"
170 " -D, --duplicates Handle keywords that hash to duplicate values. This\n"
171 " is useful for certain highly redundant keyword sets.\n"
172 " -f, --fast=ITERATIONS Generate the gen-perf.hash function ``fast''. This\n"
173 " decreases gperf's running time at the cost of\n"
174 " minimizing generated table size. The numeric\n"
175 " argument represents the number of times to iterate\n"
176 " when resolving a collision. `0' means ``iterate by\n"
177 " the number of keywords''.\n"
178 " -i, --initial-asso=N Provide an initial value for the associate values\n"
179 " array. Default is 0. Setting this value larger helps\n"
180 " inflate the size of the final table.\n"
181 " -j, --jump=JUMP-VALUE Affects the ``jump value'', i.e., how far to advance\n"
182 " the associated character value upon collisions. Must\n"
183 " be an odd number, default is %d.\n"
184 " -n, --no-strlen Do not include the length of the keyword when\n"
185 " computing the hash function.\n"
186 " -o, --occurrence-sort Reorders input keys by frequency of occurrence of\n"
187 " the key sets. This should decrease the search time\n"
188 " dramatically.\n"
189 " -r, --random Utilizes randomness to initialize the associated\n"
190 " values table.\n"
191 " -s, --size-multiple=N Affects the size of the generated hash table. The\n"
192 " numeric argument N indicates ``how many times larger\n"
193 " or smaller'' the associated value range should be,\n"
194 " in relationship to the number of keys, e.g. a value\n"
195 " of 3 means ``allow the maximum associated value to\n"
196 " be about 3 times larger than the number of input\n"
197 " keys.'' Conversely, a value of -3 means ``make the\n"
198 " maximum associated value about 3 times smaller than\n"
199 " the number of input keys. A larger table should\n"
200 " decrease the time required for an unsuccessful\n"
201 " search, at the expense of extra table space. Default\n"
202 " value is 1.\n"
203 "\n"
204 "Informative output:\n"
205 " -h, --help Print this message.\n"
206 " -v, --version Print the gperf version number.\n"
207 " -d, --debug Enables the debugging option (produces verbose\n"
208 " output to the standard error).\n"
209 "\n"
210 "Report bugs to <bug-gnu-utils@gnu.org>.\n"
211 , program_name, MAX_KEY_POS - 1, DEFAULT_JUMP_VALUE);
212}
213
214/* Output command-line Options. */
215
216void
217Options::print_options (void)
218{
219 T (Trace t ("Options::print_options");)
220 int i;
221
222 printf ("/* Command-line: ");
223
224 for (i = 0; i < argument_count; i++)
225 printf ("%s ", argument_vector[i]);
226
227 printf (" */");
228}
229
230/* Sorts the key positions *IN REVERSE ORDER!!*
231 This makes further routines more efficient. Especially when generating code.
232 Uses a simple Insertion Sort since the set is probably ordered.
233 Returns 1 if there are no duplicates, 0 otherwise. */
234
235inline int
236Options::key_sort (char *base, int len)
237{
238 T (Trace t ("Options::key_sort");)
239 int i, j;
240
241 for (i = 0, j = len - 1; i < j; i++)
242 {
243 int curr, tmp;
244
245 for (curr = i + 1,tmp = base[curr]; curr > 0 && tmp >= base[curr - 1]; curr--)
246 if ((base[curr] = base[curr - 1]) == tmp) /* oh no, a duplicate!!! */
247 return 0;
248
249 base[curr] = tmp;
250 }
251
252 return 1;
253}
254
255/* Sets the default Options. */
256
257Options::Options (void)
258{
259 T (Trace t ("Options::Options");)
260 key_positions[0] = WORD_START;
261 key_positions[1] = WORD_END;
262 key_positions[2] = EOS;
263 total_keysig_size = 2;
264 delimiters = DEFAULT_DELIMITERS;
265 jump = DEFAULT_JUMP_VALUE;
266 option_word = DEFAULTCHARS | C;
267 function_name = DEFAULT_NAME;
268 key_name = DEFAULT_KEY;
269 hash_name = DEFAULT_HASH_NAME;
270 wordlist_name = DEFAULT_WORDLIST_NAME;
271 class_name = DEFAULT_CLASS_NAME;
272 total_switches = size = 1;
273 initial_asso_value = iterations = 0;
274}
275
276/* Dumps option status when debug is set. */
277
278Options::~Options (void)
279{
280 T (Trace t ("Options::~Options");)
281 if (option_word & DEBUG)
282 {
283 char *ptr;
284
285 fprintf (stderr, "\ndumping Options:"
286 "\nDEBUG is.......: %s"
287 "\nORDER is.......: %s"
288 "\nTYPE is........: %s"
289 "\nRANDOM is......: %s"
290 "\nDEFAULTCHARS is: %s"
291 "\nSWITCH is......: %s"
292 "\nNOLENGTH is....: %s"
293 "\nLENTABLE is....: %s"
294 "\nDUP is.........: %s"
295 "\nFAST is........: %s"
296 "\nCOMP is........: %s"
297 "\nNOTYPE is......: %s"
298 "\nGLOBAL is......: %s"
299 "\nCONST is.......: %s"
300 "\nKRC is.........: %s"
301 "\nC is...........: %s"
302 "\nANSIC is.......: %s"
303 "\nCPLUSPLUS is...: %s"
304 "\nENUM is........: %s"
305 "\nINCLUDE is.....: %s"
306 "\nSEVENBIT is....: %s"
307 "\niterations = %d"
308 "\nlookup function name = %s"
309 "\nhash function name = %s"
310 "\nword list name = %s"
311 "\nkey name = %s"
312 "\njump value = %d"
313 "\nmax associated value = %d"
314 "\ninitial associated value = %d"
315 "\ndelimiters = %s"
316 "\nnumber of switch statements = %d\n",
317 option_word & DEBUG ? "enabled" : "disabled",
318 option_word & ORDER ? "enabled" : "disabled",
319 option_word & TYPE ? "enabled" : "disabled",
320 option_word & RANDOM ? "enabled" : "disabled",
321 option_word & DEFAULTCHARS ? "enabled" : "disabled",
322 option_word & SWITCH ? "enabled" : "disabled",
323 option_word & NOLENGTH ? "enabled" : "disabled",
324 option_word & LENTABLE ? "enabled" : "disabled",
325 option_word & DUP ? "enabled" : "disabled",
326 option_word & FAST ? "enabled" : "disabled",
327 option_word & COMP ? "enabled" : "disabled",
328 option_word & NOTYPE ? "enabled" : "disabled",
329 option_word & GLOBAL ? "enabled" : "disabled",
330 option_word & CONST ? "enabled" : "disabled",
331 option_word & KRC ? "enabled" : "disabled",
332 option_word & C ? "enabled" : "disabled",
333 option_word & ANSIC ? "enabled" : "disabled",
334 option_word & CPLUSPLUS ? "enabled" : "disabled",
335 option_word & ENUM ? "enabled" : "disabled",
336 option_word & INCLUDE ? "enabled" : "disabled",
337 option_word & SEVENBIT ? "enabled" : "disabled",
338 iterations,
339 function_name, hash_name, wordlist_name, key_name,
340 jump, size - 1, initial_asso_value, delimiters, total_switches);
341 if (option_word & ALLCHARS)
342 fprintf (stderr, "all characters are used in the hash function\n");
343
344 fprintf (stderr, "maximum keysig size = %d\nkey positions are: \n",
345 total_keysig_size);
346
347 for (ptr = key_positions; *ptr != EOS; ptr++)
348 if (*ptr == WORD_END)
349 fprintf (stderr, "$\n");
350 else
351 fprintf (stderr, "%d\n", *ptr);
352
353 fprintf (stderr, "finished dumping Options\n");
354 }
355}
356
357
358/* Parses the command line Options and sets appropriate flags in option_word. */
359
360static const struct option long_options[] =
361{
362 { "delimiters", required_argument, 0, 'e' },
363 { "struct-type", no_argument, 0, 't' },
364 { "language", required_argument, 0, 'L' },
365 { "slot-name", required_argument, 0, 'K' },
366 { "hash-fn-name", required_argument, 0, 'H' },
367 { "lookup-fn-name", required_argument, 0, 'N' },
368 { "class-name", required_argument, 0, 'Z' },
369 { "seven-bit", no_argument, 0, '7' },
370 { "compare-strncmp", no_argument, 0, 'c' },
371 { "readonly-tables", no_argument, 0, 'C' },
372 { "enum", no_argument, 0, 'E' },
373 { "includes", no_argument, 0, 'I' },
374 { "global", no_argument, 0, 'G' },
375 { "word-array-name", required_argument, 0, 'W' },
376 { "switch", required_argument, 0, 'S' },
377 { "omit-struct-type", no_argument, 0, 'T' },
378 { "key-positions", required_argument, 0, 'k' },
379 { "compare-strlen", no_argument, 0, 'l' },
380 { "duplicates", no_argument, 0, 'D' },
381 { "fast", required_argument, 0, 'f' },
382 { "initial-asso", required_argument, 0, 'i' },
383 { "jump", required_argument, 0, 'j' },
384 { "no-strlen", no_argument, 0, 'n' },
385 { "occurrence-sort", no_argument, 0, 'o' },
386 { "random", no_argument, 0, 'r' },
387 { "size-multiple", required_argument, 0, 's' },
388 { "help", no_argument, 0, 'h' },
389 { "version", no_argument, 0, 'v' },
390 { "debug", no_argument, 0, 'd' },
391 { 0, no_argument, 0, 0 }
392};
393
394void
395Options::operator() (int argc, char *argv[])
396{
397 T (Trace t ("Options::operator()");)
398 int option_char;
399
400 program_name = argv[0];
401 argument_count = argc;
402 argument_vector = argv;
403
404 while ((option_char =
405 getopt_long (argument_count, argument_vector,
406 "adcCDe:Ef:gGhH:i:Ij:k:K:lL:nN:oprs:S:tTvW:Z:7",
407 long_options, (int *)0))
408 != -1)
409 {
410 switch (option_char)
411 {
412 case 'a': /* Generated code uses the ANSI prototype format. */
413 break; /* This is now the default. */
414 case 'c': /* Generate strncmp rather than strcmp. */
415 {
416 option_word |= COMP;
417 break;
418 }
419 case 'C': /* Make the generated tables readonly (const). */
420 {
421 option_word |= CONST;
422 break;
423 }
424 case 'd': /* Enable debugging option. */
425 {
426 option_word |= DEBUG;
427 fprintf (stderr, "Starting program %s, version %s, with debugging on.\n",
428 program_name, version_string);
429 break;
430 }
431 case 'D': /* Enable duplicate option. */
432 {
433 option_word |= DUP;
434 break;
435 }
436 case 'e': /* Allows user to provide keyword/attribute separator */
437 {
438 option.delimiters = /*getopt*/optarg;
439 break;
440 }
441 case 'E':
442 {
443 option_word |= ENUM;
444 break;
445 }
446 case 'f': /* Generate the hash table ``fast.'' */
447 {
448 option_word |= FAST;
449 if ((iterations = atoi (/*getopt*/optarg)) < 0)
450 {
451 fprintf (stderr, "iterations value must not be negative, assuming 0\n");
452 iterations = 0;
453 }
454 break;
455 }
456 case 'g': /* Use the ``inline'' keyword for generated sub-routines, ifdef __GNUC__. */
457 break; /* This is now the default. */
458 case 'G': /* Make the keyword table a global variable. */
459 {
460 option_word |= GLOBAL;
461 break;
462 }
463 case 'h': /* Displays a list of helpful Options to the user. */
464 {
465 long_usage (stdout);
466 exit (0);
467 }
468 case 'H': /* Sets the name for the hash function */
469 {
470 hash_name = /*getopt*/optarg;
471 break;
472 }
473 case 'i': /* Sets the initial value for the associated values array. */
474 {
475 if ((initial_asso_value = atoi (/*getopt*/optarg)) < 0)
476 fprintf (stderr, "Initial value %d should be non-zero, ignoring and continuing.\n", initial_asso_value);
477 if (option[RANDOM])
478 fprintf (stderr, "warning, -r option superceeds -i, ignoring -i option and continuing\n");
479 break;
480 }
481 case 'I': /* Enable #include statements. */
482 {
483 option_word |= INCLUDE;
484 break;
485 }
486 case 'j': /* Sets the jump value, must be odd for later algorithms. */
487 {
488 if ((jump = atoi (/*getopt*/optarg)) < 0)
489 {
490 fprintf (stderr, "Jump value %d must be a positive number.\n", jump);
491 short_usage (stderr);
492 exit (1);
493 }
494 else if (jump && ((jump % 2) == 0))
495 fprintf (stderr, "Jump value %d should be odd, adding 1 and continuing...\n", jump++);
496 break;
497 }
498 case 'k': /* Sets key positions used for hash function. */
499 {
500 const int BAD_VALUE = -1;
501 int value;
502 Iterator expand (/*getopt*/optarg, 1, MAX_KEY_POS - 1, WORD_END, BAD_VALUE, EOS);
503
504 if (/*getopt*/optarg [0] == '*') /* Use all the characters for hashing!!!! */
505 option_word = (option_word & ~DEFAULTCHARS) | ALLCHARS;
506 else
507 {
508 char *key_pos;
509
510 for (key_pos = key_positions; (value = expand ()) != EOS; key_pos++)
511 if (value == BAD_VALUE)
512 {
513 fprintf (stderr, "Illegal key value or range, use 1,2,3-%d,'$' or '*'.\n",
514 MAX_KEY_POS - 1);
515 short_usage (stderr);
516 exit (1);
517 }
518 else
519 *key_pos = value;;
520
521 *key_pos = EOS;
522
523 if (! (total_keysig_size = (key_pos - key_positions)))
524 {
525 fprintf (stderr, "No keys selected.\n");
526 short_usage (stderr);
527 exit (1);
528 }
529 else if (! key_sort (key_positions, total_keysig_size))
530 {
531 fprintf (stderr, "Duplicate keys selected\n");
532 short_usage (stderr);
533 exit (1);
534 }
535
536 if (total_keysig_size != 2
537 || (key_positions[0] != 1 || key_positions[1] != WORD_END))
538 option_word &= ~DEFAULTCHARS;
539 }
540 break;
541 }
542 case 'K': /* Make this the keyname for the keyword component field. */
543 {
544 key_name = /*getopt*/optarg;
545 break;
546 }
547 case 'l': /* Create length table to avoid extra string compares. */
548 {
549 option_word |= LENTABLE;
550 break;
551 }
552 case 'L': /* Deal with different generated languages. */
553 {
554 option_word &= ~(KRC | C | ANSIC | CPLUSPLUS);
555 if (!strcmp (/*getopt*/optarg, "KR-C"))
556 option_word |= KRC;
557 else if (!strcmp (/*getopt*/optarg, "C"))
558 option_word |= C;
559 else if (!strcmp (/*getopt*/optarg, "ANSI-C"))
560 option_word |= ANSIC;
561 else if (!strcmp (/*getopt*/optarg, "C++"))
562 option_word |= CPLUSPLUS;
563 else
564 {
565 fprintf (stderr, "unsupported language option %s, defaulting to C\n", /*getopt*/optarg);
566 option_word |= C;
567 }
568 break;
569 }
570 case 'n': /* Don't include the length when computing hash function. */
571 {
572 option_word |= NOLENGTH;
573 break;
574 }
575 case 'N': /* Make generated lookup function name be optarg */
576 {
577 function_name = /*getopt*/optarg;
578 break;
579 }
580 case 'o': /* Order input by frequency of key set occurrence. */
581 {
582 option_word |= ORDER;
583 break;
584 }
585 case 'p': /* Generated lookup function a pointer instead of int. */
586 break; /* This is now the default. */
587 case 'r': /* Utilize randomness to initialize the associated values table. */
588 {
589 option_word |= RANDOM;
590 if (option.initial_asso_value != 0)
591 fprintf (stderr, "warning, -r option superceeds -i, disabling -i option and continuing\n");
592 break;
593 }
594 case 's': /* Range of associated values, determines size of final table. */
595 {
596 if (abs (size = atoi (/*getopt*/optarg)) > 50)
597 fprintf (stderr, "%d is excessive, did you really mean this?! (try `%s --help' for help)\n", size, program_name);
598 break;
599 }
600 case 'S': /* Generate switch statement output, rather than lookup table. */
601 {
602 option_word |= SWITCH;
603 if ((option.total_switches = atoi (/*getopt*/optarg)) <= 0)
604 {
605 fprintf (stderr, "number of switches %s must be a positive number\n", /*getopt*/optarg);
606 short_usage (stderr);
607 exit (1);
608 }
609 break;
610 }
611 case 't': /* Enable the TYPE mode, allowing arbitrary user structures. */
612 {
613 option_word |= TYPE;
614 break;
615 }
616 case 'T': /* Don't print structure definition. */
617 {
618 option_word |= NOTYPE;
619 break;
620 }
621 case 'v': /* Print out the version and quit. */
622 fprintf (stdout, "GNU gperf %s\n", version_string);
623 exit (0);
624 case 'W': /* Sets the name for the hash table array */
625 {
626 wordlist_name = /*getopt*/optarg;
627 break;
628 }
629 case 'Z': /* Set the class name. */
630 {
631 class_name = /*getopt*/optarg;
632 break;
633 }
634 case '7': /* Assume 7-bit characters. */
635 {
636 option_word |= SEVENBIT;
637 Vectors::ALPHA_SIZE = 128;
638 break;
639 }
640 default:
641 short_usage (stderr);
642 exit (1);
643 }
644
645 }
646
647 if (argv[/*getopt*/optind] && ! freopen (argv[/*getopt*/optind], "r", stdin))
648 {
649 fprintf (stderr, "Cannot open keyword file `%s'\n", argv[/*getopt*/optind]);
650 short_usage (stderr);
651 exit (1);
652 }
653
654 if (++/*getopt*/optind < argc)
655 {
656 fprintf (stderr, "Extra trailing arguments to %s.\n", program_name);
657 short_usage (stderr);
658 exit (1);
659 }
660}
661
662#ifndef __OPTIMIZE__
663
664#define INLINE /* not inline */
665#include "options.icc"
666#undef INLINE
667
668#endif /* not defined __OPTIMIZE__ */
2 Copyright (C) 1989-1998 Free Software Foundation, Inc.
3 written by Douglas C. Schmidt (schmidt@ics.uci.edu)
4
5This file is part of GNU GPERF.
6
7GNU GPERF is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 1, or (at your option)
10any later version.
11
12GNU GPERF is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU GPERF; see the file COPYING. If not, write to the Free
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
20
21#include <stdio.h>
22#include <stdlib.h> /* declares atoi(), abs(), exit() */
23#include <string.h> /* declares strcmp() */
24#include "getopt.h"
25#include "options.h"
26#include "iterator.h"
27#include "trace.h"
28#include "vectors.h"
29#include "version.h"
30
31/* Global option coordinator for the entire program. */
32Options option;
33
34/* Records the program name. */
35const char *program_name;
36
37/* Size to jump on a collision. */
38static const int DEFAULT_JUMP_VALUE = 5;
39
40/* Default name for generated lookup function. */
41static const char *const DEFAULT_NAME = "in_word_set";
42
43/* Default name for the key component. */
44static const char *const DEFAULT_KEY = "name";
45
46/* Default name for the generated class. */
47static const char *const DEFAULT_CLASS_NAME = "Perfect_Hash";
48
49/* Default name for generated hash function. */
50static const char *const DEFAULT_HASH_NAME = "hash";
51
52/* Default name for generated hash table array. */
53static const char *const DEFAULT_WORDLIST_NAME = "wordlist";
54
55/* Default delimiters that separate keywords from their attributes. */
56static const char *const DEFAULT_DELIMITERS = ",\n";
57
58int Options::option_word;
59int Options::total_switches;
60int Options::total_keysig_size;
61int Options::size;
62int Options::key_pos;
63int Options::jump;
64int Options::initial_asso_value;
65int Options::argument_count;
66int Options::iterations;
67char **Options::argument_vector;
68const char *Options::function_name;
69const char *Options::key_name;
70const char *Options::class_name;
71const char *Options::hash_name;
72const char *Options::wordlist_name;
73const char *Options::delimiters;
74char Options::key_positions[MAX_KEY_POS];
75
76/* Prints program usage to given stream. */
77
78void
79Options::short_usage (FILE * strm)
80{
81 T (Trace t ("Options::short_usage");)
82 fprintf (strm, "Usage: %s [-cCdDef[num]GhH
83 "Try `%s --help' for more information.\n",
84 program_name, program_name);
85}
86
87void
88Options::long_usage (FILE * strm)
89{
90 T (Trace t ("Options::long_usage");)
91 fprintf (strm,
92 "GNU `gperf' generates perfect hash functions.\n"
93 "\n"
94 "Usage: %s [OPTION]... [INPUT-FILE]\n"
95 "\n"
96 "If a long option shows an argument as mandatory, then it is mandatory\n"
97 "for the equivalent short option also.\n"
98 "\n"
99 "Input file interpretation:\n"
100 " -e, --delimiters=DELIMITER-LIST\n"
101 " Allow user to provide a string containing delimiters\n"
102 " used to separate keywords from their attributes.\n"
103 " Default is \",\\n\".\n"
104 " -t, --struct-type Allows the user to include a structured type\n"
105 " declaration for generated code. Any text before %%%%\n"
106 " is considered part of the type declaration. Key\n"
107 " words and additional fields may follow this, one\n"
108 " group of fields per line.\n"
109 "\n"
110 "Language for the output code:\n"
111 " -L, --language=LANGUAGE-NAME\n"
112 " Generates code in the specified language. Languages\n"
113 " handled are currently C++, ANSI-C, C, and KR-C. The\n"
114 " default is C.\n"
115 "\n"
116 "Details in the output code:\n"
117 " -K, --slot-name=NAME Select name of the keyword component in the keyword\n"
118 " structure.\n"
119 " -H, --hash-fn-name=NAME\n"
120 " Specify name of generated hash function. Default is\n"
121 " `hash'.\n"
122 " -N, --lookup-fn-name=NAME\n"
123 " Specify name of generated lookup function. Default\n"
124 " name is `in_word_set'.\n"
125 " -Z, --class-name=NAME Specify name of generated C++ class. Default name is\n"
126 " `Perfect_Hash'.\n"
127 " -7, --seven-bit Assume 7-bit characters.\n"
128 " -c, --compare-strncmp Generate comparison code using strncmp rather than\n"
129 " strcmp.\n"
130 " -C, --readonly-tables Make the contents of generated lookup tables\n"
131 " constant, i.e., readonly.\n"
132 " -E, --enum Define constant values using an enum local to the\n"
133 " lookup function rather than with defines.\n"
134 " -I, --includes Include the necessary system include file <string.h>\n"
135 " at the beginning of the code.\n"
136 " -G, --global Generate the static table of keywords as a static\n"
137 " global variable, rather than hiding it inside of the\n"
138 " lookup function (which is the default behavior).\n"
139 " -W, --word-array-name=NAME\n"
140 " Specify name of word list array. Default name is\n"
141 " `wordlist'.\n"
142 " -S, --switch=COUNT Causes the generated C code to use a switch\n"
143 " statement scheme, rather than an array lookup table.\n"
144 " This can lead to a reduction in both time and space\n"
145 " requirements for some keyfiles. The COUNT argument\n"
146 " determines how many switch statements are generated.\n"
147 " A value of 1 generates 1 switch containing all the\n"
148 " elements, a value of 2 generates 2 tables with 1/2\n"
149 " the elements in each table, etc. If COUNT is very\n"
150 " large, say 1000000, the generated C code does a\n"
151 " binary search.\n"
152 " -T, --omit-struct-type\n"
153 " Prevents the transfer of the type declaration to the\n"
154 " output file. Use this option if the type is already\n"
155 " defined elsewhere.\n"
156 "\n"
157 "Algorithm employed by gperf:\n"
158 " -k, --key-positions=KEYS\n"
159 " Select the key positions used in the hash function.\n"
160 " The allowable choices range between 1-%d, inclusive.\n"
161 " The positions are separated by commas, ranges may be\n"
162 " used, and key positions may occur in any order.\n"
163 " Also, the meta-character '*' causes the generated\n"
164 " hash function to consider ALL key positions, and $\n"
165 " indicates the ``final character'' of a key, e.g.,\n"
166 " $,1,2,4,6-10.\n"
167 " -l, --compare-strlen Compare key lengths before trying a string\n"
168 " comparison. This helps cut down on the number of\n"
169 " string comparisons made during the lookup.\n"
170 " -D, --duplicates Handle keywords that hash to duplicate values. This\n"
171 " is useful for certain highly redundant keyword sets.\n"
172 " -f, --fast=ITERATIONS Generate the gen-perf.hash function ``fast''. This\n"
173 " decreases gperf's running time at the cost of\n"
174 " minimizing generated table size. The numeric\n"
175 " argument represents the number of times to iterate\n"
176 " when resolving a collision. `0' means ``iterate by\n"
177 " the number of keywords''.\n"
178 " -i, --initial-asso=N Provide an initial value for the associate values\n"
179 " array. Default is 0. Setting this value larger helps\n"
180 " inflate the size of the final table.\n"
181 " -j, --jump=JUMP-VALUE Affects the ``jump value'', i.e., how far to advance\n"
182 " the associated character value upon collisions. Must\n"
183 " be an odd number, default is %d.\n"
184 " -n, --no-strlen Do not include the length of the keyword when\n"
185 " computing the hash function.\n"
186 " -o, --occurrence-sort Reorders input keys by frequency of occurrence of\n"
187 " the key sets. This should decrease the search time\n"
188 " dramatically.\n"
189 " -r, --random Utilizes randomness to initialize the associated\n"
190 " values table.\n"
191 " -s, --size-multiple=N Affects the size of the generated hash table. The\n"
192 " numeric argument N indicates ``how many times larger\n"
193 " or smaller'' the associated value range should be,\n"
194 " in relationship to the number of keys, e.g. a value\n"
195 " of 3 means ``allow the maximum associated value to\n"
196 " be about 3 times larger than the number of input\n"
197 " keys.'' Conversely, a value of -3 means ``make the\n"
198 " maximum associated value about 3 times smaller than\n"
199 " the number of input keys. A larger table should\n"
200 " decrease the time required for an unsuccessful\n"
201 " search, at the expense of extra table space. Default\n"
202 " value is 1.\n"
203 "\n"
204 "Informative output:\n"
205 " -h, --help Print this message.\n"
206 " -v, --version Print the gperf version number.\n"
207 " -d, --debug Enables the debugging option (produces verbose\n"
208 " output to the standard error).\n"
209 "\n"
210 "Report bugs to <bug-gnu-utils@gnu.org>.\n"
211 , program_name, MAX_KEY_POS - 1, DEFAULT_JUMP_VALUE);
212}
213
214/* Output command-line Options. */
215
216void
217Options::print_options (void)
218{
219 T (Trace t ("Options::print_options");)
220 int i;
221
222 printf ("/* Command-line: ");
223
224 for (i = 0; i < argument_count; i++)
225 printf ("%s ", argument_vector[i]);
226
227 printf (" */");
228}
229
230/* Sorts the key positions *IN REVERSE ORDER!!*
231 This makes further routines more efficient. Especially when generating code.
232 Uses a simple Insertion Sort since the set is probably ordered.
233 Returns 1 if there are no duplicates, 0 otherwise. */
234
235inline int
236Options::key_sort (char *base, int len)
237{
238 T (Trace t ("Options::key_sort");)
239 int i, j;
240
241 for (i = 0, j = len - 1; i < j; i++)
242 {
243 int curr, tmp;
244
245 for (curr = i + 1,tmp = base[curr]; curr > 0 && tmp >= base[curr - 1]; curr--)
246 if ((base[curr] = base[curr - 1]) == tmp) /* oh no, a duplicate!!! */
247 return 0;
248
249 base[curr] = tmp;
250 }
251
252 return 1;
253}
254
255/* Sets the default Options. */
256
257Options::Options (void)
258{
259 T (Trace t ("Options::Options");)
260 key_positions[0] = WORD_START;
261 key_positions[1] = WORD_END;
262 key_positions[2] = EOS;
263 total_keysig_size = 2;
264 delimiters = DEFAULT_DELIMITERS;
265 jump = DEFAULT_JUMP_VALUE;
266 option_word = DEFAULTCHARS | C;
267 function_name = DEFAULT_NAME;
268 key_name = DEFAULT_KEY;
269 hash_name = DEFAULT_HASH_NAME;
270 wordlist_name = DEFAULT_WORDLIST_NAME;
271 class_name = DEFAULT_CLASS_NAME;
272 total_switches = size = 1;
273 initial_asso_value = iterations = 0;
274}
275
276/* Dumps option status when debug is set. */
277
278Options::~Options (void)
279{
280 T (Trace t ("Options::~Options");)
281 if (option_word & DEBUG)
282 {
283 char *ptr;
284
285 fprintf (stderr, "\ndumping Options:"
286 "\nDEBUG is.......: %s"
287 "\nORDER is.......: %s"
288 "\nTYPE is........: %s"
289 "\nRANDOM is......: %s"
290 "\nDEFAULTCHARS is: %s"
291 "\nSWITCH is......: %s"
292 "\nNOLENGTH is....: %s"
293 "\nLENTABLE is....: %s"
294 "\nDUP is.........: %s"
295 "\nFAST is........: %s"
296 "\nCOMP is........: %s"
297 "\nNOTYPE is......: %s"
298 "\nGLOBAL is......: %s"
299 "\nCONST is.......: %s"
300 "\nKRC is.........: %s"
301 "\nC is...........: %s"
302 "\nANSIC is.......: %s"
303 "\nCPLUSPLUS is...: %s"
304 "\nENUM is........: %s"
305 "\nINCLUDE is.....: %s"
306 "\nSEVENBIT is....: %s"
307 "\niterations = %d"
308 "\nlookup function name = %s"
309 "\nhash function name = %s"
310 "\nword list name = %s"
311 "\nkey name = %s"
312 "\njump value = %d"
313 "\nmax associated value = %d"
314 "\ninitial associated value = %d"
315 "\ndelimiters = %s"
316 "\nnumber of switch statements = %d\n",
317 option_word & DEBUG ? "enabled" : "disabled",
318 option_word & ORDER ? "enabled" : "disabled",
319 option_word & TYPE ? "enabled" : "disabled",
320 option_word & RANDOM ? "enabled" : "disabled",
321 option_word & DEFAULTCHARS ? "enabled" : "disabled",
322 option_word & SWITCH ? "enabled" : "disabled",
323 option_word & NOLENGTH ? "enabled" : "disabled",
324 option_word & LENTABLE ? "enabled" : "disabled",
325 option_word & DUP ? "enabled" : "disabled",
326 option_word & FAST ? "enabled" : "disabled",
327 option_word & COMP ? "enabled" : "disabled",
328 option_word & NOTYPE ? "enabled" : "disabled",
329 option_word & GLOBAL ? "enabled" : "disabled",
330 option_word & CONST ? "enabled" : "disabled",
331 option_word & KRC ? "enabled" : "disabled",
332 option_word & C ? "enabled" : "disabled",
333 option_word & ANSIC ? "enabled" : "disabled",
334 option_word & CPLUSPLUS ? "enabled" : "disabled",
335 option_word & ENUM ? "enabled" : "disabled",
336 option_word & INCLUDE ? "enabled" : "disabled",
337 option_word & SEVENBIT ? "enabled" : "disabled",
338 iterations,
339 function_name, hash_name, wordlist_name, key_name,
340 jump, size - 1, initial_asso_value, delimiters, total_switches);
341 if (option_word & ALLCHARS)
342 fprintf (stderr, "all characters are used in the hash function\n");
343
344 fprintf (stderr, "maximum keysig size = %d\nkey positions are: \n",
345 total_keysig_size);
346
347 for (ptr = key_positions; *ptr != EOS; ptr++)
348 if (*ptr == WORD_END)
349 fprintf (stderr, "$\n");
350 else
351 fprintf (stderr, "%d\n", *ptr);
352
353 fprintf (stderr, "finished dumping Options\n");
354 }
355}
356
357
358/* Parses the command line Options and sets appropriate flags in option_word. */
359
360static const struct option long_options[] =
361{
362 { "delimiters", required_argument, 0, 'e' },
363 { "struct-type", no_argument, 0, 't' },
364 { "language", required_argument, 0, 'L' },
365 { "slot-name", required_argument, 0, 'K' },
366 { "hash-fn-name", required_argument, 0, 'H' },
367 { "lookup-fn-name", required_argument, 0, 'N' },
368 { "class-name", required_argument, 0, 'Z' },
369 { "seven-bit", no_argument, 0, '7' },
370 { "compare-strncmp", no_argument, 0, 'c' },
371 { "readonly-tables", no_argument, 0, 'C' },
372 { "enum", no_argument, 0, 'E' },
373 { "includes", no_argument, 0, 'I' },
374 { "global", no_argument, 0, 'G' },
375 { "word-array-name", required_argument, 0, 'W' },
376 { "switch", required_argument, 0, 'S' },
377 { "omit-struct-type", no_argument, 0, 'T' },
378 { "key-positions", required_argument, 0, 'k' },
379 { "compare-strlen", no_argument, 0, 'l' },
380 { "duplicates", no_argument, 0, 'D' },
381 { "fast", required_argument, 0, 'f' },
382 { "initial-asso", required_argument, 0, 'i' },
383 { "jump", required_argument, 0, 'j' },
384 { "no-strlen", no_argument, 0, 'n' },
385 { "occurrence-sort", no_argument, 0, 'o' },
386 { "random", no_argument, 0, 'r' },
387 { "size-multiple", required_argument, 0, 's' },
388 { "help", no_argument, 0, 'h' },
389 { "version", no_argument, 0, 'v' },
390 { "debug", no_argument, 0, 'd' },
391 { 0, no_argument, 0, 0 }
392};
393
394void
395Options::operator() (int argc, char *argv[])
396{
397 T (Trace t ("Options::operator()");)
398 int option_char;
399
400 program_name = argv[0];
401 argument_count = argc;
402 argument_vector = argv;
403
404 while ((option_char =
405 getopt_long (argument_count, argument_vector,
406 "adcCDe:Ef:gGhH:i:Ij:k:K:lL:nN:oprs:S:tTvW:Z:7",
407 long_options, (int *)0))
408 != -1)
409 {
410 switch (option_char)
411 {
412 case 'a': /* Generated code uses the ANSI prototype format. */
413 break; /* This is now the default. */
414 case 'c': /* Generate strncmp rather than strcmp. */
415 {
416 option_word |= COMP;
417 break;
418 }
419 case 'C': /* Make the generated tables readonly (const). */
420 {
421 option_word |= CONST;
422 break;
423 }
424 case 'd': /* Enable debugging option. */
425 {
426 option_word |= DEBUG;
427 fprintf (stderr, "Starting program %s, version %s, with debugging on.\n",
428 program_name, version_string);
429 break;
430 }
431 case 'D': /* Enable duplicate option. */
432 {
433 option_word |= DUP;
434 break;
435 }
436 case 'e': /* Allows user to provide keyword/attribute separator */
437 {
438 option.delimiters = /*getopt*/optarg;
439 break;
440 }
441 case 'E':
442 {
443 option_word |= ENUM;
444 break;
445 }
446 case 'f': /* Generate the hash table ``fast.'' */
447 {
448 option_word |= FAST;
449 if ((iterations = atoi (/*getopt*/optarg)) < 0)
450 {
451 fprintf (stderr, "iterations value must not be negative, assuming 0\n");
452 iterations = 0;
453 }
454 break;
455 }
456 case 'g': /* Use the ``inline'' keyword for generated sub-routines, ifdef __GNUC__. */
457 break; /* This is now the default. */
458 case 'G': /* Make the keyword table a global variable. */
459 {
460 option_word |= GLOBAL;
461 break;
462 }
463 case 'h': /* Displays a list of helpful Options to the user. */
464 {
465 long_usage (stdout);
466 exit (0);
467 }
468 case 'H': /* Sets the name for the hash function */
469 {
470 hash_name = /*getopt*/optarg;
471 break;
472 }
473 case 'i': /* Sets the initial value for the associated values array. */
474 {
475 if ((initial_asso_value = atoi (/*getopt*/optarg)) < 0)
476 fprintf (stderr, "Initial value %d should be non-zero, ignoring and continuing.\n", initial_asso_value);
477 if (option[RANDOM])
478 fprintf (stderr, "warning, -r option superceeds -i, ignoring -i option and continuing\n");
479 break;
480 }
481 case 'I': /* Enable #include statements. */
482 {
483 option_word |= INCLUDE;
484 break;
485 }
486 case 'j': /* Sets the jump value, must be odd for later algorithms. */
487 {
488 if ((jump = atoi (/*getopt*/optarg)) < 0)
489 {
490 fprintf (stderr, "Jump value %d must be a positive number.\n", jump);
491 short_usage (stderr);
492 exit (1);
493 }
494 else if (jump && ((jump % 2) == 0))
495 fprintf (stderr, "Jump value %d should be odd, adding 1 and continuing...\n", jump++);
496 break;
497 }
498 case 'k': /* Sets key positions used for hash function. */
499 {
500 const int BAD_VALUE = -1;
501 int value;
502 Iterator expand (/*getopt*/optarg, 1, MAX_KEY_POS - 1, WORD_END, BAD_VALUE, EOS);
503
504 if (/*getopt*/optarg [0] == '*') /* Use all the characters for hashing!!!! */
505 option_word = (option_word & ~DEFAULTCHARS) | ALLCHARS;
506 else
507 {
508 char *key_pos;
509
510 for (key_pos = key_positions; (value = expand ()) != EOS; key_pos++)
511 if (value == BAD_VALUE)
512 {
513 fprintf (stderr, "Illegal key value or range, use 1,2,3-%d,'$' or '*'.\n",
514 MAX_KEY_POS - 1);
515 short_usage (stderr);
516 exit (1);
517 }
518 else
519 *key_pos = value;;
520
521 *key_pos = EOS;
522
523 if (! (total_keysig_size = (key_pos - key_positions)))
524 {
525 fprintf (stderr, "No keys selected.\n");
526 short_usage (stderr);
527 exit (1);
528 }
529 else if (! key_sort (key_positions, total_keysig_size))
530 {
531 fprintf (stderr, "Duplicate keys selected\n");
532 short_usage (stderr);
533 exit (1);
534 }
535
536 if (total_keysig_size != 2
537 || (key_positions[0] != 1 || key_positions[1] != WORD_END))
538 option_word &= ~DEFAULTCHARS;
539 }
540 break;
541 }
542 case 'K': /* Make this the keyname for the keyword component field. */
543 {
544 key_name = /*getopt*/optarg;
545 break;
546 }
547 case 'l': /* Create length table to avoid extra string compares. */
548 {
549 option_word |= LENTABLE;
550 break;
551 }
552 case 'L': /* Deal with different generated languages. */
553 {
554 option_word &= ~(KRC | C | ANSIC | CPLUSPLUS);
555 if (!strcmp (/*getopt*/optarg, "KR-C"))
556 option_word |= KRC;
557 else if (!strcmp (/*getopt*/optarg, "C"))
558 option_word |= C;
559 else if (!strcmp (/*getopt*/optarg, "ANSI-C"))
560 option_word |= ANSIC;
561 else if (!strcmp (/*getopt*/optarg, "C++"))
562 option_word |= CPLUSPLUS;
563 else
564 {
565 fprintf (stderr, "unsupported language option %s, defaulting to C\n", /*getopt*/optarg);
566 option_word |= C;
567 }
568 break;
569 }
570 case 'n': /* Don't include the length when computing hash function. */
571 {
572 option_word |= NOLENGTH;
573 break;
574 }
575 case 'N': /* Make generated lookup function name be optarg */
576 {
577 function_name = /*getopt*/optarg;
578 break;
579 }
580 case 'o': /* Order input by frequency of key set occurrence. */
581 {
582 option_word |= ORDER;
583 break;
584 }
585 case 'p': /* Generated lookup function a pointer instead of int. */
586 break; /* This is now the default. */
587 case 'r': /* Utilize randomness to initialize the associated values table. */
588 {
589 option_word |= RANDOM;
590 if (option.initial_asso_value != 0)
591 fprintf (stderr, "warning, -r option superceeds -i, disabling -i option and continuing\n");
592 break;
593 }
594 case 's': /* Range of associated values, determines size of final table. */
595 {
596 if (abs (size = atoi (/*getopt*/optarg)) > 50)
597 fprintf (stderr, "%d is excessive, did you really mean this?! (try `%s --help' for help)\n", size, program_name);
598 break;
599 }
600 case 'S': /* Generate switch statement output, rather than lookup table. */
601 {
602 option_word |= SWITCH;
603 if ((option.total_switches = atoi (/*getopt*/optarg)) <= 0)
604 {
605 fprintf (stderr, "number of switches %s must be a positive number\n", /*getopt*/optarg);
606 short_usage (stderr);
607 exit (1);
608 }
609 break;
610 }
611 case 't': /* Enable the TYPE mode, allowing arbitrary user structures. */
612 {
613 option_word |= TYPE;
614 break;
615 }
616 case 'T': /* Don't print structure definition. */
617 {
618 option_word |= NOTYPE;
619 break;
620 }
621 case 'v': /* Print out the version and quit. */
622 fprintf (stdout, "GNU gperf %s\n", version_string);
623 exit (0);
624 case 'W': /* Sets the name for the hash table array */
625 {
626 wordlist_name = /*getopt*/optarg;
627 break;
628 }
629 case 'Z': /* Set the class name. */
630 {
631 class_name = /*getopt*/optarg;
632 break;
633 }
634 case '7': /* Assume 7-bit characters. */
635 {
636 option_word |= SEVENBIT;
637 Vectors::ALPHA_SIZE = 128;
638 break;
639 }
640 default:
641 short_usage (stderr);
642 exit (1);
643 }
644
645 }
646
647 if (argv[/*getopt*/optind] && ! freopen (argv[/*getopt*/optind], "r", stdin))
648 {
649 fprintf (stderr, "Cannot open keyword file `%s'\n", argv[/*getopt*/optind]);
650 short_usage (stderr);
651 exit (1);
652 }
653
654 if (++/*getopt*/optind < argc)
655 {
656 fprintf (stderr, "Extra trailing arguments to %s.\n", program_name);
657 short_usage (stderr);
658 exit (1);
659 }
660}
661
662#ifndef __OPTIMIZE__
663
664#define INLINE /* not inline */
665#include "options.icc"
666#undef INLINE
667
668#endif /* not defined __OPTIMIZE__ */