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.  */
35Options option;
36
37/* Records the program name.  */
38const char *program_name;
39
40/* Size to jump on a collision.  */
41static const int DEFAULT_JUMP_VALUE = 5;
42
43/* Default name for generated lookup function.  */
44static const char *const DEFAULT_FUNCTION_NAME = "in_word_set";
45
46/* Default name for the key component.  */
47static const char *const DEFAULT_SLOT_NAME = "name";
48
49/* Default struct initializer suffix.  */
50static const char *const DEFAULT_INITIALIZER_SUFFIX = "";
51
52/* Default name for the generated class.  */
53static const char *const DEFAULT_CLASS_NAME = "Perfect_Hash";
54
55/* Default name for generated hash function.  */
56static const char *const DEFAULT_HASH_NAME = "hash";
57
58/* Default name for generated hash table array.  */
59static const char *const DEFAULT_WORDLIST_NAME = "wordlist";
60
61/* Default name for generated length table array.  */
62static const char *const DEFAULT_LENGTHTABLE_NAME = "lengthtable";
63
64/* Default name for string pool.  */
65static const char *const DEFAULT_STRINGPOOL_NAME = "stringpool";
66
67/* Default delimiters that separate keywords from their attributes.  */
68static const char *const DEFAULT_DELIMITERS = ",";
69
70/* Prints program usage to given stream.  */
71
72void
73Options::short_usage (FILE * stream)
74{
75  fprintf (stream,
76           "Try '%s --help' for more information.\n", program_name);
77}
78
79void
80Options::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
270void
271Options::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') ||
297                      (*arg >= 'a' && *arg <= 'z') ||
298                       *arg == '-');
299              if (*arg == '=')
300                {
301                  putchar (*arg);
302                  arg++;
303                }
304            }
305        }
306      if (strpbrk (arg, "\t\n !\"#$&'()*;<>?[\\]`{|}~") != NULL)
307        {
308          if (strchr (arg, '\'') != NULL)
309            {
310              putchar ('"');
311              for (; *arg; arg++)
312                {
313                  if (*arg == '\"' || *arg == '\\' || *arg == '$' || *arg == '`')
314                    putchar ('\\');
315                  putchar (*arg);
316                }
317              putchar ('"');
318            }
319          else
320            {
321              putchar ('\'');
322              for (; *arg; arg++)
323                {
324                  if (*arg == '\\')
325                    putchar ('\\');
326                  putchar (*arg);
327                }
328              putchar ('\'');
329            }
330        }
331      else
332        printf ("%s", arg);
333
334      printf (" ");
335    }
336
337  printf (" */");
338}
339
340/* ------------------------------------------------------------------------- */
341
342/* Parses a string denoting key positions.  */
343
344class PositionStringParser
345{
346public:
347  /* Initializes a key position string parser for string STR.  */
348                        PositionStringParser (const char *str,
349                                              int low_bound, int high_bound,
350                                              int end_word_marker, int error_value, int end_marker);
351  /* Returns the next key position from the given string.  */
352  int                   nextPosition ();
353private:
354  /* A pointer to the string provided by the user.  */
355  const char *          _str;
356  /* Smallest possible value, inclusive.  */
357  int const             _low_bound;
358  /* Greatest possible value, inclusive.  */
359  int const             _high_bound;
360  /* A value marking the abstract "end of word" ( usually '$').  */
361  int const             _end_word_marker;
362  /* Error value returned when input is syntactically erroneous.  */
363  int const             _error_value;
364  /* Value returned after last key is processed.  */
365  int const             _end_marker;
366  /* Intermediate state for producing a range of positions.  */
367  bool                  _in_range;           /* True while producing a range of positions.  */
368  int                   _range_upper_bound;  /* Upper bound (inclusive) of the range.  */
369  int                   _range_curr_value;   /* Last value returned.  */
370};
371
372/* Initializes a key position strng parser for string STR.  */
373PositionStringParser::PositionStringParser (const char *str,
374                                            int low_bound, int high_bound,
375                                            int end_word_marker, int error_value, int end_marker)
376  : _str (str),
377    _low_bound (low_bound),
378    _high_bound (high_bound),
379    _end_word_marker (end_word_marker),
380    _error_value (error_value),
381    _end_marker (end_marker),
382    _in_range (false)
383{
384}
385
386/* Returns the next key position from the given string.  */
387int
388PositionStringParser::nextPosition ()
389{
390  if (_in_range)
391    {
392      /* We are inside a range.  Return the next value from the range.  */
393      if (++_range_curr_value >= _range_upper_bound)
394        _in_range = false;
395      return _range_curr_value;
396    }
397  else
398    {
399      /* Continue parsing the given string.  */
400      while (*_str)
401        switch (*_str)
402          {
403          case ',':
404            /* Skip the comma.  */
405            _str++;
406            break;
407          case '$':
408            /* Valid key position.  */
409            _str++;
410            return _end_word_marker;
411          case '0': case '1': case '2': case '3': case '4':
412          case '5': case '6': case '7': case '8': case '9':
413            /* Valid key position.  */
414            {
415              int curr_value;
416              for (curr_value = 0; isdigit (static_cast<unsigned char>(*_str)); _str++)
417                curr_value = curr_value * 10 + (*_str - '0');
418
419              if (*_str == '-')
420                {
421                  _str++;
422                  /* Starting a range of key positions.  */
423                  _in_range = true;
424
425                  for (_range_upper_bound = 0;
426                       isdigit (static_cast<unsigned char>(*_str));
427                       _str++)
428                    _range_upper_bound = _range_upper_bound * 10 + (*_str - '0');
429
430                  /* Verify range's upper bound.  */
431                  if (!(_range_upper_bound > curr_value && _range_upper_bound <= _high_bound))
432                    return _error_value;
433                  _range_curr_value = curr_value;
434                }
435
436              /* Verify range's lower bound.  */
437              if (!(curr_value >= _low_bound && curr_value <= _high_bound))
438                return _error_value;
439              return curr_value;
440            }
441          default:
442            /* Invalid syntax.  */
443            return _error_value;
444          }
445
446      return _end_marker;
447    }
448}
449
450/* ------------------------------------------------------------------------- */
451
452/* Sets the default Options.  */
453
454Options::Options ()
455  : _option_word (C),
456    _input_file_name (NULL),
457    _output_file_name (NULL),
458    _language (NULL),
459    _jump (DEFAULT_JUMP_VALUE),
460    _initial_asso_value (0),
461    _asso_iterations (0),
462    _total_switches (1),
463    _size_multiple (1),
464    _function_name (DEFAULT_FUNCTION_NAME),
465    _slot_name (DEFAULT_SLOT_NAME),
466    _initializer_suffix (DEFAULT_INITIALIZER_SUFFIX),
467    _class_name (DEFAULT_CLASS_NAME),
468    _hash_name (DEFAULT_HASH_NAME),
469    _wordlist_name (DEFAULT_WORDLIST_NAME),
470    _lengthtable_name (DEFAULT_LENGTHTABLE_NAME),
471    _stringpool_name (DEFAULT_STRINGPOOL_NAME),
472    _delimiters (DEFAULT_DELIMITERS),
473    _key_positions ()
474{
475}
476
477/* Dumps option status when debugging is enabled.  */
478
479Options::~Options ()
480{
481  if (_option_word & DEBUG)
482    {
483      fprintf (stderr, "\ndumping Options:"
484               "\nTYPE is........: %s"
485               "\nUPPERLOWER is..: %s"
486               "\nKRC is.........: %s"
487               "\nC is...........: %s"
488               "\nANSIC is.......: %s"
489               "\nCPLUSPLUS is...: %s"
490               "\nSEVENBIT is....: %s"
491               "\nLENTABLE is....: %s"
492               "\nCOMP is........: %s"
493               "\nCONST is.......: %s"
494               "\nENUM is........: %s"
495               "\nINCLUDE is.....: %s"
496               "\nGLOBAL is......: %s"
497               "\nNULLSTRINGS is.: %s"
498               "\nSHAREDLIB is...: %s"
499               "\nSWITCH is......: %s"
500               "\nNOTYPE is......: %s"
501               "\nDUP is.........: %s"
502               "\nNOLENGTH is....: %s"
503               "\nRANDOM is......: %s"
504               "\nDEBUG is.......: %s"
505               "\nlookup function name = %s"
506               "\nhash function name = %s"
507               "\nword list name = %s"
508               "\nlength table name = %s"
509               "\nstring pool name = %s"
510               "\nslot name = %s"
511               "\ninitializer suffix = %s"
512               "\nasso_values iterations = %d"
513               "\njump value = %d"
514               "\nhash table size multiplier = %g"
515               "\ninitial associated value = %d"
516               "\ndelimiters = %s"
517               "\nnumber of switch statements = %d\n",
518               _option_word & TYPE ? "enabled" : "disabled",
519               _option_word & UPPERLOWER ? "enabled" : "disabled",
520               _option_word & KRC ? "enabled" : "disabled",
521               _option_word & C ? "enabled" : "disabled",
522               _option_word & ANSIC ? "enabled" : "disabled",
523               _option_word & CPLUSPLUS ? "enabled" : "disabled",
524               _option_word & SEVENBIT ? "enabled" : "disabled",
525               _option_word & LENTABLE ? "enabled" : "disabled",
526               _option_word & COMP ? "enabled" : "disabled",
527               _option_word & CONST ? "enabled" : "disabled",
528               _option_word & ENUM ? "enabled" : "disabled",
529               _option_word & INCLUDE ? "enabled" : "disabled",
530               _option_word & GLOBAL ? "enabled" : "disabled",
531               _option_word & NULLSTRINGS ? "enabled" : "disabled",
532               _option_word & SHAREDLIB ? "enabled" : "disabled",
533               _option_word & SWITCH ? "enabled" : "disabled",
534               _option_word & NOTYPE ? "enabled" : "disabled",
535               _option_word & DUP ? "enabled" : "disabled",
536               _option_word & NOLENGTH ? "enabled" : "disabled",
537               _option_word & RANDOM ? "enabled" : "disabled",
538               _option_word & DEBUG ? "enabled" : "disabled",
539               _function_name, _hash_name, _wordlist_name, _lengthtable_name,
540               _stringpool_name, _slot_name, _initializer_suffix,
541               _asso_iterations, _jump, _size_multiple, _initial_asso_value,
542               _delimiters, _total_switches);
543      if (_key_positions.is_useall())
544        fprintf (stderr, "all characters are used in the hash function\n");
545      else
546        {
547          fprintf (stderr, "maximum keysig size = %d\nkey positions are: \n",
548                   _key_positions.get_size());
549
550          PositionIterator iter = _key_positions.iterator();
551          for (int pos; (pos = iter.next()) != PositionIterator::EOS; )
552            if (pos == Positions::LASTCHAR)
553              fprintf (stderr, "$\n");
554            else
555              fprintf (stderr, "%d\n", pos + 1);
556        }
557
558      fprintf (stderr, "finished dumping Options\n");
559    }
560}
561
562
563/* Sets the output language, if not already set.  */
564void
565Options::set_language (const char *language)
566{
567  if (_language == NULL)
568    {
569      _language = language;
570      _option_word &= ~(KRC | C | ANSIC | CPLUSPLUS);
571      if (!strcmp (language, "KR-C"))
572        _option_word |= KRC;
573      else if (!strcmp (language, "C"))
574        _option_word |= C;
575      else if (!strcmp (language, "ANSI-C"))
576        _option_word |= ANSIC;
577      else if (!strcmp (language, "C++"))
578        _option_word |= CPLUSPLUS;
579      else
580        {
581          fprintf (stderr, "unsupported language option %s, defaulting to C\n",
582                   language);
583          _option_word |= C;
584        }
585    }
586}
587
588/* Sets the total number of switch statements, if not already set.  */
589void
590Options::set_total_switches (int total_switches)
591{
592  if (!(_option_word & SWITCH))
593    {
594      _option_word |= SWITCH;
595      _total_switches = total_switches;
596    }
597}
598
599/* Sets the generated function name, if not already set.  */
600void
601Options::set_function_name (const char *name)
602{
603  if (_function_name == DEFAULT_FUNCTION_NAME)
604    _function_name = name;
605}
606
607/* Sets the keyword key name, if not already set.  */
608void
609Options::set_slot_name (const char *name)
610{
611  if (_slot_name == DEFAULT_SLOT_NAME)
612    _slot_name = name;
613}
614
615/* Sets the struct initializer suffix, if not already set.  */
616void
617Options::set_initializer_suffix (const char *initializers)
618{
619  if (_initializer_suffix == DEFAULT_INITIALIZER_SUFFIX)
620    _initializer_suffix = initializers;
621}
622
623/* Sets the generated class name, if not already set.  */
624void
625Options::set_class_name (const char *name)
626{
627  if (_class_name == DEFAULT_CLASS_NAME)
628    _class_name = name;
629}
630
631/* Sets the hash function name, if not already set.  */
632void
633Options::set_hash_name (const char *name)
634{
635  if (_hash_name == DEFAULT_HASH_NAME)
636    _hash_name = name;
637}
638
639/* Sets the hash table array name, if not already set.  */
640void
641Options::set_wordlist_name (const char *name)
642{
643  if (_wordlist_name == DEFAULT_WORDLIST_NAME)
644    _wordlist_name = name;
645}
646
647/* Sets the length table array name, if not already set.  */
648void
649Options::set_lengthtable_name (const char *name)
650{
651  if (_lengthtable_name == DEFAULT_LENGTHTABLE_NAME)
652    _lengthtable_name = name;
653}
654
655/* Sets the string pool name, if not already set.  */
656void
657Options::set_stringpool_name (const char *name)
658{
659  if (_stringpool_name == DEFAULT_STRINGPOOL_NAME)
660    _stringpool_name = name;
661}
662
663/* Sets the delimiters string, if not already set.  */
664void
665Options::set_delimiters (const char *delimiters)
666{
667  if (_delimiters == DEFAULT_DELIMITERS)
668    _delimiters = delimiters;
669}
670
671
672/* Parses the command line Options and sets appropriate flags in option_word.  */
673
674static const struct option long_options[] =
675{
676  { "output-file", required_argument, NULL, CHAR_MAX + 1 },
677  { "ignore-case", no_argument, NULL, CHAR_MAX + 2 },
678  { "delimiters", required_argument, NULL, 'e' },
679  { "struct-type", no_argument, NULL, 't' },
680  { "language", required_argument, NULL, 'L' },
681  { "slot-name", required_argument, NULL, 'K' },
682  { "initializer-suffix", required_argument, NULL, 'F' },
683  { "hash-fn-name", required_argument, NULL, 'H' }, /* backward compatibility */
684  { "hash-function-name", required_argument, NULL, 'H' },
685  { "lookup-fn-name", required_argument, NULL, 'N' }, /* backward compatibility */
686  { "lookup-function-name", required_argument, NULL, 'N' },
687  { "class-name", required_argument, NULL, 'Z' },
688  { "seven-bit", no_argument, NULL, '7' },
689  { "compare-strncmp", no_argument, NULL, 'c' },
690  { "readonly-tables", no_argument, NULL, 'C' },
691  { "enum", no_argument, NULL, 'E' },
692  { "includes", no_argument, NULL, 'I' },
693  { "global-table", no_argument, NULL, 'G' },
694  { "word-array-name", required_argument, NULL, 'W' },
695  { "length-table-name", required_argument, NULL, CHAR_MAX + 4 },
696  { "switch", required_argument, NULL, 'S' },
697  { "omit-struct-type", no_argument, NULL, 'T' },
698  { "key-positions", required_argument, NULL, 'k' },
699  { "compare-strlen", no_argument, NULL, 'l' }, /* backward compatibility */
700  { "compare-lengths", no_argument, NULL, 'l' },
701  { "duplicates", no_argument, NULL, 'D' },
702  { "fast", required_argument, NULL, 'f' },
703  { "initial-asso", required_argument, NULL, 'i' },
704  { "jump", required_argument, NULL, 'j' },
705  { "multiple-iterations", required_argument, NULL, 'm' },
706  { "no-strlen", no_argument, NULL, 'n' },
707  { "occurrence-sort", no_argument, NULL, 'o' },
708  { "optimized-collision-resolution", no_argument, NULL, 'O' },
709  { "pic", no_argument, NULL, 'P' },
710  { "string-pool-name", required_argument, NULL, 'Q' },
711  { "null-strings", no_argument, NULL, CHAR_MAX + 3 },
712  { "random", no_argument, NULL, 'r' },
713  { "size-multiple", required_argument, NULL, 's' },
714  { "help", no_argument, NULL, 'h' },
715  { "version", no_argument, NULL, 'v' },
716  { "debug", no_argument, NULL, 'd' },
717  { NULL, no_argument, NULL, 0 }
718};
719
720void
721Options::parse_options (int argc, char *argv[])
722{
723  int option_char;
724
725  program_name = argv[0];
726  _argument_count  = argc;
727  _argument_vector = argv;
728
729  while ((option_char =
730            getopt_long (_argument_count, _argument_vector,
731                         "acCdDe:Ef:F:gGhH:i:Ij:k:K:lL:m:nN:oOpPQ:rs:S:tTvW:Z:7",
732                         long_options, NULL))
733         != -1)
734    {
735      switch (option_char)
736        {
737        case 'a':               /* Generated code uses the ANSI prototype format.  */
738          break;                /* This is now the default.  */
739        case 'c':               /* Generate strncmp rather than strcmp.  */
740          {
741            _option_word |= COMP;
742            break;
743          }
744        case 'C':               /* Make the generated tables readonly (const).  */
745          {
746            _option_word |= CONST;
747            break;
748          }
749        case 'd':               /* Enable debugging option.  */
750          {
751            _option_word |= DEBUG;
752            fprintf (stderr, "Starting program %s, version %s, with debugging on.\n",
753                             program_name, version_string);
754            break;
755          }
756        case 'D':               /* Enable duplicate option.  */
757          {
758            _option_word |= DUP;
759            break;
760          }
761        case 'e':               /* Specify keyword/attribute separator */
762          {
763            _delimiters = /*getopt*/optarg;
764            break;
765          }
766        case 'E':
767          {
768            _option_word |= ENUM;
769            break;
770          }
771        case 'f':               /* Generate the hash table "fast".  */
772          break;                /* Not needed any more.  */
773        case 'F':
774          {
775            _initializer_suffix = /*getopt*/optarg;
776            break;
777          }
778        case 'g':               /* Use the 'inline' keyword for generated sub-routines, ifdef __GNUC__.  */
779          break;                /* This is now the default.  */
780        case 'G':               /* Make the keyword table a global variable.  */
781          {
782            _option_word |= GLOBAL;
783            break;
784          }
785        case 'h':               /* Displays a list of helpful Options to the user.  */
786          {
787            long_usage (stdout);
788            exit (0);
789          }
790        case 'H':               /* Sets the name for the hash function.  */
791          {
792            _hash_name = /*getopt*/optarg;
793            break;
794          }
795        case 'i':               /* Sets the initial value for the associated values array.  */
796          {
797            if ((_initial_asso_value = atoi (/*getopt*/optarg)) < 0)
798              fprintf (stderr, "Initial value %d should be non-zero, ignoring and continuing.\n", _initial_asso_value);
799            if (option[RANDOM])
800              fprintf (stderr, "warning, -r option superceeds -i, ignoring -i option and continuing\n");
801            break;
802          }
803        case 'I':               /* Enable #include statements.  */
804          {
805            _option_word |= INCLUDE;
806            break;
807          }
808        case 'j':               /* Sets the jump value, must be odd for later algorithms.  */
809          {
810            if ((_jump = atoi (/*getopt*/optarg)) < 0)
811              {
812                fprintf (stderr, "Jump value %d must be a positive number.\n", _jump);
813                short_usage (stderr);
814                exit (1);
815              }
816            else if (_jump && ((_jump % 2) == 0))
817              fprintf (stderr, "Jump value %d should be odd, adding 1 and continuing...\n", _jump++);
818            break;
819          }
820        case 'k':               /* Sets key positions used for hash function.  */
821          {
822            _option_word |= POSITIONS;
823            const int BAD_VALUE = -3;
824            const int EOS = PositionIterator::EOS;
825            int       value;
826            PositionStringParser sparser (/*getopt*/optarg, 1, Positions::MAX_KEY_POS, Positions::LASTCHAR, BAD_VALUE, EOS);
827
828            if (/*getopt*/optarg [0] == '*') /* Use all the characters for hashing!!!! */
829              _key_positions.set_useall(true);
830            else
831              {
832                _key_positions.set_useall(false);
833                int *key_positions = _key_positions.pointer();
834                int *key_pos;
835
836                for (key_pos = key_positions; (value = sparser.nextPosition()) != EOS; key_pos++)
837                  {
838                    if (value == BAD_VALUE)
839                      {
840                        fprintf (stderr, "Invalid position value or range, use 1,2,3-%d,'$' or '*'.\n",
841                                         Positions::MAX_KEY_POS);
842                        short_usage (stderr);
843                        exit (1);
844                      }
845                    if (key_pos - key_positions == Positions::MAX_SIZE)
846                      {
847                        /* More than Positions::MAX_SIZE key positions.
848                           Since all key positions are in the range
849                           0..Positions::MAX_KEY_POS-1 or == Positions::LASTCHAR,
850                           there must be duplicates.  */
851                        fprintf (stderr, "Duplicate key positions selected\n");
852                        short_usage (stderr);
853                        exit (1);
854                      }
855                    if (value != Positions::LASTCHAR)
856                      /* We use 0-based indices in the class Positions.  */
857                      value = value - 1;
858                    *key_pos = value;
859                  }
860
861                unsigned int total_keysig_size = key_pos - key_positions;
862                if (total_keysig_size == 0)
863                  {
864                    fprintf (stderr, "No key positions selected.\n");
865                    short_usage (stderr);
866                    exit (1);
867                  }
868                _key_positions.set_size (total_keysig_size);
869
870                /* Sorts the key positions *IN REVERSE ORDER!!*
871                   This makes further routines more efficient.  Especially
872                   when generating code.  */
873                if (! _key_positions.sort())
874                  {
875                    fprintf (stderr, "Duplicate key positions selected\n");
876                    short_usage (stderr);
877                    exit (1);
878                  }
879              }
880            break;
881          }
882        case 'K':               /* Make this the keyname for the keyword component field.  */
883          {
884            _slot_name = /*getopt*/optarg;
885            break;
886          }
887        case 'l':               /* Create length table to avoid extra string compares.  */
888          {
889            _option_word |= LENTABLE;
890            break;
891          }
892        case 'L':               /* Deal with different generated languages.  */
893          {
894            _language = NULL;
895            set_language (/*getopt*/optarg);
896            break;
897          }
898        case 'm':               /* Multiple iterations for finding good asso_values.  */
899          {
900            if ((_asso_iterations = atoi (/*getopt*/optarg)) < 0)
901              {
902                fprintf (stderr, "asso_iterations value must not be negative, assuming 0\n");
903                _asso_iterations = 0;
904              }
905            break;
906          }
907        case 'n':               /* Don't include the length when computing hash function.  */
908          {
909            _option_word |= NOLENGTH;
910            break;
911          }
912        case 'N':               /* Make generated lookup function name be optarg.  */
913          {
914            _function_name = /*getopt*/optarg;
915            break;
916          }
917        case 'o':               /* Order input by frequency of key set occurrence.  */
918          break;                /* Not needed any more.  */
919        case 'O':               /* Optimized choice during collision resolution.  */
920          break;                /* Not needed any more.  */
921        case 'p':               /* Generated lookup function a pointer instead of int.  */
922          break;                /* This is now the default.  */
923        case 'P':               /* Optimize for position-independent code.  */
924          {
925            _option_word |= SHAREDLIB;
926            break;
927          }
928        case 'Q':               /* Sets the name for the string pool.  */
929          {
930            _stringpool_name = /*getopt*/optarg;
931            break;
932          }
933        case 'r':               /* Utilize randomness to initialize the associated values table.  */
934          {
935            _option_word |= RANDOM;
936            if (_initial_asso_value != 0)
937              fprintf (stderr, "warning, -r option supersedes -i, disabling -i option and continuing\n");
938            break;
939          }
940        case 's':               /* Range of associated values, determines size of final table.  */
941          {
942            float numerator;
943            float denominator = 1;
944            bool invalid = false;
945            char *endptr;
946
947            numerator = strtod (/*getopt*/optarg, &endptr);
948            if (endptr == /*getopt*/optarg)
949              invalid = true;
950            else if (*endptr != '\0')
951              {
952                if (*endptr == '/')
953                  {
954                    char *denomptr = endptr + 1;
955                    denominator = strtod (denomptr, &endptr);
956                    if (endptr == denomptr || *endptr != '\0')
957                      invalid = true;
958                  }
959                else
960                  invalid = true;
961              }
962            if (invalid)
963              {
964                fprintf (stderr, "Invalid value for option -s.\n");
965                short_usage (stderr);
966                exit (1);
967              }
968            _size_multiple = numerator / denominator;
969            /* Backward compatibility: -3 means 1/3.  */
970            if (_size_multiple < 0)
971              _size_multiple = 1 / (-_size_multiple);
972            /* Catch stupid users.  */
973            if (_size_multiple == 0)
974              _size_multiple = 1;
975            /* Warnings.  */
976            if (_size_multiple > 50)
977              fprintf (stderr, "Size multiple %g is excessive, did you really mean this?! (try '%s --help' for help)\n", _size_multiple, program_name);
978            else if (_size_multiple < 0.01f)
979              fprintf (stderr, "Size multiple %g is extremely small, did you really mean this?! (try '%s --help' for help)\n", _size_multiple, program_name);
980            break;
981          }
982        case 'S':               /* Generate switch statement output, rather than lookup table.  */
983          {
984            _option_word |= SWITCH;
985            _total_switches = atoi (/*getopt*/optarg);
986            if (_total_switches <= 0)
987              {
988                fprintf (stderr, "number of switches %s must be a positive number\n", /*getopt*/optarg);
989                short_usage (stderr);
990                exit (1);
991              }
992            break;
993          }
994        case 't':               /* Enable the TYPE mode, allowing arbitrary user structures.  */
995          {
996            _option_word |= TYPE;
997            break;
998          }
999        case 'T':               /* Don't print structure definition.  */
1000          {
1001            _option_word |= NOTYPE;
1002            break;
1003          }
1004        case 'v':               /* Print out the version and quit.  */
1005          fprintf (stdout, "GNU gperf %s\n", version_string);
1006          fprintf (stdout, "Copyright (C) %s Free Software Foundation, Inc.\n\
1007This is free software; see the source for copying conditions.  There is NO\n\
1008warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
1009",
1010                   "1989-1998, 2000-2004, 2006-2007");
1011          fprintf (stdout, "Written by %s and %s.\n",
1012                   "Douglas C. Schmidt", "Bruno Haible");
1013          exit (0);
1014        case 'W':               /* Sets the name for the hash table array.  */
1015          {
1016            _wordlist_name = /*getopt*/optarg;
1017            break;
1018          }
1019        case 'Z':               /* Set the class name.  */
1020          {
1021            _class_name = /*getopt*/optarg;
1022            break;
1023          }
1024        case '7':               /* Assume 7-bit characters.  */
1025          {
1026            _option_word |= SEVENBIT;
1027            break;
1028          }
1029        case CHAR_MAX + 1:      /* Set the output file name.  */
1030          {
1031            _output_file_name = /*getopt*/optarg;
1032            break;
1033          }
1034        case CHAR_MAX + 2:      /* Case insignificant.  */
1035          {
1036            _option_word |= UPPERLOWER;
1037            break;
1038          }
1039        case CHAR_MAX + 3:      /* Use NULL instead of "".  */
1040          {
1041            _option_word |= NULLSTRINGS;
1042            break;
1043          }
1044        case CHAR_MAX + 4:      /* Sets the name for the length table array.  */
1045          {
1046            _lengthtable_name = /*getopt*/optarg;
1047            break;
1048          }
1049        default:
1050          short_usage (stderr);
1051          exit (1);
1052        }
1053
1054    }
1055
1056  if (/*getopt*/optind < argc)
1057    _input_file_name = argv[/*getopt*/optind++];
1058
1059  if (/*getopt*/optind < argc)
1060    {
1061      fprintf (stderr, "Extra trailing arguments to %s.\n", program_name);
1062      short_usage (stderr);
1063      exit (1);
1064    }
1065}
1066
1067/* ------------------------------------------------------------------------- */
1068
1069#ifndef __OPTIMIZE__
1070
1071#define INLINE /* not inline */
1072#include "options.icc"
1073#undef INLINE
1074
1075#endif /* not defined __OPTIMIZE__ */
1076