File: | src/gnu/usr.bin/texinfo/info/indices.c |
Warning: | line 358, column 9 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* indices.c -- deal with an Info file index. | |||
2 | $Id: indices.c,v 1.5 2006/07/17 16:12:36 espie 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((void *)0); | |||
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((void *)0); | |||
38 | ||||
39 | /* A couple of "globals" describing where the initial index was found. */ | |||
40 | static char *initial_index_filename = (char *)NULL((void *)0); | |||
41 | static char *initial_index_nodename = (char *)NULL((void *)0); | |||
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((void *)0); | |||
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_arraydo { if (index_nodenames_index + 2 >= index_nodenames_slots ) index_nodenames = (INDEX_NAME_ASSOC * *)(xrealloc (index_nodenames , (index_nodenames_slots += 10) * sizeof (INDEX_NAME_ASSOC *) )); index_nodenames[index_nodenames_index++] = (INDEX_NAME_ASSOC *)assoc; index_nodenames[index_nodenames_index] = (INDEX_NAME_ASSOC *)((void *)0); } while (0) | |||
79 | (assoc, index_nodenames_index, index_nodenames, index_nodenames_slots,do { if (index_nodenames_index + 2 >= index_nodenames_slots ) index_nodenames = (INDEX_NAME_ASSOC * *)(xrealloc (index_nodenames , (index_nodenames_slots += 10) * sizeof (INDEX_NAME_ASSOC *) )); index_nodenames[index_nodenames_index++] = (INDEX_NAME_ASSOC *)assoc; index_nodenames[index_nodenames_index] = (INDEX_NAME_ASSOC *)((void *)0); } while (0) | |||
80 | 10, INDEX_NAME_ASSOC *)do { if (index_nodenames_index + 2 >= index_nodenames_slots ) index_nodenames = (INDEX_NAME_ASSOC * *)(xrealloc (index_nodenames , (index_nodenames_slots += 10) * sizeof (INDEX_NAME_ASSOC *) )); index_nodenames[index_nodenames_index++] = (INDEX_NAME_ASSOC *)assoc; index_nodenames[index_nodenames_index] = (INDEX_NAME_ASSOC *)((void *)0); } while (0); | |||
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((void *)0); | |||
103 | ||||
104 | /* No file buffer, no indices. */ | |||
105 | if (!file_buffer) | |||
106 | return ((REFERENCE **)NULL((void *)0)); | |||
107 | ||||
108 | /* Reset globals describing where the index was found. */ | |||
109 | maybe_free (initial_index_filename)do { if (initial_index_filename) free (initial_index_filename ); } while (0); | |||
110 | maybe_free (initial_index_nodename)do { if (initial_index_nodename) free (initial_index_nodename ); } while (0); | |||
111 | initial_index_filename = (char *)NULL((void *)0); | |||
112 | initial_index_nodename = (char *)NULL((void *)0); | |||
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((void *)0); | |||
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,void info_index_search (WINDOW *window, int count, unsigned char key) | |||
172 | _("Look up a string in the index for this file"))void info_index_search (WINDOW *window, int count, unsigned char key) | |||
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)do { if (index_search) free (index_search); } while (0); | |||
190 | index_search = (char *)NULL((void *)0); | |||
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_CMPstrcmp (initial_index_filename, fb->filename) != 0)) | |||
197 | { | |||
198 | info_free_references (index_index); | |||
199 | window_message_in_echo_area ((char *) _("Finding index entries...")((const char *) ("Finding index entries...")), | |||
200 | NULL((void *)0), NULL((void *)0)); | |||
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.")((const char *) ("No indices found.")), NULL((void *)0), NULL((void *)0)); | |||
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
| |||
214 | line = xstrdup (search_string); | |||
215 | else | |||
216 | { | |||
217 | line = info_read_maybe_completing (window, (char *) _("Index entry: ")((const 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_CMPstrcmp (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,void info_next_index_match (WINDOW *window, int count, unsigned char key) | |||
325 | _("Go to the next matching index item from the last `\\[index-search]' command"))void info_next_index_match (WINDOW *window, int count, unsigned char key) | |||
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.")((const char *) ("No previous index search string.")), NULL((void *)0), NULL((void *)0)); | |||
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.")((const char *) ("No index entries.")), NULL((void *)0), NULL((void *)0)); | |||
343 | return; | |||
344 | } | |||
345 | ||||
346 | /* The direction of this search is controlled by the value of the | |||
347 | numeric argument. */ | |||
348 | if (count
| |||
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'.")((const char *) ("No %sindex entries containing `%s'.")), | |||
376 | index_offset > 0 ? (char *) _("more ")((const 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")((const char *) ("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])(isupper (match[k + start]) ? tolower (match[k + start]) : match [k + start]); | |||
414 | else | |||
415 | match[k + start] = info_toupper (match[k + start])(islower (match[k + start]) ? toupper (match[k + start]) : 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.)")((const 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 | /* Info APROPOS: Search every known index. */ | |||
461 | /* */ | |||
462 | /* **************************************************************** */ | |||
463 | ||||
464 | /* For every menu item in DIR, search the indices of that file for | |||
465 | SEARCH_STRING. */ | |||
466 | REFERENCE ** | |||
467 | apropos_in_all_indices (char *search_string, int inform) | |||
468 | { | |||
469 | register int i, dir_index; | |||
470 | REFERENCE **all_indices = (REFERENCE **)NULL((void *)0); | |||
471 | REFERENCE **dir_menu = (REFERENCE **)NULL((void *)0); | |||
472 | NODE *dir_node; | |||
473 | ||||
474 | dir_node = info_get_node ("dir", "Top"); | |||
475 | if (dir_node) | |||
476 | dir_menu = info_menu_of_node (dir_node); | |||
477 | ||||
478 | if (!dir_menu) | |||
479 | return NULL((void *)0); | |||
480 | ||||
481 | /* For every menu item in DIR, get the associated node's file buffer and | |||
482 | read the indices of that file buffer. Gather all of the indices into | |||
483 | one large one. */ | |||
484 | for (dir_index = 0; dir_menu[dir_index]; dir_index++) | |||
485 | { | |||
486 | REFERENCE **this_index, *this_item; | |||
487 | NODE *this_node; | |||
488 | FILE_BUFFER *this_fb; | |||
489 | int dir_node_duplicated = 0; | |||
490 | ||||
491 | this_item = dir_menu[dir_index]; | |||
492 | ||||
493 | if (!this_item->filename) | |||
494 | { | |||
495 | dir_node_duplicated = 1; | |||
496 | if (dir_node->parent) | |||
497 | this_item->filename = xstrdup (dir_node->parent); | |||
498 | else | |||
499 | this_item->filename = xstrdup (dir_node->filename); | |||
500 | } | |||
501 | ||||
502 | /* Find this node. If we cannot find it, try using the label of the | |||
503 | entry as a file (i.e., "(LABEL)Top"). */ | |||
504 | this_node = info_get_node (this_item->filename, this_item->nodename); | |||
505 | ||||
506 | if (!this_node && this_item->nodename && | |||
507 | (strcmp (this_item->label, this_item->nodename) == 0)) | |||
508 | this_node = info_get_node (this_item->label, "Top"); | |||
509 | ||||
510 | if (!this_node) | |||
511 | { | |||
512 | if (dir_node_duplicated) | |||
513 | free (this_item->filename); | |||
514 | continue; | |||
515 | } | |||
516 | ||||
517 | /* Get the file buffer associated with this node. */ | |||
518 | { | |||
519 | char *files_name; | |||
520 | ||||
521 | files_name = this_node->parent; | |||
522 | if (!files_name) | |||
523 | files_name = this_node->filename; | |||
524 | ||||
525 | this_fb = info_find_file (files_name); | |||
526 | ||||
527 | /* If we already scanned this file, don't do that again. | |||
528 | In addition to being faster, this also avoids having | |||
529 | multiple identical entries in the *Apropos* menu. */ | |||
530 | for (i = 0; i < dir_index; i++) | |||
531 | if (FILENAME_CMPstrcmp (this_fb->filename, dir_menu[i]->filename) == 0) | |||
532 | break; | |||
533 | if (i < dir_index) | |||
534 | { | |||
535 | if (dir_node_duplicated) | |||
536 | free (this_item->filename); | |||
537 | continue; | |||
538 | } | |||
539 | ||||
540 | if (this_fb && inform) | |||
541 | message_in_echo_area ((char *) _("Scanning indices of `%s'...")((const char *) ("Scanning indices of `%s'...")), | |||
542 | files_name, NULL((void *)0)); | |||
543 | ||||
544 | this_index = info_indices_of_file_buffer (this_fb); | |||
545 | free (this_node); | |||
546 | ||||
547 | if (this_fb && inform) | |||
548 | unmessage_in_echo_area (); | |||
549 | } | |||
550 | ||||
551 | if (this_index) | |||
552 | { | |||
553 | /* Remember the filename which contains this set of references. */ | |||
554 | for (i = 0; this_index && this_index[i]; i++) | |||
555 | if (!this_index[i]->filename) | |||
556 | this_index[i]->filename = xstrdup (this_fb->filename); | |||
557 | ||||
558 | /* Concatenate with the other indices. */ | |||
559 | all_indices = info_concatenate_references (all_indices, this_index); | |||
560 | } | |||
561 | } | |||
562 | ||||
563 | info_free_references (dir_menu); | |||
564 | ||||
565 | /* Build a list of the references which contain SEARCH_STRING. */ | |||
566 | if (all_indices) | |||
567 | { | |||
568 | REFERENCE *entry, **apropos_list = (REFERENCE **)NULL((void *)0); | |||
569 | int apropos_list_index = 0; | |||
570 | int apropos_list_slots = 0; | |||
571 | ||||
572 | for (i = 0; (entry = all_indices[i]); i++) | |||
573 | { | |||
574 | if (string_in_line (search_string, entry->label) != -1) | |||
575 | { | |||
576 | add_pointer_to_arraydo { if (apropos_list_index + 2 >= apropos_list_slots) apropos_list = (REFERENCE * *)(xrealloc (apropos_list, (apropos_list_slots += 100) * sizeof (REFERENCE *))); apropos_list[apropos_list_index ++] = (REFERENCE *)entry; apropos_list[apropos_list_index] = ( REFERENCE *)((void *)0); } while (0) | |||
577 | (entry, apropos_list_index, apropos_list, apropos_list_slots,do { if (apropos_list_index + 2 >= apropos_list_slots) apropos_list = (REFERENCE * *)(xrealloc (apropos_list, (apropos_list_slots += 100) * sizeof (REFERENCE *))); apropos_list[apropos_list_index ++] = (REFERENCE *)entry; apropos_list[apropos_list_index] = ( REFERENCE *)((void *)0); } while (0) | |||
578 | 100, REFERENCE *)do { if (apropos_list_index + 2 >= apropos_list_slots) apropos_list = (REFERENCE * *)(xrealloc (apropos_list, (apropos_list_slots += 100) * sizeof (REFERENCE *))); apropos_list[apropos_list_index ++] = (REFERENCE *)entry; apropos_list[apropos_list_index] = ( REFERENCE *)((void *)0); } while (0); | |||
579 | } | |||
580 | else | |||
581 | { | |||
582 | maybe_free (entry->label)do { if (entry->label) free (entry->label); } while (0); | |||
583 | maybe_free (entry->filename)do { if (entry->filename) free (entry->filename); } while (0); | |||
584 | maybe_free (entry->nodename)do { if (entry->nodename) free (entry->nodename); } while (0); | |||
585 | free (entry); | |||
586 | } | |||
587 | } | |||
588 | ||||
589 | free (all_indices); | |||
590 | all_indices = apropos_list; | |||
591 | } | |||
592 | return (all_indices); | |||
593 | } | |||
594 | ||||
595 | #define APROPOS_NONE("No available info files have `%s' in their indices.") \ | |||
596 | N_("No available info files have `%s' in their indices.")("No available info files have `%s' in their indices.") | |||
597 | ||||
598 | void | |||
599 | info_apropos (char *string) | |||
600 | { | |||
601 | REFERENCE **apropos_list; | |||
602 | ||||
603 | apropos_list = apropos_in_all_indices (string, 0); | |||
604 | ||||
605 | if (!apropos_list) | |||
606 | info_error ((char *) _(APROPOS_NONE)((const char *) (("No available info files have `%s' in their indices." ))), string, NULL((void *)0)); | |||
607 | else | |||
608 | { | |||
609 | register int i; | |||
610 | REFERENCE *entry; | |||
611 | ||||
612 | for (i = 0; (entry = apropos_list[i]); i++) | |||
613 | fprintf (stdout(&__sF[1]), "\"(%s)%s\" -- %s\n", | |||
614 | entry->filename, entry->nodename, entry->label); | |||
615 | } | |||
616 | info_free_references (apropos_list); | |||
617 | } | |||
618 | ||||
619 | static char *apropos_list_nodename = "*Apropos*"; | |||
620 | ||||
621 | DECLARE_INFO_COMMAND (info_index_apropos,void info_index_apropos (WINDOW *window, int count, unsigned char key) | |||
622 | _("Grovel all known info file's indices for a string and build a menu"))void info_index_apropos (WINDOW *window, int count, unsigned char key) | |||
623 | { | |||
624 | char *line; | |||
625 | ||||
626 | line = info_read_in_echo_area (window, (char *) _("Index apropos: ")((const char *) ("Index apropos: "))); | |||
627 | ||||
628 | window = active_window; | |||
629 | ||||
630 | /* User aborted? */ | |||
631 | if (!line) | |||
632 | { | |||
633 | info_abort_key (window, 1, 1); | |||
634 | return; | |||
635 | } | |||
636 | ||||
637 | /* User typed something? */ | |||
638 | if (*line) | |||
639 | { | |||
640 | REFERENCE **apropos_list; | |||
641 | NODE *apropos_node; | |||
642 | ||||
643 | apropos_list = apropos_in_all_indices (line, 1); | |||
644 | ||||
645 | if (!apropos_list) | |||
646 | info_error ((char *) _(APROPOS_NONE)((const char *) (("No available info files have `%s' in their indices." ))), line, NULL((void *)0)); | |||
647 | else | |||
648 | { | |||
649 | register int i; | |||
650 | char *line_buffer; | |||
651 | ||||
652 | initialize_message_buffer (); | |||
653 | printf_to_message_buffer | |||
654 | ((char *) _("\n* Menu: Nodes whose indices contain `%s':\n")((const char *) ("\n* Menu: Nodes whose indices contain `%s':\n" )), | |||
655 | line, NULL((void *)0), NULL((void *)0)); | |||
656 | line_buffer = (char *)xmalloc (500); | |||
657 | ||||
658 | for (i = 0; apropos_list[i]; i++) | |||
659 | { | |||
660 | int len; | |||
661 | /* The label might be identical to that of another index | |||
662 | entry in another Info file. Therefore, we make the file | |||
663 | name part of the menu entry, to make them all distinct. */ | |||
664 | sprintf (line_buffer, "* %s [%s]: ", | |||
665 | apropos_list[i]->label, apropos_list[i]->filename); | |||
666 | len = pad_to (40, line_buffer); | |||
667 | sprintf (line_buffer + len, "(%s)%s.", | |||
668 | apropos_list[i]->filename, apropos_list[i]->nodename); | |||
669 | printf_to_message_buffer ("%s\n", line_buffer, NULL((void *)0), NULL((void *)0)); | |||
670 | } | |||
671 | free (line_buffer); | |||
672 | } | |||
673 | ||||
674 | apropos_node = message_buffer_to_node (); | |||
675 | add_gcable_pointer (apropos_node->contents); | |||
676 | name_internal_node (apropos_node, apropos_list_nodename); | |||
677 | ||||
678 | /* Even though this is an internal node, we don't want the window | |||
679 | system to treat it specially. So we turn off the internalness | |||
680 | of it here. */ | |||
681 | apropos_node->flags &= ~N_IsInternal0x10; | |||
682 | ||||
683 | /* Find/Create a window to contain this node. */ | |||
684 | { | |||
685 | WINDOW *new; | |||
686 | NODE *node; | |||
687 | ||||
688 | set_remembered_pagetop_and_point (window); | |||
689 | ||||
690 | /* If a window is visible and showing an apropos list already, | |||
691 | re-use it. */ | |||
692 | for (new = windows; new; new = new->next) | |||
693 | { | |||
694 | node = new->node; | |||
695 | ||||
696 | if (internal_info_node_p (node) && | |||
697 | (strcmp (node->nodename, apropos_list_nodename) == 0)) | |||
698 | break; | |||
699 | } | |||
700 | ||||
701 | /* If we couldn't find an existing window, try to use the next window | |||
702 | in the chain. */ | |||
703 | if (!new && window->next) | |||
704 | new = window->next; | |||
705 | ||||
706 | /* If we still don't have a window, make a new one to contain | |||
707 | the list. */ | |||
708 | if (!new) | |||
709 | { | |||
710 | WINDOW *old_active; | |||
711 | ||||
712 | old_active = active_window; | |||
713 | active_window = window; | |||
714 | new = window_make_window ((NODE *)NULL((void *)0)); | |||
715 | active_window = old_active; | |||
716 | } | |||
717 | ||||
718 | /* If we couldn't make a new window, use this one. */ | |||
719 | if (!new) | |||
720 | new = window; | |||
721 | ||||
722 | /* Lines do not wrap in this window. */ | |||
723 | new->flags |= W_NoWrap0x10; | |||
724 | ||||
725 | window_set_node_of_window (new, apropos_node); | |||
726 | remember_window_and_node (new, apropos_node); | |||
727 | active_window = new; | |||
728 | } | |||
729 | info_free_references (apropos_list); | |||
730 | } | |||
731 | free (line); | |||
732 | ||||
733 | if (!info_error_was_printed) | |||
734 | window_clear_echo_area (); | |||
735 | } |