Sync usage with man page.
[netbsd-mini2440.git] / gnu / dist / texinfo / info / info.c
blobec2fff4b2a8a0b275663765caf0ed88210147409
1 /* $NetBSD: info.c,v 1.1.1.7 2008/09/02 07:49:43 christos Exp $ */
3 /* info.c -- Display nodes of Info files in multiple windows.
4 Id: info.c,v 1.11 2004/04/11 17:56:45 karl Exp
6 Copyright (C) 1993, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
7 2004 Free Software Foundation, Inc.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 Written by Brian Fox (bfox@ai.mit.edu). */
25 #include "info.h"
26 #include "indices.h"
27 #include "dribble.h"
28 #include "getopt.h"
29 #if defined (HANDLE_MAN_PAGES)
30 # include "man.h"
31 #endif /* HANDLE_MAN_PAGES */
33 static char *program_name = "info";
35 /* Non-zero means search all indices for APROPOS_SEARCH_STRING. */
36 static int apropos_p = 0;
38 /* Variable containing the string to search for when apropos_p is non-zero. */
39 static char *apropos_search_string = (char *)NULL;
41 /* Non-zero means search all indices for INDEX_SEARCH_STRING. Unlike
42 apropos, this puts the user at the node, running info. */
43 static int index_search_p = 0;
45 /* Non-zero means look for the node which describes the invocation
46 and command-line options of the program, and start the info
47 session at that node. */
48 static int goto_invocation_p = 0;
50 /* Variable containing the string to search for when index_search_p is
51 non-zero. */
52 static char *index_search_string = (char *)NULL;
54 /* Non-zero means print version info only. */
55 static int print_version_p = 0;
57 /* Non-zero means print a short description of the options. */
58 static int print_help_p = 0;
60 /* Array of the names of nodes that the user specified with "--node" on the
61 command line. */
62 static char **user_nodenames = (char **)NULL;
63 static int user_nodenames_index = 0;
64 static int user_nodenames_slots = 0;
66 /* String specifying the first file to load. This string can only be set
67 by the user specifying "--file" on the command line. */
68 static char *user_filename = (char *)NULL;
70 /* String specifying the name of the file to dump nodes to. This value is
71 filled if the user speficies "--output" on the command line. */
72 static char *user_output_filename = (char *)NULL;
74 /* Non-zero indicates that when "--output" is specified, all of the menu
75 items of the specified nodes (and their subnodes as well) should be
76 dumped in the order encountered. This basically can print a book. */
77 int dump_subnodes = 0;
79 /* Non-zero means make default keybindings be loosely modeled on vi(1). */
80 int vi_keys_p = 0;
82 /* Non-zero means don't remove ANSI escape sequences. */
83 int raw_escapes_p = 1;
85 /* Non-zero means print the absolute location of the file to be loaded. */
86 static int print_where_p = 0;
88 #ifdef __MSDOS__
89 /* Non-zero indicates that screen output should be made 'speech-friendly'.
90 Since on MSDOS the usual behavior is to write directly to the video
91 memory, speech synthesizer software cannot grab the output. Therefore,
92 we provide a user option which tells us to avoid direct screen output
93 and use stdout instead (which loses the color output). */
94 int speech_friendly = 0;
95 #endif
97 /* Structure describing the options that Info accepts. We pass this structure
98 to getopt_long (). If you add or otherwise change this structure, you must
99 also change the string which follows it. */
100 #define APROPOS_OPTION 1
101 #define DRIBBLE_OPTION 2
102 #define RESTORE_OPTION 3
103 #define IDXSRCH_OPTION 4
104 static struct option long_options[] = {
105 { "apropos", 1, 0, APROPOS_OPTION },
106 { "directory", 1, 0, 'd' },
107 { "dribble", 1, 0, DRIBBLE_OPTION },
108 { "file", 1, 0, 'f' },
109 { "help", 0, &print_help_p, 1 },
110 { "index-search", 1, 0, IDXSRCH_OPTION },
111 { "location", 0, &print_where_p, 1 },
112 { "node", 1, 0, 'n' },
113 { "output", 1, 0, 'o' },
114 { "raw-escapes", 0, &raw_escapes_p, 1 },
115 { "no-raw-escapes", 0, &raw_escapes_p, 0 },
116 { "restore", 1, 0, RESTORE_OPTION },
117 { "show-options", 0, 0, 'O' },
118 { "subnodes", 0, &dump_subnodes, 1 },
119 { "usage", 0, 0, 'O' },
120 { "version", 0, &print_version_p, 1 },
121 { "vi-keys", 0, &vi_keys_p, 1 },
122 { "where", 0, &print_where_p, 1 },
123 #ifdef __MSDOS__
124 { "speech-friendly", 0, &speech_friendly, 1 },
125 #endif
126 {NULL, 0, NULL, 0}
129 /* String describing the shorthand versions of the long options found above. */
130 #ifdef __MSDOS__
131 static char *short_options = "d:n:f:ho:ORswb";
132 #else
133 static char *short_options = "d:n:f:ho:ORws";
134 #endif
136 /* When non-zero, the Info window system has been initialized. */
137 int info_windows_initialized_p = 0;
139 /* Some "forward" declarations. */
140 static void info_short_help (void);
141 static void init_messages (void);
144 /* **************************************************************** */
145 /* */
146 /* Main Entry Point to the Info Program */
147 /* */
148 /* **************************************************************** */
151 main (int argc, char **argv)
153 int getopt_long_index; /* Index returned by getopt_long (). */
154 NODE *initial_node; /* First node loaded by Info. */
156 #ifdef HAVE_SETLOCALE
157 /* Set locale via LC_ALL. */
158 setlocale (LC_ALL, "");
159 #endif
161 #ifdef ENABLE_NLS
162 /* Set the text message domain. */
163 bindtextdomain (PACKAGE, LOCALEDIR);
164 textdomain (PACKAGE);
165 #endif
167 init_messages ();
169 while (1)
171 int option_character;
173 option_character = getopt_long
174 (argc, argv, short_options, long_options, &getopt_long_index);
176 /* getopt_long returns EOF when there are no more long options. */
177 if (option_character == EOF)
178 break;
180 /* If this is a long option, then get the short version of it. */
181 if (option_character == 0 && long_options[getopt_long_index].flag == 0)
182 option_character = long_options[getopt_long_index].val;
184 /* Case on the option that we have received. */
185 switch (option_character)
187 case 0:
188 break;
190 /* User wants to add a directory. */
191 case 'd':
192 info_add_path (optarg, INFOPATH_PREPEND);
193 break;
195 /* User is specifying a particular node. */
196 case 'n':
197 add_pointer_to_array (optarg, user_nodenames_index, user_nodenames,
198 user_nodenames_slots, 10, char *);
199 break;
201 /* User is specifying a particular Info file. */
202 case 'f':
203 if (user_filename)
204 free (user_filename);
206 user_filename = xstrdup (optarg);
207 break;
209 /* Treat -h like --help. */
210 case 'h':
211 print_help_p = 1;
212 break;
214 /* User is specifying the name of a file to output to. */
215 case 'o':
216 if (user_output_filename)
217 free (user_output_filename);
218 user_output_filename = xstrdup (optarg);
219 break;
221 /* User has specified that she wants to find the "Options"
222 or "Invocation" node for the program. */
223 case 'O':
224 goto_invocation_p = 1;
225 break;
227 /* User has specified that she wants the escape sequences
228 in man pages to be passed thru unaltered. */
229 case 'R':
230 raw_escapes_p = 1;
231 break;
233 /* User is specifying that she wishes to dump the subnodes of
234 the node that she is dumping. */
235 case 's':
236 dump_subnodes = 1;
237 break;
239 /* For compatibility with man, -w is --where. */
240 case 'w':
241 print_where_p = 1;
242 break;
244 #ifdef __MSDOS__
245 /* User wants speech-friendly output. */
246 case 'b':
247 speech_friendly = 1;
248 break;
249 #endif /* __MSDOS__ */
251 /* User has specified a string to search all indices for. */
252 case APROPOS_OPTION:
253 apropos_p = 1;
254 maybe_free (apropos_search_string);
255 apropos_search_string = xstrdup (optarg);
256 break;
258 /* User has specified a dribble file to receive keystrokes. */
259 case DRIBBLE_OPTION:
260 close_dribble_file ();
261 open_dribble_file (optarg);
262 break;
264 /* User has specified an alternate input stream. */
265 case RESTORE_OPTION:
266 info_set_input_from_file (optarg);
267 break;
269 /* User has specified a string to search all indices for. */
270 case IDXSRCH_OPTION:
271 index_search_p = 1;
272 maybe_free (index_search_string);
273 index_search_string = xstrdup (optarg);
274 break;
276 default:
277 fprintf (stderr, _("Try --help for more information.\n"));
278 xexit (1);
282 /* If the output device is not a terminal, and no output filename has been
283 specified, make user_output_filename be "-", so that the info is written
284 to stdout, and turn on the dumping of subnodes. */
285 if ((!isatty (fileno (stdout))) && (user_output_filename == (char *)NULL))
287 user_output_filename = xstrdup ("-");
288 dump_subnodes = 1;
291 /* If the user specified --version, then show the version and exit. */
292 if (print_version_p)
294 printf ("%s (GNU %s) %s\n", program_name, PACKAGE, VERSION);
295 puts ("");
296 puts ("Copyright (C) 2004 Free Software Foundation, Inc.");
297 printf (_("There is NO warranty. You may redistribute this software\n\
298 under the terms of the GNU General Public License.\n\
299 For more information about these matters, see the files named COPYING.\n"));
300 xexit (0);
303 /* If the `--help' option was present, show the help and exit. */
304 if (print_help_p)
306 info_short_help ();
307 xexit (0);
310 /* If the user hasn't specified a path for Info files, default it.
311 Lowest priority is our messy hardwired list in filesys.h.
312 Then comes the user's INFODIR from the Makefile.
313 Highest priority is the environment variable, if set. */
314 if (!infopath)
316 char *path_from_env = getenv ("INFOPATH");
318 if (path_from_env)
320 unsigned len = strlen (path_from_env);
321 /* Trailing : on INFOPATH means insert the default path. */
322 if (len && path_from_env[len - 1] == PATH_SEP[0])
324 path_from_env[len - 1] = 0;
325 info_add_path (DEFAULT_INFOPATH, INFOPATH_PREPEND);
327 #ifdef INFODIR /* from the Makefile */
328 info_add_path (INFODIR, INFOPATH_PREPEND);
329 #endif
330 info_add_path (path_from_env, INFOPATH_PREPEND);
332 else
334 info_add_path (DEFAULT_INFOPATH, INFOPATH_PREPEND);
335 #ifdef INFODIR /* from the Makefile */
336 info_add_path (INFODIR, INFOPATH_PREPEND);
337 #endif
338 #ifdef INFODIR2 /* from the Makefile, too */
339 # ifdef INFODIR
340 if (!STREQ (INFODIR, INFODIR2))
341 # endif
342 info_add_path (INFODIR2, INFOPATH_PREPEND);
343 #endif
347 /* If the user specified a particular filename, add the path of that
348 file to the contents of INFOPATH. */
349 if (user_filename)
350 add_file_directory_to_path (user_filename);
352 /* If the user wants to search every known index for a given string,
353 do that now, and report the results. */
354 if (apropos_p)
356 info_apropos (apropos_search_string);
357 xexit (0);
360 /* Get the initial Info node. It is either "(dir)Top", or what the user
361 specifed with values in user_filename and user_nodenames. */
362 initial_node = info_get_node (user_filename,
363 user_nodenames ? user_nodenames[0] : 0);
365 /* If we couldn't get the initial node, this user is in trouble. */
366 if (!initial_node)
368 if (info_recent_file_error)
369 info_error (info_recent_file_error, NULL, NULL);
370 else
371 info_error ((char *) msg_cant_find_node,
372 user_nodenames ? user_nodenames[0] : "Top", NULL);
373 xexit (1);
376 /* Special cases for when the user specifies multiple nodes. If we
377 are dumping to an output file, dump all of the nodes specified.
378 Otherwise, attempt to create enough windows to handle the nodes
379 that this user wants displayed. */
380 if (user_nodenames_index > 1)
382 free (initial_node);
384 if (print_where_p)
385 printf ("%s\n", user_filename ? user_filename : "unknown?!");
386 else if (user_output_filename)
387 dump_nodes_to_file
388 (user_filename, user_nodenames, user_output_filename, dump_subnodes);
389 else
390 begin_multiple_window_info_session (user_filename, user_nodenames);
392 xexit (0);
395 /* If there are arguments remaining, they are the names of menu items
396 in sequential info files starting from the first one loaded. That
397 file name is either "dir", or the contents of user_filename if one
398 was specified. */
400 const char *errstr;
401 char *errarg1, *errarg2;
403 NODE *new_initial_node = info_follow_menus (initial_node, argv + optind,
404 &errstr, &errarg1, &errarg2);
406 if (new_initial_node && new_initial_node != initial_node)
407 initial_node = new_initial_node;
409 if (print_where_p)
411 if (initial_node->parent)
412 printf ("%s\n", initial_node->parent);
413 else if (initial_node->filename
414 && !is_dir_name (filename_non_directory (initial_node->filename)))
415 printf ("%s\n", initial_node->filename);
416 else
417 xexit (1);
418 xexit (0);
421 /* If the user specified that this node should be output, then do that
422 now. Otherwise, start the Info session with this node. Or act
423 accordingly if the initial node was not found. */
424 if (user_output_filename && !goto_invocation_p)
426 if (!errstr)
427 dump_node_to_file (initial_node, user_output_filename,
428 dump_subnodes);
429 else
430 info_error ((char *) errstr, errarg1, errarg2);
432 else
435 if (errstr)
436 begin_info_session_with_error (initial_node, (char *) errstr,
437 errarg1, errarg2);
438 /* If the user specified `--index-search=STRING' or
439 --show-options, start the info session in the node
440 corresponding to what they want. */
441 else if (index_search_p || goto_invocation_p)
443 int status = 0;
445 initialize_info_session (initial_node, 0);
447 if (goto_invocation_p
448 || index_entry_exists (windows, index_search_string))
450 terminal_prep_terminal ();
451 terminal_clear_screen ();
452 info_last_executed_command = (VFunction *)NULL;
454 if (index_search_p)
455 do_info_index_search (windows, 0, index_search_string);
456 else
458 /* If they said "info --show-options foo bar baz",
459 the last of the arguments is the program whose
460 options they want to see. */
461 char **p = argv + optind;
462 char *program;
464 if (*p)
466 while (p[1])
467 p++;
468 program = xstrdup (*p);
470 else if (user_filename)
471 /* If there's no command-line arguments to
472 supply the program name, use the Info file
473 name (sans extension and leading directories)
474 instead. */
475 program = program_name_from_file_name (user_filename);
476 else
477 program = xstrdup ("");
479 info_intuit_options_node (windows, initial_node, program);
480 free (program);
483 if (user_output_filename)
485 dump_node_to_file (windows->node, user_output_filename,
486 dump_subnodes);
488 else
489 info_read_and_dispatch ();
491 /* On program exit, leave the cursor at the bottom of the
492 window, and restore the terminal IO. */
493 terminal_goto_xy (0, screenheight - 1);
494 terminal_clear_to_eol ();
495 fflush (stdout);
496 terminal_unprep_terminal ();
498 else
500 fprintf (stderr, _("no index entries found for `%s'\n"),
501 index_search_string);
502 status = 2;
505 close_dribble_file ();
506 xexit (status);
508 else
509 begin_info_session (initial_node);
512 xexit (0);
515 return 0; /* Avoid bogus warnings. */
518 void
519 add_file_directory_to_path (char *filename)
521 char *directory_name = xstrdup (filename);
522 char *temp = filename_non_directory (directory_name);
524 if (temp != directory_name)
526 if (HAVE_DRIVE (directory_name) && temp == directory_name + 2)
528 /* The directory of "d:foo" is stored as "d:.", to avoid
529 mixing it with "d:/" when a slash is appended. */
530 *temp = '.';
531 temp += 2;
533 temp[-1] = 0;
534 info_add_path (directory_name, INFOPATH_PREPEND);
537 free (directory_name);
541 /* Error handling. */
543 /* Non-zero if an error has been signalled. */
544 int info_error_was_printed = 0;
546 /* Non-zero means ring terminal bell on errors. */
547 int info_error_rings_bell_p = 1;
549 /* Print FORMAT with ARG1 and ARG2. If the window system was initialized,
550 then the message is printed in the echo area. Otherwise, a message is
551 output to stderr. */
552 void
553 info_error (char *format, void *arg1, void *arg2)
555 info_error_was_printed = 1;
557 if (!info_windows_initialized_p || display_inhibited)
559 fprintf (stderr, "%s: ", program_name);
560 fprintf (stderr, format, arg1, arg2);
561 fprintf (stderr, "\n");
562 fflush (stderr);
564 else
566 if (!echo_area_is_active)
568 if (info_error_rings_bell_p)
569 terminal_ring_bell ();
570 window_message_in_echo_area (format, arg1, arg2);
572 else
574 NODE *temp;
576 temp = build_message_node (format, arg1, arg2);
577 if (info_error_rings_bell_p)
578 terminal_ring_bell ();
579 inform_in_echo_area (temp->contents);
580 free (temp->contents);
581 free (temp);
587 /* Produce a scaled down description of the available options to Info. */
588 static void
589 info_short_help (void)
591 #ifdef __MSDOS__
592 static const char speech_friendly_string[] = N_("\
593 -b, --speech-friendly be friendly to speech synthesizers.\n");
594 #else
595 static const char speech_friendly_string[] = "";
596 #endif
599 printf (_("\
600 Usage: %s [OPTION]... [MENU-ITEM...]\n\
602 Read documentation in Info format.\n\
604 Options:\n\
605 --apropos=STRING look up STRING in all indices of all manuals.\n\
606 -d, --directory=DIR add DIR to INFOPATH.\n\
607 --dribble=FILENAME remember user keystrokes in FILENAME.\n\
608 -f, --file=FILENAME specify Info file to visit.\n\
609 -h, --help display this help and exit.\n\
610 --index-search=STRING go to node pointed by index entry STRING.\n\
611 -n, --node=NODENAME specify nodes in first visited Info file.\n\
612 -o, --output=FILENAME output selected nodes to FILENAME.\n\
613 -R, --raw-escapes output \"raw\" ANSI escapes (default).\n\
614 --no-raw-escapes output escapes as literal text.\n\
615 --restore=FILENAME read initial keystrokes from FILENAME.\n\
616 -O, --show-options, --usage go to command-line options node.\n%s\
617 --subnodes recursively output menu items.\n\
618 -w, --where, --location print physical location of Info file.\n\
619 --vi-keys use vi-like and less-like key bindings.\n\
620 --version display version information and exit.\n\
622 The first non-option argument, if present, is the menu entry to start from;\n\
623 it is searched for in all `dir' files along INFOPATH.\n\
624 If it is not present, info merges all `dir' files and shows the result.\n\
625 Any remaining arguments are treated as the names of menu\n\
626 items relative to the initial node visited.\n\
628 Examples:\n\
629 info show top-level dir menu\n\
630 info emacs start at emacs node from top-level dir\n\
631 info emacs buffers start at buffers node within emacs manual\n\
632 info --show-options emacs start at node with emacs' command line options\n\
633 info -f ./foo.info show file ./foo.info, not searching dir\n\
635 program_name, speech_friendly_string);
637 puts (_("\n\
638 Email bug reports to bug-texinfo@gnu.org,\n\
639 general questions and discussion to help-texinfo@gnu.org.\n\
640 Texinfo home page: http://www.gnu.org/software/texinfo/"));
642 xexit (0);
646 /* Initialize strings for gettext. Because gettext doesn't handle N_ or
647 _ within macro definitions, we put shared messages into variables and
648 use them that way. This also has the advantage that there's only one
649 copy of the strings. */
651 const char *msg_cant_find_node;
652 const char *msg_cant_file_node;
653 const char *msg_cant_find_window;
654 const char *msg_cant_find_point;
655 const char *msg_cant_kill_last;
656 const char *msg_no_menu_node;
657 const char *msg_no_foot_node;
658 const char *msg_no_xref_node;
659 const char *msg_no_pointer;
660 const char *msg_unknown_command;
661 const char *msg_term_too_dumb;
662 const char *msg_at_node_bottom;
663 const char *msg_at_node_top;
664 const char *msg_one_window;
665 const char *msg_win_too_small;
666 const char *msg_cant_make_help;
668 static void
669 init_messages (void)
671 msg_cant_find_node = _("Cannot find node `%s'.");
672 msg_cant_file_node = _("Cannot find node `(%s)%s'.");
673 msg_cant_find_window = _("Cannot find a window!");
674 msg_cant_find_point = _("Point doesn't appear within this window's node!");
675 msg_cant_kill_last = _("Cannot delete the last window.");
676 msg_no_menu_node = _("No menu in this node.");
677 msg_no_foot_node = _("No footnotes in this node.");
678 msg_no_xref_node = _("No cross references in this node.");
679 msg_no_pointer = _("No `%s' pointer for this node.");
680 msg_unknown_command = _("Unknown Info command `%c'; try `?' for help.");
681 msg_term_too_dumb = _("Terminal type `%s' is not smart enough to run Info.");
682 msg_at_node_bottom = _("You are already at the last page of this node.");
683 msg_at_node_top = _("You are already at the first page of this node.");
684 msg_one_window = _("Only one window.");
685 msg_win_too_small = _("Resulting window would be too small.");
686 msg_cant_make_help = _("Not enough room for a help window, please delete a window.");