11cc83814Sespie /* index.c -- indexing for Texinfo.
2*a1acfa9bSespie $Id: index.c,v 1.1.1.3 2006/07/17 16:03:46 espie Exp $
31cc83814Sespie
4*a1acfa9bSespie Copyright (C) 1998, 1999, 2002, 2003, 2004 Free Software Foundation,
5*a1acfa9bSespie Inc.
61cc83814Sespie
71cc83814Sespie This program is free software; you can redistribute it and/or modify
81cc83814Sespie it under the terms of the GNU General Public License as published by
91cc83814Sespie the Free Software Foundation; either version 2, or (at your option)
101cc83814Sespie any later version.
111cc83814Sespie
121cc83814Sespie This program is distributed in the hope that it will be useful,
131cc83814Sespie but WITHOUT ANY WARRANTY; without even the implied warranty of
141cc83814Sespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
151cc83814Sespie GNU General Public License for more details.
161cc83814Sespie
171cc83814Sespie You should have received a copy of the GNU General Public License
181cc83814Sespie along with this program; if not, write to the Free Software Foundation,
191cc83814Sespie Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
201cc83814Sespie
211cc83814Sespie #include "system.h"
22*a1acfa9bSespie #include "files.h"
23*a1acfa9bSespie #include "footnote.h"
24*a1acfa9bSespie #include "html.h"
251cc83814Sespie #include "index.h"
261cc83814Sespie #include "lang.h"
271cc83814Sespie #include "macro.h"
28*a1acfa9bSespie #include "sectioning.h"
291cc83814Sespie #include "toc.h"
303fb98d4aSespie #include "xml.h"
311cc83814Sespie
321cc83814Sespie INDEX_ALIST **name_index_alist = NULL;
331cc83814Sespie
341cc83814Sespie /* An array of pointers. Each one is for a different index. The
351cc83814Sespie "synindex" command changes which array slot is pointed to by a
361cc83814Sespie given "index". */
371cc83814Sespie INDEX_ELT **the_indices = NULL;
381cc83814Sespie
391cc83814Sespie /* The number of defined indices. */
401cc83814Sespie int defined_indices = 0;
411cc83814Sespie
42*a1acfa9bSespie /* This is the order of the index. */
43*a1acfa9bSespie int index_counter = 0;
44*a1acfa9bSespie
451cc83814Sespie /* Stuff for defining commands on the fly. */
461cc83814Sespie COMMAND **user_command_array = NULL;
471cc83814Sespie int user_command_array_len = 0;
481cc83814Sespie
491cc83814Sespie /* How to compare index entries for sorting. May be set to strcoll. */
50*a1acfa9bSespie int (*index_compare_fn) (const char *a, const char *b) = strcasecmp;
51*a1acfa9bSespie
52*a1acfa9bSespie /* Function to compare index entries for sorting. (Calls
53*a1acfa9bSespie `index_compare_fn' above.) */
54*a1acfa9bSespie int index_element_compare (const void *element1, const void *element2);
551cc83814Sespie
561cc83814Sespie /* Find which element in the known list of indices has this name.
571cc83814Sespie Returns -1 if NAME isn't found. */
581cc83814Sespie static int
find_index_offset(char * name)59*a1acfa9bSespie find_index_offset (char *name)
601cc83814Sespie {
611cc83814Sespie int i;
621cc83814Sespie for (i = 0; i < defined_indices; i++)
631cc83814Sespie if (name_index_alist[i] && STREQ (name, name_index_alist[i]->name))
641cc83814Sespie return i;
651cc83814Sespie return -1;
661cc83814Sespie }
671cc83814Sespie
681cc83814Sespie /* Return a pointer to the entry of (name . index) for this name.
691cc83814Sespie Return NULL if the index doesn't exist. */
70*a1acfa9bSespie static INDEX_ALIST *
find_index(char * name)71*a1acfa9bSespie find_index (char *name)
721cc83814Sespie {
731cc83814Sespie int offset = find_index_offset (name);
741cc83814Sespie if (offset > -1)
751cc83814Sespie return name_index_alist[offset];
761cc83814Sespie else
771cc83814Sespie return NULL;
781cc83814Sespie }
791cc83814Sespie
801cc83814Sespie /* User-defined commands, which happens only from user-defined indexes.
811cc83814Sespie Used to initialize the builtin indices, too. */
82*a1acfa9bSespie static void
define_user_command(char * name,COMMAND_FUNCTION (* proc),int needs_braces_p)83*a1acfa9bSespie define_user_command (char *name, COMMAND_FUNCTION (*proc), int needs_braces_p)
841cc83814Sespie {
851cc83814Sespie int slot = user_command_array_len;
861cc83814Sespie user_command_array_len++;
871cc83814Sespie
881cc83814Sespie if (!user_command_array)
891cc83814Sespie user_command_array = xmalloc (1 * sizeof (COMMAND *));
901cc83814Sespie
911cc83814Sespie user_command_array = xrealloc (user_command_array,
921cc83814Sespie (1 + user_command_array_len) * sizeof (COMMAND *));
931cc83814Sespie
941cc83814Sespie user_command_array[slot] = xmalloc (sizeof (COMMAND));
951cc83814Sespie user_command_array[slot]->name = xstrdup (name);
961cc83814Sespie user_command_array[slot]->proc = proc;
971cc83814Sespie user_command_array[slot]->argument_in_braces = needs_braces_p;
981cc83814Sespie }
991cc83814Sespie
1001cc83814Sespie /* Please release me, let me go... */
1011cc83814Sespie static void
free_index(INDEX_ELT * index)102*a1acfa9bSespie free_index (INDEX_ELT *index)
1031cc83814Sespie {
1041cc83814Sespie INDEX_ELT *temp;
1051cc83814Sespie
1061cc83814Sespie while ((temp = index))
1071cc83814Sespie {
1081cc83814Sespie free (temp->entry);
1091cc83814Sespie free (temp->entry_text);
1101cc83814Sespie /* Do not free the node, because we already freed the tag table,
1111cc83814Sespie which freed all the node names. */
1121cc83814Sespie /* free (temp->node); */
1131cc83814Sespie index = index->next;
1141cc83814Sespie free (temp);
1151cc83814Sespie }
1161cc83814Sespie }
1171cc83814Sespie
1181cc83814Sespie /* Flush an index by name. This will delete the list of entries that
1191cc83814Sespie would be written by a @printindex command for this index. */
1201cc83814Sespie static void
undefindex(char * name)121*a1acfa9bSespie undefindex (char *name)
1221cc83814Sespie {
1231cc83814Sespie int i;
1241cc83814Sespie int which = find_index_offset (name);
1251cc83814Sespie
1261cc83814Sespie /* The index might have already been freed if this was the target of
1271cc83814Sespie an @synindex. */
1281cc83814Sespie if (which < 0 || !name_index_alist[which])
1291cc83814Sespie return;
1301cc83814Sespie
1311cc83814Sespie i = name_index_alist[which]->read_index;
1321cc83814Sespie
1331cc83814Sespie free_index (the_indices[i]);
1341cc83814Sespie the_indices[i] = NULL;
1351cc83814Sespie
1361cc83814Sespie free (name_index_alist[which]->name);
1371cc83814Sespie free (name_index_alist[which]);
1381cc83814Sespie name_index_alist[which] = NULL;
1391cc83814Sespie }
1401cc83814Sespie
141*a1acfa9bSespie /* Add the arguments to the current index command to the index NAME. */
1421cc83814Sespie static void
index_add_arg(char * name)143*a1acfa9bSespie index_add_arg (char *name)
1441cc83814Sespie {
1451cc83814Sespie int which;
1461cc83814Sespie char *index_entry;
1471cc83814Sespie INDEX_ALIST *tem;
1481cc83814Sespie
1491cc83814Sespie tem = find_index (name);
1501cc83814Sespie
1511cc83814Sespie which = tem ? tem->write_index : -1;
1521cc83814Sespie
1531cc83814Sespie if (macro_expansion_output_stream && !executing_string)
1541cc83814Sespie append_to_expansion_output (input_text_offset + 1);
1551cc83814Sespie
1561cc83814Sespie get_rest_of_line (0, &index_entry);
1571cc83814Sespie ignore_blank_line ();
1581cc83814Sespie
1591cc83814Sespie if (macro_expansion_output_stream && !executing_string)
1601cc83814Sespie {
1611cc83814Sespie char *index_line = xmalloc (strlen (index_entry) + 2);
1621cc83814Sespie sprintf (index_line, "%s\n", index_entry);
1631cc83814Sespie me_execute_string_keep_state (index_line, NULL);
1641cc83814Sespie free (index_line);
1651cc83814Sespie }
1661cc83814Sespie
1671cc83814Sespie if (which < 0)
1681cc83814Sespie {
1691cc83814Sespie line_error (_("Unknown index `%s'"), name);
1701cc83814Sespie free (index_entry);
1711cc83814Sespie }
1721cc83814Sespie else
1731cc83814Sespie {
1741cc83814Sespie INDEX_ELT *new = xmalloc (sizeof (INDEX_ELT));
175*a1acfa9bSespie
176*a1acfa9bSespie index_counter++;
177*a1acfa9bSespie
178*a1acfa9bSespie /* Get output line number updated before doing anything. */
179*a1acfa9bSespie if (!html && !xml)
180*a1acfa9bSespie flush_output ();
181*a1acfa9bSespie
1821cc83814Sespie new->next = the_indices[which];
1831cc83814Sespie new->entry = NULL;
184*a1acfa9bSespie new->entry_text = index_entry;
185*a1acfa9bSespie /* Since footnotes are handled at the very end of the document,
186*a1acfa9bSespie node name in the non-split HTML outputs always show the last
187*a1acfa9bSespie node. We artificially make it ``Footnotes''. */
188*a1acfa9bSespie if (html && !splitting && already_outputting_pending_notes)
189*a1acfa9bSespie new->node = xstrdup (_("Footnotes"));
190*a1acfa9bSespie else
1911cc83814Sespie new->node = current_node ? current_node : xstrdup ("");
192*a1acfa9bSespie if (!html && !xml && no_headers)
193*a1acfa9bSespie {
194*a1acfa9bSespie new->section = current_sectioning_number ();
195*a1acfa9bSespie if (strlen (new->section) == 0)
196*a1acfa9bSespie new->section_name = current_sectioning_name ();
197*a1acfa9bSespie else
198*a1acfa9bSespie new->section_name = "";
199*a1acfa9bSespie }
200*a1acfa9bSespie else
201*a1acfa9bSespie {
202*a1acfa9bSespie new->section = NULL;
203*a1acfa9bSespie new->section_name = NULL;
204*a1acfa9bSespie }
2051cc83814Sespie new->code = tem->code;
2061cc83814Sespie new->defining_line = line_number - 1;
207*a1acfa9bSespie new->output_line = no_headers ? output_line_number : node_line_number;
2081cc83814Sespie /* We need to make a copy since input_filename may point to
2091cc83814Sespie something that goes away, for example, inside a macro.
2101cc83814Sespie (see the findexerr test). */
2111cc83814Sespie new->defining_file = xstrdup (input_filename);
212*a1acfa9bSespie
213*a1acfa9bSespie if (html && splitting)
214*a1acfa9bSespie {
215*a1acfa9bSespie if (current_output_filename && *current_output_filename)
216*a1acfa9bSespie new->output_file = filename_part (current_output_filename);
217*a1acfa9bSespie else
218*a1acfa9bSespie new->output_file = xstrdup ("");
219*a1acfa9bSespie }
220*a1acfa9bSespie else
221*a1acfa9bSespie new->output_file = NULL;
222*a1acfa9bSespie
223*a1acfa9bSespie new->entry_number = index_counter;
2241cc83814Sespie the_indices[which] = new;
225*a1acfa9bSespie
2263fb98d4aSespie #if 0
2273fb98d4aSespie /* The index breaks if there are colons in the entry.
2283fb98d4aSespie -- This is true, but it's too painful to force changing index
2293fb98d4aSespie entries to use `colon', and too confusing for users. The real
2303fb98d4aSespie fix is to change Info support to support arbitrary characters
2313fb98d4aSespie in node names, and we're not ready to do that. --karl,
2323fb98d4aSespie 19mar02. */
2333fb98d4aSespie if (strchr (new->entry_text, ':'))
2343fb98d4aSespie warning (_("Info cannot handle `:' in index entry `%s'"),
2353fb98d4aSespie new->entry_text);
2363fb98d4aSespie #endif
237*a1acfa9bSespie
238*a1acfa9bSespie if (html)
239*a1acfa9bSespie {
240*a1acfa9bSespie /* Anchor. */
241*a1acfa9bSespie int removed_empty_elt = 0;
242*a1acfa9bSespie
243*a1acfa9bSespie /* We must put the anchor outside the <dl> and <ul> blocks. */
244*a1acfa9bSespie if (rollback_empty_tag ("dl"))
245*a1acfa9bSespie removed_empty_elt = 1;
246*a1acfa9bSespie else if (rollback_empty_tag ("ul"))
247*a1acfa9bSespie removed_empty_elt = 2;
248*a1acfa9bSespie
249*a1acfa9bSespie add_word ("<a name=\"index-");
250*a1acfa9bSespie add_escaped_anchor_name (index_entry, 0);
251*a1acfa9bSespie add_word_args ("-%d\"></a>", index_counter);
252*a1acfa9bSespie
253*a1acfa9bSespie if (removed_empty_elt == 1)
254*a1acfa9bSespie add_html_block_elt_args ("\n<dl>");
255*a1acfa9bSespie else if (removed_empty_elt == 2)
256*a1acfa9bSespie add_html_block_elt_args ("\n<ul>");
2571cc83814Sespie }
258*a1acfa9bSespie }
259*a1acfa9bSespie
2603fb98d4aSespie if (xml)
2613fb98d4aSespie xml_insert_indexterm (index_entry, name);
2621cc83814Sespie }
2631cc83814Sespie
2641cc83814Sespie /* The function which user defined index commands call. */
2651cc83814Sespie static void
gen_index(void)266*a1acfa9bSespie gen_index (void)
2671cc83814Sespie {
2681cc83814Sespie char *name = xstrdup (command);
2691cc83814Sespie if (strlen (name) >= strlen ("index"))
2701cc83814Sespie name[strlen (name) - strlen ("index")] = 0;
2711cc83814Sespie index_add_arg (name);
2721cc83814Sespie free (name);
2731cc83814Sespie }
2741cc83814Sespie
2751cc83814Sespie /* Define an index known as NAME. We assign the slot number.
2761cc83814Sespie If CODE is nonzero, make this a code index. */
2771cc83814Sespie static void
defindex(char * name,int code)278*a1acfa9bSespie defindex (char *name, int code)
2791cc83814Sespie {
2801cc83814Sespie int i, slot;
2811cc83814Sespie
2821cc83814Sespie /* If it already exists, flush it. */
2831cc83814Sespie undefindex (name);
2841cc83814Sespie
2851cc83814Sespie /* Try to find an empty slot. */
2861cc83814Sespie slot = -1;
2871cc83814Sespie for (i = 0; i < defined_indices; i++)
2881cc83814Sespie if (!name_index_alist[i])
2891cc83814Sespie {
2901cc83814Sespie slot = i;
2911cc83814Sespie break;
2921cc83814Sespie }
2931cc83814Sespie
2941cc83814Sespie if (slot < 0)
2951cc83814Sespie { /* No such luck. Make space for another index. */
2961cc83814Sespie slot = defined_indices;
2971cc83814Sespie defined_indices++;
2981cc83814Sespie
2991cc83814Sespie name_index_alist = (INDEX_ALIST **)
3001cc83814Sespie xrealloc (name_index_alist, (1 + defined_indices)
3011cc83814Sespie * sizeof (INDEX_ALIST *));
3021cc83814Sespie the_indices = (INDEX_ELT **)
3031cc83814Sespie xrealloc (the_indices, (1 + defined_indices) * sizeof (INDEX_ELT *));
3041cc83814Sespie }
3051cc83814Sespie
3061cc83814Sespie /* We have a slot. Start assigning. */
3071cc83814Sespie name_index_alist[slot] = xmalloc (sizeof (INDEX_ALIST));
3081cc83814Sespie name_index_alist[slot]->name = xstrdup (name);
3091cc83814Sespie name_index_alist[slot]->read_index = slot;
3101cc83814Sespie name_index_alist[slot]->write_index = slot;
3111cc83814Sespie name_index_alist[slot]->code = code;
3121cc83814Sespie
3131cc83814Sespie the_indices[slot] = NULL;
3141cc83814Sespie }
3151cc83814Sespie
3161cc83814Sespie /* Define an index NAME, implicitly @code if CODE is nonzero. */
3171cc83814Sespie static void
top_defindex(char * name,int code)318*a1acfa9bSespie top_defindex (char *name, int code)
3191cc83814Sespie {
3201cc83814Sespie char *temp;
3211cc83814Sespie
3221cc83814Sespie temp = xmalloc (1 + strlen (name) + strlen ("index"));
3231cc83814Sespie sprintf (temp, "%sindex", name);
3241cc83814Sespie define_user_command (temp, gen_index, 0);
3251cc83814Sespie defindex (name, code);
3261cc83814Sespie free (temp);
3271cc83814Sespie }
3281cc83814Sespie
3291cc83814Sespie /* Set up predefined indices. */
3301cc83814Sespie void
init_indices(void)331*a1acfa9bSespie init_indices (void)
3321cc83814Sespie {
3331cc83814Sespie int i;
3341cc83814Sespie
3351cc83814Sespie /* Create the default data structures. */
3361cc83814Sespie
3371cc83814Sespie /* Initialize data space. */
3381cc83814Sespie if (!the_indices)
3391cc83814Sespie {
3401cc83814Sespie the_indices = xmalloc ((1 + defined_indices) * sizeof (INDEX_ELT *));
3411cc83814Sespie the_indices[defined_indices] = NULL;
3421cc83814Sespie
3431cc83814Sespie name_index_alist = xmalloc ((1 + defined_indices)
3441cc83814Sespie * sizeof (INDEX_ALIST *));
3451cc83814Sespie name_index_alist[defined_indices] = NULL;
3461cc83814Sespie }
3471cc83814Sespie
3481cc83814Sespie /* If there were existing indices, get rid of them now. */
3491cc83814Sespie for (i = 0; i < defined_indices; i++)
3501cc83814Sespie {
3511cc83814Sespie if (name_index_alist[i])
3521cc83814Sespie { /* Suppose we're called with two input files, and the first
3531cc83814Sespie does a @synindex pg cp. Then, when we get here to start
3541cc83814Sespie the second file, the "pg" element won't get freed by
3551cc83814Sespie undefindex (because it's pointing to "cp"). So free it
3561cc83814Sespie here; otherwise, when we try to define the pg index again
3571cc83814Sespie just below, it will still point to cp. */
358*a1acfa9bSespie undefindex (name_index_alist[i]->name);
359*a1acfa9bSespie
360*a1acfa9bSespie /* undefindex sets all this to null in some cases. */
361*a1acfa9bSespie if (name_index_alist[i])
362*a1acfa9bSespie {
3631cc83814Sespie free (name_index_alist[i]->name);
3641cc83814Sespie free (name_index_alist[i]);
3651cc83814Sespie name_index_alist[i] = NULL;
3661cc83814Sespie }
3671cc83814Sespie }
368*a1acfa9bSespie }
3691cc83814Sespie
3701cc83814Sespie /* Add the default indices. */
3711cc83814Sespie top_defindex ("cp", 0); /* cp is the only non-code index. */
3721cc83814Sespie top_defindex ("fn", 1);
3731cc83814Sespie top_defindex ("ky", 1);
3741cc83814Sespie top_defindex ("pg", 1);
3751cc83814Sespie top_defindex ("tp", 1);
3761cc83814Sespie top_defindex ("vr", 1);
3771cc83814Sespie }
3781cc83814Sespie
3791cc83814Sespie /* Given an index name, return the offset in the_indices of this index,
3801cc83814Sespie or -1 if there is no such index. */
381*a1acfa9bSespie static int
translate_index(char * name)382*a1acfa9bSespie translate_index (char *name)
3831cc83814Sespie {
3841cc83814Sespie INDEX_ALIST *which = find_index (name);
3851cc83814Sespie
3861cc83814Sespie if (which)
3871cc83814Sespie return which->read_index;
3881cc83814Sespie else
3891cc83814Sespie return -1;
3901cc83814Sespie }
3911cc83814Sespie
3921cc83814Sespie /* Return the index list which belongs to NAME. */
3931cc83814Sespie INDEX_ELT *
index_list(char * name)394*a1acfa9bSespie index_list (char *name)
3951cc83814Sespie {
3961cc83814Sespie int which = translate_index (name);
3971cc83814Sespie if (which < 0)
3981cc83814Sespie return (INDEX_ELT *) -1;
3991cc83814Sespie else
4001cc83814Sespie return the_indices[which];
4011cc83814Sespie }
4021cc83814Sespie
4031cc83814Sespie /* Define a new index command. Arg is name of index. */
4041cc83814Sespie static void
gen_defindex(int code)405*a1acfa9bSespie gen_defindex (int code)
4061cc83814Sespie {
4071cc83814Sespie char *name;
4081cc83814Sespie get_rest_of_line (0, &name);
4091cc83814Sespie
4101cc83814Sespie if (find_index (name))
4111cc83814Sespie {
4121cc83814Sespie line_error (_("Index `%s' already exists"), name);
4131cc83814Sespie }
4141cc83814Sespie else
4151cc83814Sespie {
4161cc83814Sespie char *temp = xmalloc (strlen (name) + sizeof ("index"));
4171cc83814Sespie sprintf (temp, "%sindex", name);
4181cc83814Sespie define_user_command (temp, gen_index, 0);
4191cc83814Sespie defindex (name, code);
4201cc83814Sespie free (temp);
4211cc83814Sespie }
4221cc83814Sespie
4231cc83814Sespie free (name);
4241cc83814Sespie }
4251cc83814Sespie
4261cc83814Sespie void
cm_defindex(void)427*a1acfa9bSespie cm_defindex (void)
4281cc83814Sespie {
4291cc83814Sespie gen_defindex (0);
4301cc83814Sespie }
4311cc83814Sespie
4321cc83814Sespie void
cm_defcodeindex(void)433*a1acfa9bSespie cm_defcodeindex (void)
4341cc83814Sespie {
4351cc83814Sespie gen_defindex (1);
4361cc83814Sespie }
4371cc83814Sespie
4381cc83814Sespie /* Expects 2 args, on the same line. Both are index abbreviations.
4391cc83814Sespie Make the first one be a synonym for the second one, i.e. make the
4401cc83814Sespie first one have the same index as the second one. */
4411cc83814Sespie void
cm_synindex(void)442*a1acfa9bSespie cm_synindex (void)
4431cc83814Sespie {
4441cc83814Sespie int source, target;
4451cc83814Sespie char *abbrev1, *abbrev2;
4461cc83814Sespie
4471cc83814Sespie skip_whitespace ();
4481cc83814Sespie get_until_in_line (0, " ", &abbrev1);
4491cc83814Sespie target = find_index_offset (abbrev1);
4501cc83814Sespie skip_whitespace ();
4511cc83814Sespie get_until_in_line (0, " ", &abbrev2);
4521cc83814Sespie source = find_index_offset (abbrev2);
4531cc83814Sespie if (source < 0 || target < 0)
4541cc83814Sespie {
4551cc83814Sespie line_error (_("Unknown index `%s' and/or `%s' in @synindex"),
4561cc83814Sespie abbrev1, abbrev2);
4571cc83814Sespie }
4581cc83814Sespie else
4591cc83814Sespie {
460*a1acfa9bSespie if (xml && !docbook)
461*a1acfa9bSespie xml_synindex (abbrev1, abbrev2);
462*a1acfa9bSespie else
4631cc83814Sespie name_index_alist[target]->write_index
4641cc83814Sespie = name_index_alist[source]->write_index;
4651cc83814Sespie }
4661cc83814Sespie
4671cc83814Sespie free (abbrev1);
4681cc83814Sespie free (abbrev2);
4691cc83814Sespie }
4701cc83814Sespie
4711cc83814Sespie void
cm_pindex(void)472*a1acfa9bSespie cm_pindex (void) /* Pinhead index. */
4731cc83814Sespie {
4741cc83814Sespie index_add_arg ("pg");
4751cc83814Sespie }
4761cc83814Sespie
4771cc83814Sespie void
cm_vindex(void)478*a1acfa9bSespie cm_vindex (void) /* Variable index. */
4791cc83814Sespie {
4801cc83814Sespie index_add_arg ("vr");
4811cc83814Sespie }
4821cc83814Sespie
4831cc83814Sespie void
cm_kindex(void)484*a1acfa9bSespie cm_kindex (void) /* Key index. */
4851cc83814Sespie {
4861cc83814Sespie index_add_arg ("ky");
4871cc83814Sespie }
4881cc83814Sespie
4891cc83814Sespie void
cm_cindex(void)490*a1acfa9bSespie cm_cindex (void) /* Concept index. */
4911cc83814Sespie {
4921cc83814Sespie index_add_arg ("cp");
4931cc83814Sespie }
4941cc83814Sespie
4951cc83814Sespie void
cm_findex(void)496*a1acfa9bSespie cm_findex (void) /* Function index. */
4971cc83814Sespie {
4981cc83814Sespie index_add_arg ("fn");
4991cc83814Sespie }
5001cc83814Sespie
5011cc83814Sespie void
cm_tindex(void)502*a1acfa9bSespie cm_tindex (void) /* Data Type index. */
5031cc83814Sespie {
5041cc83814Sespie index_add_arg ("tp");
5051cc83814Sespie }
5061cc83814Sespie
5071cc83814Sespie int
index_element_compare(const void * element1,const void * element2)508*a1acfa9bSespie index_element_compare (const void *element1, const void *element2)
5091cc83814Sespie {
510*a1acfa9bSespie INDEX_ELT **elt1 = (INDEX_ELT **) element1;
511*a1acfa9bSespie INDEX_ELT **elt2 = (INDEX_ELT **) element2;
512*a1acfa9bSespie
513*a1acfa9bSespie return index_compare_fn ((*elt1)->entry, (*elt2)->entry);
5141cc83814Sespie }
5151cc83814Sespie
5161cc83814Sespie /* Force all index entries to be unique. */
517*a1acfa9bSespie static void
make_index_entries_unique(INDEX_ELT ** array,int count)518*a1acfa9bSespie make_index_entries_unique (INDEX_ELT **array, int count)
5191cc83814Sespie {
5201cc83814Sespie int i, j;
5211cc83814Sespie INDEX_ELT **copy;
5221cc83814Sespie int counter = 1;
5231cc83814Sespie
5241cc83814Sespie copy = xmalloc ((1 + count) * sizeof (INDEX_ELT *));
5251cc83814Sespie
5261cc83814Sespie for (i = 0, j = 0; i < count; i++)
5271cc83814Sespie {
5281cc83814Sespie if (i == (count - 1)
5291cc83814Sespie || array[i]->node != array[i + 1]->node
5301cc83814Sespie || !STREQ (array[i]->entry, array[i + 1]->entry))
5311cc83814Sespie copy[j++] = array[i];
5321cc83814Sespie else
5331cc83814Sespie {
5341cc83814Sespie free (array[i]->entry);
5351cc83814Sespie free (array[i]->entry_text);
5361cc83814Sespie free (array[i]);
5371cc83814Sespie }
5381cc83814Sespie }
5391cc83814Sespie copy[j] = NULL;
5401cc83814Sespie
5411cc83814Sespie /* Now COPY contains only unique entries. Duplicated entries in the
5421cc83814Sespie original array have been freed. Replace the current array with
5431cc83814Sespie the copy, fixing the NEXT pointers. */
5441cc83814Sespie for (i = 0; copy[i]; i++)
5451cc83814Sespie {
5461cc83814Sespie copy[i]->next = copy[i + 1];
5471cc83814Sespie
5481cc83814Sespie /* Fix entry names which are the same. They point to different nodes,
5491cc83814Sespie so we make the entry name unique. */
5501cc83814Sespie if (copy[i+1]
5511cc83814Sespie && STREQ (copy[i]->entry, copy[i + 1]->entry)
5521cc83814Sespie && !html)
5531cc83814Sespie {
5541cc83814Sespie char *new_entry_name;
5551cc83814Sespie
5561cc83814Sespie new_entry_name = xmalloc (10 + strlen (copy[i]->entry));
5571cc83814Sespie sprintf (new_entry_name, "%s <%d>", copy[i]->entry, counter);
5581cc83814Sespie free (copy[i]->entry);
5591cc83814Sespie copy[i]->entry = new_entry_name;
5601cc83814Sespie counter++;
5611cc83814Sespie }
5621cc83814Sespie else
5631cc83814Sespie counter = 1;
5641cc83814Sespie
5651cc83814Sespie array[i] = copy[i];
5661cc83814Sespie }
5671cc83814Sespie array[i] = NULL;
5681cc83814Sespie
5691cc83814Sespie /* Free the storage used only by COPY. */
5701cc83814Sespie free (copy);
5711cc83814Sespie }
5721cc83814Sespie
573*a1acfa9bSespie
574*a1acfa9bSespie /* Sort the index passed in INDEX, returning an array of pointers to
575*a1acfa9bSespie elements. The array is terminated with a NULL pointer. */
576*a1acfa9bSespie
577*a1acfa9bSespie static INDEX_ELT **
sort_index(INDEX_ELT * index)578*a1acfa9bSespie sort_index (INDEX_ELT *index)
5791cc83814Sespie {
5801cc83814Sespie INDEX_ELT **array;
581*a1acfa9bSespie INDEX_ELT *temp;
5821cc83814Sespie int count = 0;
5831cc83814Sespie int save_line_number = line_number;
5841cc83814Sespie char *save_input_filename = input_filename;
5851cc83814Sespie int save_html = html;
5861cc83814Sespie
5871cc83814Sespie /* Pretend we are in non-HTML mode, for the purpose of getting the
5881cc83814Sespie expanded index entry that lacks any markup and other HTML escape
5891cc83814Sespie characters which could produce a wrong sort order. */
5901cc83814Sespie /* fixme: html: this still causes some markup, such as non-ASCII
5911cc83814Sespie characters @AE{} etc., to sort incorrectly. */
5921cc83814Sespie html = 0;
5931cc83814Sespie
594*a1acfa9bSespie for (temp = index, count = 0; temp; temp = temp->next, count++)
595*a1acfa9bSespie ;
596*a1acfa9bSespie /* We have the length, now we can allocate an array. */
5971cc83814Sespie array = xmalloc ((count + 1) * sizeof (INDEX_ELT *));
5981cc83814Sespie
599*a1acfa9bSespie for (temp = index, count = 0; temp; temp = temp->next, count++)
6001cc83814Sespie {
601*a1acfa9bSespie /* Allocate new memory for the return array, since parts of the
602*a1acfa9bSespie original INDEX get freed. Otherwise, if the document calls
603*a1acfa9bSespie @printindex twice on the same index, with duplicate entries,
604*a1acfa9bSespie we'll have garbage the second time. There are cleaner ways to
605*a1acfa9bSespie deal, but this will suffice for now. */
606*a1acfa9bSespie array[count] = xmalloc (sizeof (INDEX_ELT));
607*a1acfa9bSespie *(array[count]) = *(temp); /* struct assignment, hope it's ok */
608*a1acfa9bSespie
609*a1acfa9bSespie /* Adjust next pointers to use the new memory. */
610*a1acfa9bSespie if (count > 0)
611*a1acfa9bSespie array[count-1]->next = array[count];
6121cc83814Sespie
6131cc83814Sespie /* Set line number and input filename to the source line for this
6141cc83814Sespie index entry, as this expansion finds any errors. */
615*a1acfa9bSespie line_number = array[count]->defining_line;
616*a1acfa9bSespie input_filename = array[count]->defining_file;
6171cc83814Sespie
6181cc83814Sespie /* If this particular entry should be printed as a "code" index,
619*a1acfa9bSespie then expand it as @code{entry}, i.e., as in fixed-width font. */
620*a1acfa9bSespie array[count]->entry = expansion (temp->entry_text, array[count]->code);
6211cc83814Sespie }
6221cc83814Sespie array[count] = NULL; /* terminate the array. */
623*a1acfa9bSespie
6241cc83814Sespie line_number = save_line_number;
6251cc83814Sespie input_filename = save_input_filename;
6261cc83814Sespie html = save_html;
6271cc83814Sespie
6281cc83814Sespie #ifdef HAVE_STRCOLL
6291cc83814Sespie /* This is not perfect. We should set (then restore) the locale to the
6301cc83814Sespie documentlanguage, so strcoll operates according to the document's
6311cc83814Sespie locale, not the user's. For now, I'm just going to assume that
6321cc83814Sespie those few new documents which use @documentlanguage will be
6331cc83814Sespie processed in the appropriate locale. In any case, don't use
6341cc83814Sespie strcoll in the C (aka POSIX) locale, that is the ASCII ordering. */
6351cc83814Sespie if (language_code != en)
6361cc83814Sespie {
6371cc83814Sespie char *lang_env = getenv ("LANG");
6381cc83814Sespie if (lang_env && !STREQ (lang_env, "C") && !STREQ (lang_env, "POSIX"))
6391cc83814Sespie index_compare_fn = strcoll;
6401cc83814Sespie }
6411cc83814Sespie #endif /* HAVE_STRCOLL */
6421cc83814Sespie
6431cc83814Sespie /* Sort the array. */
6441cc83814Sespie qsort (array, count, sizeof (INDEX_ELT *), index_element_compare);
645*a1acfa9bSespie
646*a1acfa9bSespie /* Remove duplicate entries. */
6471cc83814Sespie make_index_entries_unique (array, count);
648*a1acfa9bSespie
649*a1acfa9bSespie /* Replace the original index with the sorted one, in case the
650*a1acfa9bSespie document wants to print it again. If the index wasn't empty. */
651*a1acfa9bSespie if (index)
652*a1acfa9bSespie *index = **array;
653*a1acfa9bSespie
6541cc83814Sespie return array;
6551cc83814Sespie }
6561cc83814Sespie
657*a1acfa9bSespie static void
insert_index_output_line_no(int line_number,int output_line_number_len)658*a1acfa9bSespie insert_index_output_line_no (int line_number, int output_line_number_len)
659*a1acfa9bSespie {
660*a1acfa9bSespie int last_column;
661*a1acfa9bSespie int str_size = output_line_number_len + strlen (_("(line )"))
662*a1acfa9bSespie + sizeof (NULL);
663*a1acfa9bSespie char *out_line_no_str = (char *) xmalloc (str_size + 1);
664*a1acfa9bSespie
665*a1acfa9bSespie /* Do not translate ``(line NNN)'' below for !no_headers case (Info output),
666*a1acfa9bSespie because it's something like the ``* Menu'' strings. For plaintext output
667*a1acfa9bSespie it should be translated though. */
668*a1acfa9bSespie sprintf (out_line_no_str,
669*a1acfa9bSespie no_headers ? _("(line %*d)") : "(line %*d)",
670*a1acfa9bSespie output_line_number_len, line_number);
671*a1acfa9bSespie
672*a1acfa9bSespie {
673*a1acfa9bSespie int i = output_paragraph_offset;
674*a1acfa9bSespie while (0 < i && output_paragraph[i-1] != '\n')
675*a1acfa9bSespie i--;
676*a1acfa9bSespie last_column = output_paragraph_offset - i;
677*a1acfa9bSespie }
678*a1acfa9bSespie
679*a1acfa9bSespie if (last_column + strlen (out_line_no_str) > fill_column)
680*a1acfa9bSespie {
681*a1acfa9bSespie insert ('\n');
682*a1acfa9bSespie last_column = 0;
683*a1acfa9bSespie }
684*a1acfa9bSespie
685*a1acfa9bSespie while (last_column + strlen (out_line_no_str) < fill_column)
686*a1acfa9bSespie {
687*a1acfa9bSespie insert (' ');
688*a1acfa9bSespie last_column++;
689*a1acfa9bSespie }
690*a1acfa9bSespie
691*a1acfa9bSespie insert_string (out_line_no_str);
692*a1acfa9bSespie insert ('\n');
693*a1acfa9bSespie
694*a1acfa9bSespie free (out_line_no_str);
695*a1acfa9bSespie }
696*a1acfa9bSespie
6971cc83814Sespie /* Nonzero means that we are in the middle of printing an index. */
6981cc83814Sespie int printing_index = 0;
6991cc83814Sespie
7001cc83814Sespie /* Takes one arg, a short name of an index to print.
7011cc83814Sespie Outputs a menu of the sorted elements of the index. */
7021cc83814Sespie void
cm_printindex(void)703*a1acfa9bSespie cm_printindex (void)
7043fb98d4aSespie {
7053fb98d4aSespie char *index_name;
7063fb98d4aSespie get_rest_of_line (0, &index_name);
707*a1acfa9bSespie
708*a1acfa9bSespie /* get_rest_of_line increments the line number by one,
709*a1acfa9bSespie so to make warnings/errors point to the correct line,
710*a1acfa9bSespie we decrement the line_number again. */
711*a1acfa9bSespie if (!handling_delayed_writes)
712*a1acfa9bSespie line_number--;
713*a1acfa9bSespie
714*a1acfa9bSespie if (xml && !docbook)
715*a1acfa9bSespie {
7163fb98d4aSespie xml_insert_element (PRINTINDEX, START);
7173fb98d4aSespie insert_string (index_name);
7183fb98d4aSespie xml_insert_element (PRINTINDEX, END);
7193fb98d4aSespie }
720*a1acfa9bSespie else if (!handling_delayed_writes)
721*a1acfa9bSespie {
722*a1acfa9bSespie int command_len = sizeof ("@ ") + strlen (command) + strlen (index_name);
723*a1acfa9bSespie char *index_command = xmalloc (command_len + 1);
724*a1acfa9bSespie
725*a1acfa9bSespie close_paragraph ();
726*a1acfa9bSespie if (docbook)
727*a1acfa9bSespie xml_begin_index ();
728*a1acfa9bSespie
729*a1acfa9bSespie sprintf (index_command, "@%s %s", command, index_name);
730*a1acfa9bSespie register_delayed_write (index_command);
731*a1acfa9bSespie free (index_command);
732*a1acfa9bSespie }
7333fb98d4aSespie else
7343fb98d4aSespie {
7351cc83814Sespie int item;
7361cc83814Sespie INDEX_ELT *index;
7371cc83814Sespie INDEX_ELT *last_index = 0;
7381cc83814Sespie INDEX_ELT **array;
7391cc83814Sespie unsigned line_length;
7401cc83814Sespie char *line;
7411cc83814Sespie int saved_inhibit_paragraph_indentation = inhibit_paragraph_indentation;
7421cc83814Sespie int saved_filling_enabled = filling_enabled;
7431cc83814Sespie int saved_line_number = line_number;
7441cc83814Sespie char *saved_input_filename = input_filename;
745*a1acfa9bSespie unsigned output_line_number_len;
7461cc83814Sespie
7471cc83814Sespie index = index_list (index_name);
7481cc83814Sespie if (index == (INDEX_ELT *)-1)
7491cc83814Sespie {
7501cc83814Sespie line_error (_("Unknown index `%s' in @printindex"), index_name);
7511cc83814Sespie free (index_name);
7521cc83814Sespie return;
7531cc83814Sespie }
7541cc83814Sespie
7553fb98d4aSespie /* Do this before sorting, so execute_string is in the good environment */
7563fb98d4aSespie if (xml && docbook)
7573fb98d4aSespie xml_begin_index ();
7583fb98d4aSespie
7591cc83814Sespie /* Do this before sorting, so execute_string in index_element_compare
7601cc83814Sespie will give the same results as when we actually print. */
7611cc83814Sespie printing_index = 1;
7621cc83814Sespie filling_enabled = 0;
7631cc83814Sespie inhibit_paragraph_indentation = 1;
7643fb98d4aSespie xml_sort_index = 1;
7651cc83814Sespie array = sort_index (index);
7663fb98d4aSespie xml_sort_index = 0;
7671cc83814Sespie close_paragraph ();
7681cc83814Sespie if (html)
769*a1acfa9bSespie add_html_block_elt_args ("<ul class=\"index-%s\" compact>",
770*a1acfa9bSespie index_name);
7713fb98d4aSespie else if (!no_headers && !docbook)
772*a1acfa9bSespie { /* Info. Add magic cookie for info readers (to treat this
773*a1acfa9bSespie menu differently), and the usual start-of-menu. */
774*a1acfa9bSespie add_char ('\0');
775*a1acfa9bSespie add_word ("\010[index");
776*a1acfa9bSespie add_char ('\0');
777*a1acfa9bSespie add_word ("\010]\n");
7781cc83814Sespie add_word ("* Menu:\n\n");
779*a1acfa9bSespie }
7801cc83814Sespie
7811cc83814Sespie me_inhibit_expansion++;
7821cc83814Sespie
7831cc83814Sespie /* This will probably be enough. */
7841cc83814Sespie line_length = 100;
7851cc83814Sespie line = xmalloc (line_length);
7861cc83814Sespie
787*a1acfa9bSespie {
788*a1acfa9bSespie char *max_output_line_number = (char *) xmalloc (25 * sizeof (char));
789*a1acfa9bSespie
790*a1acfa9bSespie if (no_headers)
791*a1acfa9bSespie sprintf (max_output_line_number, "%d", output_line_number);
792*a1acfa9bSespie else
793*a1acfa9bSespie {
794*a1acfa9bSespie INDEX_ELT *tmp_entry = index;
795*a1acfa9bSespie unsigned tmp = 0;
796*a1acfa9bSespie for (tmp_entry = index; tmp_entry; tmp_entry = tmp_entry->next)
797*a1acfa9bSespie tmp = tmp_entry->output_line > tmp ? tmp_entry->output_line : tmp;
798*a1acfa9bSespie sprintf (max_output_line_number, "%d", tmp);
799*a1acfa9bSespie }
800*a1acfa9bSespie
801*a1acfa9bSespie output_line_number_len = strlen (max_output_line_number);
802*a1acfa9bSespie free (max_output_line_number);
803*a1acfa9bSespie }
804*a1acfa9bSespie
8051cc83814Sespie for (item = 0; (index = array[item]); item++)
8061cc83814Sespie {
8071cc83814Sespie /* A pathological document might have an index entry outside of any
8081cc83814Sespie node. Don't crash; try using the section name instead. */
8091cc83814Sespie char *index_node = index->node;
8101cc83814Sespie
8111cc83814Sespie line_number = index->defining_line;
8121cc83814Sespie input_filename = index->defining_file;
8131cc83814Sespie
8141cc83814Sespie if ((!index_node || !*index_node) && html)
8151cc83814Sespie index_node = toc_find_section_of_node (index_node);
8161cc83814Sespie
8171cc83814Sespie if (!index_node || !*index_node)
8181cc83814Sespie {
8191cc83814Sespie line_error (_("Entry for index `%s' outside of any node"),
8201cc83814Sespie index_name);
8211cc83814Sespie if (html || !no_headers)
822*a1acfa9bSespie index_node = (char *) _("(outside of any node)");
8231cc83814Sespie }
8241cc83814Sespie
8251cc83814Sespie if (html)
8261cc83814Sespie {
827*a1acfa9bSespie /* For HTML, we need to expand and HTML-escape the
828*a1acfa9bSespie original entry text, at the same time. Consider
829*a1acfa9bSespie @cindex J@"urgen. We want Jüurgen. We can't
830*a1acfa9bSespie expand and then escape since we'll end up with
831*a1acfa9bSespie J&uuml;rgen. We can't escape and then expand
832*a1acfa9bSespie because then `expansion' will see J@"urgen, and
833*a1acfa9bSespie @"urgen is not a command. */
834*a1acfa9bSespie char *html_entry =
835*a1acfa9bSespie maybe_escaped_expansion (index->entry_text, index->code, 1);
8361cc83814Sespie
837*a1acfa9bSespie add_html_block_elt_args ("\n<li><a href=\"%s#index-",
838*a1acfa9bSespie (splitting && index->output_file) ? index->output_file : "");
839*a1acfa9bSespie add_escaped_anchor_name (index->entry_text, 0);
840*a1acfa9bSespie add_word_args ("-%d\">%s</a>: ", index->entry_number,
841*a1acfa9bSespie html_entry);
842*a1acfa9bSespie free (html_entry);
843*a1acfa9bSespie
8441cc83814Sespie add_word ("<a href=\"");
8451cc83814Sespie if (index->node && *index->node)
8461cc83814Sespie {
847*a1acfa9bSespie /* Ensure any non-macros in the node name are expanded. */
848*a1acfa9bSespie char *expanded_index;
849*a1acfa9bSespie
8501cc83814Sespie in_fixed_width_font++;
851*a1acfa9bSespie expanded_index = expansion (index_node, 0);
8521cc83814Sespie in_fixed_width_font--;
853*a1acfa9bSespie add_anchor_name (expanded_index, 1);
854*a1acfa9bSespie expanded_index = escape_string (expanded_index);
855*a1acfa9bSespie add_word_args ("\">%s</a>", expanded_index);
856*a1acfa9bSespie free (expanded_index);
8571cc83814Sespie }
8581cc83814Sespie else if (STREQ (index_node, _("(outside of any node)")))
8591cc83814Sespie {
8601cc83814Sespie add_anchor_name (index_node, 1);
8611cc83814Sespie add_word_args ("\">%s</a>", index_node);
8621cc83814Sespie }
8631cc83814Sespie else
8641cc83814Sespie /* If we use the section instead of the (missing) node, then
8651cc83814Sespie index_node already includes all we need except the #. */
8661cc83814Sespie add_word_args ("#%s</a>", index_node);
867*a1acfa9bSespie
868*a1acfa9bSespie add_html_block_elt ("</li>");
8691cc83814Sespie }
8703fb98d4aSespie else if (xml && docbook)
8713fb98d4aSespie {
872*a1acfa9bSespie /* In the DocBook case, the expanded index entry is not
873*a1acfa9bSespie good for us, since it was expanded for non-DocBook mode
874*a1acfa9bSespie inside sort_index. So we send the original entry text
875*a1acfa9bSespie to be used with execute_string. */
876*a1acfa9bSespie xml_insert_indexentry (index->entry_text, index_node);
8773fb98d4aSespie }
8781cc83814Sespie else
8791cc83814Sespie {
8801cc83814Sespie unsigned new_length = strlen (index->entry);
8811cc83814Sespie
8821cc83814Sespie if (new_length < 50) /* minimum length used below */
8831cc83814Sespie new_length = 50;
8841cc83814Sespie new_length += strlen (index_node) + 7; /* * : .\n\0 */
8851cc83814Sespie
8861cc83814Sespie if (new_length > line_length)
8871cc83814Sespie {
8881cc83814Sespie line_length = new_length;
8891cc83814Sespie line = xrealloc (line, line_length);
8901cc83814Sespie }
8911cc83814Sespie /* Print the entry, nicely formatted. We've already
8921cc83814Sespie expanded any commands in index->entry, including any
8931cc83814Sespie implicit @code. Thus, can't call execute_string, since
8941cc83814Sespie @@ has turned into @. */
8951cc83814Sespie if (!no_headers)
8961cc83814Sespie {
8971cc83814Sespie sprintf (line, "* %-37s ", index->entry);
8981cc83814Sespie line[2 + strlen (index->entry)] = ':';
8991cc83814Sespie insert_string (line);
9001cc83814Sespie /* Make sure any non-macros in the node name are expanded. */
9011cc83814Sespie in_fixed_width_font++;
902*a1acfa9bSespie execute_string ("%s. ", index_node);
903*a1acfa9bSespie insert_index_output_line_no (index->output_line,
904*a1acfa9bSespie output_line_number_len);
9051cc83814Sespie in_fixed_width_font--;
9061cc83814Sespie }
9071cc83814Sespie else
9081cc83814Sespie {
9091cc83814Sespie /* With --no-headers, the @node lines are gone, so
9101cc83814Sespie there's little sense in referring to them in the
9111cc83814Sespie index. Instead, output the number or name of the
9121cc83814Sespie section that corresponds to that node. */
913*a1acfa9bSespie sprintf (line, "%-*s ", number_sections ? 46 : 1, index->entry);
9141cc83814Sespie line[strlen (index->entry)] = ':';
9151cc83814Sespie insert_string (line);
9161cc83814Sespie
917*a1acfa9bSespie if (strlen (index->section) > 0)
918*a1acfa9bSespie { /* We got your number. */
919*a1acfa9bSespie insert_string ((char *) _("See "));
920*a1acfa9bSespie insert_string (index->section);
9211cc83814Sespie }
9221cc83814Sespie else
923*a1acfa9bSespie { /* Sigh, index in an @unnumbered. :-\ */
924*a1acfa9bSespie insert_string ("\n ");
925*a1acfa9bSespie insert_string ((char *) _("See "));
926*a1acfa9bSespie insert_string ("``");
927*a1acfa9bSespie insert_string (expansion (index->section_name, 0));
928*a1acfa9bSespie insert_string ("''");
9291cc83814Sespie }
930*a1acfa9bSespie
931*a1acfa9bSespie insert_string (". ");
932*a1acfa9bSespie insert_index_output_line_no (index->output_line,
933*a1acfa9bSespie output_line_number_len);
9341cc83814Sespie }
9351cc83814Sespie }
9361cc83814Sespie
9371cc83814Sespie /* Prevent `output_paragraph' from growing to the size of the
9381cc83814Sespie whole index. */
9391cc83814Sespie flush_output ();
9401cc83814Sespie last_index = index;
9411cc83814Sespie }
9421cc83814Sespie
9431cc83814Sespie free (line);
9441cc83814Sespie
9451cc83814Sespie me_inhibit_expansion--;
9461cc83814Sespie printing_index = 0;
947*a1acfa9bSespie
9481cc83814Sespie close_single_paragraph ();
9491cc83814Sespie filling_enabled = saved_filling_enabled;
9501cc83814Sespie inhibit_paragraph_indentation = saved_inhibit_paragraph_indentation;
9511cc83814Sespie input_filename = saved_input_filename;
9521cc83814Sespie line_number = saved_line_number;
9531cc83814Sespie
9541cc83814Sespie if (html)
955*a1acfa9bSespie add_html_block_elt ("</ul>");
9563fb98d4aSespie else if (xml && docbook)
9573fb98d4aSespie xml_end_index ();
9583fb98d4aSespie }
959*a1acfa9bSespie
960*a1acfa9bSespie free (index_name);
961*a1acfa9bSespie /* Re-increment the line number, because get_rest_of_line
962*a1acfa9bSespie left us looking at the next line after the command. */
963*a1acfa9bSespie line_number++;
9641cc83814Sespie }
965