1 /* nodes.c -- How to get an Info file and node. */
3 /* This file is part of GNU Info, a program for reading online documentation
6 Copyright (C) 1993 Free Software Foundation, Inc.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 Written by Brian Fox (bfox@ai.mit.edu). */
29 #include "info-utils.h"
31 #if defined (HANDLE_MAN_PAGES)
33 #endif /* HANDLE_MAN_PAGES */
35 /* **************************************************************** */
37 /* Functions Static to this File */
39 /* **************************************************************** */
41 static void forget_info_file (), remember_info_file ();
42 static void free_file_buffer_tags (), free_info_tag ();
43 static void get_nodes_of_tags_table (), get_nodes_of_info_file ();
44 static void get_tags_of_indirect_tags_table ();
45 static void info_reload_file_buffer_contents ();
46 static char *adjust_nodestart ();
47 static FILE_BUFFER
*info_load_file_internal (), *info_find_file_internal ();
48 static NODE
*info_node_of_file_buffer_tags ();
50 static long get_node_length ();
52 /* Magic number that RMS used to decide how much a tags table pointer could
53 be off by. I feel that it should be much smaller, like on the order of
55 #define DEFAULT_INFO_FUDGE 1000
57 /* Passed to *_internal functions. INFO_GET_TAGS says to do what is
58 neccessary to fill in the nodes or tags arrays in FILE_BUFFER. */
59 #define INFO_NO_TAGS 0
60 #define INFO_GET_TAGS 1
62 /* **************************************************************** */
64 /* Global Variables */
66 /* **************************************************************** */
68 /* When non-zero, this is a string describing the recent file error. */
69 char *info_recent_file_error
= (char *)NULL
;
71 /* The list of already loaded nodes. */
72 FILE_BUFFER
**info_loaded_files
= (FILE_BUFFER
**)NULL
;
74 /* The number of slots currently allocated to LOADED_FILES. */
75 int info_loaded_files_slots
= 0;
77 /* **************************************************************** */
79 /* Public Functions for Node Manipulation */
81 /* **************************************************************** */
83 /* Used to build "dir" menu from "localdir" files found in INFOPATH. */
84 extern void maybe_build_dir_node ();
86 /* Return a pointer to a NODE structure for the Info node (FILENAME)NODENAME.
87 FILENAME can be passed as NULL, in which case the filename of "dir" is used.
88 NODENAME can be passed as NULL, in which case the nodename of "Top" is used.
89 If the node cannot be found, return a NULL pointer. */
91 info_get_node (filename
, nodename
)
92 char *filename
, *nodename
;
94 FILE_BUFFER
*file_buffer
;
97 file_buffer
= (FILE_BUFFER
*)NULL
;
98 info_recent_file_error
= (char *)NULL
;
100 info_parse_node (nodename
, DONT_SKIP_NEWLINES
);
101 nodename
= (char *)NULL
;
103 if (info_parsed_filename
)
104 filename
= info_parsed_filename
;
106 if (info_parsed_nodename
)
107 nodename
= info_parsed_nodename
;
109 /* If FILENAME is not specified, it defaults to "dir". */
113 /* If the file to be looked up is "dir", build the contents from all of
114 the "dir"s and "localdir"s found in INFOPATH. */
115 if (strcasecmp (filename
, "dir") == 0)
116 maybe_build_dir_node (filename
);
118 /* Find the correct info file. */
119 file_buffer
= info_find_file (filename
);
123 if (filesys_error_number
)
124 info_recent_file_error
=
125 filesys_error_string (filename
, filesys_error_number
);
126 return ((NODE
*)NULL
);
129 node
= info_get_node_of_file_buffer (nodename
, file_buffer
);
130 /* If the node looked for was "Top", try again looking for the node under
131 a slightly different name. */
132 if (!node
&& (nodename
== NULL
|| strcasecmp (nodename
, "Top") == 0))
134 node
= info_get_node_of_file_buffer ("Top", file_buffer
);
136 node
= info_get_node_of_file_buffer ("top", file_buffer
);
138 node
= info_get_node_of_file_buffer ("TOP", file_buffer
);
143 /* Return a pointer to a NODE structure for the Info node NODENAME in
144 FILE_BUFFER. NODENAME can be passed as NULL, in which case the
145 nodename of "Top" is used. If the node cannot be found, return a
148 info_get_node_of_file_buffer (nodename
, file_buffer
)
150 FILE_BUFFER
*file_buffer
;
152 NODE
*node
= (NODE
*)NULL
;
154 /* If we are unable to find the file, we have to give up. There isn't
155 anything else we can do. */
157 return ((NODE
*)NULL
);
159 /* If the file buffer was gc'ed, reload the contents now. */
160 if (!file_buffer
->contents
)
161 info_reload_file_buffer_contents (file_buffer
);
163 /* If NODENAME is not specified, it defaults to "Top". */
167 /* If the name of the node that we wish to find is exactly "*", then the
168 node body is the contents of the entire file. Create and return such
170 if (strcmp (nodename
, "*") == 0)
172 node
= (NODE
*)xmalloc (sizeof (NODE
));
173 node
->filename
= file_buffer
->fullpath
;
174 node
->parent
= (char *)NULL
;
175 node
->nodename
= xstrdup ("*");
176 node
->contents
= file_buffer
->contents
;
177 node
->nodelen
= file_buffer
->filesize
;
180 #if defined (HANDLE_MAN_PAGES)
181 /* If the file buffer is the magic one associated with manpages, call
182 the manpage node finding function instead. */
183 else if (file_buffer
->flags
& N_IsManPage
)
185 node
= get_manpage_node (file_buffer
, nodename
);
187 #endif /* HANDLE_MAN_PAGES */
188 /* If this is the "main" info file, it might contain a tags table. Search
189 the tags table for an entry which matches the node that we want. If
190 there is a tags table, get the file which contains this node, but don't
191 bother building a node list for it. */
192 else if (file_buffer
->tags
)
194 node
= info_node_of_file_buffer_tags (file_buffer
, nodename
);
197 /* Return the results of our node search. */
201 /* Locate the file named by FILENAME, and return the information structure
202 describing this file. The file may appear in our list of loaded files
203 already, or it may not. If it does not already appear, find the file,
204 and add it to the list of loaded files. If the file cannot be found,
205 return a NULL FILE_BUFFER *. */
207 info_find_file (filename
)
210 return (info_find_file_internal (filename
, INFO_GET_TAGS
));
213 /* Load the info file FILENAME, remembering information about it in a
216 info_load_file (filename
)
219 return (info_load_file_internal (filename
, INFO_GET_TAGS
));
223 /* **************************************************************** */
225 /* Private Functions Implementation */
227 /* **************************************************************** */
229 /* The workhorse for info_find_file (). Non-zero 2nd argument says to
230 try to build a tags table (or otherwise glean the nodes) for this
231 file once found. By default, we build the tags table, but when this
232 function is called by info_get_node () when we already have a valid
233 tags table describing the nodes, it is unnecessary. */
235 info_find_file_internal (filename
, get_tags
)
240 register FILE_BUFFER
*file_buffer
;
242 /* First try to find the file in our list of already loaded files. */
243 if (info_loaded_files
)
245 for (i
= 0; (file_buffer
= info_loaded_files
[i
]); i
++)
246 if ((strcmp (filename
, file_buffer
->filename
) == 0) ||
247 (strcmp (filename
, file_buffer
->fullpath
) == 0) ||
248 ((*filename
!= '/') &&
250 filename_non_directory (file_buffer
->fullpath
)) == 0))
252 struct stat new_info
, *old_info
;
254 /* This file is loaded. If the filename that we want is
255 specifically "dir", then simply return the file buffer. */
256 if (strcasecmp (filename_non_directory (filename
), "dir") == 0)
257 return (file_buffer
);
259 #if defined (HANDLE_MAN_PAGES)
260 /* Do the same for the magic MANPAGE file. */
261 if (file_buffer
->flags
& N_IsManPage
)
262 return (file_buffer
);
263 #endif /* HANDLE_MAN_PAGES */
265 /* The file appears to be already loaded, and it is not "dir".
266 Check to see if it has changed since the last time it was
268 if (stat (file_buffer
->fullpath
, &new_info
) == -1)
270 filesys_error_number
= errno
;
271 return ((FILE_BUFFER
*)NULL
);
274 old_info
= &file_buffer
->finfo
;
276 if ((new_info
.st_size
!= old_info
->st_size
) ||
277 (new_info
.st_mtime
!= old_info
->st_mtime
))
279 /* The file has changed. Forget that we ever had loaded it
280 in the first place. */
281 forget_info_file (filename
);
286 /* The info file exists, and has not changed since the last
287 time it was loaded. If the caller requested a nodes list
288 for this file, and there isn't one here, build the nodes
289 for this file_buffer. In any case, return the file_buffer
291 if (get_tags
&& !file_buffer
->tags
)
292 build_tags_and_nodes (file_buffer
);
294 return (file_buffer
);
299 /* The file wasn't loaded. Try to load it now. */
300 #if defined (HANDLE_MAN_PAGES)
301 /* If the name of the file that we want is our special file buffer for
302 Unix manual pages, then create the file buffer, and return it now. */
303 if (strcasecmp (filename
, MANPAGE_FILE_BUFFER_NAME
) == 0)
304 file_buffer
= create_manpage_file_buffer ();
306 #endif /* HANDLE_MAN_PAGES */
307 file_buffer
= info_load_file_internal (filename
, get_tags
);
309 /* If the file was loaded, remember the name under which it was found. */
311 remember_info_file (file_buffer
);
313 return (file_buffer
);
316 /* The workhorse function for info_load_file (). Non-zero second argument
317 says to build a list of tags (or nodes) for this file. This is the
318 default behaviour when info_load_file () is called, but it is not
319 necessary when loading a subfile for which we already have tags. */
321 info_load_file_internal (filename
, get_tags
)
325 char *fullpath
, *contents
;
329 FILE_BUFFER
*file_buffer
= (FILE_BUFFER
*)NULL
;
331 /* Get the full pathname of this file, as known by the info system.
332 That is to say, search along INFOPATH and expand tildes, etc. */
333 fullpath
= info_find_fullpath (filename
);
335 /* Did we actually find the file? */
336 retcode
= stat (fullpath
, &finfo
);
338 /* If the file referenced by the name returned from info_find_fullpath ()
339 doesn't exist, then try again with the last part of the filename
340 appearing in lowercase. */
346 lowered_name
= xstrdup (filename
);
347 basename
= (char *) strrchr (lowered_name
, '/');
352 basename
= lowered_name
;
356 if (isupper (*basename
))
357 *basename
= tolower (*basename
);
362 fullpath
= info_find_fullpath (lowered_name
);
365 retcode
= stat (fullpath
, &finfo
);
368 /* If the file wasn't found, give up, returning a NULL pointer. */
371 filesys_error_number
= errno
;
372 return ((FILE_BUFFER
*)NULL
);
375 /* Otherwise, try to load the file. */
376 contents
= filesys_read_info_file (fullpath
, &filesize
, &finfo
);
379 return ((FILE_BUFFER
*)NULL
);
381 /* The file was found, and can be read. Allocate FILE_BUFFER and fill
382 in the various members. */
383 file_buffer
= make_file_buffer ();
384 file_buffer
->filename
= xstrdup (filename
);
385 file_buffer
->fullpath
= xstrdup (fullpath
);
386 file_buffer
->finfo
= finfo
;
387 file_buffer
->filesize
= filesize
;
388 file_buffer
->contents
= contents
;
389 if (file_buffer
->filesize
!= file_buffer
->finfo
.st_size
)
390 file_buffer
->flags
|= N_IsCompressed
;
392 /* If requested, build the tags and nodes for this file buffer. */
394 build_tags_and_nodes (file_buffer
);
396 return (file_buffer
);
399 /* Grovel FILE_BUFFER->contents finding tags and nodes, and filling in the
400 various slots. This can also be used to rebuild a tag or node table. */
402 build_tags_and_nodes (file_buffer
)
403 FILE_BUFFER
*file_buffer
;
405 SEARCH_BINDING binding
;
408 free_file_buffer_tags (file_buffer
);
409 file_buffer
->flags
&= ~N_HasTagsTable
;
411 /* See if there is a tags table in this info file. */
412 binding
.buffer
= file_buffer
->contents
;
413 binding
.start
= file_buffer
->filesize
;
414 binding
.end
= binding
.start
- 1000;
417 binding
.flags
= S_FoldCase
;
419 position
= search_backward (TAGS_TABLE_END_LABEL
, &binding
);
421 /* If there is a tag table, find the start of it, and grovel over it
422 extracting tag information. */
426 long tags_table_begin
, tags_table_end
;
428 binding
.end
= position
;
429 binding
.start
= binding
.end
- 5 - strlen (TAGS_TABLE_END_LABEL
);
430 if (binding
.start
< 0)
433 position
= find_node_separator (&binding
);
435 /* For this test, (and all others here) failure indicates a bogus
436 tags table. Grovel the file. */
440 /* Remember the end of the tags table. */
441 binding
.start
= position
;
442 tags_table_end
= binding
.start
;
445 /* Locate the start of the tags table. */
446 position
= search_backward (TAGS_TABLE_BEG_LABEL
, &binding
);
451 binding
.end
= position
;
452 binding
.start
= binding
.end
- 5 - strlen (TAGS_TABLE_BEG_LABEL
);
453 position
= find_node_separator (&binding
);
458 /* The file contains a valid tags table. Fill the FILE_BUFFER's
460 file_buffer
->flags
|= N_HasTagsTable
;
461 tags_table_begin
= position
;
463 /* If this isn't an indirect tags table, just remember the nodes
464 described locally in this tags table. Note that binding.end
465 is pointing to just after the beginning label. */
466 binding
.start
= binding
.end
;
467 binding
.end
= file_buffer
->filesize
;
469 if (!looking_at (TAGS_TABLE_IS_INDIRECT_LABEL
, &binding
))
471 binding
.start
= tags_table_begin
;
472 binding
.end
= tags_table_end
;
473 get_nodes_of_tags_table (file_buffer
, &binding
);
478 /* This is an indirect tags table. Build TAGS member. */
479 SEARCH_BINDING indirect
;
481 indirect
.start
= tags_table_begin
;
483 indirect
.buffer
= binding
.buffer
;
484 indirect
.flags
= S_FoldCase
;
486 position
= search_backward (INDIRECT_TAGS_TABLE_LABEL
, &indirect
);
490 /* This file is malformed. Give up. */
494 indirect
.start
= position
;
495 indirect
.end
= tags_table_begin
;
496 binding
.start
= tags_table_begin
;
497 binding
.end
= tags_table_end
;
498 get_tags_of_indirect_tags_table (file_buffer
, &indirect
, &binding
);
503 /* This file doesn't contain any kind of tags table. Grovel the
504 file and build node entries for it. */
505 get_nodes_of_info_file (file_buffer
);
508 /* Search through FILE_BUFFER->contents building an array of TAG *,
509 one entry per each node present in the file. Store the tags in
510 FILE_BUFFER->tags, and the number of allocated slots in
511 FILE_BUFFER->tags_slots. */
513 get_nodes_of_info_file (file_buffer
)
514 FILE_BUFFER
*file_buffer
;
518 SEARCH_BINDING binding
;
520 binding
.buffer
= file_buffer
->contents
;
522 binding
.end
= file_buffer
->filesize
;
523 binding
.flags
= S_FoldCase
;
525 while ((nodestart
= find_node_separator (&binding
)) != -1)
531 /* Skip past the characters just found. */
532 binding
.start
= nodestart
;
533 binding
.start
+= skip_node_separator (binding
.buffer
+ binding
.start
);
535 /* Move to the start of the line defining the node. */
536 nodeline
= binding
.buffer
+ binding
.start
;
539 start
= string_in_line (INFO_NODE_LABEL
, nodeline
);
541 /* If not there, this is not the start of a node. */
545 /* Find the start of the nodename. */
546 start
+= skip_whitespace (nodeline
+ start
);
548 /* Find the end of the nodename. */
550 skip_node_characters (nodeline
+ start
, DONT_SKIP_NEWLINES
);
552 /* Okay, we have isolated the node name, and we know where the
553 node starts. Remember this information in a NODE structure. */
554 entry
= (TAG
*)xmalloc (sizeof (TAG
));
555 entry
->nodename
= (char *)xmalloc (1 + (end
- start
));
556 strncpy (entry
->nodename
, nodeline
+ start
, end
- start
);
557 entry
->nodename
[end
- start
] = '\0';
558 entry
->nodestart
= nodestart
;
560 SEARCH_BINDING node_body
;
562 node_body
.buffer
= binding
.buffer
+ binding
.start
;
564 node_body
.end
= binding
.end
- binding
.start
;
565 node_body
.flags
= S_FoldCase
;
566 entry
->nodelen
= get_node_length (&node_body
);
569 entry
->filename
= file_buffer
->fullpath
;
571 /* Add this tag to the array of tag structures in this FILE_BUFFER. */
572 add_pointer_to_array (entry
, tags_index
, file_buffer
->tags
,
573 file_buffer
->tags_slots
, 100, TAG
*);
577 /* Return the length of the node which starts at BINDING. */
579 get_node_length (binding
)
580 SEARCH_BINDING
*binding
;
585 /* From the Info-RFC file:
586 [A node] ends with either a ^_, a ^L, or the end of file. */
587 for (i
= binding
->start
, body
= binding
->buffer
; i
< binding
->end
; i
++)
589 if (body
[i
] == INFO_FF
|| body
[i
] == INFO_COOKIE
)
592 return ((long) i
- binding
->start
);
595 /* Build and save the array of nodes in FILE_BUFFER by searching through the
596 contents of BUFFER_BINDING for a tags table, and groveling the contents. */
598 get_nodes_of_tags_table (file_buffer
, buffer_binding
)
599 FILE_BUFFER
*file_buffer
;
600 SEARCH_BINDING
*buffer_binding
;
602 int offset
, tags_index
= 0;
603 SEARCH_BINDING
*search
;
606 search
= copy_binding (buffer_binding
);
608 /* Find the start of the tags table. */
609 position
= find_tags_table (search
);
611 /* If none, we're all done. */
615 /* Move to one character before the start of the actual table. */
616 search
->start
= position
;
617 search
->start
+= skip_node_separator (search
->buffer
+ search
->start
);
618 search
->start
+= strlen (TAGS_TABLE_BEG_LABEL
);
621 /* The tag table consists of lines containing node names and positions.
622 Do each line until we find one that doesn't contain a node name. */
623 while ((position
= search_forward ("\n", search
)) != -1)
628 /* Prepare to skip this line. */
629 search
->start
= position
;
632 /* Skip past informative "(Indirect)" tags table line. */
633 if (!tags_index
&& looking_at (TAGS_TABLE_IS_INDIRECT_LABEL
, search
))
636 /* Find the label preceding the node name. */
638 string_in_line (INFO_NODE_LABEL
, search
->buffer
+ search
->start
);
640 /* If not there, not a defining line, so we must be out of the
645 /* Point to the beginning of the node definition. */
646 search
->start
+= offset
;
647 nodedef
= search
->buffer
+ search
->start
;
648 nodedef
+= skip_whitespace (nodedef
);
650 /* Move past the node's name. */
652 (nodedef
[offset
]) && (nodedef
[offset
] != INFO_TAGSEP
);
655 if (nodedef
[offset
] != INFO_TAGSEP
)
658 entry
= (TAG
*)xmalloc (sizeof (TAG
));
659 entry
->nodename
= (char *)xmalloc (1 + offset
);
660 strncpy (entry
->nodename
, nodedef
, offset
);
661 entry
->nodename
[offset
] = '\0';
663 entry
->nodestart
= (long) atol (nodedef
+ offset
);
665 /* We don't know the length of this node yet. */
668 /* The filename of this node is currently known as the same as the
669 name of this file. */
670 entry
->filename
= file_buffer
->fullpath
;
672 /* Add this node structure to the array of node structures in this
674 add_pointer_to_array (entry
, tags_index
, file_buffer
->tags
,
675 file_buffer
->tags_slots
, 100, TAG
*);
680 /* A structure used only in get_tags_of_indirect_tags_table () to hold onto
681 an intermediate value. */
687 /* Remember in FILE_BUFFER the nodenames, subfilenames, and offsets within the
688 subfiles of every node which appears in TAGS_BINDING. The 2nd argument is
689 a binding surrounding the indirect files list. */
691 get_tags_of_indirect_tags_table (file_buffer
, indirect_binding
, tags_binding
)
692 FILE_BUFFER
*file_buffer
;
693 SEARCH_BINDING
*indirect_binding
, *tags_binding
;
696 SUBFILE
**subfiles
= (SUBFILE
**)NULL
;
697 int subfiles_index
= 0, subfiles_slots
= 0;
700 /* First get the list of tags from the tags table. Then lookup the
701 associated file in the indirect list for each tag, and update it. */
702 get_nodes_of_tags_table (file_buffer
, tags_binding
);
704 /* We have the list of tags in file_buffer->tags. Get the list of
705 subfiles from the indirect table. */
707 char *start
, *end
, *line
;
710 start
= indirect_binding
->buffer
+ indirect_binding
->start
;
711 end
= indirect_binding
->buffer
+ indirect_binding
->end
;
718 colon
= string_in_line (":", line
);
723 subfile
= (SUBFILE
*)xmalloc (sizeof (SUBFILE
));
724 subfile
->filename
= (char *)xmalloc (colon
);
725 strncpy (subfile
->filename
, line
, colon
- 1);
726 subfile
->filename
[colon
- 1] = '\0';
727 subfile
->first_byte
= (long) atol (line
+ colon
);
730 (subfile
, subfiles_index
, subfiles
, subfiles_slots
, 10, SUBFILE
*);
732 while (*line
++ != '\n');
736 /* If we have successfully built the indirect files table, then
737 merge the information in the two tables. */
740 free_file_buffer_tags (file_buffer
);
745 register int tags_index
;
747 SEARCH_BINDING binding
;
749 /* Find the length of the header of the file containing the indirect
750 tags table. This header appears at the start of every file. We
751 want the absolute position of each node within each subfile, so
752 we subtract the start of the containing subfile from the logical
753 position of the node, and then add the length of the header in. */
754 binding
.buffer
= file_buffer
->contents
;
756 binding
.end
= file_buffer
->filesize
;
757 binding
.flags
= S_FoldCase
;
759 header_length
= find_node_separator (&binding
);
760 if (header_length
== -1)
763 /* Build the file buffer's list of subfiles. */
765 char *containing_dir
, *temp
;
766 int len_containing_dir
;
768 containing_dir
= xstrdup (file_buffer
->fullpath
);
769 temp
= (char *) strrchr (containing_dir
, '/');
774 len_containing_dir
= strlen (containing_dir
);
776 for (i
= 0; subfiles
[i
]; i
++);
778 file_buffer
->subfiles
= (char **) xmalloc ((1 + i
) * sizeof (char *));
780 for (i
= 0; subfiles
[i
]; i
++)
784 fullpath
= (char *) xmalloc
785 (2 + strlen (subfiles
[i
]->filename
) + len_containing_dir
);
787 sprintf (fullpath
, "%s/%s",
788 containing_dir
, subfiles
[i
]->filename
);
790 file_buffer
->subfiles
[i
] = fullpath
;
792 file_buffer
->subfiles
[i
] = (char *)NULL
;
793 free (containing_dir
);
796 /* For each node in the file's tags table, remember the starting
798 for (tags_index
= 0; (entry
= file_buffer
->tags
[tags_index
]);
802 subfiles
[i
] && entry
->nodestart
>= subfiles
[i
]->first_byte
;
805 /* If the Info file containing the indirect tags table is
806 malformed, then give up. */
809 /* The Info file containing the indirect tags table is
810 malformed. Give up. */
811 for (i
= 0; subfiles
[i
]; i
++)
813 free (subfiles
[i
]->filename
);
815 free (file_buffer
->subfiles
[i
]);
817 file_buffer
->subfiles
= (char **)NULL
;
818 free_file_buffer_tags (file_buffer
);
822 /* SUBFILES[i] is the index of the first subfile whose logical
823 first byte is greater than the logical offset of this node's
824 starting position. This means that the subfile directly
825 preceding this one is the one containing the node. */
827 entry
->filename
= file_buffer
->subfiles
[i
- 1];
828 entry
->nodestart
-= subfiles
[i
-1]->first_byte
;
829 entry
->nodestart
+= header_length
;
833 /* We have successfully built the tags table. Remember that it
835 file_buffer
->flags
|= N_TagsIndirect
;
838 /* Free the structures assigned to SUBFILES. Free the names as well
839 as the structures themselves, then finally, the array. */
840 for (i
= 0; subfiles
[i
]; i
++)
842 free (subfiles
[i
]->filename
);
848 /* Return the node from FILE_BUFFER which matches NODENAME by searching
849 the tags table in FILE_BUFFER. If the node could not be found, return
852 info_node_of_file_buffer_tags (file_buffer
, nodename
)
853 FILE_BUFFER
*file_buffer
;
859 for (i
= 0; (tag
= file_buffer
->tags
[i
]); i
++)
860 if (strcmp (nodename
, tag
->nodename
) == 0)
862 FILE_BUFFER
*subfile
;
864 subfile
= info_find_file_internal (tag
->filename
, INFO_NO_TAGS
);
867 return ((NODE
*)NULL
);
869 if (!subfile
->contents
)
871 info_reload_file_buffer_contents (subfile
);
873 if (!subfile
->contents
)
874 return ((NODE
*)NULL
);
877 /* If we were able to find this file and load it, then return
878 the node within it. */
882 node
= (NODE
*)xmalloc (sizeof (NODE
));
883 node
->filename
= (subfile
->fullpath
);
884 node
->nodename
= tag
->nodename
;
885 node
->contents
= subfile
->contents
+ tag
->nodestart
;
887 node
->parent
= (char *)NULL
;
889 if (file_buffer
->flags
& N_HasTagsTable
)
891 node
->flags
|= N_HasTagsTable
;
893 if (file_buffer
->flags
& N_TagsIndirect
)
895 node
->flags
|= N_TagsIndirect
;
896 node
->parent
= file_buffer
->fullpath
;
900 if (subfile
->flags
& N_IsCompressed
)
901 node
->flags
|= N_IsCompressed
;
903 /* If TAG->nodelen hasn't been calculated yet, then we aren't
904 in a position to trust the entry pointer. Adjust things so
905 that ENTRY->nodestart gets the exact address of the start of
906 the node separator which starts this node, and NODE->contents
907 gets the address of the line defining this node. If we cannot
908 do that, the node isn't really here. */
909 if (tag
->nodelen
== -1)
913 SEARCH_BINDING node_body
;
916 min
= max
= DEFAULT_INFO_FUDGE
;
918 if (tag
->nodestart
< DEFAULT_INFO_FUDGE
)
919 min
= tag
->nodestart
;
921 if (DEFAULT_INFO_FUDGE
>
922 (subfile
->filesize
- tag
->nodestart
))
923 max
= subfile
->filesize
- tag
->nodestart
;
925 /* NODE_SEP gets the address of the separator which defines
926 this node, or (char *)NULL if the node wasn't found.
927 NODE->contents is side-effected to point to right after
929 node_sep
= adjust_nodestart (node
, min
, max
);
930 if (node_sep
== (char *)NULL
)
933 return ((NODE
*)NULL
);
935 /* Readjust tag->nodestart. */
936 tag
->nodestart
= node_sep
- subfile
->contents
;
938 /* Calculate the length of the current node. */
939 buff_end
= subfile
->contents
+ subfile
->filesize
;
941 node_body
.buffer
= node
->contents
;
943 node_body
.end
= buff_end
- node_body
.buffer
;
945 tag
->nodelen
= get_node_length (&node_body
);
949 /* Since we know the length of this node, we have already
950 adjusted tag->nodestart to point to the exact start of
951 it. Simply skip the node separator. */
952 node
->contents
+= skip_node_separator (node
->contents
);
955 node
->nodelen
= tag
->nodelen
;
960 /* There was a tag table for this file, and the node wasn't found.
961 Return NULL, since this file doesn't contain the desired node. */
962 return ((NODE
*)NULL
);
965 /* **************************************************************** */
967 /* Managing file_buffers, nodes, and tags. */
969 /* **************************************************************** */
971 /* Create a new, empty file buffer. */
975 FILE_BUFFER
*file_buffer
;
977 file_buffer
= (FILE_BUFFER
*)xmalloc (sizeof (FILE_BUFFER
));
978 file_buffer
->filename
= file_buffer
->fullpath
= (char *)NULL
;
979 file_buffer
->contents
= (char *)NULL
;
980 file_buffer
->tags
= (TAG
**)NULL
;
981 file_buffer
->subfiles
= (char **)NULL
;
982 file_buffer
->tags_slots
= 0;
983 file_buffer
->flags
= 0;
985 return (file_buffer
);
988 /* Add FILE_BUFFER to our list of already loaded info files. */
990 remember_info_file (file_buffer
)
991 FILE_BUFFER
*file_buffer
;
995 for (i
= 0; info_loaded_files
&& info_loaded_files
[i
]; i
++)
998 add_pointer_to_array (file_buffer
, i
, info_loaded_files
,
999 info_loaded_files_slots
, 10, FILE_BUFFER
*);
1002 /* Forget the contents, tags table, nodes list, and names of FILENAME. */
1004 forget_info_file (filename
)
1008 FILE_BUFFER
*file_buffer
;
1010 if (!info_loaded_files
)
1013 for (i
= 0; (file_buffer
= info_loaded_files
[i
]); i
++)
1014 if ((strcmp (filename
, file_buffer
->filename
) == 0) ||
1015 (strcmp (filename
, file_buffer
->fullpath
) == 0))
1017 free (file_buffer
->filename
);
1018 free (file_buffer
->fullpath
);
1020 if (file_buffer
->contents
)
1021 free (file_buffer
->contents
);
1023 /* Note that free_file_buffer_tags () also kills the subfiles
1024 list, since the subfiles list is only of use in conjunction
1026 free_file_buffer_tags (file_buffer
);
1028 while ((info_loaded_files
[i
] = info_loaded_files
[++i
]))
1035 /* Free the tags (if any) associated with FILE_BUFFER. */
1037 free_file_buffer_tags (file_buffer
)
1038 FILE_BUFFER
*file_buffer
;
1042 if (file_buffer
->tags
)
1046 for (i
= 0; (tag
= file_buffer
->tags
[i
]); i
++)
1047 free_info_tag (tag
);
1049 free (file_buffer
->tags
);
1050 file_buffer
->tags
= (TAG
**)NULL
;
1051 file_buffer
->tags_slots
= 0;
1054 if (file_buffer
->subfiles
)
1056 for (i
= 0; file_buffer
->subfiles
[i
]; i
++)
1057 free (file_buffer
->subfiles
[i
]);
1059 free (file_buffer
->subfiles
);
1060 file_buffer
->subfiles
= (char **)NULL
;
1064 /* Free the data associated with TAG, as well as TAG itself. */
1069 free (tag
->nodename
);
1071 /* We don't free tag->filename, because that filename is part of the
1072 subfiles list for the containing FILE_BUFFER. free_info_tags ()
1073 will free the subfiles when it is appropriate. */
1078 /* Load the contents of FILE_BUFFER->contents. This function is called
1079 when a file buffer was loaded, and then in order to conserve memory, the
1080 file buffer's contents were freed and the pointer was zero'ed. Note that
1081 the file was already loaded at least once successfully, so the tags and/or
1082 nodes members are still correctly filled. */
1084 info_reload_file_buffer_contents (fb
)
1088 #if defined (HANDLE_MAN_PAGES)
1089 /* If this is the magic manpage node, don't try to reload, just give up. */
1090 if (fb
->flags
& N_IsManPage
)
1094 fb
->flags
&= ~N_IsCompressed
;
1096 /* Let the filesystem do all the work for us. */
1098 filesys_read_info_file (fb
->fullpath
, &(fb
->filesize
), &(fb
->finfo
));
1099 if (fb
->filesize
!= (long) (fb
->finfo
.st_size
))
1100 fb
->flags
|= N_IsCompressed
;
1103 /* Return the actual starting memory location of NODE, side-effecting
1104 NODE->contents. MIN and MAX are bounds for a search if one is necessary.
1105 Because of the way that tags are implemented, the physical nodestart may
1106 not actually be where the tag says it is. If that is the case, but the
1107 node was found anyway, set N_UpdateTags in NODE->flags. If the node is
1108 found, return non-zero. NODE->contents is returned positioned right after
1109 the node separator that precedes this node, while the return value is
1110 position directly on the separator that precedes this node. If the node
1111 could not be found, return a NULL pointer. */
1113 adjust_nodestart (node
, min
, max
)
1118 SEARCH_BINDING node_body
;
1120 /* Define the node body. */
1121 node_body
.buffer
= node
->contents
;
1122 node_body
.start
= 0;
1123 node_body
.end
= max
;
1124 node_body
.flags
= 0;
1126 /* Try the optimal case first. Who knows? This file may actually be
1127 formatted (mostly) correctly. */
1128 if (node_body
.buffer
[0] != INFO_COOKIE
&& min
> 2)
1129 node_body
.buffer
-= 3;
1131 position
= find_node_separator (&node_body
);
1133 /* If we found a node start, then check it out. */
1138 sep_len
= skip_node_separator (node
->contents
);
1140 /* If we managed to skip a node separator, then check for this node
1141 being the right one. */
1144 char *nodedef
, *nodestart
;
1147 nodestart
= node_body
.buffer
+ position
+ sep_len
;
1148 nodedef
= nodestart
;
1149 offset
= string_in_line (INFO_NODE_LABEL
, nodedef
);
1154 nodedef
+= skip_whitespace (nodedef
);
1155 offset
= skip_node_characters (nodedef
, DONT_SKIP_NEWLINES
);
1156 if ((offset
== strlen (node
->nodename
)) &&
1157 (strncmp (node
->nodename
, nodedef
, offset
) == 0))
1159 node
->contents
= nodestart
;
1160 return (node_body
.buffer
+ position
);
1166 /* Oh well, I guess we have to try to find it in a larger area. */
1167 node_body
.buffer
= node
->contents
- min
;
1168 node_body
.start
= 0;
1169 node_body
.end
= min
+ max
;
1170 node_body
.flags
= 0;
1172 position
= find_node_in_binding (node
->nodename
, &node_body
);
1174 /* If the node couldn't be found, we lose big. */
1176 return ((char *)NULL
);
1178 /* Otherwise, the node was found, but the tags table could need updating
1179 (if we used a tag to get here, that is). Set the flag in NODE->flags. */
1180 node
->contents
= node_body
.buffer
+ position
;
1181 node
->contents
+= skip_node_separator (node
->contents
);
1182 if (node
->flags
& N_HasTagsTable
)
1183 node
->flags
|= N_UpdateTags
;
1184 return (node_body
.buffer
+ position
);