1# This module does multiple indices, supporting the style of the LaTex 'index'
2#  package.
3
4# Version Information:
5#  16-Feb-2005 -- Original Creation.  Karl E. Cunningham
6#  14-Mar-2005 -- Clarified and Consolodated some of the code.
7#                   Changed to smoothly handle single and multiple indices.
8
9# Two LaTeX index formats are supported...
10#  --- SINGLE INDEX ---
11#  \usepackage{makeidx}
12#  \makeindex
13#  \index{entry1}
14#  \index{entry2}
15#  \index{entry3}
16#    ...
17#  \printindex
18#
19#  --- MULTIPLE INDICES ---
20#
21#  \usepackage{makeidx}
22#  \usepackage{index}
23#  \makeindex   -- latex2html doesn't care but LaTeX does.
24#  \newindex{ref1}{ext1}{ext2}{title1}
25#  \newindex{ref2}{ext1}{ext2}{title2}
26#  \newindex{ref3}{ext1}{ext2}{title3}
27#  \index[ref1]{entry1}
28#  \index[ref1]{entry2}
29#  \index[ref3]{entry3}
30#  \index[ref2]{entry4}
31#  \index{entry5}
32#  \index[ref3]{entry6}
33#    ...
34#  \printindex[ref1]
35#  \printindex[ref2]
36#  \printindex[ref3]
37#  \printindex
38#  ___________________
39#
40#  For the multiple-index  style, each index is identified by the ref argument to \newindex, \index,
41#   and \printindex. A default index is allowed, which is indicated by omitting the optional
42#   argument.  The default index does not require a \newindex command.  As \index commands
43#   are encountered, their entries are stored according
44#   to the ref argument.  When the \printindex command is encountered, the stored index
45#   entries for that argument are retrieved and printed. The title for each index is taken
46#   from the last argument in the \newindex command.
47#  While processing \index and \printindex commands, if no argument is given the index entries
48#   are built into a default index.  The title of the default index is simply "Index".
49#   This makes the difference between single- and multiple-index processing trivial.
50#
51#  Another method can be used by omitting the \printindex command and just using \include to
52#   pull in index files created by the makeindex program. These files will start with
53#   \begin{theindex}.  This command is used to determine where to print the index.  Using this
54#   approach, the indices will be output in the same order as the newindex commands were
55#   originally found (see below).  Using a combination of \printindex and \include{indexfile} has not
56#   been tested and may produce undesireable results.
57#
58#  The index data are stored in a hash for later sorting and output.  As \printindex
59#   commands are handled, the order in which they were found in the tex filea is saved,
60#   associated with the ref argument to \printindex.
61#
62#  We use the original %index hash to store the index data into.  We append a \002 followed by the
63#    name of the index to isolate the entries in different indices from each other.  This is necessary
64#    so that different indices can have entries with the same name.  For the default index, the \002 is
65#    appended without the name.
66#
67#  Since the index order in the output cannot be determined if the \include{indexfile}
68#   command is used, the order will be assumed from the order in which the \newindex
69#   commands were originally seen in the TeX files.  This order is saved as well as the
70#   order determined from any printindex{ref} commands.  If \printindex commnads are used
71#   to specify the index output, that order will be used.  If the \include{idxfile} command
72#   is used, the order of the original newindex commands will be used.  In this case the
73#   default index will be printed last since it doesn't have a corresponding \newindex
74#   command and its order cannot be determined.  Mixing \printindex and \include{idxfile}
75#   commands in the same file is likely to produce less than satisfactory results.
76#
77#
78#  The hash containing index data is named %indices.  It contains the following data:
79#{
80#	'title' => {
81#                $ref1 => $indextitle ,
82#                $ref2 => $indextitle ,
83#                ...
84#              },
85#	'newcmdorder' => [ ref1, ref2, ..., * ], # asterisk indicates the position of the default index.
86#	'printindorder' => [ ref1, ref2, ..., * ], # asterisk indicates the position of the default index.
87#}
88
89
90# Globals to handle multiple indices.
91my %indices;
92
93# This tells the system to use up to 7 words in index entries.
94$WORDS_IN_INDEX = 10;
95
96# KEC 2-18-05
97# Handles the \newindex command.  This is called if the \newindex command is
98#  encountered in the LaTex source.  Gets the index ref and title from the arguments.
99#  Saves the index ref and title.
100#  Note that we are called once to handle multiple \newindex commands that are
101#    newline-separated.
102sub do_cmd_newindex {
103	my $data = shift;
104	# The data is sent to us as fields delimited by their ID #'s.  We extract the
105	#  fields.
106	foreach my $line (split("\n",$data)) {
107		my @fields = split (/(?:\<\#\d+?\#\>)+/,$line);
108
109		# The index name and title are the second and fourth fields in the data.
110		if ($line =~ /^</ or $line =~ /^\\newindex/) {
111			my ($indexref,$indextitle) = ($fields[1],$fields[4]);
112			$indices{'title'}{$indexref} = $indextitle;
113			push (@{$indices{'newcmdorder'}},$indexref);
114		}
115	}
116}
117
118
119# KEC -- Copied from makeidx.perl and modified to do multiple indices.
120# Processes an \index entry from the LaTex file.
121#  Gets the optional argument from the index command, which is the name of the index
122#    into which to place the entry.
123#  Drops the brackets from the index_name
124#  Puts the index entry into the html stream
125#  Creates the tokenized index entry (which also saves the index entry info
126sub do_real_index {
127	local($_) = @_;
128	local($pat,$idx_entry,$index_name);
129	# catches opt-arg from \index commands for index.sty
130	$index_name = &get_next_optional_argument;
131	$index_name = "" unless defined $index_name;
132	# Drop leading and trailing brackets from the index name.
133	$index_name =~ s/^\[|\]$//g;
134
135	$idx_entry = &missing_braces unless (
136		(s/$next_pair_pr_rx/$pat=$1;$idx_entry=$2;''/e)
137		||(s/$next_pair_rx/$pat=$1;$idx_entry=$2;''/e));
138
139	if ($index_name and defined $idx_entry and
140		!defined $indices{'title'}{$index_name}) {
141			print STDERR "\nInvalid Index Name: \\index \[$index_name\]\{$idx_entry\}\n";
142	}
143
144	$idx_entry = &named_index_entry($pat, $idx_entry,$index_name);
145	$idx_entry.$_;
146}
147
148# Creates and saves an index entry in the index hashes.
149#  Modified to do multiple indices.
150#    Creates an index_key that allows index entries to have the same characteristics but be in
151#      different indices. This index_key is the regular key with the index name appended.
152#    Save the index order for the entry in the %index_order hash.
153sub named_index_entry {
154    local($br_id, $str, $index_name) = @_;
155	my ($index_key);
156    # escape the quoting etc characters
157    # ! -> \001
158    # @ -> \002
159    # | -> \003
160    $* = 1; $str =~ s/\n\s*/ /g; $* = 0; # remove any newlines
161    # protect \001 occurring with images
162    $str =~ s/\001/\016/g;			# 0x1 to 0xF
163    $str =~ s/\\\\/\011/g; 			# Double backslash -> 0xB
164    $str =~ s/\\;SPMquot;/\012/g; 	# \;SPMquot; -> 0xC
165    $str =~ s/;SPMquot;!/\013/g; 	# ;SPMquot; -> 0xD
166    $str =~ s/!/\001/g; 			# Exclamation point -> 0x1
167    $str =~ s/\013/!/g; 			# 0xD -> Exclaimation point
168    $str =~ s/;SPMquot;@/\015/g; 	# ;SPMquot;@ to 0xF
169    $str =~ s/@/\002/g; 			# At sign -> 0x2
170    $str =~ s/\015/@/g; 			# 0xF to At sign
171    $str =~ s/;SPMquot;\|/\017/g; 	# ;SMPquot;| to 0x11
172    $str =~ s/\|/\003/g; 			# Vertical line to 0x3
173    $str =~ s/\017/|/g; 			# 0x11 to vertical line
174    $str =~ s/;SPMquot;(.)/\1/g; 	# ;SPMquot; -> whatever the next character is
175    $str =~ s/\012/;SPMquot;/g; 	# 0x12 to ;SPMquot;
176    $str =~ s/\011/\\\\/g; 			# 0x11 to double backslash
177    local($key_part, $pageref) = split("\003", $str, 2);
178
179	# For any keys of the form: blablabla!blablabla, which want to be split at the
180	#   exclamation point, replace the ! with a comma and a space.  We don't do it
181	#   that way for this index.
182	$key_part =~ s/\001/, /g;
183    local(@keys) = split("\001", $key_part);
184    # If TITLE is not yet available use $before.
185    $TITLE = $saved_title if (($saved_title)&&(!($TITLE)||($TITLE eq $default_title)));
186    $TITLE = $before unless $TITLE;
187    # Save the reference
188    local($words) = '';
189    if ($SHOW_SECTION_NUMBERS) { $words = &make_idxnum; }
190		elsif ($SHORT_INDEX) { $words = &make_shortidxname; }
191		else { $words = &make_idxname; }
192    local($super_key) = '';
193    local($sort_key, $printable_key, $cur_key);
194    foreach $key (@keys) {
195		$key =~ s/\016/\001/g; # revert protected \001s
196		($sort_key, $printable_key) = split("\002", $key);
197		#
198		# RRM:  16 May 1996
199		# any \label in the printable-key will have already
200		# created a label where the \index occurred.
201		# This has to be removed, so that the desired label
202		# will be found on the Index page instead.
203		#
204		if ($printable_key =~ /tex2html_anchor_mark/ ) {
205			$printable_key =~ s/><tex2html_anchor_mark><\/A><A//g;
206			local($tmpA,$tmpB) = split("NAME=\"", $printable_key);
207			($tmpA,$tmpB) = split("\"", $tmpB);
208			$ref_files{$tmpA}='';
209			$index_labels{$tmpA} = 1;
210		}
211		#
212		# resolve and clean-up the hyperlink index-entries
213		# so they can be saved in an  index.pl  file
214		#
215		if ($printable_key =~ /$cross_ref_mark/ ) {
216			local($label,$id,$ref_label);
217	#	    $printable_key =~ s/$cross_ref_mark#(\w+)#(\w+)>$cross_ref_mark/
218			$printable_key =~ s/$cross_ref_mark#([^#]+)#([^>]+)>$cross_ref_mark/
219				do { ($label,$id) = ($1,$2);
220				$ref_label = $external_labels{$label} unless
221				($ref_label = $ref_files{$label});
222				'"' . "$ref_label#$label" . '">' .
223				&get_ref_mark($label,$id)}
224			/geo;
225		}
226		$printable_key =~ s/<\#[^\#>]*\#>//go;
227		#RRM
228		# recognise \char combinations, for a \backslash
229		#
230		$printable_key =~ s/\&\#;\'134/\\/g;		# restore \\s
231		$printable_key =~ s/\&\#;\`<BR> /\\/g;	#  ditto
232		$printable_key =~ s/\&\#;*SPMquot;92/\\/g;	#  ditto
233		#
234		#	$sort_key .= "@$printable_key" if !($printable_key);	# RRM
235		$sort_key .= "@$printable_key" if !($sort_key);	# RRM
236		$sort_key =~ tr/A-Z/a-z/;
237		if ($super_key) {
238			$cur_key = $super_key . "\001" . $sort_key;
239			$sub_index{$super_key} .= $cur_key . "\004";
240		} else {
241			$cur_key = $sort_key;
242		}
243
244		# Append the $index_name to the current key with a \002 delimiter.  This will
245		#  allow the same index entry to appear in more than one index.
246		$index_key = $cur_key . "\002$index_name";
247
248		$index{$index_key} .= "";
249
250		#
251		# RRM,  15 June 1996
252		# if there is no printable key, but one is known from
253		# a previous index-entry, then use it.
254		#
255		if (!($printable_key) && ($printable_key{$index_key}))
256			{ $printable_key = $printable_key{$index_key}; }
257#		if (!($printable_key) && ($printable_key{$cur_key}))
258#			{ $printable_key = $printable_key{$cur_key}; }
259		#
260		# do not overwrite the printable_key if it contains an anchor
261		#
262		if (!($printable_key{$index_key} =~ /tex2html_anchor_mark/ ))
263			{ $printable_key{$index_key} = $printable_key || $key; }
264#		if (!($printable_key{$cur_key} =~ /tex2html_anchor_mark/ ))
265#			{ $printable_key{$cur_key} = $printable_key || $key; }
266
267		$super_key = $cur_key;
268    }
269	#
270	# RRM
271	# page-ranges, from  |(  and  |)  and  |see
272	#
273    if ($pageref) {
274		if ($pageref eq "\(" ) {
275			$pageref = '';
276			$next .= " from ";
277		} elsif ($pageref eq "\)" ) {
278			$pageref = '';
279			local($next) = $index{$index_key};
280#			local($next) = $index{$cur_key};
281	#	    $next =~ s/[\|] *$//;
282			$next =~ s/(\n )?\| $//;
283			$index{$index_key} = "$next to ";
284#			$index{$cur_key} = "$next to ";
285		}
286    }
287
288    if ($pageref) {
289		$pageref =~ s/\s*$//g;	# remove trailing spaces
290		if (!$pageref) { $pageref = ' ' }
291		$pageref =~ s/see/<i>see <\/i> /g;
292		#
293		# RRM:  27 Dec 1996
294		# check if $pageref corresponds to a style command.
295		# If so, apply it to the $words.
296		#
297		local($tmp) = "do_cmd_$pageref";
298		if (defined &$tmp) {
299			$words = &$tmp("<#0#>$words<#0#>");
300			$words =~ s/<\#[^\#]*\#>//go;
301			$pageref = '';
302		}
303    }
304	#
305	# RRM:  25 May 1996
306	# any \label in the pageref section will have already
307	# created a label where the \index occurred.
308	# This has to be removed, so that the desired label
309	# will be found on the Index page instead.
310	#
311    if ($pageref) {
312		if ($pageref =~ /tex2html_anchor_mark/ ) {
313			$pageref =~ s/><tex2html_anchor_mark><\/A><A//g;
314			local($tmpA,$tmpB) = split("NAME=\"", $pageref);
315			($tmpA,$tmpB) = split("\"", $tmpB);
316			$ref_files{$tmpA}='';
317			$index_labels{$tmpA} = 1;
318		}
319		#
320		# resolve and clean-up any hyperlinks in the page-ref,
321		# so they can be saved in an  index.pl  file
322		#
323		if ($pageref =~ /$cross_ref_mark/ ) {
324			local($label,$id,$ref_label);
325			#	    $pageref =~ s/$cross_ref_mark#(\w+)#(\w+)>$cross_ref_mark/
326			$pageref =~ s/$cross_ref_mark#([^#]+)#([^>]+)>$cross_ref_mark/
327				do { ($label,$id) = ($1,$2);
328				$ref_files{$label} = ''; # ???? RRM
329				if ($index_labels{$label}) { $ref_label = ''; }
330					else { $ref_label = $external_labels{$label}
331						unless ($ref_label = $ref_files{$label});
332				}
333			'"' . "$ref_label#$label" . '">' . &get_ref_mark($label,$id)}/geo;
334		}
335		$pageref =~ s/<\#[^\#>]*\#>//go;
336
337		if ($pageref eq ' ') { $index{$index_key}='@'; }
338			else { $index{$index_key} .= $pageref . "\n | "; }
339    } else {
340		local($thisref) = &make_named_href('',"$CURRENT_FILE#$br_id",$words);
341		$thisref =~ s/\n//g;
342		$index{$index_key} .= $thisref."\n | ";
343    }
344	#print "\nREF: $sort_key : $index_key :$index{$index_key}";
345
346	#join('',"<A NAME=$br_id>$anchor_invisible_mark<\/A>",$_);
347
348    "<A NAME=\"$br_id\">$anchor_invisible_mark<\/A>";
349}
350
351
352# KEC. -- Copied from makeidx.perl, then modified to do multiple indices.
353#  Feeds the index entries to the output. This is called for each index to be built.
354#
355#  Generates a list of lookup keys for index entries, from both %printable_keys
356#    and %index keys.
357#  Sorts the keys according to index-sorting rules.
358#  Removes keys with a 0x01 token. (duplicates?)
359#  Builds a string to go to the index file.
360#    Adds the index entries to the string if they belong in this index.
361#    Keeps track of which index is being worked on, so only the proper entries
362#      are included.
363#  Places the index just built in to the output at the proper place.
364{ my $index_number = 0;
365sub add_real_idx {
366	print "\nDoing the index ... Index Number $index_number\n";
367	local($key, @keys, $next, $index, $old_key, $old_html);
368	my ($idx_ref,$keyref);
369	# RRM, 15.6.96:  index constructed from %printable_key, not %index
370	@keys = keys %printable_key;
371
372	while (/$idx_mark/) {
373		# Get the index reference from what follows the $idx_mark and
374		#  remove it from the string.
375		s/$idxmark\002(.*?)\002/$idxmark/;
376		$idx_ref = $1;
377		$index = '';
378		# include non- makeidx  index-entries
379		foreach $key (keys %index) {
380			next if $printable_key{$key};
381			$old_key = $key;
382			if ($key =~ s/###(.*)$//) {
383				next if $printable_key{$key};
384				push (@keys, $key);
385				$printable_key{$key} = $key;
386				if ($index{$old_key} =~ /HREF="([^"]*)"/i) {
387					$old_html = $1;
388					$old_html =~ /$dd?([^#\Q$dd\E]*)#/;
389					$old_html = $1;
390				} else { $old_html = '' }
391				$index{$key} = $index{$old_key} . $old_html."</A>\n | ";
392			};
393		}
394		@keys = sort makeidx_keysort @keys;
395		@keys = grep(!/\001/, @keys);
396		my $cnt = 0;
397		foreach $key (@keys) {
398			my ($keyref) = $key =~ /.*\002(.*)/;
399			next unless ($idx_ref eq $keyref);		# KEC.
400			$index .= &add_idx_key($key);
401			$cnt++;
402		}
403		print "$cnt Index Entries Added\n";
404		$index = '<DD>'.$index unless ($index =~ /^\s*<D(D|T)>/);
405		$index_number++;	# KEC.
406		if ($SHORT_INDEX) {
407			print "(compact version with Legend)";
408			local($num) = ( $index =~ s/\<D/<D/g );
409			if ($num > 50 ) {
410				s/$idx_mark/$preindex<HR><DL>\n$index\n<\/DL>$preindex/o;
411			} else {
412				s/$idx_mark/$preindex<HR><DL>\n$index\n<\/DL>/o;
413			}
414		} else {
415		s/$idx_mark/<DL COMPACT>\n$index\n<\/DL>/o; }
416	}
417}
418}
419
420# KEC.  Copied from latex2html.pl and modified to support multiple indices.
421# The bibliography and the index should be treated as separate sections
422# in their own HTML files. The \bibliography{} command acts as a sectioning command
423# that has the desired effect. But when the bibliography is constructed
424# manually using the thebibliography environment, or when using the
425# theindex environment it is not possible to use the normal sectioning
426# mechanism. This subroutine inserts a \bibliography{} or a dummy
427# \textohtmlindex command just before the appropriate environments
428# to force sectioning.
429sub add_bbl_and_idx_dummy_commands {
430	local($id) = $global{'max_id'};
431
432	s/([\\]begin\s*$O\d+$C\s*thebibliography)/$bbl_cnt++; $1/eg;
433	## if ($bbl_cnt == 1) {
434		s/([\\]begin\s*$O\d+$C\s*thebibliography)/$id++; "\\bibliography$O$id$C$O$id$C $1"/geo;
435	#}
436	$global{'max_id'} = $id;
437	# KEC. Modified to global substitution to place multiple index tokens.
438	s/[\\]begin\s*($O\d+$C)\s*theindex/\\textohtmlindex$1/go;
439	# KEC. Modified to pick up the optional argument to \printindex
440	s/[\\]printindex\s*(\[.*?\])?/
441		do { (defined $1) ? "\\textohtmlindex $1" : "\\textohtmlindex []"; } /ego;
442	&lib_add_bbl_and_idx_dummy_commands() if defined(&lib_add_bbl_and_idx_dummy_commands);
443}
444
445# KEC.  Copied from latex2html.pl and modified to support multiple indices.
446#  For each textohtmlindex mark found, determine the index titles and headers.
447#  We place the index ref in the header so the proper index can be generated later.
448#  For the default index, the index ref is blank.
449#
450#  One problem is that this routine is called twice..  Once for processing the
451#    command as originally seen, and once for processing the command when
452#    doing the name for the index file. We can detect that by looking at the
453#    id numbers (or ref) surrounding the \theindex command, and not incrementing
454#    index_number unless a new id (or ref) is seen.  This has the side effect of
455#    having to unconventionally start the index_number at -1. But it works.
456#
457#  Gets the title from the list of indices.
458#  If this is the first index, save the title in $first_idx_file. This is what's referenced
459#    in the navigation buttons.
460#  Increment the index_number for next time.
461#  If the indexname command is defined or a newcommand defined for indexname, do it.
462#  Save the index TITLE in the toc
463#  Save the first_idx_file into the idxfile. This goes into the nav buttons.
464#  Build index_labels if needed.
465#  Create the index headings and put them in the output stream.
466
467{ my $index_number = 0;  # Will be incremented before use.
468	my $first_idx_file;  # Static
469	my $no_increment = 0;
470
471sub do_cmd_textohtmlindex {
472	local($_) = @_;
473	my ($idxref,$idxnum,$index_name);
474
475	# We get called from make_name with the first argument = "\001noincrement". This is a sign
476	#  to not increment $index_number the next time we are called. We get called twice, once
477	#  my make_name and once by process_command.  Unfortunately, make_name calls us just to set the name
478	#  but doesn't use the result so we get called a second time by process_command.  This works fine
479	#  except for cases where there are multiple indices except if they aren't named, which is the case
480	#  when the index is inserted by an include command in latex. In these cases we are only able to use
481	#  the index number to decide which index to draw from, and we don't know how to increment that index
482	#  number if we get called a variable number of times for the same index, as is the case between
483	#  making html (one output file) and web (multiple output files) output formats.
484	if (/\001noincrement/) {
485		$no_increment = 1;
486		return;
487	}
488
489	# Remove (but save) the index reference
490	s/^\s*\[(.*?)\]/{$idxref = $1; "";}/e;
491
492	# If we have an $idxref, the index name was specified.  In this case, we have all the
493	#  information we need to carry on.  Otherwise, we need to get the idxref
494	#  from the $index_number and set the name to "Index".
495	if ($idxref) {
496		$index_name = $indices{'title'}{$idxref};
497	} else {
498		if (defined ($idxref = $indices{'newcmdorder'}->[$index_number])) {
499			$index_name = $indices{'title'}{$idxref};
500		} else {
501			$idxref = '';
502			$index_name = "Index";
503		}
504	}
505
506	$idx_title = "Index"; # The name displayed in the nav bar text.
507
508	# Only set $idxfile if we are at the first index.  This will point the
509	#  navigation panel to the first index file rather than the last.
510	$first_idx_file = $CURRENT_FILE if ($index_number == 0);
511	$idxfile = $first_idx_file; # Pointer for the Index button in the nav bar.
512	$toc_sec_title = $index_name; # Index link text in the toc.
513	$TITLE = $toc_sec_title; # Title for this index, from which its filename is built.
514	if (%index_labels) { &make_index_labels(); }
515	if (($SHORT_INDEX) && (%index_segment)) { &make_preindex(); }
516		else { $preindex = ''; }
517	local $idx_head = $section_headings{'textohtmlindex'};
518	local($heading) = join(''
519		, &make_section_heading($TITLE, $idx_head)
520		, $idx_mark, "\002", $idxref, "\002" );
521	local($pre,$post) = &minimize_open_tags($heading);
522	$index_number++ unless ($no_increment);
523	$no_increment = 0;
524	join('',"<BR>\n" , $pre, $_);
525}
526}
527
528# Returns an index key, given the key passed as the first argument.
529#  Not modified for multiple indices.
530sub add_idx_key {
531    local($key) = @_;
532	local($index, $next);
533	if (($index{$key} eq '@' )&&(!($index_printed{$key}))) {
534		if ($SHORT_INDEX) { $index .= "<DD><BR>\n<DT>".&print_key."\n<DD>"; }
535			else { $index .= "<DT><DD><BR>\n<DT>".&print_key."\n<DD>"; }
536	} elsif (($index{$key})&&(!($index_printed{$key}))) {
537		if ($SHORT_INDEX) {
538			$next = "<DD>".&print_key."\n : ". &print_idx_links;
539		} else {
540			$next = "<DT>".&print_key."\n<DD>". &print_idx_links;
541		}
542		$index .= $next."\n";
543		$index_printed{$key} = 1;
544	}
545
546	if ($sub_index{$key}) {
547		local($subkey, @subkeys, $subnext, $subindex);
548		@subkeys = sort(split("\004", $sub_index{$key}));
549		if ($SHORT_INDEX) {
550			$index .= "<DD>".&print_key  unless $index_printed{$key};
551			$index .= "<DL>\n";
552		} else {
553			$index .= "<DT>".&print_key."\n<DD>"  unless $index_printed{$key};
554			$index .= "<DL COMPACT>\n";
555		}
556		foreach $subkey (@subkeys) {
557			$index .= &add_sub_idx_key($subkey) unless ($index_printed{$subkey});
558		}
559		$index .= "</DL>\n";
560	}
561	return $index;
562}
563
5641;  # Must be present as the last line.
565