This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[RFC] Suggested replacement for specs and switch handling


This is a long mail, so please bear with me 8-)

Back in January I proposed a rough outline of an alternative to specs
(http://gcc.gnu.org/ml/gcc/2001-01/msg00299.html) that would resolve
some of their shortcomings.  I'd like to outline here something more
concrete that I've been working on, which is a bit different to what I
had in mind in January.

To recap, here are some of the issues with the current way we handle
switches at present:

o Specs are very inefficient; in parsing a whole command line in the
driver, I expect the command line is traversed one hundred times or
more looking for text-based matches.  Worse, each time we make a pass,
we have to figure out again whether each argument on the command line
is a switch, a switch's argument, or an input file.  Each front end is
inefficient too; for example the C front end contains a long chain of
"if ... else if" string comparisons that each argument passes through.
The C family front ends also have to be coded to silently accept
cpplib's switches that they have no interest in themselves.  Most of
these things could certainly be improved by recoding, but that is just
fixing the symptom and not the cause.

o Specs are not precise.  cpplib has to handle various switches it
doesn't understand, such as any -W switch, since the driver's spec of
"%{W*}" just passes the whole lot through.  If "-fno-signed-char" and
"-fsigned-char" appear on the command line, the last one should win.
But __UNSIGNED_CHAR__ is defined either way, because of specs "logic".
Again, these issues could probably be fixed, but only at the cost of
complicating the specs further and making them less maintainable.

o The specs parsing code in gcc.c is messy and hard to maintain.
Enough said :-)

In the original mail, I proposed a binary search in a sorted table for
switch lookup.  I no longer think this is a good idea; the way GCC
handles switches is a little too varied and flexible for that: many
switches can be abbreviated and take appended arguments, for example.

The solution below uses a hash table, which makes things much easier.
Input switches are hashed and looked up in the hash table character by
character, starting with the character after the initial '-', until a
match is found.  Switches that can be abbreviated are stored hashed in
the hash table under the string that represents their shortest unique
prefix (e.g. "-comm" for "--comments").  Further, when the hash table
is constructed, switches are entered shortest first.  This means that
lookups of the common single-character switches, like "-D" and "-I"
and "-o", are guaranteed to match immediately on the lookup of the
first character and without collision.

The solution I outline here is also better than January's, because it
solves the command line parsing problem for the whole of GCC: the
driver, cpplib, toplev.c, and each front end.  The command line
parser, contained in the file "switches.c" below, can be linked into
each.  Switch handling in each front end would become little more than
a large switch statement on the "switch group" the switch belongs to
(more on this later).

For example, in the front ends, I envisage toplev.c performing the
call to parse_switches().  parse_switches() does a single scan of the
command line, and returns the results in a switch list and an array.
These contain everything you need to know about the command line - no
other scanning or parsing of the command line is necessary.

toplev.c would then scan this switch list one by one, and pass any
switch not destined for it down to the front end.  It knows whether a
switch is destined for itself because each switch comes with a set of
flags that indicate which parts of GCC accept it.  Again, based on the
flags for each switch it receives from toplev.c, the C front end would
then pass on any preprocessor switches to cpplib.  Incidentally, a
toplev.c hook would also be provided so that backends can do any
processing of switches flagged for them.  Similarly, targets would
need to provide a small hook that can be linked into the driver for
target-specific handling.

Switches for all front ends, and the driver, assembler, linker etc.,
are listed in a single configuration file, "gcc.switches", below.
Target-specific switches would be contained in an extra file in the
relevant config/cpu directory.  These files are fairly free form, and
so can be concatenated to get a complete switch definition file for a
target.  The program "gen-switches" (below) takes such a file as
input, an spits out a header file containing an "enum" for each switch
group, and a ".tbl" file containing a hash table for the input
switches.  So that, for example, the C front ends doesn't need to
carry the baggage of Fortran and C++ switches, gen-switches can filter
the switches and produce a hash table for specific front ends only.

Since each part of GCC handles command line options based on the
results of a call to parse_switches (), and switches are
differentiated by the enumeration value of the group they belong to,
there is no need for the text form of a switch to appear *anywhere* in
GCC apart from the switch configuration file itself.  This allows
trivial command-line internationalisation should someone deem that a
good idea - the translator simply needs to replace the text of the
English switches with the internationalised ones in the first column
of the configuration file.

Option Groups
-------------

I'll attempt to explain the motivation for "option groups".  One
problem with specs at present is that repeated occurrences of a
command line option, such as -fsigned-char, are not reduced to a
single instance.  Further, there is a kludge in gcc.c to attempt to
ignore whichever of an option and its negative "no-" prefixed form
appears earlier on the command line.  However, it falls down when
there are alternative but not negative spellings like
"-funsigned-char", or "-fhosted" and "-ffreestanding".

I try to deal with this by assigning to each switch a switch group.
parse_switches() ignores all switches that belong to the same group,
except for the one that appears last on the command line.  In other
words, we put all of "-fsigned-char", "-funsigned-char",
"-fno-signed-char" and "-fno-unsigned-char" into a single group,
called "GP_fsigned_char" say.  Another example of a suitable grouping
is the three switches "-E", "-c" and "-S".  Each switch within a group
is distinguished by having an integer value: e.g. 1 for
"-fsigned-char" and "-fno-unsigned-char" in the group GP_fsigned_char,
and zero for the other two forms.  As mentioned above, this is enough
for GCC to get all the information it needs without having to examine
the textual form of a switch.

However, we don't want to ignore the earlier occurrences of some
switches like "-D" or "-I", since they accumulate.  Instead,
parse_switches() does not ignore earlier occurrences of these, but
links them together in a singly-linked list.

To make this a little more concrete, let's take some sample lines from
the switch configuration file below:

-D			pt		a	+D
-Wstrict-prototypes	COX		nB	Wstrict_prototypes
-falign-jumps=		T		j	falign_jumps_eq
-std=c99		pCO		n	std=STD_C99
--shared		D		nAV	-shared

Each line is made up of 4 columns.  The switch, including leading '-',
appears in column one.  The second column lists the programs / front
ends that understand the swtich (T = toplev.c, p = ISO preprocessor, t
= traditional preprocessor, D = driver, C = C front end etc.  See the
top of gcc.switches for a full list of possibilities).  The third
column is one or more flags, including ones that describe if and how
the command takes arguments.  For example, "a" means takes a separate
or joined argument, "s" means takes a separate argument only, "j"
means joined argument only, "n" means takes no argument, etc.  The
flag "B" of -Wstrict-prototypes indicates that the switch is boolean -
it can take a negative form where "no-" is inserted after the first 2
characters of the switch.  This saves making the input table larger
than necessary; the negative form has its own separate entry in the
output hash table of course.

The contents and meaning of the fourth column depends on what appears
in the flags column.  For most options, it is the name of the option
group they belong to.  The names of groups that accumulate are
preceded by a '+'.  gen-switches gathers up these group names, and
dumps them out as a large enumeration in a header file.  If the switch
takes on a particular value within a group, the 4th column can appear
in the form "group=value", as for "-std=c99" above.  The text of
"value" is inserted into a C file, so can be any valid C code,
including an enumation or macro.  Above, STD_C99 is presumably an
enumeration defined elsewhere.

Some switches are aliases, like "--shared" above.  This is indicated
by an "A" in the flags column.  This switch can also be abbreviated -
indicated by the "V" in the flags column.  The fourth column of an
alias is the switch it aliases, in this case "-shared".
parse_switches () automatically translates switches into their aliased
forms.

Aliasing is actually a little more complex than that.  For example

--machine		D		sAJR	-m
--machine-		D		jAR	-m

--machine is a switch that takes a separate argument only, for example
"--machine cpu=386".  --machine- is identical in meaning, but takes a
joined argument, e.g. "--macine-cpu=386".  These are both aliases for
"-m", which is not really a switch in and of itself, but in the sense
that they form a new switch after appending their arguments to "-m".
In this case, they form the switch "-mcpu=386", which is the switch
"-mcpu=" with argument "386".

This is handled by the flags above.  "J" means that a separate
argument should be joined onto the switch during alias rewriting. "R"
means that the result of the alias is a new switch in its own right,
and that the hashtable should be Rescanned for a match.

Finally, here's an example of a SPEC from i386/i386.h

#define CPP_CPU32_SPEC \
"-Acpu=i386 -Amachine=i386 %{!ansi:%{!std=c*:%{!std=i*:-Di386}}} -D__i386 \
-D__i386__ %(cpp_cpu32sizet)"

This would be handled as part of the driver CPP hook, found in
i386/driver.c say.  It might go something like this:-

void
i386_driver_cpp_hook (args)
	arg_set *args;
{
  ....  
  driver_cpp_switch ("-Acpu=i386");
  driver_cpp_switch ("-Amachine=i386");
  driver_cpp_define ("-Di386");
  driver_cpp_define ("-D__i386");
  driver_cpp_define ("-D__i386__");
  cpp_cpu32sizet (); /* Another function in this file that handles the
			size_t stuff.  */
  ...
}

"args" contains the result of parse_switches (), so the hook function
can do easy lookups of whether any given command line switch was
given, and what argument it took.

