/* index.c -- indexing for Texinfo. $Id: index.c,v 1.27 2008/05/19 18:26:48 karl Exp $ Copyright (C) 1998, 1999, 2002, 2003, 2004, 2007, 2008 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "system.h" #include "mbswidth.h" #include "files.h" #include "footnote.h" #include "html.h" #include "index.h" #include "lang.h" #include "macro.h" #include "sectioning.h" #include "toc.h" #include "xml.h" /* Nonzero means that we are in the middle of printing an index. */ int printing_index = 0; /* The number of defined indices. */ int defined_indices = 0; /* This is the order of the index. */ int index_counter = 0; /* Stuff for defining commands on the fly. */ COMMAND **user_command_array = NULL; int user_command_array_len = 0; INDEX_ALIST **name_index_alist = NULL; /* An array of pointers. Each one is for a different index. The @synindex command changes which array slot is pointed to by a given index. */ static INDEX_ELT **the_indices = NULL; /* How to compare index entries for sorting. May be set to strcoll. */ static int (*index_compare_fn) (const char *a, const char *b) = mbscasecmp; /* Find which element in the known list of indices has this name. Returns -1 if NAME isn't found. */ static int find_index_offset (char *name) { int i; for (i = 0; i < defined_indices; i++) if (name_index_alist[i] && STREQ (name, name_index_alist[i]->name)) return i; return -1; } /* Return a pointer to the entry of (name . index) for this name. Return NULL if the index doesn't exist. */ static INDEX_ALIST * find_index (char *name) { int offset = find_index_offset (name); if (offset > -1) return name_index_alist[offset]; else return NULL; } /* User-defined commands, which happens only from user-defined indexes. Used to initialize the builtin indices, too. */ static void define_user_command (char *name, COMMAND_FUNCTION (*proc), int needs_braces_p) { int slot = user_command_array_len; user_command_array_len++; if (!user_command_array) user_command_array = xmalloc (1 * sizeof (COMMAND *)); user_command_array = xrealloc (user_command_array, (1 + user_command_array_len) * sizeof (COMMAND *)); user_command_array[slot] = xmalloc (sizeof (COMMAND)); user_command_array[slot]->name = xstrdup (name); user_command_array[slot]->proc = proc; user_command_array[slot]->argument_in_braces = needs_braces_p; } /* Please release me, let me go... */ static void free_index (INDEX_ELT *index) { INDEX_ELT *temp; while ((temp = index)) { free (temp->entry); free (temp->entry_text); /* Do not free the node, because we already freed the tag table, which freed all the node names. */ /* free (temp->node); */ index = index->next; free (temp); } } /* Flush an index by name. This will delete the list of entries that would be written by a @printindex command for this index. */ static void undefindex (char *name) { int i; int which = find_index_offset (name); /* The index might have already been freed if this was the target of an @synindex. */ if (which < 0 || !name_index_alist[which]) return; i = name_index_alist[which]->read_index; free_index (the_indices[i]); the_indices[i] = NULL; free (name_index_alist[which]->name); free (name_index_alist[which]); name_index_alist[which] = NULL; } /* Add the arguments to the current index command to the index NAME. */ static void index_add_arg (char *name) { int which; char *index_entry; INDEX_ALIST *tem; tem = find_index (name); which = tem ? tem->write_index : -1; if (macro_expansion_output_stream && !executing_string) append_to_expansion_output (input_text_offset + 1); get_rest_of_line (0, &index_entry); ignore_blank_line (); if (macro_expansion_output_stream && !executing_string) { char *index_line = xmalloc (strlen (index_entry) + 2); sprintf (index_line, "%s\n", index_entry); me_execute_string_keep_state (index_line, NULL); free (index_line); } if (which < 0) { line_error (_("Unknown index `%s'"), name); free (index_entry); } else { INDEX_ELT *new = xmalloc (sizeof (INDEX_ELT)); index_counter++; /* Get output line number updated before doing anything. */ if (!html && !xml) flush_output (); new->next = the_indices[which]; new->entry = NULL; new->entry_text = index_entry; /* Since footnotes are handled at the very end of the document, node name in the non-split HTML outputs always show the last node. We artificially make it ``Footnotes''. */ if (html && !splitting && already_outputting_pending_notes) new->node = xstrdup (_("Footnotes")); else new->node = current_node ? current_node : xstrdup (""); if (!html && !xml && no_headers) { new->section = current_sectioning_number (); if (strlen (new->section) == 0) new->section_name = current_sectioning_name (); else new->section_name = ""; } else { new->section = NULL; new->section_name = NULL; } new->code = tem->code; new->defining_line = line_number - 1; new->output_line = no_headers ? output_line_number : node_line_number; /* We need to make a copy since input_filename may point to something that goes away, for example, inside a macro. (see the findexerr test). */ new->defining_file = xstrdup (input_filename); if (html && splitting) { if (current_output_filename && *current_output_filename) new->output_file = filename_part (current_output_filename); else new->output_file = xstrdup (""); } else new->output_file = NULL; new->entry_number = index_counter; the_indices[which] = new; #if 0 /* The index breaks if there are colons in the entry. -- This is true, but it's too painful to force changing index entries to use `colon', and too confusing for users. The real fix is to change Info support to support arbitrary characters in node names, and we're not ready to do that. --karl, 19mar02. */ if (strchr (new->entry_text, ':')) warning (_("Info cannot handle `:' in index entry `%s'"), new->entry_text); #endif if (html) { /* Anchor. */ int removed_empty_elt = 0; /* We must put the anchor outside the
and