158551Skris/* Handles parsing the Options provided to the user.
2230237Sbapt   Copyright (C) 1989-1998, 2000, 2002-2004, 2006-2007 Free Software Foundation, Inc.
3230237Sbapt   Written by Douglas C. Schmidt <schmidt@ics.uci.edu>
4230237Sbapt   and Bruno Haible <bruno@clisp.org>.
558551Skris
6230237Sbapt   This file is part of GNU GPERF.
758551Skris
8230237Sbapt   GNU GPERF is free software; you can redistribute it and/or modify
9230237Sbapt   it under the terms of the GNU General Public License as published by
10230237Sbapt   the Free Software Foundation; either version 2, or (at your option)
11230237Sbapt   any later version.
1258551Skris
13230237Sbapt   GNU GPERF is distributed in the hope that it will be useful,
14230237Sbapt   but WITHOUT ANY WARRANTY; without even the implied warranty of
15230237Sbapt   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16230237Sbapt   GNU General Public License for more details.
1758551Skris
18230237Sbapt   You should have received a copy of the GNU General Public License
19230237Sbapt   along with this program; see the file COPYING.
20230237Sbapt   If not, write to the Free Software Foundation, Inc.,
21230237Sbapt   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
2258551Skris
23230237Sbapt/* Specification. */
24230237Sbapt#include "options.h"
25230237Sbapt
2658551Skris#include <stdio.h>
2758551Skris#include <stdlib.h> /* declares atoi(), abs(), exit() */
2858551Skris#include <string.h> /* declares strcmp() */
29230237Sbapt#include <ctype.h>  /* declares isdigit() */
30230237Sbapt#include <limits.h> /* defines CHAR_MAX */
3158551Skris#include "getopt.h"
3258551Skris#include "version.h"
3358551Skris
34230237Sbapt/* Global option coordinator for the entire program.  */
3558551SkrisOptions option;
3658551Skris
37230237Sbapt/* Records the program name.  */
3858551Skrisconst char *program_name;
3958551Skris
40230237Sbapt/* Size to jump on a collision.  */
4158551Skrisstatic const int DEFAULT_JUMP_VALUE = 5;
4258551Skris
43230237Sbapt/* Default name for generated lookup function.  */
44230237Sbaptstatic const char *const DEFAULT_FUNCTION_NAME = "in_word_set";
4558551Skris
46230237Sbapt/* Default name for the key component.  */
47230237Sbaptstatic const char *const DEFAULT_SLOT_NAME = "name";
4858551Skris
49230237Sbapt/* Default struct initializer suffix.  */
5067064Sobrienstatic const char *const DEFAULT_INITIALIZER_SUFFIX = "";
5167064Sobrien
52230237Sbapt/* Default name for the generated class.  */
5358551Skrisstatic const char *const DEFAULT_CLASS_NAME = "Perfect_Hash";
5458551Skris
55230237Sbapt/* Default name for generated hash function.  */
5658551Skrisstatic const char *const DEFAULT_HASH_NAME = "hash";
5758551Skris
58230237Sbapt/* Default name for generated hash table array.  */
5958551Skrisstatic const char *const DEFAULT_WORDLIST_NAME = "wordlist";
6058551Skris
61230237Sbapt/* Default name for generated length table array.  */
62230237Sbaptstatic const char *const DEFAULT_LENGTHTABLE_NAME = "lengthtable";
6358551Skris
64230237Sbapt/* Default name for string pool.  */
65230237Sbaptstatic const char *const DEFAULT_STRINGPOOL_NAME = "stringpool";
6658551Skris
67230237Sbapt/* Default delimiters that separate keywords from their attributes.  */
68230237Sbaptstatic const char *const DEFAULT_DELIMITERS = ",";
6958551Skris
70230237Sbapt/* Prints program usage to given stream.  */
71230237Sbapt
7258551Skrisvoid
73230237SbaptOptions::short_usage (FILE * stream)
7458551Skris{
75230237Sbapt  fprintf (stream,
76230237Sbapt           "Try '%s --help' for more information.\n", program_name);
7758551Skris}
7858551Skris
7958551Skrisvoid
80230237SbaptOptions::long_usage (FILE * stream)
8158551Skris{
82230237Sbapt  fprintf (stream,
83230237Sbapt           "GNU 'gperf' generates perfect hash functions.\n");
84230237Sbapt  fprintf (stream, "\n");
85230237Sbapt  fprintf (stream,
86230237Sbapt           "Usage: %s [OPTION]... [INPUT-FILE]\n",
87230237Sbapt           program_name);
88230237Sbapt  fprintf (stream, "\n");
89230237Sbapt  fprintf (stream,
9058551Skris           "If a long option shows an argument as mandatory, then it is mandatory\n"
91230237Sbapt           "for the equivalent short option also.\n");
92230237Sbapt  fprintf (stream, "\n");
93230237Sbapt  fprintf (stream,
94230237Sbapt           "Output file location:\n");
95230237Sbapt  fprintf (stream,
96230237Sbapt           "      --output-file=FILE Write output to specified file.\n");
97230237Sbapt  fprintf (stream,
98230237Sbapt           "The results are written to standard output if no output file is specified\n"
99230237Sbapt           "or if it is -.\n");
100230237Sbapt  fprintf (stream, "\n");
101230237Sbapt  fprintf (stream,
102230237Sbapt           "Input file interpretation:\n");
103230237Sbapt  fprintf (stream,
10458551Skris           "  -e, --delimiters=DELIMITER-LIST\n"
10558551Skris           "                         Allow user to provide a string containing delimiters\n"
10658551Skris           "                         used to separate keywords from their attributes.\n"
107230237Sbapt           "                         Default is \",\".\n");
108230237Sbapt  fprintf (stream,
10958551Skris           "  -t, --struct-type      Allows the user to include a structured type\n"
11058551Skris           "                         declaration for generated code. Any text before %%%%\n"
11158551Skris           "                         is considered part of the type declaration. Key\n"
11258551Skris           "                         words and additional fields may follow this, one\n"
113230237Sbapt           "                         group of fields per line.\n");
114230237Sbapt  fprintf (stream,
115230237Sbapt           "      --ignore-case      Consider upper and lower case ASCII characters as\n"
116230237Sbapt           "                         equivalent. Note that locale dependent case mappings\n"
117230237Sbapt           "                         are ignored.\n");
118230237Sbapt  fprintf (stream, "\n");
119230237Sbapt  fprintf (stream,
120230237Sbapt           "Language for the output code:\n");
121230237Sbapt  fprintf (stream,
12258551Skris           "  -L, --language=LANGUAGE-NAME\n"
12358551Skris           "                         Generates code in the specified language. Languages\n"
12458551Skris           "                         handled are currently C++, ANSI-C, C, and KR-C. The\n"
125230237Sbapt           "                         default is C.\n");
126230237Sbapt  fprintf (stream, "\n");
127230237Sbapt  fprintf (stream,
128230237Sbapt           "Details in the output code:\n");
129230237Sbapt  fprintf (stream,
13058551Skris           "  -K, --slot-name=NAME   Select name of the keyword component in the keyword\n"
131230237Sbapt           "                         structure.\n");
132230237Sbapt  fprintf (stream,
13367064Sobrien           "  -F, --initializer-suffix=INITIALIZERS\n"
13467064Sobrien           "                         Initializers for additional components in the keyword\n"
135230237Sbapt           "                         structure.\n");
136230237Sbapt  fprintf (stream,
137230237Sbapt           "  -H, --hash-function-name=NAME\n"
13858551Skris           "                         Specify name of generated hash function. Default is\n"
139230237Sbapt           "                         'hash'.\n");
140230237Sbapt  fprintf (stream,
141230237Sbapt           "  -N, --lookup-function-name=NAME\n"
14258551Skris           "                         Specify name of generated lookup function. Default\n"
143230237Sbapt           "                         name is 'in_word_set'.\n");
144230237Sbapt  fprintf (stream,
14558551Skris           "  -Z, --class-name=NAME  Specify name of generated C++ class. Default name is\n"
146230237Sbapt           "                         'Perfect_Hash'.\n");
147230237Sbapt  fprintf (stream,
148230237Sbapt           "  -7, --seven-bit        Assume 7-bit characters.\n");
149230237Sbapt  fprintf (stream,
150230237Sbapt           "  -l, --compare-lengths  Compare key lengths before trying a string\n"
151230237Sbapt           "                         comparison. This is necessary if the keywords\n"
152230237Sbapt           "                         contain NUL bytes. It also helps cut down on the\n"
153230237Sbapt           "                         number of string comparisons made during the lookup.\n");
154230237Sbapt  fprintf (stream,
15558551Skris           "  -c, --compare-strncmp  Generate comparison code using strncmp rather than\n"
156230237Sbapt           "                         strcmp.\n");
157230237Sbapt  fprintf (stream,
15858551Skris           "  -C, --readonly-tables  Make the contents of generated lookup tables\n"
159230237Sbapt           "                         constant, i.e., readonly.\n");
160230237Sbapt  fprintf (stream,
16158551Skris           "  -E, --enum             Define constant values using an enum local to the\n"
162230237Sbapt           "                         lookup function rather than with defines.\n");
163230237Sbapt  fprintf (stream,
16458551Skris           "  -I, --includes         Include the necessary system include file <string.h>\n"
165230237Sbapt           "                         at the beginning of the code.\n");
166230237Sbapt  fprintf (stream,
167230237Sbapt           "  -G, --global-table     Generate the static table of keywords as a static\n"
16858551Skris           "                         global variable, rather than hiding it inside of the\n"
169230237Sbapt           "                         lookup function (which is the default behavior).\n");
170230237Sbapt  fprintf (stream,
171230237Sbapt           "  -P, --pic              Optimize the generated table for inclusion in shared\n"
172230237Sbapt           "                         libraries.  This reduces the startup time of programs\n"
173230237Sbapt           "                         using a shared library containing the generated code.\n");
174230237Sbapt  fprintf (stream,
175230237Sbapt           "  -Q, --string-pool-name=NAME\n"
176230237Sbapt           "                         Specify name of string pool generated by option --pic.\n"
177230237Sbapt           "                         Default name is 'stringpool'.\n");
178230237Sbapt  fprintf (stream,
179230237Sbapt           "      --null-strings     Use NULL strings instead of empty strings for empty\n"
180230237Sbapt           "                         keyword table entries.\n");
181230237Sbapt  fprintf (stream,
18258551Skris           "  -W, --word-array-name=NAME\n"
18358551Skris           "                         Specify name of word list array. Default name is\n"
184230237Sbapt           "                         'wordlist'.\n");
185230237Sbapt  fprintf (stream,
186230237Sbapt           "      --length-table-name=NAME\n"
187230237Sbapt           "                         Specify name of length table array. Default name is\n"
188230237Sbapt           "                         'lengthtable'.\n");
189230237Sbapt  fprintf (stream,
19058551Skris           "  -S, --switch=COUNT     Causes the generated C code to use a switch\n"
19158551Skris           "                         statement scheme, rather than an array lookup table.\n"
19258551Skris           "                         This can lead to a reduction in both time and space\n"
19358551Skris           "                         requirements for some keyfiles. The COUNT argument\n"
19458551Skris           "                         determines how many switch statements are generated.\n"
19558551Skris           "                         A value of 1 generates 1 switch containing all the\n"
19658551Skris           "                         elements, a value of 2 generates 2 tables with 1/2\n"
19758551Skris           "                         the elements in each table, etc. If COUNT is very\n"
19858551Skris           "                         large, say 1000000, the generated C code does a\n"
199230237Sbapt           "                         binary search.\n");
200230237Sbapt  fprintf (stream,
20158551Skris           "  -T, --omit-struct-type\n"
20258551Skris           "                         Prevents the transfer of the type declaration to the\n"
20358551Skris           "                         output file. Use this option if the type is already\n"
204230237Sbapt           "                         defined elsewhere.\n");
205230237Sbapt  fprintf (stream, "\n");
206230237Sbapt  fprintf (stream,
207230237Sbapt           "Algorithm employed by gperf:\n");
208230237Sbapt  fprintf (stream,
20958551Skris           "  -k, --key-positions=KEYS\n"
21058551Skris           "                         Select the key positions used in the hash function.\n"
21158551Skris           "                         The allowable choices range between 1-%d, inclusive.\n"
21258551Skris           "                         The positions are separated by commas, ranges may be\n"
21358551Skris           "                         used, and key positions may occur in any order.\n"
21458551Skris           "                         Also, the meta-character '*' causes the generated\n"
21558551Skris           "                         hash function to consider ALL key positions, and $\n"
216230237Sbapt           "                         indicates the \"final character\" of a key, e.g.,\n"
217230237Sbapt           "                         $,1,2,4,6-10.\n",
218230237Sbapt           Positions::MAX_KEY_POS);
219230237Sbapt  fprintf (stream,
22058551Skris           "  -D, --duplicates       Handle keywords that hash to duplicate values. This\n"
221230237Sbapt           "                         is useful for certain highly redundant keyword sets.\n");
222230237Sbapt  fprintf (stream,
223230237Sbapt           "  -m, --multiple-iterations=ITERATIONS\n"
224230237Sbapt           "                         Perform multiple choices of the -i and -j values,\n"
225230237Sbapt           "                         and choose the best results. This increases the\n"
226230237Sbapt           "                         running time by a factor of ITERATIONS but does a\n"
227230237Sbapt           "                         good job minimizing the generated table size.\n");
228230237Sbapt  fprintf (stream,
22958551Skris           "  -i, --initial-asso=N   Provide an initial value for the associate values\n"
23058551Skris           "                         array. Default is 0. Setting this value larger helps\n"
231230237Sbapt           "                         inflate the size of the final table.\n");
232230237Sbapt  fprintf (stream,
233230237Sbapt           "  -j, --jump=JUMP-VALUE  Affects the \"jump value\", i.e., how far to advance\n"
23458551Skris           "                         the associated character value upon collisions. Must\n"
235230237Sbapt           "                         be an odd number, default is %d.\n",
236230237Sbapt           DEFAULT_JUMP_VALUE);
237230237Sbapt  fprintf (stream,
23858551Skris           "  -n, --no-strlen        Do not include the length of the keyword when\n"
239230237Sbapt           "                         computing the hash function.\n");
240230237Sbapt  fprintf (stream,
24158551Skris           "  -r, --random           Utilizes randomness to initialize the associated\n"
242230237Sbapt           "                         values table.\n");
243230237Sbapt  fprintf (stream,
24458551Skris           "  -s, --size-multiple=N  Affects the size of the generated hash table. The\n"
245230237Sbapt           "                         numeric argument N indicates \"how many times larger\n"
246230237Sbapt           "                         or smaller\" the associated value range should be,\n"
24758551Skris           "                         in relationship to the number of keys, e.g. a value\n"
248230237Sbapt           "                         of 3 means \"allow the maximum associated value to\n"
24958551Skris           "                         be about 3 times larger than the number of input\n"
250230237Sbapt           "                         keys\". Conversely, a value of 1/3 means \"make the\n"
25158551Skris           "                         maximum associated value about 3 times smaller than\n"
252230237Sbapt           "                         the number of input keys\". A larger table should\n"
25358551Skris           "                         decrease the time required for an unsuccessful\n"
25458551Skris           "                         search, at the expense of extra table space. Default\n"
255230237Sbapt           "                         value is 1.\n");
256230237Sbapt  fprintf (stream, "\n");
257230237Sbapt  fprintf (stream,
25858551Skris           "Informative output:\n"
25958551Skris           "  -h, --help             Print this message.\n"
26058551Skris           "  -v, --version          Print the gperf version number.\n"
26158551Skris           "  -d, --debug            Enables the debugging option (produces verbose\n"
262230237Sbapt           "                         output to the standard error).\n");
263230237Sbapt  fprintf (stream, "\n");
264230237Sbapt  fprintf (stream,
265230237Sbapt           "Report bugs to <bug-gnu-gperf@gnu.org>.\n");
26658551Skris}
26758551Skris
268230237Sbapt/* Prints the given options.  */
26958551Skris
27058551Skrisvoid
271230237SbaptOptions::print_options () const
27258551Skris{
27358551Skris  printf ("/* Command-line: ");
27458551Skris
275230237Sbapt  for (int i = 0; i < _argument_count; i++)
27667064Sobrien    {
277230237Sbapt      const char *arg = _argument_vector[i];
27858551Skris
279230237Sbapt      /* Escape arg if it contains shell metacharacters.  */
28067064Sobrien      if (*arg == '-')
28167064Sobrien        {
28267064Sobrien          putchar (*arg);
28367064Sobrien          arg++;
284230237Sbapt          if (*arg >= 'A' && *arg <= 'Z' || *arg >= 'a' && *arg <= 'z')
28567064Sobrien            {
28667064Sobrien              putchar (*arg);
28767064Sobrien              arg++;
28867064Sobrien            }
289230237Sbapt          else if (*arg == '-')
290230237Sbapt            {
291230237Sbapt              do
292230237Sbapt                {
293230237Sbapt                  putchar (*arg);
294230237Sbapt                  arg++;
295230237Sbapt                }
296230237Sbapt              while (*arg >= 'A' && *arg <= 'Z' || *arg >= 'a' && *arg <= 'z' || *arg == '-');
297230237Sbapt              if (*arg == '=')
298230237Sbapt                {
299230237Sbapt                  putchar (*arg);
300230237Sbapt                  arg++;
301230237Sbapt                }
302230237Sbapt            }
30367064Sobrien        }
30467064Sobrien      if (strpbrk (arg, "\t\n !\"#$&'()*;<>?[\\]`{|}~") != NULL)
30567064Sobrien        {
30667064Sobrien          if (strchr (arg, '\'') != NULL)
30767064Sobrien            {
30867064Sobrien              putchar ('"');
30967064Sobrien              for (; *arg; arg++)
31067064Sobrien                {
311230237Sbapt                  if (*arg == '\"' || *arg == '\\' || *arg == '$' || *arg == '`')
31267064Sobrien                    putchar ('\\');
31367064Sobrien                  putchar (*arg);
31467064Sobrien                }
31567064Sobrien              putchar ('"');
31667064Sobrien            }
31767064Sobrien          else
31867064Sobrien            {
31967064Sobrien              putchar ('\'');
32067064Sobrien              for (; *arg; arg++)
32167064Sobrien                {
32267064Sobrien                  if (*arg == '\\')
32367064Sobrien                    putchar ('\\');
32467064Sobrien                  putchar (*arg);
32567064Sobrien                }
32667064Sobrien              putchar ('\'');
32767064Sobrien            }
32867064Sobrien        }
32967064Sobrien      else
33067064Sobrien        printf ("%s", arg);
33167064Sobrien
33267064Sobrien      printf (" ");
33367064Sobrien    }
33467064Sobrien
33558551Skris  printf (" */");
33658551Skris}
33758551Skris
338230237Sbapt/* ------------------------------------------------------------------------- */
33958551Skris
340230237Sbapt/* Parses a string denoting key positions.  */
341230237Sbapt
342230237Sbaptclass PositionStringParser
34358551Skris{
344230237Sbaptpublic:
345230237Sbapt  /* Initializes a key position string parser for string STR.  */
346230237Sbapt                        PositionStringParser (const char *str,
347230237Sbapt                                              int low_bound, int high_bound,
348230237Sbapt                                              int end_word_marker, int error_value, int end_marker);
349230237Sbapt  /* Returns the next key position from the given string.  */
350230237Sbapt  int                   nextPosition ();
351230237Sbaptprivate:
352230237Sbapt  /* A pointer to the string provided by the user.  */
353230237Sbapt  const char *          _str;
354230237Sbapt  /* Smallest possible value, inclusive.  */
355230237Sbapt  int const             _low_bound;
356230237Sbapt  /* Greatest possible value, inclusive.  */
357230237Sbapt  int const             _high_bound;
358230237Sbapt  /* A value marking the abstract "end of word" ( usually '$').  */
359230237Sbapt  int const             _end_word_marker;
360230237Sbapt  /* Error value returned when input is syntactically erroneous.  */
361230237Sbapt  int const             _error_value;
362230237Sbapt  /* Value returned after last key is processed.  */
363230237Sbapt  int const             _end_marker;
364230237Sbapt  /* Intermediate state for producing a range of positions.  */
365230237Sbapt  bool                  _in_range;           /* True while producing a range of positions.  */
366230237Sbapt  int                   _range_upper_bound;  /* Upper bound (inclusive) of the range.  */
367230237Sbapt  int                   _range_curr_value;   /* Last value returned.  */
368230237Sbapt};
36958551Skris
370230237Sbapt/* Initializes a key position strng parser for string STR.  */
371230237SbaptPositionStringParser::PositionStringParser (const char *str,
372230237Sbapt                                            int low_bound, int high_bound,
373230237Sbapt                                            int end_word_marker, int error_value, int end_marker)
374230237Sbapt  : _str (str),
375230237Sbapt    _low_bound (low_bound),
376230237Sbapt    _high_bound (high_bound),
377230237Sbapt    _end_word_marker (end_word_marker),
378230237Sbapt    _error_value (error_value),
379230237Sbapt    _end_marker (end_marker),
380230237Sbapt    _in_range (false)
381230237Sbapt{
382230237Sbapt}
383230237Sbapt
384230237Sbapt/* Returns the next key position from the given string.  */
385230237Sbaptint
386230237SbaptPositionStringParser::nextPosition ()
387230237Sbapt{
388230237Sbapt  if (_in_range)
38958551Skris    {
390230237Sbapt      /* We are inside a range.  Return the next value from the range.  */
391230237Sbapt      if (++_range_curr_value >= _range_upper_bound)
392230237Sbapt        _in_range = false;
393230237Sbapt      return _range_curr_value;
394230237Sbapt    }
395230237Sbapt  else
396230237Sbapt    {
397230237Sbapt      /* Continue parsing the given string.  */
398230237Sbapt      while (*_str)
399230237Sbapt        switch (*_str)
400230237Sbapt          {
401230237Sbapt          case ',':
402230237Sbapt            /* Skip the comma.  */
403230237Sbapt            _str++;
404230237Sbapt            break;
405230237Sbapt          case '$':
406230237Sbapt            /* Valid key position.  */
407230237Sbapt            _str++;
408230237Sbapt            return _end_word_marker;
409230237Sbapt          case '0': case '1': case '2': case '3': case '4':
410230237Sbapt          case '5': case '6': case '7': case '8': case '9':
411230237Sbapt            /* Valid key position.  */
412230237Sbapt            {
413230237Sbapt              int curr_value;
414230237Sbapt              for (curr_value = 0; isdigit (static_cast<unsigned char>(*_str)); _str++)
415230237Sbapt                curr_value = curr_value * 10 + (*_str - '0');
41658551Skris
417230237Sbapt              if (*_str == '-')
418230237Sbapt                {
419230237Sbapt                  _str++;
420230237Sbapt                  /* Starting a range of key positions.  */
421230237Sbapt                  _in_range = true;
42258551Skris
423230237Sbapt                  for (_range_upper_bound = 0;
424230237Sbapt                       isdigit (static_cast<unsigned char>(*_str));
425230237Sbapt                       _str++)
426230237Sbapt                    _range_upper_bound = _range_upper_bound * 10 + (*_str - '0');
427230237Sbapt
428230237Sbapt                  /* Verify range's upper bound.  */
429230237Sbapt                  if (!(_range_upper_bound > curr_value && _range_upper_bound <= _high_bound))
430230237Sbapt                    return _error_value;
431230237Sbapt                  _range_curr_value = curr_value;
432230237Sbapt                }
433230237Sbapt
434230237Sbapt              /* Verify range's lower bound.  */
435230237Sbapt              if (!(curr_value >= _low_bound && curr_value <= _high_bound))
436230237Sbapt                return _error_value;
437230237Sbapt              return curr_value;
438230237Sbapt            }
439230237Sbapt          default:
440230237Sbapt            /* Invalid syntax.  */
441230237Sbapt            return _error_value;
442230237Sbapt          }
443230237Sbapt
444230237Sbapt      return _end_marker;
44558551Skris    }
44658551Skris}
44758551Skris
448230237Sbapt/* ------------------------------------------------------------------------- */
44958551Skris
450230237Sbapt/* Sets the default Options.  */
451230237Sbapt
452230237SbaptOptions::Options ()
453230237Sbapt  : _option_word (C),
454230237Sbapt    _input_file_name (NULL),
455230237Sbapt    _output_file_name (NULL),
456230237Sbapt    _language (NULL),
457230237Sbapt    _jump (DEFAULT_JUMP_VALUE),
458230237Sbapt    _initial_asso_value (0),
459230237Sbapt    _asso_iterations (0),
460230237Sbapt    _total_switches (1),
461230237Sbapt    _size_multiple (1),
462230237Sbapt    _function_name (DEFAULT_FUNCTION_NAME),
463230237Sbapt    _slot_name (DEFAULT_SLOT_NAME),
464230237Sbapt    _initializer_suffix (DEFAULT_INITIALIZER_SUFFIX),
465230237Sbapt    _class_name (DEFAULT_CLASS_NAME),
466230237Sbapt    _hash_name (DEFAULT_HASH_NAME),
467230237Sbapt    _wordlist_name (DEFAULT_WORDLIST_NAME),
468230237Sbapt    _lengthtable_name (DEFAULT_LENGTHTABLE_NAME),
469230237Sbapt    _stringpool_name (DEFAULT_STRINGPOOL_NAME),
470230237Sbapt    _delimiters (DEFAULT_DELIMITERS),
471230237Sbapt    _key_positions ()
47258551Skris{
47358551Skris}
47458551Skris
475230237Sbapt/* Dumps option status when debugging is enabled.  */
47658551Skris
477230237SbaptOptions::~Options ()
47858551Skris{
479230237Sbapt  if (_option_word & DEBUG)
48058551Skris    {
48158551Skris      fprintf (stderr, "\ndumping Options:"
48258551Skris               "\nTYPE is........: %s"
483230237Sbapt               "\nUPPERLOWER is..: %s"
48458551Skris               "\nKRC is.........: %s"
48558551Skris               "\nC is...........: %s"
48658551Skris               "\nANSIC is.......: %s"
48758551Skris               "\nCPLUSPLUS is...: %s"
488230237Sbapt               "\nSEVENBIT is....: %s"
489230237Sbapt               "\nLENTABLE is....: %s"
490230237Sbapt               "\nCOMP is........: %s"
491230237Sbapt               "\nCONST is.......: %s"
49258551Skris               "\nENUM is........: %s"
49358551Skris               "\nINCLUDE is.....: %s"
494230237Sbapt               "\nGLOBAL is......: %s"
495230237Sbapt               "\nNULLSTRINGS is.: %s"
496230237Sbapt               "\nSHAREDLIB is...: %s"
497230237Sbapt               "\nSWITCH is......: %s"
498230237Sbapt               "\nNOTYPE is......: %s"
499230237Sbapt               "\nDUP is.........: %s"
500230237Sbapt               "\nNOLENGTH is....: %s"
501230237Sbapt               "\nRANDOM is......: %s"
502230237Sbapt               "\nDEBUG is.......: %s"
50358551Skris               "\nlookup function name = %s"
50458551Skris               "\nhash function name = %s"
50558551Skris               "\nword list name = %s"
506230237Sbapt               "\nlength table name = %s"
507230237Sbapt               "\nstring pool name = %s"
508230237Sbapt               "\nslot name = %s"
50967064Sobrien               "\ninitializer suffix = %s"
510230237Sbapt               "\nasso_values iterations = %d"
51158551Skris               "\njump value = %d"
512230237Sbapt               "\nhash table size multiplier = %g"
51358551Skris               "\ninitial associated value = %d"
51458551Skris               "\ndelimiters = %s"
51558551Skris               "\nnumber of switch statements = %d\n",
516230237Sbapt               _option_word & TYPE ? "enabled" : "disabled",
517230237Sbapt               _option_word & UPPERLOWER ? "enabled" : "disabled",
518230237Sbapt               _option_word & KRC ? "enabled" : "disabled",
519230237Sbapt               _option_word & C ? "enabled" : "disabled",
520230237Sbapt               _option_word & ANSIC ? "enabled" : "disabled",
521230237Sbapt               _option_word & CPLUSPLUS ? "enabled" : "disabled",
522230237Sbapt               _option_word & SEVENBIT ? "enabled" : "disabled",
523230237Sbapt               _option_word & LENTABLE ? "enabled" : "disabled",
524230237Sbapt               _option_word & COMP ? "enabled" : "disabled",
525230237Sbapt               _option_word & CONST ? "enabled" : "disabled",
526230237Sbapt               _option_word & ENUM ? "enabled" : "disabled",
527230237Sbapt               _option_word & INCLUDE ? "enabled" : "disabled",
528230237Sbapt               _option_word & GLOBAL ? "enabled" : "disabled",
529230237Sbapt               _option_word & NULLSTRINGS ? "enabled" : "disabled",
530230237Sbapt               _option_word & SHAREDLIB ? "enabled" : "disabled",
531230237Sbapt               _option_word & SWITCH ? "enabled" : "disabled",
532230237Sbapt               _option_word & NOTYPE ? "enabled" : "disabled",
533230237Sbapt               _option_word & DUP ? "enabled" : "disabled",
534230237Sbapt               _option_word & NOLENGTH ? "enabled" : "disabled",
535230237Sbapt               _option_word & RANDOM ? "enabled" : "disabled",
536230237Sbapt               _option_word & DEBUG ? "enabled" : "disabled",
537230237Sbapt               _function_name, _hash_name, _wordlist_name, _lengthtable_name,
538230237Sbapt               _stringpool_name, _slot_name, _initializer_suffix,
539230237Sbapt               _asso_iterations, _jump, _size_multiple, _initial_asso_value,
540230237Sbapt               _delimiters, _total_switches);
541230237Sbapt      if (_key_positions.is_useall())
54258551Skris        fprintf (stderr, "all characters are used in the hash function\n");
543230237Sbapt      else
544230237Sbapt        {
545230237Sbapt          fprintf (stderr, "maximum keysig size = %d\nkey positions are: \n",
546230237Sbapt                   _key_positions.get_size());
54758551Skris
548230237Sbapt          PositionIterator iter = _key_positions.iterator();
549230237Sbapt          for (int pos; (pos = iter.next()) != PositionIterator::EOS; )
550230237Sbapt            if (pos == Positions::LASTCHAR)
551230237Sbapt              fprintf (stderr, "$\n");
552230237Sbapt            else
553230237Sbapt              fprintf (stderr, "%d\n", pos + 1);
554230237Sbapt        }
55558551Skris
55658551Skris      fprintf (stderr, "finished dumping Options\n");
55758551Skris    }
55858551Skris}
55958551Skris
56058551Skris
561230237Sbapt/* Sets the output language, if not already set.  */
562230237Sbaptvoid
563230237SbaptOptions::set_language (const char *language)
564230237Sbapt{
565230237Sbapt  if (_language == NULL)
566230237Sbapt    {
567230237Sbapt      _language = language;
568230237Sbapt      _option_word &= ~(KRC | C | ANSIC | CPLUSPLUS);
569230237Sbapt      if (!strcmp (language, "KR-C"))
570230237Sbapt        _option_word |= KRC;
571230237Sbapt      else if (!strcmp (language, "C"))
572230237Sbapt        _option_word |= C;
573230237Sbapt      else if (!strcmp (language, "ANSI-C"))
574230237Sbapt        _option_word |= ANSIC;
575230237Sbapt      else if (!strcmp (language, "C++"))
576230237Sbapt        _option_word |= CPLUSPLUS;
577230237Sbapt      else
578230237Sbapt        {
579230237Sbapt          fprintf (stderr, "unsupported language option %s, defaulting to C\n",
580230237Sbapt                   language);
581230237Sbapt          _option_word |= C;
582230237Sbapt        }
583230237Sbapt    }
584230237Sbapt}
58558551Skris
586230237Sbapt/* Sets the total number of switch statements, if not already set.  */
587230237Sbaptvoid
588230237SbaptOptions::set_total_switches (int total_switches)
589230237Sbapt{
590230237Sbapt  if (!(_option_word & SWITCH))
591230237Sbapt    {
592230237Sbapt      _option_word |= SWITCH;
593230237Sbapt      _total_switches = total_switches;
594230237Sbapt    }
595230237Sbapt}
596230237Sbapt
597230237Sbapt/* Sets the generated function name, if not already set.  */
598230237Sbaptvoid
599230237SbaptOptions::set_function_name (const char *name)
600230237Sbapt{
601230237Sbapt  if (_function_name == DEFAULT_FUNCTION_NAME)
602230237Sbapt    _function_name = name;
603230237Sbapt}
604230237Sbapt
605230237Sbapt/* Sets the keyword key name, if not already set.  */
606230237Sbaptvoid
607230237SbaptOptions::set_slot_name (const char *name)
608230237Sbapt{
609230237Sbapt  if (_slot_name == DEFAULT_SLOT_NAME)
610230237Sbapt    _slot_name = name;
611230237Sbapt}
612230237Sbapt
613230237Sbapt/* Sets the struct initializer suffix, if not already set.  */
614230237Sbaptvoid
615230237SbaptOptions::set_initializer_suffix (const char *initializers)
616230237Sbapt{
617230237Sbapt  if (_initializer_suffix == DEFAULT_INITIALIZER_SUFFIX)
618230237Sbapt    _initializer_suffix = initializers;
619230237Sbapt}
620230237Sbapt
621230237Sbapt/* Sets the generated class name, if not already set.  */
622230237Sbaptvoid
623230237SbaptOptions::set_class_name (const char *name)
624230237Sbapt{
625230237Sbapt  if (_class_name == DEFAULT_CLASS_NAME)
626230237Sbapt    _class_name = name;
627230237Sbapt}
628230237Sbapt
629230237Sbapt/* Sets the hash function name, if not already set.  */
630230237Sbaptvoid
631230237SbaptOptions::set_hash_name (const char *name)
632230237Sbapt{
633230237Sbapt  if (_hash_name == DEFAULT_HASH_NAME)
634230237Sbapt    _hash_name = name;
635230237Sbapt}
636230237Sbapt
637230237Sbapt/* Sets the hash table array name, if not already set.  */
638230237Sbaptvoid
639230237SbaptOptions::set_wordlist_name (const char *name)
640230237Sbapt{
641230237Sbapt  if (_wordlist_name == DEFAULT_WORDLIST_NAME)
642230237Sbapt    _wordlist_name = name;
643230237Sbapt}
644230237Sbapt
645230237Sbapt/* Sets the length table array name, if not already set.  */
646230237Sbaptvoid
647230237SbaptOptions::set_lengthtable_name (const char *name)
648230237Sbapt{
649230237Sbapt  if (_lengthtable_name == DEFAULT_LENGTHTABLE_NAME)
650230237Sbapt    _lengthtable_name = name;
651230237Sbapt}
652230237Sbapt
653230237Sbapt/* Sets the string pool name, if not already set.  */
654230237Sbaptvoid
655230237SbaptOptions::set_stringpool_name (const char *name)
656230237Sbapt{
657230237Sbapt  if (_stringpool_name == DEFAULT_STRINGPOOL_NAME)
658230237Sbapt    _stringpool_name = name;
659230237Sbapt}
660230237Sbapt
661230237Sbapt/* Sets the delimiters string, if not already set.  */
662230237Sbaptvoid
663230237SbaptOptions::set_delimiters (const char *delimiters)
664230237Sbapt{
665230237Sbapt  if (_delimiters == DEFAULT_DELIMITERS)
666230237Sbapt    _delimiters = delimiters;
667230237Sbapt}
668230237Sbapt
669230237Sbapt
670230237Sbapt/* Parses the command line Options and sets appropriate flags in option_word.  */
671230237Sbapt
67258551Skrisstatic const struct option long_options[] =
67358551Skris{
674230237Sbapt  { "output-file", required_argument, NULL, CHAR_MAX + 1 },
675230237Sbapt  { "ignore-case", no_argument, NULL, CHAR_MAX + 2 },
676230237Sbapt  { "delimiters", required_argument, NULL, 'e' },
677230237Sbapt  { "struct-type", no_argument, NULL, 't' },
678230237Sbapt  { "language", required_argument, NULL, 'L' },
679230237Sbapt  { "slot-name", required_argument, NULL, 'K' },
680230237Sbapt  { "initializer-suffix", required_argument, NULL, 'F' },
681230237Sbapt  { "hash-fn-name", required_argument, NULL, 'H' }, /* backward compatibility */
682230237Sbapt  { "hash-function-name", required_argument, NULL, 'H' },
683230237Sbapt  { "lookup-fn-name", required_argument, NULL, 'N' }, /* backward compatibility */
684230237Sbapt  { "lookup-function-name", required_argument, NULL, 'N' },
685230237Sbapt  { "class-name", required_argument, NULL, 'Z' },
686230237Sbapt  { "seven-bit", no_argument, NULL, '7' },
687230237Sbapt  { "compare-strncmp", no_argument, NULL, 'c' },
688230237Sbapt  { "readonly-tables", no_argument, NULL, 'C' },
689230237Sbapt  { "enum", no_argument, NULL, 'E' },
690230237Sbapt  { "includes", no_argument, NULL, 'I' },
691230237Sbapt  { "global-table", no_argument, NULL, 'G' },
692230237Sbapt  { "word-array-name", required_argument, NULL, 'W' },
693230237Sbapt  { "length-table-name", required_argument, NULL, CHAR_MAX + 4 },
694230237Sbapt  { "switch", required_argument, NULL, 'S' },
695230237Sbapt  { "omit-struct-type", no_argument, NULL, 'T' },
696230237Sbapt  { "key-positions", required_argument, NULL, 'k' },
697230237Sbapt  { "compare-strlen", no_argument, NULL, 'l' }, /* backward compatibility */
698230237Sbapt  { "compare-lengths", no_argument, NULL, 'l' },
699230237Sbapt  { "duplicates", no_argument, NULL, 'D' },
700230237Sbapt  { "fast", required_argument, NULL, 'f' },
701230237Sbapt  { "initial-asso", required_argument, NULL, 'i' },
702230237Sbapt  { "jump", required_argument, NULL, 'j' },
703230237Sbapt  { "multiple-iterations", required_argument, NULL, 'm' },
704230237Sbapt  { "no-strlen", no_argument, NULL, 'n' },
705230237Sbapt  { "occurrence-sort", no_argument, NULL, 'o' },
706230237Sbapt  { "optimized-collision-resolution", no_argument, NULL, 'O' },
707230237Sbapt  { "pic", no_argument, NULL, 'P' },
708230237Sbapt  { "string-pool-name", required_argument, NULL, 'Q' },
709230237Sbapt  { "null-strings", no_argument, NULL, CHAR_MAX + 3 },
710230237Sbapt  { "random", no_argument, NULL, 'r' },
711230237Sbapt  { "size-multiple", required_argument, NULL, 's' },
712230237Sbapt  { "help", no_argument, NULL, 'h' },
713230237Sbapt  { "version", no_argument, NULL, 'v' },
714230237Sbapt  { "debug", no_argument, NULL, 'd' },
715230237Sbapt  { NULL, no_argument, NULL, 0 }
71658551Skris};
71758551Skris
71858551Skrisvoid
719230237SbaptOptions::parse_options (int argc, char *argv[])
72058551Skris{
721230237Sbapt  int option_char;
72258551Skris
72358551Skris  program_name = argv[0];
724230237Sbapt  _argument_count  = argc;
725230237Sbapt  _argument_vector = argv;
72658551Skris
72758551Skris  while ((option_char =
728230237Sbapt            getopt_long (_argument_count, _argument_vector,
729230237Sbapt                         "acCdDe:Ef:F:gGhH:i:Ij:k:K:lL:m:nN:oOpPQ:rs:S:tTvW:Z:7",
730230237Sbapt                         long_options, NULL))
73158551Skris         != -1)
73258551Skris    {
73358551Skris      switch (option_char)
73458551Skris        {
735230237Sbapt        case 'a':               /* Generated code uses the ANSI prototype format.  */
736230237Sbapt          break;                /* This is now the default.  */
737230237Sbapt        case 'c':               /* Generate strncmp rather than strcmp.  */
73858551Skris          {
739230237Sbapt            _option_word |= COMP;
74058551Skris            break;
74158551Skris          }
742230237Sbapt        case 'C':               /* Make the generated tables readonly (const).  */
74358551Skris          {
744230237Sbapt            _option_word |= CONST;
74558551Skris            break;
74658551Skris          }
747230237Sbapt        case 'd':               /* Enable debugging option.  */
74858551Skris          {
749230237Sbapt            _option_word |= DEBUG;
75058551Skris            fprintf (stderr, "Starting program %s, version %s, with debugging on.\n",
75158551Skris                             program_name, version_string);
75258551Skris            break;
75358551Skris          }
754230237Sbapt        case 'D':               /* Enable duplicate option.  */
75558551Skris          {
756230237Sbapt            _option_word |= DUP;
75758551Skris            break;
75858551Skris          }
759230237Sbapt        case 'e':               /* Specify keyword/attribute separator */
76058551Skris          {
761230237Sbapt            _delimiters = /*getopt*/optarg;
76258551Skris            break;
76358551Skris          }
76458551Skris        case 'E':
76558551Skris          {
766230237Sbapt            _option_word |= ENUM;
76758551Skris            break;
76858551Skris          }
769230237Sbapt        case 'f':               /* Generate the hash table "fast".  */
770230237Sbapt          break;                /* Not needed any more.  */
77167064Sobrien        case 'F':
77267064Sobrien          {
773230237Sbapt            _initializer_suffix = /*getopt*/optarg;
77467064Sobrien            break;
77567064Sobrien          }
776230237Sbapt        case 'g':               /* Use the 'inline' keyword for generated sub-routines, ifdef __GNUC__.  */
777230237Sbapt          break;                /* This is now the default.  */
778230237Sbapt        case 'G':               /* Make the keyword table a global variable.  */
77958551Skris          {
780230237Sbapt            _option_word |= GLOBAL;
78158551Skris            break;
78258551Skris          }
783230237Sbapt        case 'h':               /* Displays a list of helpful Options to the user.  */
78458551Skris          {
78558551Skris            long_usage (stdout);
78658551Skris            exit (0);
78758551Skris          }
788230237Sbapt        case 'H':               /* Sets the name for the hash function.  */
78958551Skris          {
790230237Sbapt            _hash_name = /*getopt*/optarg;
79158551Skris            break;
79258551Skris          }
793230237Sbapt        case 'i':               /* Sets the initial value for the associated values array.  */
79458551Skris          {
795230237Sbapt            if ((_initial_asso_value = atoi (/*getopt*/optarg)) < 0)
796230237Sbapt              fprintf (stderr, "Initial value %d should be non-zero, ignoring and continuing.\n", _initial_asso_value);
79758551Skris            if (option[RANDOM])
79858551Skris              fprintf (stderr, "warning, -r option superceeds -i, ignoring -i option and continuing\n");
79958551Skris            break;
80058551Skris          }
801230237Sbapt        case 'I':               /* Enable #include statements.  */
80258551Skris          {
803230237Sbapt            _option_word |= INCLUDE;
80458551Skris            break;
80558551Skris          }
806230237Sbapt        case 'j':               /* Sets the jump value, must be odd for later algorithms.  */
80758551Skris          {
808230237Sbapt            if ((_jump = atoi (/*getopt*/optarg)) < 0)
80958551Skris              {
810230237Sbapt                fprintf (stderr, "Jump value %d must be a positive number.\n", _jump);
81158551Skris                short_usage (stderr);
81258551Skris                exit (1);
81358551Skris              }
814230237Sbapt            else if (_jump && ((_jump % 2) == 0))
815230237Sbapt              fprintf (stderr, "Jump value %d should be odd, adding 1 and continuing...\n", _jump++);
81658551Skris            break;
81758551Skris          }
818230237Sbapt        case 'k':               /* Sets key positions used for hash function.  */
81958551Skris          {
820230237Sbapt            _option_word |= POSITIONS;
821230237Sbapt            const int BAD_VALUE = -3;
822230237Sbapt            const int EOS = PositionIterator::EOS;
82358551Skris            int       value;
824230237Sbapt            PositionStringParser sparser (/*getopt*/optarg, 1, Positions::MAX_KEY_POS, Positions::LASTCHAR, BAD_VALUE, EOS);
82558551Skris
82658551Skris            if (/*getopt*/optarg [0] == '*') /* Use all the characters for hashing!!!! */
827230237Sbapt              _key_positions.set_useall(true);
82858551Skris            else
82958551Skris              {
830230237Sbapt                _key_positions.set_useall(false);
831230237Sbapt                int *key_positions = _key_positions.pointer();
832230237Sbapt                int *key_pos;
83358551Skris
834230237Sbapt                for (key_pos = key_positions; (value = sparser.nextPosition()) != EOS; key_pos++)
835230237Sbapt                  {
836230237Sbapt                    if (value == BAD_VALUE)
837230237Sbapt                      {
838230237Sbapt                        fprintf (stderr, "Invalid position value or range, use 1,2,3-%d,'$' or '*'.\n",
839230237Sbapt                                         Positions::MAX_KEY_POS);
840230237Sbapt                        short_usage (stderr);
841230237Sbapt                        exit (1);
842230237Sbapt                      }
843230237Sbapt                    if (key_pos - key_positions == Positions::MAX_SIZE)
844230237Sbapt                      {
845230237Sbapt                        /* More than Positions::MAX_SIZE key positions.
846230237Sbapt                           Since all key positions are in the range
847230237Sbapt                           0..Positions::MAX_KEY_POS-1 or == Positions::LASTCHAR,
848230237Sbapt                           there must be duplicates.  */
849230237Sbapt                        fprintf (stderr, "Duplicate key positions selected\n");
850230237Sbapt                        short_usage (stderr);
851230237Sbapt                        exit (1);
852230237Sbapt                      }
853230237Sbapt                    if (value != Positions::LASTCHAR)
854230237Sbapt                      /* We use 0-based indices in the class Positions.  */
855230237Sbapt                      value = value - 1;
856230237Sbapt                    *key_pos = value;
857230237Sbapt                  }
85858551Skris
859230237Sbapt                unsigned int total_keysig_size = key_pos - key_positions;
860230237Sbapt                if (total_keysig_size == 0)
86158551Skris                  {
862230237Sbapt                    fprintf (stderr, "No key positions selected.\n");
86358551Skris                    short_usage (stderr);
86458551Skris                    exit (1);
86558551Skris                  }
866230237Sbapt                _key_positions.set_size (total_keysig_size);
867230237Sbapt
868230237Sbapt                /* Sorts the key positions *IN REVERSE ORDER!!*
869230237Sbapt                   This makes further routines more efficient.  Especially
870230237Sbapt                   when generating code.  */
871230237Sbapt                if (! _key_positions.sort())
87258551Skris                  {
873230237Sbapt                    fprintf (stderr, "Duplicate key positions selected\n");
87458551Skris                    short_usage (stderr);
87558551Skris                    exit (1);
87658551Skris                  }
87758551Skris              }
87858551Skris            break;
87958551Skris          }
880230237Sbapt        case 'K':               /* Make this the keyname for the keyword component field.  */
88158551Skris          {
882230237Sbapt            _slot_name = /*getopt*/optarg;
88358551Skris            break;
88458551Skris          }
885230237Sbapt        case 'l':               /* Create length table to avoid extra string compares.  */
88658551Skris          {
887230237Sbapt            _option_word |= LENTABLE;
88858551Skris            break;
88958551Skris          }
890230237Sbapt        case 'L':               /* Deal with different generated languages.  */
89158551Skris          {
892230237Sbapt            _language = NULL;
893230237Sbapt            set_language (/*getopt*/optarg);
894230237Sbapt            break;
895230237Sbapt          }
896230237Sbapt        case 'm':               /* Multiple iterations for finding good asso_values.  */
897230237Sbapt          {
898230237Sbapt            if ((_asso_iterations = atoi (/*getopt*/optarg)) < 0)
89958551Skris              {
900230237Sbapt                fprintf (stderr, "asso_iterations value must not be negative, assuming 0\n");
901230237Sbapt                _asso_iterations = 0;
90258551Skris              }
90358551Skris            break;
90458551Skris          }
905230237Sbapt        case 'n':               /* Don't include the length when computing hash function.  */
90658551Skris          {
907230237Sbapt            _option_word |= NOLENGTH;
90858551Skris            break;
90958551Skris          }
910230237Sbapt        case 'N':               /* Make generated lookup function name be optarg.  */
91158551Skris          {
912230237Sbapt            _function_name = /*getopt*/optarg;
91358551Skris            break;
91458551Skris          }
915230237Sbapt        case 'o':               /* Order input by frequency of key set occurrence.  */
916230237Sbapt          break;                /* Not needed any more.  */
917230237Sbapt        case 'O':               /* Optimized choice during collision resolution.  */
918230237Sbapt          break;                /* Not needed any more.  */
919230237Sbapt        case 'p':               /* Generated lookup function a pointer instead of int.  */
920230237Sbapt          break;                /* This is now the default.  */
921230237Sbapt        case 'P':               /* Optimize for position-independent code.  */
92258551Skris          {
923230237Sbapt            _option_word |= SHAREDLIB;
92458551Skris            break;
92558551Skris          }
926230237Sbapt        case 'Q':               /* Sets the name for the string pool.  */
92758551Skris          {
928230237Sbapt            _stringpool_name = /*getopt*/optarg;
92958551Skris            break;
93058551Skris          }
931230237Sbapt        case 'r':               /* Utilize randomness to initialize the associated values table.  */
93258551Skris          {
933230237Sbapt            _option_word |= RANDOM;
934230237Sbapt            if (_initial_asso_value != 0)
935230237Sbapt              fprintf (stderr, "warning, -r option supersedes -i, disabling -i option and continuing\n");
93658551Skris            break;
93758551Skris          }
938230237Sbapt        case 's':               /* Range of associated values, determines size of final table.  */
93958551Skris          {
940230237Sbapt            float numerator;
941230237Sbapt            float denominator = 1;
942230237Sbapt            bool invalid = false;
943230237Sbapt            char *endptr;
944230237Sbapt
945230237Sbapt            numerator = strtod (/*getopt*/optarg, &endptr);
946230237Sbapt            if (endptr == /*getopt*/optarg)
947230237Sbapt              invalid = true;
948230237Sbapt            else if (*endptr != '\0')
94958551Skris              {
950230237Sbapt                if (*endptr == '/')
951230237Sbapt                  {
952230237Sbapt                    char *denomptr = endptr + 1;
953230237Sbapt                    denominator = strtod (denomptr, &endptr);
954230237Sbapt                    if (endptr == denomptr || *endptr != '\0')
955230237Sbapt                      invalid = true;
956230237Sbapt                  }
957230237Sbapt                else
958230237Sbapt                  invalid = true;
959230237Sbapt              }
960230237Sbapt            if (invalid)
961230237Sbapt              {
962230237Sbapt                fprintf (stderr, "Invalid value for option -s.\n");
963230237Sbapt                short_usage (stderr);
964230237Sbapt                exit (1);
965230237Sbapt              }
966230237Sbapt            _size_multiple = numerator / denominator;
967230237Sbapt            /* Backward compatibility: -3 means 1/3.  */
968230237Sbapt            if (_size_multiple < 0)
969230237Sbapt              _size_multiple = 1 / (-_size_multiple);
970230237Sbapt            /* Catch stupid users.  */
971230237Sbapt            if (_size_multiple == 0)
972230237Sbapt              _size_multiple = 1;
973230237Sbapt            /* Warnings.  */
974230237Sbapt            if (_size_multiple > 50)
975230237Sbapt              fprintf (stderr, "Size multiple %g is excessive, did you really mean this?! (try '%s --help' for help)\n", _size_multiple, program_name);
976230237Sbapt            else if (_size_multiple < 0.01f)
977230237Sbapt              fprintf (stderr, "Size multiple %g is extremely small, did you really mean this?! (try '%s --help' for help)\n", _size_multiple, program_name);
978230237Sbapt            break;
979230237Sbapt          }
980230237Sbapt        case 'S':               /* Generate switch statement output, rather than lookup table.  */
981230237Sbapt          {
982230237Sbapt            _option_word |= SWITCH;
983230237Sbapt            _total_switches = atoi (/*getopt*/optarg);
984230237Sbapt            if (_total_switches <= 0)
985230237Sbapt              {
98658551Skris                fprintf (stderr, "number of switches %s must be a positive number\n", /*getopt*/optarg);
98758551Skris                short_usage (stderr);
98858551Skris                exit (1);
98958551Skris              }
99058551Skris            break;
99158551Skris          }
992230237Sbapt        case 't':               /* Enable the TYPE mode, allowing arbitrary user structures.  */
99358551Skris          {
994230237Sbapt            _option_word |= TYPE;
99558551Skris            break;
99658551Skris          }
997230237Sbapt        case 'T':               /* Don't print structure definition.  */
99858551Skris          {
999230237Sbapt            _option_word |= NOTYPE;
100058551Skris            break;
100158551Skris          }
1002230237Sbapt        case 'v':               /* Print out the version and quit.  */
100358551Skris          fprintf (stdout, "GNU gperf %s\n", version_string);
1004230237Sbapt          fprintf (stdout, "Copyright (C) %s Free Software Foundation, Inc.\n\
1005230237SbaptThis is free software; see the source for copying conditions.  There is NO\n\
1006230237Sbaptwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
1007230237Sbapt",
1008230237Sbapt                   "1989-1998, 2000-2004, 2006-2007");
1009230237Sbapt          fprintf (stdout, "Written by %s and %s.\n",
1010230237Sbapt                   "Douglas C. Schmidt", "Bruno Haible");
101158551Skris          exit (0);
1012230237Sbapt        case 'W':               /* Sets the name for the hash table array.  */
101358551Skris          {
1014230237Sbapt            _wordlist_name = /*getopt*/optarg;
101558551Skris            break;
101658551Skris          }
1017230237Sbapt        case 'Z':               /* Set the class name.  */
101858551Skris          {
1019230237Sbapt            _class_name = /*getopt*/optarg;
102058551Skris            break;
102158551Skris          }
1022230237Sbapt        case '7':               /* Assume 7-bit characters.  */
102358551Skris          {
1024230237Sbapt            _option_word |= SEVENBIT;
102558551Skris            break;
102658551Skris          }
1027230237Sbapt        case CHAR_MAX + 1:      /* Set the output file name.  */
1028230237Sbapt          {
1029230237Sbapt            _output_file_name = /*getopt*/optarg;
1030230237Sbapt            break;
1031230237Sbapt          }
1032230237Sbapt        case CHAR_MAX + 2:      /* Case insignificant.  */
1033230237Sbapt          {
1034230237Sbapt            _option_word |= UPPERLOWER;
1035230237Sbapt            break;
1036230237Sbapt          }
1037230237Sbapt        case CHAR_MAX + 3:      /* Use NULL instead of "".  */
1038230237Sbapt          {
1039230237Sbapt            _option_word |= NULLSTRINGS;
1040230237Sbapt            break;
1041230237Sbapt          }
1042230237Sbapt        case CHAR_MAX + 4:      /* Sets the name for the length table array.  */
1043230237Sbapt          {
1044230237Sbapt            _lengthtable_name = /*getopt*/optarg;
1045230237Sbapt            break;
1046230237Sbapt          }
104758551Skris        default:
104858551Skris          short_usage (stderr);
104958551Skris          exit (1);
105058551Skris        }
105158551Skris
105258551Skris    }
105358551Skris
1054230237Sbapt  if (/*getopt*/optind < argc)
1055230237Sbapt    _input_file_name = argv[/*getopt*/optind++];
105658551Skris
1057230237Sbapt  if (/*getopt*/optind < argc)
105858551Skris    {
105958551Skris      fprintf (stderr, "Extra trailing arguments to %s.\n", program_name);
106058551Skris      short_usage (stderr);
106158551Skris      exit (1);
106258551Skris    }
106358551Skris}
106458551Skris
1065230237Sbapt/* ------------------------------------------------------------------------- */
1066230237Sbapt
106758551Skris#ifndef __OPTIMIZE__
106858551Skris
106958551Skris#define INLINE /* not inline */
107058551Skris#include "options.icc"
107158551Skris#undef INLINE
107258551Skris
107358551Skris#endif /* not defined __OPTIMIZE__ */
1074