However, here, the driver function driver_cpp_define() would
effectively be a specialization of driver_cpp_switch.  It would
contain all the logic about ignoring non-ANSI macros based upon
command line switches like -ansi or -std=c89, and would simply ignore
macros that were not valid, rather than forcing each target worry
about the same tedious issues like we do now.

----

So, I propose we go with a scheme like the one described above.  It
should be possible to extend it further.  For example, one thing I
would like to do later is to move the --help documentation into the
switch configuration file to go with each switch.  This would make it
harder for people to add switches without documenting them :-) The
driver could then print out most of the --help documentation in a
loop.  Ultimately, it might even be possible to move the texinfo
documentation into the configuration file, too.

The above method does have one disadvantage compared to specs, as
Michael Meissner pointed out: we don't have run-time configuration any
more.  Specs allow to you tweak the behaviour of command line options
in a limited way at run time by editing a SPECS file.  However, I
believe the advantages of this method over SPECS outweigh this
disadvantage.

If it's generally agreed that this is the way to go, then the next
problem would be choosing a migration path.  This is a fundamental
change in GCC, and would affect a lot of stuff.  I'd suggest that we
first migrate just the driver, leaving the front-ends as they are now.
That would itself be enormously disruptive, and mean changing every
target at once, so we would probably need to migrate the driver a
target at a time.  Other targets would stay using the current driver,
and we first migrate just x86 say.  This would need some kind of
conditional compilation of the driver so that updated targets get the
new driver, and the others the old driver.

Once all targets are migrated, we could then migrate the front ends
very easily I expect.

Comments?

Neil.

[Attached files (the code has been debugged and seems to work well):

gcc.switches (the current switch table)
switches.c (command line switch parser)
switches.h (common header file for clients of switches.c)
gen-switches.c (generates filtered hash tables of switches)]
GCC command line option table.
Copyright (C) 2001 Free Software Foundation, Inc.
Contributed by Neil Booth, June 2001.

This file is part of GNU CC.

GNU CC 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 2, or (at your option)
any later version.

GNU CC 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 CC; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.



The option table is composed of four non-empty columns, separated by
whitespace.  Every line beginning with '-' is assumed to be a table
entry; all other lines are ignored.  The columns are, in order:

1) the switch, which must begin with a '-' in column 1
2) the front ends that understand the switch.  This information is
   used to filter the options at GCC build time and at GCC run time.
3) flags describing usage of the switch, and
4) the option group the switch belongs to.

All the front ends that interpret an option are specified together,
with the following letter codes:

A	Ada
C	C
D	Driver
F	Fortran
M	Mercury
O	ObjC
P	Pascal
T	Toplev
X	C++
a	Assembler
l	Linker
p	ISO C Preprocessor
t	Traditional Preprocessor

The flags column should be made up of one of the argument types below
followed by zero or more flags:

a	takes a non-empty argument, joined or separate
j	takes a non-empty argument, joined only
n	takes no arguments.
o	optionally takes joined argument (not separate)
s	takes argument, separate only

A	an alias for the option at the RHS
B	a boolean switch whose value is implicitly taken to be 1.
        Also implies a negative switch with "no-" in its text after
	the second character, which takes value 0.
J	(aliases only): Force join of argument to form one word during
	rewrite.  e.g. "--opt ARG" would become "-aliasARG"
R	(aliases only): After rewriting an option taking an argument, treat
	the result as a new option and re-scan the hashtable for it.  This
	is useful for e.g. "--warn-", which takes an argument like
	"--warn-all".  After being rewritten as "-Wall", we rescan
	for this as an option in its own right.  Otherwise we'd need a
	separate "--warn-" switch for every "-W" switch, which
	would be inconvenient and waste space.
V	If the option can be abbreviated provided the abbreviation is
	unambiguous (not recommended as abbreviated options can break
	in the future as more options are added).

The Group/Alias column should contain the aliased switch in the case
of an alias, otherwise the group the switch belongs to.  Grouping
affect the treatment of a switch by the command line parser.  Earlier
switches in the same group are overridden by later switches in the
group.  Thus, for example, it is a good idea to make "-Wcomment",
"-Wcomments", "-Wno-comment" and "-Wno-comments" all members of a
common group.  The name of the group is prefixed with "GR_" and
gen-opts creates an enumeration from them.

However, if the group is prefixed with "+", all occurrences of members
of that group are returned from the command line parser chained
together in a list.  This is useful for, e.g., the "-I" options: we
don't want later ones to override earlier ones.  Chaining them might
be useful for the caller: it can easily step through the chain and
process them all at once in the order they appear on the command line.

The switches in the table do not need to appear in any particular
order, but please keep them grouped like they are here for clarity.

Switch			FrontEnds	Flags	Group/Alias
===========================================================

--all-warnings		D		nAV	-Wall
--ansi			D		nAV	-ansi
--assemble		D		nAV	-S
--assert		D		sAV	-A
--classpath		D		sAJV	-fclasspath=
--CLASSPATH		D		sAJV	-fCLASSPATH=
--comments		D		nAV	-C
--compile		D		nAV	-c
--debug			D		oAV	-g
--define-macro		D		sAV	-D
--dependencies		D		nAV	-M
--dump			D		sAJV	-d
--dumpbase		D		nAV	-dumpbase
--entry			D		nAV	-e
--extra-warnings	D		nAV	-W
--for-assembler		D		sAJRV	-Wa,
--for-linker		D		sAV	-Xlinker
--force-link		D		sAV	-u
--imacros		D		sAV	-imacros
--include		D		sAV	-include
--include-barrier	D		n	+not_supported
--include-directory	D		sAV	-I
--include-directory-after	D	sAV	-idirafter
--include-prefix	D		sAV	-iprefix
--include-with-prefix	D		sAV	-iwithprefix
--include-with-prefix-after	D	sAV	-iwithprefixbefore
--include-with-prefix-before	D	sAV	-iwithprefix
--help			DTp		n	help
--language		D		sAV	-x
--library-directory	D		sAV	-L
--machine		D		sAJR	-m
--machine-		D		jAR	-m
--no-line-commands	D		nAV	-P
--no-standard-includes	D		nAV	-nostdinc
--no-standard-libraries	D		nAV	-nostdlib
--no-warnings		D		nAV	-w
--optimize		D		sAJV	-O
--output		D		sAV	-o
--output-class-directory	D	sAJV	-foutput-class-dir=
--param			T		sAR	-param
--pedantic		D		nAV	-pedantic
--pedantic-errors	D		nAV	-pedantic-errors
--pipe			D		nAV	-pipe
--prefix		D		sAV	-B
--preprocess		D		nAV	-E
--print-search-dirs	D		nAV	-print-search-dirs
--print-file-name	D		nAV	-print-file-name=
--print-libgcc-file-name	D	nAV	-print-libgcc-file-name
--print-missing-file-dependencies D	nAV	-MG
--print-multi-lib	D		nAV	-print-multi-lib
--print-multi-directory	D		nAV	-print-multi-directory
--print-prog-name	D		sAJV	-print-prog-name=
--profile		D		nAV	-p
--profile-blocks	D		nAV	-a
--quiet			D		nAV	-q
--save-temps		D		nAV	-save-temps
--shared		D		nAV	-shared
--silent		D		nAV	-q
--specs			D		sAJV	-specs=
--static		D		nAV	-static
--std			D		sAJV	-std=
--target		D		sAJV	-b
--target-help		DTp		n	target_help
--time			D		nAV	-time
--trace-includes	D		nAV	-H
--traditional		D		nAV	-traditional
--traditional-cpp	D		nAV	-traditional-cpp
--trigraphs		D		nAV	-trigraphs
--undefine-macro	D		sAV	-U
--use-version		D		sAV	-V
--user-dependencies	D		nAV	-MM
--verbose		D		nAV	-v
--version		D		nAV	-dumpversion
--warn-			D		jARV	-W
--write-dependencies	D		nAV	-MD
--write-user-dependencies	D	nAV	-MMD

-$			p		n	_dollar
-+			p		n	_plus

