home *** CD-ROM | disk | FTP | other *** search
- /* info.c -- Display nodes of Info files in multiple windows. */
-
- /* This file is part of GNU Info, a program for reading online documentation
- stored in Info format.
-
- Copyright (C) 1993 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Written by Brian Fox (bfox@ai.mit.edu). */
-
- #include "info.h"
- #include "dribble.h"
- #include "getopt.h"
-
- /* The version numbers of this version of Info. */
- int info_major_version = 2;
- int info_minor_version = 10;
- int info_patch_level = 1;
-
- /* Non-zero means search all indices for APROPOS_SEARCH_STRING. */
- static int apropos_p = 0;
-
- /* Variable containing the string to search for when apropos_p is non-zero. */
- static char *apropos_search_string = (char *)NULL;
-
- /* Non-zero means print version info only. */
- static int print_version_p = 0;
-
- /* Non-zero means print a short description of the options. */
- static int print_help_p = 0;
-
- /* Array of the names of nodes that the user specified with "--node" on the
- command line. */
- static char **user_nodenames = (char **)NULL;
- static int user_nodenames_index = 0;
- static int user_nodenames_slots = 0;
-
- /* String specifying the first file to load. This string can only be set
- by the user specifying "--file" on the command line. */
- static char *user_filename = (char *)NULL;
-
- /* String specifying the name of the file to dump nodes to. This value is
- filled if the user speficies "--output" on the command line. */
- static char *user_output_filename = (char *)NULL;
-
- /* Non-zero indicates that when "--output" is specified, all of the menu
- items of the specified nodes (and their subnodes as well) should be
- dumped in the order encountered. This basically can print a book. */
- int dump_subnodes = 0;
-
- /* Structure describing the options that Info accepts. We pass this structure
- to getopt_long (). If you add or otherwise change this structure, you must
- also change the string which follows it. */
- #define APROPOS_OPTION 1
- #define DRIBBLE_OPTION 2
- #define RESTORE_OPTION 3
- static struct option long_options[] = {
- { "apropos", 1, 0, APROPOS_OPTION },
- { "directory", 1, 0, 'd' },
- { "node", 1, 0, 'n' },
- { "file", 1, 0, 'f' },
- { "subnodes", 0, &dump_subnodes, 1 },
- { "output", 1, 0, 'o' },
- { "help", 0, &print_help_p, 1 },
- { "version", 0, &print_version_p, 1 },
- { "dribble", 1, 0, DRIBBLE_OPTION },
- { "restore", 1, 0, RESTORE_OPTION },
- {NULL, 0, NULL, 0}
- };
-
- /* String describing the shorthand versions of the long options found above. */
- static char *short_options = "d:n:f:o:s";
-
- /* When non-zero, the Info window system has been initialized. */
- int info_windows_initialized_p = 0;
-
- /* Some "forward" declarations. */
- static void usage (), info_short_help (), remember_info_program_name ();
-
-
- /* **************************************************************** */
- /* */
- /* Main Entry Point to the Info Program */
- /* */
- /* **************************************************************** */
-
- int
- main (argc, argv)
- int argc;
- char **argv;
- {
- int getopt_long_index; /* Index returned by getopt_long (). */
- NODE *initial_node; /* First node loaded by Info. */
-
- #if defined (NeXT) && defined (NOTDEF)
- malloc_debug (0x0ffffffff);
- #endif /* NeXT && NOTDEF */
-
- remember_info_program_name (argv[0]);
-
- while (1)
- {
- int option_character;
-
- option_character = getopt_long
- (argc, argv, short_options, long_options, &getopt_long_index);
-
- /* getopt_long () returns EOF when there are no more long options. */
- if (option_character == EOF)
- break;
-
- /* If this is a long option, then get the short version of it. */
- if (option_character == 0 && long_options[getopt_long_index].flag == 0)
- option_character = long_options[getopt_long_index].val;
-
- /* Case on the option that we have received. */
- switch (option_character)
- {
- case 0:
- break;
-
- /* User wants to add a directory. */
- case 'd':
- info_add_path (optarg, INFOPATH_PREPEND);
- break;
-
- /* User is specifying a particular node. */
- case 'n':
- add_pointer_to_array (optarg, user_nodenames_index, user_nodenames,
- user_nodenames_slots, 10, char *);
- break;
-
- /* User is specifying a particular Info file. */
- case 'f':
- if (user_filename)
- free (user_filename);
-
- user_filename = savestring (optarg);
- break;
-
- /* User is specifying the name of a file to output to. */
- case 'o':
- if (user_output_filename)
- free (user_output_filename);
- user_output_filename = savestring (optarg);
- break;
-
- /* User is specifying that she wishes to dump the subnodes of
- the node that she is dumping. */
- case 's':
- dump_subnodes = 1;
- break;
-
- /* User has specified a string to search all indices for. */
- case APROPOS_OPTION:
- apropos_p = 1;
- maybe_free (apropos_search_string);
- apropos_search_string = savestring (optarg);
- break;
-
- /* User has specified a dribble file to receive keystrokes. */
- case DRIBBLE_OPTION:
- close_dribble_file ();
- open_dribble_file (optarg);
- break;
-
- /* User has specified an alternate input stream. */
- case RESTORE_OPTION:
- info_set_input_from_file (optarg);
- break;
-
- default:
- usage ();
- }
- }
-
- /* If the user specified --version, then show the version and exit. */
- if (print_version_p)
- {
- printf ("GNU Info, Version %s.\n", version_string ());
- exit (0);
- }
-
- /* If the `--help' option was present, show the help and exit. */
- if (print_help_p)
- {
- info_short_help ();
- exit (0);
- }
-
- /* If the user hasn't specified a path for Info files, default that path
- now. */
- if (!infopath)
- {
- char *path_from_env, *getenv ();
-
- path_from_env = getenv ("INFOPATH");
-
- if (path_from_env)
- info_add_path (path_from_env);
- else
- info_add_path (DEFAULT_INFOPATH);
- }
-
- /* If the user specified a particular filename, add the path of that
- file to the contents of INFOPATH. */
- if (user_filename)
- {
- char *directory_name, *temp;
-
- directory_name = savestring (user_filename);
- temp = filename_non_directory (directory_name);
-
- if (temp != directory_name)
- {
- *temp = 0;
- info_add_path (directory_name, INFOPATH_PREPEND);
- }
-
- free (directory_name);
- }
-
- /* If the user wants to search every known index for a given string,
- do that now, and report the results. */
- if (apropos_p)
- {
- info_apropos (apropos_search_string);
- exit (0);
- }
-
- /* Get the initial Info node. It is either "(dir)Top", or what the user
- specifed with values in user_filename and user_nodenames. */
- if (user_nodenames)
- initial_node = info_get_node (user_filename, user_nodenames[0]);
- else
- initial_node = info_get_node (user_filename, (char *)NULL);
-
- /* If we couldn't get the initial node, this user is in trouble. */
- if (!initial_node)
- {
- if (info_recent_file_error)
- info_error (info_recent_file_error);
- else
- info_error
- (CANT_FIND_NODE, user_nodenames ? user_nodenames[0] : "Top");
- exit (1);
- }
-
- /* Special cases for when the user specifies multiple nodes. If we are
- dumping to an output file, dump all of the nodes specified. Otherwise,
- attempt to create enough windows to handle the nodes that this user wants
- displayed. */
- if (user_nodenames_index > 1)
- {
- free (initial_node);
-
- if (user_output_filename)
- dump_nodes_to_file
- (user_filename, user_nodenames, user_output_filename, dump_subnodes);
- else
- begin_multiple_window_info_session (user_filename, user_nodenames);
-
- exit (0);
- }
-
- /* If there are arguments remaining, they are the names of menu items
- in sequential info files starting from the first one loaded. That
- file name is either "dir", or the contents of user_filename if one
- was specified. */
- while (optind != argc)
- {
- REFERENCE **menu;
- REFERENCE *entry;
- NODE *node;
- char *arg;
-
- /* Remember the name of the menu entry we want. */
- arg = argv[optind++];
-
- /* Build and return a list of the menu items in this node. */
- menu = info_menu_of_node (initial_node);
-
- /* If there wasn't a menu item in this node, stop here, but let
- the user continue to use Info. Perhaps they wanted this node
- and didn't realize it. */
- if (!menu)
- {
- begin_info_session_with_error
- (initial_node, "There is no menu in this node.");
- exit (0);
- }
-
- /* Find the specified menu item. */
- entry = info_get_labeled_reference (arg, menu);
-
- /* If the item wasn't found, search the list sloppily. Perhaps this
- user typed "buffer" when they really meant "Buffers". */
- if (!entry)
- {
- register int i;
-
- for (i = 0; entry = menu[i]; i++)
- if (strnicmp (entry->label, arg, strlen (arg)) == 0)
- break;
- }
-
- /* If we failed to find the reference, start Info with the current
- node anyway. It is probably a misspelling. */
- if (!entry)
- {
- char *error_message = "There is no menu item \"%s\" in this node.";
-
- info_free_references (menu);
-
- /* If we were supposed to dump this node, complain. */
- if (user_output_filename)
- info_error (error_message, arg);
- else
- begin_info_session_with_error (initial_node, error_message, arg);
-
- exit (0);
- }
-
- /* We have found the reference that the user specified. Clean it
- up a little bit. */
- if (!entry->filename)
- {
- if (initial_node->parent)
- entry->filename = savestring (initial_node->parent);
- else
- entry->filename = savestring (initial_node->filename);
- }
-
- /* Find this node. If we can find it, then turn the initial_node
- into this one. If we cannot find it, try using the label of the
- entry as a file (i.e., "(LABEL)Top"). Otherwise the Info file is
- malformed in some way, and we will just use the current value of
- initial node. */
- node = info_get_node (entry->filename, entry->nodename);
-
- if (!node && entry->nodename &&
- (strcmp (entry->label, entry->nodename) == 0))
- node = info_get_node (entry->label, "Top");
-
- if (node)
- {
- free (initial_node);
- initial_node = node;
- info_free_references (menu);
- }
- else
- {
- char *temp = savestring (entry->label);
- char *error_message;
-
- error_message = "Unable to find the node referenced by \"%s\".";
-
- info_free_references (menu);
-
- /* If we were trying to dump the node, then give up. Otherwise,
- start the session with an error message. */
- if (user_output_filename)
- info_error (error_message, temp);
- else
- begin_info_session_with_error (initial_node, error_message, temp);
-
- exit (0);
- }
- }
-
- /* If the user specified that this node should be output, then do that
- now. Otherwise, start the Info session with this node. */
- if (user_output_filename)
- dump_node_to_file (initial_node, user_output_filename, dump_subnodes);
- else
- begin_info_session (initial_node);
-
- exit (0);
- }
-
- /* Return a string describing the current version of Info. */
- char *
- version_string ()
- {
- static char *vstring = (char *)NULL;
-
- if (!vstring)
- {
- vstring = (char *)xmalloc (50);
- sprintf (vstring, "%d.%d", info_major_version, info_minor_version);
- if (info_patch_level)
- sprintf (vstring + strlen (vstring), "-p%d", info_patch_level);
- }
- return (vstring);
- }
-
- /* **************************************************************** */
- /* */
- /* Error Handling for Info */
- /* */
- /* **************************************************************** */
-
- static char *program_name = (char *)NULL;
-
- static void
- remember_info_program_name (fullpath)
- char *fullpath;
- {
- char *filename;
-
- filename = filename_non_directory (fullpath);
- program_name = savestring (filename);
- }
-
- /* Non-zero if an error has been signalled. */
- int info_error_was_printed = 0;
-
- /* Non-zero means ring terminal bell on errors. */
- int info_error_rings_bell_p = 1;
-
- /* Print FORMAT with ARG1 and ARG2. If the window system was initialized,
- then the message is printed in the echo area. Otherwise, a message is
- output to stderr. */
- void
- info_error (format, arg1, arg2)
- char *format;
- void *arg1, *arg2;
- {
- info_error_was_printed = 1;
-
- if (!info_windows_initialized_p || display_inhibited)
- {
- fprintf (stderr, "%s: ", program_name);
- fprintf (stderr, format, arg1, arg2);
- fprintf (stderr, "\n");
- fflush (stderr);
- }
- else
- {
- if (!echo_area_is_active)
- {
- if (info_error_rings_bell_p)
- terminal_ring_bell ();
- window_message_in_echo_area (format, arg1, arg2);
- }
- else
- {
- NODE *temp;
-
- temp = build_message_node (format, arg1, arg2);
- if (info_error_rings_bell_p)
- terminal_ring_bell ();
- inform_in_echo_area (temp->contents);
- free (temp->contents);
- free (temp);
- }
- }
- }
-
- /* Produce a very brief descripton of the available options and exit with
- an error. */
- static void
- usage ()
- {
- fprintf (stderr,"%s\n%s\n%s\n%s\n%s\n",
- "Usage: info [-d dir-path] [-f info-file] [-o output-file] [-n node-name]...",
- " [--directory dir-path] [--file info-file] [--node node-name]...",
- " [--help] [--output output-file] [--subnodes] [--version]",
- " [--dribble dribble-file] [--restore from-file]",
- " [menu-selection ...]");
- exit (1);
- }
-
- /* Produce a scaled down description of the available options to Info. */
- static void
- info_short_help ()
- {
- printf ("%s", "\
- Here is a quick description of Info's options. For a more complete\n\
- description of how to use Info, type `info info options'.\n\
- \n\
- --directory DIR Add DIR to INFOPATH.\n\
- --file FILENAME Specify Info file to visit.\n\
- --node NODENAME Specify nodes in first visited Info file.\n\
- --output FILENAME Output selected nodes to FILENAME.\n\
- --dribble FILENAME Remember user keystrokes in FILENAME.\n\
- --restore FILENAME Read initial keystrokes from FILENAME.\n\
- --subnodes Recursively output menu items.\n\
- --help Get this help message.\n\
- --version Display Info's version information.\n\
- \n\
- Remaining arguments to Info are treated as the names of menu\n\
- items in the initial node visited. You can easily move to the\n\
- node of your choice by specifying the menu names which describe\n\
- the path to that node. For example, `info emacs buffers'.\n");
-
- exit (0);
- }
-