summaryrefslogtreecommitdiff
path: root/info/indices.c
diff options
context:
space:
mode:
Diffstat (limited to 'info/indices.c')
-rw-r--r--info/indices.c389
1 files changed, 327 insertions, 62 deletions
diff --git a/info/indices.c b/info/indices.c
index af04cdc..ae4afeb 100644
--- a/info/indices.c
+++ b/info/indices.c
@@ -1,7 +1,7 @@
/* indices.c -- deal with an Info file index.
- $Id: indices.c,v 1.11 2008/06/11 09:55:42 gray Exp $
+ $Id: indices.c 5337 2013-08-22 17:54:06Z karl $
- Copyright (C) 1993, 1997, 1998, 1999, 2002, 2003, 2004, 2007, 2008
+ Copyright 1993, 1997, 1998, 1999, 2002, 2003, 2004, 2007, 2008, 2011, 2013
Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
@@ -17,10 +17,11 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
- Originally written by Brian Fox (bfox@ai.mit.edu). */
+ Originally written by Brian Fox. */
#include "info.h"
#include "indices.h"
+#include "variables.h"
/* User-visible variable controls the output of info-index-next. */
int show_index_match = 1;
@@ -31,6 +32,8 @@ static REFERENCE **index_index = NULL;
/* The offset of the most recently selected index element. */
static int index_offset = 0;
+/* Whether we are doing partial index search */
+static int index_partial = 0;
/* Variable which holds the last string searched for. */
static char *index_search = NULL;
@@ -48,8 +51,8 @@ typedef struct {
/* An array associating index nodenames with index offset ranges. */
static INDEX_NAME_ASSOC **index_nodenames = NULL;
-static int index_nodenames_index = 0;
-static int index_nodenames_slots = 0;
+static size_t index_nodenames_index = 0;
+static size_t index_nodenames_slots = 0;
/* Add the name of NODE, and the range of the associated index elements
(passed in ARRAY) to index_nodenames. */
@@ -74,9 +77,8 @@ add_index_to_index_nodenames (REFERENCE **array, NODE *node)
assoc->first = 1 + index_nodenames[i]->last;
assoc->last = assoc->first + last;
}
- add_pointer_to_array
- (assoc, index_nodenames_index, index_nodenames, index_nodenames_slots,
- 10, INDEX_NAME_ASSOC *);
+ add_pointer_to_array (assoc, index_nodenames_index, index_nodenames,
+ index_nodenames_slots, 10);
}
/* Find and return the indices of WINDOW's file. The indices are defined
@@ -105,8 +107,8 @@ info_indices_of_file_buffer (FILE_BUFFER *file_buffer)
return NULL;
/* Reset globals describing where the index was found. */
- maybe_free (initial_index_filename);
- maybe_free (initial_index_nodename);
+ free (initial_index_filename);
+ free (initial_index_nodename);
initial_index_filename = NULL;
initial_index_nodename = NULL;
@@ -135,7 +137,8 @@ info_indices_of_file_buffer (FILE_BUFFER *file_buffer)
REFERENCE **menu;
/* Found one. Get its menu. */
- node = info_get_node (tag->filename, tag->nodename);
+ node = info_get_node (tag->filename, tag->nodename,
+ PARSE_NODE_VERBATIM);
if (!node)
continue;
@@ -185,25 +188,25 @@ do_info_index_search (WINDOW *window, int count, char *search_string)
index_offset = 0;
/* The user is selecting a new search string, so flush the old one. */
- maybe_free (index_search);
+ free (index_search);
index_search = NULL;
/* If this window's file is not the same as the one that we last built an
index for, build and remember an index now. */
fb = file_buffer_of_window (window);
if (!initial_index_filename ||
+ !fb ||
(FILENAME_CMP (initial_index_filename, fb->filename) != 0))
{
info_free_references (index_index);
- window_message_in_echo_area (_("Finding index entries..."),
- NULL, NULL);
+ window_message_in_echo_area (_("Finding index entries..."));
index_index = info_indices_of_file_buffer (fb);
}
/* If there is no index, quit now. */
if (!index_index)
{
- info_error (_("No indices found."), NULL, NULL);
+ info_error (_("No indices found."));
return;
}
@@ -234,7 +237,8 @@ do_info_index_search (WINDOW *window, int count, char *search_string)
NODE *node;
node = info_get_node (initial_index_filename,
- initial_index_nodename);
+ initial_index_nodename,
+ PARSE_NODE_DFLT);
set_remembered_pagetop_and_point (window);
window_set_node_of_window (window, node);
remember_window_and_node (window, node);
@@ -244,6 +248,14 @@ do_info_index_search (WINDOW *window, int count, char *search_string)
}
}
+ if (mbslen (line) < min_search_length)
+ {
+ info_error (_("Search string too short"));
+ free (line);
+ return;
+ }
+
+
/* The user typed either a completed index label, or a partial string.
Find an exact match, or, failing that, the first index entry containing
the partial string. So, we just call info_next_index_match () with minor
@@ -259,8 +271,11 @@ do_info_index_search (WINDOW *window, int count, char *search_string)
index_offset = i;
}
else
- index_offset = -1;
-
+ {
+ index_offset = -1;
+ index_partial = 0;
+ }
+
old_offset = index_offset;
/* The "last" string searched for is this one. */
@@ -287,8 +302,9 @@ index_entry_exists (WINDOW *window, char *string)
return 0;
fb = file_buffer_of_window (window);
- if (!initial_index_filename
- || (FILENAME_CMP (initial_index_filename, fb->filename) != 0))
+ if (!initial_index_filename ||
+ !fb ||
+ (FILENAME_CMP (initial_index_filename, fb->filename) != 0))
{
info_free_references (index_index);
index_index = info_indices_of_file_buffer (fb);
@@ -320,25 +336,51 @@ index_entry_exists (WINDOW *window, char *string)
return 1;
}
+/* Return true if ENT->label matches "S( <[0-9]+>)?", where S stands
+ for the first LEN characters from STR. */
+static int
+index_entry_matches (REFERENCE *ent, const char *str, size_t len)
+{
+ char *p;
+
+ if (strncmp (ent->label, str, len))
+ return 0;
+ p = ent->label + len;
+ if (!*p)
+ return 1;
+ if (p[0] == ' ' && p[1] == '<')
+ {
+ for (p += 2; *p; p++)
+ {
+ if (p[0] == '>' && p[1] == 0)
+ return 1;
+ else if (!isdigit (*p))
+ return 0;
+ }
+ }
+ return 0;
+}
+
DECLARE_INFO_COMMAND (info_next_index_match,
_("Go to the next matching index item from the last `\\[index-search]' command"))
{
register int i;
int partial, dir;
NODE *node;
-
+ size_t search_len;
+
/* If there is no previous search string, the user hasn't built an index
yet. */
if (!index_search)
{
- info_error (_("No previous index search string."), NULL, NULL);
+ info_error (_("No previous index search string."));
return;
}
/* If there is no index, that is an error. */
if (!index_index)
{
- info_error (_("No index entries."), NULL, NULL);
+ info_error (_("No index entries."));
return;
}
@@ -349,30 +391,47 @@ DECLARE_INFO_COMMAND (info_next_index_match,
else
dir = 1;
- /* Search for the next occurence of index_search. First try to find
- an exact match. */
+ /* Search for the next occurence of index_search. */
partial = 0;
+ search_len = strlen (index_search);
- for (i = index_offset + dir; (i > -1) && (index_index[i]); i += dir)
- if (strcmp (index_search, index_index[i]->label) == 0)
- break;
-
- /* If that failed, look for the next substring match. */
- if ((i < 0) || (!index_index[i]))
+ if (!index_partial)
{
+ /* First try to find an exact match. */
for (i = index_offset + dir; (i > -1) && (index_index[i]); i += dir)
- if (string_in_line (index_search, index_index[i]->label) != -1)
- break;
+ if (index_entry_matches (index_index[i], index_search, search_len))
+ break;
- if ((i > -1) && (index_index[i]))
- partial = string_in_line (index_search, index_index[i]->label);
+ /* If that failed, look for the next substring match. */
+ if ((i < 0) || (!index_index[i]))
+ {
+ index_offset = 0;
+ index_partial = 1;
+ }
}
+ if (index_partial)
+ {
+ /* When looking for substrings, take care not to return previous exact
+ matches. */
+ for (i = index_offset + dir; (i > -1) && (index_index[i]); i += dir)
+ if (!index_entry_matches (index_index[i], index_search, search_len))
+ {
+ partial = string_in_line (index_search, index_index[i]->label);
+ if (partial != -1)
+ break;
+ }
+ index_partial = partial > 0;
+ }
+
/* If that failed, print an error. */
if ((i < 0) || (!index_index[i]))
{
- info_error (_("No %sindex entries containing `%s'."),
- index_offset > 0 ? (char *) _("more ") : "", index_search);
+ info_error (index_offset > 0 ?
+ _("No more index entries containing `%s'.") :
+ _("No index entries containing `%s'."),
+ index_search);
+ index_offset = 0;
return;
}
@@ -399,7 +458,7 @@ DECLARE_INFO_COMMAND (info_next_index_match,
string matched. */
match = xstrdup (index_index[i]->label);
- if (partial && show_index_match)
+ if (partial > 0 && show_index_match)
{
int k, ls, start, upper;
@@ -428,7 +487,8 @@ DECLARE_INFO_COMMAND (info_next_index_match,
}
/* Select the node corresponding to this index entry. */
- node = info_get_node (index_index[i]->filename, index_index[i]->nodename);
+ node = info_get_node (index_index[i]->filename, index_index[i]->nodename,
+ PARSE_NODE_DFLT);
if (!node)
{
@@ -441,7 +501,8 @@ DECLARE_INFO_COMMAND (info_next_index_match,
{
long loc;
- long line = index_index[i]->line_number - 1;
+ long line = window_log_to_phys_line (window,
+ index_index[i]->line_number - 1);
if (line >= 0 && line < window->line_count)
{
@@ -452,7 +513,7 @@ DECLARE_INFO_COMMAND (info_next_index_match,
{
/* Try to find an occurence of LABEL in this node. */
long start = window->line_starts[1] - window->node->contents;
- loc = info_target_search_node (node, index_index[i]->label, start);
+ loc = info_target_search_node (node, index_index[i]->label, start, 1);
}
if (loc != -1)
@@ -474,12 +535,12 @@ DECLARE_INFO_COMMAND (info_next_index_match,
REFERENCE **
apropos_in_all_indices (char *search_string, int inform)
{
- register int i, dir_index;
+ size_t i, dir_index;
REFERENCE **all_indices = NULL;
REFERENCE **dir_menu = NULL;
NODE *dir_node;
- dir_node = info_get_node ("dir", "Top");
+ dir_node = info_get_node ("dir", "Top", PARSE_NODE_DFLT);
if (dir_node)
dir_menu = info_menu_of_node (dir_node);
@@ -509,11 +570,12 @@ apropos_in_all_indices (char *search_string, int inform)
/* Find this node. If we cannot find it, try using the label of the
entry as a file (i.e., "(LABEL)Top"). */
- this_node = info_get_node (this_item->filename, this_item->nodename);
+ this_node = info_get_node (this_item->filename, this_item->nodename,
+ PARSE_NODE_VERBATIM);
if (!this_node && this_item->nodename &&
(strcmp (this_item->label, this_item->nodename) == 0))
- this_node = info_get_node (this_item->label, "Top");
+ this_node = info_get_node (this_item->label, "Top", PARSE_NODE_DFLT);
if (!this_node)
{
@@ -546,8 +608,7 @@ apropos_in_all_indices (char *search_string, int inform)
}
if (this_fb && inform)
- message_in_echo_area (_("Scanning indices of `%s'..."),
- files_name, NULL);
+ message_in_echo_area (_("Scanning indices of `%s'..."), files_name);
this_index = info_indices_of_file_buffer (this_fb);
free (this_node);
@@ -574,24 +635,18 @@ apropos_in_all_indices (char *search_string, int inform)
if (all_indices)
{
REFERENCE *entry, **apropos_list = NULL;
- int apropos_list_index = 0;
- int apropos_list_slots = 0;
+ size_t apropos_list_index = 0;
+ size_t apropos_list_slots = 0;
for (i = 0; (entry = all_indices[i]); i++)
{
if (string_in_line (search_string, entry->label) != -1)
{
- add_pointer_to_array
- (entry, apropos_list_index, apropos_list, apropos_list_slots,
- 100, REFERENCE *);
+ add_pointer_to_array (entry, apropos_list_index, apropos_list,
+ apropos_list_slots, 100);
}
else
- {
- maybe_free (entry->label);
- maybe_free (entry->filename);
- maybe_free (entry->nodename);
- free (entry);
- }
+ info_reference_free (entry);
}
free (all_indices);
@@ -611,7 +666,7 @@ info_apropos (char *string)
apropos_list = apropos_in_all_indices (string, 0);
if (!apropos_list)
- info_error (_(APROPOS_NONE), string, NULL);
+ info_error (_(APROPOS_NONE), string);
else
{
register int i;
@@ -651,7 +706,7 @@ DECLARE_INFO_COMMAND (info_index_apropos,
apropos_list = apropos_in_all_indices (line, 1);
if (!apropos_list)
- info_error (_(APROPOS_NONE), line, NULL);
+ info_error (_(APROPOS_NONE), line);
else
{
register int i;
@@ -660,7 +715,7 @@ DECLARE_INFO_COMMAND (info_index_apropos,
initialize_message_buffer ();
printf_to_message_buffer
(_("\n* Menu: Nodes whose indices contain `%s':\n"),
- line, NULL, NULL);
+ line);
line_buffer = xmalloc (500);
for (i = 0; apropos_list[i]; i++)
@@ -674,7 +729,7 @@ DECLARE_INFO_COMMAND (info_index_apropos,
len = pad_to (40, line_buffer);
sprintf (line_buffer + len, "(%s)%s.",
apropos_list[i]->filename, apropos_list[i]->nodename);
- printf_to_message_buffer ("%s\n", line_buffer, NULL, NULL);
+ printf_to_message_buffer ("%s\n", line_buffer);
}
free (line_buffer);
}
@@ -741,3 +796,213 @@ DECLARE_INFO_COMMAND (info_index_apropos,
if (!info_error_was_printed)
window_clear_echo_area ();
}
+
+static FILE_BUFFER *
+create_virtindex_file_buffer (const char *filename, char *contents, size_t size)
+{
+ FILE_BUFFER *file_buffer;
+
+ file_buffer = make_file_buffer ();
+ file_buffer->filename = filename ? xstrdup (filename) : NULL;
+ file_buffer->fullpath = filename ? xstrdup (filename) : NULL;
+ file_buffer->finfo.st_size = 0;
+ file_buffer->flags = (N_IsInternal | N_CannotGC);
+
+ file_buffer->contents = contents;
+ file_buffer->filesize = size;
+ build_tags_and_nodes (file_buffer);
+ return file_buffer;
+}
+
+static NODE *
+create_virtindex_node (FILE_BUFFER *file_buffer)
+{
+ NODE *node;
+ TAG *tag = file_buffer->tags[0];
+ char *text = file_buffer->contents + tag->nodestart;
+
+ text += skip_node_separator (text);
+
+ node = xmalloc (sizeof (NODE));
+ node->filename = file_buffer->filename;
+ node->nodename = xstrdup (tag->nodename);
+ node->contents = text;
+ node->nodelen = strlen (text);
+ node->body_start = strcspn(node->contents, "\n");
+
+ node->flags = 0;
+ node->display_pos = 0;
+ node->parent = NULL;
+ node->flags = 0;
+
+ return node;
+}
+
+#define NODECOL 41
+#define LINECOL 62
+
+static void
+format_reference (REFERENCE *ref, const char *filename, struct text_buffer *buf)
+{
+ size_t n;
+
+ n = text_buffer_printf (buf, "* %s: ", ref->label);
+ if (n < NODECOL)
+ n += text_buffer_fill (buf, ' ', NODECOL - n);
+
+ if (ref->filename && strcmp (ref->filename, filename))
+ n += text_buffer_printf (buf, "(%s)", ref->filename);
+ n += text_buffer_printf (buf, "%s. ", ref->nodename);
+
+ if (n < LINECOL)
+ n += text_buffer_fill (buf, ' ', LINECOL - n);
+ else
+ {
+ text_buffer_add_char (buf, '\n');
+ text_buffer_fill (buf, ' ', LINECOL);
+ }
+
+ text_buffer_printf (buf, "(line %4d)\n", ref->line_number);
+}
+
+DECLARE_INFO_COMMAND (info_virtual_index,
+ _("List all matches of a string in the index"))
+{
+ char *line;
+ FILE_BUFFER *fb, *tfb;
+ NODE *node;
+ struct text_buffer text;
+ size_t i;
+ size_t cnt, off;
+
+ fb = file_buffer_of_window (window);
+
+ if (!initial_index_filename ||
+ !fb ||
+ (FILENAME_CMP (initial_index_filename, fb->filename) != 0))
+ {
+ info_free_references (index_index);
+ window_message_in_echo_area (_("Finding index entries..."));
+ index_index = info_indices_of_file_buffer (fb);
+ }
+
+ if (!index_index)
+ {
+ info_error (_("No index"));
+ return;
+ }
+
+ line = info_read_maybe_completing (window, _("Index topic: "),
+ index_index);
+
+ /* User aborted? */
+ if (!line)
+ {
+ info_abort_key (window, 1, 1);
+ return;
+ }
+
+ if (mbslen (line) < min_search_length)
+ {
+ info_error (_("Search string too short"));
+ free (line);
+ return;
+ }
+
+ text_buffer_init (&text);
+ text_buffer_printf (&text, _("Index for `%s'"), line);
+ text_buffer_add_char (&text, 0);
+ off = text.off;
+ text_buffer_printf (&text,
+ "\n\n%c\n%s %s, %s %s, %s Top\n\n"
+ "Info Virtual Index\n"
+ "******************\n\n"
+ "Index entries that match `%s':\n\n"
+ "* Menu:\n\n",
+ INFO_COOKIE,
+ INFO_FILE_LABEL, fb->filename,
+ INFO_NODE_LABEL, text.base,
+ INFO_UP_LABEL, line);
+ memmove (text.base, text.base + off, text.off - off);
+ text.off -= off;
+
+ cnt = 0;
+ for (i = 0; index_index[i]; i++)
+ {
+ if (string_in_line (line, index_index[i]->label) != -1)
+ {
+ format_reference (index_index[i], fb->filename, &text);
+ cnt++;
+ }
+ }
+
+ if (cnt == 0)
+ {
+ text_buffer_free (&text);
+ info_error (_("No index entries containing `%s'."), line);
+ return;
+ }
+
+ tfb = create_virtindex_file_buffer (fb->filename, text.base, text.off);
+ node = create_virtindex_node (tfb);
+
+ info_set_node_of_window (1, window, node);
+
+ if (!info_error_was_printed)
+ window_clear_echo_area ();
+}
+
+static NODE *allfiles_node;
+
+NODE *
+allfiles_create_node (char *term, REFERENCE **fref)
+{
+ int i;
+ struct text_buffer text;
+ size_t off;
+ FILE_BUFFER *fb;
+
+ text_buffer_init (&text);
+ text_buffer_printf (&text, _("File names matching `%s'"), term);
+ text_buffer_add_char (&text, 0);
+ off = text.off;
+
+ text_buffer_printf (&text,
+ "\n\n%c\n%s %s\n\n"
+ "Info File Index\n"
+ "***************\n\n"
+ "File names that match `%s':\n\n"
+ "* Menu:\n\n",
+ INFO_COOKIE,
+ INFO_NODE_LABEL, text.base, term);
+
+ memmove (text.base, text.base + off, text.off - off);
+ text.off -= off;
+
+ for (i = 0; fref[i]; i++)
+ {
+ text_buffer_printf (&text, "* %4i: (%s)", i+1, fref[i]->filename);
+ if (fref[i]->nodename)
+ text_buffer_printf (&text, "%s", fref[i]->nodename);
+ text_buffer_printf (&text, ".\n");
+ }
+
+ fb = create_virtindex_file_buffer (NULL, text.base, text.off);
+ allfiles_node = create_virtindex_node (fb);
+
+ return allfiles_node;
+}
+
+DECLARE_INFO_COMMAND (info_all_files, _("Show all matching files"))
+{
+ if (!allfiles_node)
+ {
+ info_error (_("No file index"));
+ return;
+ }
+
+ info_set_node_of_window (1, window, allfiles_node);
+
+ if (!info_error_was_printed)
+ window_clear_echo_area ();
+}