-A			pt		a	+A
-B			D		a	+B
-C			pt		n	C
-D			pt		a	+D
-E			D		n	stage='E'
-G			T		a	G
-H			p		n	H
-I			FJpt		a	+I
-L			l		a	+L
-M			ptJ		n	M
-MD			DJ		n	MD
-MF			ptJ		a	MF
-MG			pt		n	MG
-MM			ptJ		n	MM
-MMD			DJ		n	MMD
-MP			ptJ		n	MP
-MQ			pt		a	+MQ
-MT			ptJ		a	+MT
-O			T		o	+O
-P			pt		n	P
-Q			D		n	Q
-Qn			D		A	-fno-ident
-Qy			l		n	Qy
-S			D		n	stage='S'
-T			l		a	+T
-Tbss			l		a	Tbss
-Tdata			l		a	Tdata
-Ttext			l		a	Ttext
-U			pt		a	+D
-V			D		a	V
-W			T		n	W
-Wa,			D		j	+Wa
-Waggregate-return	T		nB	Waggregate_return
-Wall			CFJOXpt		n	Wall
-Wbad-function-cast	CO		nB	Wbad_function_cast
-Wcast-align		T		nB	Wcast_align
-Wcast-qual		COX		nB	Wcast_qual
-Wchar-subscripts	COX		nB	Wchar_subscripts
-Wcomment		pt		nB	Wcomments
-Wcomments		pt		nB	Wcomments
-Wconversion		COX		nB	Wconversion
-Wctor-dtor-privacy	X		nB	Wctor_dtor_privacy
-Wdeprecated		X		nB	Wdeprecated
-Wdisabled-optimization	T		nB	Wdisabled_optimization
-Weffc++		X		nB	Weff_cpp
-Werror			pT		nB	Werror
-Werror-implicit-function-declaration CO n	Wimplicit_function_declaration=2
-Wextraneous-semicolon	J		nB	Wextraneous_semicolon
-Wfloat-equal		COX		nB	Wfloat_equal
-Wformat		COX		nB	Wformat
-Wformat=		COX		j	Wformat
-Wformat-extra-args	COX		nB	Wformat_extra_args
-Wformat-nonliteral	COX		nB	Wformat_nonliteral
-Wformat-security	COX		nB	Wformat_security
-Wformat-y2k		COX		nB	Wformat_y2k
-Wglobals		F		nB	Wglobals
-Wid-clash-		D		j	Wid_clash
-Wimplicit		CFOX		nB	Wimplicit
-Wimplicit-function-declaration CO	nB	Wimplicit_function_declaration
-Wimplicit-int		CO		nB	Wimplicit_int
-Wimport		p		nB	Wimport
-Winline		T		nB	Winline
-Wl,			D		j	+Wl
-Wlarger-than-		T		j	Wlarger_than
-Wlong-long		COX		nB	Wlong_long
-Wmain			CO		nB	Wmain
-Wmissing-braces	COX		nB	Wmissing_braces
-Wmissing-declarations	CO		nB	Wmissing_declarations
-Wmissing-format-attribute COX		nB	Wmissing_format_attribute
-Wmissing-prototypes	COX		nB	Wmissing_prototypes
-Wmissing-noreturn	T		nB	Wmissing_noreturn
-Wmultichar		COX		nB	Wmultichar
-Wnested-externs	CO		nB	Wnested_externs
-Wnon-template-friend	X		nB	Wnon_template_friend
-Wnon-virtual-dtor	X		nB	Wnon_virtual_dtor
-Wold-style-cast	X		nB	Wold_style_cast
-Wout-of-date		J		nB	Wout_of_date
-Woverloaded-virtual	X		nB	Woverloaded_virtual
-Wp,			D		j	+Wp
-Wpacked		T		nB	Wpacked
-Wpadded		T		nB	Wpadded
-Wparentheses		COX		nB	Wparentheses
-Wpmf-conversions	X		nB	Wpmf_conversions
-Wpointer-arith		COX		nB	Wpointer_arith
-Wprotocol		O		nB	Wprotocol
-Wredundant-decls	COX		nB	Wredundant_decls
-Wredundant-modifiers	J		nB	Wredundant_modifiers
-Wreorder		X		nB	Wreorder
-Wreturn-type		COX		nB	Wreturn_type
-Wselector		O		nB	Wselector
-Wsequence-point	CO		nB	Wsequence_point
-Wshadow		T		nB	Wshadow
-Wsign-compare		COX		nB	Wsign_compare
-Wsign-promo		X		nB	Wsign_promo
-Wstrict-prototypes	COX		nB	Wstrict_prototypes
-Wsurprising		F		nB	Wsurprising
-Wswitch		T		nB	Wswitch
-Wsynth			X		nB	Wsynth
-Wsystem-headers	T		nB	Wsystem_headers
-Wtraditional		pCO		nB	Wtraditional
-Wtrigraphs		p		nB	Wtrigraphs
-Wundef			p		nB	Wundef
-Wuninitialized		T		nB	Wuninitialized
-Wunknown-pragmas	COX		nB	Wunknown_pragmas
-Wunreachable-code	T		nB	Wunreachable_code
-Wunused		T		nB	Wunused
-Wunused-function	T		nB	Wunused_function
-Wunused-label		T		nB	Wunused_label
-Wunused-parameter	T		nB	Wunused_parameter
-Wunused-variable	T		nB	Wunused_variable
-Wunused-value		T		nB	Wunused_value
-Wwrite-strings		COX		nB	Wwrite_strings
-Xlinker		D		s	+Wl

