158551Skris/* Handles parsing the Options provided to the user.
2228060Sbapt   Copyright (C) 1989-1998, 2000, 2002-2004, 2006-2007 Free Software Foundation, Inc.
3228060Sbapt   Written by Douglas C. Schmidt <schmidt@ics.uci.edu>
4228060Sbapt   and Bruno Haible <bruno@clisp.org>.
558551Skris
6228060Sbapt   This file is part of GNU GPERF.
758551Skris
8228060Sbapt   GNU GPERF is free software; you can redistribute it and/or modify
9228060Sbapt   it under the terms of the GNU General Public License as published by
10228060Sbapt   the Free Software Foundation; either version 2, or (at your option)
11228060Sbapt   any later version.
1258551Skris
13228060Sbapt   GNU GPERF is distributed in the hope that it will be useful,
14228060Sbapt   but WITHOUT ANY WARRANTY; without even the implied warranty of
15228060Sbapt   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16228060Sbapt   GNU General Public License for more details.
1758551Skris
18228060Sbapt   You should have received a copy of the GNU General Public License
19228060Sbapt   along with this program; see the file COPYING.
20228060Sbapt   If not, write to the Free Software Foundation, Inc.,
21228060Sbapt   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
2258551Skris
23228060Sbapt/* Specification. */
24228060Sbapt#include "options.h"
25228060Sbapt
2658551Skris#include <stdio.h>
2758551Skris#include <stdlib.h> /* declares atoi(), abs(), exit() */
2858551Skris#include <string.h> /* declares strcmp() */
29228060Sbapt#include <ctype.h>  /* declares isdigit() */
30228060Sbapt#include <limits.h> /* defines CHAR_MAX */
3158551Skris#include "getopt.h"
3258551Skris#include "version.h"
3358551Skris
34228060Sbapt/* Global option coordinator for the entire program.  */
3558551SkrisOptions option;
3658551Skris
37228060Sbapt/* Records the program name.  */
3858551Skrisconst char *program_name;
3958551Skris
40228060Sbapt/* Size to jump on a collision.  */
4158551Skrisstatic const int DEFAULT_JUMP_VALUE = 5;
4258551Skris
43228060Sbapt/* Default name for generated lookup function.  */
44228060Sbaptstatic const char *const DEFAULT_FUNCTION_NAME = "in_word_set";
4558551Skris
46228060Sbapt/* Default name for the key component.  */
47228060Sbaptstatic const char *const DEFAULT_SLOT_NAME = "name";
4858551Skris
49228060Sbapt/* Default struct initializer suffix.  */
5067064Sobrienstatic const char *const DEFAULT_INITIALIZER_SUFFIX = "";
5167064Sobrien
52228060Sbapt/* Default name for the generated class.  */
5358551Skrisstatic const char *const DEFAULT_CLASS_NAME = "Perfect_Hash";
5458551Skris
55228060Sbapt/* Default name for generated hash function.  */
5658551Skrisstatic const char *const DEFAULT_HASH_NAME = "hash";
5758551Skris
58228060Sbapt/* Default name for generated hash table array.  */
5958551Skrisstatic const char *const DEFAULT_WORDLIST_NAME = "wordlist";
6058551Skris
61228060Sbapt/* Default name for generated length table array.  */
62228060Sbaptstatic const char *const DEFAULT_LENGTHTABLE_NAME = "lengthtable";
6358551Skris
64228060Sbapt/* Default name for string pool.  */
65228060Sbaptstatic const char *const DEFAULT_STRINGPOOL_NAME = "stringpool";
6658551Skris
67228060Sbapt/* Default delimiters that separate keywords from their attributes.  */
68228060Sbaptstatic const char *const DEFAULT_DELIMITERS = ",";
6958551Skris
70228060Sbapt/* Prints program usage to given stream.  */
71228060Sbapt
7258551Skrisvoid
73228060SbaptOptions::short_usage (FILE * stream)
7458551Skris{
75228060Sbapt  fprintf (stream,
76228060Sbapt           "Try '%s --help' for more information.\n", program_name);
7758551Skris}
7858551Skris
7958551Skrisvoid
80228060SbaptOptions::long_usage (FILE * stream)
8158551Skris{
82228060Sbapt  fprintf (stream,
83228060Sbapt           "GNU 'gperf' generates perfect hash functions.\n");
84228060Sbapt  fprintf (stream, "\n");
85228060Sbapt  fprintf (stream,
86228060Sbapt           "Usage: %s [OPTION]... [INPUT-FILE]\n",
87228060Sbapt           program_name);
88228060Sbapt  fprintf (stream, "\n");
89228060Sbapt  fprintf (stream,
9058551Skris           "If a long option shows an argument as mandatory, then it is mandatory\n"
91228060Sbapt           "for the equivalent short option also.\n");
92228060Sbapt  fprintf (stream, "\n");
93228060Sbapt  fprintf (stream,
94228060Sbapt           "Output file location:\n");
95228060Sbapt  fprintf (stream,
96228060Sbapt           "      --output-file=FILE Write output to specified file.\n");
97228060Sbapt  fprintf (stream,
98228060Sbapt           "The results are written to standard output if no output file is specified\n"
99228060Sbapt           "or if it is -.\n");
100228060Sbapt  fprintf (stream, "\n");
101228060Sbapt  fprintf (stream,
102228060Sbapt           "Input file interpretation:\n");
103228060Sbapt  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"
107228060Sbapt           "                         Default is \",\".\n");
108228060Sbapt  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"
113228060Sbapt           "                         group of fields per line.\n");
114228060Sbapt  fprintf (stream,
115228060Sbapt           "      --ignore-case      Consider upper and lower case ASCII characters as\n"
116228060Sbapt           "                         equivalent. Note that locale dependent case mappings\n"
117228060Sbapt           "                         are ignored.\n");
118228060Sbapt  fprintf (stream, "\n");
119228060Sbapt  fprintf (stream,
120228060Sbapt           "Language for the output code:\n");
121228060Sbapt  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"
125228060Sbapt           "                         default is C.\n");
126228060Sbapt  fprintf (stream, "\n");
127228060Sbapt  fprintf (stream,
128228060Sbapt           "Details in the output code:\n");
129228060Sbapt  fprintf (stream,
13058551Skris           "  -K, --slot-name=NAME   Select name of the keyword component in the keyword\n"
131228060Sbapt           "                         structure.\n");
132228060Sbapt  fprintf (stream,
13367064Sobrien           "  -F, --initializer-suffix=INITIALIZERS\n"
13467064Sobrien           "                         Initializers for additional components in the keyword\n"
135228060Sbapt           "                         structure.\n");
136228060Sbapt  fprintf (stream,
137228060Sbapt           "  -H, --hash-function-name=NAME\n"
13858551Skris           "                         Specify name of generated hash function. Default is\n"
139228060Sbapt           "                         'hash'.\n");
140228060Sbapt  fprintf (stream,
141228060Sbapt           "  -N, --lookup-function-name=NAME\n"
14258551Skris           "                         Specify name of generated lookup function. Default\n"
143228060Sbapt           "                         name is 'in_word_set'.\n");
144228060Sbapt  fprintf (stream,
14558551Skris           "  -Z, --class-name=NAME  Specify name of generated C++ class. Default name is\n"
146228060Sbapt           "                         'Perfect_Hash'.\n");
147228060Sbapt  fprintf (stream,
148228060Sbapt           "  -7, --seven-bit        Assume 7-bit characters.\n");
149228060Sbapt  fprintf (stream,
150228060Sbapt           "  -l, --compare-lengths  Compare key lengths before trying a string\n"
151228060Sbapt           "                         comparison. This is necessary if the keywords\n"
152228060Sbapt           "                         contain NUL bytes. It also helps cut down on the\n"
153228060Sbapt           "                         number of string comparisons made during the lookup.\n");
154228060Sbapt  fprintf (stream,
15558551Skris           "  -c, --compare-strncmp  Generate comparison code using strncmp rather than\n"
156228060Sbapt           "                         strcmp.\n");
157228060Sbapt  fprintf (stream,
15858551Skris           "  -C, --readonly-tables  Make the contents of generated lookup tables\n"
159228060Sbapt           "                         constant, i.e., readonly.\n");
160228060Sbapt  fprintf (stream,
16158551Skris           "  -E, --enum             Define constant values using an enum local to the\n"
162228060Sbapt           "                         lookup function rather than with defines.\n");
163228060Sbapt  fprintf (stream,
16458551Skris           "  -I, --includes         Include the necessary system include file <string.h>\n"
165228060Sbapt           "                         at the beginning of the code.\n");
166228060Sbapt  fprintf (stream,
167228060Sbapt           "  -G, --global-table     Generate the static table of keywords as a static\n"
16858551Skris           "                         global variable, rather than hiding it inside of the\n"
169228060Sbapt           "                         lookup function (which is the default behavior).\n");
170228060Sbapt  fprintf (stream,
171228060Sbapt           "  -P, --pic              Optimize the generated table for inclusion in shared\n"
172228060Sbapt           "                         libraries.  This reduces the startup time of programs\n"
173228060Sbapt           "                         using a shared library containing the generated code.\n");
174228060Sbapt  fprintf (stream,
175228060Sbapt           "  -Q, --string-pool-name=NAME\n"
176228060Sbapt           "                         Specify name of string pool generated by option --pic.\n"
177228060Sbapt           "                         Default name is 'stringpool'.\n");
178228060Sbapt  fprintf (stream,
179228060Sbapt           "      --null-strings     Use NULL strings instead of empty strings for empty\n"
180228060Sbapt           "                         keyword table entries.\n");
181228060Sbapt  fprintf (stream,
18258551Skris           "  -W, --word-array-name=NAME\n"
18358551Skris           "                         Specify name of word list array. Default name is\n"
184228060Sbapt           "                         'wordlist'.\n");
185228060Sbapt  fprintf (stream,
186228060Sbapt           "      --length-table-name=NAME\n"
187228060Sbapt           "                         Specify name of length table array. Default name is\n"
188228060Sbapt           "                         'lengthtable'.\n");
189228060Sbapt  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"
199228060Sbapt           "                         binary search.\n");
200228060Sbapt  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"
204228060Sbapt           "                         defined elsewhere.\n");
205228060Sbapt  fprintf (stream, "\n");
206228060Sbapt  fprintf (stream,
207228060Sbapt           "Algorithm employed by gperf:\n");
208228060Sbapt  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"
216228060Sbapt           "                         indicates the \"final character\" of a key, e.g.,\n"
217228060Sbapt           "                         $,1,2,4,6-10.\n",
218228060Sbapt           Positions::MAX_KEY_POS);
219228060Sbapt  fprintf (stream,
22058551Skris           "  -D, --duplicates       Handle keywords that hash to duplicate values. This\n"
221228060Sbapt           "                         is useful for certain highly redundant keyword sets.\n");
222228060Sbapt  fprintf (stream,
223228060Sbapt           "  -m, --multiple-iterations=ITERATIONS\n"
224228060Sbapt           "                         Perform multiple choices of the -i and -j values,\n"
225228060Sbapt           "                         and choose the best results. This increases the\n"
226228060Sbapt           "                         running time by a factor of ITERATIONS but does a\n"
227228060Sbapt           "                         good job minimizing the generated table size.\n");
228228060Sbapt  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"
231228060Sbapt           "                         inflate the size of the final table.\n");
232228060Sbapt  fprintf (stream,
233228060Sbapt           "  -j, --jump=JUMP-VALUE  Affects the \"jump value\", i.e., how far to advance\n"
23458551Skris           "                         the associated character value upon collisions. Must\n"
235228060Sbapt           "                         be an odd number, default is %d.\n",
236228060Sbapt           DEFAULT_JUMP_VALUE);
237228060Sbapt  fprintf (stream,
23858551Skris           "  -n, --no-strlen        Do not include the length of the keyword when\n"
239228060Sbapt           "                         computing the hash function.\n");
240228060Sbapt  fprintf (stream,
24158551Skris           "  -r, --random           Utilizes randomness to initialize the associated\n"
242228060Sbapt           "                         values table.\n");
243228060Sbapt  fprintf (stream,
24458551Skris           "  -s, --size-multiple=N  Affects the size of the generated hash table. The\n"
245228060Sbapt           "                         numeric argument N indicates \"how many times larger\n"
246228060Sbapt           "                         or smaller\" the associated value range should be,\n"
24758551Skris           "                         in relationship to the number of keys, e.g. a value\n"
248228060Sbapt           "                         of 3 means \"allow the maximum associated value to\n"
24958551Skris           "                         be about 3 times larger than the number of input\n"
250228060Sbapt           "                         keys\". Conversely, a value of 1/3 means \"make the\n"
25158551Skris           "                         maximum associated value about 3 times smaller than\n"
252228060Sbapt           "                         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"
255228060Sbapt           "                         value is 1.\n");
256228060Sbapt  fprintf (stream, "\n");
257228060Sbapt  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"
262228060Sbapt           "                         output to the standard error).\n");
263228060Sbapt  fprintf (stream, "\n");
264228060Sbapt  fprintf (stream,
265228060Sbapt           "Report bugs to <bug-gnu-gperf@gnu.org>.\n");
26658551Skris}
26758551Skris
268228060Sbapt/* Prints the given options.  */
26958551Skris
27058551Skrisvoid
271228060SbaptOptions::print_options () const
27258551Skris{
27358551Skris  printf ("/* Command-line: ");
27458551Skris
275228060Sbapt  for (int i = 0; i < _argument_count; i++)
27667064Sobrien    {
277228060Sbapt      const char *arg = _argument_vector[i];
27858551Skris
279228060Sbapt      /* Escape arg if it contains shell metacharacters.  */
28067064Sobrien      if (*arg == '-')
28167064Sobrien        {
28267064Sobrien          putchar (*arg);
28367064Sobrien          arg++;
284228060Sbapt          if (*arg >= 'A' && *arg <= 'Z' || *arg >= 'a' && *arg <= 'z')
28567064Sobrien            {
28667064Sobrien              putchar (*arg);
28767064Sobrien              arg++;
28867064Sobrien            }
289228060Sbapt          else if (*arg == '-')
290228060Sbapt            {
291228060Sbapt              do
292228060Sbapt                {
293228060Sbapt                  putchar (*arg);
294228060Sbapt                  arg++;
295228060Sbapt                }
296228060Sbapt              while (*arg >= 'A' && *arg <= 'Z' || *arg >= 'a' && *arg <= 'z' || *arg == '-');
297228060Sbapt              if (*arg == '=')
298228060Sbapt                {
299228060Sbapt                  putchar (*arg);
300228060Sbapt                  arg++;
301228060Sbapt                }
302228060Sbapt            }
30367064Sobrien        }
30467064Sobrien      if (strpbrk (arg, "\t\n !\"#$&'()*;<>?[\\]`{|}~") != NULL)
30567064Sobrien        {
30667064Sobrien          if (strchr (arg, '\'') != NULL)
30767064Sobrien            {
30867064Sobrien              putchar ('"');
30967064Sobrien              for (; *arg; arg++)
31067064Sobrien                {
311228060Sbapt                  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
338228060Sbapt/* ------------------------------------------------------------------------- */
33958551Skris
340228060Sbapt/* Parses a string denoting key positions.  */
341228060Sbapt
342228060Sbaptclass PositionStringParser
34358551Skris{
344228060Sbaptpublic:
345228060Sbapt  /* Initializes a key position string parser for string STR.  */
346228060Sbapt                        PositionStringParser (const char *str,
347228060Sbapt                                              int low_bound, int high_bound,
348228060Sbapt                                              int end_word_marker, int error_value, int end_marker);
349228060Sbapt  /* Returns the next key position from the given string.  */
350228060Sbapt  int                   nextPosition ();
351228060Sbaptprivate:
352228060Sbapt  /* A pointer to the string provided by the user.  */
353228060Sbapt  const char *          _str;
354228060Sbapt  /* Smallest possible value, inclusive.  */
355228060Sbapt  int const             _low_bound;
356228060Sbapt  /* Greatest possible value, inclusive.  */
357228060Sbapt  int const             _high_bound;
358228060Sbapt  /* A value marking the abstract "end of word" ( usually '$').  */
359228060Sbapt  int const             _end_word_marker;
360228060Sbapt  /* Error value returned when input is syntactically erroneous.  */
361228060Sbapt  int const             _error_value;
362228060Sbapt  /* Value returned after last key is processed.  */
363228060Sbapt  int const             _end_marker;
364228060Sbapt  /* Intermediate state for producing a range of positions.  */
365228060Sbapt  bool                  _in_range;           /* True while producing a range of positions.  */
366228060Sbapt  int                   _range_upper_bound;  /* Upper bound (inclusive) of the range.  */
367228060Sbapt  int                   _range_curr_value;   /* Last value returned.  */
368228060Sbapt};
36958551Skris
370228060Sbapt/* Initializes a key position strng parser for string STR.  */
371228060SbaptPositionStringParser::PositionStringParser (const char *str,
372228060Sbapt                                            int low_bound, int high_bound,
373228060Sbapt                                            int end_word_marker, int error_value, int end_marker)
374228060Sbapt  : _str (str),
375228060Sbapt    _low_bound (low_bound),
376228060Sbapt    _high_bound (high_bound),
377228060Sbapt    _end_word_marker (end_word_marker),
378228060Sbapt    _error_value (error_value),
379228060Sbapt    _end_marker (end_marker),
380228060Sbapt    _in_range (false)
381228060Sbapt{
382228060Sbapt}
383228060Sbapt
384228060Sbapt/* Returns the next key position from the given string.  */
385228060Sbaptint
386228060SbaptPositionStringParser::nextPosition ()
387228060Sbapt{
388228060Sbapt  if (_in_range)
38958551Skris    {
390228060Sbapt      /* We are inside a range.  Return the next value from the range.  */
391228060Sbapt      if (++_range_curr_value >= _range_upper_bound)
392228060Sbapt        _in_range = false;
393228060Sbapt      return _range_curr_value;
394228060Sbapt    }
395228060Sbapt  else
396228060Sbapt    {
397228060Sbapt      /* Continue parsing the given string.  */
398228060Sbapt      while (*_str)
399228060Sbapt        switch (*_str)
400228060Sbapt          {
401228060Sbapt          case ',':
402228060Sbapt            /* Skip the comma.  */
403228060Sbapt            _str++;
404228060Sbapt            break;
405228060Sbapt          case '$':
406228060Sbapt            /* Valid key position.  */
407228060Sbapt            _str++;
408228060Sbapt            return _end_word_marker;
409228060Sbapt          case '0': case '1': case '2': case '3': case '4':
410228060Sbapt          case '5': case '6': case '7': case '8': case '9':
411228060Sbapt            /* Valid key position.  */
412228060Sbapt            {
413228060Sbapt              int curr_value;
414228060Sbapt              for (curr_value = 0; isdigit (static_cast<unsigned char>(*_str)); _str++)
415228060Sbapt                curr_value = curr_value * 10 + (*_str - '0');
41658551Skris
417228060Sbapt              if (*_str == '-')
418228060Sbapt                {
419228060Sbapt                  _str++;
420228060Sbapt                  /* Starting a range of key positions.  */
421228060Sbapt                  _in_range = true;
42258551Skris
423228060Sbapt                  for (_range_upper_bound = 0;
424228060Sbapt                       isdigit (static_cast<unsigned char>(*_str));
425228060Sbapt                       _str++)
426228060Sbapt                    _range_upper_bound = _range_upper_bound * 10 + (*_str - '0');
427228060Sbapt
428228060Sbapt                  /* Verify range's upper bound.  */
429228060Sbapt                  if (!(_range_upper_bound > curr_value && _range_upper_bound <= _high_bound))
430228060Sbapt                    return _error_value;
431228060Sbapt                  _range_curr_value = curr_value;
432228060Sbapt                }
433228060Sbapt
434228060Sbapt              /* Verify range's lower bound.  */
435228060Sbapt              if (!(curr_value >= _low_bound && curr_value <= _high_bound))
436228060Sbapt                return _error_value;
437228060Sbapt              return curr_value;
438228060Sbapt            }
439228060Sbapt          default:
440228060Sbapt            /* Invalid syntax.  */
441228060Sbapt            return _error_value;
442228060Sbapt          }
443228060Sbapt
444228060Sbapt      return _end_marker;
44558551Skris    }
44658551Skris}
44758551Skris
448228060Sbapt/* ------------------------------------------------------------------------- */
44958551Skris
450228060Sbapt/* Sets the default Options.  */
451228060Sbapt
452228060SbaptOptions::Options ()
453228060Sbapt  : _option_word (C),
454228060Sbapt    _input_file_name (NULL),
455228060Sbapt    _output_file_name (NULL),
456228060Sbapt    _language (NULL),
457228060Sbapt    _jump (DEFAULT_JUMP_VALUE),
458228060Sbapt    _initial_asso_value (0),
459228060Sbapt    _asso_iterations (0),
460228060Sbapt    _total_switches (1),
461228060Sbapt    _size_multiple (1),
462228060Sbapt    _function_name (DEFAULT_FUNCTION_NAME),
463228060Sbapt    _slot_name (DEFAULT_SLOT_NAME),
464228060Sbapt    _initializer_suffix (DEFAULT_INITIALIZER_SUFFIX),
465228060Sbapt    _class_name (DEFAULT_CLASS_NAME),
466228060Sbapt    _hash_name (DEFAULT_HASH_NAME),
467228060Sbapt    _wordlist_name (DEFAULT_WORDLIST_NAME),
468228060Sbapt    _lengthtable_name (DEFAULT_LENGTHTABLE_NAME),
469228060Sbapt    _stringpool_name (DEFAULT_STRINGPOOL_NAME),
470228060Sbapt    _delimiters (DEFAULT_DELIMITERS),
471228060Sbapt    _key_positions ()
47258551Skris{
47358551Skris}
47458551Skris
475228060Sbapt/* Dumps option status when debugging is enabled.  */
47658551Skris
477228060SbaptOptions::~Options ()
47858551Skris{
479228060Sbapt  if (_option_word & DEBUG)
48058551Skris    {
48158551Skris      fprintf (stderr, "\ndumping Options:"
48258551Skris               "\nTYPE is........: %s"
483228060Sbapt               "\nUPPERLOWER is..: %s"
48458551Skris               "\nKRC is.........: %s"
48558551Skris               "\nC is...........: %s"
48658551Skris               "\nANSIC is.......: %s"
48758551Skris               "\nCPLUSPLUS is...: %s"
488228060Sbapt               "\nSEVENBIT is....: %s"
489228060Sbapt               "\nLENTABLE is....: %s"
490228060Sbapt               "\nCOMP is........: %s"
491228060Sbapt               "\nCONST is.......: %s"
49258551Skris               "\nENUM is........: %s"
49358551Skris               "\nINCLUDE is.....: %s"
494228060Sbapt               "\nGLOBAL is......: %s"
495228060Sbapt               "\nNULLSTRINGS is.: %s"
496228060Sbapt               "\nSHAREDLIB is...: %s"
497228060Sbapt               "\nSWITCH is......: %s"
498228060Sbapt               "\nNOTYPE is......: %s"
499228060Sbapt               "\nDUP is.........: %s"
500228060Sbapt               "\nNOLENGTH is....: %s"
501228060Sbapt               "\nRANDOM is......: %s"
502228060Sbapt               "\nDEBUG is.......: %s"
50358551Skris               "\nlookup function name = %s"
50458551Skris               "\nhash function name = %s"
50558551Skris               "\nword list name = %s"
506228060Sbapt               "\nlength table name = %s"
507228060Sbapt               "\nstring pool name = %s"
508228060Sbapt               "\nslot name = %s"
50967064Sobrien               "\ninitializer suffix = %s"
510228060Sbapt               "\nasso_values iterations = %d"
51158551Skris               "\njump value = %d"
512228060Sbapt               "\nhash table size multiplier = %g"
51358551Skris               "\ninitial associated value = %d"
51458551Skris               "\ndelimiters = %s"
51558551Skris               "\nnumber of switch statements = %d\n",
516228060Sbapt               _option_word & TYPE ? "enabled" : "disabled",
517228060Sbapt               _option_word & UPPERLOWER ? "enabled" : "disabled",
518228060Sbapt               _option_word & KRC ? "enabled" : "disabled",
519228060Sbapt               _option_word & C ? "enabled" : "disabled",
520228060Sbapt               _option_word & ANSIC ? "enabled" : "disabled",
521228060Sbapt               _option_word & CPLUSPLUS ? "enabled" : "disabled",
522228060Sbapt               _option_word & SEVENBIT ? "enabled" : "disabled",
523228060Sbapt               _option_word & LENTABLE ? "enabled" : "disabled",
524228060Sbapt               _option_word & COMP ? "enabled" : "disabled",
525228060Sbapt               _option_word & CONST ? "enabled" : "disabled",
526228060Sbapt               _option_word & ENUM ? "enabled" : "disabled",
527228060Sbapt               _option_word & INCLUDE ? "enabled" : "disabled",
528228060Sbapt               _option_word & GLOBAL ? "enabled" : "disabled",
529228060Sbapt               _option_word & NULLSTRINGS ? "enabled" : "disabled",
530228060Sbapt               _option_word & SHAREDLIB ? "enabled" : "disabled",
531228060Sbapt               _option_word & SWITCH ? "enabled" : "disabled",
532228060Sbapt               _option_word & NOTYPE ? "enabled" : "disabled",
533228060Sbapt               _option_word & DUP ? "enabled" : "disabled",
534228060Sbapt               _option_word & NOLENGTH ? "enabled" : "disabled",
535228060Sbapt               _option_word & RANDOM ? "enabled" : "disabled",
536228060Sbapt               _option_word & DEBUG ? "enabled" : "disabled",
537228060Sbapt               _function_name, _hash_name, _wordlist_name, _lengthtable_name,
538228060Sbapt               _stringpool_name, _slot_name, _initializer_suffix,
539228060Sbapt               _asso_iterations, _jump, _size_multiple, _initial_asso_value,
540228060Sbapt               _delimiters, _total_switches);
541228060Sbapt      if (_key_positions.is_useall())
54258551Skris        fprintf (stderr, "all characters are used in the hash function\n");
543228060Sbapt      else
544228060Sbapt        {
545228060Sbapt          fprintf (stderr, "maximum keysig size = %d\nkey positions are: \n",
546228060Sbapt                   _key_positions.get_size());
54758551Skris
548228060Sbapt          PositionIterator iter = _key_positions.iterator();
549228060Sbapt          for (int pos; (pos = iter.next()) != PositionIterator::EOS; )
550228060Sbapt            if (pos == Positions::LASTCHAR)
551228060Sbapt              fprintf (stderr, "$\n");
552228060Sbapt            else
553228060Sbapt              fprintf (stderr, "%d\n", pos + 1);
554228060Sbapt        }
55558551Skris
55658551Skris      fprintf (stderr, "finished dumping Options\n");
55758551Skris    }
55858551Skris}
55958551Skris
56058551Skris
561228060Sbapt/* Sets the output language, if not already set.  */
562228060Sbaptvoid
563228060SbaptOptions::set_language (const char *language)
564228060Sbapt{
565228060Sbapt  if (_language == NULL)
566228060Sbapt    {
567228060Sbapt      _language = language;
568228060Sbapt      _option_word &= ~(KRC | C | ANSIC | CPLUSPLUS);
569228060Sbapt      if (!strcmp (language, "KR-C"))
570228060Sbapt        _option_word |= KRC;
571228060Sbapt      else if (!strcmp (language, "C"))
572228060Sbapt        _option_word |= C;
573228060Sbapt      else if (!strcmp (language, "ANSI-C"))
574228060Sbapt        _option_word |= ANSIC;
575228060Sbapt      else if (!strcmp (language, "C++"))
576228060Sbapt        _option_word |= CPLUSPLUS;
577228060Sbapt      else
578228060Sbapt        {
579228060Sbapt          fprintf (stderr, "unsupported language option %s, defaulting to C\n",
580228060Sbapt                   language);
581228060Sbapt          _option_word |= C;
582228060Sbapt        }
583228060Sbapt    }
584228060Sbapt}
58558551Skris
586228060Sbapt/* Sets the total number of switch statements, if not already set.  */
587228060Sbaptvoid
588228060SbaptOptions::set_total_switches (int total_switches)
589228060Sbapt{
590228060Sbapt  if (!(_option_word & SWITCH))
591228060Sbapt    {
592228060Sbapt      _option_word |= SWITCH;
593228060Sbapt      _total_switches = total_switches;
594228060Sbapt    }
595228060Sbapt}
596228060Sbapt
597228060Sbapt/* Sets the generated function name, if not already set.  */
598228060Sbaptvoid
599228060SbaptOptions::set_function_name (const char *name)
600228060Sbapt{
601228060Sbapt  if (_function_name == DEFAULT_FUNCTION_NAME)
602228060Sbapt    _function_name = name;
603228060Sbapt}
604228060Sbapt
605228060Sbapt/* Sets the keyword key name, if not already set.  */
606228060Sbaptvoid
607228060SbaptOptions::set_slot_name (const char *name)
608228060Sbapt{
609228060Sbapt  if (_slot_name == DEFAULT_SLOT_NAME)
610228060Sbapt    _slot_name = name;
611228060Sbapt}
612228060Sbapt
613228060Sbapt/* Sets the struct initializer suffix, if not already set.  */
614228060Sbaptvoid
615228060SbaptOptions::set_initializer_suffix (const char *initializers)
616228060Sbapt{
617228060Sbapt  if (_initializer_suffix == DEFAULT_INITIALIZER_SUFFIX)
618228060Sbapt    _initializer_suffix = initializers;
619228060Sbapt}
620228060Sbapt
621228060Sbapt/* Sets the generated class name, if not already set.  */
622228060Sbaptvoid
623228060SbaptOptions::set_class_name (const char *name)
624228060Sbapt{
625228060Sbapt  if (_class_name == DEFAULT_CLASS_NAME)
626228060Sbapt    _class_name = name;
627228060Sbapt}
628228060Sbapt
629228060Sbapt/* Sets the hash function name, if not already set.  */
630228060Sbaptvoid
631228060SbaptOptions::set_hash_name (const char *name)
632228060Sbapt{
633228060Sbapt  if (_hash_name == DEFAULT_HASH_NAME)
634228060Sbapt    _hash_name = name;
635228060Sbapt}
636228060Sbapt
637228060Sbapt/* Sets the hash table array name, if not already set.  */
638228060Sbaptvoid
639228060SbaptOptions::set_wordlist_name (const char *name)
640228060Sbapt{
641228060Sbapt  if (_wordlist_name == DEFAULT_WORDLIST_NAME)
642228060Sbapt    _wordlist_name = name;
643228060Sbapt}
644228060Sbapt
645228060Sbapt/* Sets the length table array name, if not already set.  */
646228060Sbaptvoid
647228060SbaptOptions::set_lengthtable_name (const char *name)
648228060Sbapt{
649228060Sbapt  if (_lengthtable_name == DEFAULT_LENGTHTABLE_NAME)
650228060Sbapt    _lengthtable_name = name;
651228060Sbapt}
652228060Sbapt
653228060Sbapt/* Sets the string pool name, if not already set.  */
654228060Sbaptvoid
655228060SbaptOptions::set_stringpool_name (const char *name)
656228060Sbapt{
657228060Sbapt  if (_stringpool_name == DEFAULT_STRINGPOOL_NAME)
658228060Sbapt    _stringpool_name = name;
659228060Sbapt}
660228060Sbapt
661228060Sbapt/* Sets the delimiters string, if not already set.  */
662228060Sbaptvoid
663228060SbaptOptions::set_delimiters (const char *delimiters)
664228060Sbapt{
665228060Sbapt  if (_delimiters == DEFAULT_DELIMITERS)
666228060Sbapt    _delimiters = delimiters;
667228060Sbapt}
668228060Sbapt
669228060Sbapt
670228060Sbapt/* Parses the command line Options and sets appropriate flags in option_word.  */
671228060Sbapt
67258551Skrisstatic const struct option long_options[] =
67358551Skris{
674228060Sbapt  { "output-file", required_argument, NULL, CHAR_MAX + 1 },
675228060Sbapt  { "ignore-case", no_argument, NULL, CHAR_MAX + 2 },
676228060Sbapt  { "delimiters", required_argument, NULL, 'e' },
677228060Sbapt  { "struct-type", no_argument, NULL, 't' },
678228060Sbapt  { "language", required_argument, NULL, 'L' },
679228060Sbapt  { "slot-name", required_argument, NULL, 'K' },
680228060Sbapt  { "initializer-suffix", required_argument, NULL, 'F' },
681228060Sbapt  { "hash-fn-name", required_argument, NULL, 'H' }, /* backward compatibility */
682228060Sbapt  { "hash-function-name", required_argument, NULL, 'H' },
683228060Sbapt  { "lookup-fn-name", required_argument, NULL, 'N' }, /* backward compatibility */
684228060Sbapt  { "lookup-function-name", required_argument, NULL, 'N' },
685228060Sbapt  { "class-name", required_argument, NULL, 'Z' },
686228060Sbapt  { "seven-bit", no_argument, NULL, '7' },
687228060Sbapt  { "compare-strncmp", no_argument, NULL, 'c' },
688228060Sbapt  { "readonly-tables", no_argument, NULL, 'C' },
689228060Sbapt  { "enum", no_argument, NULL, 'E' },
690228060Sbapt  { "includes", no_argument, NULL, 'I' },
691228060Sbapt  { "global-table", no_argument, NULL, 'G' },
692228060Sbapt  { "word-array-name", required_argument, NULL, 'W' },
693228060Sbapt  { "length-table-name", required_argument, NULL, CHAR_MAX + 4 },
694228060Sbapt  { "switch", required_argument, NULL, 'S' },
695228060Sbapt  { "omit-struct-type", no_argument, NULL, 'T' },
696228060Sbapt  { "key-positions", required_argument, NULL, 'k' },
697228060Sbapt  { "compare-strlen", no_argument, NULL, 'l' }, /* backward compatibility */
698228060Sbapt  { "compare-lengths", no_argument, NULL, 'l' },
699228060Sbapt  { "duplicates", no_argument, NULL, 'D' },
700228060Sbapt  { "fast", required_argument, NULL, 'f' },
701228060Sbapt  { "initial-asso", required_argument, NULL, 'i' },
702228060Sbapt  { "jump", required_argument, NULL, 'j' },
703228060Sbapt  { "multiple-iterations", required_argument, NULL, 'm' },
704228060Sbapt  { "no-strlen", no_argument, NULL, 'n' },
705228060Sbapt  { "occurrence-sort", no_argument, NULL, 'o' },
706228060Sbapt  { "optimized-collision-resolution", no_argument, NULL, 'O' },
707228060Sbapt  { "pic", no_argument, NULL, 'P' },
708228060Sbapt  { "string-pool-name", required_argument, NULL, 'Q' },
709228060Sbapt  { "null-strings", no_argument, NULL, CHAR_MAX + 3 },
710228060Sbapt  { "random", no_argument, NULL, 'r' },
711228060Sbapt  { "size-multiple", required_argument, NULL, 's' },
712228060Sbapt  { "help", no_argument, NULL, 'h' },
713228060Sbapt  { "version", no_argument, NULL, 'v' },
714228060Sbapt  { "debug", no_argument, NULL, 'd' },
715228060Sbapt  { NULL, no_argument, NULL, 0 }
71658551Skris};
71758551Skris
71858551Skrisvoid
719228060SbaptOptions::parse_options (int argc, char *argv[])
72058551Skris{
721228060Sbapt  int option_char;
72258551Skris
72358551Skris  program_name = argv[0];
724228060Sbapt  _argument_count  = argc;
725228060Sbapt  _argument_vector = argv;
72658551Skris
72758551Skris  while ((option_char =
728228060Sbapt            getopt_long (_argument_count, _argument_vector,
729228060Sbapt                         "acCdDe:Ef:F:gGhH:i:Ij:k:K:lL:m:nN:oOpPQ:rs:S:tTvW:Z:7",
730228060Sbapt                         long_options, NULL))
73158551Skris         != -1)
73258551Skris    {
73358551Skris      switch (option_char)
73458551Skris        {
735228060Sbapt        case 'a':               /* Generated code uses the ANSI prototype format.  */
736228060Sbapt          break;                /* This is now the default.  */
737228060Sbapt        case 'c':               /* Generate strncmp rather than strcmp.  */
73858551Skris          {
739228060Sbapt            _option_word |= COMP;
74058551Skris            break;
74158551Skris          }
742228060Sbapt        case 'C':               /* Make the generated tables readonly (const).  */
74358551Skris          {
744228060Sbapt            _option_word |= CONST;
74558551Skris            break;
74658551Skris          }
747228060Sbapt        case 'd':               /* Enable debugging option.  */
74858551Skris          {
749228060Sbapt            _option_word |= DEBUG;
75058551Skris            fprintf (stderr, "Starting program %s, version %s, with debugging on.\n",
75158551Skris                             program_name, version_string);
75258551Skris            break;
75358551Skris          }
754228060Sbapt        case 'D':               /* Enable duplicate option.  */
75558551Skris          {
756228060Sbapt            _option_word |= DUP;
75758551Skris            break;
75858551Skris          }
759228060Sbapt        case 'e':               /* Specify keyword/attribute separator */
76058551Skris          {
761228060Sbapt            _delimiters = /*getopt*/optarg;
76258551Skris            break;
76358551Skris          }
76458551Skris        case 'E':
76558551Skris          {
766228060Sbapt            _option_word |= ENUM;
76758551Skris            break;
76858551Skris          }
769228060Sbapt        case 'f':               /* Generate the hash table "fast".  */
770228060Sbapt          break;                /* Not needed any more.  */
77167064Sobrien        case 'F':
77267064Sobrien          {
773228060Sbapt            _initializer_suffix = /*getopt*/optarg;
77467064Sobrien            break;
77567064Sobrien          }
776228060Sbapt        case 'g':               /* Use the 'inline' keyword for generated sub-routines, ifdef __GNUC__.  */
777228060Sbapt          break;                /* This is now the default.  */
778228060Sbapt        case 'G':               /* Make the keyword table a global variable.  */
77958551Skris          {
780228060Sbapt            _option_word |= GLOBAL;
78158551Skris            break;
78258551Skris          }
783228060Sbapt        case 'h':               /* Displays a list of helpful Options to the user.  */
78458551Skris          {
78558551Skris            long_usage (stdout);
78658551Skris            exit (0);
78758551Skris          }
788228060Sbapt        case 'H':               /* Sets the name for the hash function.  */
78958551Skris          {
790228060Sbapt            _hash_name = /*getopt*/optarg;
79158551Skris            break;
79258551Skris          }
793228060Sbapt        case 'i':               /* Sets the initial value for the associated values array.  */
79458551Skris          {
795228060Sbapt            if ((_initial_asso_value = atoi (/*getopt*/optarg)) < 0)
796228060Sbapt              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          }
801228060Sbapt        case 'I':               /* Enable #include statements.  */
80258551Skris          {
803228060Sbapt            _option_word |= INCLUDE;
80458551Skris            break;
80558551Skris          }
806228060Sbapt        case 'j':               /* Sets the jump value, must be odd for later algorithms.  */
80758551Skris          {
808228060Sbapt            if ((_jump = atoi (/*getopt*/optarg)) < 0)
80958551Skris              {
810228060Sbapt                fprintf (stderr, "Jump value %d must be a positive number.\n", _jump);
81158551Skris                short_usage (stderr);
81258551Skris                exit (1);
81358551Skris              }
814228060Sbapt            else if (_jump && ((_jump % 2) == 0))
815228060Sbapt              fprintf (stderr, "Jump value %d should be odd, adding 1 and continuing...\n", _jump++);
81658551Skris            break;
81758551Skris          }
818228060Sbapt        case 'k':               /* Sets key positions used for hash function.  */
81958551Skris          {
820228060Sbapt            _option_word |= POSITIONS;
821228060Sbapt            const int BAD_VALUE = -3;
822228060Sbapt            const int EOS = PositionIterator::EOS;
82358551Skris            int       value;
824228060Sbapt            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!!!! */
827228060Sbapt              _key_positions.set_useall(true);
82858551Skris            else
82958551Skris              {
830228060Sbapt                _key_positions.set_useall(false);
831228060Sbapt                int *key_positions = _key_positions.pointer();
832228060Sbapt                int *key_pos;
83358551Skris
834228060Sbapt                for (key_pos = key_positions; (value = sparser.nextPosition()) != EOS; key_pos++)
835228060Sbapt                  {
836228060Sbapt                    if (value == BAD_VALUE)
837228060Sbapt                      {
838228060Sbapt                        fprintf (stderr, "Invalid position value or range, use 1,2,3-%d,'$' or '*'.\n",
839228060Sbapt                                         Positions::MAX_KEY_POS);
840228060Sbapt                        short_usage (stderr);
841228060Sbapt                        exit (1);
842228060Sbapt                      }
843228060Sbapt                    if (key_pos - key_positions == Positions::MAX_SIZE)
844228060Sbapt                      {
845228060Sbapt                        /* More than Positions::MAX_SIZE key positions.
846228060Sbapt                           Since all key positions are in the range
847228060Sbapt                           0..Positions::MAX_KEY_POS-1 or == Positions::LASTCHAR,
848228060Sbapt                           there must be duplicates.  */
849228060Sbapt                        fprintf (stderr, "Duplicate key positions selected\n");
850228060Sbapt                        short_usage (stderr);
851228060Sbapt                        exit (1);
852228060Sbapt                      }
853228060Sbapt                    if (value != Positions::LASTCHAR)
854228060Sbapt                      /* We use 0-based indices in the class Positions.  */
855228060Sbapt                      value = value - 1;
856228060Sbapt                    *key_pos = value;
857228060Sbapt                  }
85858551Skris
859228060Sbapt                unsigned int total_keysig_size = key_pos - key_positions;
860228060Sbapt                if (total_keysig_size == 0)
86158551Skris                  {
862228060Sbapt                    fprintf (stderr, "No key positions selected.\n");
86358551Skris                    short_usage (stderr);
86458551Skris                    exit (1);
86558551Skris                  }
866228060Sbapt                _key_positions.set_size (total_keysig_size);
867228060Sbapt
868228060Sbapt                /* Sorts the key positions *IN REVERSE ORDER!!*
869228060Sbapt                   This makes further routines more efficient.  Especially
870228060Sbapt                   when generating code.  */
871228060Sbapt                if (! _key_positions.sort())
87258551Skris                  {
873228060Sbapt                    fprintf (stderr, "Duplicate key positions selected\n");
87458551Skris                    short_usage (stderr);
87558551Skris                    exit (1);
87658551Skris                  }
87758551Skris              }
87858551Skris            break;
87958551Skris          }
880228060Sbapt        case 'K':               /* Make this the keyname for the keyword component field.  */
88158551Skris          {
882228060Sbapt            _slot_name = /*getopt*/optarg;
88358551Skris            break;
88458551Skris          }
885228060Sbapt        case 'l':               /* Create length table to avoid extra string compares.  */
88658551Skris          {
887228060Sbapt            _option_word |= LENTABLE;
88858551Skris            break;
88958551Skris          }
890228060Sbapt        case 'L':               /* Deal with different generated languages.  */
89158551Skris          {
892228060Sbapt            _language = NULL;
893228060Sbapt            set_language (/*getopt*/optarg);
894228060Sbapt            break;
895228060Sbapt          }
896228060Sbapt        case 'm':               /* Multiple iterations for finding good asso_values.  */
897228060Sbapt          {
898228060Sbapt            if ((_asso_iterations = atoi (/*getopt*/optarg)) < 0)
89958551Skris              {
900228060Sbapt                fprintf (stderr, "asso_iterations value must not be negative, assuming 0\n");
901228060Sbapt                _asso_iterations = 0;
90258551Skris              }
90358551Skris            break;
90458551Skris          }
905228060Sbapt        case 'n':               /* Don't include the length when computing hash function.  */
90658551Skris          {
907228060Sbapt            _option_word |= NOLENGTH;
90858551Skris            break;
90958551Skris          }
910228060Sbapt        case 'N':               /* Make generated lookup function name be optarg.  */
91158551Skris          {
912228060Sbapt            _function_name = /*getopt*/optarg;
91358551Skris            break;
91458551Skris          }
915228060Sbapt        case 'o':               /* Order input by frequency of key set occurrence.  */
916228060Sbapt          break;                /* Not needed any more.  */
917228060Sbapt        case 'O':               /* Optimized choice during collision resolution.  */
918228060Sbapt          break;                /* Not needed any more.  */
919228060Sbapt        case 'p':               /* Generated lookup function a pointer instead of int.  */
920228060Sbapt          break;                /* This is now the default.  */
921228060Sbapt        case 'P':               /* Optimize for position-independent code.  */
92258551Skris          {
923228060Sbapt            _option_word |= SHAREDLIB;
92458551Skris            break;
92558551Skris          }
926228060Sbapt        case 'Q':               /* Sets the name for the string pool.  */
92758551Skris          {
928228060Sbapt            _stringpool_name = /*getopt*/optarg;
92958551Skris            break;
93058551Skris          }
931228060Sbapt        case 'r':               /* Utilize randomness to initialize the associated values table.  */
93258551Skris          {
933228060Sbapt            _option_word |= RANDOM;
934228060Sbapt            if (_initial_asso_value != 0)
935228060Sbapt              fprintf (stderr, "warning, -r option supersedes -i, disabling -i option and continuing\n");
93658551Skris            break;
93758551Skris          }
938228060Sbapt        case 's':               /* Range of associated values, determines size of final table.  */
93958551Skris          {
940228060Sbapt            float numerator;
941228060Sbapt            float denominator = 1;
942228060Sbapt            bool invalid = false;
943228060Sbapt            char *endptr;
944228060Sbapt
945228060Sbapt            numerator = strtod (/*getopt*/optarg, &endptr);
946228060Sbapt            if (endptr == /*getopt*/optarg)
947228060Sbapt              invalid = true;
948228060Sbapt            else if (*endptr != '\0')
94958551Skris              {
950228060Sbapt                if (*endptr == '/')
951228060Sbapt                  {
952228060Sbapt                    char *denomptr = endptr + 1;
953228060Sbapt                    denominator = strtod (denomptr, &endptr);
954228060Sbapt                    if (endptr == denomptr || *endptr != '\0')
955228060Sbapt                      invalid = true;
956228060Sbapt                  }
957228060Sbapt                else
958228060Sbapt                  invalid = true;
959228060Sbapt              }
960228060Sbapt            if (invalid)
961228060Sbapt              {
962228060Sbapt                fprintf (stderr, "Invalid value for option -s.\n");
963228060Sbapt                short_usage (stderr);
964228060Sbapt                exit (1);
965228060Sbapt              }
966228060Sbapt            _size_multiple = numerator / denominator;
967228060Sbapt            /* Backward compatibility: -3 means 1/3.  */
968228060Sbapt            if (_size_multiple < 0)
969228060Sbapt              _size_multiple = 1 / (-_size_multiple);
970228060Sbapt            /* Catch stupid users.  */
971228060Sbapt            if (_size_multiple == 0)
972228060Sbapt              _size_multiple = 1;
973228060Sbapt            /* Warnings.  */
974228060Sbapt            if (_size_multiple > 50)
975228060Sbapt              fprintf (stderr, "Size multiple %g is excessive, did you really mean this?! (try '%s --help' for help)\n", _size_multiple, program_name);
976228060Sbapt            else if (_size_multiple < 0.01f)
977228060Sbapt              fprintf (stderr, "Size multiple %g is extremely small, did you really mean this?! (try '%s --help' for help)\n", _size_multiple, program_name);
978228060Sbapt            break;
979228060Sbapt          }
980228060Sbapt        case 'S':               /* Generate switch statement output, rather than lookup table.  */
981228060Sbapt          {
982228060Sbapt            _option_word |= SWITCH;
983228060Sbapt            _total_switches = atoi (/*getopt*/optarg);
984228060Sbapt            if (_total_switches <= 0)
985228060Sbapt              {
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          }
992228060Sbapt        case 't':               /* Enable the TYPE mode, allowing arbitrary user structures.  */
99358551Skris          {
994228060Sbapt            _option_word |= TYPE;
99558551Skris            break;
99658551Skris          }
997228060Sbapt        case 'T':               /* Don't print structure definition.  */
99858551Skris          {
999228060Sbapt            _option_word |= NOTYPE;
100058551Skris            break;
100158551Skris          }
1002228060Sbapt        case 'v':               /* Print out the version and quit.  */
100358551Skris          fprintf (stdout, "GNU gperf %s\n", version_string);
1004228060Sbapt          fprintf (stdout, "Copyright (C) %s Free Software Foundation, Inc.\n\
1005228060SbaptThis is free software; see the source for copying conditions.  There is NO\n\
1006228060Sbaptwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
1007228060Sbapt",
1008228060Sbapt                   "1989-1998, 2000-2004, 2006-2007");
1009228060Sbapt          fprintf (stdout, "Written by %s and %s.\n",
1010228060Sbapt                   "Douglas C. Schmidt", "Bruno Haible");
101158551Skris          exit (0);
1012228060Sbapt        case 'W':               /* Sets the name for the hash table array.  */
101358551Skris          {
1014228060Sbapt            _wordlist_name = /*getopt*/optarg;
101558551Skris            break;
101658551Skris          }
1017228060Sbapt        case 'Z':               /* Set the class name.  */
101858551Skris          {
1019228060Sbapt            _class_name = /*getopt*/optarg;
102058551Skris            break;
102158551Skris          }
1022228060Sbapt        case '7':               /* Assume 7-bit characters.  */
102358551Skris          {
1024228060Sbapt            _option_word |= SEVENBIT;
102558551Skris            break;
102658551Skris          }
1027228060Sbapt        case CHAR_MAX + 1:      /* Set the output file name.  */
1028228060Sbapt          {
1029228060Sbapt            _output_file_name = /*getopt*/optarg;
1030228060Sbapt            break;
1031228060Sbapt          }
1032228060Sbapt        case CHAR_MAX + 2:      /* Case insignificant.  */
1033228060Sbapt          {
1034228060Sbapt            _option_word |= UPPERLOWER;
1035228060Sbapt            break;
1036228060Sbapt          }
1037228060Sbapt        case CHAR_MAX + 3:      /* Use NULL instead of "".  */
1038228060Sbapt          {
1039228060Sbapt            _option_word |= NULLSTRINGS;
1040228060Sbapt            break;
1041228060Sbapt          }
1042228060Sbapt        case CHAR_MAX + 4:      /* Sets the name for the length table array.  */
1043228060Sbapt          {
1044228060Sbapt            _lengthtable_name = /*getopt*/optarg;
1045228060Sbapt            break;
1046228060Sbapt          }
104758551Skris        default:
104858551Skris          short_usage (stderr);
104958551Skris          exit (1);
105058551Skris        }
105158551Skris
105258551Skris    }
105358551Skris
1054228060Sbapt  if (/*getopt*/optind < argc)
1055228060Sbapt    _input_file_name = argv[/*getopt*/optind++];
105658551Skris
1057228060Sbapt  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
1065228060Sbapt/* ------------------------------------------------------------------------- */
1066228060Sbapt
106758551Skris#ifndef __OPTIMIZE__
106858551Skris
106958551Skris#define INLINE /* not inline */
107058551Skris#include "options.icc"
107158551Skris#undef INLINE
107258551Skris
107358551Skris#endif /* not defined __OPTIMIZE__ */
1074