1 /* nodes.c -- how to get an Info file and node.
2 $Id: nodes.c,v 1.11 2008/06/11 09:55:42 gray Exp $
4 Copyright (C) 1993, 1998, 1999, 2000, 2002, 2003, 2004, 2006, 2007,
5 2008 Free Software Foundation, Inc.
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 Originally written by Brian Fox (bfox@ai.mit.edu). */
27 #include "info-utils.h"
29 #if defined (HANDLE_MAN_PAGES)
31 #endif /* HANDLE_MAN_PAGES */
33 static void forget_info_file (char *filename);
34 static void remember_info_file (FILE_BUFFER *file_buffer);
35 static void free_file_buffer_tags (FILE_BUFFER *file_buffer);
36 static void free_info_tag (TAG *tag);
37 static void get_nodes_of_tags_table (FILE_BUFFER *file_buffer,
38 SEARCH_BINDING *buffer_binding);
39 static void get_nodes_of_info_file (FILE_BUFFER *file_buffer);
40 static void get_tags_of_indirect_tags_table (FILE_BUFFER *file_buffer,
41 SEARCH_BINDING *indirect_binding, SEARCH_BINDING *tags_binding);
42 static void info_reload_file_buffer_contents (FILE_BUFFER *fb);
43 static char *adjust_nodestart (NODE *node, int min, int max);
44 static FILE_BUFFER *info_load_file_internal (char *filename, int get_tags);
45 static FILE_BUFFER *info_find_file_internal (char *filename, int get_tags);
46 static NODE *info_node_of_file_buffer_tags (FILE_BUFFER *file_buffer,
49 static long get_node_length (SEARCH_BINDING *binding);
51 /* Magic number that RMS used to decide how much a tags table pointer could
52 be off by. I feel that it should be much smaller, like 4. */
53 #define DEFAULT_INFO_FUDGE 1000
55 /* Passed to *_internal functions. INFO_GET_TAGS says to do what is
56 neccessary to fill in the nodes or tags arrays in FILE_BUFFER. */
57 #define INFO_NO_TAGS 0
58 #define INFO_GET_TAGS 1
60 /* Global variables. */
62 /* When non-zero, this is a string describing the recent file error. */
63 char *info_recent_file_error = NULL;
65 /* The list of already loaded nodes. */
66 FILE_BUFFER **info_loaded_files = NULL;
68 /* The number of slots currently allocated to LOADED_FILES. */
69 int info_loaded_files_slots = 0;
71 /* Public functions for node manipulation. */
73 /* Used to build `dir' menu from `localdir' files found in INFOPATH. */
74 extern void maybe_build_dir_node (char *dirname);
76 /* Return a pointer to a NODE structure for the Info node (FILENAME)NODENAME.
77 If FILENAME is NULL, `dir' is used.
78 IF NODENAME is NULL, `Top' is used.
79 If the node cannot be found, return NULL. */
81 info_get_node (char *filename, char *nodename)
84 FILE_BUFFER *file_buffer = NULL;
86 info_recent_file_error = NULL;
87 info_parse_node (nodename, DONT_SKIP_NEWLINES);
90 if (info_parsed_filename)
91 filename = info_parsed_filename;
93 if (info_parsed_nodename)
94 nodename = info_parsed_nodename;
96 /* If FILENAME is not specified, it defaults to "dir". */
100 /* If the file to be looked up is "dir", build the contents from all of
101 the "dir"s and "localdir"s found in INFOPATH. */
102 if (is_dir_name (filename))
103 maybe_build_dir_node (filename);
105 /* Find the correct info file, or give up. */
106 file_buffer = info_find_file (filename);
109 if (filesys_error_number)
110 info_recent_file_error =
111 filesys_error_string (filename, filesys_error_number);
115 /* Look for the node. */
116 node = info_get_node_of_file_buffer (nodename, file_buffer);
118 /* If the node not found was "Top", try again with different case,
119 unless this was a man page. */
121 && mbscasecmp (filename, MANPAGE_FILE_BUFFER_NAME) != 0
122 && (nodename == NULL || mbscasecmp (nodename, "Top") == 0))
124 node = info_get_node_of_file_buffer ("Top", file_buffer);
126 node = info_get_node_of_file_buffer ("top", file_buffer);
128 node = info_get_node_of_file_buffer ("TOP", file_buffer);
134 /* Return a pointer to a NODE structure for the Info node NODENAME in
135 FILE_BUFFER. NODENAME can be passed as NULL, in which case the
136 nodename of "Top" is used. If the node cannot be found, return a
139 info_get_node_of_file_buffer (char *nodename, FILE_BUFFER *file_buffer)
142 int implicit_nodename = 0;
144 /* If we are unable to find the file, we have to give up. There isn't
145 anything else we can do. */
149 /* If the file buffer was gc'ed, reload the contents now. */
150 if (!file_buffer->contents)
151 info_reload_file_buffer_contents (file_buffer);
153 /* If NODENAME is not specified, it defaults to "Top". */
157 implicit_nodename = 1; /* don't return man page for top */
160 /* If the name of the node that we wish to find is exactly "*", then the
161 node body is the contents of the entire file. Create and return such
163 if (strcmp (nodename, "*") == 0)
165 node = xmalloc (sizeof (NODE));
166 node->filename = file_buffer->fullpath;
168 node->nodename = xstrdup ("*");
169 node->contents = file_buffer->contents;
170 node->nodelen = file_buffer->filesize;
172 node->display_pos = 0;
174 #if defined (HANDLE_MAN_PAGES)
175 /* If the file buffer is the magic one associated with manpages, call
176 the manpage node finding function instead. */
177 else if (!implicit_nodename && file_buffer->flags & N_IsManPage)
179 node = get_manpage_node (file_buffer, nodename);
181 #endif /* HANDLE_MAN_PAGES */
182 /* If this is the "main" info file, it might contain a tags table. Search
183 the tags table for an entry which matches the node that we want. If
184 there is a tags table, get the file which contains this node, but don't
185 bother building a node list for it. */
186 else if (file_buffer->tags)
188 node = info_node_of_file_buffer_tags (file_buffer, nodename);
191 /* Return the results of our node search. */
195 /* Locate the file named by FILENAME, and return the information structure
196 describing this file. The file may appear in our list of loaded files
197 already, or it may not. If it does not already appear, find the file,
198 and add it to the list of loaded files. If the file cannot be found,
199 return a NULL FILE_BUFFER *. */
201 info_find_file (char *filename)
203 return info_find_file_internal (filename, INFO_GET_TAGS);
206 /* Load the info file FILENAME, remembering information about it in a
209 info_load_file (char *filename)
211 return info_load_file_internal (filename, INFO_GET_TAGS);
215 /* Private functions implementation. */
217 /* The workhorse for info_find_file (). Non-zero 2nd argument says to
218 try to build a tags table (or otherwise glean the nodes) for this
219 file once found. By default, we build the tags table, but when this
220 function is called by info_get_node () when we already have a valid
221 tags table describing the nodes, it is unnecessary. */
223 info_find_file_internal (char *filename, int get_tags)
226 FILE_BUFFER *file_buffer;
228 /* First try to find the file in our list of already loaded files. */
229 if (info_loaded_files)
231 for (i = 0; (file_buffer = info_loaded_files[i]); i++)
232 if ((FILENAME_CMP (filename, file_buffer->filename) == 0)
233 || (FILENAME_CMP (filename, file_buffer->fullpath) == 0)
234 || (!IS_ABSOLUTE (filename)
235 && FILENAME_CMP (filename,
236 filename_non_directory (file_buffer->fullpath))
239 struct stat new_info, *old_info;
241 /* This file is loaded. If the filename that we want is
242 specifically "dir", then simply return the file buffer. */
243 if (is_dir_name (filename_non_directory (filename)))
246 #if defined (HANDLE_MAN_PAGES)
247 /* Do the same for the magic MANPAGE file. */
248 if (file_buffer->flags & N_IsManPage)
250 #endif /* HANDLE_MAN_PAGES */
252 /* The file appears to be already loaded, and is not "dir". Check
253 to see if it's changed since the last time it was loaded. */
254 if (stat (file_buffer->fullpath, &new_info) == -1)
256 filesys_error_number = errno;
260 old_info = &file_buffer->finfo;
262 if (new_info.st_size != old_info->st_size
263 || new_info.st_mtime != old_info->st_mtime)
265 /* The file has changed. Forget that we ever had loaded it
266 in the first place. */
267 forget_info_file (filename);
272 /* The info file exists, and has not changed since the last
273 time it was loaded. If the caller requested a nodes list
274 for this file, and there isn't one here, build the nodes
275 for this file_buffer. In any case, return the file_buffer
277 if (!file_buffer->contents)
279 /* The file's contents have been gc'ed. Reload it. */
280 info_reload_file_buffer_contents (file_buffer);
281 if (!file_buffer->contents)
285 if (get_tags && !file_buffer->tags)
286 build_tags_and_nodes (file_buffer);
293 /* The file wasn't loaded. Try to load it now. */
294 #if defined (HANDLE_MAN_PAGES)
295 /* If the name of the file that we want is our special file buffer for
296 Unix manual pages, then create the file buffer, and return it now. */
297 if (mbscasecmp (filename, MANPAGE_FILE_BUFFER_NAME) == 0)
298 file_buffer = create_manpage_file_buffer ();
300 #endif /* HANDLE_MAN_PAGES */
301 file_buffer = info_load_file_internal (filename, get_tags);
303 /* If the file was loaded, remember the name under which it was found. */
305 remember_info_file (file_buffer);
310 /* The workhorse function for info_load_file (). Non-zero second argument
311 says to build a list of tags (or nodes) for this file. This is the
312 default behaviour when info_load_file () is called, but it is not
313 necessary when loading a subfile for which we already have tags. */
315 info_load_file_internal (char *filename, int get_tags)
317 char *fullpath, *contents;
320 int retcode, compressed;
321 FILE_BUFFER *file_buffer = NULL;
323 /* Get the full pathname of this file, as known by the info system.
324 That is to say, search along INFOPATH and expand tildes, etc. */
325 fullpath = info_find_fullpath (filename);
327 /* Did we actually find the file? */
328 retcode = stat (fullpath, &finfo);
330 /* If the file referenced by the name returned from info_find_fullpath ()
331 doesn't exist, then try again with the last part of the filename
332 appearing in lowercase. */
333 /* This is probably not needed at all on those systems which define
334 FILENAME_CMP to be mbscasecmp. But let's do it anyway, lest some
335 network redirector supports case sensitivity. */
341 lowered_name = xstrdup (filename);
342 tmp_basename = filename_non_directory (lowered_name);
344 while (*tmp_basename)
346 if (isupper (*tmp_basename))
347 *tmp_basename = tolower (*tmp_basename);
352 fullpath = info_find_fullpath (lowered_name);
354 retcode = stat (fullpath, &finfo);
358 /* If the file wasn't found, give up, returning a NULL pointer. */
361 filesys_error_number = errno;
365 /* Otherwise, try to load the file. */
366 contents = filesys_read_info_file (fullpath, &filesize, &finfo, &compressed);
371 /* The file was found, and can be read. Allocate FILE_BUFFER and fill
372 in the various members. */
373 file_buffer = make_file_buffer ();
374 file_buffer->filename = xstrdup (filename);
375 file_buffer->fullpath = xstrdup (fullpath);
376 file_buffer->finfo = finfo;
377 file_buffer->filesize = filesize;
378 file_buffer->contents = contents;
380 file_buffer->flags |= N_IsCompressed;
382 /* If requested, build the tags and nodes for this file buffer. */
384 build_tags_and_nodes (file_buffer);
389 /* Grovel FILE_BUFFER->contents finding tags and nodes, and filling in the
390 various slots. This can also be used to rebuild a tag or node table. */
392 build_tags_and_nodes (FILE_BUFFER *file_buffer)
394 SEARCH_BINDING binding;
397 free_file_buffer_tags (file_buffer);
398 file_buffer->flags &= ~N_HasTagsTable;
400 /* See if there is a tags table in this info file. */
401 binding.buffer = file_buffer->contents;
402 binding.start = file_buffer->filesize;
403 binding.end = binding.start - 1000;
406 binding.flags = S_FoldCase;
408 position = search_backward (TAGS_TABLE_END_LABEL, &binding);
410 /* If there is a tag table, find the start of it, and grovel over it
411 extracting tag information. */
415 long tags_table_begin, tags_table_end;
417 binding.end = position;
418 binding.start = binding.end - 5 - strlen (TAGS_TABLE_END_LABEL);
419 if (binding.start < 0)
422 position = find_node_separator (&binding);
424 /* For this test, (and all others here) failure indicates a bogus
425 tags table. Grovel the file. */
429 /* Remember the end of the tags table. */
430 binding.start = position;
431 tags_table_end = binding.start;
434 /* Locate the start of the tags table. */
435 position = search_backward (TAGS_TABLE_BEG_LABEL, &binding);
440 binding.end = position;
441 binding.start = binding.end - 5 - strlen (TAGS_TABLE_BEG_LABEL);
442 position = find_node_separator (&binding);
447 /* The file contains a valid tags table. Fill the FILE_BUFFER's
449 file_buffer->flags |= N_HasTagsTable;
450 tags_table_begin = position;
452 /* If this isn't an indirect tags table, just remember the nodes
453 described locally in this tags table. Note that binding.end
454 is pointing to just after the beginning label. */
455 binding.start = binding.end;
456 binding.end = file_buffer->filesize;
458 if (!looking_at (TAGS_TABLE_IS_INDIRECT_LABEL, &binding))
460 binding.start = tags_table_begin;
461 binding.end = tags_table_end;
462 get_nodes_of_tags_table (file_buffer, &binding);
467 /* This is an indirect tags table. Build TAGS member. */
468 SEARCH_BINDING indirect;
470 indirect.start = tags_table_begin;
472 indirect.buffer = binding.buffer;
473 indirect.flags = S_FoldCase;
475 position = search_backward (INDIRECT_TAGS_TABLE_LABEL, &indirect);
479 /* This file is malformed. Give up. */
483 indirect.start = position;
484 indirect.end = tags_table_begin;
485 binding.start = tags_table_begin;
486 binding.end = tags_table_end;
487 get_tags_of_indirect_tags_table (file_buffer, &indirect, &binding);
492 /* This file doesn't contain any kind of tags table. Grovel the
493 file and build node entries for it. */
494 get_nodes_of_info_file (file_buffer);
497 /* Search through FILE_BUFFER->contents building an array of TAG *,
498 one entry per each node present in the file. Store the tags in
499 FILE_BUFFER->tags, and the number of allocated slots in
500 FILE_BUFFER->tags_slots. */
502 get_nodes_of_info_file (FILE_BUFFER *file_buffer)
506 SEARCH_BINDING binding;
508 binding.buffer = file_buffer->contents;
510 binding.end = file_buffer->filesize;
511 binding.flags = S_FoldCase;
513 while ((nodestart = find_node_separator (&binding)) != -1)
520 /* Skip past the characters just found. */
521 binding.start = nodestart;
522 binding.start += skip_node_separator (binding.buffer + binding.start);
524 /* Move to the start of the line defining the node. */
525 nodeline = binding.buffer + binding.start;
528 start = string_in_line (INFO_NODE_LABEL, nodeline);
529 /* No Node:. Maybe it's a Ref:. */
532 start = string_in_line (INFO_REF_LABEL, nodeline);
537 /* If not there, this is not the start of a node. */
541 /* Find the start of the nodename. */
542 start += skip_whitespace (nodeline + start);
544 /* Find the end of the nodename. */
546 skip_node_characters (nodeline + start, DONT_SKIP_NEWLINES);
548 /* Okay, we have isolated the node name, and we know where the
549 node starts. Remember this information. */
550 entry = xmalloc (sizeof (TAG));
551 entry->nodename = xmalloc (1 + (end - start));
552 strncpy (entry->nodename, nodeline + start, end - start);
553 entry->nodename[end - start] = 0;
554 entry->nodestart = nodestart;
559 SEARCH_BINDING node_body;
561 node_body.buffer = binding.buffer + binding.start;
563 node_body.end = binding.end - binding.start;
564 node_body.flags = S_FoldCase;
565 entry->nodelen = get_node_length (&node_body);
568 entry->filename = file_buffer->fullpath;
570 /* Add this tag to the array of tag structures in this FILE_BUFFER. */
571 add_pointer_to_array (entry, tags_index, file_buffer->tags,
572 file_buffer->tags_slots, 100, TAG *);
576 /* Return the length of the node which starts at BINDING. */
578 get_node_length (SEARCH_BINDING *binding)
583 /* [A node] ends with either a ^_, a ^L, or end of file. */
584 for (i = binding->start, body = binding->buffer; i < binding->end; i++)
586 if (body[i] == INFO_FF || body[i] == INFO_COOKIE)
589 return i - binding->start;
592 /* Build and save the array of nodes in FILE_BUFFER by searching through the
593 contents of BUFFER_BINDING for a tags table, and groveling the contents. */
595 get_nodes_of_tags_table (FILE_BUFFER *file_buffer,
596 SEARCH_BINDING *buffer_binding)
599 SEARCH_BINDING *tmp_search;
603 tmp_search = copy_binding (buffer_binding);
605 /* Find the start of the tags table. */
606 position = find_tags_table (tmp_search);
608 /* If none, we're all done. */
612 /* Move to one character before the start of the actual table. */
613 tmp_search->start = position;
614 tmp_search->start += skip_node_separator
615 (tmp_search->buffer + tmp_search->start);
616 tmp_search->start += strlen (TAGS_TABLE_BEG_LABEL);
619 /* The tag table consists of lines containing node names and positions.
620 Do each line until we find one that doesn't contain a node name. */
621 while ((position = search_forward ("\n", tmp_search)) != -1)
628 /* Prepare to skip this line. */
629 tmp_search->start = position;
632 /* Skip past informative "(Indirect)" tags table line. */
633 if (!tags_index && looking_at (TAGS_TABLE_IS_INDIRECT_LABEL, tmp_search))
636 /* Find the label preceding the node name. */
638 string_in_line (INFO_NODE_LABEL, tmp_search->buffer + tmp_search->start);
640 /* If no node label, maybe it's an anchor. */
641 if (name_offset == -1)
643 name_offset = string_in_line (INFO_REF_LABEL,
644 tmp_search->buffer + tmp_search->start);
645 if (name_offset != -1)
649 /* If not there, not a defining line, so we must be out of the
651 if (name_offset == -1)
654 entry = xmalloc (sizeof (TAG));
656 /* Find the beginning of the node definition. */
657 tmp_search->start += name_offset;
658 nodedef = tmp_search->buffer + tmp_search->start;
659 nodedef += skip_whitespace (nodedef);
661 /* Move past the node's name in this tag to the TAGSEP character. */
662 for (p = 0; nodedef[p] && nodedef[p] != INFO_TAGSEP; p++)
664 if (nodedef[p] != INFO_TAGSEP)
667 entry->nodename = xmalloc (p + 1);
668 strncpy (entry->nodename, nodedef, p);
669 entry->nodename[p] = 0;
671 entry->nodestart = atol (nodedef + p);
673 /* If a node, we don't know the length yet, but if it's an
674 anchor, the length is 0. */
675 entry->nodelen = anchor ? 0 : -1;
677 /* The filename of this node is currently known as the same as the
678 name of this file. */
679 entry->filename = file_buffer->fullpath;
681 /* Add this node structure to the array of node structures in this
683 add_pointer_to_array (entry, tags_index, file_buffer->tags,
684 file_buffer->tags_slots, 100, TAG *);
689 /* A structure used only in `get_tags_of_indirect_tags_table' to hold onto
690 an intermediate value. */
696 /* Remember in FILE_BUFFER the nodenames, subfilenames, and offsets within the
697 subfiles of every node which appears in TAGS_BINDING. The 2nd argument is
698 a binding surrounding the indirect files list. */
700 get_tags_of_indirect_tags_table (FILE_BUFFER *file_buffer,
701 SEARCH_BINDING *indirect_binding, SEARCH_BINDING *tags_binding)
704 SUBFILE **subfiles = NULL;
705 int subfiles_index = 0, subfiles_slots = 0;
708 /* First get the list of tags from the tags table. Then lookup the
709 associated file in the indirect list for each tag, and update it. */
710 get_nodes_of_tags_table (file_buffer, tags_binding);
712 /* We have the list of tags in file_buffer->tags. Get the list of
713 subfiles from the indirect table. */
715 char *start, *end, *line;
718 start = indirect_binding->buffer + indirect_binding->start;
719 end = indirect_binding->buffer + indirect_binding->end;
726 colon = string_in_line (":", line);
731 subfile = xmalloc (sizeof (SUBFILE));
732 subfile->filename = xmalloc (colon);
733 strncpy (subfile->filename, line, colon - 1);
734 subfile->filename[colon - 1] = 0;
735 subfile->first_byte = (long) atol (line + colon);
738 (subfile, subfiles_index, subfiles, subfiles_slots, 10, SUBFILE *);
740 while (*line++ != '\n');
744 /* If we have successfully built the indirect files table, then
745 merge the information in the two tables. */
748 free_file_buffer_tags (file_buffer);
755 SEARCH_BINDING binding;
757 /* Find the length of the header of the file containing the indirect
758 tags table. This header appears at the start of every file. We
759 want the absolute position of each node within each subfile, so
760 we subtract the start of the containing subfile from the logical
761 position of the node, and then add the length of the header in. */
762 binding.buffer = file_buffer->contents;
764 binding.end = file_buffer->filesize;
765 binding.flags = S_FoldCase;
767 header_length = find_node_separator (&binding);
768 if (header_length == -1)
771 /* Build the file buffer's list of subfiles. */
773 char *containing_dir = xstrdup (file_buffer->fullpath);
774 char *temp = filename_non_directory (containing_dir);
775 int len_containing_dir;
777 if (temp > containing_dir)
779 if (HAVE_DRIVE (file_buffer->fullpath) &&
780 temp == containing_dir + 2)
782 /* Avoid converting "d:foo" into "d:/foo" below. */
789 len_containing_dir = strlen (containing_dir);
791 for (i = 0; subfiles[i]; i++);
793 file_buffer->subfiles = xmalloc ((1 + i) * sizeof (char *));
795 for (i = 0; subfiles[i]; i++)
800 (2 + strlen (subfiles[i]->filename) + len_containing_dir);
802 sprintf (fullpath, "%s/%s",
803 containing_dir, subfiles[i]->filename);
805 file_buffer->subfiles[i] = fullpath;
807 file_buffer->subfiles[i] = NULL;
808 free (containing_dir);
811 /* For each node in the file's tags table, remember the starting
813 for (tags_index = 0; (entry = file_buffer->tags[tags_index]);
817 subfiles[i] && entry->nodestart >= subfiles[i]->first_byte;
820 /* If the Info file containing the indirect tags table is
821 malformed, then give up. */
824 /* The Info file containing the indirect tags table is
825 malformed. Give up. */
826 for (i = 0; subfiles[i]; i++)
828 free (subfiles[i]->filename);
830 free (file_buffer->subfiles[i]);
832 file_buffer->subfiles = NULL;
833 free_file_buffer_tags (file_buffer);
837 /* SUBFILES[i] is the index of the first subfile whose logical
838 first byte is greater than the logical offset of this node's
839 starting position. This means that the subfile directly
840 preceding this one is the one containing the node. */
842 entry->filename = file_buffer->subfiles[i - 1];
843 entry->nodestart -= subfiles[i - 1]->first_byte;
844 entry->nodestart += header_length;
847 /* We have successfully built the tags table. Remember that it
849 file_buffer->flags |= N_TagsIndirect;
852 /* Free the structures assigned to SUBFILES. Free the names as well
853 as the structures themselves, then finally, the array. */
854 for (i = 0; subfiles[i]; i++)
856 free (subfiles[i]->filename);
863 /* Return the node that contains TAG in FILE_BUFFER, else
864 (pathologically) NULL. Called from info_node_of_file_buffer_tags. */
866 find_node_of_anchor (FILE_BUFFER *file_buffer, TAG *tag)
868 int anchor_pos, node_pos;
872 /* Look through the tag list for the anchor. */
873 for (anchor_pos = 0; file_buffer->tags[anchor_pos]; anchor_pos++)
875 TAG *t = file_buffer->tags[anchor_pos];
876 if (t->nodestart == tag->nodestart)
880 /* Should not happen, because we should always find the anchor. */
881 if (!file_buffer->tags[anchor_pos])
884 /* We've found the anchor. Look backwards in the tag table for the
885 preceding node (we're assuming the tags are given in order),
886 skipping over any preceding anchors. */
887 for (node_pos = anchor_pos - 1;
888 node_pos >= 0 && file_buffer->tags[node_pos]->nodelen == 0;
892 /* An info file with an anchor before any nodes is pathological, but
893 it's possible, so don't crash. */
897 /* We have the tag for the node that contained the anchor tag. */
898 node_tag = file_buffer->tags[node_pos];
900 /* Look up the node name in the tag table to get the actual node.
901 This is a recursive call, but it can't recurse again, because we
902 call it with a real node. */
903 node = info_node_of_file_buffer_tags (file_buffer, node_tag->nodename);
905 /* Start displaying the node at the anchor position. */
907 { /* The nodestart for real nodes is three characters before the `F'
908 in the `File:' line (a newline, the CTRL-_, and another
909 newline). The nodestart for anchors is the actual position.
910 But we offset by only 2, rather than 3, because if an anchor is
911 at the beginning of a paragraph, it's nicer for it to end up on
912 the beginning of the first line of the paragraph rather than
913 the blank line before it. (makeinfo has no way of knowing that
914 a paragraph is going to start, so we can't fix it there.) */
915 node->display_pos = file_buffer->tags[anchor_pos]->nodestart
916 - (node_tag->nodestart + 2);
918 /* Otherwise an anchor at the end of a node ends up displaying at
919 the end of the last line of the node (way over on the right of
920 the screen), which looks wrong. */
921 if (node->display_pos >= (unsigned long) node->nodelen)
922 node->display_pos = node->nodelen - 1;
924 /* Don't search in the node for the xref text, it's not there. */
925 node->flags |= N_FromAnchor;
932 /* Return the node from FILE_BUFFER which matches NODENAME by searching
933 the tags table in FILE_BUFFER, or NULL. */
935 info_node_of_file_buffer_tags (FILE_BUFFER *file_buffer, char *nodename)
940 /* If no tags at all (possibly a misformatted info file), quit. */
941 if (!file_buffer->tags) {
945 for (i = 0; (tag = file_buffer->tags[i]); i++)
946 if (strcmp (nodename, tag->nodename) == 0)
948 FILE_BUFFER *subfile = info_find_file_internal (tag->filename,
953 if (!subfile->contents)
955 info_reload_file_buffer_contents (subfile);
956 if (!subfile->contents)
960 /* If we were able to find this file and load it, then return
961 the node within it. */
963 NODE *node = xmalloc (sizeof (NODE));
964 node->filename = subfile->fullpath;
966 node->nodename = tag->nodename;
967 node->contents = subfile->contents + tag->nodestart;
968 node->display_pos = 0;
971 if (file_buffer->flags & N_HasTagsTable)
973 node->flags |= N_HasTagsTable;
975 if (file_buffer->flags & N_TagsIndirect)
977 node->flags |= N_TagsIndirect;
978 node->parent = file_buffer->fullpath;
982 if (subfile->flags & N_IsCompressed)
983 node->flags |= N_IsCompressed;
985 /* If TAG->nodelen hasn't been calculated yet, then we aren't
986 in a position to trust the entry pointer. Adjust things so
987 that ENTRY->nodestart gets the exact address of the start of
988 the node separator which starts this node, and NODE->contents
989 gets the address of the line defining this node. If we cannot
990 do that, the node isn't really here. */
991 if (tag->nodelen == -1)
995 SEARCH_BINDING node_body;
998 min = max = DEFAULT_INFO_FUDGE;
1000 if (tag->nodestart < DEFAULT_INFO_FUDGE)
1001 min = tag->nodestart;
1003 if (DEFAULT_INFO_FUDGE >
1004 (subfile->filesize - tag->nodestart))
1005 max = subfile->filesize - tag->nodestart;
1007 /* NODE_SEP gets the address of the separator which defines
1008 this node, or NULL if the node wasn't found.
1009 NODE->contents is side-effected to point to right after
1011 node_sep = adjust_nodestart (node, min, max);
1012 if (node_sep == NULL)
1017 /* Readjust tag->nodestart. */
1018 tag->nodestart = node_sep - subfile->contents;
1020 /* Calculate the length of the current node. */
1021 buff_end = subfile->contents + subfile->filesize;
1023 node_body.buffer = node->contents;
1024 node_body.start = 0;
1025 node_body.end = buff_end - node_body.buffer;
1026 node_body.flags = 0;
1027 tag->nodelen = get_node_length (&node_body);
1028 node->nodelen = tag->nodelen;
1031 else if (tag->nodelen == 0) /* anchor, return containing node */
1034 node = find_node_of_anchor (file_buffer, tag);
1039 /* Since we know the length of this node, we have already
1040 adjusted tag->nodestart to point to the exact start of
1041 it. Simply skip the node separator. */
1042 node->contents += skip_node_separator (node->contents);
1043 node->nodelen = tag->nodelen;
1050 /* There was a tag table for this file, and the node wasn't found.
1051 Return NULL, since this file doesn't contain the desired node. */
1055 /* Managing file_buffers, nodes, and tags. */
1057 /* Create a new, empty file buffer. */
1059 make_file_buffer (void)
1061 FILE_BUFFER *file_buffer = xmalloc (sizeof (FILE_BUFFER));
1063 file_buffer->filename = file_buffer->fullpath = NULL;
1064 file_buffer->contents = NULL;
1065 file_buffer->tags = NULL;
1066 file_buffer->subfiles = NULL;
1067 file_buffer->tags_slots = 0;
1068 file_buffer->flags = 0;
1073 /* Add FILE_BUFFER to our list of already loaded info files. */
1075 remember_info_file (FILE_BUFFER *file_buffer)
1079 for (i = 0; info_loaded_files && info_loaded_files[i]; i++)
1082 add_pointer_to_array (file_buffer, i, info_loaded_files,
1083 info_loaded_files_slots, 10, FILE_BUFFER *);
1086 /* Forget the contents, tags table, nodes list, and names of FILENAME. */
1088 forget_info_file (char *filename)
1091 FILE_BUFFER *file_buffer;
1093 if (!info_loaded_files)
1096 for (i = 0; (file_buffer = info_loaded_files[i]); i++)
1097 if (FILENAME_CMP (filename, file_buffer->filename) == 0
1098 || FILENAME_CMP (filename, file_buffer->fullpath) == 0)
1100 free (file_buffer->filename);
1101 free (file_buffer->fullpath);
1103 if (file_buffer->contents)
1104 free (file_buffer->contents);
1106 /* free_file_buffer_tags () also kills the subfiles list, since
1107 the subfiles list is only of use in conjunction with tags. */
1108 free_file_buffer_tags (file_buffer);
1110 /* Move rest of list down. */
1111 while (info_loaded_files[i + 1])
1113 info_loaded_files[i] = info_loaded_files[i + 1];
1116 info_loaded_files[i] = 0;
1122 /* Free the tags (if any) associated with FILE_BUFFER. */
1124 free_file_buffer_tags (FILE_BUFFER *file_buffer)
1128 if (file_buffer->tags)
1132 for (i = 0; (tag = file_buffer->tags[i]); i++)
1133 free_info_tag (tag);
1135 free (file_buffer->tags);
1136 file_buffer->tags = NULL;
1137 file_buffer->tags_slots = 0;
1140 if (file_buffer->subfiles)
1142 for (i = 0; file_buffer->subfiles[i]; i++)
1143 free (file_buffer->subfiles[i]);
1145 free (file_buffer->subfiles);
1146 file_buffer->subfiles = NULL;
1150 /* Free the data associated with TAG, as well as TAG itself. */
1152 free_info_tag (TAG *tag)
1154 free (tag->nodename);
1156 /* We don't free tag->filename, because that filename is part of the
1157 subfiles list for the containing FILE_BUFFER. free_info_tags ()
1158 will free the subfiles when it is appropriate. */
1163 /* Load the contents of FILE_BUFFER->contents. This function is called
1164 when a file buffer was loaded, and then in order to conserve memory, the
1165 file buffer's contents were freed and the pointer was zero'ed. Note that
1166 the file was already loaded at least once successfully, so the tags and/or
1167 nodes members are still correctly filled. */
1169 info_reload_file_buffer_contents (FILE_BUFFER *fb)
1173 #if defined (HANDLE_MAN_PAGES)
1174 /* If this is the magic manpage node, don't try to reload, just give up. */
1175 if (fb->flags & N_IsManPage)
1179 fb->flags &= ~N_IsCompressed;
1181 /* Let the filesystem do all the work for us. */
1183 filesys_read_info_file (fb->fullpath, &(fb->filesize), &(fb->finfo),
1186 fb->flags |= N_IsCompressed;
1189 /* Return the actual starting memory location of NODE, side-effecting
1190 NODE->contents. MIN and MAX are bounds for a search if one is necessary.
1191 Because of the way that tags are implemented, the physical nodestart may
1192 not actually be where the tag says it is. If that is the case, but the
1193 node was found anyway, set N_UpdateTags in NODE->flags. If the node is
1194 found, return non-zero. NODE->contents is returned positioned right after
1195 the node separator that precedes this node, while the return value is
1196 position directly on the separator that precedes this node. If the node
1197 could not be found, return a NULL pointer. */
1199 adjust_nodestart (NODE *node, int min, int max)
1202 SEARCH_BINDING node_body;
1204 /* Define the node body. */
1205 node_body.buffer = node->contents;
1206 node_body.start = 0;
1207 node_body.end = max;
1208 node_body.flags = 0;
1210 /* Try the optimal case first. Who knows? This file may actually be
1211 formatted (mostly) correctly. */
1212 if (node_body.buffer[0] != INFO_COOKIE && min > 2)
1213 node_body.buffer -= 3;
1215 position = find_node_separator (&node_body);
1217 /* If we found a node start, then check it out. */
1222 sep_len = skip_node_separator (node->contents);
1224 /* If we managed to skip a node separator, then check for this node
1225 being the right one. */
1228 char *nodedef, *nodestart;
1231 nodestart = node_body.buffer + position + sep_len;
1232 nodedef = nodestart;
1233 offset = string_in_line (INFO_NODE_LABEL, nodedef);
1238 nodedef += skip_whitespace (nodedef);
1239 offset = skip_node_characters (nodedef, DONT_SKIP_NEWLINES);
1240 if (((unsigned int) offset == strlen (node->nodename)) &&
1241 (strncmp (node->nodename, nodedef, offset) == 0))
1243 node->contents = nodestart;
1244 return node_body.buffer + position;
1250 /* Oh well, I guess we have to try to find it in a larger area. */
1251 node_body.buffer = node->contents - min;
1252 node_body.start = 0;
1253 node_body.end = min + max;
1254 node_body.flags = 0;
1256 position = find_node_in_binding (node->nodename, &node_body);
1258 /* If the node couldn't be found, we lose big. */
1262 /* Otherwise, the node was found, but the tags table could need updating
1263 (if we used a tag to get here, that is). Set the flag in NODE->flags. */
1264 node->contents = node_body.buffer + position;
1265 node->contents += skip_node_separator (node->contents);
1266 if (node->flags & N_HasTagsTable)
1267 node->flags |= N_UpdateTags;
1268 return node_body.buffer + position;