-a			T		n	a
-ax			T		n	ax
-aux-info		T		s	aux_info
-aux-info=		T		j	aux_info
-ansi			COX		n	std=STD_C89
-b			D		a	b
-c			D		n	stage='c'
-d			ptT		o	+d
-dumpbase		T		n	dumpbase
-dumpmachine		D		n	dumpmachine
-dumpspecs		D		n	dumpspecs
-dumpversion		D		n	dumpversion
-e			l		a	+e
-f2c			F		nB	f2c
-f2c-library		F		nB	f2c_library
-f66			F		nB	f66
-f77			F		nB	f77
-f90			F		nB	f90
-fCLASSPATH=		J		j	fCLASSPATH
-fPIC			T		nB	fPIC
-faccess-control	X		nB	faccess_control
-falign-functions	T		nB	falign_functions
-falign-functions=	T		j	falign_functions_eq
-falign-jumps		T		nB	falign_jumps
-falign-jumps=		T		j	falign_jumps_eq
-falign-labels		T		nB	falign_labels
-falign-labels=		T		j	falign_labels_eq
-falign-loops		T		nB	falign_loops
-falign-loops=		T		j	falign_loops_eq
-fall-virtual		D		nB	+not_supported
-fallow-single-precision	CO	nB	fallow_single_precision
-falt-external-templates	X	nB	falt_external_templates
-fargument-alias	T		nB	fargument_alias
-fargument-noalias	T		nB	fargument_noalias
-fargument-noalias-global	T	nB	fargument_noalias_global
-fasm			COX		nB	fasm
-fassume-compiled	J		nB	fassume_compiled
-fassume-compiled=	J		jB	+fassume_compiled_eq
-fautomatic		F		nB	fautomatic
-fbackslash		F		nB	fbackslash
-fbadu77-intrinsics-delete	F	n	fbadu77_intrinsics='d'
-fbadu77-intrinsics-disable	F	n	fbadu77_intrinsics='D'
-fbadu77-intrinsics-enable	F	n	fbadu77_intrinsics='E'
-fbadu77-intrinsics-hide	F	n	fbadu77_intrinsics='H'
-fbounded-pointers	T		nB	fbounded_pointers
-fbounds-check		T		nB	fbounds_check
-fbranch-count-reg	T		nB	fbranch_count_reg
-fbranch-probabilities	T		nB	fbranch_probabilities
-fbuiltin		COX		nB	fbuiltin
-fcall-saved-		T		j	+fcall_saved
-fcall-used-		T		j	+fcall_used
-fcaller-saves		T		nB	fcaller_saves
-fcase-initcap		F		n	fcase='I'
-fcase-lower		F		n	fcase='L'
-fcase-preserve		F		n	fcase='P'
-fcase-strict-lower	F		n	fcase='l'
-fcase-strict-upper	F		n	fcase='u'
-fcase-upper		F		n	fcase='U'
-fcheck-memory-usage	T		nB	fcheck_memory_usage
-fcheck-new		X		nB	fcheck_new
-fcheck-references	J		nB	fcheck_references
-fclasspath=		J		j	fclasspath
-fcommon		T		nB	fcommon
-fcond-mismatch		CO		nB	fcond_mismatch
-fconserve-space	X		nB	fconserve_space
-fconst-strings		X		nB	fconst_strings
-fconstant-string-class= O		j	fconstant_string_class
-fcse-follow-jumps	T		nB	fcse_follow_jumps
-fcse-skip-blocks	T		nB	fcse_skip_blocks
-fdata-sections		T		nB	fdata_sections
-fdce			T		nB	fdce
-fdefault-inline	X		nB	fdefault_inline
-fdefer-pop		T		nB	fdefer_pop
-fdelayed-branch	T		nB	fdelayed_branch
-fdelete-null-pointer-checks	T	nB	fdelete_null_pointer_checks
-fdiagnostics-show-location=every-line T n	fdiagnostics_show_location=2
-fdiagnostics-show-location=once       T n	fdiagnostics_show_location=1
-fdollar-ok		F		nB	fdollar_ok
-fdollars-in-identifiers p		nB	fdollars_in_identifiers
-fdump-ast-optimized-	X		j	fdump_ast_optimized
-fdump-ast-original-	X		j	fdump_ast_original
-fdump-class-heirarchy-	X		j	fdump_class_heirarchy
-fdump-translation-unit-	X	j	fdump_translation_unit
-fdump-unnumbered	T		nB	fdump_unnumbered
-felide-constructors	X		nB	felide_constructors
-feliminate-dwarf2-dups T		nB	feliminate_dwarf2_dups
-femit-class-file	J		nB	femit_class_file
-femit-class-files	J		n	femit_class_file=1
-femulate-complex	F		nB	femulate_complex
-fencoding=		J		j	fencoding
-fenforce-eh-specs	X		nB	fenforce_eh_specs
-fenum-int-equiv	D		nB	+not_supported
-fexceptions		T		nB	fexceptions
-fexpensive-optimizations	T	nB	fexpensive_optimizations
-fexternal-templates	X		nB	fexternal_templates
-ff2c-intrinsics-delete	F		n	ff2c_intrinsics='d'
-ff2c-intrinsics-disable	F	n	ff2c_intrinsics='D'
-ff2c-intrinsics-enable	F		n	ff2c_intrinsics='E'
-ff2c-intrinsics-hide	F		n	ff2c_intrinsics='H'
-ff90-intrinsics-delete	F		n	ff90_intrinsics='d'
-ff90-intrinsics-disable	F	n	ff90_intrinsics='D'
-ff90-intrinsics-enable	F		n	ff90_intrinsics='E'
-ff90-intrinsics-hide	F		n	ff90_intrinsics='H'
-ffast-math		T		nB	ffast_math
-ffilelist-file		J		nB	ffilelist_file
-ffixed-		T		j	+ffixed
-ffixed-form		F		n	ffree_form=0
-ffixed-line-length	F		j	ffixed_line_length
-fflatten-arrays	F		nB	fflatten_arrays
-ffloat-store		T		nB	ffloat_store
-ffor-scope		X		nB	ffor_scope
-fforce-addr		T		nB	fforce_addr
-fforce-classes-archive-check	J	nB	fforce_classes_archive_check
-fforce-mem		T		nB	fforce_mem
-ffortran-bounds-check	F		nB	ffortran_bounds_check
-ffreestanding		CO		n	fhosted=0
-ffree-form		F		nB	ffree_form
-ffunction-cse		T		nB	ffunction_cse
-ffunction-sections	T		nB	ffunction_sections
-fgcse			T		nB	fgcse
-fgcse-lm		T		nB	fgcse_lm
-fgcse-sm		T		nB	fgcse_sm
-fglobals		F		nB	fglobals
-fgnu-intrinsics-delete	F		n	fgnu_intrinsics='d'
-fgnu-intrinsics-disable	F	n	fgnu_intrinsics='D'
-fgnu-intrinsics-enable	F		n	fgnu_intrinsics='E'
-fgnu-intrinsics-hide	F		n	fgnu_intrinsics='H'
-fgnu-keywords		X		nB	fgnu_keywords
-fgnu-linker		T		nB	fgnu_linker
-fgnu-runtime		O		nB	fgnu_runtime
-fguess-branch-probability	T	nB	fguess_branch_probability
-fguiding-decls		D		nB	+not_supported
-fhandle-exceptions	X		nB	fhandle_exceptions
-fhash-synchronization	J		nB	fhash_synchronization
-fhonor-std		X		nB	fhonor_std
-fhosted		CO		nB	fhosted
-fhuge-objects		D		nB	+not_supported
-fident			T		nB	fident
-fimplement-inlines	X		nB	fimplement_inlines
-fimplicit-inline-templates	X	nB	fimplicit_inline_templates
-fimplicit-templates	X		nB	fimplicit_templates
-finhibit-size-directive	T	nB	finhibit_size_directive
-finit-local-zero	F		nB	finit_local_zero
-finline		T		nB	finline
-finline-functions	T		nB	finline_functions
-finline-limit=		T		j	finline_limit
-finline-limit-		T		j	finline_limit
-finstrument-functions	T		nB	finstrument_functions
-fintrin-case-any	F		n	fintrin_case='A'
-fintrin-case-initcap	F		n	fintrin_case='I'
-fintrin-case-lower	F		n	fintrin_case='L'
-fintrin-case-upper	F		n	fintrin_case='U'
-fjni			J		nB	fjni
-fkeep-inline-functions	T		nB	fkeep_inline_functions
-fkeep-static-consts	T		nB	fkeep_static_consts
-flabels-ok		D		nB	+not_supported
-fleading_underscore	ptT		nB	fleading_underscore
-fmatch-case-any	F		n	fmatch_case='A'
-fmatch-case-initcap	F		n	fmatch_case='I'
-fmatch-case-lower	F		n	fmatch_case='L'
-fmatch-case-upper	F		n	fmatch_case='U'
-fmath-errno		T		nB	fmath_errno
-fmem-report		T		nB	fmem_report
-fmessage-length=	T		j	fmessage_length
-fmil-intrinsics-delete	F		n	fmil_intrinsics='d'
-fmil-intrinsics-disable	F	n	fmil_intrinsics='D'
-fmil-intrinsics-enable	F		n	fmil_intrinsics='E'
-fmil-intrinsics-hide	F		n	fmil_intrinsics='H'
-fmove-all-movables	T		nB	fmove_all_movables
-fms-extensions		X		nB	fms_extensions
-fname-mangling-version-	X	o	+not_supported
-fnew-abi		D		nB	+not_supported
-fnext-runtime		O		n	fgnu_runtime=0
-fno-emit-class-files	J		n	femit_class_file=0
-fno-fixed-form		F		n	ffree_form=1
-fno-freestanding	CO		n	fhosted=1
-fno-next-runtime	O		n	fgnu_runtime=1
-fno-stack-limit	T		n	fno_stack_limit
-fno-ugly		F		n	fno_ugly
-fno-unsigned-bitfields	COX		n	fsigned_bitfields=1
-fno-unsigned-char	COX		n	fsigned_char=1
-fnon-call-exceptions	T		nB	fnon_call_exceptions
-fnonansi-builtins	X		nB	fnonansi_builtins
-fnonnull-objects	D		nB	+not_supported
-fnot-vxt		F		n	fvxt=0
-fnull-version		F		n	fnull_version
-fomit-frame-pointer	T		nB	fomit_frame_pointer
-fonetrip		F		nB	fonetrip
-foperator-names	pX		nB	foperator_names
-foptimize-register-move	T	nB	foptimize_register_move
-foptimize-sibling-calls	T	nB	foptimize_sibling_calls
-foptional-diags	pX		nB	foptional_diags
-foutput-class-dir=	J		j	foutput_class_dir
-fpack-struct		T		nB	fpack_struct
-fpcc-struct-return	T		nB	fpcc_struct_return
-fpedantic		F		nB	fpedantic
-fpeephole		T		nB	fpeephole
-fpeephole2		T		nB	fpeephole2
-fpermissive		X		nB	fpermissive
-fpic			T		nB	fpic
-fprefix-function-name	T		nB	fprefix_function_name
-fpreprocessed		p		nB	fpreprocessed
-fpretend-float		T		nB	fpretend_float
-fprofile-arcs		T		nB	fprofile_arcs
-freduce_all_givs	T		nB	freduce_all_givs
-freg-struct-return	T		nB	freg_struct_return
-fregmove		T		nB	fregmove
-frename-registers	T		nB	frename_registers
-freorder-blocks	T		nB	freorder_blocks
-frepo			X		nB	frepo
-frerun-cse-after-loop	T		nB	frerun_cse_after_loop
-frerun-loop-opt	T		nB	frerun_loop_opt
-frtti			X		nB	frtti
-fsched-interblock	T		nB	fsched_interblock
-fsched-spec		T		nB	fsched_spec
-fsched-spec-load	T		nB	fsched_spec_load
-fsched-spec-load-dangerous	T	nB	fsched_spec_load_dangerous
-fsched-verbose=	T		j	fsched_verbose
-fschedule-insns	T		nB	fschedule_insns
-fschedule-insns2	T		nB	fschedule_insns2
-fsecond-underscore	F		nB	fsecond_underscore
-fshared-data		T		nB	fshared_data
-fshort-double		COX		nB	fshort_double
-fshort-enums		COX		nB	fshort_enums
-fshort-wchar		COX		nB	fshort_wchar
-fshow-column		p		nB	fshow_column
-fsigned-bitfields	COX		nB	fsigned_bitfields
-fsigned-char		COX		nB	fsigned_char
-fsilent		F		nB	fsilent
-fsingle-precision-constant	T	nB	fsingle_precision_constant
-fsource-case-lower	F		n	fsource_case='L'
-fsource-case-preserve	F		n	fsource_case='P'
-fsource-case-upper	F		n	fsource_case='U'
-fsquangle		D		nB	+not_supported
-fssa			T		nB	fssa
-fstack-check		T		nB	fstack_check
-fstack-limit-register=	T		j	fstack_limit_register
-fstack-limit-symbol=	T		j	fstack_limit_symbol
-fstats			X		nB	fstats
-fstd=			CO		jAR	-std=
-fstrength-reduce	T		nB	fstrength_reduce
-fstrict-aliasing	T		nB	fstrict_aliasing
-fstrict-prototype	D		nB	+not_supported
-fsymbol-case-any	F		n	fsymbol_case='A'
-fsymbol-case-initcap	F		n	fsymbol_case='I'
-fsymbol-case-lower	F		n	fsymbol_case='L'
-fsymbol-case-upper	F		n	fsymbol_case='U'
-fsyntax-only		T		nB	fsyntax_only
-ftabstop=		p		j	ftabstop
-ftemplate-depth	X		j	ftemplate_depth
-ftest-coverage		T		nB	ftest_coverage
-fthis-is-variable	D		nB	+not_supported
-fthread-jumps		T		nB	fthread_jumps
-ftime-report		T		nB	ftime_report
-ftraditional		CO		nB	ftraditional
-ftrapping-math		T		nB	ftrapping_math
-ftrapv			T		nB	ftrapv
-ftypeless-boz		F		nB	ftypeless_boz
-fugly-args		F		nB	fugly_args
-fugly-assign		F		nB	fugly_assign
-fugly-assumed		F		nB	fugly_assumed
-fugly-comma		F		nB	fugly_comma
-fugly-complex		F		nB	fugly_complex
-fugly-init		F		nB	fugly_init
-fugly-logint		F		nB	fugly_logint
-funderscoring		F		nB	funderscoring
-funix-intrinsics-delete	F	n	funix_intrinsics='d'
-funix-intrinsics-disable	F	n	funix_intrinsics='D'
-funix-intrinsics-enable	F	n	funix_intrinsics='E'
-funix-intrinsics-hide	F		n	funix_intrinsics='H'
-funroll-all-loops	T		nB	funroll_all_loops
-funroll-loops		T		nB	funroll_loops
-funsafe-math-optimizations	T	nB	funsafe_math_optimizations
-funsigned-bitfields	COX		n	fsigned_bitfields=0
-funsigned-char		COX		n	fsigned_char=0
-funwind-tables		T		nB	funwind_tables
-fuse-boehm-gc		J		nB	fuse_boehm_gc
-fuse-cxa-atexit	X		nB	fuse_cxa_atexit
-fuse-divide-subroutine	J		nB	fuse_divide_subroutine
-fverbose-asm		T		nB	fverbose_asm
-fversion		F		n	fversion
-fvolatile		T		nB	fvolatile
-fvolatile-global	T		nB	fvolatile_global
-fvolatile-static	T		nB	fvolatile_static
-fvtable-gc		X		nB	fvtable_gc
-fvtable-thunks		D		nB	+not_supported
-fvxt			F		n	fvxt=1
-fvxt-intrinsics-delete	F		n	fvxt_intrinsics='d'
-fvxt-intrinsics-disable	F	n	fvxt_intrinsics='D'
-fvxt-intrinsics-enable	F		n	fvxt_intrinsics='E'
-fvxt-intrinsics-hide	F		n	fvxt_intrinsics='H'
-fweak			X		nB	fweak
-fwritable-strings	T		nB	fwritable_strings
-fxref			D		nB	+not_supported
-fxyzzy			F		nB	fxyzzy
-fzeros			F		nB	fzeros
-g			T		o	+g
-gen-decls		O		n	gen_decls
-h			p		n	help
-help			p		n	help
-idirafter		p		a	+idirafter
-imacros		p		a	+imacros
-include		pt		a	+include
-iprefix		p		a	+iprefix
-isystem		p		a	+isystem
-iwithprefix		p		a	+iwithprefix
-iwithprefixbefore	p		a	+iwithprefixbefore
-l			l		a	+l
-lang-asm               pt		n	lang=LANG_ASM
-lang-c			pt		n	lang=LANG_C
-lang-c++               pt		n	lang=LANG_CXX
-lang-c89               p		n	std=STD_C89
-lang-fortran           t		n	lang=LANG_FORTRAN
-lang-objc              pt		n	lang=LANG_OBJC
-lang-objc++            p		n	lang=LANG_OBJCXX
-m			D		sAJR	-m
-march=			T		j	march
-mcpu=			T		j	mcpu
-no-gcc			D		n	no_gcc
-nodefaultlibs		D		n	nodefaultlibs
-noprecomp		D		n	+not_supported
-nostartfiles		D		n	nostartfiles
-nostdinc		pt		n	nostdinc
-nostdinc++		p		n	nostdinc_plus_plus
-nostdlib		D		n	nostdlib
-o			DTpt		a	+o
-p			T		n	p
-param			T		s	+param
-pass-exit-codes	D		n	pass_exit_codes
-pedantic		p		n	pedantic
-pedantic-errors	p		n	pedantic_errors
-pg			D		n	pg
-pipe			D		n	pipe
-print-search-dirs	D		n	print_search_dirs
-print-file-name=	D		j	+print_file_name
-print-libgcc-file-name	D		n	print_libgcc_file_name
-print-multi-lib	D		n	print_multi_lib
-print-multi-directory	D		n	print_multi_directory
-print-objc-runtime-info	D	n	print_objc_runtime_info
-print-prog-name=	D		j	+print_prog_name
-q			T		n	q
-remap			p		n	remap
-s			l		n	s
-save-temps		D		n	save_temps
-shared			D		n	shared=1
-shared-libgcc		D		n	shared_libgcc=1
-specs			D		s	+specs
-specs=			D		j	+specs
-spew-debug		X		n	spew_debug
-static			D		n	shared=0
-static-libgcc		D		n	shared_libgcc=0
-std=			D		j	badstd
-std=c++98		pX		n	std=STD_CXX98
-std=c89		pCO		n	std=STD_C89
-std=c99		pCO		n	std=STD_C99
-std=c9x		pCO		n	std=STD_C99
-std=gnu89		pCO		n	std=STD_GNUC89
-std=gnu99		pCO		n	std=STD_GNUC99
-std=gnu9x		pCO		n	std=STD_GNUC99
-std=iso9899:1990	pCO		n	std=STD_C89
-std=iso9899:199409	pCO		n	std=STD_C94
-std=iso9899:1999	pCO		n	std=STD_C99
-std=iso9899:199x	pCO		n	std=STD_C99
-symbolic		D		n	symbolic
-target-help		p		n	target_help
-time			D		n	time
-traditional		CO		n	ftraditional=1
-traditional-cpp	D		n	traditional_cpp
-trigraphs		p		n	trigraphs
-u			l		a	+u
-undef			D		n	undef
-v			pt		n	v
-version		Tp		n	version
-w			pt		n	w
-x			D		a	x

