diff options
Diffstat (limited to 'Build/source/utils/texinfo/info/nodes.c')
-rw-r--r-- | Build/source/utils/texinfo/info/nodes.c | 1269 |
1 files changed, 0 insertions, 1269 deletions
diff --git a/Build/source/utils/texinfo/info/nodes.c b/Build/source/utils/texinfo/info/nodes.c deleted file mode 100644 index a0b95411609..00000000000 --- a/Build/source/utils/texinfo/info/nodes.c +++ /dev/null @@ -1,1269 +0,0 @@ -/* nodes.c -- how to get an Info file and node. - $Id: nodes.c,v 1.10 2007/12/03 01:38:43 karl Exp $ - - Copyright (C) 1993, 1998, 1999, 2000, 2002, 2003, 2004, 2006, 2007 - 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 <http://www.gnu.org/licenses/>. - - Originally written by Brian Fox (bfox@ai.mit.edu). */ - -#include "info.h" - -#include "nodes.h" -#include "search.h" -#include "filesys.h" -#include "info-utils.h" - -#if defined (HANDLE_MAN_PAGES) -# include "man.h" -#endif /* HANDLE_MAN_PAGES */ - -static void forget_info_file (char *filename); -static void remember_info_file (FILE_BUFFER *file_buffer); -static void free_file_buffer_tags (FILE_BUFFER *file_buffer); -static void free_info_tag (TAG *tag); -static void get_nodes_of_tags_table (FILE_BUFFER *file_buffer, - SEARCH_BINDING *buffer_binding); -static void get_nodes_of_info_file (FILE_BUFFER *file_buffer); -static void get_tags_of_indirect_tags_table (FILE_BUFFER *file_buffer, - SEARCH_BINDING *indirect_binding, SEARCH_BINDING *tags_binding); -static void info_reload_file_buffer_contents (FILE_BUFFER *fb); -static char *adjust_nodestart (NODE *node, int min, int max); -static FILE_BUFFER *info_load_file_internal (char *filename, int get_tags); -static FILE_BUFFER *info_find_file_internal (char *filename, int get_tags); -static NODE *info_node_of_file_buffer_tags (FILE_BUFFER *file_buffer, - char *nodename); - -static long get_node_length (SEARCH_BINDING *binding); - -/* Magic number that RMS used to decide how much a tags table pointer could - be off by. I feel that it should be much smaller, like 4. */ -#define DEFAULT_INFO_FUDGE 1000 - -/* Passed to *_internal functions. INFO_GET_TAGS says to do what is - neccessary to fill in the nodes or tags arrays in FILE_BUFFER. */ -#define INFO_NO_TAGS 0 -#define INFO_GET_TAGS 1 - -/* Global variables. */ - -/* When non-zero, this is a string describing the recent file error. */ -char *info_recent_file_error = NULL; - -/* The list of already loaded nodes. */ -FILE_BUFFER **info_loaded_files = NULL; - -/* The number of slots currently allocated to LOADED_FILES. */ -int info_loaded_files_slots = 0; - -/* Public functions for node manipulation. */ - -/* Used to build `dir' menu from `localdir' files found in INFOPATH. */ -extern void maybe_build_dir_node (char *dirname); - -/* Return a pointer to a NODE structure for the Info node (FILENAME)NODENAME. - If FILENAME is NULL, `dir' is used. - IF NODENAME is NULL, `Top' is used. - If the node cannot be found, return NULL. */ -NODE * -info_get_node (char *filename, char *nodename) -{ - NODE *node; - FILE_BUFFER *file_buffer = NULL; - - info_recent_file_error = NULL; - info_parse_node (nodename, DONT_SKIP_NEWLINES); - nodename = NULL; - - if (info_parsed_filename) - filename = info_parsed_filename; - - if (info_parsed_nodename) - nodename = info_parsed_nodename; - - /* If FILENAME is not specified, it defaults to "dir". */ - if (!filename) - filename = "dir"; - - /* If the file to be looked up is "dir", build the contents from all of - the "dir"s and "localdir"s found in INFOPATH. */ - if (is_dir_name (filename)) - maybe_build_dir_node (filename); - - /* Find the correct info file, or give up. */ - file_buffer = info_find_file (filename); - if (!file_buffer) - { - if (filesys_error_number) - info_recent_file_error = - filesys_error_string (filename, filesys_error_number); - return NULL; - } - - /* Look for the node. */ - node = info_get_node_of_file_buffer (nodename, file_buffer); - - /* If the node not found was "Top", try again with different case, - unless this was a man page. */ - if (!node - && mbscasecmp (filename, MANPAGE_FILE_BUFFER_NAME) != 0 - && (nodename == NULL || mbscasecmp (nodename, "Top") == 0)) - { - node = info_get_node_of_file_buffer ("Top", file_buffer); - if (!node) - node = info_get_node_of_file_buffer ("top", file_buffer); - if (!node) - node = info_get_node_of_file_buffer ("TOP", file_buffer); - } - - return node; -} - -/* Return a pointer to a NODE structure for the Info node NODENAME in - FILE_BUFFER. NODENAME can be passed as NULL, in which case the - nodename of "Top" is used. If the node cannot be found, return a - NULL pointer. */ -NODE * -info_get_node_of_file_buffer (char *nodename, FILE_BUFFER *file_buffer) -{ - NODE *node = NULL; - int implicit_nodename = 0; - - /* If we are unable to find the file, we have to give up. There isn't - anything else we can do. */ - if (!file_buffer) - return NULL; - - /* If the file buffer was gc'ed, reload the contents now. */ - if (!file_buffer->contents) - info_reload_file_buffer_contents (file_buffer); - - /* If NODENAME is not specified, it defaults to "Top". */ - if (!nodename) - { - nodename = "Top"; - implicit_nodename = 1; /* don't return man page for top */ - } - - /* If the name of the node that we wish to find is exactly "*", then the - node body is the contents of the entire file. Create and return such - a node. */ - if (strcmp (nodename, "*") == 0) - { - node = (NODE *)xmalloc (sizeof (NODE)); - node->filename = file_buffer->fullpath; - node->parent = NULL; - node->nodename = xstrdup ("*"); - node->contents = file_buffer->contents; - node->nodelen = file_buffer->filesize; - node->flags = 0; - node->display_pos = 0; - } -#if defined (HANDLE_MAN_PAGES) - /* If the file buffer is the magic one associated with manpages, call - the manpage node finding function instead. */ - else if (!implicit_nodename && file_buffer->flags & N_IsManPage) - { - node = get_manpage_node (file_buffer, nodename); - } -#endif /* HANDLE_MAN_PAGES */ - /* If this is the "main" info file, it might contain a tags table. Search - the tags table for an entry which matches the node that we want. If - there is a tags table, get the file which contains this node, but don't - bother building a node list for it. */ - else if (file_buffer->tags) - { - node = info_node_of_file_buffer_tags (file_buffer, nodename); - } - - /* Return the results of our node search. */ - return node; -} - -/* Locate the file named by FILENAME, and return the information structure - describing this file. The file may appear in our list of loaded files - already, or it may not. If it does not already appear, find the file, - and add it to the list of loaded files. If the file cannot be found, - return a NULL FILE_BUFFER *. */ -FILE_BUFFER * -info_find_file (char *filename) -{ - return info_find_file_internal (filename, INFO_GET_TAGS); -} - -/* Load the info file FILENAME, remembering information about it in a - file buffer. */ -FILE_BUFFER * -info_load_file (char *filename) -{ - return info_load_file_internal (filename, INFO_GET_TAGS); -} - - -/* Private functions implementation. */ - -/* The workhorse for info_find_file (). Non-zero 2nd argument says to - try to build a tags table (or otherwise glean the nodes) for this - file once found. By default, we build the tags table, but when this - function is called by info_get_node () when we already have a valid - tags table describing the nodes, it is unnecessary. */ -static FILE_BUFFER * -info_find_file_internal (char *filename, int get_tags) -{ - int i; - FILE_BUFFER *file_buffer; - - /* First try to find the file in our list of already loaded files. */ - if (info_loaded_files) - { - for (i = 0; (file_buffer = info_loaded_files[i]); i++) - if ((FILENAME_CMP (filename, file_buffer->filename) == 0) - || (FILENAME_CMP (filename, file_buffer->fullpath) == 0) - || (!IS_ABSOLUTE (filename) - && FILENAME_CMP (filename, - filename_non_directory (file_buffer->fullpath)) - == 0)) - { - struct stat new_info, *old_info; - - /* This file is loaded. If the filename that we want is - specifically "dir", then simply return the file buffer. */ - if (is_dir_name (filename_non_directory (filename))) - return file_buffer; - -#if defined (HANDLE_MAN_PAGES) - /* Do the same for the magic MANPAGE file. */ - if (file_buffer->flags & N_IsManPage) - return file_buffer; -#endif /* HANDLE_MAN_PAGES */ - - /* The file appears to be already loaded, and is not "dir". Check - to see if it's changed since the last time it was loaded. */ - if (stat (file_buffer->fullpath, &new_info) == -1) - { - filesys_error_number = errno; - return NULL; - } - - old_info = &file_buffer->finfo; - - if (new_info.st_size != old_info->st_size - || new_info.st_mtime != old_info->st_mtime) - { - /* The file has changed. Forget that we ever had loaded it - in the first place. */ - forget_info_file (filename); - break; - } - else - { - /* The info file exists, and has not changed since the last - time it was loaded. If the caller requested a nodes list - for this file, and there isn't one here, build the nodes - for this file_buffer. In any case, return the file_buffer - object. */ - if (!file_buffer->contents) - { - /* The file's contents have been gc'ed. Reload it. */ - info_reload_file_buffer_contents (file_buffer); - if (!file_buffer->contents) - return NULL; - } - - if (get_tags && !file_buffer->tags) - build_tags_and_nodes (file_buffer); - - return file_buffer; - } - } - } - - /* The file wasn't loaded. Try to load it now. */ -#if defined (HANDLE_MAN_PAGES) - /* If the name of the file that we want is our special file buffer for - Unix manual pages, then create the file buffer, and return it now. */ - if (mbscasecmp (filename, MANPAGE_FILE_BUFFER_NAME) == 0) - file_buffer = create_manpage_file_buffer (); - else -#endif /* HANDLE_MAN_PAGES */ - file_buffer = info_load_file_internal (filename, get_tags); - - /* If the file was loaded, remember the name under which it was found. */ - if (file_buffer) - remember_info_file (file_buffer); - - return file_buffer; -} - -/* The workhorse function for info_load_file (). Non-zero second argument - says to build a list of tags (or nodes) for this file. This is the - default behaviour when info_load_file () is called, but it is not - necessary when loading a subfile for which we already have tags. */ -static FILE_BUFFER * -info_load_file_internal (char *filename, int get_tags) -{ - char *fullpath, *contents; - long filesize; - struct stat finfo; - int retcode, compressed; - FILE_BUFFER *file_buffer = NULL; - - /* Get the full pathname of this file, as known by the info system. - That is to say, search along INFOPATH and expand tildes, etc. */ - fullpath = info_find_fullpath (filename); - - /* Did we actually find the file? */ - retcode = stat (fullpath, &finfo); - - /* If the file referenced by the name returned from info_find_fullpath () - doesn't exist, then try again with the last part of the filename - appearing in lowercase. */ - /* This is probably not needed at all on those systems which define - FILENAME_CMP to be mbscasecmp. But let's do it anyway, lest some - network redirector supports case sensitivity. */ - if (retcode < 0) - { - char *lowered_name; - char *tmp_basename; - - lowered_name = xstrdup (filename); - tmp_basename = filename_non_directory (lowered_name); - - while (*tmp_basename) - { - if (isupper (*tmp_basename)) - *tmp_basename = tolower (*tmp_basename); - - tmp_basename++; - } - - fullpath = info_find_fullpath (lowered_name); - - retcode = stat (fullpath, &finfo); - free (lowered_name); - } - - /* If the file wasn't found, give up, returning a NULL pointer. */ - if (retcode < 0) - { - filesys_error_number = errno; - return NULL; - } - - /* Otherwise, try to load the file. */ - contents = filesys_read_info_file (fullpath, &filesize, &finfo, &compressed); - - if (!contents) - return NULL; - - /* The file was found, and can be read. Allocate FILE_BUFFER and fill - in the various members. */ - file_buffer = make_file_buffer (); - file_buffer->filename = xstrdup (filename); - file_buffer->fullpath = xstrdup (fullpath); - file_buffer->finfo = finfo; - file_buffer->filesize = filesize; - file_buffer->contents = contents; - if (compressed) - file_buffer->flags |= N_IsCompressed; - - /* If requested, build the tags and nodes for this file buffer. */ - if (get_tags) - build_tags_and_nodes (file_buffer); - - return file_buffer; -} - -/* Grovel FILE_BUFFER->contents finding tags and nodes, and filling in the - various slots. This can also be used to rebuild a tag or node table. */ -void -build_tags_and_nodes (FILE_BUFFER *file_buffer) -{ - SEARCH_BINDING binding; - long position; - - free_file_buffer_tags (file_buffer); - file_buffer->flags &= ~N_HasTagsTable; - - /* See if there is a tags table in this info file. */ - binding.buffer = file_buffer->contents; - binding.start = file_buffer->filesize; - binding.end = binding.start - 1000; - if (binding.end < 0) - binding.end = 0; - binding.flags = S_FoldCase; - - position = search_backward (TAGS_TABLE_END_LABEL, &binding); - - /* If there is a tag table, find the start of it, and grovel over it - extracting tag information. */ - if (position != -1) - while (1) - { - long tags_table_begin, tags_table_end; - - binding.end = position; - binding.start = binding.end - 5 - strlen (TAGS_TABLE_END_LABEL); - if (binding.start < 0) - binding.start = 0; - - position = find_node_separator (&binding); - - /* For this test, (and all others here) failure indicates a bogus - tags table. Grovel the file. */ - if (position == -1) - break; - - /* Remember the end of the tags table. */ - binding.start = position; - tags_table_end = binding.start; - binding.end = 0; - - /* Locate the start of the tags table. */ - position = search_backward (TAGS_TABLE_BEG_LABEL, &binding); - - if (position == -1) - break; - - binding.end = position; - binding.start = binding.end - 5 - strlen (TAGS_TABLE_BEG_LABEL); - position = find_node_separator (&binding); - - if (position == -1) - break; - - /* The file contains a valid tags table. Fill the FILE_BUFFER's - tags member. */ - file_buffer->flags |= N_HasTagsTable; - tags_table_begin = position; - - /* If this isn't an indirect tags table, just remember the nodes - described locally in this tags table. Note that binding.end - is pointing to just after the beginning label. */ - binding.start = binding.end; - binding.end = file_buffer->filesize; - - if (!looking_at (TAGS_TABLE_IS_INDIRECT_LABEL, &binding)) - { - binding.start = tags_table_begin; - binding.end = tags_table_end; - get_nodes_of_tags_table (file_buffer, &binding); - return; - } - else - { - /* This is an indirect tags table. Build TAGS member. */ - SEARCH_BINDING indirect; - - indirect.start = tags_table_begin; - indirect.end = 0; - indirect.buffer = binding.buffer; - indirect.flags = S_FoldCase; - - position = search_backward (INDIRECT_TAGS_TABLE_LABEL, &indirect); - - if (position == -1) - { - /* This file is malformed. Give up. */ - return; - } - - indirect.start = position; - indirect.end = tags_table_begin; - binding.start = tags_table_begin; - binding.end = tags_table_end; - get_tags_of_indirect_tags_table (file_buffer, &indirect, &binding); - return; - } - } - - /* This file doesn't contain any kind of tags table. Grovel the - file and build node entries for it. */ - get_nodes_of_info_file (file_buffer); -} - -/* Search through FILE_BUFFER->contents building an array of TAG *, - one entry per each node present in the file. Store the tags in - FILE_BUFFER->tags, and the number of allocated slots in - FILE_BUFFER->tags_slots. */ -static void -get_nodes_of_info_file (FILE_BUFFER *file_buffer) -{ - long nodestart; - int tags_index = 0; - SEARCH_BINDING binding; - - binding.buffer = file_buffer->contents; - binding.start = 0; - binding.end = file_buffer->filesize; - binding.flags = S_FoldCase; - - while ((nodestart = find_node_separator (&binding)) != -1) - { - int start, end; - char *nodeline; - TAG *entry; - int anchor = 0; - - /* Skip past the characters just found. */ - binding.start = nodestart; - binding.start += skip_node_separator (binding.buffer + binding.start); - - /* Move to the start of the line defining the node. */ - nodeline = binding.buffer + binding.start; - - /* Find "Node:" */ - start = string_in_line (INFO_NODE_LABEL, nodeline); - /* No Node:. Maybe it's a Ref:. */ - if (start == -1) - { - start = string_in_line (INFO_REF_LABEL, nodeline); - if (start != -1) - anchor = 1; - } - - /* If not there, this is not the start of a node. */ - if (start == -1) - continue; - - /* Find the start of the nodename. */ - start += skip_whitespace (nodeline + start); - - /* Find the end of the nodename. */ - end = start + - skip_node_characters (nodeline + start, DONT_SKIP_NEWLINES); - - /* Okay, we have isolated the node name, and we know where the - node starts. Remember this information. */ - entry = xmalloc (sizeof (TAG)); - entry->nodename = xmalloc (1 + (end - start)); - strncpy (entry->nodename, nodeline + start, end - start); - entry->nodename[end - start] = 0; - entry->nodestart = nodestart; - if (anchor) - entry->nodelen = 0; - else - { - SEARCH_BINDING node_body; - - node_body.buffer = binding.buffer + binding.start; - node_body.start = 0; - node_body.end = binding.end - binding.start; - node_body.flags = S_FoldCase; - entry->nodelen = get_node_length (&node_body); - } - - entry->filename = file_buffer->fullpath; - - /* Add this tag to the array of tag structures in this FILE_BUFFER. */ - add_pointer_to_array (entry, tags_index, file_buffer->tags, - file_buffer->tags_slots, 100, TAG *); - } -} - -/* Return the length of the node which starts at BINDING. */ -static long -get_node_length (SEARCH_BINDING *binding) -{ - int i; - char *body; - - /* [A node] ends with either a ^_, a ^L, or end of file. */ - for (i = binding->start, body = binding->buffer; i < binding->end; i++) - { - if (body[i] == INFO_FF || body[i] == INFO_COOKIE) - break; - } - return i - binding->start; -} - -/* Build and save the array of nodes in FILE_BUFFER by searching through the - contents of BUFFER_BINDING for a tags table, and groveling the contents. */ -static void -get_nodes_of_tags_table (FILE_BUFFER *file_buffer, - SEARCH_BINDING *buffer_binding) -{ - int name_offset; - SEARCH_BINDING *tmp_search; - long position; - int tags_index = 0; - - tmp_search = copy_binding (buffer_binding); - - /* Find the start of the tags table. */ - position = find_tags_table (tmp_search); - - /* If none, we're all done. */ - if (position == -1) - return; - - /* Move to one character before the start of the actual table. */ - tmp_search->start = position; - tmp_search->start += skip_node_separator - (tmp_search->buffer + tmp_search->start); - tmp_search->start += strlen (TAGS_TABLE_BEG_LABEL); - tmp_search->start--; - - /* The tag table consists of lines containing node names and positions. - Do each line until we find one that doesn't contain a node name. */ - while ((position = search_forward ("\n", tmp_search)) != -1) - { - TAG *entry; - char *nodedef; - unsigned p; - int anchor = 0; - - /* Prepare to skip this line. */ - tmp_search->start = position; - tmp_search->start++; - - /* Skip past informative "(Indirect)" tags table line. */ - if (!tags_index && looking_at (TAGS_TABLE_IS_INDIRECT_LABEL, tmp_search)) - continue; - - /* Find the label preceding the node name. */ - name_offset = - string_in_line (INFO_NODE_LABEL, tmp_search->buffer + tmp_search->start); - - /* If no node label, maybe it's an anchor. */ - if (name_offset == -1) - { - name_offset = string_in_line (INFO_REF_LABEL, - tmp_search->buffer + tmp_search->start); - if (name_offset != -1) - anchor = 1; - } - - /* If not there, not a defining line, so we must be out of the - tags table. */ - if (name_offset == -1) - break; - - entry = xmalloc (sizeof (TAG)); - - /* Find the beginning of the node definition. */ - tmp_search->start += name_offset; - nodedef = tmp_search->buffer + tmp_search->start; - nodedef += skip_whitespace (nodedef); - - /* Move past the node's name in this tag to the TAGSEP character. */ - for (p = 0; nodedef[p] && nodedef[p] != INFO_TAGSEP; p++) - ; - if (nodedef[p] != INFO_TAGSEP) - continue; - - entry->nodename = xmalloc (p + 1); - strncpy (entry->nodename, nodedef, p); - entry->nodename[p] = 0; - p++; - entry->nodestart = atol (nodedef + p); - - /* If a node, we don't know the length yet, but if it's an - anchor, the length is 0. */ - entry->nodelen = anchor ? 0 : -1; - - /* The filename of this node is currently known as the same as the - name of this file. */ - entry->filename = file_buffer->fullpath; - - /* Add this node structure to the array of node structures in this - FILE_BUFFER. */ - add_pointer_to_array (entry, tags_index, file_buffer->tags, - file_buffer->tags_slots, 100, TAG *); - } - free (tmp_search); -} - -/* A structure used only in `get_tags_of_indirect_tags_table' to hold onto - an intermediate value. */ -typedef struct { - char *filename; - long first_byte; -} SUBFILE; - -/* Remember in FILE_BUFFER the nodenames, subfilenames, and offsets within the - subfiles of every node which appears in TAGS_BINDING. The 2nd argument is - a binding surrounding the indirect files list. */ -static void -get_tags_of_indirect_tags_table (FILE_BUFFER *file_buffer, - SEARCH_BINDING *indirect_binding, SEARCH_BINDING *tags_binding) -{ - int i; - SUBFILE **subfiles = NULL; - int subfiles_index = 0, subfiles_slots = 0; - TAG *entry; - - /* First get the list of tags from the tags table. Then lookup the - associated file in the indirect list for each tag, and update it. */ - get_nodes_of_tags_table (file_buffer, tags_binding); - - /* We have the list of tags in file_buffer->tags. Get the list of - subfiles from the indirect table. */ - { - char *start, *end, *line; - SUBFILE *subfile; - - start = indirect_binding->buffer + indirect_binding->start; - end = indirect_binding->buffer + indirect_binding->end; - line = start; - - while (line < end) - { - int colon; - - colon = string_in_line (":", line); - - if (colon == -1) - break; - - subfile = (SUBFILE *)xmalloc (sizeof (SUBFILE)); - subfile->filename = (char *)xmalloc (colon); - strncpy (subfile->filename, line, colon - 1); - subfile->filename[colon - 1] = 0; - subfile->first_byte = (long) atol (line + colon); - - add_pointer_to_array - (subfile, subfiles_index, subfiles, subfiles_slots, 10, SUBFILE *); - - while (*line++ != '\n'); - } - } - - /* If we have successfully built the indirect files table, then - merge the information in the two tables. */ - if (!subfiles) - { - free_file_buffer_tags (file_buffer); - return; - } - else - { - int tags_index; - long header_length; - SEARCH_BINDING binding; - - /* Find the length of the header of the file containing the indirect - tags table. This header appears at the start of every file. We - want the absolute position of each node within each subfile, so - we subtract the start of the containing subfile from the logical - position of the node, and then add the length of the header in. */ - binding.buffer = file_buffer->contents; - binding.start = 0; - binding.end = file_buffer->filesize; - binding.flags = S_FoldCase; - - header_length = find_node_separator (&binding); - if (header_length == -1) - header_length = 0; - - /* Build the file buffer's list of subfiles. */ - { - char *containing_dir = xstrdup (file_buffer->fullpath); - char *temp = filename_non_directory (containing_dir); - int len_containing_dir; - - if (temp > containing_dir) - { - if (HAVE_DRIVE (file_buffer->fullpath) && - temp == containing_dir + 2) - { - /* Avoid converting "d:foo" into "d:/foo" below. */ - *temp = '.'; - temp += 2; - } - temp[-1] = 0; - } - - len_containing_dir = strlen (containing_dir); - - for (i = 0; subfiles[i]; i++); - - file_buffer->subfiles = (char **) xmalloc ((1 + i) * sizeof (char *)); - - for (i = 0; subfiles[i]; i++) - { - char *fullpath; - - fullpath = (char *) xmalloc - (2 + strlen (subfiles[i]->filename) + len_containing_dir); - - sprintf (fullpath, "%s/%s", - containing_dir, subfiles[i]->filename); - - file_buffer->subfiles[i] = fullpath; - } - file_buffer->subfiles[i] = NULL; - free (containing_dir); - } - - /* For each node in the file's tags table, remember the starting - position. */ - for (tags_index = 0; (entry = file_buffer->tags[tags_index]); - tags_index++) - { - for (i = 0; - subfiles[i] && entry->nodestart >= subfiles[i]->first_byte; - i++); - - /* If the Info file containing the indirect tags table is - malformed, then give up. */ - if (!i) - { - /* The Info file containing the indirect tags table is - malformed. Give up. */ - for (i = 0; subfiles[i]; i++) - { - free (subfiles[i]->filename); - free (subfiles[i]); - free (file_buffer->subfiles[i]); - } - file_buffer->subfiles = NULL; - free_file_buffer_tags (file_buffer); - return; - } - - /* SUBFILES[i] is the index of the first subfile whose logical - first byte is greater than the logical offset of this node's - starting position. This means that the subfile directly - preceding this one is the one containing the node. */ - - entry->filename = file_buffer->subfiles[i - 1]; - entry->nodestart -= subfiles[i - 1]->first_byte; - entry->nodestart += header_length; - } - - /* We have successfully built the tags table. Remember that it - was indirect. */ - file_buffer->flags |= N_TagsIndirect; - } - - /* Free the structures assigned to SUBFILES. Free the names as well - as the structures themselves, then finally, the array. */ - for (i = 0; subfiles[i]; i++) - { - free (subfiles[i]->filename); - free (subfiles[i]); - } - free (subfiles); -} - - -/* Return the node that contains TAG in FILE_BUFFER, else - (pathologically) NULL. Called from info_node_of_file_buffer_tags. */ -static NODE * -find_node_of_anchor (FILE_BUFFER *file_buffer, TAG *tag) -{ - int anchor_pos, node_pos; - TAG *node_tag; - NODE *node; - - /* Look through the tag list for the anchor. */ - for (anchor_pos = 0; file_buffer->tags[anchor_pos]; anchor_pos++) - { - TAG *t = file_buffer->tags[anchor_pos]; - if (t->nodestart == tag->nodestart) - break; - } - - /* Should not happen, because we should always find the anchor. */ - if (!file_buffer->tags[anchor_pos]) - return NULL; - - /* We've found the anchor. Look backwards in the tag table for the - preceding node (we're assuming the tags are given in order), - skipping over any preceding anchors. */ - for (node_pos = anchor_pos - 1; - node_pos >= 0 && file_buffer->tags[node_pos]->nodelen == 0; - node_pos--) - ; - - /* An info file with an anchor before any nodes is pathological, but - it's possible, so don't crash. */ - if (node_pos < 0) - return NULL; - - /* We have the tag for the node that contained the anchor tag. */ - node_tag = file_buffer->tags[node_pos]; - - /* Look up the node name in the tag table to get the actual node. - This is a recursive call, but it can't recurse again, because we - call it with a real node. */ - node = info_node_of_file_buffer_tags (file_buffer, node_tag->nodename); - - /* Start displaying the node at the anchor position. */ - if (node) - { /* The nodestart for real nodes is three characters before the `F' - in the `File:' line (a newline, the CTRL-_, and another - newline). The nodestart for anchors is the actual position. - But we offset by only 2, rather than 3, because if an anchor is - at the beginning of a paragraph, it's nicer for it to end up on - the beginning of the first line of the paragraph rather than - the blank line before it. (makeinfo has no way of knowing that - a paragraph is going to start, so we can't fix it there.) */ - node->display_pos = file_buffer->tags[anchor_pos]->nodestart - - (node_tag->nodestart + 2); - - /* Otherwise an anchor at the end of a node ends up displaying at - the end of the last line of the node (way over on the right of - the screen), which looks wrong. */ - if (node->display_pos >= (unsigned long) node->nodelen) - node->display_pos = node->nodelen - 1; - - /* Don't search in the node for the xref text, it's not there. */ - node->flags |= N_FromAnchor; - } - - return node; -} - - -/* Return the node from FILE_BUFFER which matches NODENAME by searching - the tags table in FILE_BUFFER, or NULL. */ -static NODE * -info_node_of_file_buffer_tags (FILE_BUFFER *file_buffer, char *nodename) -{ - TAG *tag; - int i; - - /* If no tags at all (possibly a misformatted info file), quit. */ - if (!file_buffer->tags) { - return NULL; - } - - for (i = 0; (tag = file_buffer->tags[i]); i++) - if (strcmp (nodename, tag->nodename) == 0) - { - FILE_BUFFER *subfile = info_find_file_internal (tag->filename, - INFO_NO_TAGS); - if (!subfile) - return NULL; - - if (!subfile->contents) - { - info_reload_file_buffer_contents (subfile); - if (!subfile->contents) - return NULL; - } - - /* If we were able to find this file and load it, then return - the node within it. */ - { - NODE *node = xmalloc (sizeof (NODE)); - node->filename = subfile->fullpath; - node->parent = NULL; - node->nodename = tag->nodename; - node->contents = subfile->contents + tag->nodestart; - node->display_pos = 0; - node->flags = 0; - - if (file_buffer->flags & N_HasTagsTable) - { - node->flags |= N_HasTagsTable; - - if (file_buffer->flags & N_TagsIndirect) - { - node->flags |= N_TagsIndirect; - node->parent = file_buffer->fullpath; - } - } - - if (subfile->flags & N_IsCompressed) - node->flags |= N_IsCompressed; - - /* If TAG->nodelen hasn't been calculated yet, then we aren't - in a position to trust the entry pointer. Adjust things so - that ENTRY->nodestart gets the exact address of the start of - the node separator which starts this node, and NODE->contents - gets the address of the line defining this node. If we cannot - do that, the node isn't really here. */ - if (tag->nodelen == -1) - { - int min, max; - char *node_sep; - SEARCH_BINDING node_body; - char *buff_end; - - min = max = DEFAULT_INFO_FUDGE; - - if (tag->nodestart < DEFAULT_INFO_FUDGE) - min = tag->nodestart; - - if (DEFAULT_INFO_FUDGE > - (subfile->filesize - tag->nodestart)) - max = subfile->filesize - tag->nodestart; - - /* NODE_SEP gets the address of the separator which defines - this node, or NULL if the node wasn't found. - NODE->contents is side-effected to point to right after - the separator. */ - node_sep = adjust_nodestart (node, min, max); - if (node_sep == NULL) - { - free (node); - return NULL; - } - /* Readjust tag->nodestart. */ - tag->nodestart = node_sep - subfile->contents; - - /* Calculate the length of the current node. */ - buff_end = subfile->contents + subfile->filesize; - - node_body.buffer = node->contents; - node_body.start = 0; - node_body.end = buff_end - node_body.buffer; - node_body.flags = 0; - tag->nodelen = get_node_length (&node_body); - node->nodelen = tag->nodelen; - } - - else if (tag->nodelen == 0) /* anchor, return containing node */ - { - free (node); - node = find_node_of_anchor (file_buffer, tag); - } - - else - { - /* Since we know the length of this node, we have already - adjusted tag->nodestart to point to the exact start of - it. Simply skip the node separator. */ - node->contents += skip_node_separator (node->contents); - node->nodelen = tag->nodelen; - } - - return node; - } - } - - /* There was a tag table for this file, and the node wasn't found. - Return NULL, since this file doesn't contain the desired node. */ - return NULL; -} - -/* Managing file_buffers, nodes, and tags. */ - -/* Create a new, empty file buffer. */ -FILE_BUFFER * -make_file_buffer (void) -{ - FILE_BUFFER *file_buffer = xmalloc (sizeof (FILE_BUFFER)); - - file_buffer->filename = file_buffer->fullpath = NULL; - file_buffer->contents = NULL; - file_buffer->tags = NULL; - file_buffer->subfiles = NULL; - file_buffer->tags_slots = 0; - file_buffer->flags = 0; - - return file_buffer; -} - -/* Add FILE_BUFFER to our list of already loaded info files. */ -static void -remember_info_file (FILE_BUFFER *file_buffer) -{ - int i; - - for (i = 0; info_loaded_files && info_loaded_files[i]; i++) - ; - - add_pointer_to_array (file_buffer, i, info_loaded_files, - info_loaded_files_slots, 10, FILE_BUFFER *); -} - -/* Forget the contents, tags table, nodes list, and names of FILENAME. */ -static void -forget_info_file (char *filename) -{ - int i; - FILE_BUFFER *file_buffer; - - if (!info_loaded_files) - return; - - for (i = 0; (file_buffer = info_loaded_files[i]); i++) - if (FILENAME_CMP (filename, file_buffer->filename) == 0 - || FILENAME_CMP (filename, file_buffer->fullpath) == 0) - { - free (file_buffer->filename); - free (file_buffer->fullpath); - - if (file_buffer->contents) - free (file_buffer->contents); - - /* free_file_buffer_tags () also kills the subfiles list, since - the subfiles list is only of use in conjunction with tags. */ - free_file_buffer_tags (file_buffer); - - /* Move rest of list down. */ - while (info_loaded_files[i + 1]) - { - info_loaded_files[i] = info_loaded_files[i + 1]; - i++; - } - info_loaded_files[i] = 0; - - break; - } -} - -/* Free the tags (if any) associated with FILE_BUFFER. */ -static void -free_file_buffer_tags (FILE_BUFFER *file_buffer) -{ - int i; - - if (file_buffer->tags) - { - TAG *tag; - - for (i = 0; (tag = file_buffer->tags[i]); i++) - free_info_tag (tag); - - free (file_buffer->tags); - file_buffer->tags = NULL; - file_buffer->tags_slots = 0; - } - - if (file_buffer->subfiles) - { - for (i = 0; file_buffer->subfiles[i]; i++) - free (file_buffer->subfiles[i]); - - free (file_buffer->subfiles); - file_buffer->subfiles = NULL; - } -} - -/* Free the data associated with TAG, as well as TAG itself. */ -static void -free_info_tag (TAG *tag) -{ - free (tag->nodename); - - /* We don't free tag->filename, because that filename is part of the - subfiles list for the containing FILE_BUFFER. free_info_tags () - will free the subfiles when it is appropriate. */ - - free (tag); -} - -/* Load the contents of FILE_BUFFER->contents. This function is called - when a file buffer was loaded, and then in order to conserve memory, the - file buffer's contents were freed and the pointer was zero'ed. Note that - the file was already loaded at least once successfully, so the tags and/or - nodes members are still correctly filled. */ -static void -info_reload_file_buffer_contents (FILE_BUFFER *fb) -{ - int is_compressed; - -#if defined (HANDLE_MAN_PAGES) - /* If this is the magic manpage node, don't try to reload, just give up. */ - if (fb->flags & N_IsManPage) - return; -#endif - - fb->flags &= ~N_IsCompressed; - - /* Let the filesystem do all the work for us. */ - fb->contents = - filesys_read_info_file (fb->fullpath, &(fb->filesize), &(fb->finfo), - &is_compressed); - if (is_compressed) - fb->flags |= N_IsCompressed; -} - -/* Return the actual starting memory location of NODE, side-effecting - NODE->contents. MIN and MAX are bounds for a search if one is necessary. - Because of the way that tags are implemented, the physical nodestart may - not actually be where the tag says it is. If that is the case, but the - node was found anyway, set N_UpdateTags in NODE->flags. If the node is - found, return non-zero. NODE->contents is returned positioned right after - the node separator that precedes this node, while the return value is - position directly on the separator that precedes this node. If the node - could not be found, return a NULL pointer. */ -static char * -adjust_nodestart (NODE *node, int min, int max) -{ - long position; - SEARCH_BINDING node_body; - - /* Define the node body. */ - node_body.buffer = node->contents; - node_body.start = 0; - node_body.end = max; - node_body.flags = 0; - - /* Try the optimal case first. Who knows? This file may actually be - formatted (mostly) correctly. */ - if (node_body.buffer[0] != INFO_COOKIE && min > 2) - node_body.buffer -= 3; - - position = find_node_separator (&node_body); - - /* If we found a node start, then check it out. */ - if (position != -1) - { - int sep_len; - - sep_len = skip_node_separator (node->contents); - - /* If we managed to skip a node separator, then check for this node - being the right one. */ - if (sep_len != 0) - { - char *nodedef, *nodestart; - int offset; - - nodestart = node_body.buffer + position + sep_len; - nodedef = nodestart; - offset = string_in_line (INFO_NODE_LABEL, nodedef); - - if (offset != -1) - { - nodedef += offset; - nodedef += skip_whitespace (nodedef); - offset = skip_node_characters (nodedef, DONT_SKIP_NEWLINES); - if (((unsigned int) offset == strlen (node->nodename)) && - (strncmp (node->nodename, nodedef, offset) == 0)) - { - node->contents = nodestart; - return node_body.buffer + position; - } - } - } - } - - /* Oh well, I guess we have to try to find it in a larger area. */ - node_body.buffer = node->contents - min; - node_body.start = 0; - node_body.end = min + max; - node_body.flags = 0; - - position = find_node_in_binding (node->nodename, &node_body); - - /* If the node couldn't be found, we lose big. */ - if (position == -1) - return NULL; - - /* Otherwise, the node was found, but the tags table could need updating - (if we used a tag to get here, that is). Set the flag in NODE->flags. */ - node->contents = node_body.buffer + position; - node->contents += skip_node_separator (node->contents); - if (node->flags & N_HasTagsTable) - node->flags |= N_UpdateTags; - return node_body.buffer + position; -} |