]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/gperf/src/options.cc
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / gperf / src / options.cc
1 /* Handles parsing the Options provided to the user.
2    Copyright (C) 1989-1998, 2000, 2002-2004, 2006-2007 Free Software Foundation, Inc.
3    Written by Douglas C. Schmidt <schmidt@ics.uci.edu>
4    and Bruno Haible <bruno@clisp.org>.
5
6    This file is part of GNU GPERF.
7
8    GNU GPERF is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2, or (at your option)
11    any later version.
12
13    GNU GPERF is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; see the file COPYING.
20    If not, write to the Free Software Foundation, Inc.,
21    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
22
23 /* Specification. */
24 #include "options.h"
25
26 #include <stdio.h>
27 #include <stdlib.h> /* declares atoi(), abs(), exit() */
28 #include <string.h> /* declares strcmp() */
29 #include <ctype.h>  /* declares isdigit() */
30 #include <limits.h> /* defines CHAR_MAX */
31 #include "getopt.h"
32 #include "version.h"
33
34 /* Global option coordinator for the entire program.  */
35 Options option;
36
37 /* Records the program name.  */
38 const char *program_name;
39
40 /* Size to jump on a collision.  */
41 static const int DEFAULT_JUMP_VALUE = 5;
42
43 /* Default name for generated lookup function.  */
44 static const char *const DEFAULT_FUNCTION_NAME = "in_word_set";
45
46 /* Default name for the key component.  */
47 static const char *const DEFAULT_SLOT_NAME = "name";
48
49 /* Default struct initializer suffix.  */
50 static const char *const DEFAULT_INITIALIZER_SUFFIX = "";
51
52 /* Default name for the generated class.  */
53 static const char *const DEFAULT_CLASS_NAME = "Perfect_Hash";
54
55 /* Default name for generated hash function.  */
56 static const char *const DEFAULT_HASH_NAME = "hash";
57
58 /* Default name for generated hash table array.  */
59 static const char *const DEFAULT_WORDLIST_NAME = "wordlist";
60
61 /* Default name for generated length table array.  */
62 static const char *const DEFAULT_LENGTHTABLE_NAME = "lengthtable";
63
64 /* Default name for string pool.  */
65 static const char *const DEFAULT_STRINGPOOL_NAME = "stringpool";
66
67 /* Default delimiters that separate keywords from their attributes.  */
68 static const char *const DEFAULT_DELIMITERS = ",";
69
70 /* Prints program usage to given stream.  */
71
72 void
73 Options::short_usage (FILE * stream)
74 {
75   fprintf (stream,
76            "Try '%s --help' for more information.\n", program_name);
77 }
78
79 void
80 Options::long_usage (FILE * stream)
81 {
82   fprintf (stream,
83            "GNU 'gperf' generates perfect hash functions.\n");
84   fprintf (stream, "\n");
85   fprintf (stream,
86            "Usage: %s [OPTION]... [INPUT-FILE]\n",
87            program_name);
88   fprintf (stream, "\n");
89   fprintf (stream,
90            "If a long option shows an argument as mandatory, then it is mandatory\n"
91            "for the equivalent short option also.\n");
92   fprintf (stream, "\n");
93   fprintf (stream,
94            "Output file location:\n");
95   fprintf (stream,
96            "      --output-file=FILE Write output to specified file.\n");
97   fprintf (stream,
98            "The results are written to standard output if no output file is specified\n"
99            "or if it is -.\n");
100   fprintf (stream, "\n");
101   fprintf (stream,
102            "Input file interpretation:\n");
103   fprintf (stream,
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");
108   fprintf (stream,
109            "  -t, --struct-type      Allows the user to include a structured type\n"
110            "                         declaration for generated code. Any text before %%%%\n"
111            "                         is considered part of the type declaration. Key\n"
112            "                         words and additional fields may follow this, one\n"
113            "                         group of fields per line.\n");
114   fprintf (stream,
115            "      --ignore-case      Consider upper and lower case ASCII characters as\n"
116            "                         equivalent. Note that locale dependent case mappings\n"
117            "                         are ignored.\n");
118   fprintf (stream, "\n");
119   fprintf (stream,
120            "Language for the output code:\n");
121   fprintf (stream,
122            "  -L, --language=LANGUAGE-NAME\n"
123            "                         Generates code in the specified language. Languages\n"
124            "                         handled are currently C++, ANSI-C, C, and KR-C. The\n"
125            "                         default is C.\n");
126   fprintf (stream, "\n");
127   fprintf (stream,
128            "Details in the output code:\n");
129   fprintf (stream,
130            "  -K, --slot-name=NAME   Select name of the keyword component in the keyword\n"
131            "                         structure.\n");
132   fprintf (stream,
133            "  -F, --initializer-suffix=INITIALIZERS\n"
134            "                         Initializers for additional components in the keyword\n"
135            "                         structure.\n");
136   fprintf (stream,
137            "  -H, --hash-function-name=NAME\n"
138            "                         Specify name of generated hash function. Default is\n"
139            "                         'hash'.\n");
140   fprintf (stream,
141            "  -N, --lookup-function-name=NAME\n"
142            "                         Specify name of generated lookup function. Default\n"
143            "                         name is 'in_word_set'.\n");
144   fprintf (stream,
145            "  -Z, --class-name=NAME  Specify name of generated C++ class. Default name is\n"
146            "                         'Perfect_Hash'.\n");
147   fprintf (stream,
148            "  -7, --seven-bit        Assume 7-bit characters.\n");
149   fprintf (stream,
150            "  -l, --compare-lengths  Compare key lengths before trying a string\n"
151            "                         comparison. This is necessary if the keywords\n"
152            "                         contain NUL bytes. It also helps cut down on the\n"
153            "                         number of string comparisons made during the lookup.\n");
154   fprintf (stream,
155            "  -c, --compare-strncmp  Generate comparison code using strncmp rather than\n"
156            "                         strcmp.\n");
157   fprintf (stream,
158            "  -C, --readonly-tables  Make the contents of generated lookup tables\n"
159            "                         constant, i.e., readonly.\n");
160   fprintf (stream,
161            "  -E, --enum             Define constant values using an enum local to the\n"
162            "                         lookup function rather than with defines.\n");
163   fprintf (stream,
164            "  -I, --includes         Include the necessary system include file <string.h>\n"
165            "                         at the beginning of the code.\n");
166   fprintf (stream,
167            "  -G, --global-table     Generate the static table of keywords as a static\n"
168            "                         global variable, rather than hiding it inside of the\n"
169            "                         lookup function (which is the default behavior).\n");
170   fprintf (stream,
171            "  -P, --pic              Optimize the generated table for inclusion in shared\n"
172            "                         libraries.  This reduces the startup time of programs\n"
173            "                         using a shared library containing the generated code.\n");
174   fprintf (stream,
175            "  -Q, --string-pool-name=NAME\n"
176            "                         Specify name of string pool generated by option --pic.\n"
177            "                         Default name is 'stringpool'.\n");
178   fprintf (stream,
179            "      --null-strings     Use NULL strings instead of empty strings for empty\n"
180            "                         keyword table entries.\n");
181   fprintf (stream,
182            "  -W, --word-array-name=NAME\n"
183            "                         Specify name of word list array. Default name is\n"
184            "                         'wordlist'.\n");
185   fprintf (stream,
186            "      --length-table-name=NAME\n"
187            "                         Specify name of length table array. Default name is\n"
188            "                         'lengthtable'.\n");
189   fprintf (stream,
190            "  -S, --switch=COUNT     Causes the generated C code to use a switch\n"
191            "                         statement scheme, rather than an array lookup table.\n"
192            "                         This can lead to a reduction in both time and space\n"
193            "                         requirements for some keyfiles. The COUNT argument\n"
194            "                         determines how many switch statements are generated.\n"
195            "                         A value of 1 generates 1 switch containing all the\n"
196            "                         elements, a value of 2 generates 2 tables with 1/2\n"
197            "                         the elements in each table, etc. If COUNT is very\n"
198            "                         large, say 1000000, the generated C code does a\n"
199            "                         binary search.\n");
200   fprintf (stream,
201            "  -T, --omit-struct-type\n"
202            "                         Prevents the transfer of the type declaration to the\n"
203            "                         output file. Use this option if the type is already\n"
204            "                         defined elsewhere.\n");
205   fprintf (stream, "\n");
206   fprintf (stream,
207            "Algorithm employed by gperf:\n");
208   fprintf (stream,
209            "  -k, --key-positions=KEYS\n"
210            "                         Select the key positions used in the hash function.\n"
211            "                         The allowable choices range between 1-%d, inclusive.\n"
212            "                         The positions are separated by commas, ranges may be\n"
213            "                         used, and key positions may occur in any order.\n"
214            "                         Also, the meta-character '*' causes the generated\n"
215            "                         hash function to consider ALL key positions, and $\n"
216            "                         indicates the \"final character\" of a key, e.g.,\n"
217            "                         $,1,2,4,6-10.\n",
218            Positions::MAX_KEY_POS);
219   fprintf (stream,
220            "  -D, --duplicates       Handle keywords that hash to duplicate values. This\n"
221            "                         is useful for certain highly redundant keyword sets.\n");
222   fprintf (stream,
223            "  -m, --multiple-iterations=ITERATIONS\n"
224            "                         Perform multiple choices of the -i and -j values,\n"
225            "                         and choose the best results. This increases the\n"
226            "                         running time by a factor of ITERATIONS but does a\n"
227            "                         good job minimizing the generated table size.\n");
228   fprintf (stream,
229            "  -i, --initial-asso=N   Provide an initial value for the associate values\n"
230            "                         array. Default is 0. Setting this value larger helps\n"
231            "                         inflate the size of the final table.\n");
232   fprintf (stream,
233            "  -j, --jump=JUMP-VALUE  Affects the \"jump value\", i.e., how far to advance\n"
234            "                         the associated character value upon collisions. Must\n"
235            "                         be an odd number, default is %d.\n",
236            DEFAULT_JUMP_VALUE);
237   fprintf (stream,
238            "  -n, --no-strlen        Do not include the length of the keyword when\n"
239            "                         computing the hash function.\n");
240   fprintf (stream,
241            "  -r, --random           Utilizes randomness to initialize the associated\n"
242            "                         values table.\n");
243   fprintf (stream,
244            "  -s, --size-multiple=N  Affects the size of the generated hash table. The\n"
245            "                         numeric argument N indicates \"how many times larger\n"
246            "                         or smaller\" the associated value range should be,\n"
247            "                         in relationship to the number of keys, e.g. a value\n"
248            "                         of 3 means \"allow the maximum associated value to\n"
249            "                         be about 3 times larger than the number of input\n"
250            "                         keys\". Conversely, a value of 1/3 means \"make the\n"
251            "                         maximum associated value about 3 times smaller than\n"
252            "                         the number of input keys\". A larger table should\n"
253            "                         decrease the time required for an unsuccessful\n"
254            "                         search, at the expense of extra table space. Default\n"
255            "                         value is 1.\n");
256   fprintf (stream, "\n");
257   fprintf (stream,
258            "Informative output:\n"
259            "  -h, --help             Print this message.\n"
260            "  -v, --version          Print the gperf version number.\n"
261            "  -d, --debug            Enables the debugging option (produces verbose\n"
262            "                         output to the standard error).\n");
263   fprintf (stream, "\n");
264   fprintf (stream,
265            "Report bugs to <bug-gnu-gperf@gnu.org>.\n");
266 }
267
268 /* Prints the given options.  */
269
270 void
271 Options::print_options () const
272 {
273   printf ("/* Command-line: ");
274
275   for (int i = 0; i < _argument_count; i++)
276     {
277       const char *arg = _argument_vector[i];
278
279       /* Escape arg if it contains shell metacharacters.  */
280       if (*arg == '-')
281         {
282           putchar (*arg);
283           arg++;
284           if (*arg >= 'A' && *arg <= 'Z' || *arg >= 'a' && *arg <= 'z')
285             {
286               putchar (*arg);
287               arg++;
288             }
289           else if (*arg == '-')
290             {
291               do
292                 {
293                   putchar (*arg);
294                   arg++;
295                 }
296               while (*arg >= 'A' && *arg <= 'Z' || *arg >= 'a' && *arg <= 'z' || *arg == '-');
297               if (*arg == '=')
298                 {
299                   putchar (*arg);
300                   arg++;
301                 }
302             }
303         }
304       if (strpbrk (arg, "\t\n !\"#$&'()*;<>?[\\]`{|}~") != NULL)
305         {
306           if (strchr (arg, '\'') != NULL)
307             {
308               putchar ('"');
309               for (; *arg; arg++)
310                 {
311                   if (*arg == '\"' || *arg == '\\' || *arg == '$' || *arg == '`')
312                     putchar ('\\');
313                   putchar (*arg);
314                 }
315               putchar ('"');
316             }
317           else
318             {
319               putchar ('\'');
320               for (; *arg; arg++)
321                 {
322                   if (*arg == '\\')
323                     putchar ('\\');
324                   putchar (*arg);
325                 }
326               putchar ('\'');
327             }
328         }
329       else
330         printf ("%s", arg);
331
332       printf (" ");
333     }
334
335   printf (" */");
336 }
337
338 /* ------------------------------------------------------------------------- */
339
340 /* Parses a string denoting key positions.  */
341
342 class PositionStringParser
343 {
344 public:
345   /* Initializes a key position string parser for string STR.  */
346                         PositionStringParser (const char *str,
347                                               int low_bound, int high_bound,
348                                               int end_word_marker, int error_value, int end_marker);
349   /* Returns the next key position from the given string.  */
350   int                   nextPosition ();
351 private:
352   /* A pointer to the string provided by the user.  */
353   const char *          _str;
354   /* Smallest possible value, inclusive.  */
355   int const             _low_bound;
356   /* Greatest possible value, inclusive.  */
357   int const             _high_bound;
358   /* A value marking the abstract "end of word" ( usually '$').  */
359   int const             _end_word_marker;
360   /* Error value returned when input is syntactically erroneous.  */
361   int const             _error_value;
362   /* Value returned after last key is processed.  */
363   int const             _end_marker;
364   /* Intermediate state for producing a range of positions.  */
365   bool                  _in_range;           /* True while producing a range of positions.  */
366   int                   _range_upper_bound;  /* Upper bound (inclusive) of the range.  */
367   int                   _range_curr_value;   /* Last value returned.  */
368 };
369
370 /* Initializes a key position strng parser for string STR.  */
371 PositionStringParser::PositionStringParser (const char *str,
372                                             int low_bound, int high_bound,
373                                             int end_word_marker, int error_value, int end_marker)
374   : _str (str),
375     _low_bound (low_bound),
376     _high_bound (high_bound),
377     _end_word_marker (end_word_marker),
378     _error_value (error_value),
379     _end_marker (end_marker),
380     _in_range (false)
381 {
382 }
383
384 /* Returns the next key position from the given string.  */
385 int
386 PositionStringParser::nextPosition ()
387 {
388   if (_in_range)
389     {
390       /* We are inside a range.  Return the next value from the range.  */
391       if (++_range_curr_value >= _range_upper_bound)
392         _in_range = false;
393       return _range_curr_value;
394     }
395   else
396     {
397       /* Continue parsing the given string.  */
398       while (*_str)
399         switch (*_str)
400           {
401           case ',':
402             /* Skip the comma.  */
403             _str++;
404             break;
405           case '$':
406             /* Valid key position.  */
407             _str++;
408             return _end_word_marker;
409           case '0': case '1': case '2': case '3': case '4':
410           case '5': case '6': case '7': case '8': case '9':
411             /* Valid key position.  */
412             {
413               int curr_value;
414               for (curr_value = 0; isdigit (static_cast<unsigned char>(*_str)); _str++)
415                 curr_value = curr_value * 10 + (*_str - '0');
416
417               if (*_str == '-')
418                 {
419                   _str++;
420                   /* Starting a range of key positions.  */
421                   _in_range = true;
422
423                   for (_range_upper_bound = 0;
424                        isdigit (static_cast<unsigned char>(*_str));
425                        _str++)
426                     _range_upper_bound = _range_upper_bound * 10 + (*_str - '0');
427
428                   /* Verify range's upper bound.  */
429                   if (!(_range_upper_bound > curr_value && _range_upper_bound <= _high_bound))
430                     return _error_value;
431                   _range_curr_value = curr_value;
432                 }
433
434               /* Verify range's lower bound.  */
435               if (!(curr_value >= _low_bound && curr_value <= _high_bound))
436                 return _error_value;
437               return curr_value;
438             }
439           default:
440             /* Invalid syntax.  */
441             return _error_value;
442           }
443
444       return _end_marker;
445     }
446 }
447
448 /* ------------------------------------------------------------------------- */
449
450 /* Sets the default Options.  */
451
452 Options::Options ()
453   : _option_word (C),
454     _input_file_name (NULL),
455     _output_file_name (NULL),
456     _language (NULL),
457     _jump (DEFAULT_JUMP_VALUE),
458     _initial_asso_value (0),
459     _asso_iterations (0),
460     _total_switches (1),
461     _size_multiple (1),
462     _function_name (DEFAULT_FUNCTION_NAME),
463     _slot_name (DEFAULT_SLOT_NAME),
464     _initializer_suffix (DEFAULT_INITIALIZER_SUFFIX),
465     _class_name (DEFAULT_CLASS_NAME),
466     _hash_name (DEFAULT_HASH_NAME),
467     _wordlist_name (DEFAULT_WORDLIST_NAME),
468     _lengthtable_name (DEFAULT_LENGTHTABLE_NAME),
469     _stringpool_name (DEFAULT_STRINGPOOL_NAME),
470     _delimiters (DEFAULT_DELIMITERS),
471     _key_positions ()
472 {
473 }
474
475 /* Dumps option status when debugging is enabled.  */
476
477 Options::~Options ()
478 {
479   if (_option_word & DEBUG)
480     {
481       fprintf (stderr, "\ndumping Options:"
482                "\nTYPE is........: %s"
483                "\nUPPERLOWER is..: %s"
484                "\nKRC is.........: %s"
485                "\nC is...........: %s"
486                "\nANSIC is.......: %s"
487                "\nCPLUSPLUS is...: %s"
488                "\nSEVENBIT is....: %s"
489                "\nLENTABLE is....: %s"
490                "\nCOMP is........: %s"
491                "\nCONST is.......: %s"
492                "\nENUM is........: %s"
493                "\nINCLUDE is.....: %s"
494                "\nGLOBAL is......: %s"
495                "\nNULLSTRINGS is.: %s"
496                "\nSHAREDLIB is...: %s"
497                "\nSWITCH is......: %s"
498                "\nNOTYPE is......: %s"
499                "\nDUP is.........: %s"
500                "\nNOLENGTH is....: %s"
501                "\nRANDOM is......: %s"
502                "\nDEBUG is.......: %s"
503                "\nlookup function name = %s"
504                "\nhash function name = %s"
505                "\nword list name = %s"
506                "\nlength table name = %s"
507                "\nstring pool name = %s"
508                "\nslot name = %s"
509                "\ninitializer suffix = %s"
510                "\nasso_values iterations = %d"
511                "\njump value = %d"
512                "\nhash table size multiplier = %g"
513                "\ninitial associated value = %d"
514                "\ndelimiters = %s"
515                "\nnumber of switch statements = %d\n",
516                _option_word & TYPE ? "enabled" : "disabled",
517                _option_word & UPPERLOWER ? "enabled" : "disabled",
518                _option_word & KRC ? "enabled" : "disabled",
519                _option_word & C ? "enabled" : "disabled",
520                _option_word & ANSIC ? "enabled" : "disabled",
521                _option_word & CPLUSPLUS ? "enabled" : "disabled",
522                _option_word & SEVENBIT ? "enabled" : "disabled",
523                _option_word & LENTABLE ? "enabled" : "disabled",
524                _option_word & COMP ? "enabled" : "disabled",
525                _option_word & CONST ? "enabled" : "disabled",
526                _option_word & ENUM ? "enabled" : "disabled",
527                _option_word & INCLUDE ? "enabled" : "disabled",
528                _option_word & GLOBAL ? "enabled" : "disabled",
529                _option_word & NULLSTRINGS ? "enabled" : "disabled",
530                _option_word & SHAREDLIB ? "enabled" : "disabled",
531                _option_word & SWITCH ? "enabled" : "disabled",
532                _option_word & NOTYPE ? "enabled" : "disabled",
533                _option_word & DUP ? "enabled" : "disabled",
534                _option_word & NOLENGTH ? "enabled" : "disabled",
535                _option_word & RANDOM ? "enabled" : "disabled",
536                _option_word & DEBUG ? "enabled" : "disabled",
537                _function_name, _hash_name, _wordlist_name, _lengthtable_name,
538                _stringpool_name, _slot_name, _initializer_suffix,
539                _asso_iterations, _jump, _size_multiple, _initial_asso_value,
540                _delimiters, _total_switches);
541       if (_key_positions.is_useall())
542         fprintf (stderr, "all characters are used in the hash function\n");
543       else
544         {
545           fprintf (stderr, "maximum keysig size = %d\nkey positions are: \n",
546                    _key_positions.get_size());
547
548           PositionIterator iter = _key_positions.iterator();
549           for (int pos; (pos = iter.next()) != PositionIterator::EOS; )
550             if (pos == Positions::LASTCHAR)
551               fprintf (stderr, "$\n");
552             else
553               fprintf (stderr, "%d\n", pos + 1);
554         }
555
556       fprintf (stderr, "finished dumping Options\n");
557     }
558 }
559
560
561 /* Sets the output language, if not already set.  */
562 void
563 Options::set_language (const char *language)
564 {
565   if (_language == NULL)
566     {
567       _language = language;
568       _option_word &= ~(KRC | C | ANSIC | CPLUSPLUS);
569       if (!strcmp (language, "KR-C"))
570         _option_word |= KRC;
571       else if (!strcmp (language, "C"))
572         _option_word |= C;
573       else if (!strcmp (language, "ANSI-C"))
574         _option_word |= ANSIC;
575       else if (!strcmp (language, "C++"))
576         _option_word |= CPLUSPLUS;
577       else
578         {
579           fprintf (stderr, "unsupported language option %s, defaulting to C\n",
580                    language);
581           _option_word |= C;
582         }
583     }
584 }
585
586 /* Sets the total number of switch statements, if not already set.  */
587 void
588 Options::set_total_switches (int total_switches)
589 {
590   if (!(_option_word & SWITCH))
591     {
592       _option_word |= SWITCH;
593       _total_switches = total_switches;
594     }
595 }
596
597 /* Sets the generated function name, if not already set.  */
598 void
599 Options::set_function_name (const char *name)
600 {
601   if (_function_name == DEFAULT_FUNCTION_NAME)
602     _function_name = name;
603 }
604
605 /* Sets the keyword key name, if not already set.  */
606 void
607 Options::set_slot_name (const char *name)
608 {
609   if (_slot_name == DEFAULT_SLOT_NAME)
610     _slot_name = name;
611 }
612
613 /* Sets the struct initializer suffix, if not already set.  */
614 void
615 Options::set_initializer_suffix (const char *initializers)
616 {
617   if (_initializer_suffix == DEFAULT_INITIALIZER_SUFFIX)
618     _initializer_suffix = initializers;
619 }
620
621 /* Sets the generated class name, if not already set.  */
622 void
623 Options::set_class_name (const char *name)
624 {
625   if (_class_name == DEFAULT_CLASS_NAME)
626     _class_name = name;
627 }
628
629 /* Sets the hash function name, if not already set.  */
630 void
631 Options::set_hash_name (const char *name)
632 {
633   if (_hash_name == DEFAULT_HASH_NAME)
634     _hash_name = name;
635 }
636
637 /* Sets the hash table array name, if not already set.  */
638 void
639 Options::set_wordlist_name (const char *name)
640 {
641   if (_wordlist_name == DEFAULT_WORDLIST_NAME)
642     _wordlist_name = name;
643 }
644
645 /* Sets the length table array name, if not already set.  */
646 void
647 Options::set_lengthtable_name (const char *name)
648 {
649   if (_lengthtable_name == DEFAULT_LENGTHTABLE_NAME)
650     _lengthtable_name = name;
651 }
652
653 /* Sets the string pool name, if not already set.  */
654 void
655 Options::set_stringpool_name (const char *name)
656 {
657   if (_stringpool_name == DEFAULT_STRINGPOOL_NAME)
658     _stringpool_name = name;
659 }
660
661 /* Sets the delimiters string, if not already set.  */
662 void
663 Options::set_delimiters (const char *delimiters)
664 {
665   if (_delimiters == DEFAULT_DELIMITERS)
666     _delimiters = delimiters;
667 }
668
669
670 /* Parses the command line Options and sets appropriate flags in option_word.  */
671
672 static const struct option long_options[] =
673 {
674   { "output-file", required_argument, NULL, CHAR_MAX + 1 },
675   { "ignore-case", no_argument, NULL, CHAR_MAX + 2 },
676   { "delimiters", required_argument, NULL, 'e' },
677   { "struct-type", no_argument, NULL, 't' },
678   { "language", required_argument, NULL, 'L' },
679   { "slot-name", required_argument, NULL, 'K' },
680   { "initializer-suffix", required_argument, NULL, 'F' },
681   { "hash-fn-name", required_argument, NULL, 'H' }, /* backward compatibility */
682   { "hash-function-name", required_argument, NULL, 'H' },
683   { "lookup-fn-name", required_argument, NULL, 'N' }, /* backward compatibility */
684   { "lookup-function-name", required_argument, NULL, 'N' },
685   { "class-name", required_argument, NULL, 'Z' },
686   { "seven-bit", no_argument, NULL, '7' },
687   { "compare-strncmp", no_argument, NULL, 'c' },
688   { "readonly-tables", no_argument, NULL, 'C' },
689   { "enum", no_argument, NULL, 'E' },
690   { "includes", no_argument, NULL, 'I' },
691   { "global-table", no_argument, NULL, 'G' },
692   { "word-array-name", required_argument, NULL, 'W' },
693   { "length-table-name", required_argument, NULL, CHAR_MAX + 4 },
694   { "switch", required_argument, NULL, 'S' },
695   { "omit-struct-type", no_argument, NULL, 'T' },
696   { "key-positions", required_argument, NULL, 'k' },
697   { "compare-strlen", no_argument, NULL, 'l' }, /* backward compatibility */
698   { "compare-lengths", no_argument, NULL, 'l' },
699   { "duplicates", no_argument, NULL, 'D' },
700   { "fast", required_argument, NULL, 'f' },
701   { "initial-asso", required_argument, NULL, 'i' },
702   { "jump", required_argument, NULL, 'j' },
703   { "multiple-iterations", required_argument, NULL, 'm' },
704   { "no-strlen", no_argument, NULL, 'n' },
705   { "occurrence-sort", no_argument, NULL, 'o' },
706   { "optimized-collision-resolution", no_argument, NULL, 'O' },
707   { "pic", no_argument, NULL, 'P' },
708   { "string-pool-name", required_argument, NULL, 'Q' },
709   { "null-strings", no_argument, NULL, CHAR_MAX + 3 },
710   { "random", no_argument, NULL, 'r' },
711   { "size-multiple", required_argument, NULL, 's' },
712   { "help", no_argument, NULL, 'h' },
713   { "version", no_argument, NULL, 'v' },
714   { "debug", no_argument, NULL, 'd' },
715   { NULL, no_argument, NULL, 0 }
716 };
717
718 void
719 Options::parse_options (int argc, char *argv[])
720 {
721   int option_char;
722
723   program_name = argv[0];
724   _argument_count  = argc;
725   _argument_vector = argv;
726
727   while ((option_char =
728             getopt_long (_argument_count, _argument_vector,
729                          "acCdDe:Ef:F:gGhH:i:Ij:k:K:lL:m:nN:oOpPQ:rs:S:tTvW:Z:7",
730                          long_options, NULL))
731          != -1)
732     {
733       switch (option_char)
734         {
735         case 'a':               /* Generated code uses the ANSI prototype format.  */
736           break;                /* This is now the default.  */
737         case 'c':               /* Generate strncmp rather than strcmp.  */
738           {
739             _option_word |= COMP;
740             break;
741           }
742         case 'C':               /* Make the generated tables readonly (const).  */
743           {
744             _option_word |= CONST;
745             break;
746           }
747         case 'd':               /* Enable debugging option.  */
748           {
749             _option_word |= DEBUG;
750             fprintf (stderr, "Starting program %s, version %s, with debugging on.\n",
751                              program_name, version_string);
752             break;
753           }
754         case 'D':               /* Enable duplicate option.  */
755           {
756             _option_word |= DUP;
757             break;
758           }
759         case 'e':               /* Specify keyword/attribute separator */
760           {
761             _delimiters = /*getopt*/optarg;
762             break;
763           }
764         case 'E':
765           {
766             _option_word |= ENUM;
767             break;
768           }
769         case 'f':               /* Generate the hash table "fast".  */
770           break;                /* Not needed any more.  */
771         case 'F':
772           {
773             _initializer_suffix = /*getopt*/optarg;
774             break;
775           }
776         case 'g':               /* Use the 'inline' keyword for generated sub-routines, ifdef __GNUC__.  */
777           break;                /* This is now the default.  */
778         case 'G':               /* Make the keyword table a global variable.  */
779           {
780             _option_word |= GLOBAL;
781             break;
782           }
783         case 'h':               /* Displays a list of helpful Options to the user.  */
784           {
785             long_usage (stdout);
786             exit (0);
787           }
788         case 'H':               /* Sets the name for the hash function.  */
789           {
790             _hash_name = /*getopt*/optarg;
791             break;
792           }
793         case 'i':               /* Sets the initial value for the associated values array.  */
794           {
795             if ((_initial_asso_value = atoi (/*getopt*/optarg)) < 0)
796               fprintf (stderr, "Initial value %d should be non-zero, ignoring and continuing.\n", _initial_asso_value);
797             if (option[RANDOM])
798               fprintf (stderr, "warning, -r option superceeds -i, ignoring -i option and continuing\n");
799             break;
800           }
801         case 'I':               /* Enable #include statements.  */
802           {
803             _option_word |= INCLUDE;
804             break;
805           }
806         case 'j':               /* Sets the jump value, must be odd for later algorithms.  */
807           {
808             if ((_jump = atoi (/*getopt*/optarg)) < 0)
809               {
810                 fprintf (stderr, "Jump value %d must be a positive number.\n", _jump);
811                 short_usage (stderr);
812                 exit (1);
813               }
814             else if (_jump && ((_jump % 2) == 0))
815               fprintf (stderr, "Jump value %d should be odd, adding 1 and continuing...\n", _jump++);
816             break;
817           }
818         case 'k':               /* Sets key positions used for hash function.  */
819           {
820             _option_word |= POSITIONS;
821             const int BAD_VALUE = -3;
822             const int EOS = PositionIterator::EOS;
823             int       value;
824             PositionStringParser sparser (/*getopt*/optarg, 1, Positions::MAX_KEY_POS, Positions::LASTCHAR, BAD_VALUE, EOS);
825
826             if (/*getopt*/optarg [0] == '*') /* Use all the characters for hashing!!!! */
827               _key_positions.set_useall(true);
828             else
829               {
830                 _key_positions.set_useall(false);
831                 int *key_positions = _key_positions.pointer();
832                 int *key_pos;
833
834                 for (key_pos = key_positions; (value = sparser.nextPosition()) != EOS; key_pos++)
835                   {
836                     if (value == BAD_VALUE)
837                       {
838                         fprintf (stderr, "Invalid position value or range, use 1,2,3-%d,'$' or '*'.\n",
839                                          Positions::MAX_KEY_POS);
840                         short_usage (stderr);
841                         exit (1);
842                       }
843                     if (key_pos - key_positions == Positions::MAX_SIZE)
844                       {
845                         /* More than Positions::MAX_SIZE key positions.
846                            Since all key positions are in the range
847                            0..Positions::MAX_KEY_POS-1 or == Positions::LASTCHAR,
848                            there must be duplicates.  */
849                         fprintf (stderr, "Duplicate key positions selected\n");
850                         short_usage (stderr);
851                         exit (1);
852                       }
853                     if (value != Positions::LASTCHAR)
854                       /* We use 0-based indices in the class Positions.  */
855                       value = value - 1;
856                     *key_pos = value;
857                   }
858
859                 unsigned int total_keysig_size = key_pos - key_positions;
860                 if (total_keysig_size == 0)
861                   {
862                     fprintf (stderr, "No key positions selected.\n");
863                     short_usage (stderr);
864                     exit (1);
865                   }
866                 _key_positions.set_size (total_keysig_size);
867
868                 /* Sorts the key positions *IN REVERSE ORDER!!*
869                    This makes further routines more efficient.  Especially
870                    when generating code.  */
871                 if (! _key_positions.sort())
872                   {
873                     fprintf (stderr, "Duplicate key positions selected\n");
874                     short_usage (stderr);
875                     exit (1);
876                   }
877               }
878             break;
879           }
880         case 'K':               /* Make this the keyname for the keyword component field.  */
881           {
882             _slot_name = /*getopt*/optarg;
883             break;
884           }
885         case 'l':               /* Create length table to avoid extra string compares.  */
886           {
887             _option_word |= LENTABLE;
888             break;
889           }
890         case 'L':               /* Deal with different generated languages.  */
891           {
892             _language = NULL;
893             set_language (/*getopt*/optarg);
894             break;
895           }
896         case 'm':               /* Multiple iterations for finding good asso_values.  */
897           {
898             if ((_asso_iterations = atoi (/*getopt*/optarg)) < 0)
899               {
900                 fprintf (stderr, "asso_iterations value must not be negative, assuming 0\n");
901                 _asso_iterations = 0;
902               }
903             break;
904           }
905         case 'n':               /* Don't include the length when computing hash function.  */
906           {
907             _option_word |= NOLENGTH;
908             break;
909           }
910         case 'N':               /* Make generated lookup function name be optarg.  */
911           {
912             _function_name = /*getopt*/optarg;
913             break;
914           }
915         case 'o':               /* Order input by frequency of key set occurrence.  */
916           break;                /* Not needed any more.  */
917         case 'O':               /* Optimized choice during collision resolution.  */
918           break;                /* Not needed any more.  */
919         case 'p':               /* Generated lookup function a pointer instead of int.  */
920           break;                /* This is now the default.  */
921         case 'P':               /* Optimize for position-independent code.  */
922           {
923             _option_word |= SHAREDLIB;
924             break;
925           }
926         case 'Q':               /* Sets the name for the string pool.  */
927           {
928             _stringpool_name = /*getopt*/optarg;
929             break;
930           }
931         case 'r':               /* Utilize randomness to initialize the associated values table.  */
932           {
933             _option_word |= RANDOM;
934             if (_initial_asso_value != 0)
935               fprintf (stderr, "warning, -r option supersedes -i, disabling -i option and continuing\n");
936             break;
937           }
938         case 's':               /* Range of associated values, determines size of final table.  */
939           {
940             float numerator;
941             float denominator = 1;
942             bool invalid = false;
943             char *endptr;
944
945             numerator = strtod (/*getopt*/optarg, &endptr);
946             if (endptr == /*getopt*/optarg)
947               invalid = true;
948             else if (*endptr != '\0')
949               {
950                 if (*endptr == '/')
951                   {
952                     char *denomptr = endptr + 1;
953                     denominator = strtod (denomptr, &endptr);
954                     if (endptr == denomptr || *endptr != '\0')
955                       invalid = true;
956                   }
957                 else
958                   invalid = true;
959               }
960             if (invalid)
961               {
962                 fprintf (stderr, "Invalid value for option -s.\n");
963                 short_usage (stderr);
964                 exit (1);
965               }
966             _size_multiple = numerator / denominator;
967             /* Backward compatibility: -3 means 1/3.  */
968             if (_size_multiple < 0)
969               _size_multiple = 1 / (-_size_multiple);
970             /* Catch stupid users.  */
971             if (_size_multiple == 0)
972               _size_multiple = 1;
973             /* Warnings.  */
974             if (_size_multiple > 50)
975               fprintf (stderr, "Size multiple %g is excessive, did you really mean this?! (try '%s --help' for help)\n", _size_multiple, program_name);
976             else if (_size_multiple < 0.01f)
977               fprintf (stderr, "Size multiple %g is extremely small, did you really mean this?! (try '%s --help' for help)\n", _size_multiple, program_name);
978             break;
979           }
980         case 'S':               /* Generate switch statement output, rather than lookup table.  */
981           {
982             _option_word |= SWITCH;
983             _total_switches = atoi (/*getopt*/optarg);
984             if (_total_switches <= 0)
985               {
986                 fprintf (stderr, "number of switches %s must be a positive number\n", /*getopt*/optarg);
987                 short_usage (stderr);
988                 exit (1);
989               }
990             break;
991           }
992         case 't':               /* Enable the TYPE mode, allowing arbitrary user structures.  */
993           {
994             _option_word |= TYPE;
995             break;
996           }
997         case 'T':               /* Don't print structure definition.  */
998           {
999             _option_word |= NOTYPE;
1000             break;
1001           }
1002         case 'v':               /* Print out the version and quit.  */
1003           fprintf (stdout, "GNU gperf %s\n", version_string);
1004           fprintf (stdout, "Copyright (C) %s Free Software Foundation, Inc.\n\
1005 This is free software; see the source for copying conditions.  There is NO\n\
1006 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
1007 ",
1008                    "1989-1998, 2000-2004, 2006-2007");
1009           fprintf (stdout, "Written by %s and %s.\n",
1010                    "Douglas C. Schmidt", "Bruno Haible");
1011           exit (0);
1012         case 'W':               /* Sets the name for the hash table array.  */
1013           {
1014             _wordlist_name = /*getopt*/optarg;
1015             break;
1016           }
1017         case 'Z':               /* Set the class name.  */
1018           {
1019             _class_name = /*getopt*/optarg;
1020             break;
1021           }
1022         case '7':               /* Assume 7-bit characters.  */
1023           {
1024             _option_word |= SEVENBIT;
1025             break;
1026           }
1027         case CHAR_MAX + 1:      /* Set the output file name.  */
1028           {
1029             _output_file_name = /*getopt*/optarg;
1030             break;
1031           }
1032         case CHAR_MAX + 2:      /* Case insignificant.  */
1033           {
1034             _option_word |= UPPERLOWER;
1035             break;
1036           }
1037         case CHAR_MAX + 3:      /* Use NULL instead of "".  */
1038           {
1039             _option_word |= NULLSTRINGS;
1040             break;
1041           }
1042         case CHAR_MAX + 4:      /* Sets the name for the length table array.  */
1043           {
1044             _lengthtable_name = /*getopt*/optarg;
1045             break;
1046           }
1047         default:
1048           short_usage (stderr);
1049           exit (1);
1050         }
1051
1052     }
1053
1054   if (/*getopt*/optind < argc)
1055     _input_file_name = argv[/*getopt*/optind++];
1056
1057   if (/*getopt*/optind < argc)
1058     {
1059       fprintf (stderr, "Extra trailing arguments to %s.\n", program_name);
1060       short_usage (stderr);
1061       exit (1);
1062     }
1063 }
1064
1065 /* ------------------------------------------------------------------------- */
1066
1067 #ifndef __OPTIMIZE__
1068
1069 #define INLINE /* not inline */
1070 #include "options.icc"
1071 #undef INLINE
1072
1073 #endif /* not defined __OPTIMIZE__ */