Dropped support for:

 -fvxt-not-f90		(Fortran)
 -ff90-not-vxt		(Fortran)
 -fdebug-kludge		(Fortran)
 -fno-debug-kludge	(Fortran)
 -I requires join	(Java)

Linker: -A -d -m -n -N -r -t -x -z -Z
/* Command line switch processor.
   Copyright (C) 2001 Free Software Foundation, Inc.
   Contributed by Neil Booth, June 2001.

This file is part of GNU CC.

GNU CC 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 2, or (at your option)
any later version.

GNU CC 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 CC; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

#include "config.h"
#include "system.h"
#include "switches.h"

static enum arg_t categorize PARAMS ((int, int, int));
static void match_switch PARAMS ((arg_info *, unsigned int,
				  const cl_switch_hash *));
static int rewrite_switch PARAMS ((arg_info *, const cl_switch *));
static void reverse_chains PARAMS ((const arg_set *));

/* Rewrite an aliased switch.  e.g. --pendantic has its text updated
   to -pedantic, and --define-macroFOO is changed to -DFOO.

   Returns non-zero if a rescan of the hash table is needed.  */

static int
rewrite_switch (arg, new_switch)
     arg_info *arg;
     const cl_switch *new_switch;
{
  int rescan = (arg->sw->flags & SW_RESCAN);

  /* Update the text; taking care if we have a joined argument.  */
  if (arg->type == CL_JOINED || arg->sw->flags & SW_FORCE_JOIN)
    {
      unsigned int arglen = strlen (arg->arg) + 1;
      char *newarg = xmalloc (new_switch->len + 1 + arglen);

      newarg[0] = '-';
      memcpy (newarg + 1, new_switch->text, new_switch->len);
      memcpy (newarg + 1 + new_switch->len, arg->arg, arglen);
      arg->text = newarg;
    }
  else
    arg->text = new_switch->text;

  /* Update the switch pointer after setting the text.  */
  arg->sw = new_switch;

  return rescan;
}

/* Categorize a command line argument ARG.  ARGS_LEFT is non-zero if
   there are any more arguments remaining on the command line.  HT is
   the hash table of switches.  */

static void
match_switch (arg, args_left, ht)
     arg_info *arg;
     unsigned int args_left;
     const cl_switch_hash *ht;
{
  const char *text = arg->text + 1;
  const char *p = text;
  unsigned int hash = HASH_INIT;

  arg->type = CL_UNKNOWN_SWITCH;

  /* For each character.  */
  while (*p)
    {
      unsigned int idx;

      hash = HASH_STEP (hash, (unsigned int) *p++);
      idx = hash % ht->entries;

      /* For each collision.  */
      while (ht->table[idx])
	{
	  const cl_switch *sw = &ht->switches[ht->table[idx] - 1];

	  if (sw->hash == HASH_MASK (hash))
	    {
	      /* Compare the length of the candidate switch.  For
                 abbreviations, when we compare the length of the
                 supplied text, if shorter.  */

	      unsigned int len = sw->len;

	      if (sw->flags & SW_ABBREV)
		{
		  unsigned int text_len = strlen (text);

		  if (text_len < len)
		    len = text_len;
		}

	      if (memcmp (sw->text, text, len) == 0)
		{
		  /* We've matched; possibly with a missing or
		     unwanted argument.  */
		  arg->type = categorize (sw->flags, text[len], args_left);
		  arg->sw = sw;

		  /* See if there is a longer match - they're better.  */
		  if (! (sw->flags & SW_LONGER))
		    return;
		  break;
		}

	    }

	  idx += 1 + hash % (ht->entries - 2);
	  if (idx >= ht->entries)
	    idx -= ht->entries;
	}
    }
}

