Reduce differences between our VKERNEL and VKERNEL64 configurations.
[dragonfly.git] / contrib / texinfo / info / nodemenu.c
blob9b46014537c91cef518b1d66366e7f7163992003
1 /* nodemenu.c -- produce a menu of all visited nodes.
2 $Id: nodemenu.c,v 1.11 2008/06/11 09:55:42 gray Exp $
4 Copyright (C) 1993, 1997, 1998, 2002, 2003, 2004, 2007, 2008
5 Free Software Foundation, Inc.
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 3 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 Written by Brian Fox (bfox@ai.mit.edu). */
22 #include "info.h"
24 NODE * get_visited_nodes (Function *filter_func);
26 /* Return a line describing the format of a node information line. */
27 static const char *
28 nodemenu_format_info (void)
30 return _("\n\
31 * Menu:\n\
32 (File)Node Lines Size Containing File\n\
33 ---------- ----- ---- ---------------");
36 /* Produce a formatted line of information about NODE. Here is what we want
37 the output listing to look like:
39 * Menu:
40 (File)Node Lines Size Containing File
41 ---------- ----- ---- ---------------
42 * (emacs)Buffers:: 48 2230 /usr/gnu/info/emacs/emacs-1
43 * (autoconf)Writing configure.in:: 123 58789 /usr/gnu/info/autoconf/autoconf-1
44 * (dir)Top:: 40 589 /usr/gnu/info/dir
46 static char *
47 format_node_info (NODE *node)
49 register int i, len;
50 char *parent, *containing_file;
51 static char *line_buffer = NULL;
53 if (!line_buffer)
54 line_buffer = xmalloc (1000);
56 if (node->parent)
58 parent = filename_non_directory (node->parent);
59 if (!parent)
60 parent = node->parent;
62 else
63 parent = NULL;
65 containing_file = node->filename;
67 if (!parent && !*containing_file)
68 sprintf (line_buffer, "* %s::", node->nodename);
69 else
71 char *file = NULL;
73 if (parent)
74 file = parent;
75 else
76 file = filename_non_directory (containing_file);
78 if (!file)
79 file = containing_file;
81 if (!*file)
82 file = "dir";
84 sprintf (line_buffer, "* (%s)%s::", file, node->nodename);
87 len = pad_to (36, line_buffer);
90 int lines = 1;
92 for (i = 0; i < node->nodelen; i++)
93 if (node->contents[i] == '\n')
94 lines++;
96 sprintf (line_buffer + len, "%d", lines);
99 len = pad_to (44, line_buffer);
100 sprintf (line_buffer + len, "%ld", node->nodelen);
102 if (node->filename && *(node->filename))
104 len = pad_to (51, line_buffer);
105 strcpy (line_buffer + len, node->filename);
108 return xstrdup (line_buffer);
111 /* Little string comparison routine for qsort (). */
112 static int
113 compare_strings (const void *entry1, const void *entry2)
115 char **e1 = (char **) entry1;
116 char **e2 = (char **) entry2;
118 return mbscasecmp (*e1, *e2);
121 /* The name of the nodemenu node. */
122 static char *nodemenu_nodename = "*Node Menu*";
124 /* Produce an informative listing of all the visited nodes, and return it
125 in a node. If FILTER_FUNC is non-null, it is a function which filters
126 which nodes will appear in the listing. FILTER_FUNC takes an argument
127 of NODE, and returns non-zero if the node should appear in the listing. */
128 NODE *
129 get_visited_nodes (Function *filter_func)
131 register int i, iw_index;
132 INFO_WINDOW *info_win;
133 NODE *node;
134 char **lines = NULL;
135 int lines_index = 0, lines_slots = 0;
137 if (!info_windows)
138 return NULL;
140 for (iw_index = 0; (info_win = info_windows[iw_index]); iw_index++)
142 for (i = 0; i < info_win->nodes_index; i++)
144 node = info_win->nodes[i];
146 /* We skip mentioning "*Node Menu*" nodes. */
147 if (internal_info_node_p (node) &&
148 (strcmp (node->nodename, nodemenu_nodename) == 0))
149 continue;
151 if (node && (!filter_func || (*filter_func) (node)))
153 char *line;
155 line = format_node_info (node);
156 add_pointer_to_array
157 (line, lines_index, lines, lines_slots, 20, char *);
162 /* Sort the array of information lines, if there are any. */
163 if (lines)
165 register int j, newlen;
166 char **temp;
168 qsort (lines, lines_index, sizeof (char *), compare_strings);
170 /* Delete duplicates. */
171 for (i = 0, newlen = 1; i < lines_index - 1; i++)
173 /* Use FILENAME_CMP here, since the most important piece
174 of info in each line is the file name of the node. */
175 if (FILENAME_CMP (lines[i], lines[i + 1]) == 0)
177 free (lines[i]);
178 lines[i] = NULL;
180 else
181 newlen++;
184 /* We have free ()'d and marked all of the duplicate slots.
185 Copy the live slots rather than pruning the dead slots. */
186 temp = xmalloc ((1 + newlen) * sizeof (char *));
187 for (i = 0, j = 0; i < lines_index; i++)
188 if (lines[i])
189 temp[j++] = lines[i];
191 temp[j] = NULL;
192 free (lines);
193 lines = temp;
194 lines_index = newlen;
197 initialize_message_buffer ();
199 printf_to_message_buffer
200 ("%s", replace_in_documentation
201 (_("Here is the menu of nodes you have recently visited.\n\
202 Select one from this menu, or use `\\[history-node]' in another window.\n"), 0),
203 NULL, NULL);
205 printf_to_message_buffer ("%s\n", (char *) nodemenu_format_info (),
206 NULL, NULL);
208 for (i = 0; (lines != NULL) && (i < lines_index); i++)
210 printf_to_message_buffer ("%s\n", lines[i], NULL, NULL);
211 free (lines[i]);
214 if (lines)
215 free (lines);
217 node = message_buffer_to_node ();
218 add_gcable_pointer (node->contents);
219 return node;
222 DECLARE_INFO_COMMAND (list_visited_nodes,
223 _("Make a window containing a menu of all of the currently visited nodes"))
225 WINDOW *new;
226 NODE *node;
228 set_remembered_pagetop_and_point (window);
230 /* If a window is visible and showing the buffer list already, re-use it. */
231 for (new = windows; new; new = new->next)
233 node = new->node;
235 if (internal_info_node_p (node) &&
236 (strcmp (node->nodename, nodemenu_nodename) == 0))
237 break;
240 /* If we couldn't find an existing window, try to use the next window
241 in the chain. */
242 if (!new)
244 if (window->next)
245 new = window->next;
246 /* If there is more than one window, wrap around. */
247 else if (window != windows)
248 new = windows;
251 /* If we still don't have a window, make a new one to contain the list. */
252 if (!new)
254 WINDOW *old_active;
256 old_active = active_window;
257 active_window = window;
258 new = window_make_window (NULL);
259 active_window = old_active;
262 /* If we couldn't make a new window, use this one. */
263 if (!new)
264 new = window;
266 /* Lines do not wrap in this window. */
267 new->flags |= W_NoWrap;
268 node = get_visited_nodes (NULL);
269 name_internal_node (node, nodemenu_nodename);
271 #if 0
272 /* Even if this is an internal node, we don't want the window
273 system to treat it specially. So we turn off the internalness
274 of it here. */
275 /* Why? We depend on internal_info_node_p returning true, so we must
276 not remove the flag. Otherwise, the *Node Menu* nodes themselves
277 appear in the node menu. --Andreas Schwab
278 <schwab@issan.informatik.uni-dortmund.de>. */
279 node->flags &= ~N_IsInternal;
280 #endif
282 /* If this window is already showing a node menu, reuse the existing node
283 slot. */
285 int remember_me = 1;
287 #if defined (NOTDEF)
288 if (internal_info_node_p (new->node) &&
289 (strcmp (new->node->nodename, nodemenu_nodename) == 0))
290 remember_me = 0;
291 #endif /* NOTDEF */
293 window_set_node_of_window (new, node);
295 if (remember_me)
296 remember_window_and_node (new, node);
299 active_window = new;
302 DECLARE_INFO_COMMAND (select_visited_node,
303 _("Select a node which has been previously visited in a visible window"))
305 char *line;
306 NODE *node;
307 REFERENCE **menu;
309 node = get_visited_nodes (NULL);
311 menu = info_menu_of_node (node);
312 free (node);
314 line =
315 info_read_completing_in_echo_area (window,
316 _("Select visited node: "), menu);
318 window = active_window;
320 /* User aborts, just quit. */
321 if (!line)
323 info_abort_key (window, 0, 0);
324 info_free_references (menu);
325 return;
328 if (*line)
330 REFERENCE *entry;
332 /* Find the selected label in the references. */
333 entry = info_get_labeled_reference (line, menu);
335 if (!entry)
336 info_error (_("The reference disappeared! (%s)."), line, NULL);
337 else
338 info_select_reference (window, entry);
341 free (line);
342 info_free_references (menu);
344 if (!info_error_was_printed)
345 window_clear_echo_area ();