summaryrefslogtreecommitdiff
path: root/apps/gperf/src
diff options
context:
space:
mode:
authorlevine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1996-10-21 21:41:34 +0000
committerlevine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1996-10-21 21:41:34 +0000
commita5fdebc5f6375078ec1763850a4ca23ec7fe6458 (patch)
treebcf0a25c3d45a209a6e3ac37b233a4812f29c732 /apps/gperf/src
downloadATCD-a5fdebc5f6375078ec1763850a4ca23ec7fe6458.tar.gz
Initial revision
Diffstat (limited to 'apps/gperf/src')
-rw-r--r--apps/gperf/src/Bool_Array.cpp89
-rw-r--r--apps/gperf/src/Bool_Array.h65
-rw-r--r--apps/gperf/src/Gen_Perf.cpp345
-rw-r--r--apps/gperf/src/Gen_Perf.h65
-rw-r--r--apps/gperf/src/Hash_Table.cpp84
-rw-r--r--apps/gperf/src/Hash_Table.h50
-rw-r--r--apps/gperf/src/Iterator.cpp90
-rw-r--r--apps/gperf/src/Iterator.h67
-rw-r--r--apps/gperf/src/Key_List.cpp1345
-rw-r--r--apps/gperf/src/Key_List.h116
-rw-r--r--apps/gperf/src/List_Node.cpp110
-rw-r--r--apps/gperf/src/List_Node.h65
-rw-r--r--apps/gperf/src/Makefile155
-rw-r--r--apps/gperf/src/Options.cpp616
-rw-r--r--apps/gperf/src/Options.h140
-rw-r--r--apps/gperf/src/Vectors.cpp33
-rw-r--r--apps/gperf/src/Vectors.h44
-rw-r--r--apps/gperf/src/Version.cpp25
-rw-r--r--apps/gperf/src/gperf.cpp66
-rw-r--r--apps/gperf/src/new.cpp75
20 files changed, 3645 insertions, 0 deletions
diff --git a/apps/gperf/src/Bool_Array.cpp b/apps/gperf/src/Bool_Array.cpp
new file mode 100644
index 00000000000..e3243565f41
--- /dev/null
+++ b/apps/gperf/src/Bool_Array.cpp
@@ -0,0 +1,89 @@
+/* Fast lookup table abstraction implemented as an Iteration Number Array
+// @(#)Bool_Array.cpp 1.1 10/18/96
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "Bool_Array.h"
+
+// Prints out debugging diagnostics.
+
+Bool_Array::~Bool_Array (void)
+{
+ if (option[DEBUG])
+ fprintf (stderr, "\ndumping boolean array information\n"
+ "size = %d\niteration number = %d\nend of array dump\n",
+ size, generation_number);
+}
+
+Bool_Array::Bool_Array (void)
+ : storage_array (0),
+ generation_number (0),
+ size (0)
+{
+}
+
+void
+Bool_Array::init (STORAGE_TYPE *buffer, STORAGE_TYPE s)
+{
+ size = s;
+ generation_number = 1;
+ storage_array = buffer;
+
+ memset (storage_array, 0, s * sizeof *storage_array);
+
+ if (option[DEBUG])
+ fprintf (stderr, "\nbool array size = %d, total bytes = %d\n",
+ size, size * sizeof *storage_array);
+}
+
+int
+Bool_Array::find (int index)
+{
+ if (storage_array[index] == generation_number)
+ return 1;
+ else
+ {
+ storage_array[index] = generation_number;
+ return 0;
+ }
+}
+
+void
+Bool_Array::reset (void)
+{
+ if (++generation_number == 0)
+ {
+ if (option[DEBUG])
+ {
+ fprintf (stderr, "(re-initializing bool_array)...");
+ fflush (stderr);
+ }
+
+ generation_number = 1;
+ memset (storage_array, 0, size * sizeof *storage_array);
+
+ if (option[DEBUG])
+ {
+ fprintf (stderr, "done\n");
+ fflush (stderr);
+ }
+ }
+}
+
diff --git a/apps/gperf/src/Bool_Array.h b/apps/gperf/src/Bool_Array.h
new file mode 100644
index 00000000000..d890484e485
--- /dev/null
+++ b/apps/gperf/src/Bool_Array.h
@@ -0,0 +1,65 @@
+/* -*- C++ -*- */
+// @(#)Bool_Array.h 1.1 10/18/96
+
+/* This may look like C code, but it is really -*- C++ -*- */
+
+/* Simple lookup table abstraction implemented as an Generation Number Array.
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/
+
+/* Define and implement a simple boolean array abstraction,
+ uses an Generation Numbering implementation to save on initialization time. */
+
+#ifndef bool_array_h
+#define bool_array_h 1
+
+#include "Options.h"
+
+#ifdef LO_CAL
+/* If we are on a memory diet then we'll only make these use a limited
+ amount of storage space. */
+typedef u_short STORAGE_TYPE;
+#else
+typedef int STORAGE_TYPE;
+#endif
+
+class Bool_Array
+{
+public:
+ Bool_Array (void);
+ ~Bool_Array (void);
+
+ void init (STORAGE_TYPE *buffer, STORAGE_TYPE s);
+ int find (int hash_value);
+ void reset (void);
+
+private:
+ STORAGE_TYPE *storage_array;
+ // Initialization of the index space.
+
+ STORAGE_TYPE generation_number;
+ // Keep track of the current Generation.
+
+ int size;
+ // Keep track of array size.
+};
+
+
+#endif
diff --git a/apps/gperf/src/Gen_Perf.cpp b/apps/gperf/src/Gen_Perf.cpp
new file mode 100644
index 00000000000..25c0299fd35
--- /dev/null
+++ b/apps/gperf/src/Gen_Perf.cpp
@@ -0,0 +1,345 @@
+/* Provides high-level routines to manipulate the keywork list
+// @(#)Gen_Perf.cpp 1.1 10/18/96
+
+ structures the code generation output.
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "Vectors.h"
+#include "Gen_Perf.h"
+
+/* Current release version. */
+extern char *version_string;
+
+/* Reads input keys, possibly applies the reordering heuristic, sets
+ the maximum associated value size (rounded up to the nearest power
+ of 2), may initialize the associated values array, and determines
+ the maximum hash table size. Note: using the random numbers is
+ often helpful, though not as deterministic, of course! */
+
+Gen_Perf::Gen_Perf (void)
+{
+ int asso_value_max;
+ int non_linked_length;
+
+ this->key_list.read_keys ();
+ if (option[ORDER])
+ this->key_list.reorder ();
+ asso_value_max = option.get_asso_max ();
+ non_linked_length = this->key_list.keyword_list_length ();
+ num_done = 1;
+ fewest_collisions = 0;
+ if (asso_value_max == 0)
+ asso_value_max = non_linked_length;
+ else if (asso_value_max > 0)
+ asso_value_max *= non_linked_length;
+ else /* if (asso_value_max < 0) */
+ asso_value_max = non_linked_length / -asso_value_max;
+ option.set_asso_max (ACE_POW (asso_value_max));
+
+ if (option[RANDOM])
+ {
+ srand (time (0));
+
+ for (int i = 0; i < ALPHA_SIZE; i++)
+ Vectors::asso_values[i] = (rand () & asso_value_max - 1);
+ }
+ else
+ {
+ int asso_value = option.initial_value ();
+
+ if (asso_value) /* Initialize array if user requests non-zero default. */
+ for (int i = ALPHA_SIZE - 1; i >= 0; i--)
+ Vectors::asso_values[i] = asso_value & option.get_asso_max () - 1;
+ }
+ max_hash_value = this->key_list.max_key_length () + option.get_asso_max () *
+ option.get_max_keysig_size ();
+
+ printf ("/* ");
+ if (option[C])
+ printf ("C");
+ else if (option[CPLUSPLUS])
+ printf ("C++");
+ printf (" code produced by gperf version %s */\n", version_string);
+ Options::print_options ();
+
+ if (option[DEBUG])
+ fprintf (stderr, "total non-linked keys = %d\nmaximum associated value is %d"
+ "\nmaximum size of generated hash table is %d\n",
+ non_linked_length, asso_value_max, max_hash_value);
+}
+
+/* Merge two disjoint hash key multisets to form the ordered disjoint union of the sets.
+ (In a multiset, an element can occur multiple times).
+ Precondition: both set_1 and set_2 must be ordered. Returns the length
+ of the combined set. */
+
+inline int
+Gen_Perf::compute_disjoint_union (char *set_1, char *set_2, char *set_3)
+{
+ char *base = set_3;
+
+ while (*set_1 && *set_2)
+ if (*set_1 == *set_2)
+ set_1++, set_2++;
+ else
+ {
+ *set_3 = *set_1 < *set_2 ? *set_1++ : *set_2++;
+ if (set_3 == base || *set_3 != *(set_3-1)) set_3++;
+ }
+
+ while (*set_1)
+ {
+ *set_3 = *set_1++;
+ if (set_3 == base || *set_3 != *(set_3-1)) set_3++;
+ }
+
+ while (*set_2)
+ {
+ *set_3 = *set_2++;
+ if (set_3 == base || *set_3 != *(set_3-1)) set_3++;
+ }
+ *set_3 = '\0';
+ return set_3 - base;
+}
+
+/* Sort the UNION_SET in increasing frequency of occurrence.
+ This speeds up later processing since we may assume the resulting
+ set (Set_3, in this case), is ordered. Uses insertion sort, since
+ the UNION_SET is typically short. */
+
+inline void
+Gen_Perf::sort_set (char *union_set, int len)
+{
+ int i, j;
+
+ for (i = 0, j = len - 1; i < j; i++)
+ {
+ char curr, tmp;
+
+ for (curr = i + 1, tmp = union_set[curr];
+ curr > 0 && Vectors::occurrences[tmp] < Vectors::occurrences[union_set[curr-1]];
+ curr--)
+ union_set[curr] = union_set[curr - 1];
+
+ union_set[curr] = tmp;
+ }
+}
+
+/* Generate a key set's hash value. */
+
+inline int
+Gen_Perf::hash (List_Node *key_node)
+{
+ int sum = option[NOLENGTH] ? 0 : key_node->length;
+
+ for (char *ptr = key_node->char_set; *ptr; ptr++)
+ sum += Vectors::asso_values[*ptr];
+
+ return key_node->hash_value = sum;
+}
+
+/* Find out how character value change affects successfully hashed
+ items. Returns FALSE if no other hash values are affected, else
+ returns TRUE. Note that because Option.Get_Asso_Max is a power of
+ two we can guarantee that all legal Vectors::Asso_Values are visited without
+ repetition since Option.Get_Jump was forced to be an odd value! */
+
+inline int
+Gen_Perf::affects_prev (char c, List_Node *curr)
+{
+ int original_char = Vectors::asso_values[c];
+ int total_iterations = !option[FAST]
+ ? option.get_asso_max () : option.get_iterations () ? option.get_iterations () : this->key_list.keyword_list_length ();
+
+ /* Try all legal associated values. */
+
+ for (int i = total_iterations - 1; i >= 0; i--)
+ {
+ int collisions = 0;
+
+ Vectors::asso_values[c] = Vectors::asso_values[c] + (option.get_jump () ? option.get_jump () : rand ())
+ & option.get_asso_max () - 1;
+
+ /* Iteration Number array is a win, O(1) intialization time! */
+ this->char_search.reset ();
+
+ /* See how this asso_value change affects previous keywords. If
+ it does better than before we'll take it! */
+
+ for (List_Node *ptr = this->key_list.head;
+ !this->char_search.find (hash (ptr)) || ++collisions < fewest_collisions;
+ ptr = ptr->next)
+ if (ptr == curr)
+ {
+ fewest_collisions = collisions;
+ if (option[DEBUG])
+ fprintf (stderr, "- resolved after %d iterations", total_iterations - i);
+ return 0;
+ }
+ }
+
+ /* Restore original values, no more tries. */
+ Vectors::asso_values[c] = original_char;
+ /* If we're this far it's time to try the next character.... */
+ return 1;
+}
+
+/* Change a character value, try least-used characters first. */
+
+void
+Gen_Perf::change (List_Node *prior, List_Node *curr)
+{
+ static char *union_set;
+
+ if (!union_set)
+ union_set = new char [2 * option.get_max_keysig_size () + 1];
+
+ if (option[DEBUG])
+ {
+ fprintf (stderr, "collision on keyword #%d, prior = \"%s\", curr = \"%s\" hash = %d\n",
+ num_done, prior->key, curr->key, curr->hash_value);
+ fflush (stderr);
+ }
+ sort_set (union_set, compute_disjoint_union (prior->char_set, curr->char_set, union_set));
+
+ /* Try changing some values, if change doesn't alter other values continue normal action. */
+ fewest_collisions++;
+
+ for (char *temp = union_set; *temp; temp++)
+ if (!affects_prev (*temp, curr))
+ {
+ if (option[DEBUG])
+ {
+ fprintf (stderr, " by changing asso_value['%c'] (char #%d) to %d\n",
+ *temp, temp - union_set + 1, Vectors::asso_values[*temp]);
+ fflush (stderr);
+ }
+ return; /* Good, doesn't affect previous hash values, we'll take it. */
+ }
+
+ for (List_Node *ptr = this->key_list.head; ptr != curr; ptr = ptr->next)
+ hash (ptr);
+
+ hash (curr);
+
+ if (option[DEBUG])
+ {
+ fprintf (stderr, "** collision not resolved after %d iterations, %d duplicates remain, continuing...\n",
+ !option[FAST] ? option.get_asso_max () : option.get_iterations () ? option.get_iterations () : this->key_list.keyword_list_length (),
+ fewest_collisions + this->key_list.total_duplicates);
+ fflush (stderr);
+ }
+}
+
+/* Does the hard stuff....
+ Initializes the Iteration Number array, and attempts to find a perfect
+ function that will hash all the key words without getting any
+ duplications. This is made much easier since we aren't attempting
+ to generate *minimum* functions, only perfect ones.
+ If we can't generate a perfect function in one pass *and* the user
+ hasn't enabled the DUP option, we'll inform the user to try the
+ randomization option, use -D, or choose alternative key positions.
+ The alternatives (e.g., back-tracking) are too time-consuming, i.e,
+ exponential in the number of keys. */
+
+int
+Gen_Perf::generate (void)
+{
+#if LARGE_STACK_ARRAYS
+ STORAGE_TYPE buffer[max_hash_value + 1];
+#else
+ // Note: we don't use new, because that invokes a custom operator new.
+ STORAGE_TYPE *buffer
+ = (STORAGE_TYPE*) malloc (sizeof(STORAGE_TYPE) * (max_hash_value + 1));
+ if (buffer == NULL)
+ abort ();
+#endif
+
+ this->char_search.init (buffer, max_hash_value + 1);
+
+ List_Node *curr;
+
+ for (curr = this->key_list.head;
+ curr;
+ curr = curr->next)
+ {
+ hash (curr);
+
+ for (List_Node *ptr = this->key_list.head;
+ ptr != curr;
+ ptr = ptr->next)
+ if (ptr->hash_value == curr->hash_value)
+ {
+ change (ptr, curr);
+ break;
+ }
+ num_done++;
+ }
+
+ /* Make one final check, just to make sure nothing weird happened.... */
+
+ this->char_search.reset ();
+
+ for (curr = this->key_list.head;
+ curr;
+ curr = curr->next)
+ if (this->char_search.find (hash (curr)))
+ if (option[DUP]) /* Keep track of this number... */
+ this->key_list.total_duplicates++;
+ else /* Yow, big problems. we're outta here! */
+ {
+ ACE_ERROR ((LM_ERROR, "\nInternal error, duplicate value %d:\n"
+ "try options -D or -r, or use new key positions.\n\n", hash (curr)));
+#if !LARGE_STACK_ARRAYS
+ free (buffer);
+#endif
+ return 1;
+ }
+
+ /* Sorts the key word list by hash value, and then outputs the list.
+ The generated hash table code is only output if the early stage of
+ processing turned out O.K. */
+
+ this->key_list.sort ();
+ this->key_list.output ();
+#if !LARGE_STACK_ARRAYS
+ free (buffer);
+#endif
+ return 0;
+}
+
+/* Prints out some diagnostics upon completion. */
+
+Gen_Perf::~Gen_Perf (void)
+{
+ if (option[DEBUG])
+ {
+ fprintf (stderr, "\ndumping occurrence and associated values tables\n");
+
+ for (int i = 0; i < ALPHA_SIZE; i++)
+ if (Vectors::occurrences[i])
+ fprintf (stderr, "Vectors::asso_values[%c] = %6d, Vectors::occurrences[%c] = %6d\n",
+ i, Vectors::asso_values[i], i, Vectors::occurrences[i]);
+
+ fprintf (stderr, "end table dumping\n");
+
+ }
+}
+
diff --git a/apps/gperf/src/Gen_Perf.h b/apps/gperf/src/Gen_Perf.h
new file mode 100644
index 00000000000..11817de4851
--- /dev/null
+++ b/apps/gperf/src/Gen_Perf.h
@@ -0,0 +1,65 @@
+/* -*- C++ -*- */
+// @(#)Gen_Perf.h 1.1 10/18/96
+
+/* This may look like C code, but it is really -*- C++ -*- */
+
+/* Provides high-level routines to manipulate the keyword list
+ structures the code generation output.
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef gen_perf_h
+#define gen_perf_h 1
+
+#include "Options.h"
+#include "Key_List.h"
+#include "Bool_Array.h"
+
+class Gen_Perf
+{
+public:
+ Gen_Perf (void);
+ ~Gen_Perf (void);
+ int generate (void);
+
+private:
+ void change (List_Node *prior, List_Node *curr);
+ int affects_prev (char c, List_Node *curr);
+ static int hash (List_Node *key_node);
+ static int compute_disjoint_union (char *set_1, char *set_2, char *set_3);
+ static void sort_set (char *union_set, int len);
+
+ int max_hash_value;
+ // Maximum possible hash value.
+
+ int fewest_collisions;
+ // Records fewest # of collisions for asso value.
+
+ int num_done;
+ // Number of keywords processed without a collision.
+
+ Bool_Array char_search;
+ // Table that keeps track of key collisions.
+
+ Key_List key_list;
+ // List of the keys we're trying to map into a perfect hash
+ // function.
+};
+#endif
diff --git a/apps/gperf/src/Hash_Table.cpp b/apps/gperf/src/Hash_Table.cpp
new file mode 100644
index 00000000000..dfb008514ce
--- /dev/null
+++ b/apps/gperf/src/Hash_Table.cpp
@@ -0,0 +1,84 @@
+/* Hash table for checking keyword links. Implemented using double hashing.
+// @(#)Hash_Table.cpp 1.1 10/18/96
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "ace/ACE.h"
+#include "Hash_Table.h"
+
+#define NIL(TYPE) (TYPE *)0
+
+// The size of the hash table is always the smallest power of 2 >= the
+// size indicated by the user. This allows several optimizations,
+// including the use of double hashing and elimination of the mod
+// instruction. Note that the size had better be larger than the
+// number of items in the hash table, else there's trouble!!! Note
+// that the memory for the hash table is allocated *outside* the
+// intialization routine. This compromises information hiding
+// somewhat, but greatly reduces memory fragmentation, since we can
+// now use alloca!
+
+Hash_Table::Hash_Table (List_Node **table_ptr, int s)
+ : collisions (0),
+ size (s),
+ table (table_ptr)
+{
+ memset ((char *) table, 0, size * sizeof *table);
+}
+
+Hash_Table::~Hash_Table (void)
+{
+ if (option[DEBUG])
+ {
+ int field_width = option.get_max_keysig_size ();
+
+ fprintf (stderr, "\ndumping the hash table\ntotal available table slots = %d, total bytes = %d, total collisions = %d\n"
+ "location, %*s, keyword\n", size, size * sizeof *table, collisions, field_width, "keysig");
+
+ for (int i = size - 1; i >= 0; i--)
+ if (table[i])
+ fprintf (stderr, "%8d, %*s, %s\n",
+ i, field_width, table[i]->char_set, table[i]->key);
+
+ fprintf (stderr, "\nend dumping hash table\n\n");
+ }
+}
+
+// If the ITEM is already in the hash table return the item found in
+// the table. Otherwise inserts the ITEM, and returns FALSE. Uses
+// double hashing.
+
+List_Node *
+Hash_Table::operator() (List_Node *item, int ignore_length)
+{
+ unsigned hash_val = ACE::hash_pjw (item->char_set);
+ int probe = hash_val & size - 1;
+ int increment = (hash_val ^ item->length | 1) & size - 1;
+
+ while (table[probe]
+ && (strcmp (table[probe]->char_set, item->char_set)
+ || (!ignore_length && table[probe]->length != item->length)))
+ {
+ collisions++;
+ probe = probe + increment & size - 1;
+ }
+
+ return table[probe] ? table[probe] : (table[probe] = item, NIL (List_Node));
+}
diff --git a/apps/gperf/src/Hash_Table.h b/apps/gperf/src/Hash_Table.h
new file mode 100644
index 00000000000..c7a77a1b37b
--- /dev/null
+++ b/apps/gperf/src/Hash_Table.h
@@ -0,0 +1,50 @@
+/* -*- C++ -*- */
+// @(#)Hash_Table.h 1.1 10/18/96
+
+/* This may look like C code, but it is really -*- C++ -*- */
+
+/* Hash table used to check for duplicate keyword entries.
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef hash_table_h
+#define hash_table_h 1
+
+#include "Options.h"
+#include "List_Node.h"
+
+class Hash_Table
+{
+public:
+ Hash_Table (List_Node **t, int s);
+ ~Hash_Table (void);
+ List_Node *operator () (List_Node *item, int ignore_length);
+
+private:
+ List_Node **table;
+ // Vector of pointers to linked lists of List_Node's.
+
+ int size;
+ // Size of the vector.
+
+ int collisions;
+ // Find out how well our double hashing is working!
+};
+#endif
diff --git a/apps/gperf/src/Iterator.cpp b/apps/gperf/src/Iterator.cpp
new file mode 100644
index 00000000000..2e5d37f8f00
--- /dev/null
+++ b/apps/gperf/src/Iterator.cpp
@@ -0,0 +1,90 @@
+/* Provides an Iterator for keyword characters.
+// @(#)Iterator.cpp 1.1 10/18/96
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "Iterator.h"
+
+// Constructor for Iterator.
+
+Iterator::Iterator (char *s,
+ int lo,
+ int hi,
+ int word_end,
+ int bad_val,
+ int key_end)
+ : end (key_end),
+ error_value (bad_val),
+ end_word (word_end),
+ str (s),
+ hi_bound (hi),
+ lo_bound (lo)
+{
+}
+
+// Provide an Iterator, returning the ``next'' value from the list of
+// valid values given in the constructor.
+
+int
+Iterator::operator() (void)
+{
+ // Variables to record the Iterator's status when handling ranges,
+ // e.g., 3-12.
+
+ static int size;
+ static int curr_value;
+ static int upper_bound;
+
+ if (size)
+ {
+ if (++curr_value >= upper_bound)
+ size = 0;
+ return curr_value;
+ }
+ else
+ {
+ while (*str)
+ switch (*str)
+ {
+ default: return error_value;
+ case ',': str++; break;
+ case '$': str++; return end_word;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ for (curr_value = 0; isdigit (*str); str++)
+ curr_value = curr_value * 10 + *str - '0';
+
+ if (*str == '-')
+ {
+
+ for (size = 1, upper_bound = 0;
+ isdigit (*++str);
+ upper_bound = upper_bound * 10 + *str - '0');
+
+ if (upper_bound <= curr_value || upper_bound > hi_bound)
+ return error_value;
+ }
+ return curr_value >= lo_bound && curr_value <= hi_bound
+ ? curr_value : error_value;
+ }
+
+ return end;
+ }
+}
diff --git a/apps/gperf/src/Iterator.h b/apps/gperf/src/Iterator.h
new file mode 100644
index 00000000000..d2c81039b3f
--- /dev/null
+++ b/apps/gperf/src/Iterator.h
@@ -0,0 +1,67 @@
+/* -*- C++ -*- */
+// @(#)Iterator.h 1.1 10/18/96
+
+/* This may look like C code, but it is really -*- C++ -*- */
+
+/* Provides an Iterator for keyword characters.
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Provides an Iterator that expands and decodes a control string
+ containing digits and ranges, returning an integer every time the
+ generator function is called. This is used to decode the user's
+ key position requests. For example: "-k 1,2,5-10,$" will return 1,
+ 2, 5, 6, 7, 8, 9, 10, and 0 ( representing the abstract ``last
+ character of the key'' on successive calls to the member function
+ operator (). No errors are handled in these routines, they are
+ passed back to the calling routines via a user-supplied Error_Value */
+
+#ifndef iterator_h
+#define iterator_h 1
+
+#include "Options.h"
+
+class Iterator
+{
+public:
+ Iterator (char *s, int lo, int hi, int word_end, int bad_val, int key_end);
+ int operator () (void);
+
+private:
+ char *str;
+ // A pointer to the string provided by the user.
+
+ int end;
+ // Value returned after last key is processed.
+
+ int end_word;
+ // A value marking the abstract ``end of word'' (usually '$').
+
+ int error_value;
+ // Error value returned when input is syntactically erroneous.
+
+ int hi_bound;
+ // Greatest possible value, inclusive.
+
+ int lo_bound;
+ // Smallest possible value, inclusive.
+};
+
+#endif
diff --git a/apps/gperf/src/Key_List.cpp b/apps/gperf/src/Key_List.cpp
new file mode 100644
index 00000000000..3a944b4b28b
--- /dev/null
+++ b/apps/gperf/src/Key_List.cpp
@@ -0,0 +1,1345 @@
+/* Routines for building, ordering, and printing the keyword list.
+// @(#)Key_List.cpp 1.1 10/18/96
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "ace/Read_Buffer.h"
+#include "Hash_Table.h"
+#include "Vectors.h"
+#include "Key_List.h"
+
+/* Make the hash table 10 times larger than the number of keyword entries. */
+static const int TABLE_MULTIPLE = 10;
+
+/* Default type for generated code. */
+static char *const default_array_type = "char *";
+
+/* in_word_set return type, by default. */
+static char *const default_return_type = "char *";
+
+/* How wide the printed field width must be to contain the maximum hash value. */
+static int field_width = 0;
+
+static int determined[ALPHA_SIZE];
+
+/* Destructor dumps diagnostics during debugging. */
+
+Key_List::~Key_List (void)
+{
+ if (option[DEBUG])
+ {
+ fprintf (stderr, "\nDumping key list information:\ntotal non-static linked keywords = %d"
+ "\ntotal keywords = %d\ntotal duplicates = %d\nmaximum key length = %d\n",
+ list_len, total_keys, total_duplicates ? total_duplicates + 1 : 0, max_key_len);
+ dump ();
+ ACE_ERROR ((LM_ERROR, "End dumping list.\n\n"));
+ }
+}
+
+/* Gathers the input stream into a buffer until one of two things occur:
+
+ 1. We read a '%' followed by a '%'
+ 2. We read a '%' followed by a '}'
+
+ The first symbolizes the beginning of the keyword list proper,
+ The second symbolizes the end of the C source code to be generated
+ verbatim in the output file.
+
+ I assume that the keys are separated from the optional preceding struct
+ declaration by a consecutive % followed by either % or } starting in
+ the first column. The code below uses an expandible buffer to scan off
+ and return a pointer to all the code (if any) appearing before the delimiter. */
+
+char *
+Key_List::get_special_input (char delimiter)
+{
+ int size = 80;
+ char *buf = new char[size];
+ int c, i;
+
+ for (i = 0; (c = getchar ()) != EOF; i++)
+ {
+ if (c == '%')
+ {
+ if ((c = getchar ()) == delimiter)
+ {
+
+ while ((c = getchar ()) != '\n')
+ ; /* discard newline */
+
+ if (i == 0)
+ return "";
+ else
+ {
+ buf[delimiter == '%' && buf[i - 2] == ';' ? i - 2 : i - 1] = '\0';
+ return buf;
+ }
+ }
+ else
+ buf[i++] = '%';
+ }
+ else if (i >= size) /* Yikes, time to grow the buffer! */
+ {
+ char *temp = new char[size *= 2];
+ int j;
+
+ for (j = 0; j < i; j++)
+ temp[j] = buf[j];
+
+ buf = temp;
+ }
+ buf[i] = c;
+ }
+
+ return 0; /* Problem here. */
+}
+
+/* Stores any C text that must be included verbatim into the
+ generated code output. */
+
+char *
+Key_List::save_include_src (void)
+{
+ int c;
+
+ if ((c = getchar ()) != '%')
+ ungetc (c, stdin);
+ else if ((c = getchar ()) != '{')
+ ACE_ERROR ((LM_ERROR, "internal error, %c != '{' on line %d in file %s%a", c, __LINE__, __FILE__, 1));
+ else
+ return get_special_input ('}');
+ return "";
+}
+
+/* Determines from the input file whether the user wants to build a table
+ from a user-defined struct, or whether the user is content to simply
+ use the default array of keys. */
+
+char *
+Key_List::get_array_type (void)
+{
+ return get_special_input ('%');
+}
+
+/* strcspn - find length of initial segment of S consisting entirely
+ ANSI string package, when GNU libc comes out I'll replace this...). */
+
+inline int
+Key_List::strcspn (const char *s, const char *reject)
+{
+ const char *scan;
+ const char *rej_scan;
+ int count = 0;
+
+ for (scan = s; *scan; scan++)
+ {
+
+ for (rej_scan = reject; *rej_scan; rej_scan++)
+ if (*scan == *rej_scan)
+ return count;
+
+ count++;
+ }
+
+ return count;
+}
+
+/* Sets up the Return_Type, the Struct_Tag type and the Array_Type
+ based upon various user Options. */
+
+void
+Key_List::set_output_types (void)
+{
+ if (option[TYPE] && !(array_type = get_array_type ()))
+ return; /* Something's wrong, bug we'll catch it later on.... */
+ else if (option[TYPE]) /* Yow, we've got a user-defined type... */
+ {
+ int struct_tag_length = strcspn (array_type, "{\n\0");
+
+ if (option[POINTER]) /* And it must return a pointer... */
+ {
+ return_type = new char[struct_tag_length + 2];
+ strncpy (return_type, array_type, struct_tag_length);
+ return_type[struct_tag_length] = '*';
+ return_type[struct_tag_length + 1] = '\0';
+ }
+
+ struct_tag = new char[struct_tag_length + 1];
+ strncpy (struct_tag, array_type, struct_tag_length);
+ struct_tag[struct_tag_length] = '\0';
+ }
+ else if (option[POINTER]) /* Return a char *. */
+ return_type = default_array_type;
+}
+
+/* Reads in all keys from standard input and creates a linked list pointed
+ to by Head. This list is then quickly checked for ``links,'' i.e.,
+ unhashable elements possessing identical key sets and lengths. */
+
+void
+Key_List::read_keys (void)
+{
+ include_src = save_include_src ();
+ set_output_types ();
+
+ ACE_Read_Buffer input (stdin);
+
+ char *ptr = input.read ('\n');
+
+ if (ptr == 0)
+ // Oops, problem with the input file.
+ ACE_ERROR ((LM_ERROR, "No words in input file, did you forget to prepend %s"
+ " or use -t accidentally?\n%a", "%%", 1));
+
+ /* Read in all the keywords from the input file. */
+ else
+ {
+ const char *delimiter = option.get_delimiter ();
+ List_Node *temp, *trail = 0;
+
+ head = new List_Node (ptr, strcspn (ptr, delimiter));
+
+ for (temp = head;
+ (ptr = input.read ('\n')) && strcmp (ptr, "%%");
+ temp = temp->next)
+ {
+ temp->next = new List_Node (ptr, strcspn (ptr, delimiter));
+ total_keys++;
+ }
+
+ /* See if any additional source code is included at end of this file. */
+ if (ptr)
+ additional_code = 1;
+
+ /* Hash table this number of times larger than keyword number. */
+ int table_size = (list_len = total_keys) * TABLE_MULTIPLE;
+
+#if LARGE_STACK_ARRAYS
+ /* By allocating the memory here we save on dynamic allocation overhead.
+ Table must be a power of 2 for the hash function scheme to work. */
+ List_Node *table[ACE_POW (table_size)];
+#else
+ // Note: we don't use new, because that invokes a custom operator new.
+ int malloc_size = ACE_POW (table_size) * sizeof(List_Node*);
+ if (malloc_size == 0) malloc_size = 1;
+ List_Node **table = (List_Node**)malloc(malloc_size);
+ if (table == NULL)
+ abort ();
+#endif
+
+ /* Make large hash table for efficiency. */
+ Hash_Table found_link (table, table_size);
+
+ /* Test whether there are any links and also set the maximum length of
+ an identifier in the keyword list. */
+
+ for (temp = head; temp; temp = temp->next)
+ {
+ List_Node *ptr = found_link (temp, option[NOLENGTH]);
+
+ /* Check for links. We deal with these by building an equivalence class
+ of all duplicate values (i.e., links) so that only 1 keyword is
+ representative of the entire collection. This *greatly* simplifies
+ processing during later stages of the program. */
+
+ if (ptr)
+ {
+ total_duplicates++;
+ list_len--;
+ trail->next = temp->next;
+ temp->link = ptr->link;
+ ptr->link = temp;
+
+ /* Complain if user hasn't enabled the duplicate option. */
+ if (!option[DUP] || option[DEBUG])
+ ACE_ERROR ((LM_ERROR, "Key link: \"%s\" = \"%s\", with key set \"%s\".\n",
+ temp->key, ptr->key, temp->char_set));
+ }
+ else
+ trail = temp;
+
+ /* Update minimum and maximum keyword length, if needed. */
+ if (max_key_len < temp->length)
+ max_key_len = temp->length;
+ if (min_key_len > temp->length)
+ min_key_len = temp->length;
+ }
+
+#if !LARGE_STACK_ARRAYS
+ free (table);
+#endif
+
+ /* Exit program if links exists and option[DUP] not set, since we can't continue */
+ if (total_duplicates)
+ ACE_ERROR ((LM_ERROR, option[DUP]
+ ? "%d input keys have identical hash values, examine output carefully...\n"
+ : "%d input keys have identical hash values,\ntry different key positions or use option -D.\n%a", total_duplicates, 1));
+ if (option[ALLCHARS])
+ option.set_keysig_size (max_key_len);
+ }
+}
+
+/* Recursively merges two sorted lists together to form one sorted list. The
+ ordering criteria is by frequency of occurrence of elements in the key set
+ or by the hash value. This is a kludge, but permits nice sharing of
+ almost identical code without incurring the overhead of a function
+ call comparison. */
+
+List_Node *
+Key_List::merge (List_Node *list1, List_Node *list2)
+{
+ if (!list1)
+ return list2;
+ else if (!list2)
+ return list1;
+ else if (occurrence_sort && list1->occurrence < list2->occurrence
+ || hash_sort && list1->hash_value > list2->hash_value)
+ {
+ list2->next = merge (list2->next, list1);
+ return list2;
+ }
+ else
+ {
+ list1->next = merge (list1->next, list2);
+ return list1;
+ }
+}
+
+/* Applies the merge sort algorithm to recursively sort the key list by
+ frequency of occurrence of elements in the key set. */
+
+List_Node *
+Key_List::merge_sort (List_Node *a_head)
+{
+ if (!a_head || !a_head->next)
+ return a_head;
+ else
+ {
+ List_Node *middle = a_head;
+ List_Node *temp = a_head->next->next;
+
+ while (temp)
+ {
+ temp = temp->next;
+ middle = middle->next;
+ if (temp)
+ temp = temp->next;
+ }
+
+ temp = middle->next;
+ middle->next = 0;
+ return merge (merge_sort (a_head), merge_sort (temp));
+ }
+}
+
+/* Returns the frequency of occurrence of elements in the key set. */
+
+inline int
+Key_List::get_occurrence (List_Node *ptr)
+{
+ int value = 0;
+
+ for (char *temp = ptr->char_set; *temp; temp++)
+ value += Vectors::occurrences[*temp];
+
+ return value;
+}
+
+/* Enables the index location of all key set elements that are now
+ determined. */
+
+inline void
+Key_List::set_determined (List_Node *ptr)
+{
+ for (char *temp = ptr->char_set; *temp; temp++)
+ determined[*temp] = 1;
+}
+
+/* Returns TRUE if PTR's key set is already completely determined. */
+
+inline int
+Key_List::already_determined (List_Node *ptr)
+{
+ int is_determined = 1;
+
+ for (char *temp = ptr->char_set; is_determined && *temp; temp++)
+ is_determined = determined[*temp];
+
+ return is_determined;
+}
+
+/* Reorders the table by first sorting the list so that frequently occuring
+ keys appear first, and then the list is reorded so that keys whose values
+ are already determined will be placed towards the front of the list. This
+ helps prune the search time by handling inevitable collisions early in the
+ search process. See Cichelli's paper from Jan 1980 JACM for details.... */
+
+void
+Key_List::reorder (void)
+{
+ List_Node *ptr;
+
+ for (ptr = head; ptr; ptr = ptr->next)
+ ptr->occurrence = get_occurrence (ptr);
+
+ occurrence_sort = !(hash_sort = 0); /* Pretty gross, eh?! */
+
+ for (ptr = head = merge_sort (head); ptr->next; ptr = ptr->next)
+ {
+ set_determined (ptr);
+
+ if (already_determined (ptr->next))
+ continue;
+ else
+ {
+ List_Node *trail_ptr = ptr->next;
+ List_Node *run_ptr = trail_ptr->next;
+
+ for (; run_ptr; run_ptr = trail_ptr->next)
+ {
+
+ if (already_determined (run_ptr))
+ {
+ trail_ptr->next = run_ptr->next;
+ run_ptr->next = ptr->next;
+ ptr = ptr->next = run_ptr;
+ }
+ else
+ trail_ptr = run_ptr;
+ }
+ }
+ }
+}
+
+/* Outputs the maximum and minimum hash values. Since the
+ list is already sorted by hash value all we need to do is
+ find the final item! */
+
+void
+Key_List::output_min_max ()
+{
+ List_Node *temp;
+ for (temp = head; temp->next; temp = temp->next)
+ ;
+
+ min_hash_value = head->hash_value;
+ max_hash_value = temp->hash_value;
+
+ if (!option[ENUM])
+ printf ("\n#define TOTAL_KEYWORDS %d\n#define MIN_WORD_LENGTH %d"
+ "\n#define MAX_WORD_LENGTH %d\n#define MIN_HASH_VALUE %d"
+ "\n#define MAX_HASH_VALUE %d\n#define HASH_VALUE_RANGE %d"
+ "\n#define DUPLICATES %d\n\n",
+ total_keys, min_key_len, max_key_len, min_hash_value,
+ max_hash_value, max_hash_value - min_hash_value + 1,
+ total_duplicates ? total_duplicates + 1 : 0);
+ else if (option[GLOBAL])
+ printf ("enum\n{\n"
+ " TOTAL_KEYWORDS = %d,\n"
+ " MIN_WORD_LENGTH = %d,\n"
+ " MAX_WORD_LENGTH = %d,\n"
+ " MIN_HASH_VALUE = %d,\n"
+ " MAX_HASH_VALUE = %d,\n"
+ " HASH_VALUE_RANGE = %d,\n"
+ " DUPLICATES = %d\n};\n\n",
+ total_keys, min_key_len, max_key_len, min_hash_value,
+ max_hash_value, max_hash_value - min_hash_value + 1,
+ total_duplicates ? total_duplicates + 1 : 0);
+}
+
+/* Generates the output using a C switch. This trades increased
+ search time for decreased table space (potentially *much* less
+ space for sparse tables). It the user has specified their own
+ struct in the keyword file *and* they enable the POINTER option we
+ have extra work to do. The solution here is to maintain a local
+ static array of user defined struct's, as with the
+ Output_Lookup_Function. Then we use for switch statements to
+ perform either a strcmp or strncmp, returning 0 if the str fails to
+ match, and otherwise returning a pointer to appropriate index
+ location in the local static array. */
+
+void
+Key_List::output_switch (void)
+{
+ char *comp_buffer;
+ List_Node *curr = head;
+ int pointer_and_type_enabled = option[POINTER] && option[TYPE];
+ int total_switches = option.get_total_switches ();
+ int switch_size = keyword_list_length () / total_switches;
+
+ if (pointer_and_type_enabled)
+ {
+#if defined (__GNUG__)
+ comp_buffer = (char *) alloca (strlen ("charmap[*str] == *resword->%s && !strncasecmp (str + 1, resword->%s + 1, len - 1)")
+ + 2 * strlen (option.get_key_name ()) + 1);
+#else
+ comp_buffer = new char [strlen ("charmap[*str] == *resword->%s && !strncasecmp (str + 1, resword->%s + 1, len - 1)")
+ + 2 * strlen (option.get_key_name ()) + 1];
+#endif
+ if (option[COMP])
+ sprintf (comp_buffer, "%s == *resword->%s && !%s (str + 1, resword->%s + 1, len - 1)",
+ option[STRCASECMP] ? "charmap[*str]" : "*str", option.get_key_name (),
+ option[STRCASECMP] ? "strncasecmp" : "strncmp", option.get_key_name ());
+ else
+ sprintf (comp_buffer, "%s == *resword->%s && !%s (str + 1, resword->%s + 1)",
+ option[STRCASECMP] ? "charmap[*str]" : "*str", option.get_key_name (),
+ option[STRCASECMP] ? "strcasecmp" : "strcmp", option.get_key_name ());
+ }
+ else
+ {
+ if (option[COMP])
+ comp_buffer = option[STRCASECMP]
+ ? "charmap[*str] == *resword && !strncasecmp (str + 1, resword + 1, len - 1)"
+ : "*str == *resword && !strncmp (str + 1, resword + 1, len - 1)";
+ else
+ comp_buffer = option[STRCASECMP]
+ ? "charmap[*str] == *resword && !strcasecmp (str + 1, resword + 1, len - 1)"
+ : "*str == *resword && !strcmp (str + 1, resword + 1, len - 1)";
+ }
+ if (!option[OPTIMIZE])
+ printf (" if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n {\n");
+ printf (" register int key = %s (str, len);\n\n", option.get_hash_name ());
+ if (!option[OPTIMIZE])
+ printf (" if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n");
+
+ printf (" {\n");
+
+ /* Properly deal with user's who request multiple switch statements. */
+
+ while (curr)
+ {
+ List_Node *temp = curr;
+ int lowest_case_value = curr->hash_value;
+ int number_of_cases = 0;
+
+ /* Figure out a good cut point to end this switch. */
+
+ for (; temp && ++number_of_cases < switch_size; temp = temp->next)
+ if (temp->next && temp->hash_value == temp->next->hash_value)
+ while (temp->next && temp->hash_value == temp->next->hash_value)
+ temp = temp->next;
+
+ if (temp && total_switches != 1)
+ printf (" if (key <= %d)\n {\n", temp->hash_value);
+ else
+ printf (" {\n");
+
+ /* Output each keyword as part of a switch statement indexed by hash value. */
+
+ if (option[POINTER] || option[DUP])
+ {
+ int i = 0;
+
+ printf (" %s%s *resword; %s\n\n",
+ option[CONST] ? "const " : "",
+ pointer_and_type_enabled ? struct_tag : "char",
+ option[LENTABLE] && !option[DUP] ? "int key_len;" : "");
+ if (total_switches == 1)
+ {
+ printf (" switch (key)\n {\n");
+ lowest_case_value = 0;
+ }
+ else
+ printf (" switch (key - %d)\n {\n", lowest_case_value);
+
+ for (temp = curr; temp && ++i <= number_of_cases; temp = temp->next)
+ {
+ printf (" case %*d:", field_width, temp->hash_value - lowest_case_value);
+ if (option[DEBUG])
+ printf (" /* hash value = %4d, keyword = \"%s\" */", temp->hash_value, temp->key);
+ putchar ('\n');
+
+ /* Handle `natural links,' i.e., those that occur statically. */
+
+ if (temp->link)
+ {
+ List_Node *links;
+
+ for (links = temp; links; links = links->link)
+ {
+ if (pointer_and_type_enabled)
+ printf (" resword = &wordlist[%d];\n", links->index);
+ else
+ printf (" resword = \"%s\";\n", links->key);
+ printf (" if (%s) return resword;\n", comp_buffer);
+ }
+ }
+ /* Handle unresolved duplicate hash values. These are guaranteed
+ to be adjacent since we sorted the keyword list by increasing
+ hash values. */
+ if (temp->next && temp->hash_value == temp->next->hash_value)
+ {
+
+ for ( ; temp->next && temp->hash_value == temp->next->hash_value;
+ temp = temp->next)
+ {
+ if (pointer_and_type_enabled)
+ printf (" resword = &wordlist[%d];\n", temp->index);
+ else
+ printf (" resword = \"%s\";\n", temp->key);
+ printf (" if (%s) return resword;\n", comp_buffer);
+ }
+ if (pointer_and_type_enabled)
+ printf (" resword = &wordlist[%d];\n", temp->index);
+ else
+ printf (" resword = \"%s\";\n", temp->key);
+ printf (" return %s ? resword : 0;\n", comp_buffer);
+ }
+ else if (temp->link)
+ printf (" return 0;\n");
+ else
+ {
+ if (pointer_and_type_enabled)
+ printf (" resword = &wordlist[%d];", temp->index);
+ else
+ printf (" resword = \"%s\";", temp->key);
+ if (option[LENTABLE] && !option[DUP])
+ printf (" key_len = %d;", temp->length);
+ printf (" break;\n");
+ }
+ }
+ printf (" default: return 0;\n }\n");
+ if (option[OPTIMIZE])
+ printf (" return resword;\n");
+ else
+ {
+ printf (option[LENTABLE] && !option[DUP]
+ ? " if (len == key_len && %s)\n return resword;\n"
+ : " if (%s)\n return resword;\n", comp_buffer);
+ printf (" return 0;\n");
+ }
+ printf (" }\n");
+ curr = temp;
+ }
+ else /* Nothing special required here. */
+ {
+ int i = 0;
+ printf (" char *s;\n\n switch (key - %d)\n {\n",
+ lowest_case_value);
+
+ for (temp = curr; temp && ++i <= number_of_cases; temp = temp->next)
+ if (option[LENTABLE])
+ printf (" case %*d: if (len == %d) s = \"%s\"; else return 0; break;\n",
+ field_width, temp->hash_value - lowest_case_value,
+ temp->length, temp->key);
+ else
+ printf (" case %*d: s = \"%s\"; break;\n",
+ field_width, temp->hash_value - lowest_case_value, temp->key);
+
+ printf (" default: return 0;\n }\n ");
+ if (option[COMP])
+ printf ("return %s == *s && !%s;\n }\n",
+ option[STRCASECMP] ? "charmap[*str]" : "*str",
+ option[STRCASECMP] ? "strncasecmp (s + 1, str + 1, len - 1)" : "strcmp (s + 1, str + 1)");
+ else
+ printf ("return %s == *s && !%s;\n }\n",
+ option[STRCASECMP] ? "charmap[*str]" : "*str",
+ option[STRCASECMP] ? "strcasecmp (s + 1, str + 1, len - 1)" : "strcmp (s + 1, str + 1)");
+ curr = temp;
+ }
+ }
+ printf (" }\n %s\n}\n", option[OPTIMIZE] ? "" : "}\n return 0;");
+}
+
+/* Prints out a table of keyword lengths, for use with the
+ comparison code in generated function ``in_word_set.'' */
+
+void
+Key_List::output_keylength_table (void)
+{
+ const int max_column = 15;
+ int index = 0;
+ int column = 0;
+ char *indent = option[GLOBAL] ? "" : " ";
+ List_Node *temp;
+
+ if (!option[DUP] && !option[SWITCH])
+ {
+ printf ("\n%sstatic %sunsigned %s lengthtable[] =\n%s%s{\n ",
+ indent, option[CONST] ? "const " : "",
+ max_key_len <= UCHAR_MAX ? "char" : (max_key_len <= USHRT_MAX ? "short" : "long"),
+ indent, indent);
+
+ for (temp = head; temp; temp = temp->next, index++)
+ {
+
+ if (index < temp->hash_value)
+ for ( ; index < temp->hash_value; index++)
+ printf ("%3d,%s", 0, ++column % (max_column - 1) ? "" : "\n ");
+
+ printf ("%3d,%s", temp->length, ++column % (max_column - 1 ) ? "" : "\n ");
+ }
+
+ printf ("\n%s%s};\n", indent, indent);
+ }
+}
+/* Prints out the array containing the key words for the Gen_Perf
+ hash function. */
+
+void
+Key_List::output_keyword_table (void)
+{
+ char *l_brace = *head->rest ? "{" : "";
+ char *r_brace = *head->rest ? "}," : "";
+ char *indent = option[GLOBAL] ? "" : " ";
+ int index = 0;
+ List_Node *temp;
+
+ printf ("%sstatic %s%swordlist[] =\n%s%s{\n",
+ indent, option[CONST] ? "const " : "", struct_tag, indent, indent);
+
+ /* Skip over leading blank entries if there are no duplicates. */
+
+ if (0 < head->hash_value)
+ printf (" ");
+ for (int column = 1; index < head->hash_value; index++, column++)
+ printf ("%s\"\",%s %s", l_brace, r_brace, column % 9 ? "" : "\n ");
+ if (0 < head->hash_value && column % 10)
+ printf ("\n");
+
+ /* Generate an array of reserved words at appropriate locations. */
+
+ for (temp = head ; temp; temp = temp->next, index++)
+ {
+ temp->index = index;
+
+ if (!option[SWITCH] && (total_duplicates == 0 || !option[DUP]) && index < temp->hash_value)
+ {
+ int column;
+
+ printf (" ");
+
+ for (column = 1; index < temp->hash_value; index++, column++)
+ printf ("%s\"\",%s %s", l_brace, r_brace, column % 9 ? "" : "\n ");
+
+ if (column % 10)
+ printf ("\n");
+ else
+ {
+ printf ("%s\"%s\", %s%s", l_brace, temp->key, temp->rest, r_brace);
+ if (option[DEBUG])
+ printf (" /* hash value = %d, index = %d */", temp->hash_value, temp->index);
+ putchar ('\n');
+ continue;
+ }
+ }
+
+ printf (" %s\"%s\", %s%s", l_brace, temp->key, temp->rest, r_brace);
+ if (option[DEBUG])
+ printf (" /* hash value = %d, index = %d */", temp->hash_value, temp->index);
+ putchar ('\n');
+
+ /* Deal with links specially. */
+ if (temp->link)
+ for (List_Node *links = temp->link; links; links = links->link)
+ {
+ links->index = ++index;
+ printf (" %s\"%s\", %s%s", l_brace, links->key, links->rest, r_brace);
+ if (option[DEBUG])
+ printf (" /* hash value = %d, index = %d */", links->hash_value, links->index);
+ putchar ('\n');
+ }
+ }
+ printf ("%s%s};\n\n", indent, indent);
+}
+
+/* Generates C code for the hash function that returns the
+ proper encoding for each key word. */
+
+void
+Key_List::output_hash_function (void)
+{
+ const int max_column = 10;
+ int count = max_hash_value;
+
+ /* Calculate maximum number of digits required for MAX_HASH_VALUE. */
+
+ for (field_width = 2; (count /= 10) > 0; field_width++)
+ ;
+
+ if (option[GNU])
+ printf ("#ifdef __GNUC__\ninline\n#endif\n");
+
+ if (option[C])
+ printf ("static ");
+ printf ("unsigned int\n");
+ if (option[CPLUSPLUS])
+ printf ("%s::", option.get_class_name ());
+
+ printf (option[ANSI]
+ ? "%s (register const char *str, register int len)\n{\n static %sunsigned %s asso_values[] =\n {"
+ : "%s (str, len)\n register char *str;\n register int unsigned len;\n{\n static %sunsigned %s asso_values[] =\n {",
+ option.get_hash_name (), option[CONST] ? "const " : "",
+ max_hash_value <= UCHAR_MAX ? "char" : (max_hash_value <= USHRT_MAX ? "short" : "int"));
+
+ for (count = 0; count < ALPHA_SIZE; ++count)
+ {
+ if (!(count % max_column))
+ printf ("\n ");
+
+ printf ("%*d,",
+ field_width,
+ Vectors::occurrences[count] ? Vectors::asso_values[count] : max_hash_value + 1);
+ }
+
+ /* Optimize special case of ``-k 1,$'' */
+ if (option[DEFAULTCHARS])
+ {
+ if (option[STRCASECMP])
+ printf ("\n };\n return %sasso_values[charmap[str[len - 1]]] + asso_values[charmap[str[0]]];\n}\n\n",
+ option[NOLENGTH] ? "" : "len + ");
+ else
+ printf ("\n };\n return %sasso_values[str[len - 1]] + asso_values[str[0]];\n}\n\n",
+ option[NOLENGTH] ? "" : "len + ");
+ }
+ else
+ {
+ int key_pos;
+
+ option.reset ();
+
+ /* Get first (also highest) key position. */
+ key_pos = option.get ();
+
+ /* We can perform additional optimizations here. */
+ if (!option[ALLCHARS] && key_pos <= min_key_len)
+ {
+ printf ("\n };\n return %s", option[NOLENGTH] ? "" : "len + ");
+
+ for (; key_pos != WORD_END; )
+ {
+ printf (option[STRCASECMP] ? "asso_values[charmap[str[%d]]]" : "asso_values[str[%d]]", key_pos - 1);
+ if ((key_pos = option.get ()) != EOS)
+ printf (" + ");
+ else
+ break;
+ }
+
+ printf ("%s;\n}\n\n", key_pos == WORD_END
+ ? (option[STRCASECMP] ? "asso_values[charmap[str[len - 1]]]" : "asso_values[str[len - 1]]")
+ : "");
+ }
+
+ /* We've got to use the correct, but brute force, technique. */
+ else
+ {
+ printf ("\n };\n register int hval = %s;\n\n switch (%s)\n {\n default:\n",
+ option[NOLENGTH] ? "0" : "len", option[NOLENGTH] ? "len" : "hval");
+
+ /* User wants *all* characters considered in hash. */
+ if (option[ALLCHARS])
+ {
+ int i;
+
+ /* Break these options up for speed (gee, is this misplaced efficiency or what?! */
+ if (option[STRCASECMP])
+
+ for (i = max_key_len; i > 0; i--)
+ printf (" case %d:\n hval += asso_values[charmap[str[%d]]];\n", i, i - 1);
+
+ else
+
+ for (i = max_key_len; i > 0; i--)
+ printf (" case %d:\n hval += asso_values[str[%d]];\n", i, i - 1);
+
+ printf (" }\n return hval;\n}\n\n");
+ }
+ else /* do the hard part... */
+ {
+ count = key_pos + 1;
+
+ do
+ {
+
+ while (--count > key_pos)
+ printf (" case %d:\n", count);
+
+ printf (option[STRCASECMP]
+ ? " case %d:\n hval += asso_values[charmap[str[%d]]];\n"
+ : " case %d:\n hval += asso_values[str[%d]];\n",
+ key_pos, key_pos - 1);
+ }
+ while ((key_pos = option.get ()) != EOS && key_pos != WORD_END);
+
+ printf (" }\n return hval%s;\n}\n\n",
+ key_pos == WORD_END
+ ? (option[STRCASECMP] ? " + asso_values[charmap[str[len - 1]]]" : " + asso_values[str[len - 1]]")
+ : "");
+ }
+ }
+ }
+}
+
+/* Generates the large, sparse table that maps hash values into
+ the smaller, contiguous range of the keyword table. */
+
+void
+Key_List::output_lookup_array (void)
+{
+ if (total_duplicates > 0)
+ {
+ const int DEFAULT_VALUE = -1;
+
+ struct duplicate_entry
+ {
+ int hash_value; /* Hash value for this particular duplicate set. */
+ int index; /* Index into the main keyword storage array. */
+ int count; /* Number of consecutive duplicates at this index. */
+ };
+#if LARGE_STACK_ARRAYS
+ duplicate_entry duplicates[total_duplicates];
+ int lookup_array[max_hash_value + 1];
+#else
+ // Note: we don't use new, because that invokes a custom operator new.
+ duplicate_entry *duplicates = (duplicate_entry*)
+ malloc (total_duplicates * sizeof(duplicate_entry));
+ int *lookup_array = (int*)malloc(sizeof(int) * (max_hash_value + 1));
+ if (duplicates == NULL || lookup_array == NULL)
+ abort();
+#endif
+ duplicate_entry *dup_ptr = duplicates;
+ int *lookup_ptr = lookup_array + max_hash_value + 1;
+
+ while (lookup_ptr > lookup_array)
+ *--lookup_ptr = DEFAULT_VALUE;
+
+ for (List_Node *temp = head; temp; temp = temp->next)
+ {
+ int hash_value = temp->hash_value;
+ lookup_array[hash_value] = temp->index;
+ if (option[DEBUG])
+ fprintf (stderr, "keyword = %s, index = %d\n", temp->key, temp->index);
+ if (!temp->link &&
+ (!temp->next || hash_value != temp->next->hash_value))
+ continue;
+#if LARGE_STACK_ARRAYS
+ *dup_ptr = (duplicate_entry) { hash_value, temp->index, 1 };
+#else
+ duplicate_entry _dups;
+ _dups.hash_value = hash_value;
+ _dups.index = temp->index;
+ _dups.count = 1;
+ *dup_ptr = _dups;
+#endif
+
+ for (List_Node *ptr = temp->link; ptr; ptr = ptr->link)
+ {
+ dup_ptr->count++;
+ if (option[DEBUG])
+ fprintf (stderr, "static linked keyword = %s, index = %d\n", ptr->key, ptr->index);
+ }
+
+ while (temp->next && hash_value == temp->next->hash_value)
+ {
+ temp = temp->next;
+ dup_ptr->count++;
+ if (option[DEBUG])
+ fprintf (stderr, "dynamic linked keyword = %s, index = %d\n", temp->key, temp->index);
+
+ for (List_Node *ptr = temp->link; ptr; ptr = ptr->link)
+ {
+ dup_ptr->count++;
+ if (option[DEBUG])
+ fprintf (stderr, "static linked keyword = %s, index = %d\n", ptr->key, ptr->index);
+ }
+ }
+ dup_ptr++;
+ }
+
+ while (--dup_ptr >= duplicates)
+ {
+ if (option[DEBUG])
+ fprintf (stderr, "dup_ptr[%d]: hash_value = %d, index = %d, count = %d\n",
+ dup_ptr - duplicates, dup_ptr->hash_value, dup_ptr->index, dup_ptr->count);
+
+ /* Start searching for available space towards the right part of the lookup array. */
+ int i;
+ for (i = dup_ptr->hash_value; i < max_hash_value; i++)
+ if (lookup_array[i] == DEFAULT_VALUE && lookup_array[i + 1] == DEFAULT_VALUE)
+ {
+ lookup_array[i] = -dup_ptr->index;
+ lookup_array[i + 1] = -dup_ptr->count;
+ lookup_array[dup_ptr->hash_value] = max_hash_value + (i - dup_ptr->hash_value);
+ break;
+ }
+
+ /* If we didn't find it to the right look to the left instead... */
+ if (i == max_hash_value)
+ {
+
+ for (i = dup_ptr->hash_value; i > 0; i--)
+ if (lookup_array[i] == DEFAULT_VALUE && lookup_array[i - 1] == DEFAULT_VALUE)
+ {
+ lookup_array[i - 1] = -dup_ptr->index;
+ lookup_array[i] = -dup_ptr->count;
+ lookup_array[dup_ptr->hash_value] = -(max_hash_value + (dup_ptr->hash_value - i + 1));
+ break;
+ }
+
+ /* We are in *big* trouble if this happens! */
+ assert (i != 0);
+ }
+ }
+
+ int max = INT_MIN;
+ lookup_ptr = lookup_array + max_hash_value + 1;
+ while (lookup_ptr > lookup_array)
+ {
+ int val = abs (*--lookup_ptr);
+ if (max < val)
+ max = val;
+ }
+
+ char *indent = option[GLOBAL] ? "" : " ";
+ printf ("%sstatic %s%s lookup[] =\n%s%s{\n ", indent, option[CONST] ? "const " : "",
+ max <= SCHAR_MAX ? "char" : (max <= USHRT_MAX ? "short" : "int"),
+ indent, indent);
+
+ int count = max;
+
+ /* Calculate maximum number of digits required for MAX_HASH_VALUE. */
+
+ for (field_width = 2; (count /= 10) > 0; field_width++)
+ ;
+
+ const int max_column = 15;
+ int column = 0;
+
+ for (lookup_ptr = lookup_array;
+ lookup_ptr < lookup_array + max_hash_value + 1;
+ lookup_ptr++)
+ printf ("%*d,%s", field_width, *lookup_ptr, ++column % (max_column - 1) ? "" : "\n ");
+
+ printf ("\n%s%s};\n\n", indent, indent);
+#if !LARGE_STACK_ARRAYS
+ free (duplicates);
+ free (lookup_array);
+#endif
+ }
+}
+/* Generates C code to perform the keyword lookup. */
+
+void
+Key_List::output_lookup_function (void)
+{
+ if (!option[OPTIMIZE])
+ printf (" if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n {\n");
+ printf (" register int key = %s (str, len);\n\n", option.get_hash_name ());
+ if (!option[OPTIMIZE])
+ printf (" if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n");
+ printf (" {\n");
+
+ if (option[DUP] && total_duplicates > 0)
+ {
+ printf (" register int index = lookup[key];\n\n"
+ " if (index >= 0 && index < MAX_HASH_VALUE)\n");
+ if (option[OPTIMIZE])
+ printf (" return %swordlist[index];\n", option[TYPE] && option[POINTER] ? "&" : "");
+ else
+ {
+ printf (" {\n"
+ " register %schar *s = wordlist[index]", option[CONST] ? "const " : "");
+ if (array_type != default_array_type)
+ printf (".%s", option.get_key_name ());
+
+ printf (";\n\n if (%s%s == *s && !%s)\n return %s;\n }\n",
+ option[LENTABLE] ? "len == lengthtable[key]\n && " : "",
+ option[STRCASECMP] ? "charmap[*str]" : "*str",
+ option[COMP] ? (option[STRCASECMP] ? "strncasecmp (str + 1, s + 1, len - 1)" : "strncmp (str + 1, s + 1, len - 1)")
+ : (option[STRCASECMP] ? "strcasecmp (str + 1, s + 1)" : "strcmp (str + 1, s + 1)"),
+ option[TYPE] && option[POINTER] ? "&wordlist[index]" : "s");
+ printf (" else if (index < 0 && index >= -MAX_HASH_VALUE)\n"
+ " return 0;\n");
+ }
+ printf (" else\n {\n"
+ " register int offset = key + index + (index > 0 ? -MAX_HASH_VALUE : MAX_HASH_VALUE);\n"
+ " register %s%s*base = &wordlist[-lookup[offset]];\n"
+ " register %s%s*ptr = base + -lookup[offset + 1];\n\n"
+ " while (--ptr >= base)\n ",
+ option[CONST] ? "const " : "", struct_tag,
+ option[CONST] ? "const " : "", struct_tag);
+ if (array_type != default_array_type)
+ {
+ if (option[COMP])
+ printf ("if (%s == *ptr->%s && !%s (str + 1, ptr->%s + 1, len - 1",
+ option[STRCASECMP] ? "charmap[*str]" : "*str", option.get_key_name (),
+ option[STRCASECMP] ? "strncasecmp" : "strncmp", option.get_key_name ());
+ else
+ printf ("if (%s == *ptr->%s && !%s (str + 1, ptr->%s + 1",
+ option[STRCASECMP] ? "charmap[*str]" : "*str", option.get_key_name (),
+ option[STRCASECMP] ? "strcasecmp" : "strcmp", option.get_key_name ());
+ }
+ else
+ printf (option[STRCASECMP] ? "if (charmap[*str] == **ptr && !%s" : "if (*str == **ptr && !%s",
+ option[COMP]
+ ? (option[STRCASECMP] ? "strncasecmp (str + 1, *ptr + 1, len - 1" : "strncmp (str + 1, *ptr + 1, len - 1")
+ : (option[STRCASECMP] ? "strcasecmp (str + 1, *ptr + 1" : "strcmp (str + 1, *ptr + 1"));
+ printf ("))\n return %sptr;"
+ "\n }\n }\n %s\n}\n", array_type ==
+ default_array_type ? "*" : "", option[OPTIMIZE] ? "" : "}\n return 0;");
+ }
+ else
+ {
+ if (option[OPTIMIZE])
+ printf (" return %swordlist[key]", option[TYPE] && option[POINTER] ? "&" : "");
+ else
+ {
+ printf (" register %schar *s = wordlist[key]", option[CONST] ? "const " : "");
+
+ if (array_type != default_array_type)
+ printf (".%s", option.get_key_name ());
+
+ printf (";\n\n if (%s%s == *s && !%s)\n return %s",
+ option[LENTABLE] ? "len == lengthtable[key]\n && " : "",
+ option[STRCASECMP] ? "charmap[*str]" : "*str",
+ option[COMP]
+ ? (option[STRCASECMP] ? "strncasecmp (str + 1, s + 1, len - 1)" : "strncmp (str + 1, s + 1, len - 1)")
+ : (option[STRCASECMP] ? "strcasecmp (str + 1, s + 1)" : "strcmp (str + 1, s + 1)"),
+ option[TYPE] && option[POINTER] ? "&wordlist[key]" : "s");
+ }
+ printf (";\n }\n %s\n}\n", option[OPTIMIZE] ? "" : "}\n return 0;");
+ }
+}
+
+/* Output the table and the functions that map upper case into lower case! */
+
+void
+Key_List::output_strcasecmp (void)
+{
+ printf ("%s",
+ "/* This array is designed for mapping upper and lower case letter\n"
+ " * together for a case independent comparison. The mappings are\n"
+ " * based upon ascii character sequences.\n */"
+ "static char charmap[] = {\n"
+ " '\\000', '\\001', '\\002', '\\003', '\\004', '\\005', '\\006', '\\007',\n"
+ " '\\010', '\\011', '\\012', '\\013', '\\014', '\\015', '\\016', '\\017',\n"
+ " '\\020', '\\021', '\\022', '\\023', '\\024', '\\025', '\\026', '\\027',\n"
+ " '\\030', '\\031', '\\032', '\\033', '\\034', '\\035', '\\036', '\\037',\n"
+ " '\\040', '\\041', '\\042', '\\043', '\\044', '\\045', '\\046', '\\047',\n"
+ " '\\050', '\\051', '\\052', '\\053', '\\054', '\\055', '\\056', '\\057',\n"
+ " '\\060', '\\061', '\\062', '\\063', '\\064', '\\065', '\\066', '\\067',\n"
+ " '\\070', '\\071', '\\072', '\\073', '\\074', '\\075', '\\076', '\\077',\n"
+ " '\\100', '\\141', '\\142', '\\143', '\\144', '\\145', '\\146', '\\147',\n"
+ " '\\150', '\\151', '\\152', '\\153', '\\154', '\\155', '\\156', '\\157',\n"
+ " '\\160', '\\161', '\\162', '\\163', '\\164', '\\165', '\\166', '\\167',\n"
+ " '\\170', '\\171', '\\172', '\\133', '\\134', '\\135', '\\136', '\\137',\n"
+ " '\\140', '\\141', '\\142', '\\143', '\\144', '\\145', '\\146', '\\147',\n"
+ " '\\150', '\\151', '\\152', '\\153', '\\154', '\\155', '\\156', '\\157',\n"
+ " '\\160', '\\161', '\\162', '\\163', '\\164', '\\165', '\\166', '\\167',\n"
+ " '\\170', '\\171', '\\172', '\\173', '\\174', '\\175', '\\176', '\\177',\n"
+ " '\\200', '\\201', '\\202', '\\203', '\\204', '\\205', '\\206', '\\207',\n"
+ " '\\210', '\\211', '\\212', '\\213', '\\214', '\\215', '\\216', '\\217',\n"
+ " '\\220', '\\221', '\\222', '\\223', '\\224', '\\225', '\\226', '\\227',\n"
+ " '\\230', '\\231', '\\232', '\\233', '\\234', '\\235', '\\236', '\\237',\n"
+ " '\\240', '\\241', '\\242', '\\243', '\\244', '\\245', '\\246', '\\247',\n"
+ " '\\250', '\\251', '\\252', '\\253', '\\254', '\\255', '\\256', '\\257',\n"
+ " '\\260', '\\261', '\\262', '\\263', '\\264', '\\265', '\\266', '\\267',\n"
+ " '\\270', '\\271', '\\272', '\\273', '\\274', '\\275', '\\276', '\\277',\n"
+ " '\\300', '\\341', '\\342', '\\343', '\\344', '\\345', '\\346', '\\347',\n"
+ " '\\350', '\\351', '\\352', '\\353', '\\354', '\\355', '\\356', '\\357',\n"
+ " '\\360', '\\361', '\\362', '\\363', '\\364', '\\365', '\\366', '\\367',\n"
+ " '\\370', '\\371', '\\372', '\\333', '\\334', '\\335', '\\336', '\\337',\n"
+ " '\\340', '\\341', '\\342', '\\343', '\\344', '\\345', '\\346', '\\347',\n"
+ " '\\350', '\\351', '\\352', '\\353', '\\354', '\\355', '\\356', '\\357',\n"
+ " '\\360', '\\361', '\\362', '\\363', '\\364', '\\365', '\\366', '\\367',\n"
+ " '\\370', '\\371', '\\372', '\\373', '\\374', '\\375', '\\376', '\\377',\n};\n\nstatic int\n");
+ if (option[COMP])
+ {
+ printf ("%s", option[ANSI]
+ ? "strncasecmp (register char *s1, register char *s2, register int n)"
+ : "strncasecmp (s1, s2, n)\n register char *s1, *s2;\n register int n;");
+ printf ("\n{\n register char *cm = charmap;\n\n while (--n >= 0 && cm[*s1] == cm[*s2++])\n"
+ " if (*s1++ == '\\0')\n return 0;\n"
+ "\n return n < 0 ? 0 : cm[*s1] - cm[*--s2];\n}\n\n");
+ }
+ else
+ {
+ printf ("%s", option[ANSI]
+ ? "strcasecmp (register char *s1, register char *s2)"
+ : "strcasecmp (s1, s2)\n register char *s1, *s2;");
+ printf ("\n{\n register char *cm = charmap;\n\n while (cm[*s1] == cm[*s2++])\n"
+ " if (*s1++ == '\\0')\n return 0;\n"
+ "\n return cm[*s1] - cm[*--s2];\n}\n\n");
+ }
+}
+
+/* Generates the hash function and the key word recognizer function
+ based upon the user's Options. */
+
+void
+Key_List::output (void)
+{
+ printf ("%s\n", include_src);
+
+ if (option[TYPE] && !option[NOTYPE]) /* Output type declaration now, reference it later on.... */
+ printf ("%s;\n", array_type);
+
+ output_min_max ();
+
+ if (option[STRCASECMP])
+ output_strcasecmp ();
+ if (option[CPLUSPLUS])
+ printf ("class %s\n{\nprivate:\n"
+ " static unsigned int hash (const char *str, int len);\npublic:\n"
+ " static %s%s%s (const char *str, int len);\n};\n\n",
+ option.get_class_name (), option[CONST] ? "const " : "",
+ return_type, option.get_function_name ());
+
+ output_hash_function ();
+
+ if (option[GLOBAL])
+ if (option[SWITCH])
+ {
+ if (option[LENTABLE] && option[DUP])
+ output_keylength_table ();
+ if (option[POINTER] && option[TYPE])
+ output_keyword_table ();
+ }
+ else
+ {
+ if (option[LENTABLE])
+ output_keylength_table ();
+ output_keyword_table ();
+ output_lookup_array ();
+ }
+
+ if (option[GNU]) /* Use the inline keyword to remove function overhead. */
+ printf ("#ifdef __GNUC__\ninline\n#endif\n");
+
+ printf ("%s%s\n", option[CONST] ? "const " : "", return_type);
+ if (option[CPLUSPLUS])
+ printf ("%s::", option.get_class_name ());
+
+ printf (option[ANSI]
+ ? "%s (register const char *str, register int len)\n{\n"
+ : "%s (str, len)\n register char *str;\n register unsigned int len;\n{\n",
+ option.get_function_name ());
+
+ if (option[ENUM] && !option[GLOBAL])
+ printf (" enum\n {\n"
+ " TOTAL_KEYWORDS = %d,\n"
+ " MIN_WORD_LENGTH = %d,\n"
+ " MAX_WORD_LENGTH = %d,\n"
+ " MIN_HASH_VALUE = %d,\n"
+ " MAX_HASH_VALUE = %d,\n"
+ " HASH_VALUE_RANGE = %d,\n"
+ " DUPLICATES = %d\n };\n\n",
+ total_keys, min_key_len, max_key_len, min_hash_value,
+ max_hash_value, max_hash_value - min_hash_value + 1,
+ total_duplicates ? total_duplicates + 1 : 0);
+ /* Use the switch in place of lookup table. */
+ if (option[SWITCH])
+ {
+ if (!option[GLOBAL])
+ {
+ if (option[LENTABLE] && option[DUP])
+ output_keylength_table ();
+ if (option[POINTER] && option[TYPE])
+ output_keyword_table ();
+ }
+ output_switch ();
+ }
+ /* Use the lookup table, in place of switch. */
+ else
+ {
+ if (!option[GLOBAL])
+ {
+ if (option[LENTABLE])
+ output_keylength_table ();
+ output_keyword_table ();
+ }
+ if (!option[GLOBAL])
+ output_lookup_array ();
+ output_lookup_function ();
+ }
+
+ if (additional_code)
+ {
+ for (;;)
+ {
+ int c = getchar ();
+
+ if (c == EOF)
+ break;
+ else
+ putchar (c);
+ }
+ }
+
+ fflush (stdout);
+}
+
+/* Sorts the keys by hash value. */
+
+void
+Key_List::sort (void)
+{
+ hash_sort = 1;
+ occurrence_sort = 0;
+
+ head = merge_sort (head);
+}
+
+/* Dumps the key list to stderr stream. */
+
+void
+Key_List::dump ()
+{
+ int field_width = option.get_max_keysig_size ();
+
+ fprintf (stderr, "\nList contents are:\n(hash value, key length, index, %*s, keyword):\n",
+ field_width, "char_set");
+
+ for (List_Node *ptr = head; ptr; ptr = ptr->next)
+ fprintf (stderr, "%11d,%11d,%6d, %*s, %s\n",
+ ptr->hash_value, ptr->length, ptr->index,
+ field_width, ptr->char_set, ptr->key);
+}
+
+/* Simple-minded constructor action here... */
+
+Key_List::Key_List (void)
+{
+ total_keys = 1;
+ max_key_len = INT_MIN;
+ min_key_len = INT_MAX;
+ return_type = default_return_type;
+ array_type = struct_tag = default_array_type;
+ head = 0;
+ total_duplicates = 0;
+ additional_code = 0;
+}
+
+/* Returns the length of entire key list. */
+
+int
+Key_List::keyword_list_length (void)
+{
+ return list_len;
+}
+
+/* Returns length of longest key read. */
+
+int
+Key_List::max_key_length (void)
+{
+ return max_key_len;
+}
+
diff --git a/apps/gperf/src/Key_List.h b/apps/gperf/src/Key_List.h
new file mode 100644
index 00000000000..14276eb975d
--- /dev/null
+++ b/apps/gperf/src/Key_List.h
@@ -0,0 +1,116 @@
+/* -*- C++ -*- */
+// @(#)Key_List.h 1.1 10/18/96
+
+/* This may look like C code, but it is really -*- C++ -*- */
+
+/* Data and function member declarations for the keyword list class.
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+// The key word list is a useful abstraction that keeps track of
+// various pieces of information that enable that fast generation of
+// the Gen_Perf.hash function. A Key_List is a singly-linked list of
+// List_Nodes.
+
+#ifndef key_list_h
+#define key_list_h 1
+
+#include "Options.h"
+#include "List_Node.h"
+
+class Key_List
+{
+public:
+ Key_List (void);
+ ~Key_List (void);
+ int keyword_list_length (void);
+ int max_key_length (void);
+ void reorder (void);
+ void sort (void);
+ void read_keys (void);
+ void output (void);
+
+ List_Node *head;
+ // Points to the head of the linked list.
+
+ int total_duplicates;
+ // Total number of duplicate hash values.
+
+private:
+ static int get_occurrence (List_Node *ptr);
+ static int strcspn (const char *s, const char *reject);
+ static int already_determined (List_Node *ptr);
+ static void set_determined (List_Node *ptr);
+ void output_min_max (void);
+ void output_switch (void);
+ void output_keyword_table (void);
+ void output_keylength_table (void);
+ void output_hash_function (void);
+ void output_lookup_function (void);
+ void output_lookup_array (void);
+ void output_strcasecmp (void);
+ void set_output_types (void);
+ void dump (void);
+ char *get_array_type (void);
+ char *save_include_src (void);
+ char *get_special_input (char delimiter);
+ List_Node *merge (List_Node *list1, List_Node *list2);
+ List_Node *merge_sort (List_Node *head);
+
+ char *array_type;
+ // Pointer to the type for word list.
+
+ char *return_type;
+ // Pointer to return type for lookup function.
+
+ char *struct_tag;
+ // Shorthand for user-defined struct tag type.
+
+ char *include_src;
+ // C source code to be included verbatim.
+
+ int max_key_len;
+ // Maximum length of the longest keyword.
+
+ int min_key_len;
+ // Minimum length of the shortest keyword.
+
+ int min_hash_value;
+ // Minimum hash value for all keywords.
+
+ int max_hash_value;
+ // Maximum hash value for all keywords.
+
+ int occurrence_sort;
+ // True if sorting by occurrence.
+
+ int hash_sort;
+ // True if sorting by hash value.
+
+ int additional_code;
+ // True if any additional C code is included.
+
+ int list_len;
+ // Length of head's Key_List, not counting duplicates.
+
+ int total_keys;
+ // Total number of keys, counting duplicates.
+};
+#endif
diff --git a/apps/gperf/src/List_Node.cpp b/apps/gperf/src/List_Node.cpp
new file mode 100644
index 00000000000..d72cc699c13
--- /dev/null
+++ b/apps/gperf/src/List_Node.cpp
@@ -0,0 +1,110 @@
+/* Creates and initializes a new list node.
+// @(#)List_Node.cpp 1.1 10/18/96
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "Vectors.h"
+#include "List_Node.h"
+
+/* Defined as a macro in string.h on some systems, which causes
+ conflicts. */
+#undef index
+
+/* Sorts the key set alphabetically to speed up subsequent operations.
+ Uses insertion sort since the set is probably quite small. */
+
+inline void
+List_Node::set_sort (char *base, int len)
+{
+ int i, j;
+
+ for (i = 0, j = len - 1; i < j; i++)
+ {
+ char curr, tmp;
+
+ for (curr = i + 1, tmp = base[curr]; curr > 0 && tmp < base[curr-1]; curr--)
+ base[curr] = base[curr - 1];
+
+ base[curr] = tmp;
+
+ }
+}
+
+/* Initializes a List_Node. This requires obtaining memory for the
+ CHAR_SET initializing them using the information stored in the
+ KEY_POSITIONS array in Options, and checking for simple errors.
+ It's important to note that KEY and REST are both pointers to the
+ different offsets into the same block of dynamic memory pointed to
+ by parameter K. The data member REST is used to store any
+ additional fields of the input file (it is set to the "" string if
+ Option[TYPE] is not enabled). This is useful if the user wishes to
+ incorporate a lookup structure, rather than just an array of keys.
+ Finally, KEY_NUMBER contains a count of the total number of keys
+ seen so far. This is used to initialize the INDEX field to some
+ useful value. */
+
+List_Node::List_Node (char *k, int len)
+ : key (k),
+ next (0),
+ index (0),
+ length (len),
+ link (0),
+ rest (option[TYPE] ? k + len + 1 : "")
+{
+ char *ptr = new char[(option[ALLCHARS] ? len : option.get_max_keysig_size ()) + 1];
+ char_set = ptr;
+ k[len] = '\0'; /* Null terminate KEY to separate it from REST. */
+
+ /* Lower case if STRCASECMP option is enabled. */
+ if (option[STRCASECMP])
+ for (char *p = k; *p; p++)
+ if (isupper (*p))
+ *p = tolower (*p);
+
+ if (option[ALLCHARS]) /* Use all the character position in the KEY. */
+ for (; *k; k++, ptr++)
+ ++Vectors::occurrences[*ptr = *k];
+ else /* Only use those character positions specified by the user. */
+ {
+ int i;
+
+ /* Iterate thru the list of key_positions, initializing occurrences table
+ and char_set (via char * pointer ptr). */
+
+ for (option.reset (); (i = option.get ()) != EOS; )
+ {
+ if (i == WORD_END) /* Special notation for last KEY position, i.e. '$'. */
+ *ptr = key[len - 1];
+ else if (i <= len) /* Within range of KEY length, so we'll keep it. */
+ *ptr = key[i - 1];
+ else /* Out of range of KEY length, so we'll just skip it. */
+ continue;
+ ++Vectors::occurrences[*ptr++];
+ }
+
+ /* Didn't get any hits and user doesn't want to consider the
+ keylength, so there are essentially no usable hash positions! */
+ if (ptr == char_set && option[NOLENGTH])
+ ACE_ERROR ((LM_ERROR, "Can't hash keyword %s with chosen key positions.\n%a", key, 1));
+ }
+ *ptr = '\0'; /* Terminate this bastard.... */
+ /* Sort the KEY_SET items alphabetically. */
+ set_sort (char_set, ptr - char_set);
+}
diff --git a/apps/gperf/src/List_Node.h b/apps/gperf/src/List_Node.h
new file mode 100644
index 00000000000..0cb512f0894
--- /dev/null
+++ b/apps/gperf/src/List_Node.h
@@ -0,0 +1,65 @@
+/* -*- C++ -*- */
+// @(#)List_Node.h 1.1 10/18/96
+
+/* This may look like C code, but it is really -*- C++ -*- */
+
+/* Data and function members for defining values and operations of a list node.
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef list_node_h
+#define list_node_h 1
+
+#include "Options.h"
+
+struct List_Node
+{
+ List_Node (char *key, int len);
+ static void set_sort (char *base, int len);
+
+ List_Node *link;
+ // TRUE if key has an identical KEY_SET as another key.
+
+ List_Node *next;
+ // Points to next element on the list.
+
+ char *key;
+ // Each keyword string stored here.
+
+ char *rest;
+ // Additional information for building hash function.
+
+ char *char_set;
+ // Set of characters to hash, specified by user.
+
+ int length;
+ // Length of the key.
+
+ int hash_value;
+ // Hash value for the key.
+
+ int occurrence;
+ // A metric for frequency of key set occurrences.
+
+ int index;
+ // Position of this node relative to other nodes.
+};
+
+#endif
diff --git a/apps/gperf/src/Makefile b/apps/gperf/src/Makefile
new file mode 100644
index 00000000000..ca6221f7156
--- /dev/null
+++ b/apps/gperf/src/Makefile
@@ -0,0 +1,155 @@
+#----------------------------------------------------------------------------
+# @(#)Makefile 1.1 10/18/96
+#
+# Makefile for GPERF release
+#----------------------------------------------------------------------------
+
+BIN = gperf
+LIB = libGperf.a
+
+FILES = new \
+ Options \
+ Iterator \
+ Gen_Perf \
+ Key_List \
+ List_Node \
+ Hash_Table \
+ Bool_Array \
+ Vectors \
+ Version
+
+LSRC = $(addsuffix .cpp,$(FILES))
+LOBJ = $(addsuffix .o,$(FILES))
+
+LDLIBS = -lGperf
+
+VLDLIBS = $(LDLIBS:%=%$(VAR))
+
+BUILD = $(VLIB) $(VBIN)
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.lib.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU
+
+# DO NOT DELETE THIS LINE -- g++dep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+.obj/new.o .shobj/new.so: new.cpp Options.h \
+ $(WRAPPER_ROOT)/ace/Log_Msg.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.h \
+ $(WRAPPER_ROOT)/ace/ACE.h \
+ $(WRAPPER_ROOT)/ace/OS.h \
+ $(WRAPPER_ROOT)/ace/Time_Value.h \
+ $(WRAPPER_ROOT)/ace/config.h \
+ $(WRAPPER_ROOT)/ace/Trace.h \
+ $(WRAPPER_ROOT)/ace/ACE.i \
+ $(WRAPPER_ROOT)/ace/Log_Priority.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.i
+.obj/Options.o .shobj/Options.so: Options.cpp \
+ $(WRAPPER_ROOT)/ace/Get_Opt.h \
+ $(WRAPPER_ROOT)/ace/ACE.h \
+ $(WRAPPER_ROOT)/ace/OS.h \
+ $(WRAPPER_ROOT)/ace/Time_Value.h \
+ $(WRAPPER_ROOT)/ace/config.h \
+ $(WRAPPER_ROOT)/ace/Trace.h \
+ $(WRAPPER_ROOT)/ace/ACE.i \
+ $(WRAPPER_ROOT)/ace/Log_Msg.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.h \
+ $(WRAPPER_ROOT)/ace/Log_Priority.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.i \
+ Options.h Iterator.h
+.obj/Iterator.o .shobj/Iterator.so: Iterator.cpp Iterator.h Options.h \
+ $(WRAPPER_ROOT)/ace/Log_Msg.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.h \
+ $(WRAPPER_ROOT)/ace/ACE.h \
+ $(WRAPPER_ROOT)/ace/OS.h \
+ $(WRAPPER_ROOT)/ace/Time_Value.h \
+ $(WRAPPER_ROOT)/ace/config.h \
+ $(WRAPPER_ROOT)/ace/Trace.h \
+ $(WRAPPER_ROOT)/ace/ACE.i \
+ $(WRAPPER_ROOT)/ace/Log_Priority.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.i
+.obj/Gen_Perf.o .shobj/Gen_Perf.so: Gen_Perf.cpp Gen_Perf.h Options.h \
+ $(WRAPPER_ROOT)/ace/Log_Msg.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.h \
+ $(WRAPPER_ROOT)/ace/ACE.h \
+ $(WRAPPER_ROOT)/ace/OS.h \
+ $(WRAPPER_ROOT)/ace/Time_Value.h \
+ $(WRAPPER_ROOT)/ace/config.h \
+ $(WRAPPER_ROOT)/ace/Trace.h \
+ $(WRAPPER_ROOT)/ace/ACE.i \
+ $(WRAPPER_ROOT)/ace/Log_Priority.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.i \
+ Key_List.h List_Node.h Bool_Array.h
+.obj/Key_List.o .shobj/Key_List.so: Key_List.cpp \
+ $(WRAPPER_ROOT)/ace/Read_Buffer.h \
+ $(WRAPPER_ROOT)/ace/ACE.h \
+ $(WRAPPER_ROOT)/ace/OS.h \
+ $(WRAPPER_ROOT)/ace/Time_Value.h \
+ $(WRAPPER_ROOT)/ace/config.h \
+ $(WRAPPER_ROOT)/ace/Trace.h \
+ $(WRAPPER_ROOT)/ace/ACE.i \
+ $(WRAPPER_ROOT)/ace/Log_Msg.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.h \
+ $(WRAPPER_ROOT)/ace/Log_Priority.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.i \
+ $(WRAPPER_ROOT)/ace/Malloc.h \
+ $(WRAPPER_ROOT)/ace/Malloc_T.h \
+ $(WRAPPER_ROOT)/ace/Synch.h \
+ $(WRAPPER_ROOT)/ace/Synch_T.h \
+ $(WRAPPER_ROOT)/ace/Memory_Pool.h \
+ $(WRAPPER_ROOT)/ace/Event_Handler.h \
+ $(WRAPPER_ROOT)/ace/Signal.h \
+ $(WRAPPER_ROOT)/ace/Set.h \
+ $(WRAPPER_ROOT)/ace/Mem_Map.h \
+ $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.h \
+ $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.h \
+ $(WRAPPER_ROOT)/ace/SV_Semaphore_Simple.i \
+ $(WRAPPER_ROOT)/ace/SV_Semaphore_Complex.i \
+ $(WRAPPER_ROOT)/ace/Read_Buffer.i \
+ Hash_Table.h Options.h List_Node.h Vectors.h Key_List.h
+.obj/List_Node.o .shobj/List_Node.so: List_Node.cpp Vectors.h List_Node.h Options.h \
+ $(WRAPPER_ROOT)/ace/Log_Msg.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.h \
+ $(WRAPPER_ROOT)/ace/ACE.h \
+ $(WRAPPER_ROOT)/ace/OS.h \
+ $(WRAPPER_ROOT)/ace/Time_Value.h \
+ $(WRAPPER_ROOT)/ace/config.h \
+ $(WRAPPER_ROOT)/ace/Trace.h \
+ $(WRAPPER_ROOT)/ace/ACE.i \
+ $(WRAPPER_ROOT)/ace/Log_Priority.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.i
+.obj/Hash_Table.o .shobj/Hash_Table.so: Hash_Table.cpp \
+ $(WRAPPER_ROOT)/ace/ACE.h \
+ $(WRAPPER_ROOT)/ace/OS.h \
+ $(WRAPPER_ROOT)/ace/Time_Value.h \
+ $(WRAPPER_ROOT)/ace/config.h \
+ $(WRAPPER_ROOT)/ace/Trace.h \
+ $(WRAPPER_ROOT)/ace/ACE.i \
+ $(WRAPPER_ROOT)/ace/Log_Msg.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.h \
+ $(WRAPPER_ROOT)/ace/Log_Priority.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.i \
+ Hash_Table.h Options.h List_Node.h
+.obj/Bool_Array.o .shobj/Bool_Array.so: Bool_Array.cpp Bool_Array.h Options.h \
+ $(WRAPPER_ROOT)/ace/Log_Msg.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.h \
+ $(WRAPPER_ROOT)/ace/ACE.h \
+ $(WRAPPER_ROOT)/ace/OS.h \
+ $(WRAPPER_ROOT)/ace/Time_Value.h \
+ $(WRAPPER_ROOT)/ace/config.h \
+ $(WRAPPER_ROOT)/ace/Trace.h \
+ $(WRAPPER_ROOT)/ace/ACE.i \
+ $(WRAPPER_ROOT)/ace/Log_Priority.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.i
+.obj/Version.o .shobj/Version.so: Version.cpp
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/apps/gperf/src/Options.cpp b/apps/gperf/src/Options.cpp
new file mode 100644
index 00000000000..184187b5a4a
--- /dev/null
+++ b/apps/gperf/src/Options.cpp
@@ -0,0 +1,616 @@
+/* Handles parsing the Options provided to the user.
+// @(#)Options.cpp 1.1 10/18/96
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "ace/Get_Opt.h"
+#include "Options.h"
+#include "Iterator.h"
+
+/* Global option coordinator for the entire program. */
+Options option;
+
+/* Current program version. */
+extern char *version_string;
+
+/* Size to jump on a collision. */
+static const int DEFAULT_JUMP_VALUE = 5;
+
+/* Default name for generated lookup function. */
+static const char *const DEFAULT_NAME = "in_word_set";
+
+/* Default name for the key component. */
+static const char *const DEFAULT_KEY = "name";
+
+/* Default name for the generated class. */
+static const char *const DEFAULT_CLASS_NAME = "Perfect_Hash";
+
+/* Default name for generated hash function. */
+static const char *const DEFAULT_HASH_NAME = "hash";
+
+/* Default delimiters that separate keywords from their attributes. */
+static const char *const DEFAULT_DELIMITERS = ",\n";
+
+int Options::option_word;
+int Options::total_switches;
+int Options::total_keysig_size;
+int Options::size;
+int Options::key_pos;
+int Options::jump;
+int Options::initial_asso_value;
+int Options::argument_count;
+int Options::iterations;
+char **Options::argument_vector;
+const char *Options::function_name;
+const char *Options::key_name;
+const char *Options::class_name;
+const char *Options::hash_name;
+const char *Options::delimiters;
+char Options::key_positions[MAX_KEY_POS];
+
+/* Prints program usage to standard error stream. */
+
+inline void
+Options::usage (void)
+{
+ ACE_ERROR ((LM_ERROR, "Usage: %n [-acCdDef[num]gGhH<hashname>i<init>Ijk<keys>K<keyname>lL<language>nN<function name>oOprs<size>S<switches>tTvZ<class name>].\n"
+ "(type %n -h for help)\n"));
+}
+
+/* Output command-line Options. */
+
+void
+Options::print_options (void)
+{
+ int i;
+
+ printf ("/* Command-line: ");
+
+ for (i = 0; i < argument_count; i++)
+ printf ("%s ", argument_vector[i]);
+
+ printf (" */");
+}
+
+/* Sorts the key positions *IN REVERSE ORDER!!*
+ This makes further routines more efficient. Especially when generating code.
+ Uses a simple Insertion Sort since the set is probably ordered.
+ Returns 1 if there are no duplicates, 0 otherwise. */
+
+inline int
+Options::key_sort (char *base, int len)
+{
+ int i, j;
+
+ for (i = 0, j = len - 1; i < j; i++)
+ {
+ int curr, tmp;
+
+ for (curr = i + 1,tmp = base[curr]; curr > 0 && tmp >= base[curr - 1]; curr--)
+ if ((base[curr] = base[curr - 1]) == tmp) /* oh no, a duplicate!!! */
+ return 0;
+
+ base[curr] = tmp;
+ }
+
+ return 1;
+}
+
+/* Sets the default Options. */
+
+Options::Options (void)
+{
+ key_positions[0] = WORD_START;
+ key_positions[1] = WORD_END;
+ key_positions[2] = EOS;
+ total_keysig_size = 2;
+ delimiters = DEFAULT_DELIMITERS;
+ jump = DEFAULT_JUMP_VALUE;
+ option_word = DEFAULTCHARS | C;
+ function_name = DEFAULT_NAME;
+ key_name = DEFAULT_KEY;
+ hash_name = DEFAULT_HASH_NAME;
+ class_name = DEFAULT_CLASS_NAME;
+ total_switches = size = 1;
+ initial_asso_value = iterations = 0;
+}
+
+/* Dumps option status when debug is set. */
+
+Options::~Options (void)
+{
+ if (option_word & DEBUG)
+ {
+ char *ptr;
+
+ fprintf (stderr, "\ndumping Options:\nDEBUG is.......: %s\nORDER is.......: %s"
+ "\nANSI is........: %s\nTYPE is........: %s\nGNU is.........: %s"
+ "\nRANDOM is......: %s\nDEFAULTCHARS is: %s\nSWITCH is......: %s"
+ "\nPOINTER is.....: %s\nNOLENGTH is....: %s\nLENTABLE is....: %s"
+ "\nDUP is.........: %s\nFAST is........: %s\nCOMP is.....: %s"
+ "\nNOTYPE is......: %s\nGLOBAL is......: %s\nCONST is....: %s"
+ "\nCPLUSPLUS is...: %s\nC is...........: %s\nENUM is.....: %s"
+ "\nSTRCASECMP is...: %s\nOPTIMIZE is...........: %s"
+ "\niterations = %d\nlookup function name = %s\nhash function name = %s"
+ "\nkey name = %s\njump value = %d\nmax associcated value = %d"
+ "\ninitial associated value = %d\ndelimiters = %s\nnumber of switch statements = %d\n",
+ option_word & DEBUG ? "enabled" : "disabled",
+ option_word & ORDER ? "enabled" : "disabled",
+ option_word & ANSI ? "enabled" : "disabled",
+ option_word & TYPE ? "enabled" : "disabled",
+ option_word & GNU ? "enabled" : "disabled",
+ option_word & RANDOM ? "enabled" : "disabled",
+ option_word & DEFAULTCHARS ? "enabled" : "disabled",
+ option_word & SWITCH ? "enabled" : "disabled",
+ option_word & POINTER ? "enabled" : "disabled",
+ option_word & NOLENGTH ? "enabled" : "disabled",
+ option_word & LENTABLE ? "enabled" : "disabled",
+ option_word & DUP ? "enabled" : "disabled",
+ option_word & FAST ? "enabled" : "disabled",
+ option_word & COMP ? "enabled" : "disabled",
+ option_word & NOTYPE ? "enabled" : "disabled",
+ option_word & GLOBAL ? "enabled" : "disabled",
+ option_word & CONST ? "enabled" : "disabled",
+ option_word & CPLUSPLUS ? "enabled" : "disabled",
+ option_word & C ? "enabled" : "disabled",
+ option_word & ENUM ? "enabled" : "disabled",
+ option_word & STRCASECMP ? "enabled" : "disabled",
+ option_word & OPTIMIZE ? "enabled" : "disabled",
+ iterations, function_name, hash_name, key_name, jump, size - 1,
+ initial_asso_value, delimiters, total_switches);
+ if (option_word & ALLCHARS)
+ fprintf (stderr, "all characters are used in the hash function\n");
+
+ fprintf (stderr, "maximum keysig size = %d\nkey positions are: \n",
+ total_keysig_size);
+
+ for (ptr = key_positions; *ptr != EOS; ptr++)
+ if (*ptr == WORD_END)
+ fprintf (stderr, "$\n");
+ else
+ fprintf (stderr, "%d\n", *ptr);
+
+ fprintf (stderr, "finished dumping Options\n");
+ }
+}
+
+
+/* Parses the command line Options and sets appropriate flags in option_word. */
+
+void
+Options::operator() (int argc, char *argv[])
+{
+ ACE_LOG_MSG->open (argv[0]);
+
+ ACE_Get_Opt getopt (argc, argv, "adcCDe:Ef:gGhH:i:Ij:k:K:lL:nN:oOprs:S:tTvZ:");
+ int option_char;
+
+ argument_count = argc;
+ argument_vector = argv;
+
+ while ((option_char = getopt ()) != -1)
+ {
+ switch (option_char)
+ {
+ case 'a': /* Generated coded uses the ANSI prototype format. */
+ {
+ option_word |= ANSI;
+ break;
+ }
+ case 'c': /* Generate strncmp rather than strcmp. */
+ {
+ option_word |= COMP;
+ break;
+ }
+ case 'C': /* Make the generated tables readonly (const). */
+ {
+ option_word |= CONST;
+ break;
+ }
+ case 'd': /* Enable debugging option. */
+ {
+ option_word |= DEBUG;
+ ACE_ERROR ((LM_ERROR, "Starting program %n, version %s, with debuggin on.\n",
+ version_string));
+ break;
+ }
+ case 'D': /* Enable duplicate option. */
+ {
+ option_word |= DUP;
+ break;
+ }
+ case 'e': /* Allows user to provide keyword/attribute separator */
+ {
+ option.delimiters = getopt.optarg;
+ break;
+ }
+ case 'E':
+ {
+ option_word |= ENUM;
+ break;
+ }
+ case 'f': /* Generate the hash table ``fast.'' */
+ {
+ option_word |= FAST;
+ if ((iterations = atoi (getopt.optarg)) < 0)
+ {
+ ACE_ERROR ((LM_ERROR, "iterations value must not be negative, assuming 0\n"));
+ iterations = 0;
+ }
+ break;
+ }
+ case 'g': /* Use the ``inline'' keyword for generated sub-routines. */
+ {
+ option_word |= GNU;
+ break;
+ }
+ case 'G': /* Make the keyword table a global variable. */
+ {
+ option_word |= GLOBAL;
+ break;
+ }
+ case 'h': /* Displays a list of helpful Options to the user. */
+ {
+ ACE_ERROR ((LM_ERROR,
+ "-a\tGenerate ANSI standard C output code, i.e., function prototypes.\n"
+ "-c\tGenerate comparison code using strncmp rather than strcmp.\n"
+ "-C\tMake the contents of generated lookup tables constant, i.e., readonly.\n"
+ "-d\tEnables the debugging option (produces verbose output to the standard error).\n"
+ "-D\tHandle keywords that hash to duplicate values. This is useful\n"
+ "\tfor certain highly redundant keyword sets. It enables the -S option.\n"
+ "-e\tAllow user to provide a string containing delimiters used to separate\n"
+ "\tkeywords from their attributes. Default is \",\\n\"\n"
+ "-E\tDefine constant values using an enum local to the lookup function\n"
+ "\trather than with defines\n"
+ "-f\tGenerate the gen-perf.hash function ``fast.'' This decreases GPERF's\n"
+ "\trunning time at the cost of minimizing generated table-size.\n"
+ "\tThe numeric argument represents the number of times to iterate when\n"
+ "\tresolving a collision. `0' means ``iterate by the number of keywords.''\n"
+ "-g\tAssume a GNU compiler, e.g., g++ or gcc. This makes all generated\n"
+ "\troutines use the ``inline'' keyword to remove cost of function calls.\n"
+ "-G\tGenerate the static table of keywords as a static global variable,\n"
+ "\trather than hiding it inside of the lookup function (which is the\n"
+ "\tdefault behavior).\n"
+ "-h\tPrints this mesage.\n"
+ "-H\tAllow user to specify name of generated hash function. Default\n"
+ "\tis `hash'.\n"
+ "-i\tProvide an initial value for the associate values array. Default is 0.\n"
+ "-I\tGenerate comparison code using case insensitive string comparison, e.g.,\n"
+ "\tstrncasecmp or strcasecmp.\n"
+ "\tSetting this value larger helps inflate the size of the final table.\n"
+ "-j\tAffects the ``jump value,'' i.e., how far to advance the associated\n"
+ "\tcharacter value upon collisions. Must be an odd number, default is %d.\n"
+ "-k\tAllows selection of the key positions used in the hash function.\n"
+ "\tThe allowable choices range between 1-%d, inclusive. The positions\n"
+ "\tare separated by commas, ranges may be used, and key positions may\n"
+ "\toccur in any order. Also, the meta-character '*' causes the generated\n"
+ "\thash function to consider ALL key positions, and $ indicates the\n"
+ "\t``final character'' of a key, e.g., $,1,2,4,6-10.\n"
+ "-K\tAllow use to select name of the keyword component in the keyword structure.\n"
+ "-l\tCompare key lengths before trying a string comparison. This helps\n"
+ "\tcut down on the number of string comparisons made during the lookup.\n"
+ "-L\tGenerates code in the language specified by the option's argument. Languages\n"
+ "\thandled are currently C++ and C. The default is C.\n"
+ "-n\tDo not include the length of the keyword when computing the hash function\n"
+ "-N\tAllow user to specify name of generated lookup function. Default\n"
+ "\tname is `in_word_set.'\n"
+ "-o\tReorders input keys by frequency of occurrence of the key sets.\n"
+ "\tThis should decrease the search time dramatically.\n"
+ "-O\tOptimize the generated lookup function by assuming that all input keywords \n"
+ "\tare members of the keyset from the keyfile.\n"
+ "-p\tChanges the return value of the generated function ``in_word_set''\n"
+ "\tfrom its default boolean value (i.e., 0 or 1), to type ``pointer\n"
+ "\tto wordlist array'' This is most useful when the -t option, allowing\n"
+ "\tuser-defined structs, is used.\n"
+ "-r\tUtilizes randomness to initialize the associated values table.\n"
+ "-s\tAffects the size of the generated hash table. The numeric argument\n"
+ "\tfor this option indicates ``how many times larger or smaller'' the associated\n"
+ "\tvalue range should be, in relationship to the number of keys, e.g. a value of 3\n"
+ "\tmeans ``allow the maximum associated value to be about 3 times larger than the\n"
+ "\tnumber of input keys.'' Conversely, a value of -3 means ``make the maximum\n"
+ "\tassociated value about 3 times smaller than the number of input keys.\n"
+ "\tA larger table should decrease the time required for an unsuccessful search,\n"
+ "\tat the expense of extra table space. Default value is 1.\n"
+ "-S\tCauses the generated C code to use a switch statement scheme, rather\n"
+ "\tthan an array lookup table. This can lead to a reduction in both\n"
+ "\ttime and space requirements for some keyfiles. The argument to\n"
+ "\tthis option determines how many switch statements are generated.\n"
+ "\tA value of 1 generates 1 switch containing all the elements, a value of 2\n"
+ "\tgenerates 2 tables with 1/2 the elements in each table, etc. This\n"
+ "\tis useful since many C compilers cannot correctly generate code for\n"
+ "\tlarge switch statements.\n"
+ "-t\tAllows the user to include a structured type declaration for \n"
+ "\tgenerated code. Any text before %%%% is consider part of the type\n"
+ "\tdeclaration. Key words and additional fields may follow this, one\n"
+ "\tgroup of fields per line.\n"
+ "-T\tPrevents the transfer of the type declaration to the output file.\n"
+ "\tUse this option if the type is already defined elsewhere.\n"
+ "-v\tPrints out the current version number\n"
+ "-Z\tAllow user to specify name of generated C++ class. Default\n"
+ "\tname is `Perfect_Hash.'\n%e%a", DEFAULT_JUMP_VALUE, (MAX_KEY_POS - 1), usage, 1));
+ }
+ case 'H': /* Sets the name for the hash function */
+ {
+ hash_name = getopt.optarg;
+ break;
+ }
+ case 'i': /* Sets the initial value for the associated values array. */
+ {
+ if ((initial_asso_value = atoi (getopt.optarg)) < 0)
+ ACE_ERROR ((LM_ERROR, "Initial value %d should be non-zero, ignoring and continuing.\n", initial_asso_value));
+ if (option[RANDOM])
+ ACE_ERROR ((LM_ERROR, "warning, -r option superceeds -i, ignoring -i option and continuing\n"));
+ break;
+ }
+ case 'I':
+ {
+ option_word |= STRCASECMP;
+ break;
+ }
+ case 'j': /* Sets the jump value, must be odd for later algorithms. */
+ {
+ if ((jump = atoi (getopt.optarg)) < 0)
+ ACE_ERROR ((LM_ERROR, "Jump value %d must be a positive number.\n%e%a", jump, usage, 1));
+ else if (jump && ACE_EVEN (jump))
+ ACE_ERROR ((LM_ERROR, "Jump value %d should be odd, adding 1 and continuing...\n", jump++));
+ break;
+ }
+ case 'k': /* Sets key positions used for hash function. */
+ {
+ const int BAD_VALUE = -1;
+ int value;
+ Iterator expand (getopt.optarg, 1, MAX_KEY_POS - 1, WORD_END, BAD_VALUE, EOS);
+
+ if (*getopt.optarg == '*') /* Use all the characters for hashing!!!! */
+ option_word = (option_word & ~DEFAULTCHARS) | ALLCHARS;
+ else
+ {
+ char *l_key_pos;
+
+ for (l_key_pos = key_positions; (value = expand ()) != EOS; l_key_pos++)
+ if (value == BAD_VALUE)
+ ACE_ERROR ((LM_ERROR, "Illegal key value or range, use 1,2,3-%d,'$' or '*'.\n%e%a",
+ MAX_KEY_POS - 1, usage, 1));
+ else
+ *l_key_pos = value;;
+
+ *l_key_pos = EOS;
+
+ if (! (total_keysig_size = (l_key_pos - key_positions)))
+ ACE_ERROR ((LM_ERROR, "No keys selected.\n%e%a", usage, 1));
+ else if (! key_sort (key_positions, total_keysig_size))
+ ACE_ERROR ((LM_ERROR, "Duplicate keys selected\n%e%a", usage, 1));
+
+ if (total_keysig_size != 2
+ || (key_positions[0] != 1 || key_positions[1] != WORD_END))
+ option_word &= ~DEFAULTCHARS;
+ }
+ break;
+ }
+ case 'K': /* Make this the keyname for the keyword component field. */
+ {
+ key_name = getopt.optarg;
+ break;
+ }
+ case 'l': /* Create length table to avoid extra string compares. */
+ {
+ option_word |= LENTABLE;
+ break;
+ }
+ case 'L': /* Deal with different generated languages. */
+ {
+ option_word &= ~C;
+ if (!strcmp (getopt.optarg, "C++"))
+ option_word |= (CPLUSPLUS | ANSI);
+ else if (!strcmp (getopt.optarg, "C"))
+ option_word |= C;
+ else
+ {
+ ACE_ERROR ((LM_ERROR, "unsupported language option %s, defaulting to C\n", getopt.optarg));
+ option_word |= C;
+ }
+ break;
+ }
+ case 'n': /* Don't include the length when computing hash function. */
+ {
+ option_word |= NOLENGTH;
+ break;
+ }
+ case 'N': /* Make generated lookup function name be optarg */
+ {
+ function_name = getopt.optarg;
+ break;
+ }
+ case 'o': /* Order input by frequency of key set occurrence. */
+ {
+ option_word |= ORDER;
+ break;
+ }
+ case 'O':
+ {
+ option_word |= OPTIMIZE;
+ break;
+ }
+ case 'p': /* Generated lookup function now a pointer instead of int. */
+ {
+ option_word |= POINTER;
+ break;
+ }
+ case 'r': /* Utilize randomness to initialize the associated values table. */
+ {
+ option_word |= RANDOM;
+ if (option.initial_asso_value != 0)
+ ACE_ERROR ((LM_ERROR, "warning, -r option superceeds -i, disabling -i option and continuing\n"));
+ break;
+ }
+ case 's': /* Range of associated values, determines size of final table. */
+ {
+ if (abs (size = atoi (getopt.optarg)) > 50)
+ ACE_ERROR ((LM_ERROR, "%d is excessive, did you really mean this?! (type %n -h for help)\n", size));
+ break;
+ }
+ case 'S': /* Generate switch statement output, rather than lookup table. */
+ {
+ option_word |= SWITCH;
+ if ((option.total_switches = atoi (getopt.optarg)) <= 0)
+ ACE_ERROR ((LM_ERROR, "number of switches %s must be a positive number\n%e%a", getopt.optarg, usage, 1));
+ break;
+ }
+ case 't': /* Enable the TYPE mode, allowing arbitrary user structures. */
+ {
+ option_word |= TYPE;
+ break;
+ }
+ case 'T': /* Don't print structure definition. */
+ {
+ option_word |= NOTYPE;
+ break;
+ }
+ case 'v': /* Print out the version and quit. */
+ ACE_ERROR ((LM_ERROR, "%n: version %s\n%e\n%a", version_string, usage, 1));
+ case 'Z': /* Set the class name. */
+ {
+ class_name = getopt.optarg;
+ break;
+ }
+ default:
+ ACE_ERROR ((LM_ERROR, "%e%a", usage, 1));
+ }
+
+ }
+
+ if (argv[getopt.optind] && ! freopen (argv[getopt.optind], "r", stdin))
+ ACE_ERROR ((LM_ERROR, "Cannot open keyword file %p\n%e%a", argv[getopt.optind], usage, 1));
+
+ if (++getopt.optind < argc)
+ ACE_ERROR ((LM_ERROR, "Extra trailing arguments to %n.\n%e%a", usage, 1));
+}
+
+int
+Options::operator[] (Option_Type option) /* True if option enable, else false. */
+{
+ return option_word & option;
+}
+
+void
+Options::operator = (enum Option_Type opt) /* Enables option OPT. */
+{
+ option_word |= opt;
+}
+
+void
+Options::operator != (enum Option_Type opt) /* Disables option OPT. */
+{
+ option_word &= ~opt;
+}
+
+void
+Options::reset (void) /* Initializes the key Iterator. */
+{
+ key_pos = 0;
+}
+
+int
+Options::get (void) /* Returns current key_position and advanced index. */
+{
+ return key_positions[key_pos++];
+}
+
+void
+Options::set_asso_max (int r) /* Sets the size of the table size. */
+{
+ size = r;
+}
+
+int
+Options::get_asso_max (void) /* Returns the size of the table size. */
+{
+ return size;
+}
+
+int
+Options::get_max_keysig_size (void) /* Returns total distinct key positions. */
+{
+ return total_keysig_size;
+}
+
+void
+Options::set_keysig_size (int a_size) /* Sets total distinct key positions. */
+{
+ total_keysig_size = a_size;
+}
+
+int
+Options::get_jump (void) /* Returns the jump value. */
+{
+ return jump;
+}
+
+const char *
+Options::get_function_name (void) /* Returns the generated function name. */
+{
+ return function_name;
+}
+
+const char *
+Options::get_key_name (void) /* Returns the keyword key name. */
+{
+ return key_name;
+}
+
+const char *
+Options::get_hash_name (void) /* Returns the hash function name. */
+{
+ return hash_name;
+}
+
+const char *
+Options::get_class_name (void) /* Returns the generated class name. */
+{
+ return class_name;
+}
+
+int
+Options::initial_value (void) /* Returns the initial associated character value. */
+{
+ return initial_asso_value;
+}
+
+int
+Options::get_iterations (void) /* Returns the iterations value. */
+{
+ return iterations;
+}
+
+const char *
+Options::get_delimiter () /* Returns the string used to delimit keywords from other attributes. */
+{
+ return delimiters;
+}
+
+int
+Options::get_total_switches () /* Gets the total number of switch statements to generate. */
+{
+ return total_switches;
+}
+
+
+
+
diff --git a/apps/gperf/src/Options.h b/apps/gperf/src/Options.h
new file mode 100644
index 00000000000..2d67003d991
--- /dev/null
+++ b/apps/gperf/src/Options.h
@@ -0,0 +1,140 @@
+/* -*- C++ -*- */
+// @(#)Options.h 1.1 10/18/96
+
+/* This may look like C code, but it is really -*- C++ -*- */
+
+/* Handles parsing the Options provided to the user.
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* This module provides a uniform interface to the various options
+ available to a user of the gperf hash function generator. In
+ addition to the run-time options, found in the Option_Type below,
+ there is also the hash table Size and the Keys to be used in the
+ hashing. The overall design of this module was an experiment in
+ using C++ classes as a mechanism to enhance centralization of
+ option and and error handling, which tend to get out of hand in a C
+ program. */
+
+#ifndef options_h
+#define options_h 1
+
+#include "ace/Log_Msg.h"
+
+/* Enumerate the potential debugging Options. */
+
+enum Option_Type
+{
+ DEBUG = 01, /* Enable debugging (prints diagnostics to stderr). */
+ ORDER = 02, /* Apply ordering heuristic to speed-up search time. */
+ ANSI = 04, /* Generate ANSI prototypes. */
+ ALLCHARS = 010, /* Use all characters in hash function. */
+ GNU = 020, /* Assume GNU extensions (primarily function inline). */
+ TYPE = 040, /* Handle user-defined type structured keyword input. */
+ RANDOM = 0100, /* Randomly initialize the associated values table. */
+ DEFAULTCHARS = 0200, /* Make default char positions be 1,$ (end of keyword). */
+ SWITCH = 0400, /* Generate switch output to save space. */
+ POINTER = 01000, /* Have in_word_set function return pointer, not boolean. */
+ NOLENGTH = 02000, /* Don't include keyword length in hash computations. */
+ LENTABLE = 04000, /* Generate a length table for string comparison. */
+ DUP = 010000, /* Handle duplicate hash values for keywords. */
+ FAST = 020000, /* Generate the hash function ``fast.'' */
+ NOTYPE = 040000, /* Don't include user-defined type definition in output -- it's already defined elsewhere. */
+ COMP = 0100000, /* Generate strncmp rather than strcmp. */
+ GLOBAL = 0200000, /* Make the keyword table a global variable. */
+ CONST = 0400000, /* Make the generated tables readonly (const). */
+ CPLUSPLUS = 01000000, /* Generate C++ code. */
+ C = 02000000, /* Generate C code. */
+ ENUM = 04000000, /* Use enum for constants. */
+ STRCASECMP = 010000000, /* Use the case insensitive comparison. */
+ OPTIMIZE = 020000000, /* Assume all input keywords are in the keyset. */
+ ADA = 040000000 /* Generate Ada code. */
+};
+
+/* Define some useful constants (these don't really belong here, but I'm
+ not sure where else to put them!). These should be consts, but g++
+ doesn't seem to do the right thing with them at the moment... ;-( */
+
+enum
+{
+ MAX_KEY_POS = 128 - 1, /* Max size of each word's key set. */
+ WORD_START = 1, /* Signals the start of a word. */
+ WORD_END = 0, /* Signals the end of a word. */
+ EOS = MAX_KEY_POS /* Signals end of the key list. */
+};
+
+/* Class manager for gperf program Options. */
+
+class Options
+{
+public:
+ Options (void);
+ ~Options (void);
+ int operator[] (Option_Type option);
+ void operator() (int argc, char *argv[]);
+ void operator= (enum Option_Type);
+ void operator!= (enum Option_Type);
+ static void print_options (void);
+ static void set_asso_max (int r);
+ static int get_asso_max (void);
+ static void reset (void);
+ static int get (void);
+ static int get_iterations (void);
+ static int get_max_keysig_size (void);
+ static void set_keysig_size (int);
+ static int get_jump (void);
+ static int initial_value (void);
+ static int get_total_switches (void);
+ static const char *get_function_name (void);
+ static const char *get_key_name (void);
+ static const char *get_class_name (void);
+ static const char *get_hash_name (void);
+ static const char *get_delimiter (void);
+
+private:
+ static int option_word; /* Holds the user-specified Options. */
+ static int total_switches; /* Number of switch statements to generate. */
+ static int total_keysig_size; /* Total number of distinct key_positions. */
+ static int size; /* Range of the hash table. */
+ static int key_pos; /* Tracks current key position for Iterator. */
+ static int jump; /* Jump length when trying alternative values. */
+ static int initial_asso_value; /* Initial value for asso_values table. */
+ static int argument_count; /* Records count of command-line arguments. */
+ static int iterations; /* Amount to iterate when a collision occurs. */
+ static char **argument_vector; /* Stores a pointer to command-line vector. */
+ static const char *function_name; /* Names used for generated lookup function. */
+ static const char *key_name; /* Name used for keyword key. */
+ static const char *class_name; /* Name used for generated C++ class. */
+ static const char *hash_name; /* Name used for generated hash function. */
+ static const char *delimiters; /* Separates keywords from other attributes. */
+ static char key_positions[MAX_KEY_POS]; /* Contains user-specified key choices. */
+ static int key_sort (char *base, int len); /* Sorts key positions in REVERSE order. */
+ static void usage (void); /* Prints proper program usage. */
+};
+
+/* Global option coordinator for the entire program. */
+extern Options option;
+
+/* Set to 1 if your want to stack-allocate some large arrays. */
+#ifndef LARGE_STACK_ARRAYS
+#define LARGE_STACK_ARRAYS 0
+#endif
+
+#endif
diff --git a/apps/gperf/src/Vectors.cpp b/apps/gperf/src/Vectors.cpp
new file mode 100644
index 00000000000..761e08b2672
--- /dev/null
+++ b/apps/gperf/src/Vectors.cpp
@@ -0,0 +1,33 @@
+/* This may look like C code, but it is really -*- C++ -*- */
+// @(#)Vectors.cpp 1.1 10/18/96
+
+
+/* Static class data members that are shared between several classes via
+ inheritance.
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "Vectors.h"
+
+// Counts occurrences of each key set character.
+int Vectors::occurrences[ALPHA_SIZE];
+
+// Value associated with each character.
+int Vectors::asso_values[ALPHA_SIZE];
diff --git a/apps/gperf/src/Vectors.h b/apps/gperf/src/Vectors.h
new file mode 100644
index 00000000000..c01e9f27d8f
--- /dev/null
+++ b/apps/gperf/src/Vectors.h
@@ -0,0 +1,44 @@
+/* -*- C++ -*- */
+// @(#)Vectors.h 1.1 10/18/96
+
+#include <stdio.h>
+
+/* This may look like C code, but it is really -*- C++ -*- */
+
+/* Static class data members that are shared between several classes via
+ inheritance.
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef vectors_h
+#define vectors_h 1
+
+static const int ALPHA_SIZE = 128;
+
+struct Vectors
+{
+ static int occurrences[ALPHA_SIZE];
+ // Counts occurrences of each key set character.
+
+ static int asso_values[ALPHA_SIZE];
+ // Value associated with each character.
+};
+
+#endif
diff --git a/apps/gperf/src/Version.cpp b/apps/gperf/src/Version.cpp
new file mode 100644
index 00000000000..8fb0d398887
--- /dev/null
+++ b/apps/gperf/src/Version.cpp
@@ -0,0 +1,25 @@
+/* Current program version number.
+// @(#)Version.cpp 1.1 10/18/96
+
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111,
+USA. */
+
+char *version_string = "2.6 (GNU C++ version)";
diff --git a/apps/gperf/src/gperf.cpp b/apps/gperf/src/gperf.cpp
new file mode 100644
index 00000000000..2e6aa2c6406
--- /dev/null
+++ b/apps/gperf/src/gperf.cpp
@@ -0,0 +1,66 @@
+/* Driver program for the Gen_Perf hash function generator Copyright
+// @(#)gperf.cpp 1.1 10/18/96
+
+ (C) 1989 Free Software Foundation, Inc. written by Douglas
+ C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+// Simple driver program for the Gen_Perf.hash function generator.
+// All the hard work is done in class Gen_Perf and its class methods.
+
+#include "Options.h"
+#include "Gen_Perf.h"
+
+int
+main (int argc, char *argv[])
+{
+
+ struct tm *tm;
+ time_t clock;
+
+ time (&clock);
+ tm = localtime (&clock);
+ printf ("/* starting time is %d:%02d:%02d */\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+#if defined(RLIMIT_STACK) && LARGE_STACK_ARRAYS
+ /* Get rid of any avoidable limit on stack size. */
+ {
+ struct rlimit rlim;
+
+ /* Set the stack limit huge so that alloca does not fail. */
+ getrlimit (RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit (RLIMIT_STACK, &rlim);
+ }
+#endif /* RLIMIT_STACK */
+
+ /* Sets the Options. */
+ option (argc, argv);
+
+ // Initializes the key word list.
+ Gen_Perf table;
+
+ // Generates and prints the Gen_Perf hash table. Don't use exit
+ // here, it skips the destructors.
+ int status = table.generate ();
+
+ time (&clock);
+ tm = localtime (&clock);
+ printf ("/* ending time is %d:%02d:%02d */\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
+ return status;
+}
diff --git a/apps/gperf/src/new.cpp b/apps/gperf/src/new.cpp
new file mode 100644
index 00000000000..ebaafa16917
--- /dev/null
+++ b/apps/gperf/src/new.cpp
@@ -0,0 +1,75 @@
+/* Defines a buffered memory allocation abstraction that reduces calls to
+// @(#)new.cpp 1.1 10/18/96
+
+ malloc.
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+
+This file is part of GNU GPERF.
+
+GNU GPERF is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU GPERF is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU GPERF; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "Options.h"
+
+/* Determine default alignment. If your C++ compiler does not like
+ this then try something like #define DEFAULT_ALIGNMENT 8. */
+struct fooalign {char x; double d;};
+const int ALIGNMENT = ((char *)&((struct fooalign *) 0)->d - (char *)0);
+
+/* Provide an abstraction that cuts down on the number of calls to NEW
+ by buffering the memory pool from which strings are allocated. */
+
+void *
+operator new (size_t size)
+{
+ static char *buf_start = 0; /* Large array used to reduce calls to NEW. */
+ static char *buf_end = 0; /* Indicates end of BUF_START. */
+ static int buf_size = 4 * BUFSIZ; /* Size of buffer pointed to by BUF_START. */
+ char *temp;
+
+ /* Align this on correct boundaries, just to be safe... */
+ size = ((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
+
+ /* If we are about to overflow our buffer we'll just grab another
+ chunk of memory. Since we never free the original memory it
+ doesn't matter that no one points to the beginning of that
+ chunk. Note we use a heuristic that grows the buffer either by
+ size of the request or by twice the previous size, whichever is
+ larger. */
+
+ if (buf_start + size >= buf_end)
+ {
+ buf_size *= 2;
+ if (buf_size < size)
+ buf_size = size;
+ if (buf_start = (char *)malloc (buf_size))
+ buf_end = buf_start + buf_size;
+ else
+ ACE_ERROR ((LM_ERROR, "Virtual memory failed at %s, %s in function %s\n%a", __FILE__, __LINE__, "operator new", 1));
+ }
+
+ temp = buf_start;
+ buf_start += size;
+ return temp;
+}
+
+/* We need this deletion operator in order to make the linker happy. */
+
+void
+operator delete (void *ptr)
+{
+ // We cannot call free here, as it doesn't match the mallocs.
+ // free ((char *) ptr);
+}