/* Categorize a match.  FLAGS is the usage flags of the switch,
   APPENDED_ARG is non-zero if there is extra appended text given with
   the switch (e.g. the "foo" of "-Dfoo"), and EXTRA_ARGS is non-zero
   if there are more arguments later on the command line.  */

static enum arg_t
categorize (flags, appended_arg, extra_args)
     int flags, appended_arg, extra_args;
{
  if (appended_arg && !(flags & SW_ARG_JOINED))
    return CL_UNWANTED_ARG;

  if ((flags & (SW_ARG_JOINED | SW_ARG_SEPARATE)) == 0)
    return CL_SWITCH;

  if (flags & SW_ARG_JOINED
      && (appended_arg || (flags & SW_ARG_OPTIONAL) == SW_ARG_OPTIONAL))
    return CL_JOINED;

  if ((flags & SW_ARG_SEPARATE) && extra_args)
    return CL_SEPARATE;

  return CL_MISSING_ARG;
}

/* For a vector of arguments ARGV with ARGC entries, and a switch hash
   table HT, return a malloced array of size ARGC indicating the role
   of each member of the argument array.  */

void
parse_switches (argc, argv, ngroups, ht, result)
     unsigned int argc;
     const char **argv;
     unsigned int ngroups;
     const cl_switch_hash *ht;
     arg_set *result;
{
  unsigned int i;

  result->argc = argc;
  result->ngroups = ngroups;
  result->info = (arg_info *) xmalloc (argc * sizeof (arg_info));
  result->groups = (arg_info **) xcalloc (ngroups, sizeof (arg_info *));

  for (i = 0; i < argc; i++)
    {
      arg_info *arg = &result->info[i];

      arg->next = NULL;
      arg->sw = NULL;
      arg->text = argv[i];

      /* Switches begin with '-', except for "-" itself.  */
      if (arg->text[0] != '-' || arg->text[1] == '\0')
	{
	  arg->type = CL_OTHER;
	  continue;
	}

      for (;;)
	{
	  match_switch (arg, argc - (i + 1), ht);

	  /* Categorise a separate argument, and skip past it.  */
	  if (arg->type == CL_JOINED || arg->type == CL_UNWANTED_ARG)
	    arg->arg = &arg->text[arg->sw->len + 1];
	  else if (arg->type == CL_SEPARATE)
	    {
	      arg->arg = argv[++i];
	      arg[1].type = CL_IGNORE;
	    }

	  /* Rewrite aliases, and rescan if appropriate.  */
	  if ((arg->type == CL_SEPARATE
	       || arg->type == CL_JOINED
	       || arg->type == CL_SWITCH)
	      && (arg->sw->flags & SW_ALIAS)
	      && rewrite_switch (arg, &ht->switches[GET_ALIAS (arg->sw)]))
	    continue;

	  break;
	}

      if (arg->sw)
	{
	  /* This chains the groups backwards.  Rather than finding
	     the end of the chain now, we reverse the chain later, so
	     that we aren't an O(N^2) algorithm.  */
	  if (arg->sw->flags & SW_CHAIN)
	    arg->next = result->groups[GET_GROUP (arg->sw)];
	  result->groups[GET_GROUP (arg->sw)] = arg;
	}
    }

  reverse_chains (result);
}

/* Reverse the group chains to the command line order.  */

static void
reverse_chains (args)
     const arg_set *args;
{
  arg_info *arg = args->info;
  unsigned int n;

  for (n = args->argc; n--; arg++)
    {
      if (!arg->next)
	continue;

      /* Point the group to the start.  In case pointers are signed,
	 compare the difference rather than the pointers.  */
      if (args->groups[GET_GROUP (arg->sw)] - arg->next > 0)
	args->groups[GET_GROUP (arg->sw)] = arg->next;

      /* Reverse this link.  */
      arg->next->next = arg;

      /* Assume we're the end of the chain.  */
      arg->next = NULL;
    }
}

/* Emit appropriate diagnostics about command-line switch parsing
   errors, and return the number of bad switches found.  */

unsigned int
bad_switch_count (args)
     const arg_set *args;
{
  unsigned int i, count;

  for (count = 0, i = 0; i < args->argc; i++)
    {
      arg_info *info = &args->info[i];

      if (info->type == CL_UNKNOWN_SWITCH)
	{
	  fprintf (stderr, "unrecognised switch %s\n",
		   info->text);
	  count++;
	}
      else if (info->type == CL_UNWANTED_ARG)
	{
	  fprintf (stderr, "switch %s taking an unwanted argument %s\n",
		   info->sw->text, info->arg);
	  count++;
	}
      else if (info->type == CL_MISSING_ARG)
	{
	  fprintf (stderr, "switch %s with a missing argument\n",
		   info->sw->text);
	  count++;
	}
    }

  return count;
}
/* Command-line switch processor that can handle many languages.
   Copyright (C) 2001 Free Software Foundation, Inc.

This file is part of GNU CC.

GNU CC 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 2, or (at your option)
any later version.

GNU CC 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 CC; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

/* The various parts of GCC that handle switches; mostly front ends.  */
#define FE_ADA		(1 <<  0)
#define FE_ASSEMBLER	(1 <<  1)
#define FE_C		(1 <<  2)
#define FE_CPP		(1 <<  3) /* The ISO C preprocessor.  */
#define FE_CXX		(1 <<  4)
#define FE_DRIVER	(1 <<  5) /* The driver.  */
#define FE_F77		(1 <<  6)
#define FE_JAVA		(1 <<  7)
#define FE_LINKER	(1 <<  8)
#define FE_MERCURY	(1 <<  9)
#define FE_OBJC		(1 << 10)
#define FE_PASCAL	(1 << 11)
#define FE_TOPLEV	(1 << 12) /* toplev.c.  */
#define FE_TRADCPP	(1 << 13)

/* Flags describing the behaviour of a switch.  */

/* Takes a non-empty argument that must be joined; e.g. "-fstd=".  If
   used with SW_ARG_SEPARATE, the argument can be joined or separate.  */
#define SW_ARG_JOINED	(1 << 0)

/* Takes a non-empty argument that must be separate.  e.g. "-D".  If
   used with SW_ARG_JOINED, the argument can be joined or separate.  */
#define SW_ARG_SEPARATE	(1 << 1)

/* Takes an argument that must be joined, but can be empty.  */
#define SW_ARG_OPTIONAL	((1 << 2) | SW_ARG_JOINED)

/* Longer switch with same initial text exists, e.g. "-W" has this
   flag set.  */
#define SW_LONGER	(1 << 3)

/* An alias for another switch, e.g. "--include" is an alias for "-I".  */
#define SW_ALIAS	(1 << 4)

/* If a re-written alias should be treated as a new switch.  For
   example, "--machine-cpu=386" is the switch "--machine-", an alias
   for "-m", with argument "cpu=386".  Aliasing rewrites it as
   "-mcpu=386", and this flag indicates that the result should be
   treated as a switch in its own right, rather than "-m" with
   argument "cpu=386".  */
#define SW_RESCAN	(1 << 5) 

/* Force joining of a separate argument.  With this flag and
   SW_RESCAN, "--warn comments" becomes the new switch "-Wcomments"
   rather than the invalid "-W comments".  */
#define SW_FORCE_JOIN	(1 << 6)

/* If the switch can be abbreviated as long as it is unambiguous.
   e.g. with this switch, "--compile" can be abbreviated to "--comp"
   since no other switches begin with "--comp".  */
#define SW_ABBREV	(1 << 7)

/* If the switches in the group are chained so as not to replace
   earlier ones, and for easier access.   Used for -D, -I etc.  */
#define SW_CHAIN	(1 << 8)

/* Accessor macros.  */
#define GET_ALIAS(SW) ((SW)->front_ends)
#define GET_GROUP(SW) ((SW)->group)

/* An command line switch, as pointed to in the hash table.  */
typedef struct cl_switch cl_switch;
struct cl_switch
{
  /* The switch without the leading '-'.  */
  const char *text;

  /* The hash of the text (with MSB 0 to avoid warnings).  */
  unsigned int hash;

  /* Front ends taking this switch.  If the switch is an alias, the
     index of the alias in the switch table instead.  */
  unsigned int front_ends;

  /* strlen (text).  */
  unsigned short len;

  /* Usage flags, see SW_XXX.  */
  unsigned short flags;

  /* Switch group, N_GROUPS if an alias.  Not of type enum group_t to
     avoid predeclaration issues.  */
  unsigned short group;

  /* Used to differentiate switches in the same group e.g. -Wcomments
     and -Wno-comments.  Examining their text would be error prone,
     and prevents internationalization.  */
  unsigned short value;
};

/* A hash table of switches.  */
typedef struct cl_switch_hash cl_switch_hash;
struct cl_switch_hash
{
  /* Number of slots in this hash table.  */
  unsigned int entries;

  /* Number of used slots in this hash table.  */
  unsigned int used;

  /* Full array of switches.  */
  const cl_switch *switches;

  /* Each entry in the hash table is zero, meaning an unused entry, or
     one plus the index of the switch in the SWITCHES table.  */
  unsigned short *table;
};

/* Categorises every argument on the command line.  All can be set by
   parse_switches.  */
