1 /* Handles parsing the Options provided to the user.
2 Copyright (C) 1989-1998, 2000 Free Software Foundation, Inc.
3 written by Douglas C. Schmidt (schmidt@ics.uci.edu)
5 This file is part of GNU GPERF.
7 GNU GPERF is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 1, or (at your option)
12 GNU GPERF is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU GPERF; see the file COPYING. If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
22 #include <stdlib.h> /* declares atoi(), abs(), exit() */
23 #include <string.h> /* declares strcmp() */
31 /* Global option coordinator for the entire program. */
34 /* Records the program name. */
35 const char *program_name
;
37 /* Size to jump on a collision. */
38 static const int DEFAULT_JUMP_VALUE
= 5;
40 /* Default name for generated lookup function. */
41 static const char *const DEFAULT_NAME
= "in_word_set";
43 /* Default name for the key component. */
44 static const char *const DEFAULT_KEY
= "name";
46 /* Default struct initializer suffix. */
47 static const char *const DEFAULT_INITIALIZER_SUFFIX
= "";
49 /* Default name for the generated class. */
50 static const char *const DEFAULT_CLASS_NAME
= "Perfect_Hash";
52 /* Default name for generated hash function. */
53 static const char *const DEFAULT_HASH_NAME
= "hash";
55 /* Default name for generated hash table array. */
56 static const char *const DEFAULT_WORDLIST_NAME
= "wordlist";
58 /* Default delimiters that separate keywords from their attributes. */
59 static const char *const DEFAULT_DELIMITERS
= ",\n";
61 int Options::option_word
;
62 int Options::total_switches
;
63 int Options::total_keysig_size
;
67 int Options::initial_asso_value
;
68 int Options::argument_count
;
69 int Options::iterations
;
70 char **Options::argument_vector
;
71 const char *Options::function_name
;
72 const char *Options::key_name
;
73 const char *Options::initializer_suffix
;
74 const char *Options::class_name
;
75 const char *Options::hash_name
;
76 const char *Options::wordlist_name
;
77 const char *Options::delimiters
;
78 char Options::key_positions
[MAX_KEY_POS
];
80 /* Prints program usage to given stream. */
83 Options::short_usage (FILE * strm
)
85 T (Trace
t ("Options::short_usage");)
86 fprintf (strm
, "Usage: %s [-cCdDef[num]F<initializers>GhH<hashname>i<init>Ijk<keys>K<keyname>lL<language>nN<function name>ors<size>S<switches>tTvW<wordlistname>Z<class name>7] [input-file]\n"
87 "Try `%s --help' for more information.\n",
88 program_name
, program_name
);
92 Options::long_usage (FILE * strm
)
94 T (Trace
t ("Options::long_usage");)
96 "GNU `gperf' generates perfect hash functions.\n"
98 "Usage: %s [OPTION]... [INPUT-FILE]\n"
100 "If a long option shows an argument as mandatory, then it is mandatory\n"
101 "for the equivalent short option also.\n"
103 "Input file interpretation:\n"
104 " -e, --delimiters=DELIMITER-LIST\n"
105 " Allow user to provide a string containing delimiters\n"
106 " used to separate keywords from their attributes.\n"
107 " Default is \",\\n\".\n"
108 " -t, --struct-type Allows the user to include a structured type\n"
109 " declaration for generated code. Any text before %%%%\n"
110 " is considered part of the type declaration. Key\n"
111 " words and additional fields may follow this, one\n"
112 " group of fields per line.\n"
114 "Language for the output code:\n"
115 " -L, --language=LANGUAGE-NAME\n"
116 " Generates code in the specified language. Languages\n"
117 " handled are currently C++, ANSI-C, C, and KR-C. The\n"
120 "Details in the output code:\n"
121 " -K, --slot-name=NAME Select name of the keyword component in the keyword\n"
123 " -F, --initializer-suffix=INITIALIZERS\n"
124 " Initializers for additional components in the keyword\n"
126 " -H, --hash-fn-name=NAME\n"
127 " Specify name of generated hash function. Default is\n"
129 " -N, --lookup-fn-name=NAME\n"
130 " Specify name of generated lookup function. Default\n"
131 " name is `in_word_set'.\n"
132 " -Z, --class-name=NAME Specify name of generated C++ class. Default name is\n"
134 " -7, --seven-bit Assume 7-bit characters.\n"
135 " -c, --compare-strncmp Generate comparison code using strncmp rather than\n"
137 " -C, --readonly-tables Make the contents of generated lookup tables\n"
138 " constant, i.e., readonly.\n"
139 " -E, --enum Define constant values using an enum local to the\n"
140 " lookup function rather than with defines.\n"
141 " -I, --includes Include the necessary system include file <string.h>\n"
142 " at the beginning of the code.\n"
143 " -G, --global Generate the static table of keywords as a static\n"
144 " global variable, rather than hiding it inside of the\n"
145 " lookup function (which is the default behavior).\n"
146 " -W, --word-array-name=NAME\n"
147 " Specify name of word list array. Default name is\n"
149 " -S, --switch=COUNT Causes the generated C code to use a switch\n"
150 " statement scheme, rather than an array lookup table.\n"
151 " This can lead to a reduction in both time and space\n"
152 " requirements for some keyfiles. The COUNT argument\n"
153 " determines how many switch statements are generated.\n"
154 " A value of 1 generates 1 switch containing all the\n"
155 " elements, a value of 2 generates 2 tables with 1/2\n"
156 " the elements in each table, etc. If COUNT is very\n"
157 " large, say 1000000, the generated C code does a\n"
159 " -T, --omit-struct-type\n"
160 " Prevents the transfer of the type declaration to the\n"
161 " output file. Use this option if the type is already\n"
162 " defined elsewhere.\n"
164 "Algorithm employed by gperf:\n"
165 " -k, --key-positions=KEYS\n"
166 " Select the key positions used in the hash function.\n"
167 " The allowable choices range between 1-%d, inclusive.\n"
168 " The positions are separated by commas, ranges may be\n"
169 " used, and key positions may occur in any order.\n"
170 " Also, the meta-character '*' causes the generated\n"
171 " hash function to consider ALL key positions, and $\n"
172 " indicates the ``final character'' of a key, e.g.,\n"
174 " -l, --compare-strlen Compare key lengths before trying a string\n"
175 " comparison. This helps cut down on the number of\n"
176 " string comparisons made during the lookup.\n"
177 " -D, --duplicates Handle keywords that hash to duplicate values. This\n"
178 " is useful for certain highly redundant keyword sets.\n"
179 " -f, --fast=ITERATIONS Generate the gen-perf.hash function ``fast''. This\n"
180 " decreases gperf's running time at the cost of\n"
181 " minimizing generated table size. The numeric\n"
182 " argument represents the number of times to iterate\n"
183 " when resolving a collision. `0' means ``iterate by\n"
184 " the number of keywords''.\n"
185 " -i, --initial-asso=N Provide an initial value for the associate values\n"
186 " array. Default is 0. Setting this value larger helps\n"
187 " inflate the size of the final table.\n"
188 " -j, --jump=JUMP-VALUE Affects the ``jump value'', i.e., how far to advance\n"
189 " the associated character value upon collisions. Must\n"
190 " be an odd number, default is %d.\n"
191 " -n, --no-strlen Do not include the length of the keyword when\n"
192 " computing the hash function.\n"
193 " -o, --occurrence-sort Reorders input keys by frequency of occurrence of\n"
194 " the key sets. This should decrease the search time\n"
196 " -r, --random Utilizes randomness to initialize the associated\n"
198 " -s, --size-multiple=N Affects the size of the generated hash table. The\n"
199 " numeric argument N indicates ``how many times larger\n"
200 " or smaller'' the associated value range should be,\n"
201 " in relationship to the number of keys, e.g. a value\n"
202 " of 3 means ``allow the maximum associated value to\n"
203 " be about 3 times larger than the number of input\n"
204 " keys.'' Conversely, a value of -3 means ``make the\n"
205 " maximum associated value about 3 times smaller than\n"
206 " the number of input keys. A larger table should\n"
207 " decrease the time required for an unsuccessful\n"
208 " search, at the expense of extra table space. Default\n"
211 "Informative output:\n"
212 " -h, --help Print this message.\n"
213 " -v, --version Print the gperf version number.\n"
214 " -d, --debug Enables the debugging option (produces verbose\n"
215 " output to the standard error).\n"
217 "Report bugs to <bug-gnu-utils@gnu.org>.\n"
218 , program_name
, MAX_KEY_POS
- 1, DEFAULT_JUMP_VALUE
);
221 /* Output command-line Options. */
224 Options::print_options (void)
226 T (Trace
t ("Options::print_options");)
229 printf ("/* Command-line: ");
231 for (i
= 0; i
< argument_count
; i
++)
233 const char *arg
= argument_vector
[i
];
235 /* Escape arg if it contains shell metacharacters. */
240 if (*arg
>= 'A' && *arg
<= 'Z' || *arg
>= 'a' && *arg
<= 'z')
246 if (strpbrk (arg
, "\t\n !\"#$&'()*;<>?[\\]`{|}~") != NULL
)
248 if (strchr (arg
, '\'') != NULL
)
253 if (*arg
== '\"' || *arg
== '\\' || *arg
== '$')
280 /* Sorts the key positions *IN REVERSE ORDER!!*
281 This makes further routines more efficient. Especially when generating code.
282 Uses a simple Insertion Sort since the set is probably ordered.
283 Returns 1 if there are no duplicates, 0 otherwise. */
286 Options::key_sort (char *base
, int len
)
288 T (Trace
t ("Options::key_sort");)
291 for (i
= 0, j
= len
- 1; i
< j
; i
++)
295 for (curr
= i
+ 1,tmp
= base
[curr
]; curr
> 0 && tmp
>= base
[curr
- 1]; curr
--)
296 if ((base
[curr
] = base
[curr
- 1]) == tmp
) /* oh no, a duplicate!!! */
305 /* Sets the default Options. */
307 Options::Options (void)
309 T (Trace
t ("Options::Options");)
310 key_positions
[0] = WORD_START
;
311 key_positions
[1] = WORD_END
;
312 key_positions
[2] = EOS
;
313 total_keysig_size
= 2;
314 delimiters
= DEFAULT_DELIMITERS
;
315 jump
= DEFAULT_JUMP_VALUE
;
316 option_word
= DEFAULTCHARS
| C
;
317 function_name
= DEFAULT_NAME
;
318 key_name
= DEFAULT_KEY
;
319 initializer_suffix
= DEFAULT_INITIALIZER_SUFFIX
;
320 hash_name
= DEFAULT_HASH_NAME
;
321 wordlist_name
= DEFAULT_WORDLIST_NAME
;
322 class_name
= DEFAULT_CLASS_NAME
;
323 total_switches
= size
= 1;
324 initial_asso_value
= iterations
= 0;
327 /* Dumps option status when debug is set. */
329 Options::~Options (void)
331 T (Trace
t ("Options::~Options");)
332 if (option_word
& DEBUG
)
336 fprintf (stderr
, "\ndumping Options:"
337 "\nDEBUG is.......: %s"
338 "\nORDER is.......: %s"
339 "\nTYPE is........: %s"
340 "\nRANDOM is......: %s"
341 "\nDEFAULTCHARS is: %s"
342 "\nSWITCH is......: %s"
343 "\nNOLENGTH is....: %s"
344 "\nLENTABLE is....: %s"
345 "\nDUP is.........: %s"
346 "\nFAST is........: %s"
347 "\nCOMP is........: %s"
348 "\nNOTYPE is......: %s"
349 "\nGLOBAL is......: %s"
350 "\nCONST is.......: %s"
351 "\nKRC is.........: %s"
352 "\nC is...........: %s"
353 "\nANSIC is.......: %s"
354 "\nCPLUSPLUS is...: %s"
355 "\nENUM is........: %s"
356 "\nINCLUDE is.....: %s"
357 "\nSEVENBIT is....: %s"
359 "\nlookup function name = %s"
360 "\nhash function name = %s"
361 "\nword list name = %s"
363 "\ninitializer suffix = %s"
365 "\nmax associated value = %d"
366 "\ninitial associated value = %d"
368 "\nnumber of switch statements = %d\n",
369 option_word
& DEBUG
? "enabled" : "disabled",
370 option_word
& ORDER
? "enabled" : "disabled",
371 option_word
& TYPE
? "enabled" : "disabled",
372 option_word
& RANDOM
? "enabled" : "disabled",
373 option_word
& DEFAULTCHARS
? "enabled" : "disabled",
374 option_word
& SWITCH
? "enabled" : "disabled",
375 option_word
& NOLENGTH
? "enabled" : "disabled",
376 option_word
& LENTABLE
? "enabled" : "disabled",
377 option_word
& DUP
? "enabled" : "disabled",
378 option_word
& FAST
? "enabled" : "disabled",
379 option_word
& COMP
? "enabled" : "disabled",
380 option_word
& NOTYPE
? "enabled" : "disabled",
381 option_word
& GLOBAL
? "enabled" : "disabled",
382 option_word
& CONST
? "enabled" : "disabled",
383 option_word
& KRC
? "enabled" : "disabled",
384 option_word
& C
? "enabled" : "disabled",
385 option_word
& ANSIC
? "enabled" : "disabled",
386 option_word
& CPLUSPLUS
? "enabled" : "disabled",
387 option_word
& ENUM
? "enabled" : "disabled",
388 option_word
& INCLUDE
? "enabled" : "disabled",
389 option_word
& SEVENBIT
? "enabled" : "disabled",
391 function_name
, hash_name
, wordlist_name
, key_name
,
392 initializer_suffix
, jump
, size
- 1, initial_asso_value
,
393 delimiters
, total_switches
);
394 if (option_word
& ALLCHARS
)
395 fprintf (stderr
, "all characters are used in the hash function\n");
397 fprintf (stderr
, "maximum keysig size = %d\nkey positions are: \n",
400 for (ptr
= key_positions
; *ptr
!= EOS
; ptr
++)
401 if (*ptr
== WORD_END
)
402 fprintf (stderr
, "$\n");
404 fprintf (stderr
, "%d\n", *ptr
);
406 fprintf (stderr
, "finished dumping Options\n");
411 /* Parses the command line Options and sets appropriate flags in option_word. */
413 static const struct option long_options
[] =
415 { "delimiters", required_argument
, 0, 'e' },
416 { "struct-type", no_argument
, 0, 't' },
417 { "language", required_argument
, 0, 'L' },
418 { "slot-name", required_argument
, 0, 'K' },
419 { "initializer-suffix", required_argument
, 0, 'F' },
420 { "hash-fn-name", required_argument
, 0, 'H' },
421 { "lookup-fn-name", required_argument
, 0, 'N' },
422 { "class-name", required_argument
, 0, 'Z' },
423 { "seven-bit", no_argument
, 0, '7' },
424 { "compare-strncmp", no_argument
, 0, 'c' },
425 { "readonly-tables", no_argument
, 0, 'C' },
426 { "enum", no_argument
, 0, 'E' },
427 { "includes", no_argument
, 0, 'I' },
428 { "global", no_argument
, 0, 'G' },
429 { "word-array-name", required_argument
, 0, 'W' },
430 { "switch", required_argument
, 0, 'S' },
431 { "omit-struct-type", no_argument
, 0, 'T' },
432 { "key-positions", required_argument
, 0, 'k' },
433 { "compare-strlen", no_argument
, 0, 'l' },
434 { "duplicates", no_argument
, 0, 'D' },
435 { "fast", required_argument
, 0, 'f' },
436 { "initial-asso", required_argument
, 0, 'i' },
437 { "jump", required_argument
, 0, 'j' },
438 { "no-strlen", no_argument
, 0, 'n' },
439 { "occurrence-sort", no_argument
, 0, 'o' },
440 { "random", no_argument
, 0, 'r' },
441 { "size-multiple", required_argument
, 0, 's' },
442 { "help", no_argument
, 0, 'h' },
443 { "version", no_argument
, 0, 'v' },
444 { "debug", no_argument
, 0, 'd' },
445 { 0, no_argument
, 0, 0 }
449 Options::operator() (int argc
, char *argv
[])
451 T (Trace
t ("Options::operator()");)
454 program_name
= argv
[0];
455 argument_count
= argc
;
456 argument_vector
= argv
;
458 while ((option_char
=
459 getopt_long (argument_count
, argument_vector
,
460 "adcCDe:Ef:F:gGhH:i:Ij:k:K:lL:nN:oprs:S:tTvW:Z:7",
461 long_options
, (int *)0))
466 case 'a': /* Generated code uses the ANSI prototype format. */
467 break; /* This is now the default. */
468 case 'c': /* Generate strncmp rather than strcmp. */
473 case 'C': /* Make the generated tables readonly (const). */
475 option_word
|= CONST
;
478 case 'd': /* Enable debugging option. */
480 option_word
|= DEBUG
;
481 fprintf (stderr
, "Starting program %s, version %s, with debugging on.\n",
482 program_name
, version_string
);
485 case 'D': /* Enable duplicate option. */
490 case 'e': /* Allows user to provide keyword/attribute separator */
492 option
.delimiters
= /*getopt*/optarg
;
500 case 'f': /* Generate the hash table ``fast.'' */
503 if ((iterations
= atoi (/*getopt*/optarg
)) < 0)
505 fprintf (stderr
, "iterations value must not be negative, assuming 0\n");
512 initializer_suffix
= /*getopt*/optarg
;
515 case 'g': /* Use the ``inline'' keyword for generated sub-routines, ifdef __GNUC__. */
516 break; /* This is now the default. */
517 case 'G': /* Make the keyword table a global variable. */
519 option_word
|= GLOBAL
;
522 case 'h': /* Displays a list of helpful Options to the user. */
527 case 'H': /* Sets the name for the hash function */
529 hash_name
= /*getopt*/optarg
;
532 case 'i': /* Sets the initial value for the associated values array. */
534 if ((initial_asso_value
= atoi (/*getopt*/optarg
)) < 0)
535 fprintf (stderr
, "Initial value %d should be non-zero, ignoring and continuing.\n", initial_asso_value
);
537 fprintf (stderr
, "warning, -r option superceeds -i, ignoring -i option and continuing\n");
540 case 'I': /* Enable #include statements. */
542 option_word
|= INCLUDE
;
545 case 'j': /* Sets the jump value, must be odd for later algorithms. */
547 if ((jump
= atoi (/*getopt*/optarg
)) < 0)
549 fprintf (stderr
, "Jump value %d must be a positive number.\n", jump
);
550 short_usage (stderr
);
553 else if (jump
&& ((jump
% 2) == 0))
554 fprintf (stderr
, "Jump value %d should be odd, adding 1 and continuing...\n", jump
++);
557 case 'k': /* Sets key positions used for hash function. */
559 const int BAD_VALUE
= -1;
561 Iterator
expand (/*getopt*/optarg
, 1, MAX_KEY_POS
- 1, WORD_END
, BAD_VALUE
, EOS
);
563 if (/*getopt*/optarg
[0] == '*') /* Use all the characters for hashing!!!! */
564 option_word
= (option_word
& ~DEFAULTCHARS
) | ALLCHARS
;
569 for (key_pos
= key_positions
; (value
= expand ()) != EOS
; key_pos
++)
570 if (value
== BAD_VALUE
)
572 fprintf (stderr
, "Illegal key value or range, use 1,2,3-%d,'$' or '*'.\n",
574 short_usage (stderr
);
582 if (! (total_keysig_size
= (key_pos
- key_positions
)))
584 fprintf (stderr
, "No keys selected.\n");
585 short_usage (stderr
);
588 else if (! key_sort (key_positions
, total_keysig_size
))
590 fprintf (stderr
, "Duplicate keys selected\n");
591 short_usage (stderr
);
595 if (total_keysig_size
!= 2
596 || (key_positions
[0] != 1 || key_positions
[1] != WORD_END
))
597 option_word
&= ~DEFAULTCHARS
;
601 case 'K': /* Make this the keyname for the keyword component field. */
603 key_name
= /*getopt*/optarg
;
606 case 'l': /* Create length table to avoid extra string compares. */
608 option_word
|= LENTABLE
;
611 case 'L': /* Deal with different generated languages. */
613 option_word
&= ~(KRC
| C
| ANSIC
| CPLUSPLUS
);
614 if (!strcmp (/*getopt*/optarg
, "KR-C"))
616 else if (!strcmp (/*getopt*/optarg
, "C"))
618 else if (!strcmp (/*getopt*/optarg
, "ANSI-C"))
619 option_word
|= ANSIC
;
620 else if (!strcmp (/*getopt*/optarg
, "C++"))
621 option_word
|= CPLUSPLUS
;
624 fprintf (stderr
, "unsupported language option %s, defaulting to C\n", /*getopt*/optarg
);
629 case 'n': /* Don't include the length when computing hash function. */
631 option_word
|= NOLENGTH
;
634 case 'N': /* Make generated lookup function name be optarg */
636 function_name
= /*getopt*/optarg
;
639 case 'o': /* Order input by frequency of key set occurrence. */
641 option_word
|= ORDER
;
644 case 'p': /* Generated lookup function a pointer instead of int. */
645 break; /* This is now the default. */
646 case 'r': /* Utilize randomness to initialize the associated values table. */
648 option_word
|= RANDOM
;
649 if (option
.initial_asso_value
!= 0)
650 fprintf (stderr
, "warning, -r option superceeds -i, disabling -i option and continuing\n");
653 case 's': /* Range of associated values, determines size of final table. */
655 if (abs (size
= atoi (/*getopt*/optarg
)) > 50)
656 fprintf (stderr
, "%d is excessive, did you really mean this?! (try `%s --help' for help)\n", size
, program_name
);
659 case 'S': /* Generate switch statement output, rather than lookup table. */
661 option_word
|= SWITCH
;
662 if ((option
.total_switches
= atoi (/*getopt*/optarg
)) <= 0)
664 fprintf (stderr
, "number of switches %s must be a positive number\n", /*getopt*/optarg
);
665 short_usage (stderr
);
670 case 't': /* Enable the TYPE mode, allowing arbitrary user structures. */
675 case 'T': /* Don't print structure definition. */
677 option_word
|= NOTYPE
;
680 case 'v': /* Print out the version and quit. */
681 fprintf (stdout
, "GNU gperf %s\n", version_string
);
683 case 'W': /* Sets the name for the hash table array */
685 wordlist_name
= /*getopt*/optarg
;
688 case 'Z': /* Set the class name. */
690 class_name
= /*getopt*/optarg
;
693 case '7': /* Assume 7-bit characters. */
695 option_word
|= SEVENBIT
;
696 Vectors::ALPHA_SIZE
= 128;
700 short_usage (stderr
);
706 if (argv
[/*getopt*/optind
] && ! freopen (argv
[/*getopt*/optind
], "r", stdin
))
708 fprintf (stderr
, "Cannot open keyword file `%s'\n", argv
[/*getopt*/optind
]);
709 short_usage (stderr
);
713 if (++/*getopt*/optind
< argc
)
715 fprintf (stderr
, "Extra trailing arguments to %s.\n", program_name
);
716 short_usage (stderr
);
723 #define INLINE /* not inline */
724 #include "options.icc"
727 #endif /* not defined __OPTIMIZE__ */