1 | /* indices.c -- deal with an Info file index.
|
---|
2 | $Id: indices.c,v 1.5 2004/04/11 17:56:45 karl Exp $
|
---|
3 |
|
---|
4 | Copyright (C) 1993, 1997, 1998, 1999, 2002, 2003, 2004 Free Software
|
---|
5 | Foundation, Inc.
|
---|
6 |
|
---|
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 2, or (at your option)
|
---|
10 | any later version.
|
---|
11 |
|
---|
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.
|
---|
16 |
|
---|
17 | You should have received a copy of the GNU General Public License
|
---|
18 | along with this program; if not, write to the Free Software
|
---|
19 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
---|
20 |
|
---|
21 | Originally written by Brian Fox (bfox@ai.mit.edu). */
|
---|
22 |
|
---|
23 | #include "info.h"
|
---|
24 | #include "indices.h"
|
---|
25 |
|
---|
26 | /* User-visible variable controls the output of info-index-next. */
|
---|
27 | int show_index_match = 1;
|
---|
28 |
|
---|
29 | /* In the Info sense, an index is a menu. This variable holds the last
|
---|
30 | parsed index. */
|
---|
31 | static REFERENCE **index_index = (REFERENCE **)NULL;
|
---|
32 |
|
---|
33 | /* The offset of the most recently selected index element. */
|
---|
34 | static int index_offset = 0;
|
---|
35 |
|
---|
36 | /* Variable which holds the last string searched for. */
|
---|
37 | static char *index_search = (char *)NULL;
|
---|
38 |
|
---|
39 | /* A couple of "globals" describing where the initial index was found. */
|
---|
40 | static char *initial_index_filename = (char *)NULL;
|
---|
41 | static char *initial_index_nodename = (char *)NULL;
|
---|
42 |
|
---|
43 | /* A structure associating index names with index offset ranges. */
|
---|
44 | typedef struct {
|
---|
45 | char *name; /* The nodename of this index. */
|
---|
46 | int first; /* The index in our list of the first entry. */
|
---|
47 | int last; /* The index in our list of the last entry. */
|
---|
48 | } INDEX_NAME_ASSOC;
|
---|
49 |
|
---|
50 | /* An array associating index nodenames with index offset ranges. */
|
---|
51 | static INDEX_NAME_ASSOC **index_nodenames = (INDEX_NAME_ASSOC **)NULL;
|
---|
52 | static int index_nodenames_index = 0;
|
---|
53 | static int index_nodenames_slots = 0;
|
---|
54 |
|
---|
55 | /* Add the name of NODE, and the range of the associated index elements
|
---|
56 | (passed in ARRAY) to index_nodenames. */
|
---|
57 | static void
|
---|
58 | add_index_to_index_nodenames (REFERENCE **array, NODE *node)
|
---|
59 | {
|
---|
60 | register int i, last;
|
---|
61 | INDEX_NAME_ASSOC *assoc;
|
---|
62 |
|
---|
63 | for (last = 0; array[last + 1]; last++);
|
---|
64 | assoc = (INDEX_NAME_ASSOC *)xmalloc (sizeof (INDEX_NAME_ASSOC));
|
---|
65 | assoc->name = xstrdup (node->nodename);
|
---|
66 |
|
---|
67 | if (!index_nodenames_index)
|
---|
68 | {
|
---|
69 | assoc->first = 0;
|
---|
70 | assoc->last = last;
|
---|
71 | }
|
---|
72 | else
|
---|
73 | {
|
---|
74 | for (i = 0; index_nodenames[i + 1]; i++);
|
---|
75 | assoc->first = 1 + index_nodenames[i]->last;
|
---|
76 | assoc->last = assoc->first + last;
|
---|
77 | }
|
---|
78 | add_pointer_to_array
|
---|
79 | (assoc, index_nodenames_index, index_nodenames, index_nodenames_slots,
|
---|
80 | 10, INDEX_NAME_ASSOC *);
|
---|
81 | }
|
---|
82 |
|
---|
83 | /* Find and return the indices of WINDOW's file. The indices are defined
|
---|
84 | as the first node in the file containing the word "Index" and any
|
---|
85 | immediately following nodes whose names also contain "Index". All such
|
---|
86 | indices are concatenated and the result returned. If WINDOW's info file
|
---|
87 | doesn't have any indices, a NULL pointer is returned. */
|
---|
88 | REFERENCE **
|
---|
89 | info_indices_of_window (WINDOW *window)
|
---|
90 | {
|
---|
91 | FILE_BUFFER *fb;
|
---|
92 |
|
---|
93 | fb = file_buffer_of_window (window);
|
---|
94 |
|
---|
95 | return (info_indices_of_file_buffer (fb));
|
---|
96 | }
|
---|
97 |
|
---|
98 | REFERENCE **
|
---|
99 | info_indices_of_file_buffer (FILE_BUFFER *file_buffer)
|
---|
100 | {
|
---|
101 | register int i;
|
---|
102 | REFERENCE **result = (REFERENCE **)NULL;
|
---|
103 |
|
---|
104 | /* No file buffer, no indices. */
|
---|
105 | if (!file_buffer)
|
---|
106 | return ((REFERENCE **)NULL);
|
---|
107 |
|
---|
108 | /* Reset globals describing where the index was found. */
|
---|
109 | maybe_free (initial_index_filename);
|
---|
110 | maybe_free (initial_index_nodename);
|
---|
111 | initial_index_filename = (char *)NULL;
|
---|
112 | initial_index_nodename = (char *)NULL;
|
---|
113 |
|
---|
114 | if (index_nodenames)
|
---|
115 | {
|
---|
116 | for (i = 0; index_nodenames[i]; i++)
|
---|
117 | {
|
---|
118 | free (index_nodenames[i]->name);
|
---|
119 | free (index_nodenames[i]);
|
---|
120 | }
|
---|
121 |
|
---|
122 | index_nodenames_index = 0;
|
---|
123 | index_nodenames[0] = (INDEX_NAME_ASSOC *)NULL;
|
---|
124 | }
|
---|
125 |
|
---|
126 | /* Grovel the names of the nodes found in this file. */
|
---|
127 | if (file_buffer->tags)
|
---|
128 | {
|
---|
129 | TAG *tag;
|
---|
130 |
|
---|
131 | for (i = 0; (tag = file_buffer->tags[i]); i++)
|
---|
132 | {
|
---|
133 | if (string_in_line ("Index", tag->nodename) != -1)
|
---|
134 | {
|
---|
135 | NODE *node;
|
---|
136 | REFERENCE **menu;
|
---|
137 |
|
---|
138 | /* Found one. Get its menu. */
|
---|
139 | node = info_get_node (tag->filename, tag->nodename);
|
---|
140 | if (!node)
|
---|
141 | continue;
|
---|
142 |
|
---|
143 | /* Remember the filename and nodename of this index. */
|
---|
144 | initial_index_filename = xstrdup (file_buffer->filename);
|
---|
145 | initial_index_nodename = xstrdup (tag->nodename);
|
---|
146 |
|
---|
147 | menu = info_menu_of_node (node);
|
---|
148 |
|
---|
149 | /* If we have a menu, add this index's nodename and range
|
---|
150 | to our list of index_nodenames. */
|
---|
151 | if (menu)
|
---|
152 | {
|
---|
153 | add_index_to_index_nodenames (menu, node);
|
---|
154 |
|
---|
155 | /* Concatenate the references found so far. */
|
---|
156 | result = info_concatenate_references (result, menu);
|
---|
157 | }
|
---|
158 | free (node);
|
---|
159 | }
|
---|
160 | }
|
---|
161 | }
|
---|
162 |
|
---|
163 | /* If there is a result, clean it up so that every entry has a filename. */
|
---|
164 | for (i = 0; result && result[i]; i++)
|
---|
165 | if (!result[i]->filename)
|
---|
166 | result[i]->filename = xstrdup (file_buffer->filename);
|
---|
167 |
|
---|
168 | return (result);
|
---|
169 | }
|
---|
170 |
|
---|
171 | DECLARE_INFO_COMMAND (info_index_search,
|
---|
172 | _("Look up a string in the index for this file"))
|
---|
173 | {
|
---|
174 | do_info_index_search (window, count, 0);
|
---|
175 | }
|
---|
176 |
|
---|
177 | /* Look up SEARCH_STRING in the index for this file. If SEARCH_STRING
|
---|
178 | is NULL, prompt user for input. */
|
---|
179 | void
|
---|
180 | do_info_index_search (WINDOW *window, int count, char *search_string)
|
---|
181 | {
|
---|
182 | FILE_BUFFER *fb;
|
---|
183 | char *line;
|
---|
184 |
|
---|
185 | /* Reset the index offset, since this is not the info-index-next command. */
|
---|
186 | index_offset = 0;
|
---|
187 |
|
---|
188 | /* The user is selecting a new search string, so flush the old one. */
|
---|
189 | maybe_free (index_search);
|
---|
190 | index_search = (char *)NULL;
|
---|
191 |
|
---|
192 | /* If this window's file is not the same as the one that we last built an
|
---|
193 | index for, build and remember an index now. */
|
---|
194 | fb = file_buffer_of_window (window);
|
---|
195 | if (!initial_index_filename ||
|
---|
196 | (FILENAME_CMP (initial_index_filename, fb->filename) != 0))
|
---|
197 | {
|
---|
198 | info_free_references (index_index);
|
---|
199 | window_message_in_echo_area ((char *) _("Finding index entries..."),
|
---|
200 | NULL, NULL);
|
---|
201 | index_index = info_indices_of_file_buffer (fb);
|
---|
202 | }
|
---|
203 |
|
---|
204 | /* If there is no index, quit now. */
|
---|
205 | if (!index_index)
|
---|
206 | {
|
---|
207 | info_error ((char *) _("No indices found."), NULL, NULL);
|
---|
208 | return;
|
---|
209 | }
|
---|
210 |
|
---|
211 | /* Okay, there is an index. Look for SEARCH_STRING, or, if it is
|
---|
212 | empty, prompt for one. */
|
---|
213 | if (search_string && *search_string)
|
---|
214 | line = xstrdup (search_string);
|
---|
215 | else
|
---|
216 | {
|
---|
217 | line = info_read_maybe_completing (window, (char *) _("Index entry: "),
|
---|
218 | index_index);
|
---|
219 | window = active_window;
|
---|
220 |
|
---|
221 | /* User aborted? */
|
---|
222 | if (!line)
|
---|
223 | {
|
---|
224 | info_abort_key (active_window, 1, 0);
|
---|
225 | return;
|
---|
226 | }
|
---|
227 |
|
---|
228 | /* Empty line means move to the Index node. */
|
---|
229 | if (!*line)
|
---|
230 | {
|
---|
231 | free (line);
|
---|
232 |
|
---|
233 | if (initial_index_filename && initial_index_nodename)
|
---|
234 | {
|
---|
235 | NODE *node;
|
---|
236 |
|
---|
237 | node = info_get_node (initial_index_filename,
|
---|
238 | initial_index_nodename);
|
---|
239 | set_remembered_pagetop_and_point (window);
|
---|
240 | window_set_node_of_window (window, node);
|
---|
241 | remember_window_and_node (window, node);
|
---|
242 | window_clear_echo_area ();
|
---|
243 | return;
|
---|
244 | }
|
---|
245 | }
|
---|
246 | }
|
---|
247 |
|
---|
248 | /* The user typed either a completed index label, or a partial string.
|
---|
249 | Find an exact match, or, failing that, the first index entry containing
|
---|
250 | the partial string. So, we just call info_next_index_match () with minor
|
---|
251 | manipulation of INDEX_OFFSET. */
|
---|
252 | {
|
---|
253 | int old_offset;
|
---|
254 |
|
---|
255 | /* Start the search right after/before this index. */
|
---|
256 | if (count < 0)
|
---|
257 | {
|
---|
258 | register int i;
|
---|
259 | for (i = 0; index_index[i]; i++);
|
---|
260 | index_offset = i;
|
---|
261 | }
|
---|
262 | else
|
---|
263 | index_offset = -1;
|
---|
264 |
|
---|
265 | old_offset = index_offset;
|
---|
266 |
|
---|
267 | /* The "last" string searched for is this one. */
|
---|
268 | index_search = line;
|
---|
269 |
|
---|
270 | /* Find it, or error. */
|
---|
271 | info_next_index_match (window, count, 0);
|
---|
272 |
|
---|
273 | /* If the search failed, return the index offset to where it belongs. */
|
---|
274 | if (index_offset == old_offset)
|
---|
275 | index_offset = 0;
|
---|
276 | }
|
---|
277 | }
|
---|
278 |
|
---|
279 | int
|
---|
280 | index_entry_exists (WINDOW *window, char *string)
|
---|
281 | {
|
---|
282 | register int i;
|
---|
283 | FILE_BUFFER *fb;
|
---|
284 |
|
---|
285 | /* If there is no previous search string, the user hasn't built an index
|
---|
286 | yet. */
|
---|
287 | if (!string)
|
---|
288 | return 0;
|
---|
289 |
|
---|
290 | fb = file_buffer_of_window (window);
|
---|
291 | if (!initial_index_filename
|
---|
292 | || (FILENAME_CMP (initial_index_filename, fb->filename) != 0))
|
---|
293 | {
|
---|
294 | info_free_references (index_index);
|
---|
295 | index_index = info_indices_of_file_buffer (fb);
|
---|
296 | }
|
---|
297 |
|
---|
298 | /* If there is no index, that is an error. */
|
---|
299 | if (!index_index)
|
---|
300 | return 0;
|
---|
301 |
|
---|
302 | for (i = 0; (i > -1) && (index_index[i]); i++)
|
---|
303 | if (strcmp (string, index_index[i]->label) == 0)
|
---|
304 | break;
|
---|
305 |
|
---|
306 | /* If that failed, look for the next substring match. */
|
---|
307 | if ((i < 0) || (!index_index[i]))
|
---|
308 | {
|
---|
309 | for (i = 0; (i > -1) && (index_index[i]); i++)
|
---|
310 | if (string_in_line (string, index_index[i]->label) != -1)
|
---|
311 | break;
|
---|
312 |
|
---|
313 | if ((i > -1) && (index_index[i]))
|
---|
314 | string_in_line (string, index_index[i]->label);
|
---|
315 | }
|
---|
316 |
|
---|
317 | /* If that failed, return 0. */
|
---|
318 | if ((i < 0) || (!index_index[i]))
|
---|
319 | return 0;
|
---|
320 |
|
---|
321 | return 1;
|
---|
322 | }
|
---|
323 |
|
---|
324 | DECLARE_INFO_COMMAND (info_next_index_match,
|
---|
325 | _("Go to the next matching index item from the last `\\[index-search]' command"))
|
---|
326 | {
|
---|
327 | register int i;
|
---|
328 | int partial, dir;
|
---|
329 | NODE *node;
|
---|
330 |
|
---|
331 | /* If there is no previous search string, the user hasn't built an index
|
---|
332 | yet. */
|
---|
333 | if (!index_search)
|
---|
334 | {
|
---|
335 | info_error ((char *) _("No previous index search string."), NULL, NULL);
|
---|
336 | return;
|
---|
337 | }
|
---|
338 |
|
---|
339 | /* If there is no index, that is an error. */
|
---|
340 | if (!index_index)
|
---|
341 | {
|
---|
342 | info_error ((char *) _("No index entries."), NULL, NULL);
|
---|
343 | return;
|
---|
344 | }
|
---|
345 |
|
---|
346 | /* The direction of this search is controlled by the value of the
|
---|
347 | numeric argument. */
|
---|
348 | if (count < 0)
|
---|
349 | dir = -1;
|
---|
350 | else
|
---|
351 | dir = 1;
|
---|
352 |
|
---|
353 | /* Search for the next occurence of index_search. First try to find
|
---|
354 | an exact match. */
|
---|
355 | partial = 0;
|
---|
356 |
|
---|
357 | for (i = index_offset + dir; (i > -1) && (index_index[i]); i += dir)
|
---|
358 | if (strcmp (index_search, index_index[i]->label) == 0)
|
---|
359 | break;
|
---|
360 |
|
---|
361 | /* If that failed, look for the next substring match. */
|
---|
362 | if ((i < 0) || (!index_index[i]))
|
---|
363 | {
|
---|
364 | for (i = index_offset + dir; (i > -1) && (index_index[i]); i += dir)
|
---|
365 | if (string_in_line (index_search, index_index[i]->label) != -1)
|
---|
366 | break;
|
---|
367 |
|
---|
368 | if ((i > -1) && (index_index[i]))
|
---|
369 | partial = string_in_line (index_search, index_index[i]->label);
|
---|
370 | }
|
---|
371 |
|
---|
372 | /* If that failed, print an error. */
|
---|
373 | if ((i < 0) || (!index_index[i]))
|
---|
374 | {
|
---|
375 | info_error ((char *) _("No %sindex entries containing `%s'."),
|
---|
376 | index_offset > 0 ? (char *) _("more ") : "", index_search);
|
---|
377 | return;
|
---|
378 | }
|
---|
379 |
|
---|
380 | /* Okay, we found the next one. Move the offset to the current entry. */
|
---|
381 | index_offset = i;
|
---|
382 |
|
---|
383 | /* Report to the user on what we have found. */
|
---|
384 | {
|
---|
385 | register int j;
|
---|
386 | const char *name = _("CAN'T SEE THIS");
|
---|
387 | char *match;
|
---|
388 |
|
---|
389 | for (j = 0; index_nodenames[j]; j++)
|
---|
390 | {
|
---|
391 | if ((i >= index_nodenames[j]->first) &&
|
---|
392 | (i <= index_nodenames[j]->last))
|
---|
393 | {
|
---|
394 | name = index_nodenames[j]->name;
|
---|
395 | break;
|
---|
396 | }
|
---|
397 | }
|
---|
398 |
|
---|
399 | /* If we had a partial match, indicate to the user which part of the
|
---|
400 | string matched. */
|
---|
401 | match = xstrdup (index_index[i]->label);
|
---|
402 |
|
---|
403 | if (partial && show_index_match)
|
---|
404 | {
|
---|
405 | int k, ls, start, upper;
|
---|
406 |
|
---|
407 | ls = strlen (index_search);
|
---|
408 | start = partial - ls;
|
---|
409 | upper = isupper (match[start]) ? 1 : 0;
|
---|
410 |
|
---|
411 | for (k = 0; k < ls; k++)
|
---|
412 | if (upper)
|
---|
413 | match[k + start] = info_tolower (match[k + start]);
|
---|
414 | else
|
---|
415 | match[k + start] = info_toupper (match[k + start]);
|
---|
416 | }
|
---|
417 |
|
---|
418 | {
|
---|
419 | char *format;
|
---|
420 |
|
---|
421 | format = replace_in_documentation
|
---|
422 | ((char *) _("Found `%s' in %s. (`\\[next-index-match]' tries to find next.)"),
|
---|
423 | 0);
|
---|
424 |
|
---|
425 | window_message_in_echo_area (format, match, (char *) name);
|
---|
426 | }
|
---|
427 |
|
---|
428 | free (match);
|
---|
429 | }
|
---|
430 |
|
---|
431 | /* Select the node corresponding to this index entry. */
|
---|
432 | node = info_get_node (index_index[i]->filename, index_index[i]->nodename);
|
---|
433 |
|
---|
434 | if (!node)
|
---|
435 | {
|
---|
436 | info_error ((char *) msg_cant_file_node,
|
---|
437 | index_index[i]->filename, index_index[i]->nodename);
|
---|
438 | return;
|
---|
439 | }
|
---|
440 |
|
---|
441 | info_set_node_of_window (1, window, node);
|
---|
442 |
|
---|
443 | /* Try to find an occurence of LABEL in this node. */
|
---|
444 | {
|
---|
445 | long start, loc;
|
---|
446 |
|
---|
447 | start = window->line_starts[1] - window->node->contents;
|
---|
448 | loc = info_target_search_node (node, index_index[i]->label, start);
|
---|
449 |
|
---|
450 | if (loc != -1)
|
---|
451 | {
|
---|
452 | window->point = loc;
|
---|
453 | window_adjust_pagetop (window);
|
---|
454 | }
|
---|
455 | }
|
---|
456 | }
|
---|
457 | |
---|
458 |
|
---|
459 | /* **************************************************************** */
|
---|
460 | /* */
|
---|
461 | /* Info APROPOS: Search every known index. */
|
---|
462 | /* */
|
---|
463 | /* **************************************************************** */
|
---|
464 |
|
---|
465 | /* For every menu item in DIR, search the indices of that file for
|
---|
466 | SEARCH_STRING. */
|
---|
467 | REFERENCE **
|
---|
468 | apropos_in_all_indices (char *search_string, int inform)
|
---|
469 | {
|
---|
470 | register int i, dir_index;
|
---|
471 | REFERENCE **all_indices = (REFERENCE **)NULL;
|
---|
472 | REFERENCE **dir_menu = (REFERENCE **)NULL;
|
---|
473 | NODE *dir_node;
|
---|
474 |
|
---|
475 | dir_node = info_get_node ("dir", "Top");
|
---|
476 | if (dir_node)
|
---|
477 | dir_menu = info_menu_of_node (dir_node);
|
---|
478 |
|
---|
479 | if (!dir_menu)
|
---|
480 | return NULL;
|
---|
481 |
|
---|
482 | /* For every menu item in DIR, get the associated node's file buffer and
|
---|
483 | read the indices of that file buffer. Gather all of the indices into
|
---|
484 | one large one. */
|
---|
485 | for (dir_index = 0; dir_menu[dir_index]; dir_index++)
|
---|
486 | {
|
---|
487 | REFERENCE **this_index, *this_item;
|
---|
488 | NODE *this_node;
|
---|
489 | FILE_BUFFER *this_fb;
|
---|
490 | int dir_node_duplicated = 0;
|
---|
491 |
|
---|
492 | this_item = dir_menu[dir_index];
|
---|
493 |
|
---|
494 | if (!this_item->filename)
|
---|
495 | {
|
---|
496 | dir_node_duplicated = 1;
|
---|
497 | if (dir_node->parent)
|
---|
498 | this_item->filename = xstrdup (dir_node->parent);
|
---|
499 | else
|
---|
500 | this_item->filename = xstrdup (dir_node->filename);
|
---|
501 | }
|
---|
502 |
|
---|
503 | /* Find this node. If we cannot find it, try using the label of the
|
---|
504 | entry as a file (i.e., "(LABEL)Top"). */
|
---|
505 | this_node = info_get_node (this_item->filename, this_item->nodename);
|
---|
506 |
|
---|
507 | if (!this_node && this_item->nodename &&
|
---|
508 | (strcmp (this_item->label, this_item->nodename) == 0))
|
---|
509 | this_node = info_get_node (this_item->label, "Top");
|
---|
510 |
|
---|
511 | if (!this_node)
|
---|
512 | {
|
---|
513 | if (dir_node_duplicated)
|
---|
514 | free (this_item->filename);
|
---|
515 | continue;
|
---|
516 | }
|
---|
517 |
|
---|
518 | /* Get the file buffer associated with this node. */
|
---|
519 | {
|
---|
520 | char *files_name;
|
---|
521 |
|
---|
522 | files_name = this_node->parent;
|
---|
523 | if (!files_name)
|
---|
524 | files_name = this_node->filename;
|
---|
525 |
|
---|
526 | this_fb = info_find_file (files_name);
|
---|
527 |
|
---|
528 | /* If we already scanned this file, don't do that again.
|
---|
529 | In addition to being faster, this also avoids having
|
---|
530 | multiple identical entries in the *Apropos* menu. */
|
---|
531 | for (i = 0; i < dir_index; i++)
|
---|
532 | if (FILENAME_CMP (this_fb->filename, dir_menu[i]->filename) == 0)
|
---|
533 | break;
|
---|
534 | if (i < dir_index)
|
---|
535 | {
|
---|
536 | if (dir_node_duplicated)
|
---|
537 | free (this_item->filename);
|
---|
538 | continue;
|
---|
539 | }
|
---|
540 |
|
---|
541 | if (this_fb && inform)
|
---|
542 | message_in_echo_area ((char *) _("Scanning indices of `%s'..."),
|
---|
543 | files_name, NULL);
|
---|
544 |
|
---|
545 | this_index = info_indices_of_file_buffer (this_fb);
|
---|
546 | free (this_node);
|
---|
547 |
|
---|
548 | if (this_fb && inform)
|
---|
549 | unmessage_in_echo_area ();
|
---|
550 | }
|
---|
551 |
|
---|
552 | if (this_index)
|
---|
553 | {
|
---|
554 | /* Remember the filename which contains this set of references. */
|
---|
555 | for (i = 0; this_index && this_index[i]; i++)
|
---|
556 | if (!this_index[i]->filename)
|
---|
557 | this_index[i]->filename = xstrdup (this_fb->filename);
|
---|
558 |
|
---|
559 | /* Concatenate with the other indices. */
|
---|
560 | all_indices = info_concatenate_references (all_indices, this_index);
|
---|
561 | }
|
---|
562 | }
|
---|
563 |
|
---|
564 | info_free_references (dir_menu);
|
---|
565 |
|
---|
566 | /* Build a list of the references which contain SEARCH_STRING. */
|
---|
567 | if (all_indices)
|
---|
568 | {
|
---|
569 | REFERENCE *entry, **apropos_list = (REFERENCE **)NULL;
|
---|
570 | int apropos_list_index = 0;
|
---|
571 | int apropos_list_slots = 0;
|
---|
572 |
|
---|
573 | for (i = 0; (entry = all_indices[i]); i++)
|
---|
574 | {
|
---|
575 | if (string_in_line (search_string, entry->label) != -1)
|
---|
576 | {
|
---|
577 | add_pointer_to_array
|
---|
578 | (entry, apropos_list_index, apropos_list, apropos_list_slots,
|
---|
579 | 100, REFERENCE *);
|
---|
580 | }
|
---|
581 | else
|
---|
582 | {
|
---|
583 | maybe_free (entry->label);
|
---|
584 | maybe_free (entry->filename);
|
---|
585 | maybe_free (entry->nodename);
|
---|
586 | free (entry);
|
---|
587 | }
|
---|
588 | }
|
---|
589 |
|
---|
590 | free (all_indices);
|
---|
591 | all_indices = apropos_list;
|
---|
592 | }
|
---|
593 | return (all_indices);
|
---|
594 | }
|
---|
595 |
|
---|
596 | #define APROPOS_NONE \
|
---|
597 | N_("No available info files have `%s' in their indices.")
|
---|
598 |
|
---|
599 | void
|
---|
600 | info_apropos (char *string)
|
---|
601 | {
|
---|
602 | REFERENCE **apropos_list;
|
---|
603 |
|
---|
604 | apropos_list = apropos_in_all_indices (string, 0);
|
---|
605 |
|
---|
606 | if (!apropos_list)
|
---|
607 | info_error ((char *) _(APROPOS_NONE), string, NULL);
|
---|
608 | else
|
---|
609 | {
|
---|
610 | register int i;
|
---|
611 | REFERENCE *entry;
|
---|
612 |
|
---|
613 | for (i = 0; (entry = apropos_list[i]); i++)
|
---|
614 | fprintf (stdout, "\"(%s)%s\" -- %s\n",
|
---|
615 | entry->filename, entry->nodename, entry->label);
|
---|
616 | }
|
---|
617 | info_free_references (apropos_list);
|
---|
618 | }
|
---|
619 |
|
---|
620 | static char *apropos_list_nodename = "*Apropos*";
|
---|
621 |
|
---|
622 | DECLARE_INFO_COMMAND (info_index_apropos,
|
---|
623 | _("Grovel all known info file's indices for a string and build a menu"))
|
---|
624 | {
|
---|
625 | char *line;
|
---|
626 |
|
---|
627 | line = info_read_in_echo_area (window, (char *) _("Index apropos: "));
|
---|
628 |
|
---|
629 | window = active_window;
|
---|
630 |
|
---|
631 | /* User aborted? */
|
---|
632 | if (!line)
|
---|
633 | {
|
---|
634 | info_abort_key (window, 1, 1);
|
---|
635 | return;
|
---|
636 | }
|
---|
637 |
|
---|
638 | /* User typed something? */
|
---|
639 | if (*line)
|
---|
640 | {
|
---|
641 | REFERENCE **apropos_list;
|
---|
642 | NODE *apropos_node;
|
---|
643 |
|
---|
644 | apropos_list = apropos_in_all_indices (line, 1);
|
---|
645 |
|
---|
646 | if (!apropos_list)
|
---|
647 | info_error ((char *) _(APROPOS_NONE), line, NULL);
|
---|
648 | else
|
---|
649 | {
|
---|
650 | register int i;
|
---|
651 | char *line_buffer;
|
---|
652 |
|
---|
653 | initialize_message_buffer ();
|
---|
654 | printf_to_message_buffer
|
---|
655 | ((char *) _("\n* Menu: Nodes whose indices contain `%s':\n"),
|
---|
656 | line, NULL, NULL);
|
---|
657 | line_buffer = (char *)xmalloc (500);
|
---|
658 |
|
---|
659 | for (i = 0; apropos_list[i]; i++)
|
---|
660 | {
|
---|
661 | int len;
|
---|
662 | /* The label might be identical to that of another index
|
---|
663 | entry in another Info file. Therefore, we make the file
|
---|
664 | name part of the menu entry, to make them all distinct. */
|
---|
665 | sprintf (line_buffer, "* %s [%s]: ",
|
---|
666 | apropos_list[i]->label, apropos_list[i]->filename);
|
---|
667 | len = pad_to (40, line_buffer);
|
---|
668 | sprintf (line_buffer + len, "(%s)%s.",
|
---|
669 | apropos_list[i]->filename, apropos_list[i]->nodename);
|
---|
670 | printf_to_message_buffer ("%s\n", line_buffer, NULL, NULL);
|
---|
671 | }
|
---|
672 | free (line_buffer);
|
---|
673 | }
|
---|
674 |
|
---|
675 | apropos_node = message_buffer_to_node ();
|
---|
676 | add_gcable_pointer (apropos_node->contents);
|
---|
677 | name_internal_node (apropos_node, apropos_list_nodename);
|
---|
678 |
|
---|
679 | /* Even though this is an internal node, we don't want the window
|
---|
680 | system to treat it specially. So we turn off the internalness
|
---|
681 | of it here. */
|
---|
682 | apropos_node->flags &= ~N_IsInternal;
|
---|
683 |
|
---|
684 | /* Find/Create a window to contain this node. */
|
---|
685 | {
|
---|
686 | WINDOW *new;
|
---|
687 | NODE *node;
|
---|
688 |
|
---|
689 | set_remembered_pagetop_and_point (window);
|
---|
690 |
|
---|
691 | /* If a window is visible and showing an apropos list already,
|
---|
692 | re-use it. */
|
---|
693 | for (new = windows; new; new = new->next)
|
---|
694 | {
|
---|
695 | node = new->node;
|
---|
696 |
|
---|
697 | if (internal_info_node_p (node) &&
|
---|
698 | (strcmp (node->nodename, apropos_list_nodename) == 0))
|
---|
699 | break;
|
---|
700 | }
|
---|
701 |
|
---|
702 | /* If we couldn't find an existing window, try to use the next window
|
---|
703 | in the chain. */
|
---|
704 | if (!new && window->next)
|
---|
705 | new = window->next;
|
---|
706 |
|
---|
707 | /* If we still don't have a window, make a new one to contain
|
---|
708 | the list. */
|
---|
709 | if (!new)
|
---|
710 | {
|
---|
711 | WINDOW *old_active;
|
---|
712 |
|
---|
713 | old_active = active_window;
|
---|
714 | active_window = window;
|
---|
715 | new = window_make_window ((NODE *)NULL);
|
---|
716 | active_window = old_active;
|
---|
717 | }
|
---|
718 |
|
---|
719 | /* If we couldn't make a new window, use this one. */
|
---|
720 | if (!new)
|
---|
721 | new = window;
|
---|
722 |
|
---|
723 | /* Lines do not wrap in this window. */
|
---|
724 | new->flags |= W_NoWrap;
|
---|
725 |
|
---|
726 | window_set_node_of_window (new, apropos_node);
|
---|
727 | remember_window_and_node (new, apropos_node);
|
---|
728 | active_window = new;
|
---|
729 | }
|
---|
730 | info_free_references (apropos_list);
|
---|
731 | }
|
---|
732 | free (line);
|
---|
733 |
|
---|
734 | if (!info_error_was_printed)
|
---|
735 | window_clear_echo_area ();
|
---|
736 | }
|
---|