enum arg_t
{
  CL_OTHER,			/* Not a switch or one's argument.  */
  CL_IGNORE,			/* Ignore this argument, e.g. an
                                   argument to the previous switch.  */
  CL_SWITCH,			/* A switch that takes no arguments.  */
  CL_SEPARATE,			/* A switch with a separate argument.  */
  CL_JOINED,			/* A switch and (possibly empty)
				   argument combined.  */
  CL_UNKNOWN_SWITCH,		/* An unrecognised switch.  */
  CL_UNWANTED_ARG,		/* A switch and unwanted joined argument.  */
  CL_MISSING_ARG		/* A switch with a missing argument.  */
};

/* Describes a parsed command line argument.  */
typedef struct arg_info arg_info;
struct arg_info
{
  /* The next argument in the chain, if any.  */
  struct arg_info *next;

  /* The full text of the argument.  */
  const char *text;

  /* If TYPE is CL_SWITCH, CL_SEPARATE, CL_JOINED or CL_UNWANTED_ARG,
     the argument.  */
  const char *arg;

  /* The matched switch in the switch table, if not CL_OTHER,
     CL_IGNORE or CL_UNKNOWN_SWITCH.  */
  const cl_switch *sw;

  /* The type of this command line argument.  */
  enum arg_t type;
};

/* An arg_set structure is filled out by parse_switches.  */
typedef struct arg_set arg_set;
struct arg_set
{
  /* Number of command-line arguments (less argv[0]).  */
  unsigned int argc;

  /* The original command line argument vector (less argv[0]).  */
  const char **argv;

  /* The number of groups.  */
  unsigned int ngroups;

  /* An array of size ARGC, with information on each argument.  */
  arg_info *info;

  /* An array of size N_GROUPS.  Each entry is either NULL, meaning no
     switch for that group, or pointers to the first (possibly only)
     member of the group.  */
  arg_info **groups;
};

#if 1
/*# define HASH_INIT 18652613*/
# define HASH_INIT 2166136261
# define HASH_STEP(r, c) (((r) * 16777619) ^ (c));
#else
# define HASH_INIT 0
# define HASH_STEP(r, c) ((r) * 67 + ((c) - 113));
#endif

/* We can't suffix a 'U' on hash values with -Wtraditional, but
   without the 'U' we get "integer so big it is unsigned" warnings.
   Avoid such silliness by masking out the MSB.  */

#define HASH_MASK(hash) ((hash) & (((unsigned int) ~0) >> 1))

/* Parse a vector of command line arguments, given a switch table.  */

extern void parse_switches PARAMS ((unsigned int, const char **,
				    unsigned int, const cl_switch_hash *,
				    arg_set *));

/* For an arg_set returned by parse_switches, emit appropriate errors,
   if any, and return the number of bad switches found.  */

extern unsigned int bad_switch_count PARAMS ((const arg_set *));
/* Generate switch hash table.
   Copyright (C) 2001 Free Software Foundation, Inc.
   Contributed by Neil Booth, 2001.

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 2, 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#include <config.h>
#include <system.h>
#include "switches.h"

#define FLAG_LONGER 1

const char *negator = "no-";
unsigned int negator_len;

/* This file's view of a command line switch.  */
typedef struct opt option;
struct opt
{
  struct opt *next;		/* Next in chain.  */
  const char *text;		/* Text of option, less the initial '-'.  */
  const char *fe;		/* Front ends.  */
  const char *arg;		/* How it takes an argument.  */
  const char *group;		/* Or alias if an alias switch.  */
  const char *value;		/* "0" if none given.  */
  unsigned int alias;		/* Index of alias.  */
  unsigned int flags;
  unsigned int hash;
  unsigned short hash_len;
  unsigned short len;
  unsigned short index;
};

static unsigned int higher_prime_number PARAMS ((unsigned int));
static unsigned int hash_str PARAMS ((option *));
static unsigned int calc_match_len PARAMS ((const char *, const char *));
static void hash_switches PARAMS ((void));
static void parse_line PARAMS ((char *));
static void add_switch PARAMS ((const char *, const char *,
				const char *, const char *, int));
static int compare_alpha PARAMS ((option **, option **));
static int compare_opts PARAMS ((option **, option **));
static void dump_groups PARAMS ((void));
static void dump_hashtable PARAMS ((void));
static void dump_switches PARAMS ((void));
static int output_flag PARAMS ((const char *, int));
int main PARAMS ((int, char **));

option *head;
option **table, **opt_list;
const char *filter = 0;
unsigned int hash_size;
unsigned int max_chain;
unsigned int collisions;
unsigned int ncollisions;
unsigned int nswitches;

/* Hash an option's first hash_len characters, not including the '-'.  */
static unsigned int
hash_str (opt)
     option *opt;
{
  const unsigned char *str = (unsigned char *) opt->text;
  const unsigned char *limit = str + opt->hash_len;
  unsigned int hash = HASH_INIT;

  /* Don't hash the initial '-'.  */
  while (++str < limit)
    hash = HASH_STEP (hash, (unsigned int) *str);

  return hash;
}

/* The following function returns the nearest prime number which is
   greater than a given source number, N. */

static unsigned int
higher_prime_number (n)
     unsigned int n;
{
  unsigned int i;

  /* Ensure we have a larger number and then force to odd.  */
  n++;  
  n |= 0x01; 

  /* All odd numbers < 9 are prime.  */
  if (n < 9)
    return n;

  /* Otherwise find the next prime using a sieve.  */

 next:
  for (i = 3; i * i <= n; i += 2)
    if (n % i == 0)
      {
	 n += 2;
	 goto next;
       }

  return n;
}

typedef int (*qfunc) (const void *, const void *);

/* Sort options in order of increasing length.  */
static int
compare_opts (option **opt1, option **opt2)
{
  unsigned int len = (*opt1)->len - (*opt2)->len;

  if (len)
    return len;

  return strcmp ((*opt1)->text, (*opt2)->text);
}

static int
compare_alpha (option **opt1, option **opt2)
{
  return strcmp ((*opt1)->text, (*opt2)->text);
}

static int
compare_groups (option **opt1, option **opt2)
{
  const char *t1 = (*opt1)->group;
  const char *t2 = (*opt2)->group;

  if (*t1 == '+')
    t1++;
  if (*t2 == '+')
    t2++;

  return strcmp (t1, t2);
}

static unsigned int
calc_match_len (str1, str2)
     const char *str1, *str2;
{
  unsigned int i = 0;

  while (str1[i] && str1[i] == str2[i])
    i++;

  return i;
}

static void
hash_switches ()
{
  unsigned int i, chain;
  unsigned int match_len, prev_match_len = 0;
  struct opt *opt;

  /* First, sort the list into alphabetical order.  */
  opt_list = (struct opt **) xmalloc (nswitches * sizeof (struct opt *));
  for (i = 0, opt = head; opt; opt = opt->next, i++)
    opt_list[i] = opt;
  qsort (opt_list, nswitches, sizeof (struct opt *), (qfunc) compare_alpha);

  for (i = 0; i < nswitches; i++)
    {
      opt = opt_list[i];
      if (i + 1 < nswitches)
	{
	  match_len = calc_match_len (opt->text, opt_list[i + 1]->text);
	  if (match_len == opt->len)
	    {
	      if (opt_list[i + 1]->text[opt->len] == '\0')
		{
		  fprintf (stderr, "Switch %s given twice\n", opt->text);
		  exit (FATAL_EXIT_CODE);
		}
	      opt->flags |= FLAG_LONGER;
	    }
	  opt->hash_len = MAX (prev_match_len, match_len) + 1;
	}
      else
	opt->hash_len = prev_match_len + 1;

      if (opt->hash_len > opt->len)
	opt->hash_len = opt->len;
      prev_match_len = match_len;
    }

  /* Now sort them by length, then alphabetically.  */
  qsort (opt_list, nswitches, sizeof (struct opt *), (qfunc) compare_opts);

  hash_size = higher_prime_number (nswitches * 2);
  table = (struct opt **) xcalloc (hash_size, sizeof (struct opt *));
    
  for (i = 0; i < nswitches; i++)
     {
      struct opt *opt = opt_list[i];
      unsigned int hash2;
      unsigned int index;

      opt->index = i;
      opt->hash = hash_str (opt);
      hash2 = 1 + opt->hash % (hash_size - 2);

      if (strchr (opt->arg, 'A'))
	{
	  for (opt->alias = 0; opt->alias < nswitches; opt->alias++)
	    if (!strcmp (opt->group, opt_list[opt->alias]->text))
	      break;

	  if (opt->alias == nswitches)
	    {
	      fprintf (stderr, "Alias %s of %s not found\n",
		       opt->group, opt->text);
	      exit (FATAL_EXIT_CODE);
	    }
	}

      chain = 0;
      index = opt->hash % hash_size;
      for (;;)
	{
	  if (table[index] == 0)
	    {
	      table[index] = opt;
	      break;
	    }

	  chain++;
	  index += hash2;
	  if (index >= hash_size)
	    index -= hash_size;
	}

      if (chain > max_chain)
	max_chain = chain;
      collisions += chain;
      if (chain)
	ncollisions++;
    }
}

