aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile77
-rw-r--r--src/Makefile.in146
-rw-r--r--src/bool-array.cc49
-rw-r--r--src/bool-array.h66
-rw-r--r--src/bool-array.icc85
-rw-r--r--src/boolarray.c90
-rw-r--r--src/boolarray.h48
-rw-r--r--src/config.h.in19
-rwxr-xr-xsrc/configure1660
-rw-r--r--src/configure.in71
-rw-r--r--src/gen-perf.cc359
-rw-r--r--src/gen-perf.h50
-rw-r--r--src/getopt.c413
-rw-r--r--src/gperf-to-do22
-rw-r--r--src/hash-table.cc95
-rw-r--r--src/hash-table.h43
-rw-r--r--src/hashtable.c132
-rw-r--r--src/hashtable.h37
-rw-r--r--src/iterator.c106
-rw-r--r--src/iterator.cc87
-rw-r--r--src/iterator.h51
-rw-r--r--src/key-list.cc2184
-rw-r--r--src/key-list.h96
-rw-r--r--src/keylist.c1033
-rw-r--r--src/keylist.h54
-rw-r--r--src/list-node.cc102
-rw-r--r--src/list-node.h46
-rw-r--r--src/listnode.c111
-rw-r--r--src/listnode.h43
-rw-r--r--src/main.c96
-rw-r--r--src/main.cc76
-rw-r--r--src/new.cc87
-rw-r--r--src/options.c444
-rw-r--r--src/options.cc727
-rw-r--r--src/options.h159
-rw-r--r--src/options.icc183
-rw-r--r--src/perfect.c350
-rw-r--r--src/perfect.h45
-rw-r--r--src/prototype.h15
-rw-r--r--src/read-line.cc97
-rw-r--r--src/read-line.h53
-rw-r--r--src/read-line.icc47
-rw-r--r--src/readline.c87
-rw-r--r--src/readline.h31
-rw-r--r--src/stderr.c90
-rw-r--r--src/stderr.h29
-rw-r--r--src/trace.cc35
-rw-r--r--src/trace.h40
-rw-r--r--src/vectors.cc25
-rw-r--r--src/vectors.h37
-rw-r--r--src/version.c22
-rw-r--r--src/version.cc22
-rw-r--r--src/version.h23
-rw-r--r--src/xmalloc.c78
54 files changed, 10273 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 000000000000..05f59a4bdabb
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,77 @@
+# 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+CC = gcc
+DFLAGS= -DLO_CAL -DGATHER_STATISTICS #-DRLIMIT_STACK
+OFLAGS= -O -p -g -fstrength-reduce -fomit-frame-pointer -fdelayed-branch -finline-functions # gcc options
+CFLAGS= $(DFLAGS) $(OFLAGS)
+OBJS = options.o iterator.o main.o perfect.o keylist.o listnode.o xmalloc.o \
+ hashtable.o boolarray.o readline.o stderr.o version.o getopt.o
+SOURCES = options.c iterator.c main.c perfect.c keylist.c listnode.c xmalloc.c \
+ hashtable.c boolarray.c readline.c stderr.c version.c getopt.c
+
+all: gperf
+
+gperf: $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
+
+clean:
+ -rm -f *.o core *~ #*#
+
+realclean: clean
+ -rm -f gperf
+
+# dependencies
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+boolarray.o: boolarray.c /usr/include/stdio.h boolarray.h prototype.h options.h
+boolarray.o: /usr/include/stdio.h prototype.h
+getopt.o: getopt.c /usr/include/stdio.h
+hashtable.o: hashtable.c /usr/include/stdio.h hashtable.h keylist.h
+hashtable.o: /usr/include/stdio.h listnode.h prototype.h prototype.h options.h
+hashtable.o: /usr/include/stdio.h prototype.h
+iterator.o: iterator.c /usr/include/stdio.h /usr/include/ctype.h iterator.h
+iterator.o: prototype.h
+keylist.o: keylist.c /usr/include/assert.h /usr/include/stdio.h options.h
+keylist.o: /usr/include/stdio.h prototype.h readline.h prototype.h keylist.h
+keylist.o: /usr/include/stdio.h listnode.h prototype.h hashtable.h keylist.h
+keylist.o: prototype.h stderr.h prototype.h /usr/include/varargs.h
+listnode.o: listnode.c /usr/include/stdio.h options.h /usr/include/stdio.h
+listnode.o: prototype.h listnode.h prototype.h stderr.h prototype.h
+listnode.o: /usr/include/varargs.h
+main.o: main.c /usr/include/stdio.h stderr.h prototype.h /usr/include/varargs.h
+main.o: options.h /usr/include/stdio.h prototype.h perfect.h prototype.h
+main.o: keylist.h /usr/include/stdio.h listnode.h prototype.h boolarray.h
+main.o: prototype.h
+options.o: options.c /usr/include/stdio.h /usr/include/assert.h options.h
+options.o: /usr/include/stdio.h prototype.h iterator.h prototype.h stderr.h
+options.o: prototype.h /usr/include/varargs.h
+perfect.o: perfect.c /usr/include/stdio.h /usr/include/assert.h
+perfect.o: /usr/include/ctype.h options.h /usr/include/stdio.h prototype.h
+perfect.o: perfect.h prototype.h keylist.h /usr/include/stdio.h listnode.h
+perfect.o: prototype.h boolarray.h prototype.h stderr.h prototype.h
+perfect.o: /usr/include/varargs.h
+readline.o: readline.c /usr/include/stdio.h readline.h prototype.h
+stderr.o: stderr.c /usr/include/stdio.h stderr.h prototype.h
+stderr.o: /usr/include/varargs.h
+version.o: version.c
+xmalloc.o: xmalloc.c /usr/include/stdio.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 000000000000..60f73c735a34
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,146 @@
+# Makefile for gperf/src
+
+# Copyright (C) 1989, 1992, 1993, 1998, 2000 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.
+
+#### Start of system configuration section. ####
+
+# Directories used by "make":
+srcdir = @srcdir@
+
+# Directories used by "make install":
+prefix = @prefix@
+local_prefix = /usr/local
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+
+# Programs used by "make":
+# C compiler
+CC = @CC@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+# C++ compiler
+CXX = @CXX@
+CXXFLAGS = @CXXFLAGS@
+CXXCPP = @CXXCPP@
+# Both C and C++ compiler
+LDFLAGS = @LDFLAGS@
+# Other
+MV = mv
+LN = ln
+RM = rm -f
+@SET_MAKE@
+
+# Programs used by "make install":
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+MKINSTALLDIRS = $(SHELL) $(srcdir)/../mkinstalldirs
+
+#### End of system configuration section. ####
+
+SHELL = /bin/sh
+
+VPATH = $(srcdir)
+
+OBJECTS = new.o options.o iterator.o main.o gen-perf.o key-list.o list-node.o \
+ hash-table.o bool-array.o read-line.o trace.o vectors.o version.o
+LIBS = ../lib/libgp.a -lm
+CPPFLAGS = -I. -I$(srcdir)/../lib
+
+TARGETPROG = gperf
+
+all : $(TARGETPROG)
+
+$(TARGETPROG): $(OBJECTS)
+ $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
+
+# Don't use implicit rules, since AIX "make" and OSF/1 "make" don't always
+# expand $< correctly in this context.
+#
+#%.o : %.c
+# $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
+#
+#%.o : %.cc
+# $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
+
+# Dependencies.
+CONFIG_H = config.h
+VERSION_H = version.h
+VECTORS_H = vectors.h
+TRACE_H = trace.h
+READ_LINE_H = read-line.h read-line.icc $(TRACE_H)
+OPTIONS_H = options.h options.icc $(TRACE_H)
+LIST_NODE_H = list-node.h $(VECTORS_H)
+KEY_LIST_H = key-list.h $(LIST_NODE_H) $(VECTORS_H) $(READ_LINE_H)
+ITERATOR_H = iterator.h
+HASH_TABLE_H = hash-table.h $(LIST_NODE_H)
+BOOL_ARRAY_H = bool-array.h bool-array.icc $(TRACE_H) $(OPTIONS_H)
+GEN_PERF_H = gen-perf.h $(KEY_LIST_H) $(BOOL_ARRAY_H)
+
+bool-array.o : bool-array.cc $(BOOL_ARRAY_H) $(OPTIONS_H) $(TRACE_H)
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/bool-array.cc
+gen-perf.o : gen-perf.cc $(GEN_PERF_H) $(OPTIONS_H) $(TRACE_H)
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/gen-perf.cc
+hash-table.o : hash-table.cc $(HASH_TABLE_H) $(OPTIONS_H) $(TRACE_H)
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/hash-table.cc
+iterator.o : iterator.cc $(ITERATOR_H) $(TRACE_H)
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/iterator.cc
+key-list.o : key-list.cc $(KEY_LIST_H) $(OPTIONS_H) $(READ_LINE_H) $(HASH_TABLE_H) $(TRACE_H) $(VERSION_H)
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/key-list.cc
+list-node.o : list-node.cc $(LIST_NODE_H) $(OPTIONS_H) $(TRACE_H)
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/list-node.cc
+main.o : main.cc $(OPTIONS_H) $(GEN_PERF_H) $(TRACE_H) $(CONFIG_H)
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/main.cc
+new.o : new.cc $(TRACE_H) $(CONFIG_H)
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/new.cc
+options.o : options.cc $(OPTIONS_H) $(ITERATOR_H) $(TRACE_H) $(VECTORS_H) $(VERSION_H)
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/options.cc
+read-line.o : read-line.cc $(READ_LINE_H) $(OPTIONS_H) $(TRACE_H)
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/read-line.cc
+trace.o : trace.cc $(TRACE_H)
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/trace.cc
+vectors.o : vectors.cc $(VECTORS_H)
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/vectors.cc
+version.o : version.cc $(VERSION_H)
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(srcdir)/version.cc
+
+install : all force
+ $(MKINSTALLDIRS) $(DESTDIR)$(bindir)
+ $(INSTALL_PROGRAM) $(TARGETPROG) $(DESTDIR)$(bindir)/$(TARGETPROG)
+
+installdirs : force
+ $(MKINSTALLDIRS) $(DESTDIR)$(bindir)
+
+uninstall : force
+ $(RM) $(DESTDIR)$(bindir)/$(TARGETPROG)
+
+check : all
+
+mostlyclean : clean
+
+clean : force
+ $(RM) *~ *.s *.o *.a $(TARGETPROG) core
+
+distclean : clean
+ $(RM) config.status config.log config.cache Makefile config.h
+
+maintainer-clean : distclean
+
+force :
diff --git a/src/bool-array.cc b/src/bool-array.cc
new file mode 100644
index 000000000000..0774b2d65265
--- /dev/null
+++ b/src/bool-array.cc
@@ -0,0 +1,49 @@
+/* Fast lookup table abstraction implemented as an Iteration Number Array
+ Copyright (C) 1989-1998 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"
+
+#include <stdio.h>
+#include <string.h>
+#include "options.h"
+#include "trace.h"
+
+STORAGE_TYPE * Bool_Array::storage_array;
+STORAGE_TYPE Bool_Array::iteration_number;
+unsigned int Bool_Array::size;
+
+/* Prints out debugging diagnostics. */
+
+Bool_Array::~Bool_Array (void)
+{
+ T (Trace t ("Bool_Array::~Bool_Array");)
+ if (option[DEBUG])
+ fprintf (stderr, "\ndumping boolean array information\n"
+ "size = %d\niteration number = %d\nend of array dump\n",
+ size, iteration_number);
+}
+
+#ifndef __OPTIMIZE__
+
+#define INLINE /* not inline */
+#include "bool-array.icc"
+#undef INLINE
+
+#endif /* not defined __OPTIMIZE__ */
diff --git a/src/bool-array.h b/src/bool-array.h
new file mode 100644
index 000000000000..8330fcd22019
--- /dev/null
+++ b/src/bool-array.h
@@ -0,0 +1,66 @@
+/* This may look like C code, but it is really -*- C++ -*- */
+
+/* Simple lookup table abstraction implemented as an Iteration Number Array.
+
+ Copyright (C) 1989-1998 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 Iteration Numbering implementation to save on initialization time. */
+
+#ifndef bool_array_h
+#define bool_array_h 1
+
+#include "trace.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 unsigned short STORAGE_TYPE;
+#else
+typedef unsigned int STORAGE_TYPE;
+#endif
+
+class Bool_Array
+{
+private:
+ static STORAGE_TYPE *storage_array; /* Initialization of the index space. */
+ static STORAGE_TYPE iteration_number; /* Keep track of the current iteration. */
+ static unsigned int size; /* Keep track of array size. */
+
+public:
+ Bool_Array (void);
+ ~Bool_Array (void);
+ static void init (STORAGE_TYPE *buffer, unsigned int s);
+ static int find (int hash_value);
+ static void reset (void);
+};
+
+#ifdef __OPTIMIZE__ /* efficiency hack! */
+
+#include <stdio.h>
+#include <string.h>
+#include "options.h"
+#define INLINE inline
+#include "bool-array.icc"
+#undef INLINE
+
+#endif
+
+#endif
diff --git a/src/bool-array.icc b/src/bool-array.icc
new file mode 100644
index 000000000000..6de6f236e712
--- /dev/null
+++ b/src/bool-array.icc
@@ -0,0 +1,85 @@
+/* Inline Functions for bool-array.{h,cc}.
+
+ Copyright (C) 1989-1998 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. */
+
+// This needs:
+//#include <stdio.h>
+//#include <string.h>
+//#include "options.h"
+//#include "trace.h"
+
+INLINE
+Bool_Array::Bool_Array (void)
+{
+ T (Trace t ("Bool_Array::Bool_Array");)
+ storage_array = 0;
+ iteration_number = size = 0;
+}
+
+INLINE void
+Bool_Array::init (STORAGE_TYPE *buffer, unsigned int s)
+{
+ T (Trace t ("Bool_Array::init");)
+ size = s;
+ iteration_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, (unsigned int) (size * sizeof (*storage_array)));
+}
+
+INLINE int
+Bool_Array::find (int index)
+{
+ T (Trace t ("Bool_Array::find");)
+ if (storage_array[index] == iteration_number)
+ return 1;
+ else
+ {
+ storage_array[index] = iteration_number;
+ return 0;
+ }
+}
+
+INLINE void
+Bool_Array::reset (void)
+{
+ T (Trace t ("Bool_Array::reset");)
+ /* If we wrap around it's time to zero things out again! However, this only
+ occurs once about every 2^31 or 2^15 iterations, so it should probably
+ never happen! */
+
+ if (++iteration_number == 0)
+ {
+ if (option[DEBUG])
+ {
+ fprintf (stderr, "(re-initializing bool_array)...");
+ fflush (stderr);
+ }
+ iteration_number = 1;
+ memset (storage_array, 0, size * sizeof (*storage_array));
+ if (option[DEBUG])
+ {
+ fprintf (stderr, "done\n");
+ fflush (stderr);
+ }
+ }
+}
diff --git a/src/boolarray.c b/src/boolarray.c
new file mode 100644
index 000000000000..890613499200
--- /dev/null
+++ b/src/boolarray.c
@@ -0,0 +1,90 @@
+/* Fast lookup table abstraction implemented as a Guilmette 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "boolarray.h"
+#include "options.h"
+
+/* Locally visible BOOL_ARRAY object. */
+
+static BOOL_ARRAY bool_array;
+
+/* Prints out debugging diagnostics. */
+
+void
+bool_array_destroy ()
+{
+ if (OPTION_ENABLED (option, DEBUG))
+ fprintf (stderr, "\ndumping boolean array information\niteration number = %d\nend of array dump\n",
+ bool_array.iteration_number);
+ free ((char *) bool_array.storage_array);
+}
+
+void
+bool_array_init (size)
+ int size;
+{
+ STORAGE_TYPE *xmalloc ();
+ bool_array.iteration_number = 1;
+ bool_array.size = size;
+ bool_array.storage_array = xmalloc (size * sizeof *bool_array.storage_array);
+ bzero (bool_array.storage_array, size * sizeof *bool_array.storage_array);
+ if (OPTION_ENABLED (option, DEBUG))
+ fprintf (stderr, "\nbool array size = %d, total bytes = %d\n",
+ bool_array.size, bool_array.size * sizeof *bool_array.storage_array);
+}
+
+bool
+lookup (index)
+ int index;
+{
+ if (bool_array.storage_array[index] == bool_array.iteration_number)
+ return 1;
+ else
+ {
+ bool_array.storage_array[index] = bool_array.iteration_number;
+ return 0;
+ }
+}
+
+/* Simple enough to reset, eh?! */
+
+void
+bool_array_reset ()
+{
+ /* If we wrap around it's time to zero things out again! */
+
+
+ if (++bool_array.iteration_number == 0)
+ {
+ if (OPTION_ENABLED (option, DEBUG))
+ {
+ fprintf (stderr, "(re-initializing bool_array)...");
+ fflush (stderr);
+ }
+ bool_array.iteration_number = 1;
+ bzero (bool_array.storage_array, bool_array.size * sizeof *bool_array.storage_array);
+ if (OPTION_ENABLED (option, DEBUG))
+ {
+ fprintf (stderr, "done\n");
+ fflush (stderr);
+ }
+ }
+}
diff --git a/src/boolarray.h b/src/boolarray.h
new file mode 100644
index 000000000000..48339755060a
--- /dev/null
+++ b/src/boolarray.h
@@ -0,0 +1,48 @@
+/* Simple lookup table abstraction implemented as a Guilmette 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Define and implement a simple boolean array abstraction,
+ uses a Guilmette array implementation to save on initialization time. */
+
+#ifndef _boolarray_h
+#define _boolarray_h
+#include "prototype.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 unsigned short STORAGE_TYPE;
+#else
+typedef int STORAGE_TYPE;
+#endif
+typedef struct bool_array
+{
+ STORAGE_TYPE *storage_array; /* Initialization of the index space. */
+ STORAGE_TYPE iteration_number; /* Keep track of the current iteration. */
+ int size; /* Size of the entire array (dynamically initialized). */
+} BOOL_ARRAY;
+
+extern void bool_array_init P ((int size));
+extern void bool_array_destroy P ((void));
+extern bool lookup P ((int hash_value));
+extern void bool_array_reset P ((void));
+
+#endif /* _boolarray_h */
diff --git a/src/config.h.in b/src/config.h.in
new file mode 100644
index 000000000000..4d3d76212d6c
--- /dev/null
+++ b/src/config.h.in
@@ -0,0 +1,19 @@
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if the C++ compiler supports "throw ()" declarations. */
+#undef HAVE_THROW_DECL
+
+/* Define if you have the getrlimit function. */
+#undef HAVE_GETRLIMIT
+
+/* Define if you have the setrlimit function. */
+#undef HAVE_SETRLIMIT
+
+/* Define if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
diff --git a/src/configure b/src/configure
new file mode 100755
index 000000000000..edd1fd7f0520
--- /dev/null
+++ b/src/configure
@@ -0,0 +1,1660 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=gen-perf.cc
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:527: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:556: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:586: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:637: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:669: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 680 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:685: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:711: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:716: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:725: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:744: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+ echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:776: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 791 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:797: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 808 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:814: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 825 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:831: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+ for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:860: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CXX"; then
+ ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CXX="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CXX="$ac_cv_prog_CXX"
+if test -n "$CXX"; then
+ echo "$ac_t""$CXX" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$CXX" && break
+done
+test -n "$CXX" || CXX="gcc"
+
+
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:892: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 903 "configure"
+#include "confdefs.h"
+
+int main(){return(0);}
+EOF
+if { (eval echo configure:908: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cxx_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cxx_cross=no
+ else
+ ac_cv_prog_cxx_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cxx_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6
+if test $ac_cv_prog_cxx_works = no; then
+ { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:934: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6
+cross_compiling=$ac_cv_prog_cxx_cross
+
+echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
+echo "configure:939: checking whether we are using GNU C++" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.C <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:948: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gxx=yes
+else
+ ac_cv_prog_gxx=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gxx" 1>&6
+
+if test $ac_cv_prog_gxx = yes; then
+ GXX=yes
+else
+ GXX=
+fi
+
+ac_test_CXXFLAGS="${CXXFLAGS+set}"
+ac_save_CXXFLAGS="$CXXFLAGS"
+CXXFLAGS=
+echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+echo "configure:967: checking whether ${CXX-g++} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.cc
+if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
+ ac_cv_prog_cxx_g=yes
+else
+ ac_cv_prog_cxx_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6
+if test "$ac_test_CXXFLAGS" = set; then
+ CXXFLAGS="$ac_save_CXXFLAGS"
+elif test $ac_cv_prog_cxx_g = yes; then
+ if test "$GXX" = yes; then
+ CXXFLAGS="-g -O2"
+ else
+ CXXFLAGS="-g"
+ fi
+else
+ if test "$GXX" = yes; then
+ CXXFLAGS="-O2"
+ else
+ CXXFLAGS=
+ fi
+fi
+
+ echo $ac_n "checking how to run the C++ preprocessor""... $ac_c" 1>&6
+echo "configure:999: checking how to run the C++ preprocessor" >&5
+if test -z "$CXXCPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CXXCPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+ CXXCPP="${CXX-g++} -E"
+ cat > conftest.$ac_ext <<EOF
+#line 1012 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1017: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CXXCPP=/lib/cpp
+fi
+rm -f conftest*
+ ac_cv_prog_CXXCPP="$CXXCPP"
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+fi
+fi
+CXXCPP="$ac_cv_prog_CXXCPP"
+echo "$ac_t""$CXXCPP" 1>&6
+
+ # Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1052: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'cl_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ for ac_prog in ginstall installbsd scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ # OSF/1 installbsd also uses dspmsg, but is usable.
+ :
+ else
+ if test $ac_prog = installbsd &&
+ grep src/bos $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX installbsd doesn't work without option "-g".
+ :
+ else
+ cl_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_ifs"
+ # As a last resort, use cp.
+ test -z "$cl_cv_path_install" && cl_cv_path_install="cp"
+
+fi
+ INSTALL="$cl_cv_path_install"
+fi
+echo "$ac_t""$INSTALL" 1>&6
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='$(INSTALL)'
+if test -z "$INSTALL_DATA"; then
+ case "$INSTALL" in
+ cp | */cp ) INSTALL_DATA='$(INSTALL)' ;;
+ * ) INSTALL_DATA='$(INSTALL) -m 644' ;;
+ esac
+fi
+
+ echo $ac_n "checking for working throw()""... $ac_c" 1>&6
+echo "configure:1105: checking for working throw()" >&5
+if eval "test \"`echo '$''{'gp_cv_cxx_throw_decl'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+cat > conftest.$ac_ext <<EOF
+#line 1119 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+void operator delete (void* ptr) throw() {}
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:1127: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ gp_cv_cxx_throw_decl=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ gp_cv_cxx_throw_decl=no
+fi
+rm -f conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+
+fi
+
+echo "$ac_t""$gp_cv_cxx_throw_decl" 1>&6
+if test $gp_cv_cxx_throw_decl = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_THROW_DECL 1
+EOF
+
+fi
+for ac_hdr in unistd.h sys/time.h sys/resource.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1158: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1163 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1168: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ if test $ac_cv_header_sys_resource_h = yes; then
+for ac_func in getrlimit
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1198: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1203 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1226: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ if test $ac_cv_func_getrlimit = yes; then
+for ac_func in setrlimit
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1254: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1259 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1282: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ fi
+fi
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+
+trap 'rm -fr `echo "Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@CXX@%$CXX%g
+s%@CXXCPP@%$CXXCPP%g
+s%@INSTALL@%$INSTALL%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/src/configure.in b/src/configure.in
new file mode 100644
index 000000000000..e8880d507f85
--- /dev/null
+++ b/src/configure.in
@@ -0,0 +1,71 @@
+dnl autoconf configuration for gperf/src
+
+dnl Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+dnl written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+dnl
+dnl This file is part of GNU GPERF.
+dnl
+dnl GNU GPERF is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 1, or (at your option)
+dnl any later version.
+dnl
+dnl GNU GPERF is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with GNU GPERF; see the file COPYING. If not, write to the
+dnl Free Software Foundation, 59 Temple Place - Suite 330, Boston,
+dnl MA 02111-1307, USA.
+
+AC_INIT(gen-perf.cc)
+AC_CONFIG_HEADER(config.h)
+AC_PROG_MAKE_SET
+dnl
+dnl checks for programs
+dnl
+AC_PROG_CC
+ dnl sets variable CC
+AC_PROG_CPP
+ dnl sets variable CPP
+AC_PROG_CXX
+ dnl sets variable CXX
+AC_PROG_CXXCPP
+ dnl sets variable CXXCPP
+CL_PROG_INSTALL
+ dnl sets variables INSTALL, INSTALL_DATA, INSTALL_PROGRAM
+dnl
+dnl checks for compiler characteristics
+dnl
+AC_MSG_CHECKING([for working throw()])
+AC_CACHE_VAL(gp_cv_cxx_throw_decl,[
+AC_LANG_SAVE()
+AC_LANG_CPLUSPLUS()
+AC_TRY_COMPILE([#include <stdlib.h>
+void operator delete (void* ptr) throw() {}], [],
+gp_cv_cxx_throw_decl=yes, gp_cv_cxx_throw_decl=no)
+AC_LANG_RESTORE()
+])
+AC_MSG_RESULT([$]gp_cv_cxx_throw_decl)
+if test [$]gp_cv_cxx_throw_decl = yes; then
+ AC_DEFINE(HAVE_THROW_DECL)
+fi
+dnl
+dnl checks for functions and declarations
+dnl
+AC_CHECK_HEADERS(unistd.h sys/time.h sys/resource.h)
+ dnl DEFs HAVE_UNISTD_H, HAVE_SYS_TIME_H, HAVE_SYS_RESOURCE_H
+if test $ac_cv_header_sys_resource_h = yes; then
+AC_CHECK_FUNCS(getrlimit)
+ dnl DEFS HAVE_GETRLIMIT
+if test $ac_cv_func_getrlimit = yes; then
+AC_CHECK_FUNCS(setrlimit)
+ dnl DEFS HAVE_SETRLIMIT
+fi
+fi
+dnl
+dnl That's it.
+dnl
+AC_OUTPUT(Makefile)
diff --git a/src/gen-perf.cc b/src/gen-perf.cc
new file mode 100644
index 000000000000..0b5109d4ff4d
--- /dev/null
+++ b/src/gen-perf.cc
@@ -0,0 +1,359 @@
+/* Provides high-level routines to manipulate the keywork list
+ structures the code generation output.
+ Copyright (C) 1989-1998, 2000 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 <stdio.h>
+#include <stdlib.h> /* declares rand(), srand() */
+#include <time.h> /* declares time() */
+#include "options.h"
+#include "gen-perf.h"
+#include "trace.h"
+
+/* Efficiently returns the least power of two greater than or equal to X! */
+#define POW(X) ((!X)?1:(X-=1,X|=X>>1,X|=X>>2,X|=X>>4,X|=X>>8,X|=X>>16,(++X)))
+
+/* 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)
+{
+ T (Trace t ("Gen_Perf::Gen_Perf");)
+ int asso_value_max;
+ int non_linked_length;
+
+ Key_List::read_keys ();
+ if (option[ORDER])
+ reorder ();
+ asso_value_max = option.get_asso_max ();
+ non_linked_length = 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 (POW (asso_value_max));
+
+ if (option[RANDOM])
+ {
+ srand ((long) time (0));
+
+ for (int i = 0; i < ALPHA_SIZE; i++)
+ 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--)
+ asso_values[i] = asso_value & option.get_asso_max () - 1;
+ }
+ max_hash_value = Key_List::max_key_length () + option.get_asso_max () *
+ option.get_max_keysig_size ();
+
+ 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 (const char *set_1, int size_1, const char *set_2, int size_2, char *set_3)
+{
+ T (Trace t ("Gen_Perf::compute_disjoint_union");)
+ char *base = set_3;
+
+ while (size_1 > 0 && size_2 > 0)
+ if (*set_1 == *set_2)
+ set_1++, size_1--, set_2++, size_2--;
+ else
+ {
+ char next;
+ if (*set_1 < *set_2)
+ next = *set_1++, size_1--;
+ else
+ next = *set_2++, size_2--;
+ if (set_3 == base || next != set_3[-1])
+ *set_3++ = next;
+ }
+
+ while (size_1 > 0)
+ {
+ char next;
+ next = *set_1++, size_1--;
+ if (set_3 == base || next != set_3[-1])
+ *set_3++ = next;
+ }
+
+ while (size_2 > 0)
+ {
+ char next;
+ next = *set_2++, size_2--;
+ if (set_3 == base || next != set_3[-1])
+ *set_3++ = next;
+ }
+ 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)
+{
+ T (Trace t ("Gen_Perf::sort_set");)
+ int i, j;
+
+ for (i = 0, j = len - 1; i < j; i++)
+ {
+ int curr;
+ char tmp;
+
+ for (curr = i + 1, tmp = union_set[curr];
+ curr > 0 && occurrences[(unsigned char)tmp] < occurrences[(unsigned char)(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)
+{
+ T (Trace t ("Gen_Perf::hash");)
+ int sum = option[NOLENGTH] ? 0 : key_node->key_length;
+
+ const char *p = key_node->char_set;
+ int i = key_node->char_set_length;
+ for (; i > 0; p++, i--)
+ sum += asso_values[(unsigned char)(*p)];
+
+ 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 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)
+{
+ T (Trace t ("Gen_Perf::affects_prev");)
+ int original_char = asso_values[(unsigned char)c];
+ int total_iterations = !option[FAST]
+ ? option.get_asso_max () : option.get_iterations () ? option.get_iterations () : keyword_list_length ();
+
+ /* Try all legal associated values. */
+
+ for (int i = total_iterations - 1; i >= 0; i--)
+ {
+ int collisions = 0;
+
+ asso_values[(unsigned char)c] =
+ (asso_values[(unsigned char)c] + (option.get_jump () ? option.get_jump () : rand ()))
+ & (option.get_asso_max () - 1);
+
+ /* Iteration Number array is a win, O(1) intialization time! */
+ reset ();
+
+ /* See how this asso_value change affects previous keywords. If
+ it does better than before we'll take it! */
+
+ for (List_Node *ptr = head;
+ !Bool_Array::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. */
+ asso_values[(unsigned char)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)
+{
+ T (Trace t ("Gen_Perf::change");)
+ static char *union_set;
+ int union_set_length;
+
+ if (!union_set)
+ union_set = new char [2 * option.get_max_keysig_size ()];
+
+ if (option[DEBUG])
+ {
+ fprintf (stderr, "collision on keyword #%d, prior = \"%.*s\", curr = \"%.*s\" hash = %d\n",
+ num_done,
+ prior->key_length, prior->key,
+ curr->key_length, curr->key,
+ curr->hash_value);
+ fflush (stderr);
+ }
+ union_set_length = compute_disjoint_union (prior->char_set, prior->char_set_length, curr->char_set, curr->char_set_length, union_set);
+ sort_set (union_set, union_set_length);
+
+ /* Try changing some values, if change doesn't alter other values continue normal action. */
+ fewest_collisions++;
+
+ const char *p = union_set;
+ int i = union_set_length;
+ for (; i > 0; p++, i--)
+ if (!affects_prev (*p, curr))
+ {
+ if (option[DEBUG])
+ {
+ fprintf (stderr, " by changing asso_value['%c'] (char #%d) to %d\n",
+ *p, p - union_set + 1, asso_values[(unsigned char)(*p)]);
+ fflush (stderr);
+ }
+ return; /* Good, doesn't affect previous hash values, we'll take it. */
+ }
+
+ for (List_Node *ptr = 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 () : keyword_list_length (),
+ fewest_collisions + 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::operator() (void)
+{
+ T (Trace t ("Gen_Perf::operator()");)
+#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
+
+ Bool_Array::init (buffer, max_hash_value + 1);
+
+ List_Node *curr;
+ for (curr = head; curr; curr = curr->next)
+ {
+ hash (curr);
+
+ for (List_Node *ptr = 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.... */
+
+ Bool_Array::reset ();
+
+ for (curr = head; curr; curr = curr->next)
+ if (Bool_Array::find (hash (curr)))
+ if (option[DUP]) /* Keep track of this number... */
+ total_duplicates++;
+ else /* Yow, big problems. we're outta here! */
+ {
+ fprintf (stderr, "\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 ((char *) 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. */
+
+ sort ();
+ output ();
+#if !LARGE_STACK_ARRAYS
+ free ((char *) buffer);
+#endif
+ return 0;
+}
+
+/* Prints out some diagnostics upon completion. */
+
+Gen_Perf::~Gen_Perf (void)
+{
+ T (Trace t ("Gen_Perf::~Gen_Perf");)
+ if (option[DEBUG])
+ {
+ fprintf (stderr, "\ndumping occurrence and associated values tables\n");
+
+ for (int i = 0; i < ALPHA_SIZE; i++)
+ if (occurrences[i])
+ fprintf (stderr, "asso_values[%c] = %6d, occurrences[%c] = %6d\n",
+ i, asso_values[i], i, occurrences[i]);
+
+ fprintf (stderr, "end table dumping\n");
+
+ }
+}
+
diff --git a/src/gen-perf.h b/src/gen-perf.h
new file mode 100644
index 000000000000..602d160131d3
--- /dev/null
+++ b/src/gen-perf.h
@@ -0,0 +1,50 @@
+/* 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-1998, 2000 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 "key-list.h"
+#include "bool-array.h"
+
+class Gen_Perf : private Key_List, private Bool_Array
+{
+private:
+ 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. */
+
+ 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 (const char *set_1, int size_1, const char *set_2, int size_2, char *set_3);
+ static void sort_set (char *union_set, int len);
+
+public:
+ Gen_Perf (void);
+ ~Gen_Perf (void);
+ int operator () (void);
+};
+
+#endif
diff --git a/src/getopt.c b/src/getopt.c
new file mode 100644
index 000000000000..4eb3c2090887
--- /dev/null
+++ b/src/getopt.c
@@ -0,0 +1,413 @@
+/* Getopt for GNU.
+ Copyright (C) 1987, 1989 Free Software Foundation, Inc.
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of `argv' so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable _POSIX_OPTION_ORDER disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include <stdio.h>
+
+#ifdef sparc
+#include <alloca.h>
+#endif
+#ifdef USG
+#define bcopy(s, d, l) memcpy((d), (s), (l))
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ UNSPECIFIED means the caller did not specify anything;
+ the default is then REQUIRE_ORDER if the environment variable
+ _OPTIONS_FIRST is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options.
+ Stop option processing when the first non-option is seen.
+ This is what Unix does.
+
+ PERMUTE is the default. We permute the contents of `argv' as we scan,
+ so that eventually all the options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code zero.
+ Using `-' as the first character of the list of option characters
+ requests this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering;
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int nonopts_size
+ = (last_nonopt - first_nonopt) * sizeof (char *);
+ char **temp = (char **) alloca (nonopts_size);
+
+ /* Interchange the two blocks of data in argv. */
+
+ bcopy (&argv[first_nonopt], temp, nonopts_size);
+ bcopy (&argv[last_nonopt], &argv[first_nonopt],
+ (optind - last_nonopt) * sizeof (char *));
+ bcopy (temp, &argv[first_nonopt + optind - last_nonopt],
+ nonopts_size);
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of theoption characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ A colon in OPTSTRING means that the previous character is an option
+ that wants an argument. The argument is taken from the rest of the
+ current ARGV-element, or from the following ARGV-element,
+ and returned in `optarg'.
+
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg'.
+
+ If OPTSTRING starts with `-', it requests a different method of handling the
+ non-option ARGV-elements. See the comments about RETURN_IN_ORDER, above. */
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char **argv;
+ char *optstring;
+{
+ /* Initialize the internal data when the first call is made.
+ Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ if (optind == 0)
+ {
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = 0;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ ordering = RETURN_IN_ORDER;
+ else if (getenv ("_POSIX_OPTION_ORDER") != 0)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == 0 || *nextchar == 0)
+ {
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange (argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Now skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-'
+ || argv[optind][1] == 0))
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange (argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if (argv[optind][0] != '-' || argv[optind][1] == 0)
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 0;
+ }
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+
+ nextchar = argv[optind] + 1;
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = (char *) index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == 0)
+ optind++;
+
+ if (temp == 0 || c == ':')
+ {
+ if (opterr != 0)
+ {
+ if (c < 040 || c >= 0177)
+ fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+ argv[0], c);
+ else
+ fprintf (stderr, "%s: unrecognized option `-%c'\n",
+ argv[0], c);
+ }
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != 0)
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = 0;
+ nextchar = 0;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != 0)
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr != 0)
+ fprintf (stderr, "%s: no argument for `-%c' option\n",
+ argv[0], c);
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = 0;
+ }
+ }
+ return c;
+ }
+}
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind;
+ if ((c = getopt (argc, argv, "abc:d:0123456789")) == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ return 0;
+}
+
+#endif /* TEST */
diff --git a/src/gperf-to-do b/src/gperf-to-do
new file mode 100644
index 000000000000..05caecca9dbd
--- /dev/null
+++ b/src/gperf-to-do
@@ -0,0 +1,22 @@
+1. provide output diagnostics that explain how many input keys total,
+ how many after dealing with static links, and finally, after the
+ algorithm is complete, how many dynamic duplicates do we now
+ have.
+2. fix up GATHER_STATISTICS for all instrumentation.
+3. Useful idea:
+
+ a. Generate the wordlist as a contiguous block of keywords, as before.
+ This wordlist *must* be sorted by hash value.
+
+ b. generate the lookup_array, which are an array of signed {chars,shorts,ints},
+ which ever allows full coverage of the wordlist dimensions. If the
+ value v, where v = lookup_array[hash(str,len)], is >= 0, then we
+ simply use this result as a direct access into wordlist to snag
+ the keyword for comparison.
+
+ c. Otherwise, if v is < 0 this is an indication that we'll need to
+ search through some number of duplicates hash values. Using a
+ hash linking scheme we'd then index into a duplicate_address
+ table that would provide the starting index and total length of
+ the duplicate entries to consider sequentially.
+
diff --git a/src/hash-table.cc b/src/hash-table.cc
new file mode 100644
index 000000000000..a147674b3074
--- /dev/null
+++ b/src/hash-table.cc
@@ -0,0 +1,95 @@
+/* Hash table for checking keyword links. Implemented using double hashing.
+ Copyright (C) 1989-1998, 2000 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 "hash-table.h"
+
+#include <stdio.h>
+#include <string.h> /* declares memset(), strcmp() */
+#include <hash.h>
+#include "options.h"
+#include "trace.h"
+
+/* 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, int ignore_len):
+ table (table_ptr), size (s), collisions (0), ignore_length (ignore_len)
+{
+ T (Trace t ("Hash_Table::Hash_Table");)
+ memset ((char *) table, 0, size * sizeof (*table));
+}
+
+Hash_Table::~Hash_Table (void)
+{
+ T (Trace t ("Hash_Table::~Hash_Table");)
+ if (option[DEBUG])
+ {
+ int field_width = option.get_max_keysig_size ();
+
+ fprintf (stderr,
+ "\ndumping the hash table\n"
+ "total available table slots = %d, total bytes = %d, total collisions = %d\n"
+ "location, %*s, keyword\n",
+ size, size * (int) 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_length, table[i]->char_set,
+ table[i]->key_length, 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::insert (List_Node *item)
+{
+ T (Trace t ("Hash_Table::operator()");)
+ unsigned hash_val = hashpjw (item->char_set, item->char_set_length);
+ int probe = hash_val & (size - 1);
+ int increment = ((hash_val ^ item->key_length) | 1) & (size - 1);
+
+ while (table[probe])
+ {
+ if (table[probe]->char_set_length == item->char_set_length
+ && memcmp (table[probe]->char_set, item->char_set, item->char_set_length) == 0
+ && (ignore_length || table[probe]->key_length == item->key_length))
+ return table[probe];
+
+ collisions++;
+ probe = (probe + increment) & (size - 1);
+ }
+
+ table[probe] = item;
+ return (List_Node *) 0;
+}
diff --git a/src/hash-table.h b/src/hash-table.h
new file mode 100644
index 000000000000..86438d00f7d6
--- /dev/null
+++ b/src/hash-table.h
@@ -0,0 +1,43 @@
+/* This may look like C code, but it is really -*- C++ -*- */
+
+/* Hash table used to check for duplicate keyword entries.
+
+ Copyright (C) 1989-1998, 2000 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 "list-node.h"
+
+class Hash_Table
+{
+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! */
+ int ignore_length;
+
+public:
+ Hash_Table (List_Node **t, int s, int ignore_len);
+ ~Hash_Table (void);
+ List_Node *insert (List_Node *item);
+};
+
+#endif
diff --git a/src/hashtable.c b/src/hashtable.c
new file mode 100644
index 000000000000..c256addd307c
--- /dev/null
+++ b/src/hashtable.c
@@ -0,0 +1,132 @@
+/* Hash table for checking keyword links. Implemented using double hashing.
+ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "hashtable.h"
+#include "options.h"
+
+#ifdef GATHER_STATISTICS
+/* Find out how well our double hashing is working! */
+static collisions = 0;
+#endif
+
+/* Locally visible hash table. */
+static HASH_TABLE hash_table;
+
+/* Basically the algorithm from the Dragon book. */
+
+static unsigned
+hash_pjw (str)
+ char *str;
+{
+ char *temp;
+ unsigned g, h = 0;
+
+ for (temp = str; *temp; temp++)
+ {
+ h = (h << 4) + (*temp * 13);
+ if (g = h & 0xf0000000)
+ {
+ h ^= (g >> 24);
+ h ^= g;
+ }
+ }
+
+ return h;
+}
+
+/* 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! */
+
+void
+hash_table_init (table, s)
+ LIST_NODE **table;
+ int s;
+{
+ hash_table.size = s;
+ hash_table.table = table;
+ bzero ((char *) hash_table.table, hash_table.size * sizeof *hash_table.table);
+}
+
+/* Frees the dynamically allocated table. Note that since we don't
+ really need this space anymore, and since it is potentially quite
+ big it is best to return it when we are done. */
+
+void
+hash_table_destroy ()
+{
+ if (OPTION_ENABLED (option, DEBUG))
+ {
+ int i;
+
+ fprintf (stderr, "\ndumping the hash table\ntotal elements = %d, bytes = %d\n",
+ hash_table.size, hash_table.size * sizeof *hash_table.table);
+
+ for (i = hash_table.size - 1; i >= 0; i--)
+ if (hash_table.table[i])
+ fprintf (stderr, "location[%d] has charset \"%s\" and keyword \"%s\"\n",
+ i, hash_table.table[i]->char_set, hash_table.table[i]->key);
+
+#ifdef GATHER_STATISTICS
+ fprintf (stderr, "\ntotal collisions during hashing = %d\n", collisions);
+#endif
+ fprintf (stderr, "end 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 *
+retrieve (item, ignore_length)
+ LIST_NODE *item;
+ int ignore_length;
+{
+ unsigned hash_val = hash_pjw (item->char_set);
+ int probe = hash_val & hash_table.size - 1;
+ int increment = (hash_val ^ item->length | 1) & hash_table.size - 1;
+
+ while (hash_table.table[probe]
+ && (strcmp (hash_table.table[probe]->char_set, item->char_set)
+ || (!ignore_length && hash_table.table[probe]->length != item->length)))
+ {
+#ifdef GATHER_STATISTICS
+ collisions++;
+#endif
+ probe = probe + increment & hash_table.size - 1;
+ }
+
+ if (hash_table.table[probe])
+ return hash_table.table[probe];
+ else
+ {
+ hash_table.table[probe] = item;
+ return 0;
+ }
+}
+
+
diff --git a/src/hashtable.h b/src/hashtable.h
new file mode 100644
index 000000000000..218e9874a1d1
--- /dev/null
+++ b/src/hashtable.h
@@ -0,0 +1,37 @@
+/* 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _hashtable_h
+#define _hashtable_h
+#include "keylist.h"
+#include "prototype.h"
+
+typedef struct hash_table
+{
+ LIST_NODE **table; /* Vector of pointers to linked lists of List_Node's. */
+ int size; /* Size of the vector. */
+} HASH_TABLE;
+
+extern void hash_table_init P ((LIST_NODE **table, int size));
+extern void hash_table_destroy P ((void));
+extern LIST_NODE *retrieve P ((LIST_NODE *item, int ignore_length));
+
+#endif /* _hashtable_h */
diff --git a/src/iterator.c b/src/iterator.c
new file mode 100644
index 000000000000..b5930f089bb2
--- /dev/null
+++ b/src/iterator.c
@@ -0,0 +1,106 @@
+/* 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "iterator.h"
+
+/* Locally visible ITERATOR object. */
+
+ITERATOR iterator;
+
+/* Constructor for ITERATOR. */
+
+void
+iterator_init (s, lo, hi, word_end, bad_val, key_end)
+ char *s;
+ int lo;
+ int hi;
+ int word_end;
+ int bad_val;
+ int key_end;
+{
+ iterator.end = key_end;
+ iterator.error_value = bad_val;
+ iterator.end_word = word_end;
+ iterator.str = s;
+ iterator.hi_bound = hi;
+ iterator.lo_bound = lo;
+}
+
+/* Define several useful macros to clarify subsequent code. */
+#define ISPOSDIGIT(X) ((X)<='9'&&(X)>'0')
+#define TODIGIT(X) ((X)-'0')
+
+/* Provide an Iterator, returning the ``next'' value from
+ the list of valid values given in the constructor. */
+
+int
+next ()
+{
+/* 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 (*iterator.str)
+ {
+ if (*iterator.str == ',')
+ iterator.str++;
+ else if (*iterator.str == '$')
+ {
+ iterator.str++;
+ return iterator.end_word;
+ }
+ else if (ISPOSDIGIT (*iterator.str))
+ {
+
+ for (curr_value = 0; isdigit (*iterator.str); iterator.str++)
+ curr_value = curr_value * 10 + *iterator.str - '0';
+
+ if (*iterator.str == '-')
+ {
+
+ for (size = 1, upper_bound = 0;
+ isdigit (*++iterator.str);
+ upper_bound = upper_bound * 10 + *iterator.str - '0');
+
+ if (upper_bound <= curr_value || upper_bound > iterator.hi_bound)
+ return iterator.error_value;
+ }
+ return curr_value >= iterator.lo_bound && curr_value <= iterator.hi_bound
+ ? curr_value : iterator.error_value;
+ }
+ else
+ return iterator.error_value;
+ }
+
+ return iterator.end;
+ }
+}
diff --git a/src/iterator.cc b/src/iterator.cc
new file mode 100644
index 000000000000..ca66bbb8aca4
--- /dev/null
+++ b/src/iterator.cc
@@ -0,0 +1,87 @@
+/* Provides an Iterator for keyword characters.
+ Copyright (C) 1989-1998, 2000 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"
+
+#include <ctype.h>
+#include "trace.h"
+
+/* Constructor for Iterator. */
+
+Iterator::Iterator (const char *s, int lo, int hi, int word_end, int bad_val, int key_end)
+{
+ T (Trace t ("Iterator::Iterator");)
+ 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)
+{
+ T (Trace t ("Iterator::operator()");)
+/* 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 ((unsigned char)(*str)); str++)
+ curr_value = curr_value * 10 + (*str - '0');
+
+ if (*str == '-')
+ {
+
+ for (size = 1, upper_bound = 0;
+ isdigit ((unsigned char)(*++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/src/iterator.h b/src/iterator.h
new file mode 100644
index 000000000000..d5138ab99447
--- /dev/null
+++ b/src/iterator.h
@@ -0,0 +1,51 @@
+/* This may look like C code, but it is really -*- C++ -*- */
+
+/* Provides an Iterator for keyword characters.
+
+ Copyright (C) 1989-1998 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
+
+class Iterator
+{
+private:
+ const 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. */
+
+public:
+ Iterator (const char *s, int lo, int hi, int word_end, int bad_val, int key_end);
+ int operator () (void);
+};
+
+#endif
diff --git a/src/key-list.cc b/src/key-list.cc
new file mode 100644
index 000000000000..1c941a453579
--- /dev/null
+++ b/src/key-list.cc
@@ -0,0 +1,2184 @@
+/* Routines for building, ordering, and printing the keyword list.
+ Copyright (C) 1989-1998, 2000 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 <stdio.h>
+#include <string.h> /* declares strncpy(), strchr() */
+#include <stdlib.h> /* declares malloc(), free(), abs(), exit(), abort() */
+#include <ctype.h> /* declares isprint() */
+#include <assert.h> /* defines assert() */
+#include <limits.h> /* defines SCHAR_MAX etc. */
+#include "options.h"
+#include "read-line.h"
+#include "hash-table.h"
+#include "key-list.h"
+#include "trace.h"
+#include "version.h"
+
+/* Make the hash table 8 times larger than the number of keyword entries. */
+static const int TABLE_MULTIPLE = 10;
+
+/* Efficiently returns the least power of two greater than or equal to X! */
+#define POW(X) ((!X)?1:(X-=1,X|=X>>1,X|=X>>2,X|=X>>4,X|=X>>8,X|=X>>16,(++X)))
+
+int Key_List::determined[MAX_ALPHA_SIZE];
+
+/* Destructor dumps diagnostics during debugging. */
+
+Key_List::~Key_List (void)
+{
+ T (Trace t ("Key_List::~Key_List");)
+ 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, max_key_len);
+ dump ();
+ fprintf (stderr, "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. */
+
+const char *
+Key_List::get_special_input (char delimiter)
+{
+ T (Trace t ("Key_List::get_special_input");)
+ 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. */
+
+const char *
+Key_List::save_include_src (void)
+{
+ T (Trace t ("Key_List::save_include_src");)
+ int c;
+
+ if ((c = getchar ()) != '%')
+ ungetc (c, stdin);
+ else if ((c = getchar ()) != '{')
+ {
+ fprintf (stderr, "internal error, %c != '{' on line %d in file %s", c, __LINE__, __FILE__);
+ exit (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. */
+
+const char *
+Key_List::get_array_type (void)
+{
+ T (Trace t ("Key_List::get_array_type");)
+ return get_special_input ('%');
+}
+
+/* strcspn - find length of initial segment of S consisting entirely
+ of characters not from REJECT (borrowed from Henry Spencer's
+ ANSI string package, when GNU libc comes out I'll replace this...). */
+
+#ifndef strcspn
+inline int
+Key_List::strcspn (const char *s, const char *reject)
+{
+ T (Trace t ("Key_List::strcspn");)
+ 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;
+}
+#endif
+
+/* 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)
+{
+ T (Trace t ("Key_List::set_output_types");)
+ if (option[TYPE])
+ {
+ array_type = get_array_type ();
+ if (!array_type)
+ /* Something's wrong, but we'll catch it later on, in read_keys()... */
+ return;
+ /* Yow, we've got a user-defined type... */
+ int i = strcspn (array_type, "{\n\0");
+ /* Remove trailing whitespace. */
+ while (i > 0 && strchr (" \t", array_type[i-1]))
+ i--;
+ int struct_tag_length = i;
+
+ /* Set `struct_tag' to a naked "struct something". */
+ char *structtag = new char[struct_tag_length + 1];
+ strncpy (structtag, array_type, struct_tag_length);
+ structtag[struct_tag_length] = '\0';
+ struct_tag = structtag;
+
+ /* The return type of the lookup function is "struct something *".
+ No "const" here, because if !option[CONST], some user code might want
+ to modify the structure. */
+ char *rettype = new char[struct_tag_length + 3];
+ strncpy (rettype, array_type, struct_tag_length);
+ rettype[struct_tag_length] = ' ';
+ rettype[struct_tag_length + 1] = '*';
+ rettype[struct_tag_length + 2] = '\0';
+ return_type = rettype;
+ }
+}
+
+/* Extracts a key from an input line and creates a new List_Node for it. */
+
+static List_Node *
+parse_line (const char *line, const char *delimiters)
+{
+ if (*line == '"')
+ {
+ /* Parse a string in ANSI C syntax. */
+ char *key = new char[strlen(line)];
+ char *kp = key;
+ const char *lp = line + 1;
+
+ for (; *lp;)
+ {
+ char c = *lp;
+
+ if (c == '\0')
+ {
+ fprintf (stderr, "unterminated string: %s\n", line);
+ exit (1);
+ }
+ else if (c == '\\')
+ {
+ c = *++lp;
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ {
+ int code = 0;
+ int count = 0;
+ while (count < 3 && *lp >= '0' && *lp <= '7')
+ {
+ code = (code << 3) + (*lp - '0');
+ lp++;
+ count++;
+ }
+ if (code > UCHAR_MAX)
+ fprintf (stderr, "octal escape out of range: %s\n", line);
+ *kp = (char) code;
+ break;
+ }
+ case 'x':
+ {
+ int code = 0;
+ int count = 0;
+ lp++;
+ while ((*lp >= '0' && *lp <= '9')
+ || (*lp >= 'A' && *lp <= 'F')
+ || (*lp >= 'a' && *lp <= 'f'))
+ {
+ code = (code << 4)
+ + (*lp >= 'A' && *lp <= 'F' ? *lp - 'A' + 10 :
+ *lp >= 'a' && *lp <= 'f' ? *lp - 'a' + 10 :
+ *lp - '0');
+ lp++;
+ count++;
+ }
+ if (count == 0)
+ fprintf (stderr, "hexadecimal escape without any hex digits: %s\n", line);
+ if (code > UCHAR_MAX)
+ fprintf (stderr, "hexadecimal escape out of range: %s\n", line);
+ *kp = (char) code;
+ break;
+ }
+ case '\\': case '\'': case '"':
+ *kp = c;
+ lp++;
+ break;
+ case 'n':
+ *kp = '\n';
+ lp++;
+ break;
+ case 't':
+ *kp = '\t';
+ lp++;
+ break;
+ case 'r':
+ *kp = '\r';
+ lp++;
+ break;
+ case 'f':
+ *kp = '\f';
+ lp++;
+ break;
+ case 'b':
+ *kp = '\b';
+ lp++;
+ break;
+ case 'a':
+ *kp = '\a';
+ lp++;
+ break;
+ case 'v':
+ *kp = '\v';
+ lp++;
+ break;
+ default:
+ fprintf (stderr, "invalid escape sequence in string: %s\n", line);
+ exit (1);
+ }
+ }
+ else if (c == '"')
+ break;
+ else
+ {
+ *kp = c;
+ lp++;
+ }
+ kp++;
+ }
+ lp++;
+ if (*lp != '\0')
+ {
+ if (strchr (delimiters, *lp) == NULL)
+ {
+ fprintf (stderr, "string not followed by delimiter: %s\n", line);
+ exit (1);
+ }
+ lp++;
+ }
+ return new List_Node (key, kp - key, option[TYPE] ? lp : "");
+ }
+ else
+ {
+ /* Not a string. Look for the delimiter. */
+ int len = strcspn (line, delimiters);
+ const char *rest;
+
+ if (line[len] == '\0')
+ rest = "";
+ else
+ /* Skip the first delimiter. */
+ rest = &line[len + 1];
+ return new List_Node (line, len, option[TYPE] ? rest : "");
+ }
+}
+
+/* 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)
+{
+ T (Trace t ("Key_List::read_keys");)
+ char *ptr;
+
+ include_src = save_include_src ();
+ set_output_types ();
+
+ /* Oops, problem with the input file. */
+ if (! (ptr = Read_Line::get_line ()))
+ {
+ fprintf (stderr, "No words in input file, did you forget to prepend %s or use -t accidentally?\n", "%%");
+ exit (1);
+ }
+
+ /* Read in all the keywords from the input file. */
+ else
+ {
+ const char *delimiter = option.get_delimiter ();
+ List_Node *temp, *trail = 0;
+
+ head = parse_line (ptr, delimiter);
+
+ for (temp = head;
+ (ptr = Read_Line::get_line ()) && strcmp (ptr, "%%");
+ temp = temp->next)
+ {
+ temp->next = parse_line (ptr, delimiter);
+ total_keys++;
+ }
+
+ /* See if any additional C 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[POW (table_size)];
+#else
+ // Note: we don't use new, because that invokes a custom operator new.
+ int malloc_size = 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, option[NOLENGTH]);
+
+ /* 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.insert (temp);
+
+ /* 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])
+ fprintf (stderr, "Key link: \"%.*s\" = \"%.*s\", with key set \"%.*s\".\n",
+ temp->key_length, temp->key,
+ ptr->key_length, ptr->key,
+ temp->char_set_length, temp->char_set);
+ }
+ else
+ trail = temp;
+
+ /* Update minimum and maximum keyword length, if needed. */
+ if (max_key_len < temp->key_length)
+ max_key_len = temp->key_length;
+ if (min_key_len > temp->key_length)
+ min_key_len = temp->key_length;
+ }
+
+#if !LARGE_STACK_ARRAYS
+ free ((char *) table);
+#endif
+
+ /* Exit program if links exists and option[DUP] not set, since we can't continue */
+ if (total_duplicates)
+ {
+ if (option[DUP])
+ fprintf (stderr, "%d input keys have identical hash values, examine output carefully...\n",
+ total_duplicates);
+ else
+ {
+ fprintf (stderr, "%d input keys have identical hash values,\ntry different key positions or use option -D.\n",
+ total_duplicates);
+ exit (1);
+ }
+ }
+ /* Exit program if an empty string is used as key, since the comparison
+ expressions don't work correctly for looking up an empty string. */
+ if (min_key_len == 0)
+ {
+ fprintf (stderr, "Empty input key is not allowed.\nTo recognize an empty input key, your code should check for\nlen == 0 before calling the gperf generated lookup function.\n");
+ exit (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)
+{
+ T (Trace t ("Key_List::merge");)
+ List_Node *result;
+ List_Node **resultp = &result;
+ for (;;)
+ {
+ if (!list1)
+ {
+ *resultp = list2;
+ break;
+ }
+ if (!list2)
+ {
+ *resultp = list1;
+ break;
+ }
+ if (occurrence_sort && list1->occurrence < list2->occurrence
+ || hash_sort && list1->hash_value > list2->hash_value)
+ {
+ *resultp = list2;
+ resultp = &list2->next; list2 = list1; list1 = *resultp;
+ }
+ else
+ {
+ *resultp = list1;
+ resultp = &list1->next; list1 = *resultp;
+ }
+ }
+ return result;
+}
+
+/* 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 *head)
+{
+ T (Trace t ("Key_List::merge_sort");)
+ if (!head || !head->next)
+ return head;
+ else
+ {
+ List_Node *middle = head;
+ List_Node *temp = 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 (head), merge_sort (temp));
+ }
+}
+
+/* Returns the frequency of occurrence of elements in the key set. */
+
+inline int
+Key_List::get_occurrence (List_Node *ptr)
+{
+ T (Trace t ("Key_List::get_occurrence");)
+ int value = 0;
+
+ const char *p = ptr->char_set;
+ unsigned int i = ptr->char_set_length;
+ for (; i > 0; p++, i--)
+ value += occurrences[(unsigned char)(*p)];
+
+ return value;
+}
+
+/* Enables the index location of all key set elements that are now
+ determined. */
+
+inline void
+Key_List::set_determined (List_Node *ptr)
+{
+ T (Trace t ("Key_List::set_determined");)
+
+ const char *p = ptr->char_set;
+ unsigned int i = ptr->char_set_length;
+ for (; i > 0; p++, i--)
+ determined[(unsigned char)(*p)] = 1;
+}
+
+/* Returns TRUE if PTR's key set is already completely determined. */
+
+inline int
+Key_List::already_determined (List_Node *ptr)
+{
+ T (Trace t ("Key_List::already_determined");)
+ int is_determined = 1;
+
+ const char *p = ptr->char_set;
+ unsigned int i = ptr->char_set_length;
+ for (; is_determined && i > 0; p++, i--)
+ is_determined = determined[(unsigned char)(*p)];
+
+ 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)
+{
+ T (Trace t ("Key_List::reorder");)
+ List_Node *ptr;
+ for (ptr = head; ptr; ptr = ptr->next)
+ ptr->occurrence = get_occurrence (ptr);
+
+ hash_sort = 0;
+ occurrence_sort = 1;
+
+ 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;
+ }
+ }
+ }
+}
+
+/* ============================ Output routines ============================ */
+
+/* The "const " qualifier. */
+static const char *const_always;
+
+/* The "const " qualifier, for read-only arrays. */
+static const char *const_readonly_array;
+
+/* The "const " qualifier, for the array type. */
+static const char *const_for_struct;
+
+/* Returns the smallest unsigned C type capable of holding integers up to N. */
+
+static const char *
+smallest_integral_type (int n)
+{
+ if (n <= UCHAR_MAX) return "unsigned char";
+ if (n <= USHRT_MAX) return "unsigned short";
+ return "unsigned int";
+}
+
+/* Returns the smallest signed C type capable of holding integers
+ from MIN to MAX. */
+
+static const char *
+smallest_integral_type (int min, int max)
+{
+ if (option[ANSIC] | option[CPLUSPLUS])
+ if (min >= SCHAR_MIN && max <= SCHAR_MAX) return "signed char";
+ if (min >= SHRT_MIN && max <= SHRT_MAX) return "short";
+ return "int";
+}
+
+/* A cast from `char' to a valid array index. */
+static const char *char_to_index;
+
+/* ------------------------------------------------------------------------- */
+
+/* Computes 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::compute_min_max (void)
+{
+ T (Trace t ("Key_List::compute_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;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Returns the number of different hash values. */
+
+int
+Key_List::num_hash_values (void)
+{
+ T (Trace t ("Key_List::num_hash_values");)
+ int count = 1;
+ List_Node *temp;
+ int value;
+
+ for (temp = head, value = temp->hash_value; temp->next; )
+ {
+ temp = temp->next;
+ if (value != temp->hash_value)
+ {
+ value = temp->hash_value;
+ count++;
+ }
+ }
+ return count;
+}
+
+/* -------------------- Output_Constants and subclasses -------------------- */
+
+/* This class outputs an enumeration defining some constants. */
+
+struct Output_Constants
+{
+ virtual void output_start () = 0;
+ virtual void output_item (const char *name, int value) = 0;
+ virtual void output_end () = 0;
+ Output_Constants () {}
+ virtual ~Output_Constants () {}
+};
+
+/* This class outputs an enumeration in #define syntax. */
+
+struct Output_Defines : public Output_Constants
+{
+ virtual void output_start ();
+ virtual void output_item (const char *name, int value);
+ virtual void output_end ();
+ Output_Defines () {}
+ virtual ~Output_Defines () {}
+};
+
+void Output_Defines::output_start ()
+{
+ T (Trace t ("Output_Defines::output_start");)
+ printf ("\n");
+}
+
+void Output_Defines::output_item (const char *name, int value)
+{
+ T (Trace t ("Output_Defines::output_item");)
+ printf ("#define %s %d\n", name, value);
+}
+
+void Output_Defines::output_end ()
+{
+ T (Trace t ("Output_Defines::output_end");)
+}
+
+/* This class outputs an enumeration using `enum'. */
+
+struct Output_Enum : public Output_Constants
+{
+ virtual void output_start ();
+ virtual void output_item (const char *name, int value);
+ virtual void output_end ();
+ Output_Enum (const char *indent) : indentation (indent) {}
+ virtual ~Output_Enum () {}
+private:
+ const char *indentation;
+ int pending_comma;
+};
+
+void Output_Enum::output_start ()
+{
+ T (Trace t ("Output_Enum::output_start");)
+ printf ("%senum\n"
+ "%s {\n",
+ indentation, indentation);
+ pending_comma = 0;
+}
+
+void Output_Enum::output_item (const char *name, int value)
+{
+ T (Trace t ("Output_Enum::output_item");)
+ if (pending_comma)
+ printf (",\n");
+ printf ("%s %s = %d", indentation, name, value);
+ pending_comma = 1;
+}
+
+void Output_Enum::output_end ()
+{
+ T (Trace t ("Output_Enum::output_end");)
+ if (pending_comma)
+ printf ("\n");
+ printf ("%s };\n\n", indentation);
+}
+
+/* Outputs the maximum and minimum hash values etc. */
+
+void
+Key_List::output_constants (struct Output_Constants& style)
+{
+ T (Trace t ("Key_List::output_constants");)
+
+ style.output_start ();
+ style.output_item ("TOTAL_KEYWORDS", total_keys);
+ style.output_item ("MIN_WORD_LENGTH", min_key_len);
+ style.output_item ("MAX_WORD_LENGTH", max_key_len);
+ style.output_item ("MIN_HASH_VALUE", min_hash_value);
+ style.output_item ("MAX_HASH_VALUE", max_hash_value);
+ style.output_end ();
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Outputs a keyword, as a string: enclosed in double quotes, escaping
+ backslashes, double quote and unprintable characters. */
+
+static void
+output_string (const char *key, int len)
+{
+ T (Trace t ("output_string");)
+
+ putchar ('"');
+ for (; len > 0; len--)
+ {
+ unsigned char c = (unsigned char) *key++;
+ if (isprint (c))
+ {
+ if (c == '"' || c == '\\')
+ putchar ('\\');
+ putchar (c);
+ }
+ else
+ {
+ /* Use octal escapes, not hexadecimal escapes, because some old
+ C compilers didn't understand hexadecimal escapes, and because
+ hexadecimal escapes are not limited to 2 digits, thus needing
+ special care if the following character happens to be a digit. */
+ putchar ('\\');
+ putchar ('0' + ((c >> 6) & 7));
+ putchar ('0' + ((c >> 3) & 7));
+ putchar ('0' + (c & 7));
+ }
+ }
+ putchar ('"');
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Outputs a type and a const specifier.
+ The output is terminated with a space. */
+
+static void
+output_const_type (const char *const_string, const char *type_string)
+{
+ if (type_string[strlen(type_string)-1] == '*')
+ printf ("%s %s", type_string, const_string);
+ else
+ printf ("%s%s ", const_string, type_string);
+}
+
+/* ----------------------- Output_Expr and subclasses ----------------------- */
+
+/* This class outputs a general expression. */
+
+struct Output_Expr
+{
+ virtual void output_expr () const = 0;
+ Output_Expr () {}
+ virtual ~Output_Expr () {}
+};
+
+/* This class outputs an expression formed by a single string. */
+
+struct Output_Expr1 : public Output_Expr
+{
+ virtual void output_expr () const;
+ Output_Expr1 (const char *piece1) : p1 (piece1) {}
+ virtual ~Output_Expr1 () {}
+private:
+ const char *p1;
+};
+
+void Output_Expr1::output_expr () const
+{
+ T (Trace t ("Output_Expr1::output_expr");)
+ printf ("%s", p1);
+}
+
+#if 0 /* unused */
+
+/* This class outputs an expression formed by the concatenation of two
+ strings. */
+
+struct Output_Expr2 : public Output_Expr
+{
+ virtual void output_expr () const;
+ Output_Expr2 (const char *piece1, const char *piece2)
+ : p1 (piece1), p2 (piece2) {}
+ virtual ~Output_Expr2 () {}
+private:
+ const char *p1;
+ const char *p2;
+};
+
+void Output_Expr2::output_expr () const
+{
+ T (Trace t ("Output_Expr2::output_expr");)
+ printf ("%s%s", p1, p2);
+}
+
+#endif
+
+/* --------------------- Output_Compare and subclasses --------------------- */
+
+/* This class outputs a comparison expression. */
+
+struct Output_Compare
+{
+ virtual void output_comparison (const Output_Expr& expr1,
+ const Output_Expr& expr2) const = 0;
+ Output_Compare () {}
+ virtual ~Output_Compare () {}
+};
+
+/* This class outputs a comparison using strcmp. */
+
+struct Output_Compare_Strcmp : public Output_Compare
+{
+ virtual void output_comparison (const Output_Expr& expr1,
+ const Output_Expr& expr2) const;
+ Output_Compare_Strcmp () {}
+ virtual ~Output_Compare_Strcmp () {}
+};
+
+void Output_Compare_Strcmp::output_comparison (const Output_Expr& expr1,
+ const Output_Expr& expr2) const
+{
+ T (Trace t ("Output_Compare_Strcmp::output_comparison");)
+ printf ("*");
+ expr1.output_expr ();
+ printf (" == *");
+ expr2.output_expr ();
+ printf (" && !strcmp (");
+ expr1.output_expr ();
+ printf (" + 1, ");
+ expr2.output_expr ();
+ printf (" + 1)");
+}
+
+/* This class outputs a comparison using strncmp.
+ Note that the length of expr1 will be available through the local variable
+ `len'. */
+
+struct Output_Compare_Strncmp : public Output_Compare
+{
+ virtual void output_comparison (const Output_Expr& expr1,
+ const Output_Expr& expr2) const;
+ Output_Compare_Strncmp () {}
+ virtual ~Output_Compare_Strncmp () {}
+};
+
+void Output_Compare_Strncmp::output_comparison (const Output_Expr& expr1,
+ const Output_Expr& expr2) const
+{
+ T (Trace t ("Output_Compare_Strncmp::output_comparison");)
+ printf ("*");
+ expr1.output_expr ();
+ printf (" == *");
+ expr2.output_expr ();
+ printf (" && !strncmp (");
+ expr1.output_expr ();
+ printf (" + 1, ");
+ expr2.output_expr ();
+ printf (" + 1, len - 1) && ");
+ expr2.output_expr ();
+ printf ("[len] == '\\0'");
+}
+
+/* This class outputs a comparison using memcmp.
+ Note that the length of expr1 (available through the local variable `len')
+ must be verified to be equal to the length of expr2 prior to this
+ comparison. */
+
+struct Output_Compare_Memcmp : public Output_Compare
+{
+ virtual void output_comparison (const Output_Expr& expr1,
+ const Output_Expr& expr2) const;
+ Output_Compare_Memcmp () {}
+ virtual ~Output_Compare_Memcmp () {}
+};
+
+void Output_Compare_Memcmp::output_comparison (const Output_Expr& expr1,
+ const Output_Expr& expr2) const
+{
+ T (Trace t ("Output_Compare_Memcmp::output_comparison");)
+ printf ("*");
+ expr1.output_expr ();
+ printf (" == *");
+ expr2.output_expr ();
+ printf (" && !memcmp (");
+ expr1.output_expr ();
+ printf (" + 1, ");
+ expr2.output_expr ();
+ printf (" + 1, len - 1)");
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Generates C code for the hash function that returns the
+ proper encoding for each key word. */
+
+void
+Key_List::output_hash_function (void)
+{
+ T (Trace t ("Key_List::output_hash_function");)
+ const int max_column = 10;
+ int field_width;
+
+ /* Calculate maximum number of digits required for MAX_HASH_VALUE. */
+ field_width = 2;
+ for (int trunc = max_hash_value; (trunc /= 10) > 0;)
+ field_width++;
+
+ /* Output the function's head. */
+ if (option[CPLUSPLUS])
+ printf ("inline ");
+ else if (option[KRC] | option[C] | option[ANSIC])
+ printf ("#ifdef __GNUC__\n"
+ "__inline\n"
+ "#else\n"
+ "#ifdef __cplusplus\n"
+ "inline\n"
+ "#endif\n"
+ "#endif\n");
+
+ if (option[KRC] | option[C] | option[ANSIC])
+ printf ("static ");
+ printf ("unsigned int\n");
+ if (option[CPLUSPLUS])
+ printf ("%s::", option.get_class_name ());
+ printf ("%s ", option.get_hash_name ());
+ printf (option[KRC] ?
+ "(str, len)\n"
+ " register char *str;\n"
+ " register unsigned int len;\n" :
+ option[C] ?
+ "(str, len)\n"
+ " register const char *str;\n"
+ " register unsigned int len;\n" :
+ option[ANSIC] | option[CPLUSPLUS] ?
+ "(register const char *str, register unsigned int len)\n" :
+ "");
+
+ /* Note that when the hash function is called, it has already been verified
+ that min_key_len <= len <= max_key_len. */
+
+ /* Output the function's body. */
+ printf ("{\n");
+
+ /* First the asso_values array. */
+ printf (" static %s%s asso_values[] =\n"
+ " {",
+ const_readonly_array,
+ smallest_integral_type (max_hash_value + 1));
+
+ for (int count = 0; count < ALPHA_SIZE; count++)
+ {
+ if (count > 0)
+ printf (",");
+ if (!(count % max_column))
+ printf ("\n ");
+ printf ("%*d", field_width,
+ occurrences[count] ? asso_values[count] : max_hash_value + 1);
+ }
+
+ printf ("\n"
+ " };\n");
+
+ /* Optimize special case of ``-k 1,$'' */
+ if (option[DEFAULTCHARS])
+ printf (" return %sasso_values[%sstr[len - 1]] + asso_values[%sstr[0]];\n",
+ option[NOLENGTH] ? "" : "len + ",
+ char_to_index, char_to_index);
+ else
+ {
+ int key_pos;
+
+ option.reset ();
+
+ /* Get first (also highest) key position. */
+ key_pos = option.get ();
+
+ if (!option[ALLCHARS] && (key_pos == WORD_END || key_pos <= min_key_len))
+ {
+ /* We can perform additional optimizations here:
+ Write it out as a single expression. Note that the values
+ are added as `int's even though the asso_values array may
+ contain `unsigned char's or `unsigned short's. */
+
+ printf (" return %s",
+ option[NOLENGTH] ? "" : "len + ");
+
+ for (; key_pos != WORD_END; )
+ {
+ printf ("asso_values[%sstr[%d]]", char_to_index, key_pos - 1);
+ if ((key_pos = option.get ()) != EOS)
+ printf (" + ");
+ else
+ break;
+ }
+
+ if (key_pos == WORD_END)
+ printf ("asso_values[%sstr[len - 1]]", char_to_index);
+
+ printf (";\n");
+ }
+ else
+ {
+ /* We've got to use the correct, but brute force, technique. */
+ printf (" 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])
+ {
+ for (int i = max_key_len; i > 0; i--)
+ printf (" case %d:\n"
+ " hval += asso_values[%sstr[%d]];\n",
+ i, char_to_index, i - 1);
+
+ printf (" break;\n"
+ " }\n"
+ " return hval;\n");
+ }
+ else /* do the hard part... */
+ {
+ while (key_pos != WORD_END && key_pos > max_key_len)
+ if ((key_pos = option.get ()) == EOS)
+ break;
+
+ if (key_pos != EOS && key_pos != WORD_END)
+ {
+ int i = key_pos;
+ do
+ {
+ for ( ; i >= key_pos; i--)
+ printf (" case %d:\n", i);
+
+ printf (" hval += asso_values[%sstr[%d]];\n",
+ char_to_index, key_pos - 1);
+
+ key_pos = option.get ();
+ }
+ while (key_pos != EOS && key_pos != WORD_END);
+
+ for ( ; i >= min_key_len; i--)
+ printf (" case %d:\n", i);
+ }
+
+ printf (" break;\n"
+ " }\n"
+ " return hval");
+ if (key_pos == WORD_END)
+ printf (" + asso_values[%sstr[len - 1]]", char_to_index);
+ printf (";\n");
+ }
+ }
+ }
+ printf ("}\n\n");
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* 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)
+{
+ T (Trace t ("Key_List::output_keylength_table");)
+ const int columns = 14;
+ int index;
+ int column;
+ const char *indent = option[GLOBAL] ? "" : " ";
+ List_Node *temp;
+
+ printf ("%sstatic %s%s lengthtable[] =\n%s {",
+ indent, const_readonly_array,
+ smallest_integral_type (max_key_len),
+ indent);
+
+ /* Generate an array of lengths, similar to output_keyword_table. */
+
+ column = 0;
+ for (temp = head, index = 0; temp; temp = temp->next)
+ {
+ if (option[SWITCH] && !option[TYPE]
+ && !(temp->link
+ || (temp->next && temp->hash_value == temp->next->hash_value)))
+ continue;
+
+ if (index < temp->hash_value && !option[SWITCH] && !option[DUP])
+ {
+ /* Some blank entries. */
+ for ( ; index < temp->hash_value; index++)
+ {
+ if (index > 0)
+ printf (",");
+ if ((column++ % columns) == 0)
+ printf ("\n%s ", indent);
+ printf ("%3d", 0);
+ }
+ }
+
+ if (index > 0)
+ printf (",");
+ if ((column++ % columns) == 0)
+ printf("\n%s ", indent);
+ printf ("%3d", temp->key_length);
+
+ /* Deal with links specially. */
+ if (temp->link) // implies option[DUP]
+ for (List_Node *links = temp->link; links; links = links->link)
+ {
+ ++index;
+ printf (",");
+ if ((column++ % columns) == 0)
+ printf("\n%s ", indent);
+ printf ("%3d", links->key_length);
+ }
+
+ index++;
+ }
+
+ printf ("\n%s };\n", indent);
+ if (option[GLOBAL])
+ printf ("\n");
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void
+output_keyword_entry (List_Node *temp, const char *indent)
+{
+ printf ("%s ", indent);
+ if (option[TYPE])
+ printf ("{");
+ output_string (temp->key, temp->key_length);
+ if (option[TYPE])
+ {
+ if (strlen (temp->rest) > 0)
+ printf (",%s", temp->rest);
+ printf ("}");
+ }
+ if (option[DEBUG])
+ printf (" /* hash value = %d, index = %d */",
+ temp->hash_value, temp->index);
+}
+
+static void
+output_keyword_blank_entries (int count, const char *indent)
+{
+ int columns;
+ if (option[TYPE])
+ {
+ columns = 58 / (6 + strlen (option.get_initializer_suffix()));
+ if (columns == 0)
+ columns = 1;
+ }
+ else
+ {
+ columns = 9;
+ }
+ int column = 0;
+ for (int i = 0; i < count; i++)
+ {
+ if ((column % columns) == 0)
+ {
+ if (i > 0)
+ printf (",\n");
+ printf ("%s ", indent);
+ }
+ else
+ {
+ if (i > 0)
+ printf (", ");
+ }
+ if (option[TYPE])
+ printf ("{\"\"%s}", option.get_initializer_suffix());
+ else
+ printf ("\"\"");
+ column++;
+ }
+}
+
+/* Prints out the array containing the key words for the hash function. */
+
+void
+Key_List::output_keyword_table (void)
+{
+ T (Trace t ("Key_List::output_keyword_table");)
+ const char *indent = option[GLOBAL] ? "" : " ";
+ int index;
+ List_Node *temp;
+
+ printf ("%sstatic ",
+ indent);
+ output_const_type (const_readonly_array, struct_tag);
+ printf ("%s[] =\n"
+ "%s {\n",
+ option.get_wordlist_name (),
+ indent);
+
+ /* Generate an array of reserved words at appropriate locations. */
+
+ for (temp = head, index = 0; temp; temp = temp->next)
+ {
+ if (option[SWITCH] && !option[TYPE]
+ && !(temp->link
+ || (temp->next && temp->hash_value == temp->next->hash_value)))
+ continue;
+
+ if (index > 0)
+ printf (",\n");
+
+ if (index < temp->hash_value && !option[SWITCH] && !option[DUP])
+ {
+ /* Some blank entries. */
+ output_keyword_blank_entries (temp->hash_value - index, indent);
+ printf (",\n");
+ index = temp->hash_value;
+ }
+
+ temp->index = index;
+
+ output_keyword_entry (temp, indent);
+
+ /* Deal with links specially. */
+ if (temp->link) // implies option[DUP]
+ for (List_Node *links = temp->link; links; links = links->link)
+ {
+ links->index = ++index;
+ printf (",\n");
+ output_keyword_entry (links, indent);
+ }
+
+ index++;
+ }
+ if (index > 0)
+ printf ("\n");
+
+ printf ("%s };\n\n", indent);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* 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)
+{
+ T (Trace t ("Key_List::output_lookup_array");)
+ if (option[DUP])
+ {
+ const int DEFAULT_VALUE = -1;
+
+ /* Because of the way output_keyword_table works, every duplicate set is
+ stored contiguously in the wordlist array. */
+ 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 + 2*total_duplicates];
+#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) + 1);
+ int *lookup_array = (int *)
+ malloc ((max_hash_value + 1 + 2*total_duplicates) * sizeof(int));
+ if (duplicates == NULL || lookup_array == NULL)
+ abort();
+#endif
+ int lookup_array_size = max_hash_value + 1;
+ duplicate_entry *dup_ptr = &duplicates[0];
+ int *lookup_ptr = &lookup_array[max_hash_value + 1 + 2*total_duplicates];
+
+ while (lookup_ptr > lookup_array)
+ *--lookup_ptr = DEFAULT_VALUE;
+
+ /* Now dup_ptr = &duplicates[0] and lookup_ptr = &lookup_array[0]. */
+
+ 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_length, temp->key, temp->index);
+ if (temp->link
+ || (temp->next && hash_value == temp->next->hash_value))
+ {
+ /* Start a duplicate entry. */
+ dup_ptr->hash_value = hash_value;
+ dup_ptr->index = temp->index;
+ dup_ptr->count = 1;
+
+ for (;;)
+ {
+ 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_length, ptr->key, ptr->index);
+ }
+
+ if (!(temp->next && hash_value == temp->next->hash_value))
+ break;
+
+ temp = temp->next;
+
+ dup_ptr->count++;
+ if (option[DEBUG])
+ fprintf (stderr, "dynamic linked keyword = %.*s, index = %d\n",
+ temp->key_length, temp->key, temp->index);
+ }
+ assert (dup_ptr->count >= 2);
+ dup_ptr++;
+ }
+ }
+
+ while (dup_ptr > duplicates)
+ {
+ dup_ptr--;
+
+ 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);
+
+ int i;
+ /* Start searching for available space towards the right part
+ of the lookup array. */
+ for (i = dup_ptr->hash_value; i < lookup_array_size-1; i++)
+ if (lookup_array[i] == DEFAULT_VALUE
+ && lookup_array[i + 1] == DEFAULT_VALUE)
+ goto found_i;
+ /* If we didn't find it to the right look to the left instead... */
+ for (i = dup_ptr->hash_value-1; i >= 0; i--)
+ if (lookup_array[i] == DEFAULT_VALUE
+ && lookup_array[i + 1] == DEFAULT_VALUE)
+ goto found_i;
+ /* Append to the end of lookup_array. */
+ i = lookup_array_size;
+ lookup_array_size += 2;
+ found_i:
+ /* Put in an indirection from dup_ptr->hash_value to i.
+ At i and i+1 store dup_ptr->index and dup_ptr->count. */
+ assert (lookup_array[dup_ptr->hash_value] == dup_ptr->index);
+ lookup_array[dup_ptr->hash_value] = - 1 - total_keys - i;
+ lookup_array[i] = - total_keys + dup_ptr->index;
+ lookup_array[i + 1] = - dup_ptr->count;
+ /* All these three values are <= -2, distinct from DEFAULT_VALUE. */
+ }
+
+ /* The values of the lookup array are now known. */
+
+ int min = INT_MAX;
+ int max = INT_MIN;
+ lookup_ptr = lookup_array + lookup_array_size;
+ while (lookup_ptr > lookup_array)
+ {
+ int val = *--lookup_ptr;
+ if (min > val)
+ min = val;
+ if (max < val)
+ max = val;
+ }
+
+ const char *indent = option[GLOBAL] ? "" : " ";
+ printf ("%sstatic %s%s lookup[] =\n"
+ "%s {",
+ indent, const_readonly_array, smallest_integral_type (min, max),
+ indent);
+
+ int field_width;
+ /* Calculate maximum number of digits required for MIN..MAX. */
+ {
+ field_width = 2;
+ for (int trunc = max; (trunc /= 10) > 0;)
+ field_width++;
+ }
+ if (min < 0)
+ {
+ int neg_field_width = 2;
+ for (int trunc = -min; (trunc /= 10) > 0;)
+ neg_field_width++;
+ neg_field_width++; /* account for the minus sign */
+ if (field_width < neg_field_width)
+ field_width = neg_field_width;
+ }
+
+ const int columns = 42 / field_width;
+ int column;
+
+ column = 0;
+ for (int i = 0; i < lookup_array_size; i++)
+ {
+ if (i > 0)
+ printf (",");
+ if ((column++ % columns) == 0)
+ printf("\n%s ", indent);
+ printf ("%*d", field_width, lookup_array[i]);
+ }
+ printf ("\n%s };\n\n", indent);
+
+#if !LARGE_STACK_ARRAYS
+ free ((char *) duplicates);
+ free ((char *) lookup_array);
+#endif
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Generate all the tables needed for the lookup function. */
+
+void
+Key_List::output_lookup_tables (void)
+{
+ T (Trace t ("Key_List::output_lookup_tables");)
+
+ if (option[SWITCH])
+ {
+ /* Use the switch in place of lookup table. */
+ if (option[LENTABLE] && (option[DUP] && total_duplicates > 0))
+ output_keylength_table ();
+ if (option[TYPE] || (option[DUP] && total_duplicates > 0))
+ output_keyword_table ();
+ }
+ else
+ {
+ /* Use the lookup table, in place of switch. */
+ if (option[LENTABLE])
+ output_keylength_table ();
+ output_keyword_table ();
+ output_lookup_array ();
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Output a single switch case (including duplicates). Advance list. */
+
+static List_Node *
+output_switch_case (List_Node *list, int indent, int *jumps_away)
+{
+ T (Trace t ("output_switch_case");)
+
+ if (option[DEBUG])
+ printf ("%*s/* hash value = %4d, keyword = \"%.*s\" */\n",
+ indent, "", list->hash_value, list->key_length, list->key);
+
+ if (option[DUP]
+ && (list->link
+ || (list->next && list->hash_value == list->next->hash_value)))
+ {
+ if (option[LENTABLE])
+ printf ("%*slengthptr = &lengthtable[%d];\n",
+ indent, "", list->index);
+ printf ("%*swordptr = &%s[%d];\n",
+ indent, "", option.get_wordlist_name (), list->index);
+
+ int count = 0;
+ for (List_Node *temp = list; ; temp = temp->next)
+ {
+ for (List_Node *links = temp; links; links = links->link)
+ count++;
+ if (!(temp->next && temp->hash_value == temp->next->hash_value))
+ break;
+ }
+
+ printf ("%*swordendptr = wordptr + %d;\n"
+ "%*sgoto multicompare;\n",
+ indent, "", count,
+ indent, "");
+ *jumps_away = 1;
+ }
+ else
+ {
+ if (option[LENTABLE])
+ {
+ printf ("%*sif (len == %d)\n"
+ "%*s {\n",
+ indent, "", list->key_length,
+ indent, "");
+ indent += 4;
+ }
+ printf ("%*sresword = ",
+ indent, "");
+ if (option[TYPE])
+ printf ("&%s[%d]", option.get_wordlist_name (), list->index);
+ else
+ output_string (list->key, list->key_length);
+ printf (";\n");
+ printf ("%*sgoto compare;\n",
+ indent, "");
+ if (option[LENTABLE])
+ {
+ indent -= 4;
+ printf ("%*s }\n",
+ indent, "");
+ }
+ else
+ *jumps_away = 1;
+ }
+
+ while (list->next && list->hash_value == list->next->hash_value)
+ list = list->next;
+ list = list->next;
+ return list;
+}
+
+/* Output a total of size cases, grouped into num_switches switch statements,
+ where 0 < num_switches <= size. */
+
+static void
+output_switches (List_Node *list, int num_switches, int size, int min_hash_value, int max_hash_value, int indent)
+{
+ T (Trace t ("output_switches");)
+
+ if (option[DEBUG])
+ printf ("%*s/* know %d <= key <= %d, contains %d cases */\n",
+ indent, "", min_hash_value, max_hash_value, size);
+
+ if (num_switches > 1)
+ {
+ int part1 = num_switches / 2;
+ int part2 = num_switches - part1;
+ int size1 = (int)((double)size / (double)num_switches * (double)part1 + 0.5);
+ int size2 = size - size1;
+
+ List_Node *temp = list;
+ for (int count = size1; count > 0; count--)
+ {
+ while (temp->hash_value == temp->next->hash_value)
+ temp = temp->next;
+ temp = temp->next;
+ }
+
+ printf ("%*sif (key < %d)\n"
+ "%*s {\n",
+ indent, "", temp->hash_value,
+ indent, "");
+
+ output_switches (list, part1, size1, min_hash_value, temp->hash_value-1, indent+4);
+
+ printf ("%*s }\n"
+ "%*selse\n"
+ "%*s {\n",
+ indent, "", indent, "", indent, "");
+
+ output_switches (temp, part2, size2, temp->hash_value, max_hash_value, indent+4);
+
+ printf ("%*s }\n",
+ indent, "");
+ }
+ else
+ {
+ /* Output a single switch. */
+ int lowest_case_value = list->hash_value;
+ if (size == 1)
+ {
+ int jumps_away = 0;
+ assert (min_hash_value <= lowest_case_value);
+ assert (lowest_case_value <= max_hash_value);
+ if (min_hash_value == max_hash_value)
+ output_switch_case (list, indent, &jumps_away);
+ else
+ {
+ printf ("%*sif (key == %d)\n"
+ "%*s {\n",
+ indent, "", lowest_case_value,
+ indent, "");
+ output_switch_case (list, indent+4, &jumps_away);
+ printf ("%*s }\n",
+ indent, "");
+ }
+ }
+ else
+ {
+ if (lowest_case_value == 0)
+ printf ("%*sswitch (key)\n", indent, "");
+ else
+ printf ("%*sswitch (key - %d)\n", indent, "", lowest_case_value);
+ printf ("%*s {\n",
+ indent, "");
+ for (; size > 0; size--)
+ {
+ int jumps_away = 0;
+ printf ("%*s case %d:\n",
+ indent, "", list->hash_value - lowest_case_value);
+ list = output_switch_case (list, indent+6, &jumps_away);
+ if (!jumps_away)
+ printf ("%*s break;\n",
+ indent, "");
+ }
+ printf ("%*s }\n",
+ indent, "");
+ }
+ }
+}
+
+/* Generates C code to perform the keyword lookup. */
+
+void
+Key_List::output_lookup_function_body (const Output_Compare& comparison)
+{
+ T (Trace t ("Key_List::output_lookup_function_body");)
+
+ printf (" if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n"
+ " {\n"
+ " register int key = %s (str, len);\n\n",
+ option.get_hash_name ());
+
+ if (option[SWITCH])
+ {
+ int switch_size = num_hash_values ();
+ int num_switches = option.get_total_switches ();
+ if (num_switches > switch_size)
+ num_switches = switch_size;
+
+ printf (" if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n"
+ " {\n");
+ if (option[DUP])
+ {
+ if (option[LENTABLE])
+ printf (" register %s%s *lengthptr;\n",
+ const_always, smallest_integral_type (max_key_len));
+ printf (" register ");
+ output_const_type (const_readonly_array, struct_tag);
+ printf ("*wordptr;\n");
+ printf (" register ");
+ output_const_type (const_readonly_array, struct_tag);
+ printf ("*wordendptr;\n");
+ }
+ if (option[TYPE])
+ {
+ printf (" register ");
+ output_const_type (const_readonly_array, struct_tag);
+ printf ("*resword;\n\n");
+ }
+ else
+ printf (" register %sresword;\n\n",
+ struct_tag);
+
+ output_switches (head, num_switches, switch_size, min_hash_value, max_hash_value, 10);
+
+ if (option[DUP])
+ {
+ int indent = 8;
+ printf ("%*s return 0;\n"
+ "%*smulticompare:\n"
+ "%*s while (wordptr < wordendptr)\n"
+ "%*s {\n",
+ indent, "", indent, "", indent, "", indent, "");
+ if (option[LENTABLE])
+ {
+ printf ("%*s if (len == *lengthptr)\n"
+ "%*s {\n",
+ indent, "", indent, "");
+ indent += 4;
+ }
+ printf ("%*s register %schar *s = ",
+ indent, "", const_always);
+ if (option[TYPE])
+ printf ("wordptr->%s", option.get_key_name ());
+ else
+ printf ("*wordptr");
+ printf (";\n\n"
+ "%*s if (",
+ indent, "");
+ comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
+ printf (")\n"
+ "%*s return %s;\n",
+ indent, "",
+ option[TYPE] ? "wordptr" : "s");
+ if (option[LENTABLE])
+ {
+ indent -= 4;
+ printf ("%*s }\n",
+ indent, "");
+ }
+ if (option[LENTABLE])
+ printf ("%*s lengthptr++;\n",
+ indent, "");
+ printf ("%*s wordptr++;\n"
+ "%*s }\n",
+ indent, "", indent, "");
+ }
+ printf (" return 0;\n"
+ " compare:\n");
+ if (option[TYPE])
+ {
+ printf (" {\n"
+ " register %schar *s = resword->%s;\n\n"
+ " if (",
+ const_always, option.get_key_name ());
+ comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
+ printf (")\n"
+ " return resword;\n"
+ " }\n");
+ }
+ else
+ {
+ printf (" if (");
+ comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("resword"));
+ printf (")\n"
+ " return resword;\n");
+ }
+ printf (" }\n");
+ }
+ else
+ {
+ printf (" if (key <= MAX_HASH_VALUE && key >= 0)\n");
+
+ if (option[DUP])
+ {
+ int indent = 8;
+ printf ("%*s{\n"
+ "%*s register int index = lookup[key];\n\n"
+ "%*s if (index >= 0)\n",
+ indent, "", indent, "", indent, "");
+ if (option[LENTABLE])
+ {
+ printf ("%*s {\n"
+ "%*s if (len == lengthtable[index])\n",
+ indent, "", indent, "");
+ indent += 4;
+ }
+ printf ("%*s {\n"
+ "%*s register %schar *s = %s[index]",
+ indent, "",
+ indent, "", const_always, option.get_wordlist_name ());
+ if (option[TYPE])
+ printf (".%s", option.get_key_name ());
+ printf (";\n\n"
+ "%*s if (",
+ indent, "");
+ comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
+ printf (")\n"
+ "%*s return ",
+ indent, "");
+ if (option[TYPE])
+ printf ("&%s[index]", option.get_wordlist_name ());
+ else
+ printf ("s");
+ printf (";\n"
+ "%*s }\n",
+ indent, "");
+ if (option[LENTABLE])
+ {
+ indent -= 4;
+ printf ("%*s }\n", indent, "");
+ }
+ if (total_duplicates > 0)
+ {
+ printf ("%*s else if (index < -TOTAL_KEYWORDS)\n"
+ "%*s {\n"
+ "%*s register int offset = - 1 - TOTAL_KEYWORDS - index;\n",
+ indent, "", indent, "", indent, "");
+ if (option[LENTABLE])
+ printf ("%*s register %s%s *lengthptr = &lengthtable[TOTAL_KEYWORDS + lookup[offset]];\n",
+ indent, "", const_always, smallest_integral_type (max_key_len));
+ printf ("%*s register ",
+ indent, "");
+ output_const_type (const_readonly_array, struct_tag);
+ printf ("*wordptr = &%s[TOTAL_KEYWORDS + lookup[offset]];\n",
+ option.get_wordlist_name ());
+ printf ("%*s register ",
+ indent, "");
+ output_const_type (const_readonly_array, struct_tag);
+ printf ("*wordendptr = wordptr + -lookup[offset + 1];\n\n");
+ printf ("%*s while (wordptr < wordendptr)\n"
+ "%*s {\n",
+ indent, "", indent, "");
+ if (option[LENTABLE])
+ {
+ printf ("%*s if (len == *lengthptr)\n"
+ "%*s {\n",
+ indent, "", indent, "");
+ indent += 4;
+ }
+ printf ("%*s register %schar *s = ",
+ indent, "", const_always);
+ if (option[TYPE])
+ printf ("wordptr->%s", option.get_key_name ());
+ else
+ printf ("*wordptr");
+ printf (";\n\n"
+ "%*s if (",
+ indent, "");
+ comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
+ printf (")\n"
+ "%*s return %s;\n",
+ indent, "",
+ option[TYPE] ? "wordptr" : "s");
+ if (option[LENTABLE])
+ {
+ indent -= 4;
+ printf ("%*s }\n",
+ indent, "");
+ }
+ if (option[LENTABLE])
+ printf ("%*s lengthptr++;\n",
+ indent, "");
+ printf ("%*s wordptr++;\n"
+ "%*s }\n"
+ "%*s }\n",
+ indent, "", indent, "", indent, "");
+ }
+ printf ("%*s}\n",
+ indent, "");
+ }
+ else
+ {
+ int indent = 8;
+ if (option[LENTABLE])
+ {
+ printf ("%*sif (len == lengthtable[key])\n",
+ indent, "");
+ indent += 2;
+ }
+
+ printf ("%*s{\n"
+ "%*s register %schar *s = %s[key]",
+ indent, "",
+ indent, "", const_always, option.get_wordlist_name ());
+
+ if (option[TYPE])
+ printf (".%s", option.get_key_name ());
+
+ printf (";\n\n"
+ "%*s if (",
+ indent, "");
+ comparison.output_comparison (Output_Expr1 ("str"), Output_Expr1 ("s"));
+ printf (")\n"
+ "%*s return ",
+ indent, "");
+ if (option[TYPE])
+ printf ("&%s[key]", option.get_wordlist_name ());
+ else
+ printf ("s");
+ printf (";\n"
+ "%*s}\n",
+ indent, "");
+ }
+ }
+ printf (" }\n"
+ " return 0;\n");
+}
+
+/* Generates C code for the lookup function. */
+
+void
+Key_List::output_lookup_function (void)
+{
+ T (Trace t ("Key_List::output_lookup_function");)
+
+ /* Output the function's head. */
+ if (option[KRC] | option[C] | option[ANSIC])
+ printf ("#ifdef __GNUC__\n"
+ "__inline\n"
+ "#endif\n");
+
+ printf ("%s%s\n",
+ const_for_struct, return_type);
+ if (option[CPLUSPLUS])
+ printf ("%s::", option.get_class_name ());
+ printf ("%s ", option.get_function_name ());
+ printf (option[KRC] ?
+ "(str, len)\n"
+ " register char *str;\n"
+ " register unsigned int len;\n" :
+ option[C] ?
+ "(str, len)\n"
+ " register const char *str;\n"
+ " register unsigned int len;\n" :
+ option[ANSIC] | option[CPLUSPLUS] ?
+ "(register const char *str, register unsigned int len)\n" :
+ "");
+
+ /* Output the function's body. */
+ printf ("{\n");
+
+ if (option[ENUM] && !option[GLOBAL])
+ {
+ Output_Enum style (" ");
+ output_constants (style);
+ }
+
+ if (!option[GLOBAL])
+ output_lookup_tables ();
+
+ if (option[LENTABLE])
+ output_lookup_function_body (Output_Compare_Memcmp ());
+ else
+ {
+ if (option[COMP])
+ output_lookup_function_body (Output_Compare_Strncmp ());
+ else
+ output_lookup_function_body (Output_Compare_Strcmp ());
+ }
+
+ printf ("}\n");
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Generates the hash function and the key word recognizer function
+ based upon the user's Options. */
+
+void
+Key_List::output (void)
+{
+ T (Trace t ("Key_List::output");)
+
+ compute_min_max ();
+
+ if (option[C] | option[ANSIC] | option[CPLUSPLUS])
+ {
+ const_always = "const ";
+ const_readonly_array = (option[CONST] ? "const " : "");
+ const_for_struct = ((option[CONST] && option[TYPE]) ? "const " : "");
+ }
+ else
+ {
+ const_always = "";
+ const_readonly_array = "";
+ const_for_struct = "";
+ }
+
+ if (!option[TYPE])
+ {
+ return_type = (const_always[0] ? "const char *" : "char *");
+ struct_tag = (const_always[0] ? "const char *" : "char *");
+ }
+
+ char_to_index = (option[SEVENBIT] ? "" : "(unsigned char)");
+
+ printf ("/* ");
+ if (option[KRC])
+ printf ("KR-C");
+ else if (option[C])
+ printf ("C");
+ else if (option[ANSIC])
+ printf ("ANSI-C");
+ else if (option[CPLUSPLUS])
+ printf ("C++");
+ printf (" code produced by gperf version %s */\n", version_string);
+ Options::print_options ();
+
+ printf ("%s\n", include_src);
+
+ if (option[TYPE] && !option[NOTYPE]) /* Output type declaration now, reference it later on.... */
+ printf ("%s;\n", array_type);
+
+ if (option[INCLUDE])
+ printf ("#include <string.h>\n"); /* Declare strlen(), strcmp(), strncmp(). */
+
+ if (!option[ENUM])
+ {
+ Output_Defines style;
+ output_constants (style);
+ }
+ else if (option[GLOBAL])
+ {
+ Output_Enum style ("");
+ output_constants (style);
+ }
+
+ printf ("/* maximum key range = %d, duplicates = %d */\n\n",
+ max_hash_value - min_hash_value + 1, total_duplicates);
+
+ if (option[CPLUSPLUS])
+ printf ("class %s\n"
+ "{\n"
+ "private:\n"
+ " static inline unsigned int %s (const char *str, unsigned int len);\n"
+ "public:\n"
+ " static %s%s%s (const char *str, unsigned int len);\n"
+ "};\n"
+ "\n",
+ option.get_class_name (), option.get_hash_name (),
+ const_for_struct, return_type, option.get_function_name ());
+
+ output_hash_function ();
+
+ if (option[GLOBAL])
+ output_lookup_tables ();
+
+ output_lookup_function ();
+
+ if (additional_code)
+ for (int c; (c = getchar ()) != EOF; putchar (c))
+ ;
+
+ fflush (stdout);
+}
+
+/* ========================= End of Output routines ========================= */
+
+/* Sorts the keys by hash value. */
+
+void
+Key_List::sort (void)
+{
+ T (Trace t ("Key_List::sort");)
+ hash_sort = 1;
+ occurrence_sort = 0;
+
+ head = merge_sort (head);
+}
+
+/* Dumps the key list to stderr stream. */
+
+void
+Key_List::dump ()
+{
+ T (Trace t ("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->key_length, ptr->index,
+ field_width, ptr->char_set_length, ptr->char_set,
+ ptr->key_length, ptr->key);
+}
+
+/* Simple-minded constructor action here... */
+
+Key_List::Key_List (void)
+{
+ T (Trace t ("Key_List::Key_List");)
+ total_keys = 1;
+ max_key_len = INT_MIN;
+ min_key_len = INT_MAX;
+ array_type = 0;
+ return_type = 0;
+ struct_tag = 0;
+ head = 0;
+ total_duplicates = 0;
+ additional_code = 0;
+}
+
+/* Returns the length of entire key list. */
+
+int
+Key_List::keyword_list_length (void)
+{
+ T (Trace t ("Key_List::keyword_list_length");)
+ return list_len;
+}
+
+/* Returns length of longest key read. */
+
+int
+Key_List::max_key_length (void)
+{
+ T (Trace t ("Key_List::max_key_length");)
+ return max_key_len;
+}
+
diff --git a/src/key-list.h b/src/key-list.h
new file mode 100644
index 000000000000..98b8fa5e0c84
--- /dev/null
+++ b/src/key-list.h
@@ -0,0 +1,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-1998 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 "list-node.h"
+#include "vectors.h"
+#include "read-line.h"
+
+/* OSF/1 cxx needs these forward declarations. */
+struct Output_Constants;
+struct Output_Compare;
+
+class Key_List : private Read_Line, public Vectors
+{
+private:
+ const char *array_type; /* Pointer to the type for word list. */
+ const char *return_type; /* Pointer to return type for lookup function. */
+ const char *struct_tag; /* Shorthand for user-defined struct tag type. */
+ const 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. */
+ static int determined[MAX_ALPHA_SIZE]; /* Used in function reorder, below. */
+ static int get_occurrence (List_Node *ptr);
+#ifndef strcspn
+ static int strcspn (const char *s, const char *reject);
+#endif
+ static int already_determined (List_Node *ptr);
+ static void set_determined (List_Node *ptr);
+ void compute_min_max (void);
+ int num_hash_values (void);
+ void output_constants (struct Output_Constants&);
+ void output_hash_function (void);
+ void output_keylength_table (void);
+ void output_keyword_table (void);
+ void output_lookup_array (void);
+ void output_lookup_tables (void);
+ void output_lookup_function_body (const struct Output_Compare&);
+ void output_lookup_function (void);
+ void set_output_types (void);
+ void dump (void);
+ const char *get_array_type (void);
+ const char *save_include_src (void);
+ const char *get_special_input (char delimiter);
+ List_Node *merge (List_Node *list1, List_Node *list2);
+ List_Node *merge_sort (List_Node *head);
+
+protected:
+ List_Node *head; /* Points to the head of the linked list. */
+ int total_duplicates; /* Total number of duplicate hash values. */
+
+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);
+};
+
+#endif
diff --git a/src/keylist.c b/src/keylist.c
new file mode 100644
index 000000000000..f92d97549694
--- /dev/null
+++ b/src/keylist.c
@@ -0,0 +1,1033 @@
+/* Routines for building, ordering, and printing the keyword list.
+ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <assert.h>
+#include <stdio.h>
+#include "options.h"
+#include "readline.h"
+#include "keylist.h"
+#include "hashtable.h"
+#include "stderr.h"
+#ifdef sparc
+#include <alloca.h>
+#endif
+
+/* Current release version. */
+extern char *version_string;
+
+/* See comments in perfect.cc. */
+extern int occurrences[ALPHABET_SIZE];
+
+/* Ditto. */
+extern int asso_values[ALPHABET_SIZE];
+
+/* Used in function reorder, below. */
+static bool determined[ALPHABET_SIZE];
+
+/* Default type for generated code. */
+static char *default_array_type = "char *";
+
+/* Generated function ``in_word_set'' default return type. */
+static char *default_return_type = "char *";
+
+/* Largest positive integer value. */
+#define MAX_INT ((~(unsigned)0)>>1)
+
+/* Most negative integer value. */
+#define NEG_MAX_INT ((~(unsigned)0)^((~(unsigned)0)>>1))
+
+/* Maximum value an unsigned char can take. */
+#define MAX_UNSIGNED_CHAR 256
+
+/* Maximum value an unsigned short can take. */
+#define MAX_UNSIGNED_SHORT 65536
+
+/* Make the hash table 5 times larger than the number of keyword entries. */
+#define TABLE_MULTIPLE 5
+
+/* Efficiently returns the least power of two greater than or equal to X! */
+#define POW(X) ((!X)?1:(X-=1,X|=X>>1,X|=X>>2,X|=X>>4,X|=X>>8,X|=X>>16,(++X)))
+
+/* How wide the printed field width must be to contain the maximum hash value. */
+static int field_width = 2;
+
+/* Globally visible KEY_LIST object. */
+
+KEY_LIST key_list;
+
+/* 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. */
+
+static char *
+get_special_input (delimiter)
+ char delimiter;
+{
+ char *xmalloc ();
+ int size = 80;
+ char *buf = xmalloc (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
+ ungetc (c, stdin);
+ }
+ else if (i >= size) /* Yikes, time to grow the buffer! */
+ {
+ char *temp = xmalloc (size *= 2);
+ int j;
+
+ for (j = 0; j < i; j++)
+ temp[j] = buf[j];
+
+ free (buf);
+ buf = temp;
+ }
+ buf[i] = c;
+ }
+
+ return NULL; /* Problem here. */
+}
+
+/* Stores any C text that must be included verbatim into the
+ generated code output. */
+
+static char *
+save_include_src ()
+{
+ int c;
+
+ if ((c = getchar ()) != '%')
+ {
+ ungetc (c, stdin);
+ return "";
+ }
+ else if ((c = getchar ()) != '{')
+ report_error ("internal error, %c != '{' on line %d in file %s%a", c, __LINE__, __FILE__);
+ /*NOT REACHED*/
+ else
+ return get_special_input ('}');
+}
+
+/* strcspn - find length of initial segment of s consisting entirely
+ of characters not from reject (borrowed from Henry Spencer's
+ ANSI string package). */
+
+static int
+strcspn (s, reject)
+ char *s;
+ char *reject;
+{
+ char *scan;
+ char *rej_scan;
+ int count = 0;
+
+ for (scan = s; *scan; scan++)
+ {
+
+ for (rej_scan = reject; *rej_scan;)
+ if (*scan == *rej_scan++)
+ return count;
+
+ count++;
+ }
+
+ return count;
+}
+
+/* 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. */
+
+static char *
+get_array_type ()
+{
+ return get_special_input ('%');
+}
+
+/* Sets up the Return_Type, the Struct_Tag type and the Array_Type
+ based upon various user Options. */
+
+static void
+set_output_types ()
+{
+ char *xmalloc ();
+
+ if (OPTION_ENABLED (option, TYPE) && !(key_list.array_type = get_array_type ()))
+ return; /* Something's wrong, bug we'll catch it later on.... */
+ else if (OPTION_ENABLED (option, TYPE)) /* Yow, we've got a user-defined type... */
+ {
+ int struct_tag_length = strcspn (key_list.array_type, "{\n\0");
+
+ if (OPTION_ENABLED (option, POINTER)) /* And it must return a pointer... */
+ {
+ key_list.return_type = xmalloc (struct_tag_length + 2);
+ strncpy (key_list.return_type, key_list.array_type, struct_tag_length);
+ key_list.return_type[struct_tag_length] = '\0';
+ strcat (key_list.return_type, "*");
+ }
+
+ key_list.struct_tag = (char *) xmalloc (struct_tag_length + 1);
+ strncpy (key_list.struct_tag, key_list.array_type, struct_tag_length);
+ key_list.struct_tag[struct_tag_length] = '\0';
+ }
+ else if (OPTION_ENABLED (option, POINTER)) /* Return a char *. */
+ key_list.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
+read_keys ()
+{
+ char *ptr;
+
+ key_list.include_src = save_include_src ();
+ set_output_types ();
+
+ /* Oops, problem with the input file. */
+ if (! (ptr = read_line ()))
+ report_error ("No words in input file, did you forget\
+ to prepend %s or use -t accidentally?\n%a", "%%");
+
+ /* Read in all the keywords from the input file. */
+ else
+ {
+ LIST_NODE *temp, *trail;
+ char *delimiter = GET_DELIMITER (option);
+
+ for (temp = key_list.head = make_list_node (ptr, strcspn (ptr, delimiter));
+ (ptr = read_line ()) && strcmp (ptr, "%%");
+ key_list.total_keys++, temp = temp->next)
+ temp->next = make_list_node (ptr, strcspn (ptr, delimiter));
+
+ /* See if any additional C code is included at end of this file. */
+ if (ptr)
+ key_list.additional_code = TRUE;
+ {
+ /* If this becomes TRUE we've got a link. */
+ bool link = FALSE;
+
+ /* Make large hash table for efficiency. */
+ int table_size = (key_list.list_len = key_list.total_keys) * TABLE_MULTIPLE;
+
+ /* 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 = (LIST_NODE **) alloca (POW (table_size) * sizeof (LIST_NODE *));
+
+ hash_table_init (table, table_size);
+
+ /* Test whether there are any links and also set the maximum length of
+ an identifier in the keyword list. */
+
+ for (temp = key_list.head, trail = NULL; temp; temp = temp->next)
+ {
+ LIST_NODE *ptr = retrieve (temp, OPTION_ENABLED (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)
+ {
+ key_list.list_len--;
+ trail->next = temp->next;
+ temp->link = ptr->link;
+ ptr->link = temp;
+ link = TRUE;
+
+ /* Complain if user hasn't enabled the duplicate option. */
+ if (!OPTION_ENABLED (option, DUP))
+ fprintf (stderr, "Key link: \"%s\" = \"%s\", with key set \"%s\".\n",
+ temp->key, ptr->key, temp->char_set);
+ else if (OPTION_ENABLED (option, DEBUG))
+ fprintf (stderr, "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 (temp->length > key_list.max_key_len)
+ key_list.max_key_len = temp->length;
+ if (temp->length < key_list.min_key_len)
+ key_list.min_key_len = temp->length;
+ }
+
+ /* Free up the dynamic memory used in the hash table. */
+ hash_table_destroy ();
+
+ /* Exit program if links exists and option[DUP] not set, since we can't continue safely. */
+ if (link)
+ report_error (OPTION_ENABLED (option, DUP)
+ ? "Some input keys have identical hash values, examine output carefully...\n"
+ : "Some input keys have identical hash values,\ntry different key positions or use option -D.\n%a");
+ }
+ if (OPTION_ENABLED (option, ALLCHARS))
+ SET_CHARSET_SIZE (option, key_list.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. */
+
+static LIST_NODE *
+merge (list1, list2)
+ LIST_NODE *list1;
+ LIST_NODE *list2;
+{
+ if (!list1)
+ return list2;
+ else if (!list2)
+ return list1;
+ else if (key_list.occurrence_sort && list1->occurrence < list2->occurrence
+ || key_list.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. */
+
+static LIST_NODE *
+merge_sort (head)
+ LIST_NODE *head;
+{
+ if (!head || !head->next)
+ return head;
+ else
+ {
+ LIST_NODE *middle = head;
+ LIST_NODE *temp = head->next->next;
+
+ while (temp)
+ {
+ temp = temp->next;
+ middle = middle->next;
+ if (temp)
+ temp = temp->next;
+ }
+
+ temp = middle->next;
+ middle->next = NULL;
+ return merge (merge_sort (head), merge_sort (temp));
+ }
+}
+
+/* Returns the frequency of occurrence of elements in the key set. */
+
+static int
+get_occurrence (ptr)
+ LIST_NODE *ptr;
+{
+ int value = 0;
+ char *temp;
+
+ for (temp = ptr->char_set; *temp; temp++)
+ value += occurrences[*temp];
+
+ return value;
+}
+
+/* Enables the index location of all key set elements that are now
+ determined. */
+
+static void
+set_determined (ptr)
+ LIST_NODE *ptr;
+{
+ char *temp;
+
+ for (temp = ptr->char_set; *temp; temp++)
+ determined[*temp] = TRUE;
+
+}
+
+/* Returns TRUE if PTR's key set is already completely determined. */
+
+static bool
+already_determined (ptr)
+ LIST_NODE *ptr;
+{
+ bool is_determined = TRUE;
+ char *temp;
+
+ for (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
+reorder ()
+{
+ LIST_NODE *ptr;
+
+ for (ptr = key_list.head; ptr; ptr = ptr->next)
+ ptr->occurrence = get_occurrence (ptr);
+
+ key_list.hash_sort = FALSE;
+ key_list.occurrence_sort = TRUE;
+
+ for (ptr = key_list.head = merge_sort (key_list.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;
+ }
+ }
+ }
+}
+
+/* Determines the maximum and minimum hash values. One notable feature is
+ Ira Pohl's optimal algorithm to calculate both the maximum and minimum
+ items in a list in O(3n/2) time (faster than the O (2n) method).
+ Returns the maximum hash value encountered. */
+
+static int
+print_min_max ()
+{
+ int min_hash_value;
+ int max_hash_value;
+ LIST_NODE *temp;
+
+ if (ODD (key_list.list_len)) /* Pre-process first item, list now has an even length. */
+ {
+ min_hash_value = max_hash_value = key_list.head->hash_value;
+ temp = key_list.head->next;
+ }
+ else /* List is already even length, no extra work necessary. */
+ {
+ min_hash_value = MAX_INT;
+ max_hash_value = NEG_MAX_INT;
+ temp = key_list.head;
+ }
+
+ for ( ; temp; temp = temp->next) /* Find max and min in optimal o(3n/2) time. */
+ {
+ static int i;
+ int key_2, key_1 = temp->hash_value;
+ temp = temp->next;
+ key_2 = temp->hash_value;
+ i++;
+
+ if (key_1 < key_2)
+ {
+ if (key_1 < min_hash_value)
+ min_hash_value = key_1;
+ if (key_2 > max_hash_value)
+ max_hash_value = key_2;
+ }
+ else
+ {
+ if (key_2 < min_hash_value)
+ min_hash_value = key_2;
+ if (key_1 > max_hash_value)
+ max_hash_value = key_1;
+ }
+ }
+
+ printf ("\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/*\n%5d keywords\n%5d is the maximum key range\n*/\n\n",
+ key_list.min_key_len == MAX_INT ? key_list.max_key_len : key_list.min_key_len,
+ key_list.max_key_len, min_hash_value, max_hash_value,
+ key_list.total_keys, (max_hash_value - min_hash_value + 1));
+ return max_hash_value;
+}
+
+/* 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 Print_Lookup_Function. Then we use for
+ switch statements to perform 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. */
+
+static void
+print_switch ()
+{
+ char *comp_buffer;
+ LIST_NODE *curr = key_list.head;
+ int pointer_and_type_enabled = OPTION_ENABLED (option, POINTER) && OPTION_ENABLED (option, TYPE);
+ int total_switches = GET_TOTAL_SWITCHES (option);
+ int switch_size = keyword_list_length () / total_switches;
+
+ if (pointer_and_type_enabled)
+ {
+ comp_buffer = (char *) alloca (strlen ("*str == *resword->%s && !strncmp (str + 1, resword->%s + 1, len - 1)")
+ + 2 * strlen (GET_KEY_NAME (option)) + 1);
+ sprintf (comp_buffer, OPTION_ENABLED (option, COMP)
+ ? "*str == *resword->%s && !strncmp (str + 1, resword->%s + 1, len - 1)"
+ : "*str == *resword->%s && !strcmp (str + 1, resword->%s + 1)",
+ GET_KEY_NAME (option), GET_KEY_NAME (option));
+ }
+ else
+ comp_buffer = OPTION_ENABLED (option, COMP)
+ ? "*str == *resword && !strncmp (str + 1, resword + 1, len - 1)"
+ : "*str == *resword && !strcmp (str + 1, resword + 1)";
+
+ printf (" if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n {\n\
+ register int key = %s (str, len);\n\n\
+ if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n {\n", GET_HASH_NAME (option));
+
+ /* 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)
+ 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_ENABLED (option, POINTER) || OPTION_ENABLED (option, DUP))
+ {
+ int i = 0;
+
+ printf (" %s%s *resword; %s\n\n",
+ OPTION_ENABLED (option, CONST) ? "const " : "",
+ pointer_and_type_enabled ? key_list.struct_tag : "char",
+ OPTION_ENABLED (option, LENTABLE) && !OPTION_ENABLED (option, DUP) ? "int key_len;" : "");
+ 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_ENABLED (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_ENABLED (option, LENTABLE) && !OPTION_ENABLED (option, DUP))
+ printf (" key_len = %d;", temp->length);
+ printf (" break;\n");
+ }
+ }
+ printf (" default: return 0;\n }\n");
+ printf (OPTION_ENABLED (option, LENTABLE) && !OPTION_ENABLED (option, DUP)
+ ? " if (len == key_len && %s)\n return resword;\n"
+ : " if (%s)\n return resword;\n", comp_buffer);
+ printf (" return 0;\n }\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_ENABLED (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 ");
+ printf ("return *s == *str && !%s;\n }\n",
+ OPTION_ENABLED (option, COMP)
+ ? "strncmp (s + 1, str + 1, len - 1)" : "strcmp (s + 1, str + 1)");
+ curr = temp;
+ }
+ }
+ printf (" }\n }\n return 0;\n}\n");
+}
+
+/* Prints out a table of keyword lengths, for use with the
+ comparison code in generated function ``in_word_set.'' */
+
+static void
+print_keylength_table ()
+{
+ int max_column = 15;
+ int index = 0;
+ int column = 0;
+ char *indent = OPTION_ENABLED (option, GLOBAL) ? "" : " ";
+ LIST_NODE *temp;
+
+ if (!OPTION_ENABLED (option, DUP) && !OPTION_ENABLED (option, SWITCH))
+ {
+ printf ("\n%sstatic %sunsigned %s lengthtable[] =\n%s%s{\n ",
+ indent, OPTION_ENABLED (option, CONST) ? "const " : "",
+ key_list.max_key_len < MAX_UNSIGNED_CHAR ? "char" :
+ (key_list.max_key_len < MAX_UNSIGNED_SHORT ? "short" : "long"),
+ indent, indent);
+
+ for (temp = key_list.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\n", indent, indent);
+ }
+}
+
+/* Prints out the array containing the key words for the Perfect
+ hash function. */
+
+static void
+print_keyword_table ()
+{
+ char *l_brace = *key_list.head->rest ? "{" : "";
+ char *r_brace = *key_list.head->rest ? "}," : "";
+ int doing_switch = OPTION_ENABLED (option, SWITCH);
+ char *indent = OPTION_ENABLED (option, GLOBAL) ? "" : " ";
+ int index = 0;
+ LIST_NODE *temp;
+
+ printf ("\n%sstatic %s%s wordlist[] =\n%s%s{\n",
+ indent, OPTION_ENABLED (option, CONST) ? "const " : "",
+ key_list.struct_tag, indent, indent);
+
+ /* Generate an array of reserved words at appropriate locations. */
+
+ for (temp = key_list.head; temp; temp = temp->next, index++)
+ {
+ temp->index = index;
+
+ if (!doing_switch && 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\n", l_brace, temp->key, temp->rest, r_brace);
+ continue;
+ }
+ }
+
+ printf (" %s\"%s\", %s%s\n", l_brace, temp->key, temp->rest, r_brace);
+
+ /* Deal with links specially. */
+ if (temp->link)
+ {
+ LIST_NODE *links;
+
+ for (links = temp->link; links; links = links->link)
+ {
+ links->index = ++index;
+ printf (" %s\"%s\", %s%s\n", l_brace, links->key, links->rest, r_brace);
+ }
+ }
+
+ }
+
+ printf ("%s%s};\n\n", indent, indent);
+}
+
+/* Generates C code for the hash function that returns the
+ proper encoding for each key word. */
+
+static void
+print_hash_function (max_hash_value)
+ int max_hash_value;
+{
+ int max_column = 10;
+ int count = max_hash_value;
+
+ /* Calculate maximum number of digits required for MAX_HASH_VALUE. */
+
+ while ((count /= 10) > 0)
+ field_width++;
+
+ if (OPTION_ENABLED (option, GNU))
+ printf ("#ifdef __GNUC__\ninline\n#endif\n");
+
+ printf (OPTION_ENABLED (option, ANSI)
+ ? "static int\n%s (register const char *str, register int len)\n{\n static %sunsigned %s hash_table[] =\n {"
+ : "static int\n%s (str, len)\n register char *str;\n register unsigned int len;\n{\n static %sunsigned %s hash_table[] =\n {",
+ GET_HASH_NAME (option), OPTION_ENABLED (option, CONST) ? "const " : "",
+ max_hash_value < MAX_UNSIGNED_CHAR
+ ? "char" : (max_hash_value < MAX_UNSIGNED_SHORT ? "short" : "int"));
+
+ for (count = 0; count < ALPHABET_SIZE; ++count)
+ {
+ if (!(count % max_column))
+ printf ("\n ");
+
+ printf ("%*d,", field_width, occurrences[count] ? asso_values[count] : max_hash_value);
+ }
+
+ /* Optimize special case of ``-k 1,$'' */
+ if (OPTION_ENABLED (option, DEFAULTCHARS))
+ printf ("\n };\n return %s + hash_table[str[len - 1]] + hash_table[str[0]];\n}\n\n",
+ OPTION_ENABLED (option, NOLENGTH) ? "0" : "len");
+ else
+ {
+ int key_pos;
+
+ RESET (option);
+
+ /* Get first (also highest) key position. */
+ key_pos = GET (option);
+
+ /* We can perform additional optimizations here. */
+ if (!OPTION_ENABLED (option, ALLCHARS) && key_pos <= key_list.min_key_len)
+ {
+ printf ("\n };\n return %s", OPTION_ENABLED (option, NOLENGTH) ? "0" : "len");
+
+ for ( ; key_pos != EOS && key_pos != WORD_END; key_pos = GET (option))
+ printf (" + hash_table[str[%d]]", key_pos - 1);
+
+ printf ("%s;\n}\n\n", key_pos == WORD_END ? " + hash_table[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_ENABLED (option, NOLENGTH)
+ ? "0" : "len", OPTION_ENABLED (option, NOLENGTH) ? "len" : "hval");
+
+ /* User wants *all* characters considered in hash. */
+ if (OPTION_ENABLED (option, ALLCHARS))
+ {
+ int i;
+
+ for (i = key_list.max_key_len; i > 0; i--)
+ printf (" case %d:\n hval += hash_table[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 (" case %d:\n hval += hash_table[str[%d]];\n",
+ key_pos, key_pos - 1);
+ }
+ while ((key_pos = GET (option)) != EOS && key_pos != WORD_END);
+
+ printf (" }\n return hval%s ;\n}\n\n", key_pos == WORD_END
+ ? " + hash_table[str[len - 1]]" : "");
+ }
+ }
+ }
+}
+
+/* Generates C code to perform the keyword lookup. */
+
+static void
+print_lookup_function ()
+{
+ printf (" if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n {\n\
+ register int key = %s (str, len);\n\n\
+ if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n {\n\
+ register %schar *s = wordlist[key]",
+ GET_HASH_NAME (option), OPTION_ENABLED (option, CONST) ? "const " : "");
+ if (key_list.array_type != default_array_type)
+ printf (".%s", GET_KEY_NAME (option));
+
+ printf (";\n\n if (%s*s == *str && !%s)\n return %s",
+ OPTION_ENABLED (option, LENTABLE) ? "len == lengthtable[key]\n && " : "",
+ OPTION_ENABLED (option, COMP) ? "strncmp (str + 1, s + 1, len - 1)" : "strcmp (str + 1, s + 1)",
+ OPTION_ENABLED (option, TYPE) && OPTION_ENABLED (option, POINTER) ? "&wordlist[key]" : "s");
+ printf (";\n }\n }\n return 0;\n}\n");
+}
+
+/* Generates the hash function and the key word recognizer function
+ based upon the user's Options. */
+
+void
+print_output ()
+{
+ int global_table = OPTION_ENABLED (option, GLOBAL);
+
+ printf ("%s\n", key_list.include_src);
+
+ /* Potentially output type declaration now, reference it later on.... */
+ if (OPTION_ENABLED (option, TYPE) && !OPTION_ENABLED (option, NOTYPE))
+ printf ("%s;\n", key_list.array_type);
+
+ print_hash_function (print_min_max ());
+
+ if (global_table)
+ if (OPTION_ENABLED (option, SWITCH))
+ {
+ if (OPTION_ENABLED (option, LENTABLE) && OPTION_ENABLED (option, DUP))
+ print_keylength_table ();
+ if (OPTION_ENABLED (option, POINTER) && OPTION_ENABLED (option, TYPE))
+ print_keyword_table ();
+ }
+ else
+ {
+ if (OPTION_ENABLED (option, LENTABLE))
+ print_keylength_table ();
+ print_keyword_table ();
+ }
+ /* Use the inline keyword to remove function overhead. */
+ if (OPTION_ENABLED (option, GNU))
+ printf ("#ifdef __GNUC__\ninline\n#endif\n");
+
+ /* Use ANSI function prototypes. */
+ printf (OPTION_ENABLED (option, ANSI)
+ ? "%s%s\n%s (register const char *str, register int len)\n{\n"
+ : "%s%s\n%s (str, len)\n register char *str;\n register unsigned int len;\n{\n",
+ OPTION_ENABLED (option, CONST) ? "const " : "",
+ key_list.return_type, GET_FUNCTION_NAME (option));
+
+ /* Use the switch in place of lookup table. */
+ if (OPTION_ENABLED (option, SWITCH))
+ {
+ if (!global_table)
+ {
+ if (OPTION_ENABLED (option, LENTABLE) && OPTION_ENABLED (option, DUP))
+ print_keylength_table ();
+ if (OPTION_ENABLED (option, POINTER) && OPTION_ENABLED (option, TYPE))
+ print_keyword_table ();
+ }
+ print_switch ();
+ }
+ else /* Use the lookup table, in place of switch. */
+ {
+ if (!global_table)
+ {
+ if (OPTION_ENABLED (option, LENTABLE))
+ print_keylength_table ();
+ print_keyword_table ();
+ }
+ print_lookup_function ();
+ }
+
+ if (key_list.additional_code)
+ {
+ int c;
+
+ while ((c = getchar ()) != EOF)
+ putchar (c);
+ }
+ fflush (stdout);
+}
+
+/* Sorts the keys by hash value. */
+
+void
+sort ()
+{
+ key_list.hash_sort = TRUE;
+ key_list.occurrence_sort = FALSE;
+
+ key_list.head = merge_sort (key_list.head);
+}
+
+/* Dumps the key list to stderr stream. */
+
+static void
+dump ()
+{
+ LIST_NODE *ptr;
+
+ fprintf (stderr, "\nList contents are:\n(hash value, key length, index, key set, key):\n");
+
+ for (ptr = key_list.head; ptr; ptr = ptr->next)
+ fprintf (stderr, "%7d,%7d,%6d, %s, %s\n",
+ ptr->hash_value, ptr->length, ptr->index,
+ ptr->char_set, ptr->key);
+}
+
+/* Simple-minded constructor action here... */
+
+void
+key_list_init ()
+{
+ key_list.total_keys = 1;
+ key_list.max_key_len = NEG_MAX_INT;
+ key_list.min_key_len = MAX_INT;
+ key_list.return_type = default_return_type;
+ key_list.array_type = key_list.struct_tag = default_array_type;
+ key_list.head = NULL;
+ key_list.additional_code = FALSE;
+}
+
+/* Returns the length of entire key list. */
+
+int
+keyword_list_length ()
+{
+ return key_list.list_len;
+}
+
+/* Returns length of longest key read. */
+
+int
+max_key_length ()
+{
+ return key_list.max_key_len;
+}
+
+/* DESTRUCTOR dumps diagnostics during debugging. */
+
+void
+key_list_destroy ()
+{
+ if (OPTION_ENABLED (option, DEBUG))
+ {
+ fprintf (stderr, "\nDumping key list information:\ntotal unique keywords = %d\
+\ntotal keywords = %d\nmaximum key length = %d.\n",
+ key_list.list_len, key_list.total_keys, key_list.max_key_len);
+ dump ();
+ fprintf (stderr, "End dumping list.\n\n");
+ }
+}
+
diff --git a/src/keylist.h b/src/keylist.h
new file mode 100644
index 000000000000..38143b73cb14
--- /dev/null
+++ b/src/keylist.h
@@ -0,0 +1,54 @@
+/* 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The key word list is a useful abstraction that keeps track of
+ various pieces of information that enable that fast generation
+ of the Perfect.hash function. A Key_List is a singly-linked
+ list of List_Nodes. */
+
+#ifndef _keylist_h
+#define _keylist_h
+#include <stdio.h>
+#include "listnode.h"
+
+typedef struct key_list
+{
+ LIST_NODE *head; /* Points to the head of the linked list. */
+ 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 list_len; /* Length of head's Key_List, not counting duplicates. */
+ int total_keys; /* Total number of keys, counting duplicates. */
+ int max_key_len; /* Maximum length of the longest keyword. */
+ int min_key_len; /* Minimum length of the shortest keyword. */
+ bool occurrence_sort; /* True if sorting by occurrence. */
+ bool hash_sort; /* True if sorting by hash value. */
+ bool additional_code; /* True if any additional C code is included. */
+} KEY_LIST;
+
+extern void key_list_init P ((void));
+extern void key_list_destroy P ((void));
+extern void print_output P ((void));
+extern int keyword_list_length P ((void));
+extern int max_key_length P ((void));
+extern KEY_LIST key_list;
+#endif /* _keylist_h */
diff --git a/src/list-node.cc b/src/list-node.cc
new file mode 100644
index 000000000000..57a04a071fe4
--- /dev/null
+++ b/src/list-node.cc
@@ -0,0 +1,102 @@
+/* Creates and initializes a new list node.
+ Copyright (C) 1989-1998, 2000 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 "list-node.h"
+
+#include <stdio.h>
+#include <stdlib.h> /* declares exit() */
+#include "options.h"
+#include "trace.h"
+
+/* 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)
+{
+ T (Trace t ("List_Node::set_sort");)
+ 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 (const char *k, int len, const char *r):
+ link (0), next (0), key (k), key_length (len), rest (r), index (0)
+{
+ T (Trace t ("List_Node::List_Node");)
+ char *key_set = new char[(option[ALLCHARS] ? len : option.get_max_keysig_size ())];
+ char *ptr = key_set;
+ int i;
+
+ if (option[ALLCHARS]) /* Use all the character positions in the KEY. */
+ for (i = len; i > 0; k++, ptr++, i--)
+ ++occurrences[(unsigned char)(*ptr = *k)];
+ else /* Only use those character positions specified by the user. */
+ {
+ /* Iterate through 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;
+ ++occurrences[(unsigned char)(*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])
+ {
+ fprintf (stderr, "Can't hash keyword %.*s with chosen key positions.\n",
+ key_length, key);
+ exit (1);
+ }
+ }
+
+ /* Sort the KEY_SET items alphabetically. */
+ set_sort (key_set, ptr - key_set);
+
+ char_set = key_set;
+ char_set_length = ptr - key_set;
+}
diff --git a/src/list-node.h b/src/list-node.h
new file mode 100644
index 000000000000..3bd21b3359df
--- /dev/null
+++ b/src/list-node.h
@@ -0,0 +1,46 @@
+/* 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-1998, 2000 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 "vectors.h"
+
+struct List_Node : private Vectors
+{
+ List_Node *link; /* TRUE if key has an identical KEY_SET as another key. */
+ List_Node *next; /* Points to next element on the list. */
+ const char *key; /* Each keyword string stored here. */
+ int key_length; /* Length of the key. */
+ const char *rest; /* Additional information for building hash function. */
+ const char *char_set; /* Set of characters to hash, specified by user. */
+ int char_set_length; /* Length of char_set. */
+ 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. */
+
+ List_Node (const char *key, int len, const char *rest);
+ static void set_sort (char *base, int len);
+};
+
+#endif
diff --git a/src/listnode.c b/src/listnode.c
new file mode 100644
index 000000000000..2eec1a6f74f8
--- /dev/null
+++ b/src/listnode.c
@@ -0,0 +1,111 @@
+/* Creates and initializes a new 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "options.h"
+#include "listnode.h"
+#include "stderr.h"
+
+/* See comments in perfect.cc. */
+extern int occurrences[ALPHABET_SIZE];
+
+/* Sorts the key set alphabetically to speed up subsequent operations.
+ Uses insertion sort since the set is probably quite small. */
+
+static void
+set_sort (base, len)
+ 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 KEY_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. */
+
+LIST_NODE *
+make_list_node (k, len)
+ char *k;
+ int len;
+{
+ LIST_NODE *buffered_malloc ();
+ int char_set_size = OPTION_ENABLED (option, ALLCHARS) ? len : GET_CHARSET_SIZE (option) + 1;
+ LIST_NODE *temp = buffered_malloc (sizeof (LIST_NODE) + char_set_size);
+ char *ptr = temp->char_set;
+
+ k[len] = '\0'; /* Null terminate KEY to separate it from REST. */
+ temp->key = k;
+ temp->next = 0;
+ temp->index = 0;
+ temp->length = len;
+ temp->link = 0;
+ temp->rest = OPTION_ENABLED (option, TYPE) ? k + len + 1 : "";
+
+ if (OPTION_ENABLED (option, ALLCHARS)) /* Use all the character position in the KEY. */
+
+ for (; *k; k++, ptr++)
+ ++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 temp->char_set (via char * pointer ptr). */
+
+ for(RESET (option); (i = GET (option)) != EOS; )
+ {
+ if (i == WORD_END) /* Special notation for last KEY position, i.e. '$'. */
+ *ptr = temp->key[len - 1];
+ else if (i <= len) /* Within range of KEY length, so we'll keep it. */
+ *ptr = temp->key[i - 1];
+ else /* Out of range of KEY length, so we'll just skip it. */
+ continue;
+ ++occurrences[*ptr++];
+ }
+
+ if (ptr == temp->char_set) /* Didn't get any hits, i.e., no usable positions. */
+ report_error ("can't hash keyword %s with chosen key positions\n%a", temp->key);
+ }
+
+ *ptr = '\0'; /* Terminate this bastard.... */
+ /* Sort the KEY_SET items alphabetically. */
+ set_sort (temp->char_set, ptr - temp->char_set);
+
+ return temp;
+}
diff --git a/src/listnode.h b/src/listnode.h
new file mode 100644
index 000000000000..3e64709f5c10
--- /dev/null
+++ b/src/listnode.h
@@ -0,0 +1,43 @@
+/* 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _listnode_h
+#define _listnode_h
+#include "prototype.h"
+
+#define ALPHABET_SIZE 128
+
+typedef struct list_node
+{
+ struct list_node *link; /* TRUE if key has an identical KEY_SET as another key. */
+ struct list_node *next; /* Points to next element on the list. */
+ 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. */
+ char *key; /* Key string. */
+ char *rest; /* Additional information for building hash function. */
+ char char_set[1]; /* Set of characters to hash, specified by user. */
+} LIST_NODE;
+
+extern LIST_NODE *make_list_node P ((char *k, int len));
+
+#endif _listnode_h
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 000000000000..a54c1dfc5069
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,96 @@
+/* Driver program for the Perfect hash function generator.
+ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Simple driver program for the Perfect.hash function generator.
+ Most of the hard work is done in class Perfect and its class methods. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <time.h>
+#include "stderr.h"
+#include "options.h"
+#include "perfect.h"
+
+/* Calls the appropriate intialization routines for each
+ ADT. Note that certain initialization routines require
+ initialization *after* certain values are computed. Therefore,
+ they cannot be called here. */
+
+static void
+init_all (argc, argv)
+ int argc;
+ char *argv[];
+{
+#ifdef RLIMIT_STACK
+ /* 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 */
+
+ options_init (argc, argv);
+ key_list_init ();
+ perfect_init ();
+}
+
+/* Calls appropriate destruction routines for each ADT. These
+ routines print diagnostics if the debugging option is enabled. */
+
+static void
+destroy_all ()
+{
+ options_destroy ();
+ key_list_destroy ();
+ perfect_destroy ();
+}
+
+/* Driver for perfect hash function generation. */
+
+int
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct tm *tm;
+ time_t clock;
+ int status;
+
+ time (&clock);
+ tm = localtime (&clock);
+
+ fprintf (stderr, "/* starting time is %d:%d:%d */\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
+ /* Sets the options. */
+ init_all (argc, argv);
+
+ /* Generates the perfect hash table.
+ Also prints generated code neatly to the output. */
+ status = perfect_generate ();
+ destroy_all ();
+
+ time (&clock);
+ tm = localtime (&clock);
+ fprintf (stderr, "/* ending time is %d:%d:%d */\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
+ return status;
+}
diff --git a/src/main.cc b/src/main.cc
new file mode 100644
index 000000000000..03b6c7ea242b
--- /dev/null
+++ b/src/main.cc
@@ -0,0 +1,76 @@
+/* Driver program for the Gen_Perf hash function generator
+ Copyright (C) 1989-1998, 2000 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.
+ Most of the hard work is done in class Gen_Perf and its class methods. */
+
+#include "config.h"
+#include <sys/types.h>
+#if LARGE_STACK_ARRAYS && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#endif
+
+#include <stdio.h>
+#include "options.h"
+#include "gen-perf.h"
+#include "trace.h"
+
+int
+main (int argc, char *argv[])
+{
+ T (Trace t ("main");)
+
+#if LARGE_STACK_ARRAYS && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK)
+ /* Get rid of any avoidable limit on stack size. */
+ {
+ struct rlimit rlim;
+ if (getrlimit (RLIMIT_STACK, &rlim) == 0)
+ if (rlim.rlim_cur < rlim.rlim_max)
+ {
+ 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 generate_table;
+
+ /* Generates and prints the Gen_Perf hash table. */
+ int status = generate_table ();
+
+ /* Check for write error on stdout. */
+ if (fflush (stdout) || ferror (stdout))
+ status = 1;
+
+ /* Don't use exit() here, it skips the destructors. */
+ return status;
+}
diff --git a/src/new.cc b/src/new.cc
new file mode 100644
index 000000000000..8c6728ec4b2a
--- /dev/null
+++ b/src/new.cc
@@ -0,0 +1,87 @@
+/* Defines a buffered memory allocation abstraction that reduces calls to
+ malloc.
+ Copyright (C) 1989-1998 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 "config.h"
+#include <stdio.h>
+#include <stdlib.h> /* declares malloc(), exit() */
+#include "trace.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)
+{
+ T (Trace t ("operator new");)
+ static char *buf_start = 0; /* Large array used to reduce calls to NEW. */
+ static char *buf_end = 0; /* Indicates end of BUF_START. */
+ static size_t buf_size = 4096; /* 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)) != (char *)0)
+ buf_end = buf_start + buf_size;
+ else
+ {
+ fprintf (stderr, "Virtual memory exhausted in `operator new'\n");
+ exit (1);
+ }
+ }
+
+ temp = buf_start;
+ buf_start += size;
+ return temp;
+}
+
+/* We need this deletion operator in order to make the linker happy.
+ Because `operator new' and `operator delete' always come together. */
+
+void
+operator delete (void *ptr)
+#ifdef HAVE_THROW_DECL
+ throw()
+#endif
+{
+ T (Trace t ("operator delete");)
+ // We cannot call free here, as it doesn't match the mallocs.
+ // free ((char *) ptr);
+ (void) ptr;
+}
diff --git a/src/options.c b/src/options.c
new file mode 100644
index 000000000000..40fdf0a6588e
--- /dev/null
+++ b/src/options.c
@@ -0,0 +1,444 @@
+/* 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <assert.h>
+#include "options.h"
+#include "iterator.h"
+#include "stderr.h"
+
+/* Current program version. */
+extern char *version_string;
+
+/* Size to jump on a collision. */
+#define DEFAULT_JUMP_VALUE 5
+
+/* Default name for generated lookup function. */
+#define DEFAULT_NAME "in_word_set"
+
+/* Default name for the key component. */
+#define DEFAULT_KEY "name"
+
+/* Default name for generated hash function. */
+#define DEFAULT_HASH_NAME "hash"
+
+/* Globally visible OPTIONS object. */
+OPTIONS option;
+
+/* Default delimiters that separate keywords from their attributes. */
+#define DEFAULT_DELIMITERS ",\n"
+
+/* Prints program usage to standard error stream. */
+
+void
+usage ()
+{
+ report_error ("usage: %n [-acCdDef[num]gGhH<hashname>i<init>jk<keys>\
+K<keyname>lnN<name>oprs<size>S<switches>tTv].\n(type %n -h for help)\n");
+}
+
+/* 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. */
+
+static int
+key_sort (base, len)
+ 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;
+}
+
+/* Dumps option status when debug is set. */
+
+void
+options_destroy ()
+{
+ if (OPTION_ENABLED (option, 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\nCOMP is........: %s\nFAST is........: %s\
+\nNOTYPE is......: %s\nGLOBAL is......: %s\nCONST 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\napproximate switch statement size = %d\n",
+ OPTION_ENABLED (option, DEBUG) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, ORDER) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, ANSI) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, TYPE) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, GNU) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, RANDOM) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, DEFAULTCHARS) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, SWITCH) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, POINTER) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, NOLENGTH) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, LENTABLE) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, DUP) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, COMP) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, FAST) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, NOTYPE) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, GLOBAL) ? "enabled" : "disabled",
+ OPTION_ENABLED (option, CONST) ? "enabled" : "disabled",
+ option.iterations, option.function_name, option.hash_name,
+ option.key_name, option.jump, option.size - 1,
+ option.initial_asso_value, option.delimiters, option.total_switches,
+ keyword_list_length () / option.total_switches);
+
+ if (OPTION_ENABLED (option, ALLCHARS))
+ fprintf (stderr, "all characters are used in the hash function\n");
+ fprintf (stderr, "maximum charset size = %d\nkey positions are: \n",
+ option.total_charset_size);
+
+ for (ptr = option.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.option_word. */
+
+void
+options_init (argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern int optind;
+ extern char *optarg;
+ int option_char;
+
+ option.key_positions[0] = WORD_START;
+ option.key_positions[1] = WORD_END;
+ option.key_positions[2] = EOS;
+ option.total_charset_size = 2;
+ option.jump = DEFAULT_JUMP_VALUE;
+ option.option_word = (int) DEFAULTCHARS;
+ option.function_name = DEFAULT_NAME;
+ option.hash_name = DEFAULT_HASH_NAME;
+ option.key_name = DEFAULT_KEY;
+ option.delimiters = DEFAULT_DELIMITERS;
+ option.initial_asso_value = option.size = option.iterations = 0;
+ option.total_switches = 1;
+ option.argument_count = argc;
+ option.argument_vector = argv;
+ set_program_name (argv[0]);
+
+ while ((option_char = getopt (argc, argv, "adcCDe:f:gGhH:i:j:k:K:lnN:oprs:S:tTv")) != EOF)
+ {
+ switch (option_char)
+ {
+ case 'a': /* Generated coded uses the ANSI prototype format. */
+ {
+ SET_OPTION (option, ANSI);
+ break;
+ }
+ case 'c': /* Generate strncmp rather than strcmp. */
+ {
+ SET_OPTION (option, COMP);
+ break;
+ }
+ case 'C': /* Make the generated tables readonly (const). */
+ {
+ SET_OPTION (option, CONST);
+ break;
+ }
+ case 'd': /* Enable debugging option. */
+ {
+ SET_OPTION (option, DEBUG);
+ report_error ("starting program %n, version %s, with debuggin on.\n",
+ version_string);
+ break;
+ }
+ case 'D': /* Enable duplicate option. */
+ {
+ SET_OPTION (option, DUP);
+ break;
+ }
+ case 'e': /* Allows user to provide keyword/attribute separator */
+ {
+ SET_DELIMITERS (option, optarg);
+ break;
+ }
+ case 'f': /* Generate the hash table ``fast.'' */
+ {
+ SET_OPTION (option, FAST);
+ if ((option.iterations = atoi (optarg)) < 0)
+ {
+ report_error ("iterations value must not be negative, assuming 0\n");
+ option.iterations = 0;
+ }
+ break;
+ }
+ case 'g': /* Use the ``inline'' keyword for generated sub-routines. */
+ {
+ SET_OPTION (option, GNU);
+ break;
+ }
+ case 'G': /* Make the keyword table a global variable. */
+ {
+ SET_OPTION (option, GLOBAL);
+ break;
+ }
+ case 'h': /* Displays a list of helpful Options to the user. */
+ {
+ report_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 Std_Err).\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\
+-f\tGenerate the perfect 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");
+ report_error (
+"-H\tAllow user to specify name of generated hash function. Default is `hash'.\n\
+-i\tProvide an initial value for the associate values array. Default is 0.\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 user 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\
+-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\
+-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",
+ DEFAULT_JUMP_VALUE, MAX_KEY_POS - 1);
+ report_error (
+"-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'' the table range\n\
+\tshould be, in relationship to the number of keys, e.g. a value of 3\n\
+\tmeans ``make the table about 3 times larger than the number of input\n\
+\tkeys.'' A larger table should decrease the time required for an\n\
+\tunsuccessful search, at the expense of extra table space. Default\n\
+\tvalue is 1. This actual table size may vary somewhat.\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\
+\tthe expense of longer time for each lookup. Mostly important for\n\
+\t*large* input sets, i.e., greater than around 100 items or so.\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%e%a\n",
+ usage);
+ }
+ case 'H': /* Sets the name for the hash function */
+ {
+ option.hash_name = optarg;
+ break;
+ }
+ case 'i': /* Sets the initial value for the associated values array. */
+ {
+ if ((option.initial_asso_value = atoi (optarg)) < 0)
+ report_error ("initial value %d must be non-zero, ignoring and continuing\n",
+ option.initial_asso_value);
+ if (OPTION_ENABLED (option, RANDOM))
+ report_error ("warning, -r option superceeds -i, ignoring -i option and continuing\n");
+ break;
+ }
+ case 'j': /* Sets the jump value, must be odd for later algorithms. */
+ {
+ if ((option.jump = atoi (optarg)) < 0)
+ report_error ("jump value %d must be a positive number\n%e%a",
+ option.jump, usage);
+ else if (option.jump && EVEN (option.jump))
+ report_error ("jump value %d should be odd, adding 1 and continuing...\n",
+ option.jump++);
+ break;
+ }
+ case 'k': /* Sets key positions used for hash function. */
+ {
+ int BAD_VALUE = -1;
+ int value;
+
+ iterator_init (optarg, 1, MAX_KEY_POS - 1, WORD_END, BAD_VALUE, EOS);
+
+ if (*optarg == '*') /* Use all the characters for hashing!!!! */
+ {
+ UNSET_OPTION (option, DEFAULTCHARS);
+ SET_OPTION (option, ALLCHARS);
+ }
+ else
+ {
+ char *key_pos;
+
+ for (key_pos = option.key_positions; (value = next ()) != EOS; key_pos++)
+ if (value == BAD_VALUE)
+ report_error ("illegal key value or range, use 1,2,3-%d,'$' or '*'.\n%e%a",
+ (MAX_KEY_POS - 1),usage);
+ else
+ *key_pos = value;;
+
+ *key_pos = EOS;
+
+ if (! (option.total_charset_size = (key_pos - option.key_positions)))
+ report_error ("no keys selected\n%e%a", usage);
+ else if (! key_sort (option.key_positions, option.total_charset_size))
+ report_error ("duplicate keys selected\n%e%a", usage);
+
+ if (option.total_charset_size != 2
+ || (option.key_positions[0] != 1 || option.key_positions[1] != WORD_END))
+ UNSET_OPTION (option, DEFAULTCHARS);
+ }
+ break;
+ }
+ case 'K': /* Make this the keyname for the keyword component field. */
+ {
+ option.key_name = optarg;
+ break;
+ }
+ case 'l': /* Create length table to avoid extra string compares. */
+ {
+ SET_OPTION (option, LENTABLE);
+ break;
+ }
+ case 'n': /* Don't include the length when computing hash function. */
+ {
+ SET_OPTION (option, NOLENGTH);
+ break;
+ }
+ case 'N': /* Make generated lookup function name be optarg */
+ {
+ option.function_name = optarg;
+ break;
+ }
+ case 'o': /* Order input by frequency of key set occurrence. */
+ {
+ SET_OPTION (option, ORDER);
+ break;
+ }
+ case 'p': /* Generated lookup function now a pointer instead of int. */
+ {
+ SET_OPTION (option, POINTER);
+ break;
+ }
+ case 'r': /* Utilize randomness to initialize the associated values table. */
+ {
+ SET_OPTION (option, RANDOM);
+ if (option.initial_asso_value != 0)
+ report_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 ((option.size = atoi (optarg)) <= 0)
+ report_error ("improper range argument %s\n%e%a", optarg, usage);
+ else if (option.size > 50)
+ report_error ("%d is excessive, did you really mean this?! (type %n -h for help)\n",
+ option.size);
+ break;
+ }
+ case 'S': /* Generate switch statement output, rather than lookup table. */
+ {
+ SET_OPTION (option, SWITCH);
+ if ((option.total_switches = atoi (optarg)) <= 0)
+ report_error ("number of switches %s must be a positive number\n%e%a", optarg, usage);
+ break;
+ }
+ case 't': /* Enable the TYPE mode, allowing arbitrary user structures. */
+ {
+ SET_OPTION (option, TYPE);
+ break;
+ }
+ case 'T': /* Don't print structure definition. */
+ {
+ SET_OPTION (option, NOTYPE);
+ break;
+ }
+ case 'v': /* Print out the version and quit. */
+ report_error ("%n: version %s\n%e%a\n", version_string, usage);
+ default:
+ report_error ("%e%a", usage);
+ }
+ }
+
+ if (argv[optind] && ! freopen (argv[optind], "r", stdin))
+ report_error ("unable to read key word file %s\n%e%a", argv[optind], usage);
+
+ if (++optind < argc)
+ report_error ("extra trailing arguments to %n\n%e%a", usage);
+}
+
+/* Output command-line Options. */
+void
+print_options ()
+{
+ int i;
+
+ printf ("/* Command-line: ");
+
+ for (i = 0; i < option.argument_count; i++)
+ printf ("%s ", option.argument_vector[i]);
+
+ printf (" */\n\n");
+}
+
diff --git a/src/options.cc b/src/options.cc
new file mode 100644
index 000000000000..d15e21cee8ce
--- /dev/null
+++ b/src/options.cc
@@ -0,0 +1,727 @@
+/* Handles parsing the Options provided to the user.
+ Copyright (C) 1989-1998, 2000 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 <stdio.h>
+#include <stdlib.h> /* declares atoi(), abs(), exit() */
+#include <string.h> /* declares strcmp() */
+#include "getopt.h"
+#include "options.h"
+#include "iterator.h"
+#include "trace.h"
+#include "vectors.h"
+#include "version.h"
+
+/* Global option coordinator for the entire program. */
+Options option;
+
+/* Records the program name. */
+const char *program_name;
+
+/* 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 struct initializer suffix. */
+static const char *const DEFAULT_INITIALIZER_SUFFIX = "";
+
+/* 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 name for generated hash table array. */
+static const char *const DEFAULT_WORDLIST_NAME = "wordlist";
+
+/* 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::initializer_suffix;
+const char *Options::class_name;
+const char *Options::hash_name;
+const char *Options::wordlist_name;
+const char *Options::delimiters;
+char Options::key_positions[MAX_KEY_POS];
+
+/* Prints program usage to given stream. */
+
+void
+Options::short_usage (FILE * strm)
+{
+ T (Trace t ("Options::short_usage");)
+ fprintf (strm, "Usage: %s [-cCdDef[num]F<initializers>GhH<hashname>i<init>Ijk<keys>K<keyname>lL<language>nN<function name>ors<size>S<switches>tTvW<wordlistname>Z<class name>7] [input-file]\n"
+ "Try `%s --help' for more information.\n",
+ program_name, program_name);
+}
+
+void
+Options::long_usage (FILE * strm)
+{
+ T (Trace t ("Options::long_usage");)
+ fprintf (strm,
+ "GNU `gperf' generates perfect hash functions.\n"
+ "\n"
+ "Usage: %s [OPTION]... [INPUT-FILE]\n"
+ "\n"
+ "If a long option shows an argument as mandatory, then it is mandatory\n"
+ "for the equivalent short option also.\n"
+ "\n"
+ "Input file interpretation:\n"
+ " -e, --delimiters=DELIMITER-LIST\n"
+ " Allow user to provide a string containing delimiters\n"
+ " used to separate keywords from their attributes.\n"
+ " Default is \",\\n\".\n"
+ " -t, --struct-type Allows the user to include a structured type\n"
+ " declaration for generated code. Any text before %%%%\n"
+ " is considered part of the type declaration. Key\n"
+ " words and additional fields may follow this, one\n"
+ " group of fields per line.\n"
+ "\n"
+ "Language for the output code:\n"
+ " -L, --language=LANGUAGE-NAME\n"
+ " Generates code in the specified language. Languages\n"
+ " handled are currently C++, ANSI-C, C, and KR-C. The\n"
+ " default is C.\n"
+ "\n"
+ "Details in the output code:\n"
+ " -K, --slot-name=NAME Select name of the keyword component in the keyword\n"
+ " structure.\n"
+ " -F, --initializer-suffix=INITIALIZERS\n"
+ " Initializers for additional components in the keyword\n"
+ " structure.\n"
+ " -H, --hash-fn-name=NAME\n"
+ " Specify name of generated hash function. Default is\n"
+ " `hash'.\n"
+ " -N, --lookup-fn-name=NAME\n"
+ " Specify name of generated lookup function. Default\n"
+ " name is `in_word_set'.\n"
+ " -Z, --class-name=NAME Specify name of generated C++ class. Default name is\n"
+ " `Perfect_Hash'.\n"
+ " -7, --seven-bit Assume 7-bit characters.\n"
+ " -c, --compare-strncmp Generate comparison code using strncmp rather than\n"
+ " strcmp.\n"
+ " -C, --readonly-tables Make the contents of generated lookup tables\n"
+ " constant, i.e., readonly.\n"
+ " -E, --enum Define constant values using an enum local to the\n"
+ " lookup function rather than with defines.\n"
+ " -I, --includes Include the necessary system include file <string.h>\n"
+ " at the beginning of the code.\n"
+ " -G, --global Generate the static table of keywords as a static\n"
+ " global variable, rather than hiding it inside of the\n"
+ " lookup function (which is the default behavior).\n"
+ " -W, --word-array-name=NAME\n"
+ " Specify name of word list array. Default name is\n"
+ " `wordlist'.\n"
+ " -S, --switch=COUNT Causes the generated C code to use a switch\n"
+ " statement scheme, rather than an array lookup table.\n"
+ " This can lead to a reduction in both time and space\n"
+ " requirements for some keyfiles. The COUNT argument\n"
+ " determines how many switch statements are generated.\n"
+ " A value of 1 generates 1 switch containing all the\n"
+ " elements, a value of 2 generates 2 tables with 1/2\n"
+ " the elements in each table, etc. If COUNT is very\n"
+ " large, say 1000000, the generated C code does a\n"
+ " binary search.\n"
+ " -T, --omit-struct-type\n"
+ " Prevents the transfer of the type declaration to the\n"
+ " output file. Use this option if the type is already\n"
+ " defined elsewhere.\n"
+ "\n"
+ "Algorithm employed by gperf:\n"
+ " -k, --key-positions=KEYS\n"
+ " Select the key positions used in the hash function.\n"
+ " The allowable choices range between 1-%d, inclusive.\n"
+ " The positions are separated by commas, ranges may be\n"
+ " used, and key positions may occur in any order.\n"
+ " Also, the meta-character '*' causes the generated\n"
+ " hash function to consider ALL key positions, and $\n"
+ " indicates the ``final character'' of a key, e.g.,\n"
+ " $,1,2,4,6-10.\n"
+ " -l, --compare-strlen Compare key lengths before trying a string\n"
+ " comparison. This helps cut down on the number of\n"
+ " string comparisons made during the lookup.\n"
+ " -D, --duplicates Handle keywords that hash to duplicate values. This\n"
+ " is useful for certain highly redundant keyword sets.\n"
+ " -f, --fast=ITERATIONS Generate the gen-perf.hash function ``fast''. This\n"
+ " decreases gperf's running time at the cost of\n"
+ " minimizing generated table size. The numeric\n"
+ " argument represents the number of times to iterate\n"
+ " when resolving a collision. `0' means ``iterate by\n"
+ " the number of keywords''.\n"
+ " -i, --initial-asso=N Provide an initial value for the associate values\n"
+ " array. Default is 0. Setting this value larger helps\n"
+ " inflate the size of the final table.\n"
+ " -j, --jump=JUMP-VALUE Affects the ``jump value'', i.e., how far to advance\n"
+ " the associated character value upon collisions. Must\n"
+ " be an odd number, default is %d.\n"
+ " -n, --no-strlen Do not include the length of the keyword when\n"
+ " computing the hash function.\n"
+ " -o, --occurrence-sort Reorders input keys by frequency of occurrence of\n"
+ " the key sets. This should decrease the search time\n"
+ " dramatically.\n"
+ " -r, --random Utilizes randomness to initialize the associated\n"
+ " values table.\n"
+ " -s, --size-multiple=N Affects the size of the generated hash table. The\n"
+ " numeric argument N indicates ``how many times larger\n"
+ " or smaller'' the associated value range should be,\n"
+ " in relationship to the number of keys, e.g. a value\n"
+ " of 3 means ``allow the maximum associated value to\n"
+ " be about 3 times larger than the number of input\n"
+ " keys.'' Conversely, a value of -3 means ``make the\n"
+ " maximum associated value about 3 times smaller than\n"
+ " the number of input keys. A larger table should\n"
+ " decrease the time required for an unsuccessful\n"
+ " search, at the expense of extra table space. Default\n"
+ " value is 1.\n"
+ "\n"
+ "Informative output:\n"
+ " -h, --help Print this message.\n"
+ " -v, --version Print the gperf version number.\n"
+ " -d, --debug Enables the debugging option (produces verbose\n"
+ " output to the standard error).\n"
+ "\n"
+ "Report bugs to <bug-gnu-utils@gnu.org>.\n"
+ , program_name, MAX_KEY_POS - 1, DEFAULT_JUMP_VALUE);
+}
+
+/* Output command-line Options. */
+
+void
+Options::print_options (void)
+{
+ T (Trace t ("Options::print_options");)
+ int i;
+
+ printf ("/* Command-line: ");
+
+ for (i = 0; i < argument_count; i++)
+ {
+ const char *arg = argument_vector[i];
+
+ /* Escape arg if it contains shell metacharacters. */
+ if (*arg == '-')
+ {
+ putchar (*arg);
+ arg++;
+ if (*arg >= 'A' && *arg <= 'Z' || *arg >= 'a' && *arg <= 'z')
+ {
+ putchar (*arg);
+ arg++;
+ }
+ }
+ if (strpbrk (arg, "\t\n !\"#$&'()*;<>?[\\]`{|}~") != NULL)
+ {
+ if (strchr (arg, '\'') != NULL)
+ {
+ putchar ('"');
+ for (; *arg; arg++)
+ {
+ if (*arg == '\"' || *arg == '\\' || *arg == '$')
+ putchar ('\\');
+ putchar (*arg);
+ }
+ putchar ('"');
+ }
+ else
+ {
+ putchar ('\'');
+ for (; *arg; arg++)
+ {
+ if (*arg == '\\')
+ putchar ('\\');
+ putchar (*arg);
+ }
+ putchar ('\'');
+ }
+ }
+ else
+ printf ("%s", arg);
+
+ printf (" ");
+ }
+
+ 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)
+{
+ T (Trace t ("Options::key_sort");)
+ 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)
+{
+ T (Trace t ("Options::Options");)
+ 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;
+ initializer_suffix = DEFAULT_INITIALIZER_SUFFIX;
+ hash_name = DEFAULT_HASH_NAME;
+ wordlist_name = DEFAULT_WORDLIST_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)
+{
+ T (Trace t ("Options::~Options");)
+ if (option_word & DEBUG)
+ {
+ char *ptr;
+
+ fprintf (stderr, "\ndumping Options:"
+ "\nDEBUG is.......: %s"
+ "\nORDER is.......: %s"
+ "\nTYPE is........: %s"
+ "\nRANDOM is......: %s"
+ "\nDEFAULTCHARS is: %s"
+ "\nSWITCH 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"
+ "\nKRC is.........: %s"
+ "\nC is...........: %s"
+ "\nANSIC is.......: %s"
+ "\nCPLUSPLUS is...: %s"
+ "\nENUM is........: %s"
+ "\nINCLUDE is.....: %s"
+ "\nSEVENBIT is....: %s"
+ "\niterations = %d"
+ "\nlookup function name = %s"
+ "\nhash function name = %s"
+ "\nword list name = %s"
+ "\nkey name = %s"
+ "\ninitializer suffix = %s"
+ "\njump value = %d"
+ "\nmax associated 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 & TYPE ? "enabled" : "disabled",
+ option_word & RANDOM ? "enabled" : "disabled",
+ option_word & DEFAULTCHARS ? "enabled" : "disabled",
+ option_word & SWITCH ? "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 & KRC ? "enabled" : "disabled",
+ option_word & C ? "enabled" : "disabled",
+ option_word & ANSIC ? "enabled" : "disabled",
+ option_word & CPLUSPLUS ? "enabled" : "disabled",
+ option_word & ENUM ? "enabled" : "disabled",
+ option_word & INCLUDE ? "enabled" : "disabled",
+ option_word & SEVENBIT ? "enabled" : "disabled",
+ iterations,
+ function_name, hash_name, wordlist_name, key_name,
+ initializer_suffix, 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. */
+
+static const struct option long_options[] =
+{
+ { "delimiters", required_argument, 0, 'e' },
+ { "struct-type", no_argument, 0, 't' },
+ { "language", required_argument, 0, 'L' },
+ { "slot-name", required_argument, 0, 'K' },
+ { "initializer-suffix", required_argument, 0, 'F' },
+ { "hash-fn-name", required_argument, 0, 'H' },
+ { "lookup-fn-name", required_argument, 0, 'N' },
+ { "class-name", required_argument, 0, 'Z' },
+ { "seven-bit", no_argument, 0, '7' },
+ { "compare-strncmp", no_argument, 0, 'c' },
+ { "readonly-tables", no_argument, 0, 'C' },
+ { "enum", no_argument, 0, 'E' },
+ { "includes", no_argument, 0, 'I' },
+ { "global", no_argument, 0, 'G' },
+ { "word-array-name", required_argument, 0, 'W' },
+ { "switch", required_argument, 0, 'S' },
+ { "omit-struct-type", no_argument, 0, 'T' },
+ { "key-positions", required_argument, 0, 'k' },
+ { "compare-strlen", no_argument, 0, 'l' },
+ { "duplicates", no_argument, 0, 'D' },
+ { "fast", required_argument, 0, 'f' },
+ { "initial-asso", required_argument, 0, 'i' },
+ { "jump", required_argument, 0, 'j' },
+ { "no-strlen", no_argument, 0, 'n' },
+ { "occurrence-sort", no_argument, 0, 'o' },
+ { "random", no_argument, 0, 'r' },
+ { "size-multiple", required_argument, 0, 's' },
+ { "help", no_argument, 0, 'h' },
+ { "version", no_argument, 0, 'v' },
+ { "debug", no_argument, 0, 'd' },
+ { 0, no_argument, 0, 0 }
+};
+
+void
+Options::operator() (int argc, char *argv[])
+{
+ T (Trace t ("Options::operator()");)
+ int option_char;
+
+ program_name = argv[0];
+ argument_count = argc;
+ argument_vector = argv;
+
+ while ((option_char =
+ getopt_long (argument_count, argument_vector,
+ "adcCDe:Ef:F:gGhH:i:Ij:k:K:lL:nN:oprs:S:tTvW:Z:7",
+ long_options, (int *)0))
+ != -1)
+ {
+ switch (option_char)
+ {
+ case 'a': /* Generated code uses the ANSI prototype format. */
+ break; /* This is now the default. */
+ 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;
+ fprintf (stderr, "Starting program %s, version %s, with debugging on.\n",
+ program_name, 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)
+ {
+ fprintf (stderr, "iterations value must not be negative, assuming 0\n");
+ iterations = 0;
+ }
+ break;
+ }
+ case 'F':
+ {
+ initializer_suffix = /*getopt*/optarg;
+ break;
+ }
+ case 'g': /* Use the ``inline'' keyword for generated sub-routines, ifdef __GNUC__. */
+ break; /* This is now the default. */
+ case 'G': /* Make the keyword table a global variable. */
+ {
+ option_word |= GLOBAL;
+ break;
+ }
+ case 'h': /* Displays a list of helpful Options to the user. */
+ {
+ long_usage (stdout);
+ exit (0);
+ }
+ 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)
+ fprintf (stderr, "Initial value %d should be non-zero, ignoring and continuing.\n", initial_asso_value);
+ if (option[RANDOM])
+ fprintf (stderr, "warning, -r option superceeds -i, ignoring -i option and continuing\n");
+ break;
+ }
+ case 'I': /* Enable #include statements. */
+ {
+ option_word |= INCLUDE;
+ break;
+ }
+ case 'j': /* Sets the jump value, must be odd for later algorithms. */
+ {
+ if ((jump = atoi (/*getopt*/optarg)) < 0)
+ {
+ fprintf (stderr, "Jump value %d must be a positive number.\n", jump);
+ short_usage (stderr);
+ exit (1);
+ }
+ else if (jump && ((jump % 2) == 0))
+ fprintf (stderr, "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 [0] == '*') /* Use all the characters for hashing!!!! */
+ option_word = (option_word & ~DEFAULTCHARS) | ALLCHARS;
+ else
+ {
+ char *key_pos;
+
+ for (key_pos = key_positions; (value = expand ()) != EOS; key_pos++)
+ if (value == BAD_VALUE)
+ {
+ fprintf (stderr, "Illegal key value or range, use 1,2,3-%d,'$' or '*'.\n",
+ MAX_KEY_POS - 1);
+ short_usage (stderr);
+ exit (1);
+ }
+ else
+ *key_pos = value;;
+
+ *key_pos = EOS;
+
+ if (! (total_keysig_size = (key_pos - key_positions)))
+ {
+ fprintf (stderr, "No keys selected.\n");
+ short_usage (stderr);
+ exit (1);
+ }
+ else if (! key_sort (key_positions, total_keysig_size))
+ {
+ fprintf (stderr, "Duplicate keys selected\n");
+ short_usage (stderr);
+ exit (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 &= ~(KRC | C | ANSIC | CPLUSPLUS);
+ if (!strcmp (/*getopt*/optarg, "KR-C"))
+ option_word |= KRC;
+ else if (!strcmp (/*getopt*/optarg, "C"))
+ option_word |= C;
+ else if (!strcmp (/*getopt*/optarg, "ANSI-C"))
+ option_word |= ANSIC;
+ else if (!strcmp (/*getopt*/optarg, "C++"))
+ option_word |= CPLUSPLUS;
+ else
+ {
+ fprintf (stderr, "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 'p': /* Generated lookup function a pointer instead of int. */
+ break; /* This is now the default. */
+ case 'r': /* Utilize randomness to initialize the associated values table. */
+ {
+ option_word |= RANDOM;
+ if (option.initial_asso_value != 0)
+ fprintf (stderr, "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)
+ fprintf (stderr, "%d is excessive, did you really mean this?! (try `%s --help' for help)\n", size, program_name);
+ break;
+ }
+ case 'S': /* Generate switch statement output, rather than lookup table. */
+ {
+ option_word |= SWITCH;
+ if ((option.total_switches = atoi (/*getopt*/optarg)) <= 0)
+ {
+ fprintf (stderr, "number of switches %s must be a positive number\n", /*getopt*/optarg);
+ short_usage (stderr);
+ exit (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. */
+ fprintf (stdout, "GNU gperf %s\n", version_string);
+ exit (0);
+ case 'W': /* Sets the name for the hash table array */
+ {
+ wordlist_name = /*getopt*/optarg;
+ break;
+ }
+ case 'Z': /* Set the class name. */
+ {
+ class_name = /*getopt*/optarg;
+ break;
+ }
+ case '7': /* Assume 7-bit characters. */
+ {
+ option_word |= SEVENBIT;
+ Vectors::ALPHA_SIZE = 128;
+ break;
+ }
+ default:
+ short_usage (stderr);
+ exit (1);
+ }
+
+ }
+
+ if (argv[/*getopt*/optind] && ! freopen (argv[/*getopt*/optind], "r", stdin))
+ {
+ fprintf (stderr, "Cannot open keyword file `%s'\n", argv[/*getopt*/optind]);
+ short_usage (stderr);
+ exit (1);
+ }
+
+ if (++/*getopt*/optind < argc)
+ {
+ fprintf (stderr, "Extra trailing arguments to %s.\n", program_name);
+ short_usage (stderr);
+ exit (1);
+ }
+}
+
+#ifndef __OPTIMIZE__
+
+#define INLINE /* not inline */
+#include "options.icc"
+#undef INLINE
+
+#endif /* not defined __OPTIMIZE__ */
diff --git a/src/options.h b/src/options.h
new file mode 100644
index 000000000000..9025c86f1732
--- /dev/null
+++ b/src/options.h
@@ -0,0 +1,159 @@
+/* This may look like C code, but it is really -*- C++ -*- */
+
+/* Handles parsing the Options provided to the user.
+
+ Copyright (C) 1989-1998, 2000 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 <stdio.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. */
+ ALLCHARS = 04, /* Use all characters in hash function. */
+ TYPE = 010, /* Handle user-defined type structured keyword input. */
+ RANDOM = 020, /* Randomly initialize the associated values table. */
+ DEFAULTCHARS = 040, /* Make default char positions be 1,$ (end of keyword). */
+ SWITCH = 0100, /* Generate switch output to save space. */
+ NOLENGTH = 0200, /* Don't include keyword length in hash computations. */
+ LENTABLE = 0400, /* Generate a length table for string comparison. */
+ DUP = 01000, /* Handle duplicate hash values for keywords. */
+ FAST = 02000, /* Generate the hash function ``fast.'' */
+ NOTYPE = 04000, /* Don't include user-defined type definition in output -- it's already defined elsewhere. */
+ COMP = 010000, /* Generate strncmp rather than strcmp. */
+ GLOBAL = 020000, /* Make the keyword table a global variable. */
+ CONST = 040000, /* Make the generated tables readonly (const). */
+ KRC = 0100000, /* Generate K&R C code: no prototypes, no const. */
+ C = 0200000, /* Generate C code: no prototypes, but const (user can #define it away). */
+ ANSIC = 0400000, /* Generate ISO/ANSI C code: prototypes and const, but no class. */
+ CPLUSPLUS = 01000000, /* Generate C++ code: prototypes, const, class, inline, enum. */
+ ENUM = 02000000, /* Use enum for constants. */
+ INCLUDE = 04000000, /* Generate #include statements. */
+ SEVENBIT = 010000000 /* Assume 7-bit, not 8-bit, characters. */
+};
+
+/* 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_initializer_suffix (void);
+ static const char *get_class_name (void);
+ static const char *get_hash_name (void);
+ static const char *get_wordlist_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 *initializer_suffix; /* Suffix for empty struct initializers. */
+ 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 *wordlist_name; /* Name used for hash table array. */
+ 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 short_usage (FILE * strm); /* Prints proper program usage. */
+ static void long_usage (FILE * strm); /* 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.
+ This requires compiler support for variable-size arrays on the stack
+ (not ANSI). */
+#ifndef LARGE_STACK_ARRAYS
+#if defined(__GNUG__) && !defined(__STRICT_ANSI__)
+#define LARGE_STACK_ARRAYS 1
+#else
+#define LARGE_STACK_ARRAYS 0
+#endif
+#endif
+
+/* Set to 1 if the stack is large enough for holding a text line. */
+#ifndef LARGE_STACK
+#define LARGE_STACK 1
+#endif
+
+#ifdef __OPTIMIZE__
+
+#include "trace.h"
+#define INLINE inline
+#include "options.icc"
+#undef INLINE
+
+#endif
+
+#endif
diff --git a/src/options.icc b/src/options.icc
new file mode 100644
index 000000000000..82fe5375c23f
--- /dev/null
+++ b/src/options.icc
@@ -0,0 +1,183 @@
+/* Inline Functions for options.{h,cc}.
+
+ Copyright (C) 1989-1998, 2000 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 needs:
+//#include "trace.h"
+
+/* TRUE if option enable, else FALSE. */
+INLINE int
+Options::operator[] (Option_Type option)
+{
+ T (Trace t ("Options::operator[]");)
+ return option_word & option;
+}
+
+/* Enables option OPT. */
+INLINE void
+Options::operator = (enum Option_Type opt)
+{
+ T (Trace t ("Options::operator=");)
+ option_word |= opt;
+}
+
+/* Disables option OPT. */
+INLINE void
+Options::operator != (enum Option_Type opt)
+{
+ T (Trace t ("Options::operator!=");)
+ option_word &= ~opt;
+}
+
+/* Initializes the key Iterator. */
+INLINE void
+Options::reset (void)
+{
+ T (Trace t ("Options::reset");)
+ key_pos = 0;
+}
+
+/* Returns current key_position and advance index. */
+INLINE int
+Options::get (void)
+{
+ T (Trace t ("Options::get");)
+ return key_positions[key_pos++];
+}
+
+/* Sets the size of the table size. */
+INLINE void
+Options::set_asso_max (int r)
+{
+ T (Trace t ("Options::set_asso_max");)
+ size = r;
+}
+
+/* Returns the size of the table size. */
+INLINE int
+Options::get_asso_max (void)
+{
+ T (Trace t ("Options::get_asso_max");)
+ return size;
+}
+
+/* Returns total distinct key positions. */
+INLINE int
+Options::get_max_keysig_size (void)
+{
+ T (Trace t ("Options::get_max_keysig_size");)
+ return total_keysig_size;
+}
+
+/* Sets total distinct key positions. */
+INLINE void
+Options::set_keysig_size (int size)
+{
+ T (Trace t ("Options::set_keysig_size");)
+ total_keysig_size = size;
+}
+
+/* Returns the jump value. */
+INLINE int
+Options::get_jump (void)
+{
+ T (Trace t ("Options::get_jump");)
+ return jump;
+}
+
+/* Returns the generated function name. */
+INLINE const char *
+Options::get_function_name (void)
+{
+ T (Trace t ("Options::get_function_name");)
+ return function_name;
+}
+
+/* Returns the keyword key name. */
+INLINE const char *
+Options::get_key_name (void)
+{
+ T (Trace t ("Options::get_key_name");)
+ return key_name;
+}
+
+/* Returns the struct initializer suffix. */
+INLINE const char *
+Options::get_initializer_suffix (void)
+{
+ T (Trace t ("Options::get_initializer_suffix");)
+ return initializer_suffix;
+}
+
+/* Returns the hash function name. */
+INLINE const char *
+Options::get_hash_name (void)
+{
+ T (Trace t ("Options::get_hash_name");)
+ return hash_name;
+}
+
+/* Returns the hash table array name. */
+INLINE const char *
+Options::get_wordlist_name (void)
+{
+ T (Trace t ("Options::get_wordlist_name");)
+ return wordlist_name;
+}
+
+/* Returns the generated class name. */
+INLINE const char *
+Options::get_class_name (void)
+{
+ T (Trace t ("Options::get_class_name");)
+ return class_name;
+}
+
+/* Returns the initial associated character value. */
+INLINE int
+Options::initial_value (void)
+{
+ T (Trace t ("Options::initial_value");)
+ return initial_asso_value;
+}
+
+/* Returns the iterations value. */
+INLINE int
+Options::get_iterations (void)
+{
+ T (Trace t ("Options::get_iterations");)
+ return iterations;
+}
+
+/* Returns the string used to delimit keywords from other attributes. */
+INLINE const char *
+Options::get_delimiter ()
+{
+ T (Trace t ("Options::get_delimiter");)
+ return delimiters;
+}
+
+/* Gets the total number of switch statements to generate. */
+INLINE int
+Options::get_total_switches ()
+{
+ T (Trace t ("Options::get_total_switches");)
+ return total_switches;
+}
diff --git a/src/perfect.c b/src/perfect.c
new file mode 100644
index 000000000000..25b958e2e44e
--- /dev/null
+++ b/src/perfect.c
@@ -0,0 +1,350 @@
+/* Provides high-level routines to manipulate the keywork 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+#include "options.h"
+#include "perfect.h"
+#include "stderr.h"
+
+/* Current release version. */
+extern char *version_string;
+
+/* Counts occurrences of each key set character. */
+int occurrences[ALPHABET_SIZE];
+
+/* Value associated with each character. */
+int asso_values[ALPHABET_SIZE];
+
+/* Locally visible PERFECT object. */
+PERFECT perfect;
+
+/* Efficiently returns the least power of two greater than or equal to X! */
+#define POW(X) ((!X)?1:(X-=1,X|=X>>1,X|=X>>2,X|=X>>4,X|=X>>8,X|=X>>16,(++X)))
+
+/* 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! */
+
+void
+perfect_init ()
+{
+ int asso_value_max;
+ int len;
+
+ perfect.num_done = 1;
+ perfect.fewest_collisions = 0;
+ read_keys ();
+ if (OPTION_ENABLED (option, ORDER))
+ reorder ();
+ asso_value_max = GET_ASSO_MAX (option);
+ len = keyword_list_length ();
+ asso_value_max = (asso_value_max ? asso_value_max * len : len);
+ SET_ASSO_MAX (option, POW (asso_value_max));
+
+ if (OPTION_ENABLED (option, RANDOM))
+ {
+ int i;
+
+ srandom (time (0));
+
+ for (i = 0; i < ALPHABET_SIZE; i++)
+ asso_values[i] = (random () & asso_value_max - 1);
+ }
+ else
+ {
+ int asso_value = INITIAL_VALUE (option);
+ if (asso_value) /* Initialize array if user requests non-zero default. */
+ {
+ int i;
+
+ for (i = ALPHABET_SIZE - 1; i >= 0; i--)
+ asso_values[i] = asso_value & GET_ASSO_MAX (option) - 1;
+ }
+ }
+ perfect.max_hash_value = max_key_length () + GET_ASSO_MAX (option) *
+ GET_CHARSET_SIZE (option);
+
+ printf ("/* C code produced by gperf version %s */\n", version_string);
+ print_options ();
+
+ if (OPTION_ENABLED (option, DEBUG))
+ {
+ int i;
+ fprintf (stderr, "\nnumber of keys = %d\nmaximum associated value is %d\
+\nmaximum possible size of generated hash table is %d\n",
+ len, asso_value_max, perfect.max_hash_value);
+ }
+}
+
+/* Merge two 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. */
+
+static int
+compute_disjoint_union (set_1, set_2, set_3)
+ 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. */
+
+static void
+sort_set (union_set, len)
+ 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 && occurrences[tmp] < occurrences[union_set[curr-1]];
+ curr--)
+ union_set[curr] = union_set[curr - 1];
+
+ union_set[curr] = tmp;
+ }
+}
+
+/* Generate a key set's hash value. */
+
+static int
+hash (key_node)
+ LIST_NODE *key_node;
+{
+ int sum = OPTION_ENABLED (option, NOLENGTH) ? 0 : key_node->length;
+ char *ptr;
+
+ for (ptr = key_node->char_set; *ptr; ptr++)
+ sum += asso_values[*ptr];
+
+ return key_node->hash_value = sum;
+}
+
+/* Find out how associated value changes affect successfully hashed items.
+ Returns FALSE if no other hash values are affected, else returns TRUE.
+ Note that because GET_ASSO_MAX (option) is a power of two we can guarantee
+ that all legal ASSO_VALUES are visited without repetition since
+ GET_JUMP (option) was forced to be an odd value! */
+
+static bool
+affects_prev (c, curr)
+ char c;
+ LIST_NODE *curr;
+{
+ int original_char = asso_values[c];
+ int i = !OPTION_ENABLED (option, FAST) ? GET_ASSO_MAX (option) :
+ GET_ITERATIONS (option) == 0 ? key_list.list_len : GET_ITERATIONS (option);
+
+ /* Try all asso_values. */
+
+ while (--i >= 0)
+ {
+ int collisions = 0;
+ LIST_NODE *ptr;
+
+ asso_values[c] = asso_values[c] + (GET_JUMP (option) ? GET_JUMP (option) : random ())
+ & GET_ASSO_MAX (option) - 1;
+ bool_array_reset ();
+
+ /* See how this asso_value change affects previous keywords. If
+ it does better than before we'll take it! */
+
+ for (ptr = key_list.head;
+ !lookup (hash (ptr)) || ++collisions < perfect.fewest_collisions;
+ ptr = ptr->next)
+ if (ptr == curr)
+ {
+ perfect.fewest_collisions = collisions;
+ return FALSE;
+ }
+ }
+
+ asso_values[c] = original_char; /* Restore original values, no more tries. */
+ return TRUE; /* If we're this far it's time to try the next character.... */
+}
+
+/* Change a character value, try least-used characters first. */
+
+static void
+change (prior, curr)
+ LIST_NODE *prior;
+ LIST_NODE *curr;
+{
+ char *xmalloc ();
+ static char *union_set = 0;
+ char *temp;
+ LIST_NODE *ptr;
+
+ if (!union_set)
+ union_set = xmalloc (2 * GET_CHARSET_SIZE (option) + 1);
+
+ if (OPTION_ENABLED (option, DEBUG)) /* Very useful for debugging. */
+ {
+ fprintf (stderr, "collision on keyword #%d, prior=\"%s\", curr=\"%s\", hash=%d\n",
+ perfect.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. */
+
+ perfect.fewest_collisions++;
+
+ for (temp = union_set; *temp; temp++)
+ if (!affects_prev (*temp, curr))
+ {
+ if (OPTION_ENABLED (option, DEBUG))
+ {
+ fprintf (stderr, "- resolved by changing asso_value['%c'] (char #%d) to %d\n",
+ *temp, temp - union_set + 1, asso_values[*temp]);
+ fflush (stderr);
+ }
+ return; /* Good, doesn't affect previous hash values, we'll take it. */
+ }
+
+ for (ptr = key_list.head; ptr != curr; ptr = ptr->next)
+ hash (ptr);
+
+ hash (curr);
+
+ if (OPTION_ENABLED (option, DEBUG))
+ {
+ fprintf (stderr, "** collision not resolved, %d duplicates remain, continuing...\n",
+ perfect.fewest_collisions);
+ fflush (stderr);
+ }
+}
+
+/* Does the hard stuff....
+ Initializes the Iteration Number boolean array, and then trys 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
+perfect_generate ()
+{
+ LIST_NODE *curr;
+ bool_array_init (perfect.max_hash_value);
+
+ for (curr = key_list.head; curr; curr = curr->next)
+ {
+ LIST_NODE *ptr;
+ hash (curr);
+
+ for (ptr = key_list.head; ptr != curr; ptr = ptr->next)
+ if (ptr->hash_value == curr->hash_value)
+ {
+ change (ptr, curr);
+ break;
+ }
+ perfect.num_done++;
+ }
+
+
+ /* Make one final check, just to make sure nothing weird happened.... */
+ bool_array_reset ();
+
+ for (curr = key_list.head; curr; curr = curr->next)
+ if (lookup (hash (curr)))
+ if (OPTION_ENABLED (option, DUP)) /* We'll try to deal with this later..... */
+ break;
+ else /* Yow, big problems. we're outta here! */
+ {
+ report_error ("\nInternal error, duplicate value %d:\n\
+try options -D or -r, or use new key positions.\n\n",
+ hash (curr));
+ return 1;
+ }
+
+ bool_array_destroy ();
+
+ /* First sorts the key word list by hash value, and the outputs the
+ list to the proper ostream. The generated hash table code is only
+ output if the early stage of processing turned out O.K. */
+
+ sort ();
+ print_output ();
+ return 0;
+}
+
+/* Prints out some diagnostics upon completion. */
+
+void
+perfect_destroy ()
+{
+ if (OPTION_ENABLED (option, DEBUG))
+ {
+ int i;
+
+ fprintf (stderr, "\ndumping occurrence and associated values tables\n");
+
+ for (i = 0; i < ALPHABET_SIZE; i++)
+ if (occurrences[i])
+ fprintf (stderr, "asso_values[%c] = %3d, occurrences[%c] = %3d\n",
+ i, asso_values[i], i, occurrences[i]);
+
+ fprintf (stderr, "end table dumping\n");
+
+ }
+}
+
diff --git a/src/perfect.h b/src/perfect.h
new file mode 100644
index 000000000000..c5b9443413d5
--- /dev/null
+++ b/src/perfect.h
@@ -0,0 +1,45 @@
+/* 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _perfect_h
+#define _perfect_h
+
+#include "prototype.h"
+#include "keylist.h"
+#include "boolarray.h"
+
+typedef struct perfect
+{
+ KEY_LIST list; /* List of key words provided by the user. */
+ BOOL_ARRAY duplicate; /* Speeds up check for redundant hash values. */
+ 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. */
+} PERFECT;
+
+extern void perfect_init P ((void));
+extern void perfect_destroy P ((void));
+extern int perfect_generate P ((void));
+extern void perfect_print P ((void));
+#endif /* _perfect_h */
+
+
diff --git a/src/prototype.h b/src/prototype.h
new file mode 100644
index 000000000000..a6077b65c206
--- /dev/null
+++ b/src/prototype.h
@@ -0,0 +1,15 @@
+#ifndef _prototype_h
+#define _prototype_h
+#ifdef __STDC__
+#define P(X) X
+#else
+#define P(X) ()
+#endif
+
+typedef char bool;
+#define FALSE 0
+#define TRUE 1
+
+#define ODD(X) ((X) & 1)
+#define EVEN(X) (!((X) & 1))
+#endif /* _prototype_h */
diff --git a/src/read-line.cc b/src/read-line.cc
new file mode 100644
index 000000000000..8cb0971cb6b9
--- /dev/null
+++ b/src/read-line.cc
@@ -0,0 +1,97 @@
+/* Correctly reads an arbitrarily size string.
+
+ Copyright (C) 1989-1998 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 "read-line.h"
+
+#include <stdlib.h>
+#include <string.h> /* declares memcpy() */
+#include "options.h"
+#include "trace.h"
+
+/* Recursively fills up the buffer. */
+
+#define CHUNK_SIZE 4096
+
+/* CHUNKS is the number of chunks (each of size CHUNK_SIZE) which have
+ already been read and which are temporarily stored on the stack.
+ This function reads the remainder of the line, allocates a buffer
+ for the entire line, fills the part beyond &buffer[chunks*CHUNK_SIZE],
+ and returns &buffer[chunks*CHUNK_SIZE]. */
+
+char *
+Read_Line::readln_aux (int chunks)
+{
+ T (Trace t ("Read_Line::readln_aux");)
+#if LARGE_STACK
+ char buf[CHUNK_SIZE];
+#else
+ // Note: we don't use new, because that invokes a custom operator new.
+ char *buf = (char*)malloc(CHUNK_SIZE);
+ if (buf == NULL)
+ abort ();
+#endif
+ char *bufptr = buf;
+ char *ptr;
+ int c;
+
+ while (c = getc (fp), c != EOF && c != '\n') /* fill the current buffer */
+ {
+ *bufptr++ = c;
+ if (bufptr - buf == CHUNK_SIZE)
+ {
+ if ((ptr = readln_aux (chunks + 1)) != NULL)
+
+ /* prepend remainder to ptr buffer */
+ {
+ ptr -= CHUNK_SIZE;
+ memcpy (ptr, buf, CHUNK_SIZE);
+ }
+
+ goto done;
+ }
+ }
+ if (c == EOF && bufptr == buf && chunks == 0)
+ ptr = NULL;
+ else
+ {
+ size_t s1 = chunks * CHUNK_SIZE;
+ size_t s2 = bufptr - buf;
+
+ ptr = new char[s1+s2+1];
+ ptr += s1;
+ ptr[s2] = '\0';
+ memcpy (ptr, buf, s2);
+ }
+ done:
+#if !LARGE_STACK
+ free (buf);
+#endif
+
+ return ptr;
+}
+
+#ifndef __OPTIMIZE__
+
+#define INLINE /* not inline */
+#include "read-line.icc"
+#undef INLINE
+
+#endif /* not defined __OPTIMIZE__ */
diff --git a/src/read-line.h b/src/read-line.h
new file mode 100644
index 000000000000..b243c84749b5
--- /dev/null
+++ b/src/read-line.h
@@ -0,0 +1,53 @@
+/* This may look like C code, but it is really -*- C++ -*- */
+
+/* Reads arbitrarily long string from input file, returning it as a
+ dynamically allocated buffer.
+
+ Copyright (C) 1989-1998 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. */
+
+/* Returns a pointer to an arbitrary length string. Returns NULL on error or EOF
+ The storage for the string is dynamically allocated by new. */
+
+#ifndef read_line_h
+#define read_line_h 1
+
+#include <stdio.h>
+
+class Read_Line
+{
+private:
+ char *readln_aux (int chunks);
+ FILE *fp; /* FILE pointer to the input stream. */
+
+public:
+ Read_Line (FILE *stream = stdin) : fp (stream) {}
+ char *get_line (void);
+};
+
+#ifdef __OPTIMIZE__
+
+#include "trace.h"
+#define INLINE inline
+#include "read-line.icc"
+#undef INLINE
+
+#endif
+
+#endif
diff --git a/src/read-line.icc b/src/read-line.icc
new file mode 100644
index 000000000000..cdb5bf6f8c0a
--- /dev/null
+++ b/src/read-line.icc
@@ -0,0 +1,47 @@
+/* Inline Functions for read-line.{h,cc}.
+
+ Copyright (C) 1989-1998 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 needs:
+//#include <stdio.h>
+//#include "trace.h"
+
+/* Returns the ``next'' line, ignoring comments beginning with '#'. */
+INLINE char *
+Read_Line::get_line (void)
+{
+ T (Trace t ("Read_Line::get_line");)
+ int c;
+
+ while ((c = getc (fp)) == '#')
+ {
+ while (c = getc (fp), c != EOF && c != '\n')
+ ;
+
+ if (c == EOF)
+ return (char *)0;
+ }
+
+ if (c == EOF)
+ return (char *)0;
+
+ ungetc (c, stdin);
+ return readln_aux (0);
+}
diff --git a/src/readline.c b/src/readline.c
new file mode 100644
index 000000000000..19ac5e56366c
--- /dev/null
+++ b/src/readline.c
@@ -0,0 +1,87 @@
+/* Correctly reads an arbitrarily size string.
+
+ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "readline.h"
+
+/* Size of each chunk. */
+#define CHUNK_SIZE BUFSIZ
+
+/* Recursively fills up the buffer. */
+
+static char *
+readln_aux (chunks)
+ int chunks;
+{
+ char *buffered_malloc ();
+ char buf[CHUNK_SIZE];
+ register char *bufptr = buf;
+ register char *ptr;
+ int c;
+
+ while ((c = getchar ()) != EOF && c != '\n') /* fill the current buffer */
+ {
+ *bufptr++ = c;
+ if (bufptr - buf >= CHUNK_SIZE) /* prepend remainder to ptr buffer */
+ {
+ if (ptr = readln_aux (chunks + 1))
+
+ for (; bufptr != buf; *--ptr = *--bufptr);
+
+ return ptr;
+ }
+ }
+
+ if (c == EOF && bufptr == buf)
+ return NULL;
+
+ c = (chunks * CHUNK_SIZE + bufptr - buf) + 1;
+
+ if (ptr = buffered_malloc (c))
+ {
+
+ for (*(ptr += (c - 1)) = '\0'; bufptr != buf; *--ptr = *--bufptr)
+ ;
+
+ return ptr;
+ }
+ else
+ return NULL;
+}
+
+/* Returns the ``next'' line, ignoring comments beginning with '#'. */
+
+char *read_line ()
+{
+ int c;
+ if ((c = getchar ()) == '#')
+ {
+ while ((c = getchar ()) != '\n' && c != EOF)
+ ;
+
+ return c != EOF ? read_line () : NULL;
+ }
+ else
+ {
+ ungetc (c, stdin);
+ return readln_aux (0);
+ }
+}
diff --git a/src/readline.h b/src/readline.h
new file mode 100644
index 000000000000..13164d902bb9
--- /dev/null
+++ b/src/readline.h
@@ -0,0 +1,31 @@
+/* Reads arbitrarily long string from input file, returning it as a dynamic buffer.
+
+ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Returns a pointer to an arbitrary length string. Returns NULL on error or EOF
+ The storage for the string is dynamically allocated by new. */
+
+#ifndef _readline_h
+#define _readline_h
+#include "prototype.h"
+
+extern char *read_line P ((void));
+#endif /* _readline_h */
+
diff --git a/src/stderr.c b/src/stderr.c
new file mode 100644
index 000000000000..3f00dd50eebb
--- /dev/null
+++ b/src/stderr.c
@@ -0,0 +1,90 @@
+/* Provides a useful variable-length argument error handling abstraction.
+
+ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "stderr.h"
+
+/* Holds the name of the currently active program. */
+static char *program_name;
+
+/* Sets name of program. */
+
+void
+set_program_name (prog_name)
+ char *prog_name;
+{
+ program_name = prog_name;
+}
+
+/* Valid Options (prefixed by '%', as in printf format strings) include:
+ 'a': exit the program at this point
+ 'c': print a character
+ 'd': print a decimal number
+ 'e': call the function pointed to by the corresponding argument
+ 'f','g': print a double
+ 'n': print the name of the program (NULL if not set in constructor or elsewhere)
+ 'p': print out the appropriate errno value from sys_errlist
+ 's': print out a character string
+ '%': print out a single percent sign, '%' */
+
+void
+report_error (va_alist)
+ va_dcl
+{
+ extern int errno, sys_nerr;
+ extern char *sys_errlist[];
+ typedef void (*PTF)();
+ typedef char *CHARP;
+ va_list argp;
+ int abort = 0;
+ char *format;
+
+ va_start (argp);
+
+ for (format = va_arg (argp, char *); *format; format++)
+ {
+ if (*format != '%')
+ putc (*format, stderr);
+ else
+ {
+ switch(*++format)
+ {
+ case '%' : putc ('%', stderr); break;
+ case 'a' : abort = 1; break;
+ case 'c' : putc (va_arg (argp, int), stderr); break;
+ case 'd' : fprintf (stderr, "%d", va_arg (argp, int)); break;
+ case 'e' : (*va_arg (argp, PTF))(); break;
+ case 'f' : fprintf (stderr, "%g", va_arg (argp, double)); break;
+ case 'n' : fputs (program_name ? program_name : "error", stderr); break;
+ case 'p' :
+ if (errno < sys_nerr)
+ fprintf (stderr, "%s: %s", va_arg (argp, CHARP), sys_errlist[errno]);
+ else
+ fprintf (stderr, "<unknown error> %d", errno);
+ break;
+ case 's' : fputs (va_arg (argp, CHARP), stderr); break;
+ }
+ }
+ if (abort)
+ exit (1);
+ }
+ va_end (argp);
+}
diff --git a/src/stderr.h b/src/stderr.h
new file mode 100644
index 000000000000..a94255e4d004
--- /dev/null
+++ b/src/stderr.h
@@ -0,0 +1,29 @@
+/* Provides a useful variable-length argument error handling abstraction.
+
+ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _stderr_h
+#define _stderr_h
+#include "prototype.h"
+#include <varargs.h>
+
+extern void set_program_name P ((char *prog_name));
+extern void report_error ();
+#endif /* _stderr_h */
diff --git a/src/trace.cc b/src/trace.cc
new file mode 100644
index 000000000000..e571abae4239
--- /dev/null
+++ b/src/trace.cc
@@ -0,0 +1,35 @@
+/* Tracing function calls.
+ Copyright (C) 1989-1998 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 "trace.h"
+
+#include <stdio.h>
+
+int Trace::nesting = 0;
+
+Trace::Trace (const char *n)
+{
+ fprintf (stderr, "%*scalling %s\n", 3 * nesting++, "", name = n);
+}
+
+Trace::~Trace (void)
+{
+ fprintf (stderr, "%*sleaving %s\n", 3 * --nesting, "", name);
+}
diff --git a/src/trace.h b/src/trace.h
new file mode 100644
index 000000000000..f16fcc5bd99e
--- /dev/null
+++ b/src/trace.h
@@ -0,0 +1,40 @@
+/* Tracing function calls.
+ Copyright (C) 1989-1998 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 trace_h
+#define trace_h 1
+
+#ifdef TRACE
+#define T(X) X
+#else
+#define T(X)
+#endif
+
+class Trace
+{
+private:
+ static int nesting;
+ const char *name;
+public:
+ Trace (const char *n);
+ ~Trace (void);
+};
+
+#endif
diff --git a/src/vectors.cc b/src/vectors.cc
new file mode 100644
index 000000000000..1da014d4a31a
--- /dev/null
+++ b/src/vectors.cc
@@ -0,0 +1,25 @@
+/* Static class data members that are shared between several classes.
+ Copyright (C) 1989-1998 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"
+
+int Vectors::ALPHA_SIZE = MAX_ALPHA_SIZE;
+int Vectors::occurrences[MAX_ALPHA_SIZE];
+int Vectors::asso_values[MAX_ALPHA_SIZE];
diff --git a/src/vectors.h b/src/vectors.h
new file mode 100644
index 000000000000..28a105397ebb
--- /dev/null
+++ b/src/vectors.h
@@ -0,0 +1,37 @@
+/* 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-1998 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 MAX_ALPHA_SIZE = 256;
+
+struct Vectors
+{
+ static int ALPHA_SIZE; /* Size of alphabet. */
+ static int occurrences[MAX_ALPHA_SIZE]; /* Counts occurrences of each key set character. */
+ static int asso_values[MAX_ALPHA_SIZE]; /* Value associated with each character. */
+};
+
+#endif
diff --git a/src/version.c b/src/version.c
new file mode 100644
index 000000000000..7fa142cdcc90
--- /dev/null
+++ b/src/version.c
@@ -0,0 +1,22 @@
+/* Current program version number.
+
+ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+char *version_string = "2.1 (K&R C version)";
diff --git a/src/version.cc b/src/version.cc
new file mode 100644
index 000000000000..8f07c695d537
--- /dev/null
+++ b/src/version.cc
@@ -0,0 +1,22 @@
+/* Current program version number.
+
+ Copyright (C) 1989-1998, 2000 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. */
+
+const char *version_string = "2.7.2";
diff --git a/src/version.h b/src/version.h
new file mode 100644
index 000000000000..4ffba2ec91a1
--- /dev/null
+++ b/src/version.h
@@ -0,0 +1,23 @@
+/* Current program version number.
+
+ Copyright (C) 1989-1998 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. */
+
+/* Current release version. */
+extern const char *version_string;
diff --git a/src/xmalloc.c b/src/xmalloc.c
new file mode 100644
index 000000000000..09cc0227564c
--- /dev/null
+++ b/src/xmalloc.c
@@ -0,0 +1,78 @@
+/* Provide a useful malloc sanity checker and an efficient buffered memory
+ allocator that reduces calls to 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+
+/* Grabs SIZE bytes of dynamic memory or dies trying! */
+
+char *
+xmalloc (size)
+ int size;
+{
+ char *malloc ();
+ char *temp = malloc (size);
+
+ if (temp == 0)
+ {
+ fprintf (stderr, "out of virtual memory\n");
+ exit (1);
+ }
+ return temp;
+}
+
+/* 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;};
+#define ALIGNMENT ((char *)&((struct fooalign *) 0)->d - (char *)0)
+
+/* Provide an abstraction that cuts down on the number of
+ calls to MALLOC by buffering the memory pool from which
+ items are allocated. */
+
+char *
+buffered_malloc (size)
+ int size;
+{
+ char *temp;
+ 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. */
+
+ /* 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. Furthermore, as a heuristic, we double the
+ size of the new buffer! */
+
+ if (buf_start + size >= buf_end)
+ {
+ buf_size = buf_size * 2 > size ? buf_size * 2 : size;
+ buf_start = xmalloc (buf_size);
+ buf_end = buf_start + buf_size;
+ }
+
+ temp = buf_start;
+ buf_start += size;
+ return temp;
+}