2000-01-17 10:39:58 +00:00
|
|
|
|
/* indices.c -- deal with an Info file index.
|
2003-06-18 12:57:43 +00:00
|
|
|
|
$Id: indices.c,v 1.2 2003/02/11 16:39:06 karl Exp $
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
2003-06-18 12:57:43 +00:00
|
|
|
|
Copyright (C) 1993, 1997, 1998, 1999, 2002, 2003 Free Software
|
|
|
|
|
Foundation, Inc.
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
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 2, 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, write to the Free Software
|
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
|
|
Written by Brian Fox (bfox@ai.mit.edu). */
|
|
|
|
|
|
|
|
|
|
#include "info.h"
|
|
|
|
|
#include "indices.h"
|
|
|
|
|
|
|
|
|
|
/* User-visible variable controls the output of info-index-next. */
|
|
|
|
|
int show_index_match = 1;
|
|
|
|
|
|
|
|
|
|
/* In the Info sense, an index is a menu. This variable holds the last
|
|
|
|
|
parsed index. */
|
|
|
|
|
static REFERENCE **index_index = (REFERENCE **)NULL;
|
|
|
|
|
|
|
|
|
|
/* The offset of the most recently selected index element. */
|
|
|
|
|
static int index_offset = 0;
|
|
|
|
|
|
|
|
|
|
/* Variable which holds the last string searched for. */
|
|
|
|
|
static char *index_search = (char *)NULL;
|
|
|
|
|
|
|
|
|
|
/* A couple of "globals" describing where the initial index was found. */
|
|
|
|
|
static char *initial_index_filename = (char *)NULL;
|
|
|
|
|
static char *initial_index_nodename = (char *)NULL;
|
|
|
|
|
|
|
|
|
|
/* A structure associating index names with index offset ranges. */
|
|
|
|
|
typedef struct {
|
1999-01-14 19:35:19 +00:00
|
|
|
|
char *name; /* The nodename of this index. */
|
|
|
|
|
int first; /* The index in our list of the first entry. */
|
|
|
|
|
int last; /* The index in our list of the last entry. */
|
1997-01-11 02:12:38 +00:00
|
|
|
|
} INDEX_NAME_ASSOC;
|
|
|
|
|
|
|
|
|
|
/* An array associating index nodenames with index offset ranges. */
|
|
|
|
|
static INDEX_NAME_ASSOC **index_nodenames = (INDEX_NAME_ASSOC **)NULL;
|
|
|
|
|
static int index_nodenames_index = 0;
|
|
|
|
|
static int index_nodenames_slots = 0;
|
|
|
|
|
|
|
|
|
|
/* Add the name of NODE, and the range of the associated index elements
|
|
|
|
|
(passed in ARRAY) to index_nodenames. */
|
|
|
|
|
static void
|
|
|
|
|
add_index_to_index_nodenames (array, node)
|
|
|
|
|
REFERENCE **array;
|
|
|
|
|
NODE *node;
|
|
|
|
|
{
|
|
|
|
|
register int i, last;
|
|
|
|
|
INDEX_NAME_ASSOC *assoc;
|
|
|
|
|
|
2002-07-22 16:52:57 +00:00
|
|
|
|
for (last = 0; array[last + 1]; last++);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
assoc = (INDEX_NAME_ASSOC *)xmalloc (sizeof (INDEX_NAME_ASSOC));
|
1999-01-14 19:35:19 +00:00
|
|
|
|
assoc->name = xstrdup (node->nodename);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
if (!index_nodenames_index)
|
|
|
|
|
{
|
|
|
|
|
assoc->first = 0;
|
|
|
|
|
assoc->last = last;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; index_nodenames[i + 1]; i++);
|
|
|
|
|
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 *);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find and return the indices of WINDOW's file. The indices are defined
|
|
|
|
|
as the first node in the file containing the word "Index" and any
|
|
|
|
|
immediately following nodes whose names also contain "Index". All such
|
|
|
|
|
indices are concatenated and the result returned. If WINDOW's info file
|
|
|
|
|
doesn't have any indices, a NULL pointer is returned. */
|
|
|
|
|
REFERENCE **
|
|
|
|
|
info_indices_of_window (window)
|
|
|
|
|
WINDOW *window;
|
|
|
|
|
{
|
|
|
|
|
FILE_BUFFER *fb;
|
|
|
|
|
|
|
|
|
|
fb = file_buffer_of_window (window);
|
|
|
|
|
|
|
|
|
|
return (info_indices_of_file_buffer (fb));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
REFERENCE **
|
|
|
|
|
info_indices_of_file_buffer (file_buffer)
|
|
|
|
|
FILE_BUFFER *file_buffer;
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
REFERENCE **result = (REFERENCE **)NULL;
|
|
|
|
|
|
|
|
|
|
/* No file buffer, no indices. */
|
|
|
|
|
if (!file_buffer)
|
|
|
|
|
return ((REFERENCE **)NULL);
|
|
|
|
|
|
|
|
|
|
/* Reset globals describing where the index was found. */
|
|
|
|
|
maybe_free (initial_index_filename);
|
|
|
|
|
maybe_free (initial_index_nodename);
|
|
|
|
|
initial_index_filename = (char *)NULL;
|
|
|
|
|
initial_index_nodename = (char *)NULL;
|
|
|
|
|
|
|
|
|
|
if (index_nodenames)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; index_nodenames[i]; i++)
|
1999-01-14 19:35:19 +00:00
|
|
|
|
{
|
|
|
|
|
free (index_nodenames[i]->name);
|
|
|
|
|
free (index_nodenames[i]);
|
|
|
|
|
}
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
index_nodenames_index = 0;
|
|
|
|
|
index_nodenames[0] = (INDEX_NAME_ASSOC *)NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Grovel the names of the nodes found in this file. */
|
|
|
|
|
if (file_buffer->tags)
|
|
|
|
|
{
|
|
|
|
|
TAG *tag;
|
|
|
|
|
|
1999-01-14 19:35:19 +00:00
|
|
|
|
for (i = 0; (tag = file_buffer->tags[i]); i++)
|
|
|
|
|
{
|
|
|
|
|
if (string_in_line ("Index", tag->nodename) != -1)
|
|
|
|
|
{
|
|
|
|
|
NODE *node;
|
|
|
|
|
REFERENCE **menu;
|
|
|
|
|
|
|
|
|
|
/* Found one. Get its menu. */
|
|
|
|
|
node = info_get_node (tag->filename, tag->nodename);
|
|
|
|
|
if (!node)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Remember the filename and nodename of this index. */
|
|
|
|
|
initial_index_filename = xstrdup (file_buffer->filename);
|
|
|
|
|
initial_index_nodename = xstrdup (tag->nodename);
|
|
|
|
|
|
|
|
|
|
menu = info_menu_of_node (node);
|
|
|
|
|
|
|
|
|
|
/* If we have a menu, add this index's nodename and range
|
|
|
|
|
to our list of index_nodenames. */
|
|
|
|
|
if (menu)
|
|
|
|
|
{
|
|
|
|
|
add_index_to_index_nodenames (menu, node);
|
|
|
|
|
|
|
|
|
|
/* Concatenate the references found so far. */
|
|
|
|
|
result = info_concatenate_references (result, menu);
|
|
|
|
|
}
|
|
|
|
|
free (node);
|
|
|
|
|
}
|
|
|
|
|
}
|
1997-01-11 02:12:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If there is a result, clean it up so that every entry has a filename. */
|
|
|
|
|
for (i = 0; result && result[i]; i++)
|
|
|
|
|
if (!result[i]->filename)
|
1999-01-14 19:35:19 +00:00
|
|
|
|
result[i]->filename = xstrdup (file_buffer->filename);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DECLARE_INFO_COMMAND (info_index_search,
|
1999-01-14 19:35:19 +00:00
|
|
|
|
_("Look up a string in the index for this file"))
|
|
|
|
|
{
|
|
|
|
|
do_info_index_search (window, count, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Look up SEARCH_STRING in the index for this file. If SEARCH_STRING
|
|
|
|
|
is NULL, prompt user for input. */
|
|
|
|
|
void
|
|
|
|
|
do_info_index_search (window, count, search_string)
|
|
|
|
|
WINDOW *window;
|
|
|
|
|
int count;
|
|
|
|
|
char *search_string;
|
1997-01-11 02:12:38 +00:00
|
|
|
|
{
|
|
|
|
|
FILE_BUFFER *fb;
|
|
|
|
|
char *line;
|
|
|
|
|
|
|
|
|
|
/* Reset the index offset, since this is not the info-index-next command. */
|
|
|
|
|
index_offset = 0;
|
|
|
|
|
|
|
|
|
|
/* The user is selecting a new search string, so flush the old one. */
|
|
|
|
|
maybe_free (index_search);
|
|
|
|
|
index_search = (char *)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 ||
|
2000-01-17 10:39:58 +00:00
|
|
|
|
(FILENAME_CMP (initial_index_filename, fb->filename) != 0))
|
1997-01-11 02:12:38 +00:00
|
|
|
|
{
|
|
|
|
|
info_free_references (index_index);
|
1999-01-14 19:35:19 +00:00
|
|
|
|
window_message_in_echo_area (_("Finding index entries..."));
|
1997-01-11 02:12:38 +00:00
|
|
|
|
index_index = info_indices_of_file_buffer (fb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If there is no index, quit now. */
|
|
|
|
|
if (!index_index)
|
|
|
|
|
{
|
1999-01-14 19:35:19 +00:00
|
|
|
|
info_error (_("No indices found."));
|
1997-01-11 02:12:38 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1999-01-14 19:35:19 +00:00
|
|
|
|
/* Okay, there is an index. Look for SEARCH_STRING, or, if it is
|
|
|
|
|
empty, prompt for one. */
|
|
|
|
|
if (search_string && *search_string)
|
|
|
|
|
line = xstrdup (search_string);
|
|
|
|
|
else
|
1997-01-11 02:12:38 +00:00
|
|
|
|
{
|
1999-01-14 19:35:19 +00:00
|
|
|
|
line = info_read_maybe_completing (window, _("Index entry: "),
|
|
|
|
|
index_index);
|
|
|
|
|
window = active_window;
|
|
|
|
|
|
|
|
|
|
/* User aborted? */
|
|
|
|
|
if (!line)
|
|
|
|
|
{
|
|
|
|
|
info_abort_key (active_window, 1, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Empty line means move to the Index node. */
|
|
|
|
|
if (!*line)
|
|
|
|
|
{
|
|
|
|
|
free (line);
|
|
|
|
|
|
|
|
|
|
if (initial_index_filename && initial_index_nodename)
|
|
|
|
|
{
|
|
|
|
|
NODE *node;
|
|
|
|
|
|
|
|
|
|
node = info_get_node (initial_index_filename,
|
|
|
|
|
initial_index_nodename);
|
|
|
|
|
set_remembered_pagetop_and_point (window);
|
|
|
|
|
window_set_node_of_window (window, node);
|
|
|
|
|
remember_window_and_node (window, node);
|
|
|
|
|
window_clear_echo_area ();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
1997-01-11 02:12:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
manipulation of INDEX_OFFSET. */
|
|
|
|
|
{
|
|
|
|
|
int old_offset;
|
|
|
|
|
|
|
|
|
|
/* Start the search right after/before this index. */
|
|
|
|
|
if (count < 0)
|
|
|
|
|
{
|
1999-01-14 19:35:19 +00:00
|
|
|
|
register int i;
|
|
|
|
|
for (i = 0; index_index[i]; i++);
|
|
|
|
|
index_offset = i;
|
1997-01-11 02:12:38 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
index_offset = -1;
|
|
|
|
|
|
|
|
|
|
old_offset = index_offset;
|
|
|
|
|
|
|
|
|
|
/* The "last" string searched for is this one. */
|
|
|
|
|
index_search = line;
|
|
|
|
|
|
|
|
|
|
/* Find it, or error. */
|
|
|
|
|
info_next_index_match (window, count, 0);
|
|
|
|
|
|
|
|
|
|
/* If the search failed, return the index offset to where it belongs. */
|
|
|
|
|
if (index_offset == old_offset)
|
|
|
|
|
index_offset = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-01-14 19:35:19 +00:00
|
|
|
|
int
|
|
|
|
|
index_entry_exists (window, string)
|
|
|
|
|
WINDOW *window;
|
|
|
|
|
char *string;
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
FILE_BUFFER *fb;
|
|
|
|
|
|
|
|
|
|
/* If there is no previous search string, the user hasn't built an index
|
|
|
|
|
yet. */
|
|
|
|
|
if (!string)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
fb = file_buffer_of_window (window);
|
|
|
|
|
if (!initial_index_filename
|
2000-01-17 10:39:58 +00:00
|
|
|
|
|| (FILENAME_CMP (initial_index_filename, fb->filename) != 0))
|
1999-01-14 19:35:19 +00:00
|
|
|
|
{
|
|
|
|
|
info_free_references (index_index);
|
|
|
|
|
index_index = info_indices_of_file_buffer (fb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If there is no index, that is an error. */
|
|
|
|
|
if (!index_index)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; (i > -1) && (index_index[i]); i++)
|
|
|
|
|
if (strcmp (string, index_index[i]->label) == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* If that failed, look for the next substring match. */
|
|
|
|
|
if ((i < 0) || (!index_index[i]))
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; (i > -1) && (index_index[i]); i++)
|
|
|
|
|
if (string_in_line (string, index_index[i]->label) != -1)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if ((i > -1) && (index_index[i]))
|
|
|
|
|
string_in_line (string, index_index[i]->label);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If that failed, return 0. */
|
|
|
|
|
if ((i < 0) || (!index_index[i]))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
1997-01-11 02:12:38 +00:00
|
|
|
|
DECLARE_INFO_COMMAND (info_next_index_match,
|
1999-01-14 19:35:19 +00:00
|
|
|
|
_("Go to the next matching index item from the last `\\[index-search]' command"))
|
1997-01-11 02:12:38 +00:00
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
int partial, dir;
|
|
|
|
|
NODE *node;
|
|
|
|
|
|
|
|
|
|
/* If there is no previous search string, the user hasn't built an index
|
|
|
|
|
yet. */
|
|
|
|
|
if (!index_search)
|
|
|
|
|
{
|
1999-01-14 19:35:19 +00:00
|
|
|
|
info_error (_("No previous index search string."));
|
1997-01-11 02:12:38 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If there is no index, that is an error. */
|
|
|
|
|
if (!index_index)
|
|
|
|
|
{
|
1999-01-14 19:35:19 +00:00
|
|
|
|
info_error (_("No index entries."));
|
1997-01-11 02:12:38 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The direction of this search is controlled by the value of the
|
|
|
|
|
numeric argument. */
|
|
|
|
|
if (count < 0)
|
|
|
|
|
dir = -1;
|
|
|
|
|
else
|
|
|
|
|
dir = 1;
|
|
|
|
|
|
|
|
|
|
/* Search for the next occurence of index_search. First try to find
|
|
|
|
|
an exact match. */
|
|
|
|
|
partial = 0;
|
|
|
|
|
|
|
|
|
|
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]))
|
|
|
|
|
{
|
|
|
|
|
for (i = index_offset + dir; (i > -1) && (index_index[i]); i += dir)
|
1999-01-14 19:35:19 +00:00
|
|
|
|
if (string_in_line (index_search, index_index[i]->label) != -1)
|
|
|
|
|
break;
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
if ((i > -1) && (index_index[i]))
|
1999-01-14 19:35:19 +00:00
|
|
|
|
partial = string_in_line (index_search, index_index[i]->label);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If that failed, print an error. */
|
|
|
|
|
if ((i < 0) || (!index_index[i]))
|
|
|
|
|
{
|
1999-01-14 19:35:19 +00:00
|
|
|
|
info_error (_("No %sindex entries containing \"%s\"."),
|
|
|
|
|
index_offset > 0 ? _("more ") : "", index_search);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Okay, we found the next one. Move the offset to the current entry. */
|
|
|
|
|
index_offset = i;
|
|
|
|
|
|
|
|
|
|
/* Report to the user on what we have found. */
|
|
|
|
|
{
|
|
|
|
|
register int j;
|
2003-06-18 12:57:43 +00:00
|
|
|
|
const char *name = _("CAN'T SEE THIS");
|
1997-01-11 02:12:38 +00:00
|
|
|
|
char *match;
|
|
|
|
|
|
|
|
|
|
for (j = 0; index_nodenames[j]; j++)
|
|
|
|
|
{
|
1999-01-14 19:35:19 +00:00
|
|
|
|
if ((i >= index_nodenames[j]->first) &&
|
|
|
|
|
(i <= index_nodenames[j]->last))
|
|
|
|
|
{
|
|
|
|
|
name = index_nodenames[j]->name;
|
|
|
|
|
break;
|
|
|
|
|
}
|
1997-01-11 02:12:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we had a partial match, indicate to the user which part of the
|
|
|
|
|
string matched. */
|
1999-01-14 19:35:19 +00:00
|
|
|
|
match = xstrdup (index_index[i]->label);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
if (partial && show_index_match)
|
|
|
|
|
{
|
1999-01-14 19:35:19 +00:00
|
|
|
|
int j, ls, start, upper;
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
1999-01-14 19:35:19 +00:00
|
|
|
|
ls = strlen (index_search);
|
|
|
|
|
start = partial - ls;
|
|
|
|
|
upper = isupper (match[start]) ? 1 : 0;
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
1999-01-14 19:35:19 +00:00
|
|
|
|
for (j = 0; j < ls; j++)
|
|
|
|
|
if (upper)
|
|
|
|
|
match[j + start] = info_tolower (match[j + start]);
|
|
|
|
|
else
|
|
|
|
|
match[j + start] = info_toupper (match[j + start]);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
char *format;
|
|
|
|
|
|
|
|
|
|
format = replace_in_documentation
|
1999-01-14 19:35:19 +00:00
|
|
|
|
(_("Found \"%s\" in %s. (`\\[next-index-match]' tries to find next.)"));
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
window_message_in_echo_area (format, match, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free (match);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Select the node corresponding to this index entry. */
|
|
|
|
|
node = info_get_node (index_index[i]->filename, index_index[i]->nodename);
|
|
|
|
|
|
|
|
|
|
if (!node)
|
|
|
|
|
{
|
2000-01-17 10:39:58 +00:00
|
|
|
|
info_error (msg_cant_file_node,
|
1999-01-14 19:35:19 +00:00
|
|
|
|
index_index[i]->filename, index_index[i]->nodename);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-17 10:39:58 +00:00
|
|
|
|
info_set_node_of_window (1, window, node);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
/* Try to find an occurence of LABEL in this node. */
|
|
|
|
|
{
|
|
|
|
|
long start, loc;
|
|
|
|
|
|
|
|
|
|
start = window->line_starts[1] - window->node->contents;
|
|
|
|
|
loc = info_target_search_node (node, index_index[i]->label, start);
|
|
|
|
|
|
|
|
|
|
if (loc != -1)
|
|
|
|
|
{
|
1999-01-14 19:35:19 +00:00
|
|
|
|
window->point = loc;
|
|
|
|
|
window_adjust_pagetop (window);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* **************************************************************** */
|
1999-01-14 19:35:19 +00:00
|
|
|
|
/* */
|
|
|
|
|
/* Info APROPOS: Search every known index. */
|
|
|
|
|
/* */
|
1997-01-11 02:12:38 +00:00
|
|
|
|
/* **************************************************************** */
|
|
|
|
|
|
|
|
|
|
/* For every menu item in DIR, search the indices of that file for
|
|
|
|
|
SEARCH_STRING. */
|
|
|
|
|
REFERENCE **
|
|
|
|
|
apropos_in_all_indices (search_string, inform)
|
|
|
|
|
char *search_string;
|
|
|
|
|
int inform;
|
|
|
|
|
{
|
|
|
|
|
register int i, dir_index;
|
|
|
|
|
REFERENCE **all_indices = (REFERENCE **)NULL;
|
|
|
|
|
REFERENCE **dir_menu = (REFERENCE **)NULL;
|
|
|
|
|
NODE *dir_node;
|
|
|
|
|
|
|
|
|
|
dir_node = info_get_node ("dir", "Top");
|
|
|
|
|
if (dir_node)
|
|
|
|
|
dir_menu = info_menu_of_node (dir_node);
|
|
|
|
|
|
|
|
|
|
if (!dir_menu)
|
1999-01-14 19:35:19 +00:00
|
|
|
|
return NULL;
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
/* For every menu item in DIR, get the associated node's file buffer and
|
|
|
|
|
read the indices of that file buffer. Gather all of the indices into
|
|
|
|
|
one large one. */
|
|
|
|
|
for (dir_index = 0; dir_menu[dir_index]; dir_index++)
|
|
|
|
|
{
|
|
|
|
|
REFERENCE **this_index, *this_item;
|
|
|
|
|
NODE *this_node;
|
|
|
|
|
FILE_BUFFER *this_fb;
|
2000-01-17 10:39:58 +00:00
|
|
|
|
int dir_node_duplicated = 0;
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
this_item = dir_menu[dir_index];
|
|
|
|
|
|
|
|
|
|
if (!this_item->filename)
|
1999-01-14 19:35:19 +00:00
|
|
|
|
{
|
2000-01-17 10:39:58 +00:00
|
|
|
|
dir_node_duplicated = 1;
|
1999-01-14 19:35:19 +00:00
|
|
|
|
if (dir_node->parent)
|
|
|
|
|
this_item->filename = xstrdup (dir_node->parent);
|
|
|
|
|
else
|
|
|
|
|
this_item->filename = xstrdup (dir_node->filename);
|
|
|
|
|
}
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
/* Find this node. If we cannot find it, try using the label of the
|
1999-01-14 19:35:19 +00:00
|
|
|
|
entry as a file (i.e., "(LABEL)Top"). */
|
1997-01-11 02:12:38 +00:00
|
|
|
|
this_node = info_get_node (this_item->filename, this_item->nodename);
|
|
|
|
|
|
|
|
|
|
if (!this_node && this_item->nodename &&
|
1999-01-14 19:35:19 +00:00
|
|
|
|
(strcmp (this_item->label, this_item->nodename) == 0))
|
|
|
|
|
this_node = info_get_node (this_item->label, "Top");
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
if (!this_node)
|
2000-01-17 10:39:58 +00:00
|
|
|
|
{
|
|
|
|
|
if (dir_node_duplicated)
|
|
|
|
|
free (this_item->filename);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
/* Get the file buffer associated with this node. */
|
|
|
|
|
{
|
1999-01-14 19:35:19 +00:00
|
|
|
|
char *files_name;
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
1999-01-14 19:35:19 +00:00
|
|
|
|
files_name = this_node->parent;
|
|
|
|
|
if (!files_name)
|
|
|
|
|
files_name = this_node->filename;
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
1999-01-14 19:35:19 +00:00
|
|
|
|
this_fb = info_find_file (files_name);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
2000-01-17 10:39:58 +00:00
|
|
|
|
/* If we already scanned this file, don't do that again.
|
|
|
|
|
In addition to being faster, this also avoids having
|
|
|
|
|
multiple identical entries in the *Apropos* menu. */
|
|
|
|
|
for (i = 0; i < dir_index; i++)
|
|
|
|
|
if (FILENAME_CMP (this_fb->filename, dir_menu[i]->filename) == 0)
|
|
|
|
|
break;
|
|
|
|
|
if (i < dir_index)
|
|
|
|
|
{
|
|
|
|
|
if (dir_node_duplicated)
|
|
|
|
|
free (this_item->filename);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
1999-01-14 19:35:19 +00:00
|
|
|
|
if (this_fb && inform)
|
|
|
|
|
message_in_echo_area (_("Scanning indices of \"%s\"..."), files_name);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
1999-01-14 19:35:19 +00:00
|
|
|
|
this_index = info_indices_of_file_buffer (this_fb);
|
|
|
|
|
free (this_node);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
1999-01-14 19:35:19 +00:00
|
|
|
|
if (this_fb && inform)
|
|
|
|
|
unmessage_in_echo_area ();
|
1997-01-11 02:12:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this_index)
|
1999-01-14 19:35:19 +00:00
|
|
|
|
{
|
|
|
|
|
/* Remember the filename which contains this set of references. */
|
|
|
|
|
for (i = 0; this_index && this_index[i]; i++)
|
|
|
|
|
if (!this_index[i]->filename)
|
|
|
|
|
this_index[i]->filename = xstrdup (this_fb->filename);
|
|
|
|
|
|
|
|
|
|
/* Concatenate with the other indices. */
|
|
|
|
|
all_indices = info_concatenate_references (all_indices, this_index);
|
|
|
|
|
}
|
1997-01-11 02:12:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info_free_references (dir_menu);
|
|
|
|
|
|
|
|
|
|
/* Build a list of the references which contain SEARCH_STRING. */
|
|
|
|
|
if (all_indices)
|
|
|
|
|
{
|
|
|
|
|
REFERENCE *entry, **apropos_list = (REFERENCE **)NULL;
|
|
|
|
|
int apropos_list_index = 0;
|
|
|
|
|
int apropos_list_slots = 0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; (entry = all_indices[i]); i++)
|
1999-01-14 19:35:19 +00:00
|
|
|
|
{
|
|
|
|
|
if (string_in_line (search_string, entry->label) != -1)
|
|
|
|
|
{
|
|
|
|
|
add_pointer_to_array
|
|
|
|
|
(entry, apropos_list_index, apropos_list, apropos_list_slots,
|
|
|
|
|
100, REFERENCE *);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
maybe_free (entry->label);
|
|
|
|
|
maybe_free (entry->filename);
|
|
|
|
|
maybe_free (entry->nodename);
|
|
|
|
|
free (entry);
|
|
|
|
|
}
|
|
|
|
|
}
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
free (all_indices);
|
|
|
|
|
all_indices = apropos_list;
|
|
|
|
|
}
|
|
|
|
|
return (all_indices);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define APROPOS_NONE \
|
2000-01-17 10:39:58 +00:00
|
|
|
|
N_("No available info files have \"%s\" in their indices.")
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
info_apropos (string)
|
|
|
|
|
char *string;
|
|
|
|
|
{
|
|
|
|
|
REFERENCE **apropos_list;
|
|
|
|
|
|
|
|
|
|
apropos_list = apropos_in_all_indices (string, 0);
|
|
|
|
|
|
|
|
|
|
if (!apropos_list)
|
|
|
|
|
{
|
2000-01-17 10:39:58 +00:00
|
|
|
|
info_error (_(APROPOS_NONE), string);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
REFERENCE *entry;
|
|
|
|
|
|
|
|
|
|
for (i = 0; (entry = apropos_list[i]); i++)
|
2000-01-17 10:39:58 +00:00
|
|
|
|
fprintf (stdout, "\"(%s)%s\" -- %s\n",
|
1999-01-14 19:35:19 +00:00
|
|
|
|
entry->filename, entry->nodename, entry->label);
|
1997-01-11 02:12:38 +00:00
|
|
|
|
}
|
|
|
|
|
info_free_references (apropos_list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *apropos_list_nodename = "*Apropos*";
|
|
|
|
|
|
|
|
|
|
DECLARE_INFO_COMMAND (info_index_apropos,
|
1999-01-14 19:35:19 +00:00
|
|
|
|
_("Grovel all known info file's indices for a string and build a menu"))
|
1997-01-11 02:12:38 +00:00
|
|
|
|
{
|
|
|
|
|
char *line;
|
|
|
|
|
|
1999-01-14 19:35:19 +00:00
|
|
|
|
line = info_read_in_echo_area (window, _("Index apropos: "));
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
window = active_window;
|
|
|
|
|
|
|
|
|
|
/* User aborted? */
|
|
|
|
|
if (!line)
|
|
|
|
|
{
|
|
|
|
|
info_abort_key (window, 1, 1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* User typed something? */
|
|
|
|
|
if (*line)
|
|
|
|
|
{
|
|
|
|
|
REFERENCE **apropos_list;
|
|
|
|
|
NODE *apropos_node;
|
|
|
|
|
|
|
|
|
|
apropos_list = apropos_in_all_indices (line, 1);
|
|
|
|
|
|
|
|
|
|
if (!apropos_list)
|
1999-01-14 19:35:19 +00:00
|
|
|
|
{
|
2000-01-17 10:39:58 +00:00
|
|
|
|
info_error (_(APROPOS_NONE), line);
|
1999-01-14 19:35:19 +00:00
|
|
|
|
}
|
1997-01-11 02:12:38 +00:00
|
|
|
|
else
|
1999-01-14 19:35:19 +00:00
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
char *line_buffer;
|
|
|
|
|
|
|
|
|
|
initialize_message_buffer ();
|
|
|
|
|
printf_to_message_buffer
|
|
|
|
|
(_("\n* Menu: Nodes whoses indices contain \"%s\":\n"), line);
|
|
|
|
|
line_buffer = (char *)xmalloc (500);
|
|
|
|
|
|
|
|
|
|
for (i = 0; apropos_list[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
int len;
|
2000-01-17 10:39:58 +00:00
|
|
|
|
/* The label might be identical to that of another index
|
|
|
|
|
entry in another Info file. Therefore, we make the file
|
|
|
|
|
name part of the menu entry, to make them all distinct. */
|
|
|
|
|
sprintf (line_buffer, "* %s [%s]: ",
|
|
|
|
|
apropos_list[i]->label, apropos_list[i]->filename);
|
|
|
|
|
len = pad_to (40, line_buffer);
|
|
|
|
|
sprintf (line_buffer + len, "(%s)%s.",
|
1999-01-14 19:35:19 +00:00
|
|
|
|
apropos_list[i]->filename, apropos_list[i]->nodename);
|
|
|
|
|
printf_to_message_buffer ("%s\n", line_buffer);
|
|
|
|
|
}
|
|
|
|
|
free (line_buffer);
|
|
|
|
|
}
|
1997-01-11 02:12:38 +00:00
|
|
|
|
|
|
|
|
|
apropos_node = message_buffer_to_node ();
|
|
|
|
|
add_gcable_pointer (apropos_node->contents);
|
|
|
|
|
name_internal_node (apropos_node, apropos_list_nodename);
|
|
|
|
|
|
|
|
|
|
/* Even though this is an internal node, we don't want the window
|
1999-01-14 19:35:19 +00:00
|
|
|
|
system to treat it specially. So we turn off the internalness
|
|
|
|
|
of it here. */
|
1997-01-11 02:12:38 +00:00
|
|
|
|
apropos_node->flags &= ~N_IsInternal;
|
|
|
|
|
|
|
|
|
|
/* Find/Create a window to contain this node. */
|
|
|
|
|
{
|
1999-01-14 19:35:19 +00:00
|
|
|
|
WINDOW *new;
|
|
|
|
|
NODE *node;
|
|
|
|
|
|
|
|
|
|
set_remembered_pagetop_and_point (window);
|
|
|
|
|
|
|
|
|
|
/* If a window is visible and showing an apropos list already,
|
|
|
|
|
re-use it. */
|
|
|
|
|
for (new = windows; new; new = new->next)
|
|
|
|
|
{
|
|
|
|
|
node = new->node;
|
|
|
|
|
|
|
|
|
|
if (internal_info_node_p (node) &&
|
|
|
|
|
(strcmp (node->nodename, apropos_list_nodename) == 0))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we couldn't find an existing window, try to use the next window
|
|
|
|
|
in the chain. */
|
|
|
|
|
if (!new && window->next)
|
|
|
|
|
new = window->next;
|
|
|
|
|
|
|
|
|
|
/* If we still don't have a window, make a new one to contain
|
|
|
|
|
the list. */
|
|
|
|
|
if (!new)
|
|
|
|
|
{
|
|
|
|
|
WINDOW *old_active;
|
|
|
|
|
|
|
|
|
|
old_active = active_window;
|
|
|
|
|
active_window = window;
|
|
|
|
|
new = window_make_window ((NODE *)NULL);
|
|
|
|
|
active_window = old_active;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we couldn't make a new window, use this one. */
|
|
|
|
|
if (!new)
|
|
|
|
|
new = window;
|
|
|
|
|
|
|
|
|
|
/* Lines do not wrap in this window. */
|
|
|
|
|
new->flags |= W_NoWrap;
|
|
|
|
|
|
|
|
|
|
window_set_node_of_window (new, apropos_node);
|
|
|
|
|
remember_window_and_node (new, apropos_node);
|
|
|
|
|
active_window = new;
|
1997-01-11 02:12:38 +00:00
|
|
|
|
}
|
|
|
|
|
info_free_references (apropos_list);
|
|
|
|
|
}
|
|
|
|
|
free (line);
|
|
|
|
|
|
|
|
|
|
if (!info_error_was_printed)
|
|
|
|
|
window_clear_echo_area ();
|
|
|
|
|
}
|
|
|
|
|
|