1 /* session.c -- user windowing interface to Info.
2 $Id: session.c,v 1.43 2008/06/11 17:38:33 gray Exp $
4 Copyright (C) 1993, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
5 2004, 2007, 2008 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 Originally written by Brian Fox (bfox@ai.mit.edu). */
24 #include <sys/ioctl.h>
26 #if defined (HAVE_SYS_TIME_H)
27 # include <sys/time.h>
28 # define HAVE_STRUCT_TIMEVAL
29 #endif /* HAVE_SYS_TIME_H */
31 #if defined (HANDLE_MAN_PAGES)
35 static void info_clear_pending_input (void);
36 static void info_set_pending_input (unsigned char key);
37 static void info_handle_pointer (char *label, WINDOW *window);
38 static void display_info_keyseq (int expecting_future_input);
39 char *node_printed_rep (NODE *node);
41 /* **************************************************************** */
43 /* Running an Info Session */
45 /* **************************************************************** */
47 /* The place that we are reading input from. */
48 static FILE *info_input_stream = NULL;
50 /* The last executed command. */
51 VFunction *info_last_executed_command = NULL;
53 /* Becomes non-zero when 'q' is typed to an Info window. */
54 int quit_info_immediately = 0;
56 /* Array of structures describing for each window which nodes have been
57 visited in that window. */
58 INFO_WINDOW **info_windows = NULL;
60 /* Where to add the next window, if we need to add one. */
61 static int info_windows_index = 0;
63 /* Number of slots allocated to `info_windows'. */
64 static int info_windows_slots = 0;
66 /* Whether to use regexps or not for search. */
67 static int use_regex = 1;
69 void remember_window_and_node (WINDOW *window, NODE *node);
70 void forget_window_and_nodes (WINDOW *window);
71 void display_startup_message_and_start (void);
73 /* Begin an info session finding the nodes specified by FILENAME and NODENAMES.
74 For each loaded node, create a new window. Always split the largest of the
77 begin_multiple_window_info_session (char *filename, char **nodenames)
80 WINDOW *window = NULL;
82 for (i = 0; nodenames[i]; i++)
86 node = info_get_node (filename, nodenames[i]);
91 /* If this is the first node, initialize the info session. */
94 initialize_info_session (node, 1);
95 window = active_window;
99 /* Find the largest window in WINDOWS, and make that be the active
100 one. Then split it and add our window and node to the list
101 of remembered windows and nodes. Then tile the windows. */
102 WINDOW *win, *largest = NULL;
105 for (win = windows; win; win = win->next)
106 if (win->height > max_height)
108 max_height = win->height;
114 display_update_display (windows);
115 info_error (msg_cant_find_window, NULL, NULL);
120 active_window = largest;
121 window = window_make_window (node);
124 window_tile_windows (TILE_INTERNALS);
125 remember_window_and_node (window, node);
129 display_update_display (windows);
130 info_error (msg_win_too_small, NULL, NULL);
136 display_startup_message_and_start ();
139 /* Start an info session with INITIAL_NODE, and an error message in the echo
140 area made from FORMAT and ARG. */
142 begin_info_session_with_error (NODE *initial_node, const char *format,
143 void *arg1, void *arg2)
145 initialize_info_session (initial_node, 1);
146 info_error (format, arg1, arg2);
150 /* Start an info session with INITIAL_NODE. */
152 begin_info_session (NODE *initial_node)
154 initialize_info_session (initial_node, 1);
155 display_startup_message_and_start ();
159 display_startup_message_and_start (void)
163 format = replace_in_documentation
164 (_("Welcome to Info version %s. Type \\[get-help-window] for help, \\[menu-item] for menu item."),
167 window_message_in_echo_area (format, VERSION, NULL);
171 /* Run an info session with an already initialized window and node. */
175 display_update_display (windows);
176 info_last_executed_command = NULL;
177 info_read_and_dispatch ();
178 /* On program exit, leave the cursor at the bottom of the window, and
179 restore the terminal I/O. */
180 terminal_goto_xy (0, screenheight - 1);
181 terminal_clear_to_eol ();
183 terminal_unprep_terminal ();
184 close_dribble_file ();
187 /* Here is a window-location dependent event loop. Called from the
188 functions info_session (), and from read_xxx_in_echo_area (). */
190 info_read_and_dispatch (void)
196 while (!done && !quit_info_immediately)
200 /* If we haven't just gone up or down a line, there is no
201 goal column for this window. */
202 if ((info_last_executed_command != (VFunction *) info_next_line) &&
203 (info_last_executed_command != (VFunction *) info_prev_line))
204 active_window->goal_column = -1;
206 if (echo_area_is_active)
208 lk = echo_area_last_command_was_kill;
209 echo_area_prep_read ();
212 if (!info_any_buffered_input_p ())
213 display_update_display (windows);
215 display_cursor_at_point (active_window);
216 info_initialize_numeric_arg ();
218 initialize_keyseq ();
219 key = info_get_input_char ();
221 /* No errors yet. We just read a character, that's all. Only clear
222 the echo_area if it is not currently active. */
223 if (!echo_area_is_active)
224 window_clear_echo_area ();
226 info_error_was_printed = 0;
228 /* Do the selected command. */
229 info_dispatch_on_key (key, active_window->keymap);
231 if (echo_area_is_active)
233 /* Echo area commands that do killing increment the value of
234 ECHO_AREA_LAST_COMMAND_WAS_KILL. Thus, if there is no
235 change in the value of this variable, the last command
236 executed was not a kill command. */
237 if (lk == echo_area_last_command_was_kill)
238 echo_area_last_command_was_kill = 0;
240 if (ea_last_executed_command == (VFunction *) ea_newline ||
241 info_aborted_echo_area)
243 ea_last_executed_command = NULL;
247 if (info_last_executed_command == (VFunction *) info_quit)
248 quit_info_immediately = 1;
250 else if (info_last_executed_command == (VFunction *) info_quit)
255 /* Found in signals.c */
256 extern void initialize_info_signal_handler (void );
258 /* Initialize the first info session by starting the terminal, window,
259 and display systems. If CLEAR_SCREEN is 0, don't clear the screen. */
261 initialize_info_session (NODE *node, int clear_screen)
263 char *term_name = getenv ("TERM");
264 terminal_initialize_terminal (term_name);
266 if (terminal_is_dumb_p)
271 info_error (msg_term_too_dumb, term_name, NULL);
277 terminal_prep_terminal ();
278 terminal_clear_screen ();
281 initialize_info_keymaps ();
282 window_initialize_windows (screenwidth, screenheight);
283 initialize_info_signal_handler ();
284 display_initialize_display (screenwidth, screenheight);
285 info_set_node_of_window (0, active_window, node);
287 /* Tell the window system how to notify us when a window needs to be
288 asynchronously deleted (e.g., user resizes window very small). */
289 window_deletion_notifier = (VFunction *) forget_window_and_nodes;
291 /* If input has not been redirected yet, make it come from unbuffered
293 if (!info_input_stream)
295 setbuf (stdin, NULL);
296 info_input_stream = stdin;
299 info_windows_initialized_p = 1;
302 /* Tell Info that input is coming from the file FILENAME. */
304 info_set_input_from_file (char *filename)
308 /* Input may include binary characters. */
309 stream = fopen (filename, FOPEN_RBIN);
314 if ((info_input_stream != NULL) &&
315 (info_input_stream != stdin))
316 fclose (info_input_stream);
318 info_input_stream = stream;
321 display_inhibited = 1;
324 /* Return the INFO_WINDOW containing WINDOW, or NULL if there isn't one. */
326 get_info_window_of_window (WINDOW *window)
329 INFO_WINDOW *info_win = NULL;
331 for (i = 0; info_windows && (info_win = info_windows[i]); i++)
332 if (info_win->window == window)
338 /* Reset the remembered pagetop and point of WINDOW to WINDOW's current
339 values if the window and node are the same as the current one being
342 set_remembered_pagetop_and_point (WINDOW *window)
344 INFO_WINDOW *info_win;
346 info_win = get_info_window_of_window (window);
351 if (info_win->nodes_index &&
352 (info_win->nodes[info_win->current] == window->node))
354 info_win->pagetops[info_win->current] = window->pagetop;
355 info_win->points[info_win->current] = window->point;
360 remember_window_and_node (WINDOW *window, NODE *node)
362 /* See if we already have this window in our list. */
363 INFO_WINDOW *info_win = get_info_window_of_window (window);
365 /* If the window wasn't already on our list, then make a new entry. */
368 info_win = xmalloc (sizeof (INFO_WINDOW));
369 info_win->window = window;
370 info_win->nodes = NULL;
371 info_win->pagetops = NULL;
372 info_win->points = NULL;
373 info_win->current = 0;
374 info_win->nodes_index = 0;
375 info_win->nodes_slots = 0;
377 add_pointer_to_array (info_win, info_windows_index, info_windows,
378 info_windows_slots, 10, INFO_WINDOW *);
381 /* If this node, the current pagetop, and the current point are the
382 same as the current saved node and pagetop, don't really add this to
383 the list of history nodes. This may happen only at the very
384 beginning of the program, I'm not sure. --karl */
386 && info_win->current >= 0
387 && info_win->nodes[info_win->current]->contents == node->contents
388 && info_win->pagetops[info_win->current] == window->pagetop
389 && info_win->points[info_win->current] == window->point)
392 /* Remember this node, the currently displayed pagetop, and the current
393 location of point in this window. Because we are updating pagetops
394 and points as well as nodes, it is more efficient to avoid the
395 add_pointer_to_array macro here. */
396 if (info_win->nodes_index + 2 >= info_win->nodes_slots)
398 info_win->nodes_slots += 20;
399 info_win->nodes = (NODE **) xrealloc (info_win->nodes,
400 info_win->nodes_slots * sizeof (NODE *));
401 info_win->pagetops = (int *) xrealloc (info_win->pagetops,
402 info_win->nodes_slots * sizeof (int));
403 info_win->points = (long *) xrealloc (info_win->points,
404 info_win->nodes_slots * sizeof (long));
407 info_win->nodes[info_win->nodes_index] = node;
408 info_win->pagetops[info_win->nodes_index] = window->pagetop;
409 info_win->points[info_win->nodes_index] = window->point;
410 info_win->current = info_win->nodes_index++;
411 info_win->nodes[info_win->nodes_index] = NULL;
412 info_win->pagetops[info_win->nodes_index] = 0;
413 info_win->points[info_win->nodes_index] = 0;
416 #define DEBUG_FORGET_WINDOW_AND_NODES
417 #if defined (DEBUG_FORGET_WINDOW_AND_NODES)
419 consistency_check_info_windows (void)
423 for (i = 0; i < info_windows_index; i++)
427 for (win = windows; win; win = win->next)
428 if (win == info_windows[i]->window)
435 #endif /* DEBUG_FORGET_WINDOW_AND_NODES */
437 /* Remove WINDOW and its associated list of nodes from INFO_WINDOWS. */
439 forget_window_and_nodes (WINDOW *window)
442 INFO_WINDOW *info_win = NULL;
444 for (i = 0; info_windows && (info_win = info_windows[i]); i++)
445 if (info_win->window == window)
448 /* If we found the window to forget, then do so. */
451 while (i < info_windows_index)
453 info_windows[i] = info_windows[i + 1];
457 info_windows_index--;
458 info_windows[info_windows_index] = NULL;
462 /* Free the node structures which held onto internal node contents
463 here. This doesn't free the contents; we have a garbage collector
465 for (i = 0; info_win->nodes[i]; i++)
466 if (internal_info_node_p (info_win->nodes[i]))
467 free (info_win->nodes[i]);
468 free (info_win->nodes);
470 maybe_free (info_win->pagetops);
471 maybe_free (info_win->points);
476 #if defined (DEBUG_FORGET_WINDOW_AND_NODES)
477 consistency_check_info_windows ();
478 #endif /* DEBUG_FORGET_WINDOW_AND_NODES */
481 /* Set WINDOW to show NODE. Remember the new window in our list of Info
482 windows. If we are doing automatic footnote display, also try to display
483 the footnotes for this window. If REMEMBER is nonzero, first call
484 set_remembered_pagetop_and_point. */
486 info_set_node_of_window (int remember, WINDOW *window, NODE *node)
489 set_remembered_pagetop_and_point (window);
491 /* Put this node into the window. */
492 window_set_node_of_window (window, node);
494 /* Remember this node and window in our list of info windows. */
495 remember_window_and_node (window, node);
497 /* If doing auto-footnote display/undisplay, show the footnotes belonging
498 to this window's node. */
499 if (auto_footnotes_p)
500 info_get_or_remove_footnotes (window);
504 /* **************************************************************** */
506 /* Info Movement Commands */
508 /* **************************************************************** */
510 /* Change the pagetop of WINDOW to DESIRED_TOP, perhaps scrolling the screen
513 set_window_pagetop (WINDOW *window, int desired_top)
515 int point_line, old_pagetop;
519 else if (desired_top > window->line_count)
520 desired_top = window->line_count - 1;
522 if (window->pagetop == desired_top)
525 old_pagetop = window->pagetop;
526 window->pagetop = desired_top;
528 /* Make sure that point appears in this window. */
529 point_line = window_line_of_point (window);
530 if ((point_line < window->pagetop) ||
531 ((point_line - window->pagetop) > window->height - 1))
533 window->line_starts[window->pagetop] - window->node->contents;
535 window->flags |= W_UpdateWindow;
537 /* Find out which direction to scroll, and scroll the window in that
538 direction. Do this only if there would be a savings in redisplay
539 time. This is true if the amount to scroll is less than the height
540 of the window, and if the number of lines scrolled would be greater
541 than 10 % of the window's height. */
542 if (old_pagetop < desired_top)
544 int start, end, amount;
546 amount = desired_top - old_pagetop;
548 if ((amount >= window->height) ||
549 (((window->height - amount) * 10) < window->height))
552 start = amount + window->first_row;
553 end = window->height + window->first_row;
555 display_scroll_display (start, end, -amount);
559 int start, end, amount;
561 amount = old_pagetop - desired_top;
563 if ((amount >= window->height) ||
564 (((window->height - amount) * 10) < window->height))
567 start = window->first_row;
568 end = (window->first_row + window->height) - amount;
569 display_scroll_display (start, end, amount);
573 /* Immediately make WINDOW->point visible on the screen, and move the
574 terminal cursor there. */
576 info_show_point (WINDOW *window)
580 old_pagetop = window->pagetop;
581 window_adjust_pagetop (window);
582 if (old_pagetop != window->pagetop)
586 new_pagetop = window->pagetop;
587 window->pagetop = old_pagetop;
588 set_window_pagetop (window, new_pagetop);
591 if (window->flags & W_UpdateWindow)
592 display_update_one_window (window);
594 display_cursor_at_point (window);
597 /* Move WINDOW->point from OLD line index to NEW line index. */
599 move_to_new_line (int old, int new, WINDOW *window)
603 info_error (msg_cant_find_point, NULL, NULL);
609 if (new >= window->line_count || new < 0)
612 goal = window_get_goal_column (window);
613 window->goal_column = goal;
615 window->point = window->line_starts[new] - window->node->contents;
616 window->point += window_chars_to_goal (window, goal);
617 info_show_point (window);
621 static int forward_move_node_structure (WINDOW *window, int behaviour);
622 static int backward_move_node_structure (WINDOW *window, int behaviour);
624 /* Move WINDOW's point down to the next line if possible. */
625 DECLARE_INFO_COMMAND (info_next_line, _("Move down to the next line"))
627 int old_line, new_line;
630 info_prev_line (window, -count, key);
636 old_line = window_line_of_point (window);
637 diff = window->line_count - old_line;
642 new_line = old_line + diff;
643 if (new_line >= window->line_count)
645 if (cursor_movement_scrolls_p)
647 if (forward_move_node_structure (window,
648 info_scroll_behaviour))
650 move_to_new_line (0, 0, window);
656 move_to_new_line (old_line, new_line, window);
660 /* Move WINDOW's point up to the previous line if possible. */
661 DECLARE_INFO_COMMAND (info_prev_line, _("Move up to the previous line"))
663 int old_line, new_line;
666 info_next_line (window, -count, key);
672 old_line = window_line_of_point (window);
678 new_line = old_line - diff;
681 && cursor_movement_scrolls_p)
683 if (backward_move_node_structure (window, info_scroll_behaviour))
685 if (window->line_count > window->height)
686 set_window_pagetop (window, window->line_count - window->height);
687 move_to_new_line (window->line_count,
688 window->line_count - 1, window);
691 move_to_new_line (old_line, new_line, window);
695 /* Return true if POINT sits on a newline character. */
697 _looking_at_newline (WINDOW *win, long point)
701 mbi_init (iter, win->node->contents + point,
702 win->node->nodelen - point);
704 return mbi_cur (iter).wc_valid && mbi_cur (iter).wc == '\n';
707 /* Advance point of WIN to the beginning of the next logical line.
708 Return 1 if there is no next line. */
710 point_next_line (WINDOW *win)
712 int line = window_line_of_point (win);
713 if (line + 1 >= win->line_count)
715 win->point = win->line_starts[line + 1] - win->node->contents;
716 window_compute_line_map (win);
720 /* Move point of WIN to the beginning of the previous logical
722 Return 1 if there is no previous line. */
724 point_prev_line (WINDOW *win)
726 int line = window_line_of_point (win);
729 win->point = win->line_starts[line - 1] - win->node->contents;
730 window_compute_line_map (win);
734 /* Advance point to the next multibyte character. Return 1 if this would
735 cause pointing past the end of node buffer. */
737 point_forward_char (WINDOW *win)
739 long point = win->point;
742 window_compute_line_map (win);
743 col = window_point_to_column (win, point, &point) + 1;
744 if (col >= win->line_map.used)
746 if (point_next_line (win))
750 win->point = win->line_map.map[col];
754 /* Set point to the previous multibyte character.
755 Return 1 if already on the beginning of node buffer. */
757 point_backward_char (WINDOW *win)
759 long point = win->point;
762 window_compute_line_map (win);
763 col = window_point_to_column (win, point, &point);
764 for (; col >= 0 && win->line_map.map[col] == point; col--)
768 if (point_prev_line (win))
770 col = win->line_map.used - 1;
772 win->point = win->line_map.map[col];
776 /* Skip forward any white space characters starting from column *PCOL in
777 the current line, advancing line if necessary. Return 1 if going past
778 the end of node buffer. */
780 point_skip_ws_forward (WINDOW *win, int *pcol)
787 char *buffer = win->node->contents;
788 size_t buflen = win->node->nodelen;
790 for (; col < win->line_map.used; col++)
792 mbi_init (iter, buffer + win->line_map.map[col],
793 buflen - win->line_map.map[col]);
795 if (!mbi_cur (iter).wc_valid || iswalnum (mbi_cur (iter).wc))
801 if (point_next_line (win))
808 /* Skip backward any white space characters starting from column *PCOL in
809 the current line, retracting line if necessary. Return 1 if going
810 before the beginning of node buffer. */
812 point_skip_ws_backward (WINDOW *win, int *pcol)
819 char *buffer = win->node->contents;
820 size_t buflen = win->node->nodelen;
822 for (; col > 0; col--)
824 mbi_init (iter, buffer + win->line_map.map[col],
825 buflen - win->line_map.map[col]);
827 if (!mbi_cur (iter).wc_valid || iswalnum (mbi_cur (iter).wc))
833 if (point_prev_line (win))
835 col = win->line_map.used - 1;
840 /* Advance window point to the beginning of the next word. Return 1
841 if there are no more words in the buffer. */
843 point_forward_word (WINDOW *win)
848 window_compute_line_map (win);
849 col = window_point_to_column (win, win->point, &win->point);
851 if (point_skip_ws_forward (win, &col))
856 char *buffer = win->node->contents;
857 size_t buflen = win->node->nodelen;
859 for (; col < win->line_map.used; col++)
861 mbi_init (iter, buffer + win->line_map.map[col],
862 buflen - win->line_map.map[col]);
864 if (!(mbi_cur (iter).wc_valid && iswalnum (mbi_cur (iter).wc)))
866 if (point_skip_ws_forward (win, &col))
868 win->point = win->line_map.map[col];
872 if (point_next_line (win))
879 /* Set window point to the beginning of the previous word. Return 1
880 if looking at the very first word in the buffer. */
882 point_backward_word (WINDOW *win)
887 window_compute_line_map (win);
888 col = window_point_to_column (win, win->point, &win->point);
898 if (point_prev_line (win))
900 col = win->line_map.used;
903 if (point_skip_ws_backward (win, &col))
906 buffer = win->node->contents;
907 buflen = win->node->nodelen;
909 for (; col >= 0; col--)
911 mbi_init (iter, buffer + win->line_map.map[col],
912 buflen - win->line_map.map[col]);
914 if (!(mbi_cur (iter).wc_valid && iswalnum (mbi_cur (iter).wc)))
916 win->point = win->line_map.map[col+1];
920 point = win->line_map.map[0] - 1;
921 if (point > 0 && _looking_at_newline (win, point))
923 win->point = win->line_map.map[0];
930 /* Move WINDOW's point to the end of the true line. */
931 DECLARE_INFO_COMMAND (info_end_of_line, _("Move to the end of the line"))
933 int point = window_end_of_line (window);
934 if (point != window->point)
936 window->point = point;
937 info_show_point (window);
941 /* Move WINDOW's point to the beginning of the true line. */
942 DECLARE_INFO_COMMAND (info_beginning_of_line, _("Move to the start of the line"))
944 int old_point = window->point;
949 window_compute_line_map (window);
950 point = window->line_map.map[0];
951 if (point == 0 || _looking_at_newline (window, point-1))
953 point_prev_line (window);
956 if (point != old_point)
958 window->point = point;
959 info_show_point (window);
962 window->point = old_point;
965 /* Move point forward in the node. */
966 DECLARE_INFO_COMMAND (info_forward_char, _("Move forward a character"))
969 info_backward_char (window, -count, key);
974 if (point_forward_char (window))
976 if (cursor_movement_scrolls_p
977 && forward_move_node_structure (window,
978 info_scroll_behaviour) == 0)
982 window->point = window->node->nodelen - 1;
988 info_show_point (window);
992 /* Move point backward in the node. */
993 DECLARE_INFO_COMMAND (info_backward_char, _("Move backward a character"))
996 info_forward_char (window, -count, key);
1001 if (point_backward_char (window))
1003 if (cursor_movement_scrolls_p
1004 && backward_move_node_structure (window,
1005 info_scroll_behaviour) == 0)
1007 window->point = window->node->nodelen - 1;
1008 if (window->line_count > window->height)
1009 set_window_pagetop (window,
1010 window->line_count - window->height);
1020 info_show_point (window);
1024 /* Move forward a word in this node. */
1025 DECLARE_INFO_COMMAND (info_forward_word, _("Move forward a word"))
1029 info_backward_word (window, -count, key);
1035 if (point_forward_word (window))
1037 if (cursor_movement_scrolls_p
1038 && forward_move_node_structure (window,
1039 info_scroll_behaviour) == 0)
1046 info_show_point (window);
1049 DECLARE_INFO_COMMAND (info_backward_word, _("Move backward a word"))
1053 info_forward_word (window, -count, key);
1059 if (point_backward_word (window))
1061 if (cursor_movement_scrolls_p
1062 && backward_move_node_structure (window,
1063 info_scroll_behaviour) == 0)
1065 if (window->line_count > window->height)
1066 set_window_pagetop (window,
1067 window->line_count - window->height);
1068 window->point = window->node->nodelen;
1075 info_show_point (window);
1078 /* Variable controlling the behaviour of default scrolling when you are
1079 already at the bottom of a node. Possible values are defined in session.h.
1082 IS_Continuous Try to get first menu item, or failing that, the
1083 "Next:" pointer, or failing that, the "Up:" and
1085 IS_NextOnly Try to get "Next:" menu item.
1086 IS_PageOnly Simply give up at the bottom of a node. */
1088 int info_scroll_behaviour = IS_Continuous;
1090 /* Choices used by the completer when reading a value for the user-visible
1091 variable "scroll-behaviour". */
1092 char *info_scroll_choices[] = {
1093 "Continuous", "Next Only", "Page Only", NULL
1096 /* Controls whether scroll-behavior affects line movement commands */
1097 int cursor_movement_scrolls_p = 1;
1099 /* Choices for the scroll-last-node variable */
1100 char *scroll_last_node_choices[] = {
1101 "Stop", "Scroll", "Top", NULL
1104 /* Controls what to do when a scrolling command is issued at the end of the
1106 int scroll_last_node = SLN_Stop;
1108 /* Default window sizes for scrolling commands. */
1109 int default_window_size = -1; /* meaning 1 window-full */
1110 int default_scroll_size = -1; /* meaning half screen size */
1112 #define INFO_LABEL_FOUND() \
1113 (info_parsed_nodename || (info_parsed_filename \
1114 && !is_dir_name (info_parsed_filename)))
1117 last_node_p (NODE *node)
1119 info_next_label_of_node (node);
1120 if (!INFO_LABEL_FOUND ())
1122 info_up_label_of_node (node);
1123 return !INFO_LABEL_FOUND () || strcmp (info_parsed_nodename, "Top") == 0;
1128 /* Move to 1st menu item, Next, Up/Next, or error in this window. */
1130 forward_move_node_structure (WINDOW *window, int behaviour)
1135 info_error (msg_at_node_bottom, NULL, NULL);
1139 info_next_label_of_node (window->node);
1140 if (!info_parsed_nodename && !info_parsed_filename)
1142 info_error (msg_no_pointer, (char *) _("Next"), NULL);
1147 info_handle_pointer ("Next", window);
1153 if (last_node_p (window->node))
1155 switch (scroll_last_node)
1158 info_error (_("No more nodes within this document."),
1166 info_top_node (window, 1, 0);
1174 /* First things first. If this node contains a menu, move down
1179 menu = info_menu_of_node (window->node);
1183 info_free_references (menu);
1184 info_menu_digit (window, 1, '1');
1189 /* Okay, this node does not contain a menu. If it contains a
1190 "Next:" pointer, use that. */
1191 info_next_label_of_node (window->node);
1192 if (INFO_LABEL_FOUND ())
1194 info_handle_pointer ("Next", window);
1198 /* Okay, there wasn't a "Next:" for this node. Move "Up:" until we
1199 can move "Next:". If that isn't possible, complain that there
1200 are no more nodes. */
1202 int up_counter, old_current;
1203 INFO_WINDOW *info_win;
1205 /* Remember the current node and location. */
1206 info_win = get_info_window_of_window (window);
1207 old_current = info_win->current;
1209 /* Back up through the "Up:" pointers until we have found a "Next:"
1210 that isn't the same as the first menu item found in that node. */
1212 while (!info_error_was_printed)
1214 info_up_label_of_node (window->node);
1215 if (INFO_LABEL_FOUND ())
1217 info_handle_pointer ("Up", window);
1218 if (info_error_was_printed)
1223 info_next_label_of_node (window->node);
1225 /* If no "Next" pointer, keep backing up. */
1226 if (!INFO_LABEL_FOUND ())
1229 /* If this node's first menu item is the same as this node's
1230 Next pointer, keep backing up. */
1231 if (!info_parsed_filename)
1234 char *next_nodename;
1236 /* Remember the name of the Next node, since reading
1237 the menu can overwrite the contents of the
1238 info_parsed_xxx strings. */
1239 next_nodename = xstrdup (info_parsed_nodename);
1241 menu = info_menu_of_node (window->node);
1244 (menu[0]->nodename, next_nodename) == 0))
1246 info_free_references (menu);
1247 free (next_nodename);
1252 /* Restore the world to where it was before
1253 reading the menu contents. */
1254 info_free_references (menu);
1255 free (next_nodename);
1256 info_next_label_of_node (window->node);
1260 /* This node has a "Next" pointer, and it is not the
1261 same as the first menu item found in this node. */
1262 info_handle_pointer ("Next", window);
1267 /* No more "Up" pointers. Print an error, and call it
1271 for (i = 0; i < up_counter; i++)
1273 info_win->nodes_index--;
1274 free (info_win->nodes[info_win->nodes_index]);
1275 info_win->nodes[info_win->nodes_index] = NULL;
1277 info_win->current = old_current;
1278 window->node = info_win->nodes[old_current];
1279 window->pagetop = info_win->pagetops[old_current];
1280 window->point = info_win->points[old_current];
1281 recalculate_line_starts (window);
1282 window->flags |= W_UpdateWindow;
1283 info_error (_("No more nodes within this document."),
1292 return info_error_was_printed; /*FIXME*/
1295 /* Move Prev, Up or error in WINDOW depending on BEHAVIOUR. */
1297 backward_move_node_structure (WINDOW *window, int behaviour)
1302 info_error (msg_at_node_top, NULL, NULL);
1306 info_prev_label_of_node (window->node);
1307 if (!info_parsed_nodename && !info_parsed_filename)
1309 info_error (_("No `Prev' for this node."), NULL, NULL);
1314 info_handle_pointer ("Prev", window);
1319 info_prev_label_of_node (window->node);
1321 if (!info_parsed_nodename && (!info_parsed_filename
1322 || is_dir_name (info_parsed_filename)))
1324 info_up_label_of_node (window->node);
1325 if (!info_parsed_nodename && (!info_parsed_filename
1326 || is_dir_name (info_parsed_filename)))
1329 _("No `Prev' or `Up' for this node within this document."),
1335 info_handle_pointer ("Up", window);
1341 int inhibit_menu_traversing = 0;
1343 /* Watch out! If this node's Prev is the same as the Up, then
1344 move Up. Otherwise, we could move Prev, and then to the last
1345 menu item in the Prev. This would cause the user to loop
1346 through a subsection of the info file. */
1347 if (!info_parsed_filename && info_parsed_nodename)
1351 pnode = xstrdup (info_parsed_nodename);
1352 info_up_label_of_node (window->node);
1354 if (!info_parsed_filename && info_parsed_nodename &&
1355 strcmp (info_parsed_nodename, pnode) == 0)
1357 /* The nodes are the same. Inhibit moving to the last
1360 inhibit_menu_traversing = 1;
1365 info_prev_label_of_node (window->node);
1369 /* Move to the previous node. If this node now contains a menu,
1370 and we have not inhibited movement to it, move to the node
1371 corresponding to the last menu item. */
1372 info_handle_pointer ("Prev", window);
1374 if (!inhibit_menu_traversing)
1376 while (!info_error_was_printed &&
1377 (menu = info_menu_of_node (window->node)))
1379 info_free_references (menu);
1380 info_menu_digit (window, 1, '0');
1389 /* Move continuously forward through the node structure of this info file. */
1390 DECLARE_INFO_COMMAND (info_global_next_node,
1391 _("Move forwards or down through node structure"))
1394 info_global_prev_node (window, -count, key);
1397 while (count && !info_error_was_printed)
1399 forward_move_node_structure (window, IS_Continuous);
1405 /* Move continuously backward through the node structure of this info file. */
1406 DECLARE_INFO_COMMAND (info_global_prev_node,
1407 _("Move backwards or up through node structure"))
1410 info_global_next_node (window, -count, key);
1413 while (count && !info_error_was_printed)
1415 backward_move_node_structure (window, IS_Continuous);
1421 static void _scroll_forward(WINDOW *window, int count,
1422 unsigned char key, int behaviour);
1423 static void _scroll_backward(WINDOW *window, int count,
1424 unsigned char key, int behaviour);
1427 _scroll_forward(WINDOW *window, int count, unsigned char key, int behaviour)
1430 _scroll_backward (window, -count, key, behaviour);
1435 /* Without an explicit numeric argument, scroll the bottom two
1436 lines to the top of this window, Or, if at bottom of window,
1437 and the chosen behaviour is to scroll through nodes get the
1438 "Next" node for this window. */
1439 if (default_window_size > 0)
1440 desired_top = window->pagetop + default_window_size;
1441 else if (!info_explicit_arg && count == 1)
1443 desired_top = window->pagetop + (window->height - 2);
1445 /* If there are no more lines to scroll here, error, or get
1446 another node, depending on BEHAVIOUR. */
1447 if (desired_top > window->line_count)
1449 if (forward_move_node_structure (window, behaviour))
1450 info_end_of_node (window, 1, 0);
1455 desired_top = window->pagetop + count;
1457 if (desired_top >= window->line_count)
1458 desired_top = window->line_count - 2;
1460 if (window->pagetop > desired_top)
1463 set_window_pagetop (window, desired_top);
1468 _scroll_backward(WINDOW *window, int count, unsigned char key, int behaviour)
1471 _scroll_forward (window, -count, key, behaviour);
1476 /* Without an explicit numeric argument, scroll the top two lines
1477 to the bottom of this window, or, depending on the selected
1478 behaviour, move to the previous, or Up'th node. */
1479 if (default_window_size > 0)
1480 desired_top = window->pagetop - default_window_size;
1481 else if (!info_explicit_arg && count == 1)
1483 desired_top = window->pagetop - (window->height - 2);
1485 if ((desired_top < 0) && (window->pagetop == 0))
1487 if ((backward_move_node_structure (window, behaviour) == 0)
1488 && (cursor_movement_scrolls_p))
1489 info_end_of_node (window, 1, 0);
1490 window->point = (window->line_starts[window->pagetop]
1491 - window->node->contents);
1496 desired_top = window->pagetop - count;
1498 if (desired_top < 0)
1501 set_window_pagetop (window, desired_top);
1502 window->point = (window->line_starts[window->pagetop]
1503 - window->node->contents);
1507 /* Show the next screen of WINDOW's node. */
1508 DECLARE_INFO_COMMAND (info_scroll_forward, _("Scroll forward in this window"))
1510 _scroll_forward (window, count, key, info_scroll_behaviour);
1513 /* Like info_scroll_forward, but sets default_window_size as a side
1515 DECLARE_INFO_COMMAND (info_scroll_forward_set_window,
1516 _("Scroll forward in this window and set default window size"))
1518 if (info_explicit_arg)
1519 default_window_size = count;
1520 _scroll_forward (window, count, key, info_scroll_behaviour);
1523 /* Show the next screen of WINDOW's node but never advance to next node. */
1524 DECLARE_INFO_COMMAND (info_scroll_forward_page_only, _("Scroll forward in this window staying within node"))
1526 _scroll_forward (window, count, key, IS_PageOnly);
1529 /* Like info_scroll_forward_page_only, but sets default_window_size as a side
1531 DECLARE_INFO_COMMAND (info_scroll_forward_page_only_set_window,
1532 _("Scroll forward in this window staying within node and set default window size"))
1534 if (info_explicit_arg)
1535 default_window_size = count;
1536 _scroll_forward (window, count, key, IS_PageOnly);
1539 /* Show the previous screen of WINDOW's node. */
1540 DECLARE_INFO_COMMAND (info_scroll_backward, _("Scroll backward in this window"))
1542 _scroll_backward (window, count, key, info_scroll_behaviour);
1545 /* Like info_scroll_backward, but sets default_window_size as a side
1547 DECLARE_INFO_COMMAND (info_scroll_backward_set_window,
1548 _("Scroll backward in this window and set default window size"))
1550 if (info_explicit_arg)
1551 default_window_size = count;
1552 _scroll_backward (window, count, key, info_scroll_behaviour);
1555 /* Show the previous screen of WINDOW's node but never move to previous
1557 DECLARE_INFO_COMMAND (info_scroll_backward_page_only, _("Scroll backward in this window staying within node"))
1559 _scroll_backward (window, count, key, IS_PageOnly);
1562 /* Like info_scroll_backward_page_only, but sets default_window_size as a side
1564 DECLARE_INFO_COMMAND (info_scroll_backward_page_only_set_window,
1565 _("Scroll backward in this window staying within node and set default window size"))
1567 if (info_explicit_arg)
1568 default_window_size = count;
1569 _scroll_backward (window, count, key, IS_PageOnly);
1572 /* Move to the beginning of the node. */
1573 DECLARE_INFO_COMMAND (info_beginning_of_node, _("Move to the start of this node"))
1575 window->pagetop = window->point = 0;
1576 window->flags |= W_UpdateWindow;
1579 /* Move to the end of the node. */
1580 DECLARE_INFO_COMMAND (info_end_of_node, _("Move to the end of this node"))
1582 window->point = window->node->nodelen - 1;
1583 info_show_point (window);
1586 /* Scroll the window forward by N lines. */
1587 DECLARE_INFO_COMMAND (info_down_line, _("Scroll down by lines"))
1590 info_up_line (window, -count, key);
1593 int desired_top = window->pagetop + count;
1595 if (desired_top >= window->line_count)
1596 desired_top = window->line_count - 2;
1598 if (window->pagetop <= desired_top)
1599 set_window_pagetop (window, desired_top);
1603 /* Scroll the window backward by N lines. */
1604 DECLARE_INFO_COMMAND (info_up_line, _("Scroll up by lines"))
1607 info_down_line (window, -count, key);
1610 int desired_top = window->pagetop - count;
1612 if (desired_top < 0)
1615 set_window_pagetop (window, desired_top);
1619 /* Scroll the window forward by N lines and remember N as default for
1620 subsequent commands. */
1621 DECLARE_INFO_COMMAND (info_scroll_half_screen_down,
1622 _("Scroll down by half screen size"))
1625 info_scroll_half_screen_up (window, -count, key);
1628 int scroll_size = (the_screen->height + 1) / 2;
1631 if (info_explicit_arg)
1632 default_scroll_size = count;
1633 if (default_scroll_size > 0)
1634 scroll_size = default_scroll_size;
1636 desired_top = window->pagetop + scroll_size;
1637 if (desired_top >= window->line_count)
1638 desired_top = window->line_count - 2;
1640 if (window->pagetop <= desired_top)
1641 set_window_pagetop (window, desired_top);
1645 /* Scroll the window backward by N lines and remember N as default for
1646 subsequent commands. */
1647 DECLARE_INFO_COMMAND (info_scroll_half_screen_up,
1648 _("Scroll up by half screen size"))
1651 info_scroll_half_screen_down (window, -count, key);
1654 int scroll_size = (the_screen->height + 1) / 2;
1657 if (info_explicit_arg)
1658 default_scroll_size = count;
1659 if (default_scroll_size > 0)
1660 scroll_size = default_scroll_size;
1662 desired_top = window->pagetop - scroll_size;
1663 if (desired_top < 0)
1666 set_window_pagetop (window, desired_top);
1670 /* **************************************************************** */
1672 /* Commands for Manipulating Windows */
1674 /* **************************************************************** */
1676 /* Make the next window in the chain be the active window. */
1677 DECLARE_INFO_COMMAND (info_next_window, _("Select the next window"))
1681 info_prev_window (window, -count, key);
1685 /* If no other window, error now. */
1686 if (!windows->next && !echo_area_is_active)
1688 info_error (msg_one_window, NULL, NULL);
1695 window = window->next;
1698 if (window == the_echo_area || !echo_area_is_active)
1701 window = the_echo_area;
1705 if (active_window != window)
1707 if (auto_footnotes_p)
1708 info_get_or_remove_footnotes (window);
1710 window->flags |= W_UpdateWindow;
1711 active_window = window;
1715 /* Make the previous window in the chain be the active window. */
1716 DECLARE_INFO_COMMAND (info_prev_window, _("Select the previous window"))
1720 info_next_window (window, -count, key);
1724 /* Only one window? */
1726 if (!windows->next && !echo_area_is_active)
1728 info_error (msg_one_window, NULL, NULL);
1734 /* If we are in the echo area, or if the echo area isn't active and we
1735 are in the first window, find the last window in the chain. */
1736 if (window == the_echo_area ||
1737 (window == windows && !echo_area_is_active))
1739 register WINDOW *win, *last = NULL;
1741 for (win = windows; win; win = win->next)
1748 if (window == windows)
1749 window = the_echo_area;
1751 window = window->prev;
1755 if (active_window != window)
1757 if (auto_footnotes_p)
1758 info_get_or_remove_footnotes (window);
1760 window->flags |= W_UpdateWindow;
1761 active_window = window;
1765 /* Split WINDOW into two windows, both showing the same node. If we
1766 are automatically tiling windows, re-tile after the split. */
1767 DECLARE_INFO_COMMAND (info_split_window, _("Split the current window"))
1769 WINDOW *split, *old_active;
1772 /* Remember the current pagetop of the window being split. If it doesn't
1773 change, we can scroll its contents around after the split. */
1774 pagetop = window->pagetop;
1776 /* Make the new window. */
1777 old_active = active_window;
1778 active_window = window;
1779 split = window_make_window (window->node);
1780 active_window = old_active;
1784 info_error (msg_win_too_small, NULL, NULL);
1788 #if defined (SPLIT_BEFORE_ACTIVE)
1789 /* Try to scroll the old window into its new postion. */
1790 if (pagetop == window->pagetop)
1792 int start, end, amount;
1794 start = split->first_row;
1795 end = start + window->height;
1796 amount = split->height + 1;
1797 display_scroll_display (start, end, amount);
1799 #else /* !SPLIT_BEFORE_ACTIVE */
1800 /* Make sure point still appears in the active window. */
1801 info_show_point (window);
1802 #endif /* !SPLIT_BEFORE_ACTIVE */
1804 /* If the window just split was one internal to Info, try to display
1805 something else in it. */
1806 if (internal_info_node_p (split->node))
1813 for (i = 0; (iw = info_windows[i]); i++)
1815 for (j = 0; j < iw->nodes_index; j++)
1816 if (!internal_info_node_p (iw->nodes[j]))
1818 if (iw->nodes[j]->parent)
1819 filename = iw->nodes[j]->parent;
1821 filename = iw->nodes[j]->filename;
1823 node = info_get_node (filename, iw->nodes[j]->nodename);
1826 window_set_node_of_window (split, node);
1827 i = info_windows_index - 1;
1833 split->pagetop = window->pagetop;
1836 window_tile_windows (DONT_TILE_INTERNALS);
1838 window_adjust_pagetop (split);
1840 remember_window_and_node (split, split->node);
1844 /* Delete WINDOW, forgetting the list of last visited nodes. If we are
1845 automatically displaying footnotes, show or remove the footnotes
1846 window. If we are automatically tiling windows, re-tile after the
1848 DECLARE_INFO_COMMAND (info_delete_window, _("Delete the current window"))
1852 info_error (msg_cant_kill_last, NULL, NULL);
1854 else if (window->flags & W_WindowIsPerm)
1856 info_error (_("Cannot delete a permanent window"), NULL, NULL);
1860 info_delete_window_internal (window);
1862 if (auto_footnotes_p)
1863 info_get_or_remove_footnotes (active_window);
1866 window_tile_windows (DONT_TILE_INTERNALS);
1870 /* Do the physical deletion of WINDOW, and forget this window and
1871 associated nodes. */
1873 info_delete_window_internal (WINDOW *window)
1875 if (windows->next && ((window->flags & W_WindowIsPerm) == 0))
1877 /* We not only delete the window from the display, we forget it from
1878 our list of remembered windows. */
1879 forget_window_and_nodes (window);
1880 window_delete_window (window);
1882 if (echo_area_is_active)
1883 echo_area_inform_of_deleted_window (window);
1887 /* Just keep WINDOW, deleting all others. */
1888 DECLARE_INFO_COMMAND (info_keep_one_window, _("Delete all other windows"))
1890 int num_deleted; /* The number of windows we deleted. */
1891 int pagetop, start, end;
1893 /* Remember a few things about this window. We may be able to speed up
1894 redisplay later by scrolling its contents. */
1895 pagetop = window->pagetop;
1896 start = window->first_row;
1897 end = start + window->height;
1905 /* Find an eligible window and delete it. If no eligible windows
1906 are found, we are done. A window is eligible for deletion if
1907 is it not permanent, and it is not WINDOW. */
1908 for (win = windows; win; win = win->next)
1909 if (win != window && ((win->flags & W_WindowIsPerm) == 0))
1915 info_delete_window_internal (win);
1919 /* Scroll the contents of this window into the right place so that the
1920 user doesn't have to wait any longer than necessary for redisplay. */
1925 amount = (window->first_row - start);
1926 amount -= (window->pagetop - pagetop);
1927 display_scroll_display (start, end, amount);
1930 window->flags |= W_UpdateWindow;
1933 /* Scroll the "other" window of WINDOW. */
1934 DECLARE_INFO_COMMAND (info_scroll_other_window, _("Scroll the other window"))
1938 /* If only one window, give up. */
1941 info_error (msg_one_window, NULL, NULL);
1945 other = window->next;
1948 other = window->prev;
1950 info_scroll_forward (other, count, key);
1953 /* Scroll the "other" window of WINDOW. */
1954 DECLARE_INFO_COMMAND (info_scroll_other_window_backward,
1955 _("Scroll the other window backward"))
1957 info_scroll_other_window (window, -count, key);
1960 /* Change the size of WINDOW by AMOUNT. */
1961 DECLARE_INFO_COMMAND (info_grow_window, _("Grow (or shrink) this window"))
1963 window_change_window_height (window, count);
1966 /* When non-zero, tiling takes place automatically when info_split_window
1968 int auto_tiling_p = 0;
1970 /* Tile all of the visible windows. */
1971 DECLARE_INFO_COMMAND (info_tile_windows,
1972 _("Divide the available screen space among the visible windows"))
1974 window_tile_windows (TILE_INTERNALS);
1977 /* Toggle the state of this window's wrapping of lines. */
1978 DECLARE_INFO_COMMAND (info_toggle_wrap,
1979 _("Toggle the state of line wrapping in the current window"))
1981 window_toggle_wrap (window);
1984 /* Toggle the usage of regular expressions in searches. */
1985 DECLARE_INFO_COMMAND (info_toggle_regexp,
1986 _("Toggle the usage of regular expressions in searches"))
1988 use_regex = 1 - use_regex;
1989 window_message_in_echo_area (use_regex
1990 ? _("Using regular expressions for searches.")
1991 : _("Using literal strings for searches."),
1995 /* **************************************************************** */
1997 /* Info Node Commands */
1999 /* **************************************************************** */
2001 /* Return (FILENAME)NODENAME for NODE, or just NODENAME if NODE's
2002 filename is not set. */
2004 node_printed_rep (NODE *node)
2011 = filename_non_directory (node->parent ? node->parent : node->filename);
2012 rep = xmalloc (1 + strlen (filename) + 1 + strlen (node->nodename) + 1);
2013 sprintf (rep, "(%s)%s", filename, node->nodename);
2016 rep = node->nodename;
2022 /* Using WINDOW for various defaults, select the node referenced by ENTRY
2023 in it. If the node is selected, the window and node are remembered. */
2025 info_select_reference (WINDOW *window, REFERENCE *entry)
2028 char *filename, *nodename, *file_system_error;
2030 file_system_error = NULL;
2032 filename = entry->filename;
2034 filename = window->node->parent;
2036 filename = window->node->filename;
2039 filename = xstrdup (filename);
2041 if (entry->nodename)
2042 nodename = xstrdup (entry->nodename);
2044 nodename = xstrdup ("Top");
2046 node = info_get_node (filename, nodename);
2048 /* Try something a little weird. If the node couldn't be found, and the
2049 reference was of the form "foo::", see if the entry->label can be found
2050 as a file, with a node of "Top". */
2053 if (info_recent_file_error)
2054 file_system_error = xstrdup (info_recent_file_error);
2056 if (entry->nodename && (strcmp (entry->nodename, entry->label) == 0))
2058 node = info_get_node (entry->label, "Top");
2059 if (!node && info_recent_file_error)
2061 maybe_free (file_system_error);
2062 file_system_error = xstrdup (info_recent_file_error);
2069 if (file_system_error)
2070 info_error (file_system_error, NULL, NULL);
2072 info_error (msg_cant_find_node, nodename, NULL);
2075 maybe_free (file_system_error);
2076 maybe_free (filename);
2077 maybe_free (nodename);
2080 info_set_node_of_window (1, window, node);
2083 /* Parse the node specification in LINE using WINDOW to default the filename.
2084 Select the parsed node in WINDOW and remember it, or error if the node
2085 couldn't be found. */
2087 info_parse_and_select (char *line, WINDOW *window)
2091 info_parse_node (line, DONT_SKIP_NEWLINES);
2093 entry.nodename = info_parsed_nodename;
2094 entry.filename = info_parsed_filename;
2095 entry.label = "*info-parse-and-select*";
2097 info_select_reference (window, &entry);
2100 /* Given that the values of INFO_PARSED_FILENAME and INFO_PARSED_NODENAME
2101 are previously filled, try to get the node represented by them into
2102 WINDOW. The node should have been pointed to by the LABEL pointer of
2105 info_handle_pointer (char *label, WINDOW *window)
2107 if (info_parsed_filename || info_parsed_nodename)
2109 char *filename, *nodename;
2112 filename = nodename = NULL;
2114 if (info_parsed_filename)
2115 filename = xstrdup (info_parsed_filename);
2118 if (window->node->parent)
2119 filename = xstrdup (window->node->parent);
2120 else if (window->node->filename)
2121 filename = xstrdup (window->node->filename);
2124 if (info_parsed_nodename)
2125 nodename = xstrdup (info_parsed_nodename);
2127 nodename = xstrdup ("Top");
2129 node = info_get_node (filename, nodename);
2133 INFO_WINDOW *info_win;
2135 info_win = get_info_window_of_window (window);
2138 info_win->pagetops[info_win->current] = window->pagetop;
2139 info_win->points[info_win->current] = window->point;
2141 info_set_node_of_window (1, window, node);
2145 if (info_recent_file_error)
2146 info_error (info_recent_file_error, NULL, NULL);
2148 info_error (msg_cant_file_node, filename, nodename);
2156 info_error (msg_no_pointer, label, NULL);
2160 /* Make WINDOW display the "Next:" node of the node currently being
2162 DECLARE_INFO_COMMAND (info_next_node, _("Select the Next node"))
2164 info_next_label_of_node (window->node);
2165 info_handle_pointer ("Next", window);
2168 /* Make WINDOW display the "Prev:" node of the node currently being
2170 DECLARE_INFO_COMMAND (info_prev_node, _("Select the Prev node"))
2172 info_prev_label_of_node (window->node);
2173 info_handle_pointer ("Prev", window);
2176 /* Make WINDOW display the "Up:" node of the node currently being
2178 DECLARE_INFO_COMMAND (info_up_node, _("Select the Up node"))
2180 info_up_label_of_node (window->node);
2181 info_handle_pointer ("Up", window);
2184 /* Make WINDOW display the last node of this info file. */
2185 DECLARE_INFO_COMMAND (info_last_node, _("Select the last node in this file"))
2188 FILE_BUFFER *fb = file_buffer_of_window (window);
2193 int last_node_tag_idx = -1;
2195 /* If no explicit argument, or argument of zero, default to the
2197 if (count == 0 || (count == 1 && !info_explicit_arg))
2199 for (i = 0; count && fb->tags[i]; i++)
2200 if (fb->tags[i]->nodelen != 0) /* don't count anchor tags */
2203 last_node_tag_idx = i;
2206 i = last_node_tag_idx + 1;
2208 node = info_get_node (fb->filename, fb->tags[i - 1]->nodename);
2212 info_error (_("This window has no additional nodes"), NULL, NULL);
2214 info_set_node_of_window (1, window, node);
2217 /* Make WINDOW display the first node of this info file. */
2218 DECLARE_INFO_COMMAND (info_first_node, _("Select the first node in this file"))
2220 FILE_BUFFER *fb = file_buffer_of_window (window);
2223 /* If no explicit argument, or argument of zero, default to the
2230 int last_node_tag_idx = -1;
2232 for (i = 0; count && fb->tags[i]; i++)
2233 if (fb->tags[i]->nodelen != 0) /* don't count anchor tags */
2236 last_node_tag_idx = i;
2239 i = last_node_tag_idx + 1;
2241 node = info_get_node (fb->filename, fb->tags[i - 1]->nodename);
2245 info_error (_("This window has no additional nodes"), NULL, NULL);
2247 info_set_node_of_window (1, window, node);
2250 /* Select the last menu item in WINDOW->node. */
2251 DECLARE_INFO_COMMAND (info_last_menu_item,
2252 _("Select the last item in this node's menu"))
2254 info_menu_digit (window, 1, '0');
2257 /* Use KEY (a digit) to select the Nth menu item in WINDOW->node. */
2258 DECLARE_INFO_COMMAND (info_menu_digit, _("Select this menu item"))
2260 register int i, item;
2261 register REFERENCE **menu;
2263 menu = info_menu_of_node (window->node);
2267 info_error (msg_no_menu_node, NULL, NULL);
2271 /* We have the menu. See if there are this many items in it. */
2274 /* Special case. Item "0" is the last item in this menu. */
2276 for (i = 0; menu[i + 1]; i++);
2279 for (i = 0; menu[i]; i++)
2286 info_select_reference (window, menu[i]);
2287 if (menu[i]->line_number > 0)
2288 info_next_line (window, menu[i]->line_number - 1, key);
2291 info_error (_("There aren't %d items in this menu."),
2292 (void *) (long) item, NULL);
2294 info_free_references (menu);
2300 /* Return a pointer to the xref in XREF_LIST that is nearest to POS, or
2301 NULL if XREF_LIST is empty. That is, if POS is within any of the
2302 given xrefs, return that one. Otherwise, return the one with the
2303 nearest beginning or end. If there are two that are equidistant,
2304 prefer the one forward. The return is in newly-allocated memory,
2305 since the caller frees it.
2307 This is called from info_menu_or_ref_item with XREF_LIST being all
2308 the xrefs in the node, and POS being point. The ui function that
2309 starts it all off is select-reference-this-line.
2311 This is not the same logic as in info.el. Info-get-token prefers
2312 searching backwards to searching forwards, and has a hardwired search
2313 limit of 200 chars (in Emacs 21.2). */
2316 nearest_xref (REFERENCE **xref_list, long int pos)
2320 long best_delta = -1;
2322 for (this_xref = 0; xref_list[this_xref]; this_xref++)
2325 REFERENCE *xref = xref_list[this_xref];
2326 if (xref->start <= pos && pos <= xref->end)
2327 { /* POS is within this xref, we're done */
2328 nearest = this_xref;
2332 /* See how far POS is from this xref. Take into account the
2333 `*Note' that begins the xref, since as far as the user is
2334 concerned, that's where it starts. */
2335 delta = MIN (labs (pos - (xref->start - strlen (INFO_XREF_LABEL))),
2336 labs (pos - xref->end));
2338 /* It's the <= instead of < that makes us choose the forward xref
2339 of POS if two are equidistant. Of course, because of all the
2340 punctuation surrounding xrefs, it's not necessarily obvious
2342 if (delta <= best_delta || best_delta < 0)
2344 nearest = this_xref;
2349 /* Maybe there was no list to search through. */
2353 /* Ok, we have a nearest xref, make a list of it. */
2355 REFERENCE **ret = xmalloc (sizeof (REFERENCE *) * 2);
2356 ret[0] = info_copy_reference (xref_list[nearest]);
2363 /* Read a menu or followed reference from the user defaulting to the
2364 reference found on the current line, and select that node. The
2365 reading is done with completion. BUILDER is the function used
2366 to build the list of references. ASK_P is non-zero if the user
2367 should be prompted, or zero to select the default item. */
2369 info_menu_or_ref_item (WINDOW *window, int count,
2370 unsigned char key, REFERENCE **(*builder) (NODE *node), int ask_p)
2374 REFERENCE *defentry = NULL;
2375 REFERENCE **menu = (*builder) (window->node);
2379 if (builder == info_menu_of_node)
2380 info_error (msg_no_menu_node, NULL, NULL);
2382 info_error (msg_no_xref_node, NULL, NULL);
2386 /* Default the selected reference to the one which is on the line that
2389 REFERENCE **refs = NULL;
2390 int point_line = window_line_of_point (window);
2392 if (point_line != -1)
2394 SEARCH_BINDING binding;
2396 binding.buffer = window->node->contents;
2397 binding.start = window->line_starts[point_line] - binding.buffer;
2398 if (window->line_starts[point_line + 1])
2399 binding.end = window->line_starts[point_line + 1] - binding.buffer;
2401 binding.end = window->node->nodelen;
2404 if (builder == info_menu_of_node)
2409 refs = info_menu_items (&binding);
2414 #if defined (HANDLE_MAN_PAGES)
2415 if (window->node->flags & N_IsManPage)
2416 refs = manpage_xrefs_in_binding (window->node, &binding);
2418 #endif /* HANDLE_MAN_PAGES */
2419 refs = nearest_xref (menu, window->point);
2422 if (refs && refs[0])
2424 if (strcmp (refs[0]->label, "Menu") != 0
2425 || builder == info_xrefs_of_node)
2429 /* For xrefs, find the closest reference to point,
2430 unless we only have one reference (as we will if
2431 we've called nearest_xref above). It would be better
2432 to have only one piece of code, but the conditions
2433 when we call this are tangled. */
2434 if (builder == info_xrefs_of_node && refs[1])
2438 for (; refs[which]; which++)
2440 if (window->point >= refs[which]->start
2441 && window->point <= refs[which]->end)
2446 else if (window->point < refs[which]->start)
2458 defentry = xmalloc (sizeof (REFERENCE));
2459 defentry->label = xstrdup (refs[which]->label);
2460 defentry->filename = refs[which]->filename;
2461 defentry->nodename = refs[which]->nodename;
2462 defentry->line_number = refs[which]->line_number;
2464 if (defentry->filename)
2465 defentry->filename = xstrdup (defentry->filename);
2466 if (defentry->nodename)
2467 defentry->nodename = xstrdup (defentry->nodename);
2469 info_free_references (refs);
2474 /* If we are going to ask the user a question, do it now. */
2479 /* Build the prompt string. */
2480 if (builder == info_menu_of_node)
2484 prompt = xmalloc (strlen (defentry->label)
2485 + strlen (_("Menu item (%s): ")));
2486 sprintf (prompt, _("Menu item (%s): "), defentry->label);
2489 prompt = xstrdup (_("Menu item: "));
2495 prompt = xmalloc (strlen (defentry->label)
2496 + strlen (_("Follow xref (%s): ")));
2497 sprintf (prompt, _("Follow xref (%s): "), defentry->label);
2500 prompt = xstrdup (_("Follow xref: "));
2503 line = info_read_completing_in_echo_area (window, prompt, menu);
2506 window = active_window;
2508 /* User aborts, just quit. */
2511 maybe_free (defentry);
2512 info_free_references (menu);
2513 info_abort_key (window, 0, 0);
2517 /* If we had a default and the user accepted it, use that. */
2522 line = xstrdup (defentry->label);
2529 /* Not going to ask any questions. If we have a default entry, use
2530 that, otherwise return. */
2534 line = xstrdup (defentry->label);
2539 /* It is possible that the references have more than a single
2540 entry with the same label, and also LINE is down-cased, which
2541 complicates matters even more. Try to be as accurate as we
2542 can: if they've chosen the default, use defentry directly. */
2543 if (defentry && strcmp (line, defentry->label) == 0)
2546 /* Find the selected label in the references. If there are
2547 more than one label which matches, find the one that's
2548 closest to point. */
2551 int best = -1, min_dist = window->node->nodelen;
2554 for (i = 0; menu && (ref = menu[i]); i++)
2556 /* Need to use mbscasecmp because LINE is downcased
2557 inside info_read_completing_in_echo_area. */
2558 if (mbscasecmp (line, ref->label) == 0)
2560 /* ref->end is more accurate estimate of position
2561 for menus than ref->start. Go figure. */
2562 int dist = abs (window->point - ref->end);
2564 if (dist < min_dist)
2577 if (!entry && defentry)
2578 info_error (_("The reference disappeared! (%s)."), line, NULL);
2581 NODE *orig = window->node;
2582 info_select_reference (window, entry);
2584 if (builder == info_xrefs_of_node && window->node != orig
2585 && !(window->node->flags & N_FromAnchor))
2586 { /* Search for this reference in the node. */
2590 if (window->line_count > 0)
2591 start = window->line_starts[1] - window->node->contents;
2596 info_target_search_node (window->node, entry->label, start);
2600 window->point = offset;
2601 window_adjust_pagetop (window);
2605 if (entry->line_number > 0)
2606 /* next_line starts at line 1? Anyway, the -1 makes it
2607 move to the right line. */
2608 info_next_line (window, entry->line_number - 1, key);
2614 free (defentry->label);
2615 maybe_free (defentry->filename);
2616 maybe_free (defentry->nodename);
2621 info_free_references (menu);
2623 if (!info_error_was_printed)
2624 window_clear_echo_area ();
2627 /* Read a line (with completion) which is the name of a menu item,
2628 and select that item. */
2629 DECLARE_INFO_COMMAND (info_menu_item, _("Read a menu item and select its node"))
2631 info_menu_or_ref_item (window, count, key, info_menu_of_node, 1);
2634 /* Read a line (with completion) which is the name of a reference to
2635 follow, and select the node. */
2636 DECLARE_INFO_COMMAND
2637 (info_xref_item, _("Read a footnote or cross reference and select its node"))
2639 info_menu_or_ref_item (window, count, key, info_xrefs_of_node, 1);
2642 /* Position the cursor at the start of this node's menu. */
2643 DECLARE_INFO_COMMAND (info_find_menu, _("Move to the start of this node's menu"))
2645 SEARCH_BINDING binding;
2648 binding.buffer = window->node->contents;
2650 binding.end = window->node->nodelen;
2651 binding.flags = S_FoldCase | S_SkipDest;
2653 position = search (INFO_MENU_LABEL, &binding);
2656 info_error (msg_no_menu_node, NULL, NULL);
2659 window->point = position;
2660 window_adjust_pagetop (window);
2661 window->flags |= W_UpdateWindow;
2665 /* Visit as many menu items as is possible, each in a separate window. */
2666 DECLARE_INFO_COMMAND (info_visit_menu,
2667 _("Visit as many menu items at once as possible"))
2670 REFERENCE *entry, **menu;
2672 menu = info_menu_of_node (window->node);
2675 info_error (msg_no_menu_node, NULL, NULL);
2677 for (i = 0; (!info_error_was_printed) && (entry = menu[i]); i++)
2681 new = window_make_window (window->node);
2682 window_tile_windows (TILE_INTERNALS);
2685 info_error (msg_win_too_small, NULL, NULL);
2688 active_window = new;
2689 info_select_reference (new, entry);
2694 /* Read a line of input which is a node name, and go to that node. */
2695 DECLARE_INFO_COMMAND (info_goto_node, _("Read a node name and select it"))
2699 #define GOTO_COMPLETES
2700 #if defined (GOTO_COMPLETES)
2701 /* Build a completion list of all of the known nodes. */
2703 register int fbi, i;
2704 FILE_BUFFER *current;
2705 REFERENCE **items = NULL;
2706 int items_index = 0;
2707 int items_slots = 0;
2709 current = file_buffer_of_window (window);
2711 for (fbi = 0; info_loaded_files && info_loaded_files[fbi]; fbi++)
2715 int this_is_the_current_fb;
2717 fb = info_loaded_files[fbi];
2718 this_is_the_current_fb = (current == fb);
2720 entry = xmalloc (sizeof (REFERENCE));
2721 entry->filename = entry->nodename = NULL;
2722 entry->label = xmalloc (4 + strlen (fb->filename));
2723 sprintf (entry->label, "(%s)*", fb->filename);
2725 add_pointer_to_array
2726 (entry, items_index, items, items_slots, 10, REFERENCE *);
2730 for (i = 0; fb->tags[i]; i++)
2732 entry = xmalloc (sizeof (REFERENCE));
2733 entry->filename = entry->nodename = NULL;
2734 if (this_is_the_current_fb)
2735 entry->label = xstrdup (fb->tags[i]->nodename);
2738 entry->label = xmalloc
2739 (4 + strlen (fb->filename) +
2740 strlen (fb->tags[i]->nodename));
2741 sprintf (entry->label, "(%s)%s",
2742 fb->filename, fb->tags[i]->nodename);
2745 add_pointer_to_array
2746 (entry, items_index, items, items_slots, 100, REFERENCE *);
2750 line = info_read_maybe_completing (window, _("Goto node: "),
2752 info_free_references (items);
2754 #else /* !GOTO_COMPLETES */
2755 line = info_read_in_echo_area (window, _("Goto node: "));
2756 #endif /* !GOTO_COMPLETES */
2758 /* If the user aborted, quit now. */
2761 info_abort_key (window, 0, 0);
2765 canonicalize_whitespace (line);
2768 info_parse_and_select (line, window);
2771 if (!info_error_was_printed)
2772 window_clear_echo_area ();
2775 /* Follow the menu list in MENUS (list of strings terminated by a NULL
2776 entry) from INITIAL_NODE. If can't continue at any point (no menu or
2777 no menu entry for the next item), return the node so far -- that
2778 might be INITIAL_NODE itself. If error, *ERRSTR and *ERRARG[12] will
2779 be set to the error message and argument for message, otherwise they
2783 info_follow_menus (NODE *initial_node, char **menus,
2784 const char **errstr, char **errarg1, char **errarg2)
2787 *errstr = *errarg1 = *errarg2 = NULL;
2789 for (; *menus; menus++)
2791 static char *first_arg = NULL;
2794 char *arg = *menus; /* Remember the name of the menu entry we want. */
2796 /* A leading space is certainly NOT part of a node name. Most
2797 probably, they typed a space after the separating comma. The
2798 strings in menus[] have their whitespace canonicalized, so
2799 there's at most one space to ignore. */
2805 /* Build and return a list of the menu items in this node. */
2806 menu = info_menu_of_node (initial_node);
2808 /* If no menu item in this node, stop here, but let the user
2809 continue to use Info. Perhaps they wanted this node and didn't
2813 if (arg == first_arg)
2815 node = make_manpage_node (first_arg);
2817 goto maybe_got_node;
2819 *errstr = _("No menu in node `%s'.");
2820 *errarg1 = node_printed_rep (initial_node);
2821 return initial_node;
2824 /* Find the specified menu item. */
2825 entry = info_get_labeled_reference (arg, menu);
2827 /* If the item wasn't found, search the list sloppily. Perhaps this
2828 user typed "buffer" when they really meant "Buffers". */
2832 int best_guess = -1;
2834 for (i = 0; (entry = menu[i]); i++)
2836 if (mbscasecmp (entry->label, arg) == 0)
2839 if ((best_guess == -1)
2840 && (mbsncasecmp (entry->label, arg, strlen (arg)) == 0))
2844 if (!entry && best_guess != -1)
2845 entry = menu[best_guess];
2848 /* If we still failed to find the reference, start Info with the current
2849 node anyway. It is probably a misspelling. */
2852 if (arg == first_arg)
2854 /* Maybe they typed "info foo" instead of "info -f foo". */
2855 node = info_get_node (first_arg, 0);
2857 add_file_directory_to_path (first_arg);
2859 node = make_manpage_node (first_arg);
2861 goto maybe_got_node;
2864 info_free_references (menu);
2865 *errstr = _("No menu item `%s' in node `%s'.");
2867 *errarg2 = node_printed_rep (initial_node);
2868 return initial_node;
2871 /* We have found the reference that the user specified. If no
2872 filename in this reference, define it. */
2873 if (!entry->filename)
2874 entry->filename = xstrdup (initial_node->parent ? initial_node->parent
2875 : initial_node->filename);
2877 /* Try to find this node. */
2878 node = info_get_node (entry->filename, entry->nodename);
2879 if (!node && arg == first_arg)
2881 node = make_manpage_node (first_arg);
2883 goto maybe_got_node;
2886 /* Since we cannot find it, try using the label of the entry as a
2887 file, i.e., "(LABEL)Top". */
2888 if (!node && entry->nodename
2889 && strcmp (entry->label, entry->nodename) == 0)
2890 node = info_get_node (entry->label, "Top");
2895 *errstr = _("Unable to find node referenced by `%s' in `%s'.");
2896 *errarg1 = xstrdup (entry->label);
2897 *errarg2 = node_printed_rep (initial_node);
2898 info_free_references (menu);
2899 return initial_node;
2902 info_free_references (menu);
2904 /* Success. Go round the loop again. */
2905 free (initial_node);
2906 initial_node = node;
2909 return initial_node;
2912 /* Split STR into individual node names by writing null bytes in wherever
2913 there are commas and constructing a list of the resulting pointers.
2914 (We can do this since STR has had canonicalize_whitespace called on it.)
2915 Return array terminated with NULL. */
2918 split_list_of_nodenames (char *str)
2921 char **nodes = xmalloc (len * sizeof (char *));
2923 nodes[len - 2] = str;
2929 *str++ = 0; /* get past the null byte */
2931 nodes = xrealloc (nodes, len * sizeof (char *));
2932 nodes[len - 2] = str;
2936 nodes[len - 1] = NULL;
2942 /* Read a line of input which is a sequence of menus (starting from
2943 dir), and follow them. */
2944 DECLARE_INFO_COMMAND (info_menu_sequence,
2945 _("Read a list of menus starting from dir and follow them"))
2947 char *line = info_read_in_echo_area (window, _("Follow menus: "));
2949 /* If the user aborted, quit now. */
2952 info_abort_key (window, 0, 0);
2956 canonicalize_whitespace (line);
2961 char *errarg1, *errarg2;
2962 NODE *dir_node = info_get_node (NULL, NULL);
2963 char **nodes = split_list_of_nodenames (line);
2966 /* If DIR_NODE is NULL, they might be reading a file directly,
2967 like in "info -d . -f ./foo". Try using "Top" instead. */
2970 char *file_name = window->node->parent;
2973 file_name = window->node->filename;
2974 dir_node = info_get_node (file_name, NULL);
2977 /* If we still cannot find the starting point, give up.
2978 We cannot allow a NULL pointer inside info_follow_menus. */
2980 info_error (msg_cant_find_node, "Top", NULL);
2982 node = info_follow_menus (dir_node, nodes, &errstr, &errarg1, &errarg2);
2986 info_set_node_of_window (1, window, node);
2988 info_error (errstr, errarg1, errarg2);
2992 if (!info_error_was_printed)
2993 window_clear_echo_area ();
2996 /* Search the menu MENU for a (possibly mis-spelled) entry ARG.
2997 Return the menu entry, or the best guess for what they meant by ARG,
2998 or NULL if there's nothing in this menu seems to fit the bill.
2999 If EXACT is non-zero, allow only exact matches. */
3001 entry_in_menu (char *arg, REFERENCE **menu, int exact)
3005 /* First, try to find the specified menu item verbatim. */
3006 entry = info_get_labeled_reference (arg, menu);
3008 /* If the item wasn't found, search the list sloppily. Perhaps we
3009 have "Option Summary", but ARG is "option". */
3010 if (!entry && !exact)
3013 int best_guess = -1;
3015 for (i = 0; (entry = menu[i]); i++)
3017 if (mbscasecmp (entry->label, arg) == 0)
3020 if (mbsncasecmp (entry->label, arg, strlen (arg)) == 0)
3024 if (!entry && best_guess != -1)
3025 entry = menu[best_guess];
3031 /* Find the node that is the best candidate to list the PROGRAM's
3032 invocation info and its command-line options, by looking for menu
3033 items and chains of menu items with characteristic names. */
3035 info_intuit_options_node (WINDOW *window, NODE *initial_node, char *program)
3037 /* The list of node names typical for GNU manuals where the program
3038 usage and specifically the command-line arguments are described.
3039 This is pure heuristics. I gathered these node names by looking
3040 at all the Info files I could put my hands on. If you are
3041 looking for evidence to complain to the GNU project about
3042 non-uniform style of documentation, here you have your case! */
3043 static const char *invocation_nodes[] = {
3046 "Preliminaries", /* m4 has Invoking under Preliminaries! */
3048 "Command Arguments",/* Emacs */
3052 "Option ", /* e.g. "Option Summary" */
3054 "All options", /* tar, paxutils */
3056 "%s cmdline", /* ar */
3057 "%s", /* last resort */
3062 const char **try_node;
3064 /* We keep looking deeper and deeper in the menu structure until
3065 there are no more menus or no menu items from the above list.
3066 Some manuals have the invocation node sitting 3 or 4 levels deep
3067 in the menu hierarchy... */
3068 for (node = initial_node; node; initial_node = node)
3070 REFERENCE *entry = NULL;
3072 /* Build and return a list of the menu items in this node. */
3073 menu = info_menu_of_node (initial_node);
3075 /* If no menu item in this node, stop here. Perhaps this node
3076 is the one they need. */
3080 /* Look for node names typical for usage nodes in this menu. */
3081 for (try_node = invocation_nodes; *try_node; try_node++)
3085 nodename = xmalloc (strlen (program) + strlen (*try_node));
3086 sprintf (nodename, *try_node, program);
3087 /* The last resort "%s" is dangerous, so we restrict it
3088 to exact matches here. */
3089 entry = entry_in_menu (nodename, menu,
3090 strcmp (*try_node, "%s") == 0);
3099 if (!entry->filename)
3100 entry->filename = xstrdup (initial_node->parent ? initial_node->parent
3101 : initial_node->filename);
3102 /* Try to find this node. */
3103 node = info_get_node (entry->filename, entry->nodename);
3104 info_free_references (menu);
3109 /* We've got our best shot at the invocation node. Now select it. */
3111 info_set_node_of_window (1, window, initial_node);
3112 if (!info_error_was_printed)
3113 window_clear_echo_area ();
3116 /* Given a name of an Info file, find the name of the package it
3117 describes by removing the leading directories and extensions. */
3119 program_name_from_file_name (char *file_name)
3122 char *program_name = xstrdup (filename_non_directory (file_name));
3124 for (i = strlen (program_name) - 1; i > 0; i--)
3125 if (program_name[i] == '.'
3126 && (FILENAME_CMPN (program_name + i, ".info", 5) == 0
3127 || FILENAME_CMPN (program_name + i, ".inf", 4) == 0
3129 || FILENAME_CMPN (program_name + i, ".i", 2) == 0
3131 || isdigit (program_name[i + 1]))) /* a man page foo.1 */
3133 program_name[i] = 0;
3136 return program_name;
3139 DECLARE_INFO_COMMAND (info_goto_invocation_node,
3140 _("Find the node describing program invocation"))
3142 const char *invocation_prompt = _("Find Invocation node of [%s]: ");
3143 char *program_name, *line;
3144 char *default_program_name, *prompt, *file_name;
3147 /* Intuit the name of the program they are likely to want.
3148 We use the file name of the current Info file as a hint. */
3149 file_name = window->node->parent ? window->node->parent
3150 : window->node->filename;
3151 default_program_name = program_name_from_file_name (file_name);
3153 prompt = xmalloc (strlen (default_program_name) +
3154 strlen (invocation_prompt));
3155 sprintf (prompt, invocation_prompt, default_program_name);
3156 line = info_read_in_echo_area (window, prompt);
3160 info_abort_key (window, 0, 0);
3164 program_name = line;
3166 program_name = default_program_name;
3168 /* In interactive usage they'd probably expect us to begin looking
3169 from the Top node. */
3170 top_node = info_get_node (file_name, NULL);
3172 info_error (msg_cant_find_node, "Top", NULL);
3174 info_intuit_options_node (window, top_node, program_name);
3176 free (default_program_name);
3179 #if defined (HANDLE_MAN_PAGES)
3180 DECLARE_INFO_COMMAND (info_man, _("Read a manpage reference and select it"))
3184 line = info_read_in_echo_area (window, _("Get Manpage: "));
3188 info_abort_key (window, 0, 0);
3192 canonicalize_whitespace (line);
3198 goto_command = xmalloc
3199 (4 + strlen (MANPAGE_FILE_BUFFER_NAME) + strlen (line));
3201 sprintf (goto_command, "(%s)%s", MANPAGE_FILE_BUFFER_NAME, line);
3203 info_parse_and_select (goto_command, window);
3204 free (goto_command);
3208 if (!info_error_was_printed)
3209 window_clear_echo_area ();
3211 #endif /* HANDLE_MAN_PAGES */
3213 /* Move to the "Top" node in this file. */
3214 DECLARE_INFO_COMMAND (info_top_node, _("Select the node `Top' in this file"))
3216 info_parse_and_select ("Top", window);
3219 /* Move to the node "(dir)Top". */
3220 DECLARE_INFO_COMMAND (info_dir_node, _("Select the node `(dir)'"))
3222 info_parse_and_select ("(dir)Top", window);
3226 /* Read the name of a node to kill. The list of available nodes comes
3227 from the nodes appearing in the current window configuration. */
3229 read_nodename_to_kill (WINDOW *window)
3233 INFO_WINDOW *info_win;
3234 REFERENCE **menu = NULL;
3235 int menu_index = 0, menu_slots = 0;
3236 char *default_nodename = xstrdup (active_window->node->nodename);
3237 char *prompt = xmalloc (strlen (_("Kill node (%s): ")) + strlen (default_nodename));
3239 sprintf (prompt, _("Kill node (%s): "), default_nodename);
3241 for (iw = 0; (info_win = info_windows[iw]); iw++)
3243 REFERENCE *entry = xmalloc (sizeof (REFERENCE));
3244 entry->label = xstrdup (info_win->window->node->nodename);
3245 entry->filename = entry->nodename = NULL;
3247 add_pointer_to_array (entry, menu_index, menu, menu_slots, 10,
3251 nodename = info_read_completing_in_echo_area (window, prompt, menu);
3253 info_free_references (menu);
3254 if (nodename && !*nodename)
3257 nodename = default_nodename;
3260 free (default_nodename);
3266 /* Delete NODENAME from this window, showing the most
3267 recently selected node in this window. */
3269 kill_node (WINDOW *window, char *nodename)
3272 INFO_WINDOW *info_win;
3275 /* If there is no nodename to kill, quit now. */
3278 info_abort_key (window, 0, 0);
3282 /* If there is a nodename, find it in our window list. */
3283 for (iw = 0; (info_win = info_windows[iw]); iw++)
3284 if (strcmp (nodename, info_win->nodes[info_win->current]->nodename) == 0
3285 && info_win->window == window)
3291 info_error (_("Cannot kill node `%s'"), nodename, NULL);
3293 window_clear_echo_area ();
3298 /* If there are no more nodes left anywhere to view, complain and exit. */
3299 if (info_windows_index == 1 && info_windows[0]->nodes_index == 1)
3301 info_error (_("Cannot kill the last node"), NULL, NULL);
3305 /* INFO_WIN contains the node that the user wants to stop viewing. Delete
3306 this node from the list of nodes previously shown in this window. */
3307 for (i = info_win->current; i < info_win->nodes_index; i++)
3308 info_win->nodes[i] = info_win->nodes[i + 1];
3310 /* There is one less node in this window's history list. */
3311 info_win->nodes_index--;
3313 /* Make this window show the most recent history node. */
3314 info_win->current = info_win->nodes_index - 1;
3316 /* If there aren't any nodes left in this window, steal one from the
3318 if (info_win->current < 0)
3320 INFO_WINDOW *stealer;
3324 if (info_windows[iw + 1])
3325 stealer = info_windows[iw + 1];
3327 stealer = info_windows[0];
3329 /* If the node being displayed in the next window is not the most
3330 recently loaded one, get the most recently loaded one. */
3331 if ((stealer->nodes_index - 1) != stealer->current)
3332 which = stealer->nodes_index - 1;
3334 /* Else, if there is another node behind the stealers current node,
3336 else if (stealer->current > 0)
3337 which = stealer->current - 1;
3339 /* Else, just use the node appearing in STEALER's window. */
3341 which = stealer->current;
3343 /* Copy this node. */
3345 NODE *copy = xmalloc (sizeof (NODE));
3347 temp = stealer->nodes[which];
3348 point = stealer->points[which];
3349 pagetop = stealer->pagetops[which];
3351 copy->filename = temp->filename;
3352 copy->parent = temp->parent;
3353 copy->nodename = temp->nodename;
3354 copy->contents = temp->contents;
3355 copy->nodelen = temp->nodelen;
3356 copy->flags = temp->flags;
3357 copy->display_pos = temp->display_pos;
3362 window_set_node_of_window (info_win->window, temp);
3363 window->point = point;
3364 window->pagetop = pagetop;
3365 remember_window_and_node (info_win->window, temp);
3369 temp = info_win->nodes[info_win->current];
3370 temp->display_pos = info_win->points[info_win->current];
3371 window_set_node_of_window (info_win->window, temp);
3374 if (!info_error_was_printed)
3375 window_clear_echo_area ();
3377 if (auto_footnotes_p)
3378 info_get_or_remove_footnotes (window);
3381 /* Kill current node, thus going back one in the node history. I (karl)
3382 do not think this is completely correct yet, because of the
3383 window-changing stuff in kill_node, but it's a lot better than the
3384 previous implementation, which did not account for nodes being
3385 visited twice at all. */
3386 DECLARE_INFO_COMMAND (info_history_node,
3387 _("Select the most recently selected node"))
3389 kill_node (window, active_window->node->nodename);
3392 /* Kill named node. */
3393 DECLARE_INFO_COMMAND (info_kill_node, _("Kill this node"))
3395 char *nodename = read_nodename_to_kill (window);
3396 kill_node (window, nodename);
3400 /* Read the name of a file and select the entire file. */
3401 DECLARE_INFO_COMMAND (info_view_file, _("Read the name of a file and select it"))
3405 line = info_read_in_echo_area (window, _("Find file: "));
3408 info_abort_key (active_window, 1, 0);
3416 node = info_get_node (line, "*");
3419 if (info_recent_file_error)
3420 info_error (info_recent_file_error, NULL, NULL);
3422 info_error (_("Cannot find `%s'."), line, NULL);
3425 info_set_node_of_window (1, window, node);
3430 if (!info_error_was_printed)
3431 window_clear_echo_area ();
3434 /* **************************************************************** */
3436 /* Dumping and Printing Nodes */
3438 /* **************************************************************** */
3440 #define VERBOSE_NODE_DUMPING
3441 static void write_node_to_stream (NODE *node, FILE *stream);
3442 static void dump_node_to_stream (char *filename, char *nodename,
3443 FILE *stream, int dump_subnodes);
3444 static void initialize_dumping (void);
3446 /* Dump the nodes specified by FILENAME and NODENAMES to the file named
3447 in OUTPUT_FILENAME. If DUMP_SUBNODES is non-zero, recursively dump
3448 the nodes which appear in the menu of each node dumped. */
3450 dump_nodes_to_file (char *filename, char **nodenames,
3451 char *output_filename, int dump_subnodes)
3454 FILE *output_stream;
3456 /* Get the stream to print the nodes to. Special case of an output
3457 filename of "-" means to dump the nodes to stdout. */
3458 if (strcmp (output_filename, "-") == 0)
3459 output_stream = stdout;
3461 output_stream = fopen (output_filename, "w");
3465 info_error (_("Could not create output file `%s'."),
3466 output_filename, NULL);
3470 /* Print each node to stream. */
3471 initialize_dumping ();
3472 for (i = 0; nodenames[i]; i++)
3473 dump_node_to_stream (filename, nodenames[i], output_stream, dump_subnodes);
3475 if (output_stream != stdout)
3476 fclose (output_stream);
3478 #if defined (VERBOSE_NODE_DUMPING)
3479 info_error (_("Done."), NULL, NULL);
3480 #endif /* VERBOSE_NODE_DUMPING */
3483 /* A place to remember already dumped nodes. */
3484 static char **dumped_already = NULL;
3485 static int dumped_already_index = 0;
3486 static int dumped_already_slots = 0;
3489 initialize_dumping (void)
3491 dumped_already_index = 0;
3494 /* Get and print the node specified by FILENAME and NODENAME to STREAM.
3495 If DUMP_SUBNODES is non-zero, recursively dump the nodes which appear
3496 in the menu of each node dumped. */
3498 dump_node_to_stream (char *filename, char *nodename,
3499 FILE *stream, int dump_subnodes)
3504 node = info_get_node (filename, nodename);
3508 if (info_recent_file_error)
3509 info_error (info_recent_file_error, NULL, NULL);
3512 if (filename && *nodename != '(')
3513 info_error (msg_cant_file_node,
3514 filename_non_directory (filename),
3517 info_error (msg_cant_find_node, nodename, NULL);
3522 /* If we have already dumped this node, don't dump it again. */
3523 for (i = 0; i < dumped_already_index; i++)
3524 if (strcmp (node->nodename, dumped_already[i]) == 0)
3529 add_pointer_to_array (node->nodename, dumped_already_index, dumped_already,
3530 dumped_already_slots, 50, char *);
3532 #if defined (VERBOSE_NODE_DUMPING)
3533 /* Maybe we should print some information about the node being output. */
3534 info_error (_("Writing node %s..."), node_printed_rep (node), NULL);
3535 #endif /* VERBOSE_NODE_DUMPING */
3537 write_node_to_stream (node, stream);
3539 /* If we are dumping subnodes, get the list of menu items in this node,
3540 and dump each one recursively. */
3543 REFERENCE **menu = NULL;
3545 /* If this node is an Index, do not dump the menu references. */
3546 if (string_in_line ("Index", node->nodename) == -1)
3547 menu = info_menu_of_node (node);
3551 for (i = 0; menu[i]; i++)
3553 /* We don't dump Info files which are different than the
3555 if (!menu[i]->filename)
3557 (filename, menu[i]->nodename, stream, dump_subnodes);
3559 info_free_references (menu);
3566 /* Dump NODE to FILENAME. If DUMP_SUBNODES is non-zero, recursively dump
3567 the nodes which appear in the menu of each node dumped. */
3569 dump_node_to_file (NODE *node, char *filename, int dump_subnodes)
3571 FILE *output_stream;
3572 char *nodes_filename;
3574 /* Get the stream to print this node to. Special case of an output
3575 filename of "-" means to dump the nodes to stdout. */
3576 if (strcmp (filename, "-") == 0)
3577 output_stream = stdout;
3579 output_stream = fopen (filename, "w");
3583 info_error (_("Could not create output file `%s'."), filename,
3589 nodes_filename = node->parent;
3591 nodes_filename = node->filename;
3593 initialize_dumping ();
3595 (nodes_filename, node->nodename, output_stream, dump_subnodes);
3597 if (output_stream != stdout)
3598 fclose (output_stream);
3600 #if defined (VERBOSE_NODE_DUMPING)
3601 info_error (_("Done."), NULL, NULL);
3602 #endif /* VERBOSE_NODE_DUMPING */
3605 #if !defined (DEFAULT_INFO_PRINT_COMMAND)
3606 # define DEFAULT_INFO_PRINT_COMMAND "lpr"
3607 #endif /* !DEFAULT_INFO_PRINT_COMMAND */
3609 DECLARE_INFO_COMMAND (info_print_node,
3610 _("Pipe the contents of this node through INFO_PRINT_COMMAND"))
3612 print_node (window->node);
3615 /* Print NODE on a printer piping it into INFO_PRINT_COMMAND. */
3617 print_node (NODE *node)
3620 char *print_command = getenv ("INFO_PRINT_COMMAND");
3623 if (!print_command || !*print_command)
3624 print_command = DEFAULT_INFO_PRINT_COMMAND;
3626 /* Note that on MS-DOS/MS-Windows, this MUST open the pipe in the
3627 (default) text mode, since the printer drivers there need to see
3628 DOS-style CRLF pairs at the end of each line.
3630 FIXME: if we are to support Mac-style text files, we might need
3631 to convert the text here. */
3633 /* INFO_PRINT_COMMAND which says ">file" means write to that file.
3634 Presumably, the name of the file is the local printer device. */
3635 if (*print_command == '>')
3636 printer_pipe = fopen (++print_command, "w");
3639 printer_pipe = popen (print_command, "w");
3645 info_error (_("Cannot open pipe to `%s'."), print_command, NULL);
3649 #if defined (VERBOSE_NODE_DUMPING)
3650 /* Maybe we should print some information about the node being output. */
3651 info_error (_("Printing node %s..."), node_printed_rep (node), NULL);
3652 #endif /* VERBOSE_NODE_DUMPING */
3654 write_node_to_stream (node, printer_pipe);
3656 pclose (printer_pipe);
3658 fclose (printer_pipe);
3660 #if defined (VERBOSE_NODE_DUMPING)
3661 info_error (_("Done."), NULL, NULL);
3662 #endif /* VERBOSE_NODE_DUMPING */
3666 write_node_to_stream (NODE *node, FILE *stream)
3668 fwrite (node->contents, 1, node->nodelen, stream);
3671 /* **************************************************************** */
3673 /* Info Searching Commands */
3675 /* **************************************************************** */
3677 /* Variable controlling the garbage collection of files briefly visited
3678 during searches. Such files are normally gc'ed, unless they were
3679 compressed to begin with. If this variable is non-zero, it says
3680 to gc even those file buffer contents which had to be uncompressed. */
3681 int gc_compressed_files = 0;
3683 static void info_gc_file_buffers (void);
3684 static void info_search_1 (WINDOW *window, int count,
3685 unsigned char key, int case_sensitive, int ask_for_string);
3687 static char *search_string = NULL;
3688 static int search_string_size = 0;
3689 static int isearch_is_active = 0;
3691 static int last_search_direction = 0;
3692 static int last_search_case_sensitive = 0;
3694 /* Return the file buffer which belongs to WINDOW's node. */
3696 file_buffer_of_window (WINDOW *window)
3698 /* If this window has no node, then it has no file buffer. */
3702 if (window->node->parent)
3703 return info_find_file (window->node->parent);
3705 if (window->node->filename)
3706 return info_find_file (window->node->filename);
3711 /* Search for STRING in NODE starting at START. Return -1 if the string
3712 was not found, or the location of the string if it was. If WINDOW is
3713 passed as non-null, set the window's node to be NODE, its point to be
3714 the found string, and readjust the window's pagetop. The DIR argument
3715 says which direction to search in. If it is positive, search
3716 forward, else backwards.
3718 The last argument, RESBND, makes sense only when USE_REGEX is set.
3719 If the regexp search succeeds, RESBND is filled with the final state
3720 of the search binding. In particular, its START and END fields contain
3721 bounds of the found string instance.
3724 info_search_in_node_internal (char *string, NODE *node, long int start,
3725 WINDOW *window, int dir, int case_sensitive,
3726 SEARCH_BINDING *resbnd)
3728 SEARCH_BINDING binding;
3731 binding.buffer = node->contents;
3732 binding.start = start;
3733 binding.end = node->nodelen;
3735 if (!case_sensitive)
3736 binding.flags |= S_FoldCase;
3741 binding.flags |= S_SkipDest;
3744 if (binding.start < 0)
3747 /* For incremental searches, we always wish to skip past the string. */
3748 if (isearch_is_active)
3749 binding.flags |= S_SkipDest;
3751 offset = (use_regex ?
3752 regexp_search (string, &binding, node->nodelen, resbnd):
3753 search (string, &binding));
3755 if (offset != -1 && window)
3757 set_remembered_pagetop_and_point (window);
3758 if (window->node != node)
3759 window_set_node_of_window (window, node);
3760 window->point = offset;
3761 window_adjust_pagetop (window);
3767 info_search_in_node (char *string, NODE *node, long int start,
3768 WINDOW *window, int dir, int case_sensitive)
3770 return info_search_in_node_internal (string, node, start,
3771 window, dir, case_sensitive, NULL);
3774 /* Search NODE, looking for the largest possible match of STRING. Start the
3775 search at START. Return the absolute position of the match, or -1, if
3776 no part of the string could be found. */
3778 info_target_search_node (NODE *node, char *string, long int start)
3784 target = xstrdup (string);
3785 i = strlen (target);
3787 /* Try repeatedly searching for this string while removing words from
3792 offset = info_search_in_node (target, node, start, NULL, 1, 0);
3797 /* Delete the last word from TARGET. */
3798 for (; i && (!whitespace (target[i]) && (target[i] != ',')); i--);
3804 /* Search for STRING starting in WINDOW. The starting position is determined
3805 by DIR and RESBND argument. If the latter is given, and its START field
3806 is not -1, it gives starting position. Otherwise, the search begins at
3809 If the string is found in this node, set point to that position.
3810 Otherwise, get the file buffer associated with WINDOW's node, and search
3811 through each node in that file.
3813 If the search succeeds and RESBND is given, its START and END fields
3814 contain bounds of the found string instance (only for regexp searches).
3816 If the search fails, return non-zero, else zero. Side-effect window
3817 leaving the node and point where the string was found current. */
3819 info_search_internal (char *string, WINDOW *window,
3820 int dir, int case_sensitive,
3821 SEARCH_BINDING *resbnd)
3824 FILE_BUFFER *file_buffer;
3825 char *initial_nodename;
3828 file_buffer = file_buffer_of_window (window);
3829 initial_nodename = window->node->nodename;
3831 if (resbnd && resbnd->start != -1)
3832 start = resbnd->start;
3834 /* This used to begin from window->point, unless this was a repeated
3835 search command. But invoking search with an argument loses with
3836 that logic, since info_last_executed_command is then set to
3837 info_add_digit_to_numeric_arg. I think there's no sense in
3838 ``finding'' a string that is already under the cursor, anyway. */
3839 start = window->point + dir;
3841 ret = info_search_in_node_internal
3842 (string, window->node, start, window, dir,
3843 case_sensitive, resbnd);
3848 if (!echo_area_is_active && !isearch_is_active)
3849 window_clear_echo_area ();
3855 /* The string wasn't found in the current node. Search through the
3856 window's file buffer, iff the current node is not "*". */
3857 if (!file_buffer || (strcmp (initial_nodename, "*") == 0))
3860 /* If this file has tags, search through every subfile, starting at
3861 this node's subfile and node. Otherwise, search through the
3862 file's node list. */
3863 if (file_buffer->tags)
3865 register int current_tag = 0, number_of_tags;
3870 /* Find number of tags and current tag. */
3871 last_subfile = NULL;
3872 for (i = 0; file_buffer->tags[i]; i++)
3873 if (strcmp (initial_nodename, file_buffer->tags[i]->nodename) == 0)
3876 last_subfile = file_buffer->tags[i]->filename;
3881 /* If there is no last_subfile, our tag wasn't found. */
3885 /* Search through subsequent nodes, wrapping around to the top
3886 of the info file until we find the string or return to this
3887 window's node and point. */
3892 /* Allow C-g to quit the search, failing it if pressed. */
3893 return_if_control_g (-1);
3895 /* Find the next tag that isn't an anchor. */
3896 for (i = current_tag + dir; i != current_tag; i += dir)
3900 msg = N_("Search continued from the end of the document.");
3901 i = number_of_tags - 1;
3903 else if (i == number_of_tags)
3905 msg = N_("Search continued from the beginning of the document.");
3909 tag = file_buffer->tags[i];
3910 if (tag->nodelen != 0)
3914 /* If we got past out starting point, bail out. */
3915 if (i == current_tag)
3919 if (!echo_area_is_active && (last_subfile != tag->filename))
3921 window_message_in_echo_area
3922 (_("Searching subfile %s ..."),
3923 filename_non_directory (tag->filename), NULL);
3925 last_subfile = tag->filename;
3928 node = info_get_node (file_buffer->filename, tag->nodename);
3932 /* If not doing i-search... */
3933 if (!echo_area_is_active)
3935 if (info_recent_file_error)
3936 info_error (info_recent_file_error, NULL, NULL);
3938 info_error (msg_cant_file_node,
3939 filename_non_directory (file_buffer->filename),
3946 start = tag->nodelen;
3949 info_search_in_node_internal (string, node, start, window, dir,
3950 case_sensitive, resbnd);
3952 /* Did we find the string in this node? */
3956 remember_window_and_node (window, node);
3957 if (!echo_area_is_active)
3960 window_message_in_echo_area ("%s", (char *) _(msg), NULL);
3962 window_clear_echo_area ();
3967 /* No. Free this node, and make sure that we haven't passed
3968 our starting point. */
3971 if (strcmp (initial_nodename, tag->nodename) == 0)
3978 DECLARE_INFO_COMMAND (info_search_case_sensitively,
3979 _("Read a string and search for it case-sensitively"))
3981 last_search_direction = count > 0 ? 1 : -1;
3982 last_search_case_sensitive = 1;
3983 info_search_1 (window, count, key, 1, 1);
3986 DECLARE_INFO_COMMAND (info_search, _("Read a string and search for it"))
3988 last_search_direction = count > 0 ? 1 : -1;
3989 last_search_case_sensitive = 0;
3990 info_search_1 (window, count, key, 0, 1);
3993 DECLARE_INFO_COMMAND (info_search_backward,
3994 _("Read a string and search backward for it"))
3996 last_search_direction = count > 0 ? -1 : 1;
3997 last_search_case_sensitive = 0;
3998 info_search_1 (window, -count, key, 0, 1);
4002 info_search_1 (WINDOW *window, int count, unsigned char key,
4003 int case_sensitive, int ask_for_string)
4005 char *line, *prompt;
4006 int result, old_pagetop;
4018 count = 1; /* for backward compatibility */
4021 /* Read a string from the user, defaulting the search to SEARCH_STRING. */
4024 search_string = xmalloc (search_string_size = 100);
4025 search_string[0] = '\0';
4030 prompt = xmalloc (strlen (_("%s%s%s [%s]: "))
4031 + strlen (_("Regexp search"))
4032 + strlen (_(" case-sensitively"))
4033 + strlen (_(" backward"))
4034 + strlen (search_string));
4036 sprintf (prompt, _("%s%s%s [%s]: "),
4037 use_regex ? _("Regexp search") : _("Search"),
4038 case_sensitive ? _(" case-sensitively") : "",
4039 direction < 0 ? _(" backward") : "",
4042 line = info_read_in_echo_area (window, prompt);
4047 info_abort_key (window, 0, 0);
4053 if (strlen (line) + 1 > (unsigned int) search_string_size)
4054 search_string = xrealloc
4055 (search_string, (search_string_size += 50 + strlen (line)));
4057 strcpy (search_string, line);
4062 /* If the search string includes upper-case letters, make the search
4064 if (case_sensitive == 0)
4065 for (line = search_string; *line; line++)
4066 if (isupper (*line))
4072 old_pagetop = active_window->pagetop;
4073 for (result = 0; result == 0 && count--; )
4074 result = info_search_internal (search_string,
4075 active_window, direction, case_sensitive,
4078 if (result != 0 && !info_error_was_printed)
4079 info_error (_("Search failed."), NULL, NULL);
4080 else if (old_pagetop != active_window->pagetop)
4084 new_pagetop = active_window->pagetop;
4085 active_window->pagetop = old_pagetop;
4086 set_window_pagetop (active_window, new_pagetop);
4087 if (auto_footnotes_p)
4088 info_get_or_remove_footnotes (active_window);
4091 /* Perhaps free the unreferenced file buffers that were searched, but
4093 info_gc_file_buffers ();
4096 DECLARE_INFO_COMMAND (info_search_next,
4097 _("Repeat last search in the same direction"))
4099 if (!last_search_direction)
4100 info_error (_("No previous search string"), NULL, NULL);
4102 info_search_1 (window, last_search_direction * count,
4103 key, last_search_case_sensitive, 0);
4106 DECLARE_INFO_COMMAND (info_search_previous,
4107 _("Repeat last search in the reverse direction"))
4109 if (!last_search_direction)
4110 info_error (_("No previous search string"), NULL, NULL);
4112 info_search_1 (window, -last_search_direction * count,
4113 key, last_search_case_sensitive, 0);
4116 /* **************************************************************** */
4118 /* Incremental Searching */
4120 /* **************************************************************** */
4122 static void incremental_search (WINDOW *window, int count,
4123 unsigned char ignore);
4125 DECLARE_INFO_COMMAND (isearch_forward,
4126 _("Search interactively for a string as you type it"))
4128 incremental_search (window, count, key);
4131 DECLARE_INFO_COMMAND (isearch_backward,
4132 _("Search interactively for a string as you type it"))
4134 incremental_search (window, -count, key);
4137 /* Incrementally search for a string as it is typed. */
4138 /* The last accepted incremental search string. */
4139 static char *last_isearch_accepted = NULL;
4141 /* The current incremental search string. */
4142 static char *isearch_string = NULL;
4143 static int isearch_string_index = 0;
4144 static int isearch_string_size = 0;
4145 static unsigned char isearch_terminate_search_key = ESC;
4147 /* Array of search states. */
4148 static SEARCH_STATE **isearch_states = NULL;
4149 static int isearch_states_index = 0;
4150 static int isearch_states_slots = 0;
4152 /* Push the state of this search. */
4154 push_isearch (WINDOW *window, int search_index, int direction, int failing)
4156 SEARCH_STATE *state;
4158 state = xmalloc (sizeof (SEARCH_STATE));
4159 window_get_state (window, state);
4160 state->search_index = search_index;
4161 state->direction = direction;
4162 state->failing = failing;
4164 add_pointer_to_array (state, isearch_states_index, isearch_states,
4165 isearch_states_slots, 20, SEARCH_STATE *);
4168 /* Pop the state of this search to WINDOW, SEARCH_INDEX, and DIRECTION. */
4170 pop_isearch (WINDOW *window, int *search_index, int *direction, int *failing)
4172 SEARCH_STATE *state;
4174 if (isearch_states_index)
4176 isearch_states_index--;
4177 state = isearch_states[isearch_states_index];
4178 window_set_state (window, state);
4179 *search_index = state->search_index;
4180 *direction = state->direction;
4181 *failing = state->failing;
4184 isearch_states[isearch_states_index] = NULL;
4188 /* Free the memory used by isearch_states. */
4190 free_isearch_states (void)
4194 for (i = 0; i < isearch_states_index; i++)
4196 free (isearch_states[i]);
4197 isearch_states[i] = NULL;
4199 isearch_states_index = 0;
4202 /* Display the current search in the echo area. */
4204 show_isearch_prompt (int dir, unsigned char *string, int failing_p)
4208 char *prompt, *p_rep;
4209 unsigned int prompt_len, p_rep_index, p_rep_size;
4212 prefix = use_regex ? _("Regexp I-search backward: ")
4213 : _("I-search backward: ");
4215 prefix = use_regex ? _("Regexp I-search: ")
4218 p_rep_index = p_rep_size = 0;
4220 for (i = 0; string[i]; i++)
4226 case ' ': rep = " "; break;
4227 case LFD: rep = "\\n"; break;
4228 case TAB: rep = "\\t"; break;
4230 rep = pretty_keyname (string[i]);
4232 if ((p_rep_index + strlen (rep) + 1) >= p_rep_size)
4233 p_rep = xrealloc (p_rep, p_rep_size += 100);
4235 strcpy (p_rep + p_rep_index, rep);
4236 p_rep_index += strlen (rep);
4239 prompt_len = strlen (prefix) + p_rep_index + 1;
4241 prompt_len += strlen (_("Failing "));
4242 prompt = xmalloc (prompt_len);
4243 sprintf (prompt, "%s%s%s", failing_p ? _("Failing ") : "", prefix,
4244 p_rep ? p_rep : "");
4246 window_message_in_echo_area ("%s", prompt, NULL);
4249 display_cursor_at_point (active_window);
4253 incremental_search (WINDOW *window, int count, unsigned char ignore)
4256 int last_search_result, search_result, dir;
4257 SEARCH_STATE mystate, orig_state;
4259 int case_sensitive = 0;
4269 last_search_result = search_result = 0;
4271 window_get_state (window, &orig_state);
4273 isearch_string_index = 0;
4274 if (!isearch_string_size)
4275 isearch_string = xmalloc (isearch_string_size = 50);
4277 /* Show the search string in the echo area. */
4278 isearch_string[isearch_string_index] = '\0';
4279 show_isearch_prompt (dir, (unsigned char *) isearch_string, search_result);
4281 isearch_is_active = 1;
4283 while (isearch_is_active)
4285 VFunction *func = NULL;
4288 /* If a recent display was interrupted, then do the redisplay now if
4289 it is convenient. */
4290 if (!info_any_buffered_input_p () && display_was_interrupted_p)
4292 display_update_one_window (window);
4293 display_cursor_at_point (active_window);
4296 /* Read a character and dispatch on it. */
4297 key = info_get_input_char ();
4298 window_get_state (window, &mystate);
4300 if (key == DEL || key == Control ('h'))
4302 /* User wants to delete one level of search? */
4303 if (!isearch_states_index)
4305 terminal_ring_bell ();
4311 (window, &isearch_string_index, &dir, &search_result);
4312 isearch_string[isearch_string_index] = '\0';
4313 show_isearch_prompt (dir, (unsigned char *) isearch_string,
4318 else if (key == Control ('q'))
4320 key = info_get_input_char ();
4324 /* We are about to search again, or quit. Save the current search. */
4325 push_isearch (window, isearch_string_index, dir, search_result);
4328 goto insert_and_search;
4330 if (!Meta_p (key) || key > 32)
4332 /* If this key is not a keymap, get its associated function,
4333 if any. If it is a keymap, then it's probably ESC from an
4334 arrow key, and we handle that case below. */
4335 char type = window->keymap[key].type;
4336 func = type == ISFUNC
4337 ? InfoFunction(window->keymap[key].function)
4338 : NULL; /* function member is a Keymap if ISKMAP */
4340 if (isprint (key) || (type == ISFUNC && func == NULL))
4344 if (isearch_string_index + 2 >= isearch_string_size)
4345 isearch_string = xrealloc
4346 (isearch_string, isearch_string_size += 100);
4348 isearch_string[isearch_string_index++] = key;
4349 isearch_string[isearch_string_index] = '\0';
4352 else if (func == (VFunction *) isearch_forward
4353 || func == (VFunction *) isearch_backward)
4355 /* If this key invokes an incremental search, then this
4356 means that we will either search again in the same
4357 direction, search again in the reverse direction, or
4358 insert the last search string that was accepted through
4359 incremental searching. */
4360 if ((func == (VFunction *) isearch_forward && dir > 0) ||
4361 (func == (VFunction *) isearch_backward && dir < 0))
4363 /* If the user has typed no characters, then insert the
4364 last successful search into the current search string. */
4365 if (isearch_string_index == 0)
4367 /* Of course, there must be something to insert. */
4368 if (last_isearch_accepted)
4370 if (strlen ((char *) last_isearch_accepted) + 1
4371 >= (unsigned int) isearch_string_size)
4372 isearch_string = (char *)
4373 xrealloc (isearch_string,
4374 isearch_string_size += 10 +
4375 strlen (last_isearch_accepted));
4376 strcpy (isearch_string, last_isearch_accepted);
4377 isearch_string_index = strlen (isearch_string);
4385 /* Search again in the same direction. This means start
4386 from a new place if the last search was successful. */
4387 if (search_result == 0)
4389 window->point += dir;
4396 /* Reverse the direction of the search. */
4400 else if (func == (VFunction *) info_abort_key)
4402 /* If C-g pressed, and the search is failing, pop the search
4403 stack back to the last unfailed search. */
4404 if (isearch_states_index && (search_result != 0))
4406 terminal_ring_bell ();
4407 while (isearch_states_index && (search_result != 0))
4409 (window, &isearch_string_index, &dir, &search_result);
4410 isearch_string[isearch_string_index] = '\0';
4411 show_isearch_prompt (dir, (unsigned char *) isearch_string,
4424 /* The character is not printable, or it has a function which is
4425 non-null. Exit the search, remembering the search string. If
4426 the key is not the same as the isearch_terminate_search_key,
4427 then push it into pending input. */
4428 if (isearch_string_index && func != (VFunction *) info_abort_key)
4430 maybe_free (last_isearch_accepted);
4431 last_isearch_accepted = xstrdup (isearch_string);
4434 /* If the key is the isearch_terminate_search_key, but some buffered
4435 input is pending, it is almost invariably because the ESC key is
4436 actually the beginning of an escape sequence, like in case they
4437 pressed an arrow key. So don't gobble the ESC key, push it back
4438 into pending input. */
4439 /* FIXME: this seems like a kludge! We need a more reliable
4440 mechanism to know when ESC is a separate key and when it is
4441 part of an escape sequence. */
4442 if (key != RET /* Emacs addicts want RET to get lost */
4443 && (key != isearch_terminate_search_key
4444 || info_any_buffered_input_p ()))
4445 info_set_pending_input (key);
4447 if (func == (VFunction *) info_abort_key)
4449 if (isearch_states_index)
4450 window_set_state (window, &orig_state);
4453 if (!echo_area_is_active)
4454 window_clear_echo_area ();
4456 if (auto_footnotes_p)
4457 info_get_or_remove_footnotes (active_window);
4459 isearch_is_active = 0;
4463 /* Search for the contents of isearch_string. */
4465 show_isearch_prompt (dir, (unsigned char *) isearch_string, search_result);
4467 /* If the search string includes upper-case letters, make the
4468 search case-sensitive. */
4469 for (p = isearch_string; *p; p++)
4476 /* Regex isearch means we better search again every time. We
4477 might have had a failed search for "\", for example, but now we
4481 search_result = info_search_internal (isearch_string,
4482 window, dir, case_sensitive,
4485 else if (search_result == 0)
4486 { /* We test for search_result being zero because a non-zero
4487 value means the string was not found in entire document. */
4488 /* Check to see if the current search string is right here. If
4489 we are looking at it, then don't bother calling the search
4492 ((case_sensitive ? strncmp : mbsncasecmp)
4493 (window->node->contents + window->point,
4494 isearch_string, isearch_string_index) == 0)) ||
4496 ((window->point - isearch_string_index) >= 0) &&
4497 ((case_sensitive ? strncmp : mbsncasecmp)
4498 (window->node->contents +
4499 (window->point - (isearch_string_index - 1)),
4500 isearch_string, isearch_string_index) == 0)))
4506 search_result = info_search_internal (isearch_string,
4507 window, dir, case_sensitive,
4511 /* If this search failed, and we didn't already have a failed search,
4512 then ring the terminal bell. */
4513 if (search_result != 0 && last_search_result == 0)
4514 terminal_ring_bell ();
4517 show_isearch_prompt (dir, (unsigned char *) isearch_string, search_result);
4519 if (search_result == 0)
4521 if ((mystate.node == window->node) &&
4522 (mystate.pagetop != window->pagetop))
4524 int newtop = window->pagetop;
4525 window->pagetop = mystate.pagetop;
4526 set_window_pagetop (window, newtop);
4528 display_update_one_window (window);
4529 display_cursor_at_point (window);
4532 last_search_result = search_result;
4535 /* Free the memory used to remember each search state. */
4536 free_isearch_states ();
4538 /* Perhaps GC some file buffers. */
4539 info_gc_file_buffers ();
4541 /* After searching, leave the window in the correct state. */
4542 if (!echo_area_is_active)
4543 window_clear_echo_area ();
4546 /* GC some file buffers. A file buffer can be gc-ed if there we have
4547 no nodes in INFO_WINDOWS that reference this file buffer's contents.
4548 Garbage collecting a file buffer means to free the file buffers
4551 info_gc_file_buffers (void)
4553 register int fb_index, iw_index, i;
4554 register FILE_BUFFER *fb;
4555 register INFO_WINDOW *iw;
4557 if (!info_loaded_files)
4560 for (fb_index = 0; (fb = info_loaded_files[fb_index]); fb_index++)
4562 int fb_referenced_p = 0;
4564 /* If already gc-ed, do nothing. */
4568 /* If this file had to be uncompressed, check to see if we should
4569 gc it. This means that the user-variable "gc-compressed-files"
4571 if ((fb->flags & N_IsCompressed) && !gc_compressed_files)
4574 /* If this file's contents are not gc-able, move on. */
4575 if (fb->flags & N_CannotGC)
4578 /* Check each INFO_WINDOW to see if it has any nodes which reference
4580 for (iw_index = 0; (iw = info_windows[iw_index]); iw_index++)
4582 for (i = 0; iw->nodes && iw->nodes[i]; i++)
4584 if ((FILENAME_CMP (fb->fullpath, iw->nodes[i]->filename) == 0) ||
4585 (FILENAME_CMP (fb->filename, iw->nodes[i]->filename) == 0))
4587 fb_referenced_p = 1;
4593 /* If this file buffer wasn't referenced, free its contents. */
4594 if (!fb_referenced_p)
4596 free (fb->contents);
4597 fb->contents = NULL;
4602 /* **************************************************************** */
4604 /* Traversing and Selecting References */
4606 /* **************************************************************** */
4608 /* Move to the next or previous cross reference in this node. */
4610 info_move_to_xref (WINDOW *window, int count, unsigned char key, int dir)
4612 long firstmenu, firstxref;
4613 long nextmenu, nextxref;
4614 long placement = -1;
4616 NODE *node = window->node;
4617 int save_use_regex = use_regex;
4619 /* Most of our keywords contain * characters; don't use regexes. */
4623 start = node->nodelen;
4625 /* This search is only allowed to fail if there is no menu or cross
4626 reference in the current node. Otherwise, the first menu or xref
4627 found is moved to. */
4629 firstmenu = info_search_in_node
4630 (INFO_MENU_ENTRY_LABEL, node, start, NULL, dir, 0);
4632 /* FIRSTMENU may point directly to the line defining the menu. Skip that
4633 and go directly to the first item. */
4635 if (firstmenu != -1)
4637 char *text = node->contents + firstmenu;
4639 if (strncmp (text, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL)) == 0)
4640 firstmenu = info_search_in_node
4641 (INFO_MENU_ENTRY_LABEL, node, firstmenu + dir, NULL, dir, 0);
4645 info_search_in_node (INFO_XREF_LABEL, node, start, NULL, dir, 0);
4647 #if defined (HANDLE_MAN_PAGES)
4648 if ((firstxref == -1) && (node->flags & N_IsManPage))
4650 firstxref = locate_manpage_xref (node, start, dir);
4652 #endif /* HANDLE_MAN_PAGES */
4654 if (firstmenu == -1 && firstxref == -1)
4656 if (!cursor_movement_scrolls_p)
4657 info_error (msg_no_xref_node, NULL, NULL);
4658 use_regex = save_use_regex;
4659 return cursor_movement_scrolls_p;
4662 /* There is at least one cross reference or menu entry in this node.
4663 Try hard to find the next available one. */
4665 nextmenu = info_search_in_node
4666 (INFO_MENU_ENTRY_LABEL, node, window->point + dir, NULL, dir, 0);
4668 nextxref = info_search_in_node
4669 (INFO_XREF_LABEL, node, window->point + dir, NULL, dir, 0);
4671 #if defined (HANDLE_MAN_PAGES)
4672 if ((nextxref == -1) && (node->flags & N_IsManPage) && (firstxref != -1))
4673 nextxref = locate_manpage_xref (node, window->point + dir, dir);
4674 #endif /* HANDLE_MAN_PAGES */
4676 /* Ignore "Menu:" as a menu item. */
4679 char *text = node->contents + nextmenu;
4681 if (strncmp (text, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL)) == 0)
4682 nextmenu = info_search_in_node
4683 (INFO_MENU_ENTRY_LABEL, node, nextmenu + dir, NULL, dir, 0);
4686 /* No more searches, back to whatever the user wanted. */
4687 use_regex = save_use_regex;
4689 /* If there is both a next menu entry, and a next xref entry, choose the
4690 one which occurs first. Otherwise, select the one which actually
4691 appears in this node following point. */
4692 if (nextmenu != -1 && nextxref != -1)
4694 if (((dir == 1) && (nextmenu < nextxref)) ||
4695 ((dir == -1) && (nextmenu > nextxref)))
4696 placement = nextmenu + 1;
4698 placement = nextxref;
4700 else if (nextmenu != -1)
4701 placement = nextmenu + 1;
4702 else if (nextxref != -1)
4703 placement = nextxref;
4705 /* If there was neither a menu or xref entry appearing in this node after
4706 point, choose the first menu or xref entry appearing in this node. */
4707 if (placement == -1)
4709 if (cursor_movement_scrolls_p)
4713 if (firstmenu != -1 && firstxref != -1)
4715 if (((dir == 1) && (firstmenu < firstxref)) ||
4716 ((dir == -1) && (firstmenu > firstxref)))
4717 placement = firstmenu + 1;
4719 placement = firstxref;
4721 else if (firstmenu != -1)
4722 placement = firstmenu + 1;
4724 placement = firstxref;
4727 window->point = placement;
4728 window_adjust_pagetop (window);
4729 window->flags |= W_UpdateWindow;
4733 DECLARE_INFO_COMMAND (info_move_to_prev_xref,
4734 _("Move to the previous cross reference"))
4737 info_move_to_prev_xref (window, -count, key);
4740 while (info_move_to_xref (window, count, key, -1))
4742 info_error_was_printed = 0;
4743 if (backward_move_node_structure (window, info_scroll_behaviour))
4745 move_to_new_line (window->line_count, window->line_count - 1,
4751 DECLARE_INFO_COMMAND (info_move_to_next_xref,
4752 _("Move to the next cross reference"))
4755 info_move_to_next_xref (window, -count, key);
4758 /* Note: This can cause some blinking when the next cross reference is
4759 located several nodes further. This effect can be easily suppressed
4760 by setting display_inhibited to 1, however this will also make
4761 error messages to be dumped on stderr, instead on the echo area. */
4762 while (info_move_to_xref (window, count, key, 1))
4764 info_error_was_printed = 0;
4765 if (forward_move_node_structure (window, info_scroll_behaviour))
4767 move_to_new_line (0, 0, window);
4772 /* Select the menu item or reference that appears on this line. */
4773 DECLARE_INFO_COMMAND (info_select_reference_this_line,
4774 _("Select reference or menu item appearing on this line"))
4778 if (window->line_starts)
4779 line = window->line_starts[window_line_of_point (window)];
4783 /* If this line contains a menu item, select that one. */
4784 if (strncmp ("* ", line, 2) == 0)
4785 info_menu_or_ref_item (window, count, key, info_menu_of_node, 0);
4787 info_menu_or_ref_item (window, count, key, info_xrefs_of_node, 0);
4790 /* **************************************************************** */
4792 /* Miscellaneous Info Commands */
4794 /* **************************************************************** */
4796 /* What to do when C-g is pressed in a window. */
4797 DECLARE_INFO_COMMAND (info_abort_key, _("Cancel current operation"))
4799 /* If error printing doesn't oridinarily ring the bell, do it now,
4800 since C-g always rings the bell. Otherwise, let the error printer
4802 if (!info_error_rings_bell_p)
4803 terminal_ring_bell ();
4804 info_error (_("Quit"), NULL, NULL);
4806 info_initialize_numeric_arg ();
4807 info_clear_pending_input ();
4808 info_last_executed_command = NULL;
4811 /* Move the cursor to the desired line of the window. */
4812 DECLARE_INFO_COMMAND (info_move_to_window_line,
4813 _("Move the cursor to a specific line of the window"))
4817 /* With no numeric argument of any kind, default to the center line. */
4818 if (!info_explicit_arg && count == 1)
4819 line = (window->height / 2) + window->pagetop;
4823 line = (window->height + count) + window->pagetop;
4825 line = window->pagetop + count;
4828 /* If the line doesn't appear in this window, make it do so. */
4829 if ((line - window->pagetop) >= window->height)
4830 line = window->pagetop + (window->height - 1);
4832 /* If the line is too small, make it fit. */
4833 if (line < window->pagetop)
4834 line = window->pagetop;
4836 /* If the selected line is past the bottom of the node, force it back. */
4837 if (line >= window->line_count)
4838 line = window->line_count - 1;
4840 window->point = (window->line_starts[line] - window->node->contents);
4843 /* Clear the screen and redraw its contents. Given a numeric argument,
4844 move the line the cursor is on to the COUNT'th line of the window. */
4845 DECLARE_INFO_COMMAND (info_redraw_display, _("Redraw the display"))
4847 if ((!info_explicit_arg && count == 1) || echo_area_is_active)
4849 terminal_clear_screen ();
4850 display_clear_display (the_display);
4851 window_mark_chain (windows, W_UpdateWindow);
4852 display_update_display (windows);
4856 int desired_line, point_line;
4859 point_line = window_line_of_point (window) - window->pagetop;
4862 desired_line = window->height + count;
4864 desired_line = count;
4866 if (desired_line < 0)
4869 if (desired_line >= window->height)
4870 desired_line = window->height - 1;
4872 if (desired_line == point_line)
4875 new_pagetop = window->pagetop + (point_line - desired_line);
4877 set_window_pagetop (window, new_pagetop);
4880 /* This command does nothing. It is the fact that a key is bound to it
4881 that has meaning. See the code at the top of info_session (). */
4882 DECLARE_INFO_COMMAND (info_quit, _("Quit using Info"))
4886 /* **************************************************************** */
4888 /* Reading Keys and Dispatching on Them */
4890 /* **************************************************************** */
4892 /* Declaration only. Special cased in info_dispatch_on_key ().
4893 Doc string is to avoid ugly results with describe_key etc. */
4894 DECLARE_INFO_COMMAND (info_do_lowercase_version,
4895 _("Run command bound to this key's lowercase variant"))
4899 dispatch_error (char *keyseq)
4903 rep = pretty_keyseq (keyseq);
4905 if (!echo_area_is_active)
4906 info_error (_("Unknown command (%s)."), rep, NULL);
4909 char *temp = xmalloc (1 + strlen (rep) + strlen (_("\"%s\" is invalid")));
4910 sprintf (temp, _("`%s' is invalid"), rep);
4911 terminal_ring_bell ();
4912 inform_in_echo_area (temp);
4917 /* Keeping track of key sequences. */
4918 static char *info_keyseq = NULL;
4919 static int info_keyseq_index = 0;
4920 static int info_keyseq_size = 0;
4921 static int info_keyseq_displayed_p = 0;
4923 /* Initialize the length of the current key sequence. */
4925 initialize_keyseq (void)
4927 info_keyseq_index = 0;
4928 info_keyseq_displayed_p = 0;
4931 /* Add CHARACTER to the current key sequence. */
4933 add_char_to_keyseq (char character)
4935 if (info_keyseq_index + 2 >= info_keyseq_size)
4936 info_keyseq = (char *)xrealloc (info_keyseq, info_keyseq_size += 10);
4938 info_keyseq[info_keyseq_index++] = character;
4939 info_keyseq[info_keyseq_index] = '\0';
4942 /* Display the current value of info_keyseq. If argument EXPECTING is
4943 non-zero, input is expected to be read after the key sequence is
4944 displayed, so add an additional prompting character to the sequence. */
4946 display_info_keyseq (int expecting_future_input)
4950 rep = pretty_keyseq (info_keyseq);
4951 if (expecting_future_input)
4954 if (echo_area_is_active)
4955 inform_in_echo_area (rep);
4958 window_message_in_echo_area (rep, NULL, NULL);
4959 display_cursor_at_point (active_window);
4961 info_keyseq_displayed_p = 1;
4964 /* Called by interactive commands to read a keystroke. */
4966 info_get_another_input_char (void)
4968 int ready = !info_keyseq_displayed_p; /* ready if new and pending key */
4970 /* If there isn't any input currently available, then wait a
4971 moment looking for input. If we don't get it fast enough,
4972 prompt a little bit with the current key sequence. */
4973 if (!info_keyseq_displayed_p)
4976 if (!info_any_buffered_input_p () &&
4977 !info_input_pending_p ())
4979 #if defined (FD_SET)
4980 struct timeval timer;
4984 FD_SET (fileno (info_input_stream), &readfds);
4986 timer.tv_usec = 750;
4987 ready = select (fileno(info_input_stream)+1, &readfds,
4988 NULL, NULL, &timer);
4996 display_info_keyseq (1);
4998 return info_get_input_char ();
5001 /* Do the command associated with KEY in MAP. If the associated command is
5002 really a keymap, then read another key, and dispatch into that map. */
5004 info_dispatch_on_key (unsigned char key, Keymap map)
5006 #if !defined(INFOKEY)
5007 if (Meta_p (key) && (!ISO_Latin_p || map[key].function != ea_insert))
5009 if (map[ESC].type == ISKMAP)
5011 map = (Keymap)map[ESC].function;
5012 add_char_to_keyseq (ESC);
5014 info_dispatch_on_key (key, map);
5018 dispatch_error (info_keyseq);
5022 #endif /* INFOKEY */
5024 switch (map[key].type)
5030 func = InfoFunction(map[key].function);
5033 /* Special case info_do_lowercase_version (). */
5034 if (func == (VFunction *) info_do_lowercase_version)
5036 #if defined(INFOKEY)
5037 unsigned char lowerkey;
5039 lowerkey = Meta_p(key) ? Meta (tolower (UnMeta (key))) : tolower (key);
5040 if (lowerkey == key)
5042 add_char_to_keyseq (key);
5043 dispatch_error (info_keyseq);
5046 info_dispatch_on_key (lowerkey, map);
5047 #else /* !INFOKEY */
5048 info_dispatch_on_key (tolower (key), map);
5049 #endif /* INFOKEY */
5053 add_char_to_keyseq (key);
5055 if (info_keyseq_displayed_p)
5056 display_info_keyseq (0);
5061 where = active_window;
5062 (*InfoFunction(map[key].function))
5063 (active_window, info_numeric_arg * info_numeric_arg_sign, key);
5065 /* If we have input pending, then the last command was a prefix
5066 command. Don't change the value of the last function vars.
5067 Otherwise, remember the last command executed in the var
5068 appropriate to the window in which it was executed. */
5069 if (!info_input_pending_p ())
5071 if (where == the_echo_area)
5072 ea_last_executed_command = InfoFunction(map[key].function);
5074 info_last_executed_command = InfoFunction(map[key].function);
5080 add_char_to_keyseq (key);
5081 dispatch_error (info_keyseq);
5088 add_char_to_keyseq (key);
5089 if (map[key].function != NULL)
5091 unsigned char newkey;
5093 newkey = info_get_another_input_char ();
5094 info_dispatch_on_key (newkey, (Keymap)map[key].function);
5098 dispatch_error (info_keyseq);
5105 /* **************************************************************** */
5107 /* Numeric Arguments */
5109 /* **************************************************************** */
5111 /* Handle C-u style numeric args, as well as M--, and M-digits. */
5113 /* Non-zero means that an explicit argument has been passed to this
5114 command, as in C-u C-v. */
5115 int info_explicit_arg = 0;
5117 /* The sign of the numeric argument. */
5118 int info_numeric_arg_sign = 1;
5120 /* The value of the argument itself. */
5121 int info_numeric_arg = 1;
5123 /* Add the current digit to the argument in progress. */
5124 DECLARE_INFO_COMMAND (info_add_digit_to_numeric_arg,
5125 _("Add this digit to the current numeric argument"))
5127 info_numeric_arg_digit_loop (window, 0, key);
5130 /* C-u, universal argument. Multiply the current argument by 4.
5131 Read a key. If the key has nothing to do with arguments, then
5132 dispatch on it. If the key is the abort character then abort. */
5133 DECLARE_INFO_COMMAND (info_universal_argument,
5134 _("Start (or multiply by 4) the current numeric argument"))
5136 info_numeric_arg *= 4;
5137 info_numeric_arg_digit_loop (window, 0, 0);
5140 /* Create a default argument. */
5142 info_initialize_numeric_arg (void)
5144 info_numeric_arg = info_numeric_arg_sign = 1;
5145 info_explicit_arg = 0;
5148 DECLARE_INFO_COMMAND (info_numeric_arg_digit_loop,
5149 _("Internally used by \\[universal-argument]"))
5151 unsigned char pure_key;
5152 Keymap keymap = window->keymap;
5160 if (display_was_interrupted_p && !info_any_buffered_input_p ())
5161 display_update_display (windows);
5163 if (active_window != the_echo_area)
5164 display_cursor_at_point (active_window);
5166 pure_key = key = info_get_another_input_char ();
5168 #if !defined(INFOKEY)
5170 add_char_to_keyseq (ESC);
5172 add_char_to_keyseq (UnMeta (key));
5173 #else /* defined(INFOKEY) */
5174 add_char_to_keyseq (key);
5175 #endif /* defined(INFOKEY) */
5178 #if !defined(INFOKEY)
5181 #endif /* !defined(INFOKEY) */
5183 if (keymap[key].type == ISFUNC
5184 && InfoFunction(keymap[key].function)
5185 == (VFunction *) info_universal_argument)
5187 info_numeric_arg *= 4;
5192 #if defined(INFOKEY)
5195 #endif /* !defined(INFOKEY) */
5200 if (info_explicit_arg)
5201 info_numeric_arg = (info_numeric_arg * 10) + (key - '0');
5203 info_numeric_arg = (key - '0');
5204 info_explicit_arg = 1;
5208 if (key == '-' && !info_explicit_arg)
5210 info_numeric_arg_sign = -1;
5211 info_numeric_arg = 1;
5215 info_keyseq_index--;
5216 info_dispatch_on_key (pure_key, keymap);
5224 /* **************************************************************** */
5226 /* Input Character Buffering */
5228 /* **************************************************************** */
5230 /* Character waiting to be read next. */
5231 static int pending_input_character = 0;
5233 /* How to make there be no pending input. */
5235 info_clear_pending_input (void)
5237 pending_input_character = 0;
5240 /* How to set the pending input character. */
5242 info_set_pending_input (unsigned char key)
5244 pending_input_character = key;
5247 /* How to see if there is any pending input. */
5249 info_input_pending_p (void)
5251 return pending_input_character;
5254 /* Largest number of characters that we can read in advance. */
5255 #define MAX_INFO_INPUT_BUFFERING 512
5257 static int pop_index = 0, push_index = 0;
5258 static unsigned char info_input_buffer[MAX_INFO_INPUT_BUFFERING];
5260 /* Add KEY to the buffer of characters to be read. */
5262 info_push_typeahead (unsigned char key)
5264 /* Flush all pending input in the case of C-g pressed. */
5265 if (key == Control ('g'))
5267 push_index = pop_index;
5268 info_set_pending_input (Control ('g'));
5272 info_input_buffer[push_index++] = key;
5273 if ((unsigned int) push_index >= sizeof (info_input_buffer))
5278 /* Return the amount of space available in INFO_INPUT_BUFFER for new chars. */
5280 info_input_buffer_space_available (void)
5282 if (pop_index > push_index)
5283 return pop_index - push_index;
5285 return sizeof (info_input_buffer) - (push_index - pop_index);
5288 /* Get a key from the buffer of characters to be read.
5289 Return the key in KEY.
5290 Result is non-zero if there was a key, or 0 if there wasn't. */
5292 info_get_key_from_typeahead (unsigned char *key)
5294 if (push_index == pop_index)
5297 *key = info_input_buffer[pop_index++];
5299 if ((unsigned int) pop_index >= sizeof (info_input_buffer))
5306 info_any_buffered_input_p (void)
5308 info_gather_typeahead ();
5309 return push_index != pop_index;
5312 /* If characters are available to be read, then read them and stuff them into
5313 info_input_buffer. Otherwise, do nothing. */
5315 info_gather_typeahead (void)
5318 int tty, space_avail;
5320 unsigned char input[MAX_INFO_INPUT_BUFFERING];
5322 tty = fileno (info_input_stream);
5325 space_avail = info_input_buffer_space_available ();
5327 /* If we can just find out how many characters there are to read, do so. */
5328 #if defined (FIONREAD)
5330 ioctl (tty, FIONREAD, &chars_avail);
5332 if (chars_avail > space_avail)
5333 chars_avail = space_avail;
5336 chars_avail = read (tty, &input[0], chars_avail);
5338 #else /* !FIONREAD */
5339 # if defined (O_NDELAY)
5343 flags = fcntl (tty, F_GETFL, 0);
5345 fcntl (tty, F_SETFL, (flags | O_NDELAY));
5346 chars_avail = read (tty, &input[0], space_avail);
5347 fcntl (tty, F_SETFL, flags);
5349 if (chars_avail == -1)
5352 # else /* !O_NDELAY */
5355 extern long pc_term_chars_avail (void);
5358 chars_avail = pc_term_chars_avail ();
5361 /* We could be more accurate by calling ltell, but we have no idea
5362 whether tty is buffered by stdio functions, and if so, how many
5363 characters are already waiting in the buffer. So we punt. */
5366 if (fstat (tty, &st) < 0)
5369 chars_avail = st.st_size;
5371 if (chars_avail > space_avail)
5372 chars_avail = space_avail;
5374 chars_avail = read (tty, &input[0], chars_avail);
5376 # endif/* __DJGPP__ */
5377 # endif /* O_NDELAY */
5378 #endif /* !FIONREAD */
5380 while (i < chars_avail)
5382 info_push_typeahead (input[i]);
5387 /* How to read a single character. */
5389 info_get_input_char (void)
5391 unsigned char keystroke;
5393 info_gather_typeahead ();
5395 if (pending_input_character)
5397 keystroke = pending_input_character;
5398 pending_input_character = 0;
5400 else if (info_get_key_from_typeahead (&keystroke) == 0)
5404 int tty = fileno (info_input_stream);
5406 /* Using stream I/O causes FIONREAD etc to fail to work
5407 so unless someone can find a portable way of finding
5408 out how many characters are currently buffered, we
5409 should stay with away from stream I/O.
5410 --Egil Kvaleberg <egilk@sn.no>, January 1997. */
5412 /* Keep reading if we got EINTR, so that we don't just exit.
5413 --Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>,
5418 n = read (tty, &c, 1);
5419 while (n == -1 && errno == EINTR);
5420 rawkey = n == 1 ? c : EOF;
5423 rawkey = (read (tty, &c, 1) == 1) ? c : EOF;
5430 if (info_input_stream != stdin)
5432 fclose (info_input_stream);
5433 info_input_stream = stdin;
5434 tty = fileno (info_input_stream);
5435 display_inhibited = 0;
5436 display_update_display (windows);
5437 display_cursor_at_point (active_window);
5438 rawkey = (read (tty, &c, 1) == 1) ? c : EOF;
5444 terminal_unprep_terminal ();
5445 close_dribble_file ();
5451 if (info_dribble_file)
5452 dribble (keystroke);