1 /* dir.c -- how to build a special "dir" node from "localdir" files.
2 $Id: dir.c,v 1.7 1998/06/28 19:51:36 karl Exp $
4 Copyright (C) 1993, 97, 98 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 Written by Brian Fox (bfox@ai.mit.edu). */
23 #include "info-utils.h"
27 /* The "dir" node can be built from the contents of a file called "dir",
28 with the addition of the menus of every file named in the array
29 dirs_to_add which are found in INFOPATH. */
31 static void add_menu_to_file_buffer (), insert_text_into_fb_at_binding ();
33 static char *dirs_to_add[] = {
34 "dir", "localdir", (char *)NULL
38 /* Return zero if the file represented in the stat structure TEST has
39 already been seen, nonzero else. */
45 } dir_file_list_entry_type;
51 static unsigned dir_file_list_len = 0;
52 static dir_file_list_entry_type *dir_file_list = NULL;
55 for (i = 0; i < dir_file_list_len; i++)
57 dir_file_list_entry_type entry;
58 entry = dir_file_list[i];
59 if (entry.device == test->st_dev && entry.inode == test->st_ino)
64 dir_file_list = xrealloc (dir_file_list,
65 dir_file_list_len * sizeof (dir_file_list_entry_type));
66 dir_file_list[dir_file_list_len - 1].device = test->st_dev;
67 dir_file_list[dir_file_list_len - 1].inode = test->st_ino;
73 maybe_build_dir_node (dirname)
76 int path_index, update_tags;
78 FILE_BUFFER *dir_buffer = info_find_file (dirname);
80 /* If there is no "dir" in the current info path, we cannot build one
85 /* If this directory has already been built, return now. */
86 if (dir_buffer->flags & N_CannotGC)
89 /* Initialize the list we use to avoid reading the same dir file twice
90 with the dir file just found. */
91 new_dir_file_p (&dir_buffer->finfo);
93 path_index = update_tags = 0;
95 /* Using each element of the path, check for one of the files in
96 DIRS_TO_ADD. Do not check for "localdir.info.Z" or anything else.
97 Only files explictly named are eligible. This is a design decision.
98 There can be an info file name "localdir.info" which contains
99 information on the setting up of "localdir" files. */
100 while ((this_dir = extract_colon_unit (infopath, &path_index)))
102 register int da_index;
105 /* Expand a leading tilde if one is present. */
106 if (*this_dir == '~')
108 char *tilde_expanded_dirname;
110 tilde_expanded_dirname = tilde_expand_word (this_dir);
111 if (tilde_expanded_dirname != this_dir)
114 this_dir = tilde_expanded_dirname;
118 /* For every different file named in DIRS_TO_ADD found in the
119 search path, add that file's menu to our "dir" node. */
120 for (da_index = 0; (from_file = dirs_to_add[da_index]); da_index++)
124 int namelen = strlen (from_file);
125 char *fullpath = xmalloc (3 + strlen (this_dir) + namelen);
127 strcpy (fullpath, this_dir);
128 if (!IS_SLASH (fullpath[strlen (fullpath) - 1]))
129 strcat (fullpath, "/");
130 strcat (fullpath, from_file);
132 statable = (stat (fullpath, &finfo) == 0);
134 /* Only add this file if we have not seen it before. */
135 if (statable && S_ISREG (finfo.st_mode) && new_dir_file_p (&finfo))
139 char *contents = filesys_read_info_file (fullpath, &filesize,
140 &finfo, &compressed);
144 add_menu_to_file_buffer (contents, filesize, dir_buffer);
155 build_tags_and_nodes (dir_buffer);
157 /* Flag that the dir buffer has been built. */
158 dir_buffer->flags |= N_CannotGC;
161 /* Given CONTENTS and FB (a file buffer), add the menu found in CONTENTS
162 to the menu found in FB->contents. Second argument SIZE is the total
165 add_menu_to_file_buffer (contents, size, fb)
170 SEARCH_BINDING contents_binding, fb_binding;
171 long contents_offset, fb_offset;
173 contents_binding.buffer = contents;
174 contents_binding.start = 0;
175 contents_binding.end = size;
176 contents_binding.flags = S_FoldCase | S_SkipDest;
178 fb_binding.buffer = fb->contents;
179 fb_binding.start = 0;
180 fb_binding.end = fb->filesize;
181 fb_binding.flags = S_FoldCase | S_SkipDest;
183 /* Move to the start of the menus in CONTENTS and FB. */
184 contents_offset = search_forward (INFO_MENU_LABEL, &contents_binding);
185 fb_offset = search_forward (INFO_MENU_LABEL, &fb_binding);
187 /* If there is no menu in CONTENTS, quit now. */
188 if (contents_offset == -1)
191 /* There is a menu in CONTENTS, and contents_offset points to the first
192 character following the menu starter string. Skip all whitespace
193 and newline characters. */
194 contents_offset += skip_whitespace_and_newlines (contents + contents_offset);
196 /* If there is no menu in FB, make one. */
199 /* Find the start of the second node in this file buffer. If there
200 is only one node, we will be adding the contents to the end of
202 fb_offset = find_node_separator (&fb_binding);
204 /* If not even a single node separator, give up. */
208 fb_binding.start = fb_offset;
210 skip_node_separator (fb_binding.buffer + fb_binding.start);
212 /* Try to find the next node separator. */
213 fb_offset = find_node_separator (&fb_binding);
215 /* If found one, consider that the start of the menu. Otherwise, the
216 start of this menu is the end of the file buffer (i.e., fb->size). */
218 fb_binding.start = fb_offset;
220 fb_binding.start = fb_binding.end;
222 insert_text_into_fb_at_binding
223 (fb, &fb_binding, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL));
225 fb_binding.buffer = fb->contents;
226 fb_binding.start = 0;
227 fb_binding.end = fb->filesize;
228 fb_offset = search_forward (INFO_MENU_LABEL, &fb_binding);
233 /* CONTENTS_OFFSET and FB_OFFSET point to the starts of the menus that
234 appear in their respective buffers. Add the remainder of CONTENTS
235 to the end of FB's menu. */
236 fb_binding.start = fb_offset;
237 fb_offset = find_node_separator (&fb_binding);
239 fb_binding.start = fb_offset;
241 fb_binding.start = fb_binding.end;
243 /* Leave exactly one blank line between directory entries. */
247 while ((fb_binding.start > 0) &&
248 (whitespace_or_newline (fb_binding.buffer[fb_binding.start - 1])))
254 /* Optimize if possible. */
257 fb_binding.buffer[fb_binding.start++] = '\n';
258 fb_binding.buffer[fb_binding.start++] = '\n';
262 /* Do it the hard way. */
263 insert_text_into_fb_at_binding (fb, &fb_binding, "\n\n", 2);
264 fb_binding.start += 2;
268 /* Insert the new menu. */
269 insert_text_into_fb_at_binding
270 (fb, &fb_binding, contents + contents_offset, size - contents_offset);
274 insert_text_into_fb_at_binding (fb, binding, text, textlen)
276 SEARCH_BINDING *binding;
283 start = binding->start;
286 contents = (char *)xmalloc (fb->filesize + textlen + 1);
287 memcpy (contents, fb->contents, start);
288 memcpy (contents + start, text, textlen);
289 memcpy (contents + start + textlen, fb->contents + start, end - start);
291 fb->contents = contents;
292 fb->filesize += textlen;
293 fb->finfo.st_size = fb->filesize;