File: | src/gnu/usr.bin/texinfo/info/indices.c |
Warning: | line 531, column 8 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 && *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 < 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'.")((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 | } |