Initial commit
[cgperf.git] / options.c
blob1fb9da336b25695c248aacf3fb0079febf132bd0
1 #ifndef GPERF_OPTIONS_C
2 #define GPERF_OPTIONS_C
3 #include <limits.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <getopt.h>
7 #include <ctype.h>
8 #include <string.h>
10 #include "globals.h"
11 #include "options.h"
12 #include "version.h"
13 #include "positions.h"
14 /*------------------------------------------------------------------------------------------------*/
15 #include "namespace/globals.h"
16 #include "namespace/options.h"
17 #include "namespace/positions.h"
18 /*------------------------------------------------------------------------------------------------*/
19 /*{{{ defaults */
20 /* default struct initializer suffix */
21 static u8 *DEFAULT_INITIALIZER_SUFFIX = "";
22 /* default name for the key component */
23 static u8 *DEFAULT_SLOT_NAME = "name";
24 /* default delimiters that separate keywords from their attributes */
25 static u8 *DEFAULT_DELIMITERS = ",";
26 /* default name for generated hash function */
27 static u8 *DEFAULT_HASH_NAME = "hash";
28 /* default name for generated lookup function */
29 static u8 *DEFAULT_FUNCTION_NAME = "in_word_set";
30 /* default name for the generated class */
31 static u8 *DEFAULT_CLASS_NAME = "Perfect_Hash";
32 /* default name for string pool */
33 static u8 *DEFAULT_STRINGPOOL_NAME = "stringpool";
34 /* default prefix for constants */
35 static u8 *DEFAULT_CONSTANTS_PREFIX = "";
36 /* default name for generated hash table array */
37 static u8 *DEFAULT_WORDLIST_NAME = "wordlist";
38 /* default name for generated length table array */
39 static u8 *DEFAULT_LENGTHTABLE_NAME = "lengthtable";
40 /*}}} default -- END */
41 /*{{{ opts_new */
42 static struct Options *opts_new(void)
44 struct Options *t;
46 t = calloc(1, sizeof(*t));
47 t->option_word = OPTS_ANSIC;
48 t->jump = OPTS_DEFAULT_JUMP_VALUE;
49 t->total_switches = 1;
50 t->size_multiple = 1;
51 t->function_name = DEFAULT_FUNCTION_NAME;
52 t->slot_name = DEFAULT_SLOT_NAME;
53 t->initializer_suffix = DEFAULT_INITIALIZER_SUFFIX;
54 t->class_name = DEFAULT_CLASS_NAME;
55 t->hash_name = DEFAULT_HASH_NAME;
56 t->wordlist_name = DEFAULT_WORDLIST_NAME;
57 t->lengthtable_name = DEFAULT_LENGTHTABLE_NAME;
58 t->stringpool_name = DEFAULT_STRINGPOOL_NAME;
59 t->constants_prefix = DEFAULT_CONSTANTS_PREFIX;
60 t->delimiters = DEFAULT_DELIMITERS;
61 t->key_positions = pos_new();
62 return t;
63 }/*}}}*/
64 /*{{{ opts_del */
65 static void opts_del(struct Options *t)
67 if (OPTS(DEBUG)) {
68 struct PositionIterator *iter;
69 s32 pos;
71 fprintf(stderr, "\ndumping Options:"
72 "\nTYPE is........: %s"
73 "\nUPPERLOWER is..: %s"
74 "\nKRC is.........: %s"
75 "\nC is...........: %s"
76 "\nANSIC is.......: %s"
77 "\nCPLUSPLUS is...: %s"
78 "\nSEVENBIT is....: %s"
79 "\nLENTABLE is....: %s"
80 "\nCOMP is........: %s"
81 "\nCONST is.......: %s"
82 "\nENUM is........: %s"
83 "\nINCLUDE is.....: %s"
84 "\nGLOBAL is......: %s"
85 "\nNULLSTRINGS is.: %s"
86 "\nSHAREDLIB is...: %s"
87 "\nSWITCH is......: %s"
88 "\nNOTYPE is......: %s"
89 "\nDUP is.........: %s"
90 "\nNOLENGTH is....: %s"
91 "\nRANDOM is......: %s"
92 "\nDEBUG is.......: %s"
93 "\nlookup function name = %s"
94 "\nhash function name = %s"
95 "\nword list name = %s"
96 "\nlength table name = %s"
97 "\nstring pool name = %s"
98 "\nslot name = %s"
99 "\ninitializer suffix = %s"
100 "\nasso_values iterations = %d"
101 "\njump value = %d"
102 "\nhash table size multiplier = %g"
103 "\ninitial associated value = %d"
104 "\ndelimiters = %s"
105 "\nnumber of switch statements = %d\n",
106 OPTS(TYPE) ? "enabled" : "disabled",
107 OPTS(UPPERLOWER) ? "enabled" : "disabled",
108 OPTS(KRC) ? "enabled" : "disabled",
109 OPTS(C) ? "enabled" : "disabled",
110 OPTS(ANSIC) ? "enabled" : "disabled",
111 OPTS(CPLUSPLUS) ? "enabled" : "disabled",
112 OPTS(SEVENBIT) ? "enabled" : "disabled",
113 OPTS(LENTABLE) ? "enabled" : "disabled",
114 OPTS(COMP) ? "enabled" : "disabled",
115 OPTS(CONST) ? "enabled" : "disabled",
116 OPTS(ENUM) ? "enabled" : "disabled",
117 OPTS(INCLUDE) ? "enabled" : "disabled",
118 OPTS(GLOBAL) ? "enabled" : "disabled",
119 OPTS(NULLSTRINGS) ? "enabled" : "disabled",
120 OPTS(SHAREDLIB) ? "enabled" : "disabled",
121 OPTS(SWITCH) ? "enabled" : "disabled",
122 OPTS(NOTYPE) ? "enabled" : "disabled",
123 OPTS(DUP) ? "enabled" : "disabled",
124 OPTS(NOLENGTH) ? "enabled" : "disabled",
125 OPTS(RANDOM) ? "enabled" : "disabled",
126 OPTS(DEBUG) ? "enabled" : "disabled",
127 t->function_name, t->hash_name, t->wordlist_name, t->lengthtable_name,
128 t->stringpool_name, t->slot_name, t->initializer_suffix,
129 t->asso_iterations, t->jump, t->size_multiple, t->initial_asso_value,
130 t->delimiters, t->total_switches);
131 if (t->key_positions->useall)
132 fprintf(stderr, "all characters are used in the hash function\n");
133 else {
134 fprintf(stderr, "maximum keysig size = %d\nkey positions are: \n", t->key_positions->size);
135 iter = pos_iterator_all(t->key_positions);
136 loop {
137 pos = positer_next(iter);
138 if (pos == POSITER_EOS)
139 break;
140 if (pos == POS_LASTCHAR)
141 fprintf(stderr, "$\n");
142 else
143 fprintf(stderr, "%d\n", pos + 1);
147 fprintf (stderr, "finished dumping Options\n");
149 pos_del(t->key_positions);
150 free(t);
151 }/*}}}*/
152 /*{{{ opts_long_options
153 Parses the command line Options and sets appropriate flags in option_word. */
154 static const struct option opts_long_options[] =
156 { "output-file", required_argument, NULL, CHAR_MAX + 1 },
157 { "ignore-case", no_argument, NULL, CHAR_MAX + 2 },
158 { "delimiters", required_argument, NULL, 'e' },
159 { "struct-type", no_argument, NULL, 't' },
160 { "language", required_argument, NULL, 'L' },
161 { "slot-name", required_argument, NULL, 'K' },
162 { "initializer-suffix", required_argument, NULL, 'F' },
163 { "hash-fn-name", required_argument, NULL, 'H' }, /* backward compatibility */
164 { "hash-function-name", required_argument, NULL, 'H' },
165 { "lookup-fn-name", required_argument, NULL, 'N' }, /* backward compatibility */
166 { "lookup-function-name", required_argument, NULL, 'N' },
167 { "class-name", required_argument, NULL, 'Z' },
168 { "seven-bit", no_argument, NULL, '7' },
169 { "compare-strncmp", no_argument, NULL, 'c' },
170 { "readonly-tables", no_argument, NULL, 'C' },
171 { "enum", no_argument, NULL, 'E' },
172 { "includes", no_argument, NULL, 'I' },
173 { "global-table", no_argument, NULL, 'G' },
174 { "constants-prefix", required_argument, NULL, CHAR_MAX + 5 },
175 { "word-array-name", required_argument, NULL, 'W' },
176 { "length-table-name", required_argument, NULL, CHAR_MAX + 4 },
177 { "switch", required_argument, NULL, 'S' },
178 { "omit-struct-type", no_argument, NULL, 'T' },
179 { "key-positions", required_argument, NULL, 'k' },
180 { "compare-strlen", no_argument, NULL, 'l' }, /* backward compatibility */
181 { "compare-lengths", no_argument, NULL, 'l' },
182 { "duplicates", no_argument, NULL, 'D' },
183 { "fast", required_argument, NULL, 'f' },
184 { "initial-asso", required_argument, NULL, 'i' },
185 { "jump", required_argument, NULL, 'j' },
186 { "multiple-iterations", required_argument, NULL, 'm' },
187 { "no-strlen", no_argument, NULL, 'n' },
188 { "occurrence-sort", no_argument, NULL, 'o' },
189 { "optimized-collision-resolution", no_argument, NULL, 'O' },
190 { "pic", no_argument, NULL, 'P' },
191 { "string-pool-name", required_argument, NULL, 'Q' },
192 { "null-strings", no_argument, NULL, CHAR_MAX + 3 },
193 { "random", no_argument, NULL, 'r' },
194 { "size-multiple", required_argument, NULL, 's' },
195 { "help", no_argument, NULL, 'h' },
196 { "version", no_argument, NULL, 'v' },
197 { "debug", no_argument, NULL, 'd' },
198 { NULL, no_argument, NULL, 0 }
199 };/*}}}*/
200 /*{{{ opts_parse_options */
201 static void opts_parse_options(struct Options *t, u32 argc, u8 **argv)
203 opts_program_name = (u8*)argv[0];
204 t->argument_count = argc;
205 t->argument_vector = argv;
207 loop {
208 int option_char;
210 option_char = getopt_long(t->argument_count, t->argument_vector,
211 "acCdDe:Ef:F:gGhH:i:Ij:k:K:lL:m:nN:oOpPQ:rs:S:tTvW:Z:7", opts_long_options,
212 NULL);
213 if (option_char == -1)
214 break;
215 switch (option_char) {
216 case 'a': /* generated code uses the ANSI prototype format */
217 break; /* This is now the default */
218 case 'c': /* generate strncmp rather than strcmp */
219 t->option_word |= OPTS_COMP;
220 break;
221 case 'C': /* make the generated tables readonly (const) */
222 t->option_word |= OPTS_CONST;
223 break;
224 case 'd': /* enable debugging option */
225 t->option_word |= OPTS_DEBUG;
226 fprintf(stderr, "Starting program %s, version %s, with debugging on.\n", opts_program_name, cgperf_version_string);
227 break;
228 case 'D': /* enable duplicate option */
229 t->option_word |= OPTS_DUP;
230 break;
231 case 'e': /* specify keyword/attribute separator */
232 t->delimiters = /*getopt*/(u8*)optarg;
233 break;
234 case 'E':
235 t->option_word |= OPTS_ENUM;
236 break;
237 case 'f': /* generate the hash table "fast" */
238 break; /* Not needed any more */
239 case 'F':
240 t->initializer_suffix = /*getopt*/(u8*)optarg;
241 break;
242 case 'g': /* use the 'inline' keyword for generated sub-routines, ifdef __GNUC__ */
243 break; /* This is now the default */
244 case 'G': /* make the keyword table a global variable */
245 t->option_word |= OPTS_GLOBAL;
246 break;
247 case 'h': /* displays a list of helpful Options to the user */
248 opts_long_usage(stdout);
249 exit(0);
250 case 'H': /* sets the name for the hash function */
251 t->hash_name = /*getopt*/(u8*)optarg;
252 break;
253 case 'i': /* sets the initial value for the associated values array */
254 t->initial_asso_value = atoi(/*getopt*/optarg);
255 if (t->initial_asso_value < 0)
256 fprintf(stderr, "Initial value %d should be non-zero, ignoring and continuing.\n", t->initial_asso_value);
257 if (OPTS(RANDOM))
258 fprintf(stderr, "warning, -r option superceeds -i, ignoring -i option and continuing\n");
259 break;
260 case 'I': /* enable #include statements */
261 t->option_word |= OPTS_INCLUDE;
262 break;
263 case 'j': /* sets the jump value, must be odd for later algorithms */
264 t->jump = atoi (/*getopt*/optarg);
265 if (t->jump < 0) {
266 fprintf(stderr, "Jump value %d must be a positive number.\n", t->jump);
267 opts_short_usage(stderr);
268 exit(1);
269 } else if ((t->jump != 0) && ((t->jump % 2) == 0))
270 fprintf (stderr, "Jump value %d should be odd, adding 1 and continuing...\n", t->jump++);
271 break;
272 case 'k': { /* sets key positions used for hash function */
273 t->option_word |= OPTS_POSITIONS;
274 s32 BAD_VALUE = -3;
275 s32 EOS = POSITER_EOS;
276 s32 value;
277 struct PositionStringParser *sparser;
279 sparser = posstrp_new(/*getopt*/(u8*)optarg, 1,
280 POS_MAX_KEY_POS, POS_LASTCHAR, BAD_VALUE, EOS);
282 if (/*getopt*/optarg[0] == '*') /* use all the characters for hashing!!!! */
283 pos_set_useall(t->key_positions, true);
284 else {
285 s32 *key_positions;
286 s32 *key_pos;
287 u32 total_keysig_size;
289 pos_set_useall(t->key_positions, false);
290 key_positions = t->key_positions->positions;
292 key_pos = key_positions;
293 loop {
294 value = posstrp_nextPosition(sparser);
295 if (value == EOS)
296 break;
297 if (value == BAD_VALUE) {
298 fprintf(stderr, "Invalid position value or range, use 1,2,3-%d,'$' or '*'.\n", POS_MAX_KEY_POS);
299 opts_short_usage(stderr);
300 exit(1);
302 if ((key_pos - key_positions) == POS_MAX_SIZE) {
304 * More than Positions_max_size key positions.
305 * Since all key positions are in the range
306 * 0..Positions_max_key_pos-1 or == Positions_lastchar,
307 * there must be duplicates.
309 fprintf(stderr, "Duplicate key positions selected\n");
310 opts_short_usage(stderr);
311 exit(1);
313 if (value != POS_LASTCHAR)
314 /* We use 0-based indices in the class Positions */
315 value = value - 1;
316 *key_pos = value;
317 ++key_pos;
319 total_keysig_size = key_pos - key_positions;
320 if (total_keysig_size == 0) {
321 fprintf(stderr, "No key positions selected.\n");
322 opts_short_usage(stderr);
323 exit(1);
325 t->key_positions->size = total_keysig_size;
327 * Sorts the key positions *IN REVERSE ORDER!!*
328 * This makes further routines more efficient.
329 * Especially when generating code.
331 if (!pos_sort(t->key_positions)) {
332 fprintf(stderr, "Duplicate key positions selected\n");
333 opts_short_usage(stderr);
334 exit(1);
337 break;}
338 case 'K':/* make this the keyname for the keyword component field */
339 t->slot_name = /*getopt*/optarg;
340 break;
341 case 'l':/* create length table to avoid extra string compares */
342 t->option_word |= OPTS_LENTABLE;
343 break;
344 case 'L':/* deal with different generated languages */
345 t->language = 0;
346 opts_set_language(t,/*getopt*/optarg);
347 break;
348 case 'm':/* multiple iterations for finding good asso_values */
349 t->asso_iterations = atoi(/*getopt*/optarg);
350 if (t->asso_iterations < 0) {
351 fprintf(stderr, "asso_iterations value must not be negative, assuming 0\n");
352 t->asso_iterations = 0;
354 break;
355 case 'n':/* don't include the length when computing hash function */
356 t->option_word |= OPTS_NOLENGTH;
357 break;
358 case 'N':/* make generated lookup function name be optarg */
359 t->function_name = /*getopt*/optarg;
360 break;
361 case 'o':/* order input by frequency of key set occurrence */
362 break; /* not needed any more */
363 case 'O':/* optimized choice during collision resolution */
364 break; /* not needed any more */
365 case 'p':/* generated lookup function a pointer instead of int */
366 break; /* this is now the default */
367 case 'P':/* optimize for position-independent code */
368 t->option_word |= OPTS_SHAREDLIB;
369 break;
370 case 'Q':/* sets the name for the string pool */
371 t->stringpool_name = /*getopt*/optarg;
372 break;
373 case 'r':/* utilize randomness to initialize the associated values table */
374 t->option_word |= OPTS_RANDOM;
375 if (t->initial_asso_value != 0)
376 fprintf(stderr, "warning, -r option supersedes -i, disabling -i option and continuing\n");
377 break;
378 case 's':{/* range of associated values, determines size of final table */
379 f32 numerator;
380 f32 denominator;
381 bool invalid;
382 u8 *endptr;
384 denominator = 1;
385 invalid = false;
386 numerator = strtod(/*getopt*/optarg, &endptr);
387 if (endptr == /*getopt*/(u8*)optarg)
388 invalid = true;
389 else if (*endptr != '\0') {
390 if (*endptr == '/') {
391 u8 *denomptr;
393 denomptr = endptr + 1;
394 denominator = strtod(denomptr, &endptr);
395 if (endptr == denomptr || *endptr != '\0')
396 invalid = true;
397 } else
398 invalid = true;
400 if (invalid) {
401 fprintf(stderr, "Invalid value for option -s.\n");
402 opts_short_usage(stderr);
403 exit (1);
405 t->size_multiple = numerator / denominator;
406 /* backward compatibility: -3 means 1/3 */
407 if (t->size_multiple < 0)
408 t->size_multiple = 1 / (-t->size_multiple);
409 /* catch stupid users and port to C the c++ from stupid coders */
410 if (t->size_multiple == 0)
411 t->size_multiple = 1;
412 /* warnings */
413 if (t->size_multiple > 50)
414 fprintf(stderr, "Size multiple %g is excessive, did you really mean this?! (try '%s --help' for help)\n", t->size_multiple, opts_program_name);
415 else if (t->size_multiple < 0.01f)
416 fprintf(stderr, "Size multiple %g is extremely small, did you really mean this?! (try '%s --help' for help)\n", t->size_multiple, opts_program_name);
417 break;}
418 case 'S':/* generate switch statement output, rather than lookup table */
419 t->option_word |= OPTS_SWITCH;
420 t->total_switches = atoi(/*getopt*/optarg);
421 if (t->total_switches <= 0) {
422 fprintf(stderr, "number of switches %s must be a positive number\n", /*getopt*/optarg);
423 opts_short_usage (stderr);
424 exit(1);
426 break;
427 case 't':/* enable the TYPE mode, allowing arbitrary user structures */
428 t->option_word |= OPTS_TYPE;
429 break;
430 case 'T':/* don't print structure definition */
431 t->option_word |= OPTS_NOTYPE;
432 break;
433 case 'v':/* print out the version and quit */
434 fprintf(stdout, "GNU gperf %s\n", cgperf_version_string);
435 fprintf(stdout, "Copyright (C) %s Free Software Foundation, Inc.\n\
436 License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>\n\
437 This is free software: you are free to change and redistribute it.\n\
438 There is NO WARRANTY, to the extent permitted by law.\n\
440 "1989-2018");
441 fprintf(stdout, "Written by %s and %s. C89 with benign bits of C99/C11 port by Sylvain BERTRAND\n", "Douglas C. Schmidt", "Bruno Haible");
442 exit(0);
443 case 'W':/* sets the name for the hash table array */
444 t->wordlist_name = /*getopt*/optarg;
445 break;
446 case 'Z':/* set the class name */
447 t->class_name = /*getopt*/optarg;
448 break;
449 case '7':/* assume 7-bit characters */
450 t->option_word |= OPTS_SEVENBIT;
451 break;
452 case CHAR_MAX + 1:/* set the output file name */
453 t->output_file_name = /*getopt*/optarg;
454 break;
455 case CHAR_MAX + 2:/* case insignificant */
456 t->option_word |= OPTS_UPPERLOWER;
457 break;
458 case CHAR_MAX + 3:/* use NULL instead of "" */
459 t->option_word |= OPTS_NULLSTRINGS;
460 break;
461 case CHAR_MAX + 4:/* sets the name for the length table array */
462 t->lengthtable_name = /*getopt*/optarg;
463 break;
464 case CHAR_MAX + 5:/* sets the prefix for the constants */
465 t->constants_prefix = /*getopt*/optarg;
466 break;
467 default:
468 opts_short_usage(stderr);
469 exit(1);
472 if (/*getopt*/optind < argc)
473 t->input_file_name = argv[/*getopt*/optind++];
475 if (/*getopt*/optind < argc) {
476 fprintf(stderr, "Extra trailing arguments to %s.\n", opts_program_name);
477 opts_short_usage(stderr);
478 exit(1);
480 }/*}}}*/
481 /*{{{ opts_short_usage */
482 static void opts_short_usage(FILE * stream)
484 fprintf(stream, "Try '%s --help' for more information.\n", opts_program_name);
485 }/*}}}*/
486 /*{{{ opts_long_usage */
487 static void opts_long_usage(FILE * stream)
489 fprintf(stream,
490 "GNU 'gperf' generates perfect hash functions.\n");
491 fprintf(stream, "\n");
492 fprintf(stream,
493 "Usage: %s [OPTION]... [INPUT-FILE]\n",
494 opts_program_name);
495 fprintf(stream, "\n");
496 fprintf(stream,
497 "If a long option shows an argument as mandatory, then it is mandatory\n"
498 "for the equivalent short option also.\n");
499 fprintf(stream, "\n");
500 fprintf(stream,
501 "Output file location:\n");
502 fprintf(stream,
503 " --output-file=FILE Write output to specified file.\n");
504 fprintf(stream,
505 "The results are written to standard output if no output file is specified\n"
506 "or if it is -.\n");
507 fprintf(stream, "\n");
508 fprintf(stream,
509 "Input file interpretation:\n");
510 fprintf(stream,
511 " -e, --delimiters=DELIMITER-LIST\n"
512 " Allow user to provide a string containing delimiters\n"
513 " used to separate keywords from their attributes.\n"
514 " Default is \",\".\n");
515 fprintf(stream,
516 " -t, --struct-type Allows the user to include a structured type\n"
517 " declaration for generated code. Any text before %%%%\n"
518 " is considered part of the type declaration. Key\n"
519 " words and additional fields may follow this, one\n"
520 " group of fields per line.\n");
521 fprintf(stream,
522 " --ignore-case Consider upper and lower case ASCII characters as\n"
523 " equivalent. Note that locale dependent case mappings\n"
524 " are ignored.\n");
525 fprintf(stream, "\n");
526 fprintf(stream,
527 "Language for the output code:\n");
528 fprintf(stream,
529 " -L, --language=LANGUAGE-NAME\n"
530 " Generates code in the specified language. Languages\n"
531 " handled are currently C++, ANSI-C, C, and KR-C. The\n"
532 " default is ANSI-C.\n");
533 fprintf(stream, "\n");
534 fprintf(stream,
535 "Details in the output code:\n");
536 fprintf(stream,
537 " -K, --slot-name=NAME Select name of the keyword component in the keyword\n"
538 " structure.\n");
539 fprintf(stream,
540 " -F, --initializer-suffix=INITIALIZERS\n"
541 " Initializers for additional components in the keyword\n"
542 " structure.\n");
543 fprintf(stream,
544 " -H, --hash-function-name=NAME\n"
545 " Specify name of generated hash function. Default is\n"
546 " 'hash'.\n");
547 fprintf(stream,
548 " -N, --lookup-function-name=NAME\n"
549 " Specify name of generated lookup function. Default\n"
550 " name is 'in_word_set'.\n");
551 fprintf(stream,
552 " -Z, --class-name=NAME Specify name of generated C++ class. Default name is\n"
553 " 'Perfect_Hash'.\n");
554 fprintf(stream,
555 " -7, --seven-bit Assume 7-bit characters.\n");
556 fprintf(stream,
557 " -l, --compare-lengths Compare key lengths before trying a string\n"
558 " comparison. This is necessary if the keywords\n"
559 " contain NUL bytes. It also helps cut down on the\n"
560 " number of string comparisons made during the lookup.\n");
561 fprintf(stream,
562 " -c, --compare-strncmp Generate comparison code using strncmp rather than\n"
563 " strcmp.\n");
564 fprintf(stream,
565 " -C, --readonly-tables Make the contents of generated lookup tables\n"
566 " constant, i.e., readonly.\n");
567 fprintf(stream,
568 " -E, --enum Define constant values using an enum local to the\n"
569 " lookup function rather than with defines.\n");
570 fprintf(stream,
571 " -I, --includes Include the necessary system include file <string.h>\n"
572 " at the beginning of the code.\n");
573 fprintf(stream,
574 " -G, --global-table Generate the static table of keywords as a static\n"
575 " global variable, rather than hiding it inside of the\n"
576 " lookup function (which is the default behavior).\n");
577 fprintf(stream,
578 " -P, --pic Optimize the generated table for inclusion in shared\n"
579 " libraries. This reduces the startup time of programs\n"
580 " using a shared library containing the generated code.\n");
581 fprintf(stream,
582 " -Q, --string-pool-name=NAME\n"
583 " Specify name of string pool generated by option --pic.\n"
584 " Default name is 'stringpool'.\n");
585 fprintf(stream,
586 " --null-strings Use NULL strings instead of empty strings for empty\n"
587 " keyword table entries.\n");
588 fprintf(stream,
589 " --constants-prefix=PREFIX\n"
590 " Specify prefix for the constants like TOTAL_KEYWORDS.\n");
591 fprintf(stream,
592 " -W, --word-array-name=NAME\n"
593 " Specify name of word list array. Default name is\n"
594 " 'wordlist'.\n");
595 fprintf(stream,
596 " --length-table-name=NAME\n"
597 " Specify name of length table array. Default name is\n"
598 " 'lengthtable'.\n");
599 fprintf(stream,
600 " -S, --switch=COUNT Causes the generated C code to use a switch\n"
601 " statement scheme, rather than an array lookup table.\n"
602 " This can lead to a reduction in both time and space\n"
603 " requirements for some keyfiles. The COUNT argument\n"
604 " determines how many switch statements are generated.\n"
605 " A value of 1 generates 1 switch containing all the\n"
606 " elements, a value of 2 generates 2 tables with 1/2\n"
607 " the elements in each table, etc. If COUNT is very\n"
608 " large, say 1000000, the generated C code does a\n"
609 " binary search.\n");
610 fprintf(stream,
611 " -T, --omit-struct-type\n"
612 " Prevents the transfer of the type declaration to the\n"
613 " output file. Use this option if the type is already\n"
614 " defined elsewhere.\n");
615 fprintf(stream, "\n");
616 fprintf(stream,
617 "Algorithm employed by gperf:\n");
618 fprintf(stream,
619 " -k, --key-positions=KEYS\n"
620 " Select the key positions used in the hash function.\n"
621 " The allowable choices range between 1-%d, inclusive.\n"
622 " The positions are separated by commas, ranges may be\n"
623 " used, and key positions may occur in any order.\n"
624 " Also, the meta-character '*' causes the generated\n"
625 " hash function to consider ALL key positions, and $\n"
626 " indicates the \"final character\" of a key, e.g.,\n"
627 " $,1,2,4,6-10.\n",
628 POS_MAX_KEY_POS);
629 fprintf(stream,
630 " -D, --duplicates Handle keywords that hash to duplicate values. This\n"
631 " is useful for certain highly redundant keyword sets.\n");
632 fprintf(stream,
633 " -m, --multiple-iterations=ITERATIONS\n"
634 " Perform multiple choices of the -i and -j values,\n"
635 " and choose the best results. This increases the\n"
636 " running time by a factor of ITERATIONS but does a\n"
637 " good job minimizing the generated table size.\n");
638 fprintf(stream,
639 " -i, --initial-asso=N Provide an initial value for the associate values\n"
640 " array. Default is 0. Setting this value larger helps\n"
641 " inflate the size of the final table.\n");
642 fprintf(stream,
643 " -j, --jump=JUMP-VALUE Affects the \"jump value\", i.e., how far to advance\n"
644 " the associated character value upon collisions. Must\n"
645 " be an odd number, default is %d.\n",
646 OPTS_DEFAULT_JUMP_VALUE);
647 fprintf(stream,
648 " -n, --no-strlen Do not include the length of the keyword when\n"
649 " computing the hash function.\n");
650 fprintf(stream,
651 " -r, --random Utilizes randomness to initialize the associated\n"
652 " values table.\n");
653 fprintf(stream,
654 " -s, --size-multiple=N Affects the size of the generated hash table. The\n"
655 " numeric argument N indicates \"how many times larger\n"
656 " or smaller\" the associated value range should be,\n"
657 " in relationship to the number of keys, e.g. a value\n"
658 " of 3 means \"allow the maximum associated value to\n"
659 " be about 3 times larger than the number of input\n"
660 " keys\". Conversely, a value of 1/3 means \"make the\n"
661 " maximum associated value about 3 times smaller than\n"
662 " the number of input keys\". A larger table should\n"
663 " decrease the time required for an unsuccessful\n"
664 " search, at the expense of extra table space. Default\n"
665 " value is 1.\n");
666 fprintf(stream, "\n");
667 fprintf(stream,
668 "Informative output:\n"
669 " -h, --help Print this message.\n"
670 " -v, --version Print the gperf version number.\n"
671 " -d, --debug Enables the debugging option (produces verbose\n"
672 " output to the standard error).\n");
673 fprintf(stream, "\n");
674 fprintf(stream,
675 "Report bugs to <bug-gperf@gnu.org>.\n");
676 }/*}}}*/
677 /*{{{ opts_set_language */
678 /* Sets the output language, if not already set */
679 void opts_set_language(struct Options *t, u8 *language)
681 if (t->language != 0)
682 return;
683 t->language = language;
684 t->option_word &= ~(OPTS_KRC | OPTS_C | OPTS_ANSIC | OPTS_CPLUSPLUS);
685 if (strcmp(language, "KR-C") == 0)
686 t->option_word |= OPTS_KRC;
687 else if (strcmp (language, "C") == 0)
688 t->option_word |= OPTS_C;
689 else if (strcmp (language, "ANSI-C") == 0)
690 t->option_word |= OPTS_ANSIC;
691 else if (strcmp (language, "C++") == 0)
692 t->option_word |= OPTS_CPLUSPLUS;
693 else {
694 fprintf(stderr, "unsupported language option %s, defaulting to ANSI-C\n", language);
695 t->option_word |= OPTS_ANSIC;
697 }/*}}}*/
698 /*{{{ opts_set_delimiters */
699 /* Sets the delimiters string, if not already set. */
700 static void opts_set_delimiters(struct Options *t, u8 *delimiters)
702 if (t->delimiters == DEFAULT_DELIMITERS)
703 t->delimiters = delimiters;
704 }/*}}}*/
705 /*{{{ opts_set_slot_name */
706 /* sets the keyword key name, if not already set */
707 static void opts_set_slot_name(struct Options *t, u8 *name)
709 if (t->slot_name == DEFAULT_SLOT_NAME)
710 t->slot_name = name;
711 }/*}}}*/
712 /*{{{ opts_set_initializer_suffix */
713 /* sets the struct initializer suffix, if not already set */
714 static void opts_set_initializer_suffix(struct Options *t, u8 *initializers)
716 if (t->initializer_suffix == DEFAULT_INITIALIZER_SUFFIX)
717 t->initializer_suffix = initializers;
718 }/*}}}*/
719 /*{{{ opts_set_hash_name */
720 /* sets the hash function name, if not already set */
721 static void opts_set_hash_name(struct Options *t, u8 *name)
723 if (t->hash_name == DEFAULT_HASH_NAME)
724 t->hash_name = name;
725 }/*}}}*/
726 /*{{{ opts_set_function_name */
727 /* sets the generated function name, if not already set */
728 static void opts_set_function_name(struct Options *t, u8 *name)
730 if (t->function_name == DEFAULT_FUNCTION_NAME)
731 t->function_name = name;
732 }/*}}}*/
733 /*{{{ opts_set_class_name */
734 /* sets the generated class name, if not already set */
735 static void opts_set_class_name(struct Options *t, u8 *name)
737 if (t->class_name == DEFAULT_CLASS_NAME)
738 t->class_name = name;
739 }/*}}}*/
740 /*{{{ opts_set_stringpool_name */
741 /* sets the string pool name, if not already set */
742 static void opts_set_stringpool_name(struct Options *t, u8 *name)
744 if (t->stringpool_name == DEFAULT_STRINGPOOL_NAME)
745 t->stringpool_name = name;
746 }/*}}}*/
747 /*{{{ opts_set_constants_prefix */
748 /* sets the prefix for the constants, if not already set */
749 static void opts_set_constants_prefix(struct Options *t, u8 *prefix)
751 if (t->constants_prefix == DEFAULT_CONSTANTS_PREFIX)
752 t->constants_prefix = prefix;
753 }/*}}}*/
754 /*{{{ opts_set_wordlist_name */
755 /* sets the hash table array name, if not already set */
756 static void opts_set_wordlist_name(struct Options *t, u8 *name)
758 if (t->wordlist_name == DEFAULT_WORDLIST_NAME)
759 t->wordlist_name = name;
760 }/*}}}*/
761 /*{{{ opts_set_lengthtable_name */
762 /* sets the length table array name, if not already set */
763 static void opts_set_lengthtable_name(struct Options *t, u8 *name)
765 if (t->lengthtable_name == DEFAULT_LENGTHTABLE_NAME)
766 t->lengthtable_name = name;
767 }/*}}}*/
768 /*{{{ opts_set_total_switches */
769 /* sets the total number of switch statements, if not already set */
770 static void opts_set_total_switches(struct Options *t, s32 total_switches)
772 if (!OPTS(SWITCH)) {
773 t->option_word |= OPTS_SWITCH;
774 t->total_switches = total_switches;
776 }/*}}}*/
777 /*{{{ posstrp_new */
778 static struct PositionStringParser *posstrp_new(u8 *str, s32 low_bound,
779 s32 high_bound, s32 end_word_marker, s32 error_value, s32 end_marker)
781 struct PositionStringParser *t;
783 t = calloc(1, sizeof(*t));
784 t->str = str;
785 t->low_bound = low_bound;
786 t->high_bound = high_bound;
787 t->end_word_marker = end_word_marker;
788 t->error_value = error_value;
789 t->end_marker = end_marker;
790 t->in_range = false;
791 return t;
793 /*}}}*/
794 /*{{{ posstrp_del */
795 static void posstrp_del(struct PositionStringParser *t)
797 free(t);
798 }/*}}}*/
799 /*{{{ posstrp_nextPosition */
800 /* Returns the next key position from the given string */
801 static s32 posstrp_nextPosition(struct PositionStringParser *t)
803 if (t->in_range) {
804 /* We are inside a range. Return the next value from the range */
805 if (++t->range_curr_value >= t->range_upper_bound)
806 t->in_range = false;
807 return t->range_curr_value;
809 /* we are not inside a range */
810 /* Continue parsing the given string */
811 loop {
812 if (t->str[0] == 0)
813 break;
814 switch (t->str[0]) {
815 case ',':
816 /* Skip the comma */
817 ++(t->str);
818 break;
819 case '$':
820 /* Valid key position */
821 ++(t->str);
822 return t->end_word_marker;
823 case '0': case '1': case '2': case '3': case '4':
824 case '5': case '6': case '7': case '8': case '9': {
825 /* Valid key position */
826 s32 curr_value;
828 curr_value = 0;
829 loop {
830 if (!isdigit((int)(t->str[0])))
831 break;
832 curr_value = curr_value * 10 + (t->str[0] - '0');
833 ++(t->str);
835 if (t->str[0] == '-') {
836 ++(t->str);
837 /* starting a range of key positions */
838 t->in_range = true;
840 t->range_upper_bound = 0;
841 loop {
842 if (!isdigit((int)(t->str[0])))
843 break;
844 t->range_upper_bound = t->range_upper_bound * 10
845 + (t->str[0] - '0');
846 ++(t->str);
848 /* Verify range's upper bound */
849 if (!(t->range_upper_bound > curr_value && t->range_upper_bound
850 <= t->high_bound))
851 return t->error_value;
852 t->range_curr_value = curr_value;
854 /* Verify range's lower bound */
855 if (!(curr_value >= t->low_bound && curr_value <= t->high_bound))
856 return t->error_value;
857 return curr_value;
859 default:
860 /* Invalid syntax. */
861 return t->error_value;
864 return t->end_marker;
865 }/*}}}*/
866 /*{{{ opts_print */
867 static void opts_print(struct Options *t)
869 s32 i;
871 printf("/* Command-line: ");
872 i = 0;
873 loop {
874 u8 *arg;
876 if (i >= t->argument_count)
877 break;
878 arg = t->argument_vector[i];
879 /* escape arg if it contains shell metacharacters */
880 if (*arg == '-') {
881 putchar(*arg);
882 ++arg;
883 if ((*arg >= 'A' && *arg <= 'Z') || (*arg >= 'a' && *arg <= 'z')) {
884 putchar(*arg);
885 ++arg;
886 } else if (*arg == '-') {
887 loop {
888 putchar(*arg);
889 ++arg;
890 if (!((*arg >= 'A' && *arg <= 'Z') || (*arg >= 'a'
891 && *arg <= 'z') || *arg == '-'))
892 break;
894 if (*arg == '=') {
895 putchar(*arg);
896 ++arg;
900 if (strpbrk(arg, "\t\n !\"#$&'()*;<>?[\\]`{|}~") != 0) {
901 if (strchr(arg, '\'') != 0) {
902 putchar('"');
903 loop {
904 if (*arg == 0)
905 break;
906 if (*arg == '\"' || *arg == '\\' || *arg == '$'
907 || *arg == '`')
908 putchar('\\');
909 putchar(*arg);
910 ++arg;
912 putchar('"');
913 } else {
914 putchar('\'');
915 loop {
916 if (*arg == 0)
917 break;
918 if (*arg == '\\')
919 putchar('\\');
920 putchar(*arg);
921 ++arg;
923 putchar('\'');
925 } else
926 printf("%s", arg);
927 printf(" ");
928 ++i;
930 printf(" */");
932 /*}}}*/
933 /*------------------------------------------------------------------------------------------------*/
934 #define EPILOG
935 #include "namespace/globals.h"
936 #include "namespace/options.h"
937 #include "namespace/positions.h"
938 #undef EPILOG
939 /*------------------------------------------------------------------------------------------------*/
940 #endif