static void
add_switch (text, fe, arg, group, negative_p)
     const char *text, *fe, *arg, *group;
     int negative_p;
{
  unsigned int len;
  struct opt *opt;
  char *buff, *value;
  int bool_p = (strchr (arg, 'B') != 0);

  if (filter)
    {
      unsigned int i;

      len = strlen (filter);
      for (i = 0; i < len; i++)
	if (strchr (fe, filter[i]))
	  break;

      /* None of the front ends are in filter.  */
      if (i == len)
	return;
    }

  opt = (struct opt *) xmalloc (sizeof (struct opt));
  opt->flags = 0;
  opt->len = strlen (text);
  if (negative_p)
    opt->len += negator_len;

  len = opt->len + strlen (fe) + strlen (arg) + strlen (group) + 4;

  buff = xmalloc (len);
  if (negative_p)
    {
      buff[0] = text[0];
      buff[1] = text[1];
      strcpy (buff + 2, negator);
      strcpy (buff + 2 + negator_len, text + 2);
    }
  else
    strcpy (buff, text);

  opt->text = buff;
  buff += opt->len + 1;

  opt->fe = buff;
  strcpy (buff, fe);
  buff += strlen (buff) + 1;

  opt->arg = buff;
  strcpy (buff, arg);
  buff += strlen (buff) + 1;

  opt->group = buff;
  strcpy (buff, group);

  /* If not an alias nor a chaining group, separate out a value.  */
  if (bool_p)
    opt->value = negative_p ? "0": "1";
  else if (buff[0] != '-'
	   && buff[0] != '+'
	   && (value = strchr (buff, '=')) != 0)
    {
      *value++ = '\0';
      opt->value = value;
    }
  else
    opt->value = "0";

  opt->next = head;
  head = opt;
  nswitches++;

  /* Boolean switches negative form is not explicitly given.  */
  if (bool_p && !negative_p)
    add_switch (text, fe, arg, group, 1);
}

static void
parse_line (line)
     char *line;
{
  char *opt, *fe, *arg, *group;

  if (line[0] != '-')
    return;

  opt = line;
  while (*line && !IS_SPACE_OR_NUL (*line))
    line++;
  *line++ = '\0';

  while (IS_SPACE_OR_NUL (*line))
    line++;
  fe = line;
  while (*line && !IS_SPACE_OR_NUL (*line))
    line++;
  *line++ = '\0';

  while (IS_SPACE_OR_NUL (*line))
    line++;
  arg = line;
  while (*line && !IS_SPACE_OR_NUL (*line))
    line++;
  *line++ = '\0';

  while (IS_SPACE_OR_NUL (*line))
    line++;
  group = line;
  while (*line && !IS_SPACE_OR_NUL (*line))
    line++;
  *line = '\0';

  add_switch (opt, fe, arg, group, 0);
}

/* Outputs the enum for the switch groupings.  */

static void
dump_groups ()
{
  option **optarray, *opt;
  unsigned int j, col, len, ngroups, n;

  optarray = (option **) xmalloc (nswitches * sizeof (option *));
  for (j = 0, opt = head; opt; opt = opt->next)
    {
      /* Aliases don't give us new groups.  */
      if (strchr (opt->arg, 'A'))
	continue;
      optarray[j++] = opt;
    }
  n = j;
  
  qsort (optarray, n, sizeof (option *), (qfunc) compare_groups);

  for (ngroups = 0, j = 0; j < n; j++)
    {
      if (j > 0 && compare_groups (&optarray[j], &optarray[j - 1]) == 0)
	{
	  if (optarray[j]->group[0] != optarray[j - 1]->group[0])
	    fprintf (stderr, "Not all uses of group %s are used with '+'",
		     optarray[j]->group);
	  continue;
	}
      if (optarray[j]->group[0] == '-')
	continue;
      optarray[ngroups++] = optarray[j];
    }

  /* Dump the enums.  */
  printf ("/* One enum for every switch group.  */\n\nenum group_t\n{");
  for (col = 80, j = 0; j < ngroups; j++)
    {
      const char *text = optarray[j]->group;

      if (*text == '+')
	text++;
      len = strlen (text) + 5;
      if (col + len > 78)
	printf ("\n  GP_%s,", text), col = 2;
      else
	printf (" GP_%s,", text);
      col += len;
    }
  printf ("\n  N_GROUPS\n};\n");

  free (optarray);
}

/* Output flags intelligently.  */

static int
output_flag (text, dumped)
     const char *text;
     int dumped;
{
  if (text == NULL)
    return dumped;

  if (dumped)
    fputs (" | ", stdout);

  fputs (text, stdout);
  return 1;
}

/* Dump the static array of switches.  */

static void
dump_switches ()
{
  unsigned int i, j;

  /* Dump the array of switches.  */
  printf ("/* A static array describing each switch.  */\n\n\
static struct cl_switch switch_array[] = \n{\n");
  for (i = 0; i < nswitches; i++)
    {
      option *opt = opt_list[i];
      unsigned int fe_len;
      const char *text, *flags;
      int dumped;

      printf ("  {\"%s\", %u, ", opt->text + 1, HASH_MASK (opt->hash));

      /* Aliases index their alias, and have no group.  */
      if (strchr (opt->arg, 'A'))
	printf ("%u /* %s */", opt->alias, opt->group);
      else
	{
	  dumped = 0;
	  fe_len = strlen (opt->fe);
	  for (j = 0; j < fe_len; j++)
	    {
	      switch (opt->fe[j])
		{
		case 'A': text = "FE_ADA"; break;
		case 'C': text = "FE_C"; break;
		case 'D': text = "FE_DRIVER"; break;
		case 'F': text = "FE_F77"; break;
		case 'J': text = "FE_JAVA"; break;
		case 'M': text = "FE_MERCURY"; break;
		case 'O': text = "FE_OBJC"; break;
		case 'P': text = "FE_PASCAL"; break;
		case 'T': text = "FE_TOPLEV"; break;
		case 'X': text = "FE_CXX"; break;
		case 'a': text = "FE_ASSEMBLER"; break;
		case 'l': text = "FE_LINKER"; break;
		case 'p': text = "FE_CPP"; break;
		case 't': text = "FE_TRADCPP"; break;
		default: text = 0; continue;
		}

	      dumped = output_flag (text, dumped);
	    }
	  if (!dumped)
	    putchar ('0');
	}
      printf (", %u,\n   ", opt->len - 1);

      flags = opt->arg;
      dumped = 0;
      for (;;)
	{
	  switch (*flags++)
	    {
	    case 'A': text = "SW_ALIAS"; break;
	    case 'J': text = "SW_FORCE_JOIN"; break;
	    case 'R': text = "SW_RESCAN"; break;
	    case 'V': text = "SW_ABBREV"; break;
	    case 'a': text = "SW_ARG_JOINED | SW_ARG_SEPARATE"; break;
	    case 'j': text = "SW_ARG_JOINED"; break;
	    case 'o': text = "SW_ARG_OPTIONAL"; break;
	    case 's': text = "SW_ARG_SEPARATE"; break;
	    default:  text = 0; break;
	    }

	  dumped = output_flag (text, dumped);
	  if (*flags == '\0')
	    break;
	}

      if (opt->flags & FLAG_LONGER)
	dumped = output_flag ("SW_LONGER", dumped);
      if (opt->group[0] == '+')
	dumped = output_flag ("SW_CHAIN", dumped);
      if (!dumped)
	putchar ('0');
      fputs (", ", stdout);

      /* Aliases have no group or value.  */
      if (strchr (opt->arg, 'A'))
	fputs ("N_GROUPS, 0}", stdout);
      else
	{
	  text = opt->group;
	  if (*text == '+')
	    text++;

	  printf ("GP_%s, %s}", text, opt->value);
	}

      if (i + 1 < nswitches)
	putchar (',');
      putchar ('\n');
    }
  printf ("};\n");
}

/* Dump the hashtable that indexes into the array of switches.  */

static void
dump_hashtable ()
{
  unsigned int i;

  /* Dump the hash table.  */
  printf ("\n/* The switch hash table, indexing into the array\n\
   of switches above.  */\n\nstatic unsigned short switch_ht[] = \n{");
  for (i = 0; i < hash_size; i++)
    {
      if (i % 10 == 0)
	{
	  putchar ('\n');
	  putchar (' ');
	}
      putchar (' ');

      printf ("%u", table[i] ? (table[i]->index + 1): 0);
      if (i + 1 != hash_size)
	putchar (',');
    }

  fputs ("\n};\n", stdout);
}

int
main (argc, argv)
     int argc;
     char **argv;
{
  char buff[1024];

  if (argc < 2 || argc > 3)
    {
      fprintf (stderr, "Usage: %s G|T [front-end filter]\n", argv[0]);
      return FATAL_EXIT_CODE;
    }

  if (argc == 3)
    filter = argv[1];

  negator_len = strlen (negator);

  for (;;)
    {
      if (!fgets (buff, sizeof (buff), stdin))
	break;
      parse_line (buff);
    }

  if (argv[1][0] == 'G')
    dump_groups ();
  else
    {
      hash_switches ();
      dump_switches ();
      dump_hashtable ();

      fprintf (stderr, "Total switches: %d\n", nswitches);
      fprintf (stderr, "Distinct collisions: %d\n", ncollisions);
      fprintf (stderr, "Total collisions: %d\n", collisions);
      fprintf (stderr, "Max chain length: %d\n", max_chain);
    }

  return SUCCESS_EXIT_CODE;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]