xref: /openbsd-src/gnu/usr.bin/texinfo/makeinfo/index.c (revision a1acfa9b69ad64eb720639240c8438f11107dc85)
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&uuml;urgen.  We can't
830*a1acfa9bSespie                  expand and then escape since we'll end up with
831*a1acfa9bSespie                  J&amp;uuml;rgen.  We can't escape and then expand
832*a1acfa9bSespie                  because then `expansion' will see J@&quot;urgen, and
833*a1acfa9bSespie                  @&quot;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