Home | History | Annotate | Line # | Download | only in info
      1 /*	$NetBSD: info.c,v 1.2 2016/01/14 00:34:52 christos Exp $	*/
      2 
      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
      5 
      6    Copyright (C) 1993, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
      7    2004 Free Software Foundation, Inc.
      8 
      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.
     13 
     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.
     18 
     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.
     22 
     23    Written by Brian Fox (bfox (at) ai.mit.edu). */
     24 
     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 */
     32 
     33 static char *program_name = "info";
     34 
     35 /* Non-zero means search all indices for APROPOS_SEARCH_STRING. */
     36 static int apropos_p = 0;
     37 
     38 /* Variable containing the string to search for when apropos_p is non-zero. */
     39 static char *apropos_search_string = (char *)NULL;
     40 
     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;
     44 
     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;
     49 
     50 /* Variable containing the string to search for when index_search_p is
     51    non-zero. */
     52 static char *index_search_string = (char *)NULL;
     53 
     54 /* Non-zero means print version info only. */
     55 static int print_version_p = 0;
     56 
     57 /* Non-zero means print a short description of the options. */
     58 static int print_help_p = 0;
     59 
     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;
     65 
     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;
     69 
     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;
     73 
     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;
     78 
     79 /* Non-zero means make default keybindings be loosely modeled on vi(1).  */
     80 int vi_keys_p = 0;
     81 
     82 /* Non-zero means don't remove ANSI escape sequences.  */
     83 int raw_escapes_p = 1;
     84 
     85 /* Non-zero means print the absolute location of the file to be loaded.  */
     86 static int print_where_p = 0;
     87 
     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
     96 
     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}
    127 };
    128 
    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
    135 
    136 /* When non-zero, the Info window system has been initialized. */
    137 int info_windows_initialized_p = 0;
    138 
    139 /* Some "forward" declarations. */
    140 static void info_short_help (void);
    141 static void init_messages (void);
    142 
    143 
    144 /* **************************************************************** */
    146 /*                                                                  */
    147 /*                Main Entry Point to the Info Program              */
    148 /*                                                                  */
    149 /* **************************************************************** */
    150 
    151 int
    152 main (int argc, char **argv)
    153 {
    154   int getopt_long_index;        /* Index returned by getopt_long (). */
    155   NODE *initial_node;           /* First node loaded by Info. */
    156 
    157 #ifdef HAVE_SETLOCALE
    158   /* Set locale via LC_ALL.  */
    159   setlocale (LC_ALL, "");
    160 #endif
    161 
    162 #ifdef ENABLE_NLS
    163   /* Set the text message domain.  */
    164   bindtextdomain (PACKAGE, LOCALEDIR);
    165   textdomain (PACKAGE);
    166 #endif
    167 
    168   init_messages ();
    169 
    170   while (1)
    171     {
    172       int option_character;
    173 
    174       option_character = getopt_long
    175         (argc, argv, short_options, long_options, &getopt_long_index);
    176 
    177       /* getopt_long returns EOF when there are no more long options. */
    178       if (option_character == EOF)
    179         break;
    180 
    181       /* If this is a long option, then get the short version of it. */
    182       if (option_character == 0 && long_options[getopt_long_index].flag == 0)
    183         option_character = long_options[getopt_long_index].val;
    184 
    185       /* Case on the option that we have received. */
    186       switch (option_character)
    187         {
    188         case 0:
    189           break;
    190 
    191           /* User wants to add a directory. */
    192         case 'd':
    193           info_add_path (optarg, INFOPATH_PREPEND);
    194           break;
    195 
    196           /* User is specifying a particular node. */
    197         case 'n':
    198           add_pointer_to_array (optarg, user_nodenames_index, user_nodenames,
    199                                 user_nodenames_slots, 10, char *);
    200           break;
    201 
    202           /* User is specifying a particular Info file. */
    203         case 'f':
    204           if (user_filename)
    205             free (user_filename);
    206 
    207           user_filename = xstrdup (optarg);
    208           break;
    209 
    210           /* Treat -h like --help. */
    211         case 'h':
    212           print_help_p = 1;
    213           break;
    214 
    215           /* User is specifying the name of a file to output to. */
    216         case 'o':
    217           if (user_output_filename)
    218             free (user_output_filename);
    219           user_output_filename = xstrdup (optarg);
    220           break;
    221 
    222          /* User has specified that she wants to find the "Options"
    223              or "Invocation" node for the program.  */
    224         case 'O':
    225           goto_invocation_p = 1;
    226           break;
    227 
    228 	  /* User has specified that she wants the escape sequences
    229 	     in man pages to be passed thru unaltered.  */
    230         case 'R':
    231           raw_escapes_p = 1;
    232           break;
    233 
    234           /* User is specifying that she wishes to dump the subnodes of
    235              the node that she is dumping. */
    236         case 's':
    237           dump_subnodes = 1;
    238           break;
    239 
    240           /* For compatibility with man, -w is --where.  */
    241         case 'w':
    242           print_where_p = 1;
    243           break;
    244 
    245 #ifdef __MSDOS__
    246 	  /* User wants speech-friendly output.  */
    247 	case 'b':
    248 	  speech_friendly = 1;
    249 	  break;
    250 #endif /* __MSDOS__ */
    251 
    252           /* User has specified a string to search all indices for. */
    253         case APROPOS_OPTION:
    254           apropos_p = 1;
    255           maybe_free (apropos_search_string);
    256           apropos_search_string = xstrdup (optarg);
    257           break;
    258 
    259           /* User has specified a dribble file to receive keystrokes. */
    260         case DRIBBLE_OPTION:
    261           close_dribble_file ();
    262           open_dribble_file (optarg);
    263           break;
    264 
    265           /* User has specified an alternate input stream. */
    266         case RESTORE_OPTION:
    267           info_set_input_from_file (optarg);
    268           break;
    269 
    270           /* User has specified a string to search all indices for. */
    271         case IDXSRCH_OPTION:
    272           index_search_p = 1;
    273           maybe_free (index_search_string);
    274           index_search_string = xstrdup (optarg);
    275           break;
    276 
    277         default:
    278           fprintf (stderr, _("Try --help for more information.\n"));
    279           xexit (1);
    280         }
    281     }
    282 
    283   /* If the output device is not a terminal, and no output filename has been
    284      specified, make user_output_filename be "-", so that the info is written
    285      to stdout, and turn on the dumping of subnodes. */
    286   if ((!isatty (fileno (stdout))) && (user_output_filename == (char *)NULL))
    287     {
    288       user_output_filename = xstrdup ("-");
    289       dump_subnodes = 1;
    290     }
    291 
    292   /* If the user specified --version, then show the version and exit. */
    293   if (print_version_p)
    294     {
    295       printf ("%s (GNU %s) %s\n", program_name, PACKAGE, VERSION);
    296       puts ("");
    297       puts ("Copyright (C) 2004 Free Software Foundation, Inc.");
    298       printf (_("There is NO warranty.  You may redistribute this software\n\
    299 under the terms of the GNU General Public License.\n\
    300 For more information about these matters, see the files named COPYING.\n"));
    301       xexit (0);
    302     }
    303 
    304   /* If the `--help' option was present, show the help and exit. */
    305   if (print_help_p)
    306     {
    307       info_short_help ();
    308       xexit (0);
    309     }
    310 
    311   /* If the user hasn't specified a path for Info files, default it.
    312      Lowest priority is our messy hardwired list in filesys.h.
    313      Then comes the user's INFODIR from the Makefile.
    314      Highest priority is the environment variable, if set.  */
    315   if (!infopath)
    316     {
    317       char *path_from_env = getenv ("INFOPATH");
    318 
    319       if (path_from_env)
    320         {
    321           unsigned len = strlen (path_from_env);
    322           /* Trailing : on INFOPATH means insert the default path.  */
    323           if (len && path_from_env[len - 1] == PATH_SEP[0])
    324             {
    325               path_from_env[len - 1] = 0;
    326               info_add_path (DEFAULT_INFOPATH, INFOPATH_PREPEND);
    327             }
    328 #ifdef INFODIR /* from the Makefile */
    329           info_add_path (INFODIR, INFOPATH_PREPEND);
    330 #endif
    331           info_add_path (path_from_env, INFOPATH_PREPEND);
    332         }
    333       else
    334         {
    335           info_add_path (DEFAULT_INFOPATH, INFOPATH_PREPEND);
    336 #ifdef INFODIR /* from the Makefile */
    337           info_add_path (INFODIR, INFOPATH_PREPEND);
    338 #endif
    339 #ifdef INFODIR2 /* from the Makefile, too */
    340 #  ifdef INFODIR
    341           if (!STREQ (INFODIR, INFODIR2))
    342 #  endif
    343             info_add_path (INFODIR2, INFOPATH_PREPEND);
    344 #endif
    345         }
    346     }
    347 
    348   /* If the user specified a particular filename, add the path of that
    349      file to the contents of INFOPATH. */
    350   if (user_filename)
    351     add_file_directory_to_path (user_filename);
    352 
    353   /* If the user wants to search every known index for a given string,
    354      do that now, and report the results. */
    355   if (apropos_p)
    356     {
    357       info_apropos (apropos_search_string);
    358       xexit (0);
    359     }
    360 
    361   /* Get the initial Info node.  It is either "(dir)Top", or what the user
    362      specified with values in user_filename and user_nodenames. */
    363   initial_node = info_get_node (user_filename,
    364                                 user_nodenames ? user_nodenames[0] : 0);
    365 
    366   /* If we couldn't get the initial node, this user is in trouble. */
    367   if (!initial_node)
    368     {
    369       if (info_recent_file_error)
    370         info_error (info_recent_file_error, NULL, NULL);
    371       else
    372         info_error ((char *) msg_cant_find_node,
    373                     user_nodenames ? user_nodenames[0] : "Top", NULL);
    374       xexit (1);
    375     }
    376 
    377   /* Special cases for when the user specifies multiple nodes.  If we
    378      are dumping to an output file, dump all of the nodes specified.
    379      Otherwise, attempt to create enough windows to handle the nodes
    380      that this user wants displayed. */
    381   if (user_nodenames_index > 1)
    382     {
    383       free (initial_node);
    384 
    385       if (print_where_p)
    386         printf ("%s\n", user_filename ? user_filename : "unknown?!");
    387       else if (user_output_filename)
    388         dump_nodes_to_file
    389           (user_filename, user_nodenames, user_output_filename, dump_subnodes);
    390       else
    391         begin_multiple_window_info_session (user_filename, user_nodenames);
    392 
    393       xexit (0);
    394     }
    395 
    396   /* If there are arguments remaining, they are the names of menu items
    397      in sequential info files starting from the first one loaded.  That
    398      file name is either "dir", or the contents of user_filename if one
    399      was specified. */
    400   {
    401     const char *errstr;
    402     char *errarg1, *errarg2;
    403 
    404     NODE *new_initial_node = info_follow_menus (initial_node, argv + optind,
    405         &errstr, &errarg1, &errarg2);
    406 
    407     if (new_initial_node && new_initial_node != initial_node)
    408       initial_node = new_initial_node;
    409 
    410     if (print_where_p)
    411       {
    412         if (initial_node->parent)
    413           printf ("%s\n", initial_node->parent);
    414         else if (initial_node->filename
    415             && !is_dir_name (filename_non_directory (initial_node->filename)))
    416           printf ("%s\n", initial_node->filename);
    417         else
    418           xexit (1);
    419         xexit (0);
    420       }
    421 
    422     /* If the user specified that this node should be output, then do that
    423        now.  Otherwise, start the Info session with this node.  Or act
    424        accordingly if the initial node was not found.  */
    425     if (user_output_filename && !goto_invocation_p)
    426       {
    427         if (!errstr)
    428           dump_node_to_file (initial_node, user_output_filename,
    429                              dump_subnodes);
    430         else
    431           info_error ((char *) errstr, errarg1, errarg2);
    432       }
    433     else
    434       {
    435 
    436         if (errstr)
    437           begin_info_session_with_error (initial_node, (char *) errstr,
    438               errarg1, errarg2);
    439         /* If the user specified `--index-search=STRING' or
    440            --show-options, start the info session in the node
    441            corresponding to what they want. */
    442         else if (index_search_p || goto_invocation_p)
    443           {
    444             int status = 0;
    445 
    446             initialize_info_session (initial_node, 0);
    447 
    448             if (goto_invocation_p
    449                 || index_entry_exists (windows, index_search_string))
    450               {
    451                 terminal_prep_terminal ();
    452                 terminal_clear_screen ();
    453                 info_last_executed_command = (VFunction *)NULL;
    454 
    455                 if (index_search_p)
    456                   do_info_index_search (windows, 0, index_search_string);
    457                 else
    458                   {
    459                     /* If they said "info --show-options foo bar baz",
    460                        the last of the arguments is the program whose
    461                        options they want to see.  */
    462                     char **p = argv + optind;
    463                     char *program;
    464 
    465                     if (*p)
    466                       {
    467                         while (p[1])
    468                           p++;
    469                         program = xstrdup (*p);
    470                       }
    471                     else if (user_filename)
    472 		      /* If there's no command-line arguments to
    473 			 supply the program name, use the Info file
    474 			 name (sans extension and leading directories)
    475 			 instead.  */
    476 		      program = program_name_from_file_name (user_filename);
    477 		    else
    478 		      program = xstrdup ("");
    479 
    480                     info_intuit_options_node (windows, initial_node, program);
    481                     free (program);
    482                   }
    483 
    484 		if (user_output_filename)
    485 		  {
    486 		    dump_node_to_file (windows->node, user_output_filename,
    487 				       dump_subnodes);
    488 		  }
    489 		else
    490 		  info_read_and_dispatch ();
    491 
    492                 /* On program exit, leave the cursor at the bottom of the
    493                    window, and restore the terminal IO. */
    494                 terminal_goto_xy (0, screenheight - 1);
    495                 terminal_clear_to_eol ();
    496                 fflush (stdout);
    497                 terminal_unprep_terminal ();
    498               }
    499             else
    500               {
    501                 fprintf (stderr, _("no index entries found for `%s'\n"),
    502                          index_search_string);
    503                 status = 2;
    504               }
    505 
    506             close_dribble_file ();
    507             xexit (status);
    508           }
    509         else
    510           begin_info_session (initial_node);
    511       }
    512 
    513     xexit (0);
    514   }
    515 
    516   return 0; /* Avoid bogus warnings.  */
    517 }
    518 
    519 void
    520 add_file_directory_to_path (char *filename)
    521 {
    522   char *directory_name = xstrdup (filename);
    523   char *temp = filename_non_directory (directory_name);
    524 
    525   if (temp != directory_name)
    526     {
    527       if (HAVE_DRIVE (directory_name) && temp == directory_name + 2)
    528 	{
    529 	  /* The directory of "d:foo" is stored as "d:.", to avoid
    530 	     mixing it with "d:/" when a slash is appended.  */
    531 	  *temp = '.';
    532 	  temp += 2;
    533 	}
    534       temp[-1] = 0;
    535       info_add_path (directory_name, INFOPATH_PREPEND);
    536     }
    537 
    538   free (directory_name);
    539 }
    540 
    541 
    542 /* Error handling.  */
    544 
    545 /* Non-zero if an error has been signalled. */
    546 int info_error_was_printed = 0;
    547 
    548 /* Non-zero means ring terminal bell on errors. */
    549 int info_error_rings_bell_p = 1;
    550 
    551 /* Print FORMAT with ARG1 and ARG2.  If the window system was initialized,
    552    then the message is printed in the echo area.  Otherwise, a message is
    553    output to stderr. */
    554 void
    555 info_error (char *format, void *arg1, void *arg2)
    556 {
    557   info_error_was_printed = 1;
    558 
    559   if (!info_windows_initialized_p || display_inhibited)
    560     {
    561       fprintf (stderr, "%s: ", program_name);
    562       fprintf (stderr, format, arg1, arg2);
    563       fprintf (stderr, "\n");
    564       fflush (stderr);
    565     }
    566   else
    567     {
    568       if (!echo_area_is_active)
    569         {
    570           if (info_error_rings_bell_p)
    571             terminal_ring_bell ();
    572           window_message_in_echo_area (format, arg1, arg2);
    573         }
    574       else
    575         {
    576           NODE *temp;
    577 
    578           temp = build_message_node (format, arg1, arg2);
    579           if (info_error_rings_bell_p)
    580             terminal_ring_bell ();
    581           inform_in_echo_area (temp->contents);
    582           free (temp->contents);
    583           free (temp);
    584         }
    585     }
    586 }
    587 
    588 
    589 /* Produce a scaled down description of the available options to Info. */
    591 static void
    592 info_short_help (void)
    593 {
    594 #ifdef __MSDOS__
    595   static const char speech_friendly_string[] = N_("\
    596   -b, --speech-friendly        be friendly to speech synthesizers.\n");
    597 #else
    598   static const char speech_friendly_string[] = "";
    599 #endif
    600 
    601 
    602   printf (_("\
    603 Usage: %s [OPTION]... [MENU-ITEM...]\n\
    604 \n\
    605 Read documentation in Info format.\n\
    606 \n\
    607 Options:\n\
    608       --apropos=STRING         look up STRING in all indices of all manuals.\n\
    609   -d, --directory=DIR          add DIR to INFOPATH.\n\
    610       --dribble=FILENAME       remember user keystrokes in FILENAME.\n\
    611   -f, --file=FILENAME          specify Info file to visit.\n\
    612   -h, --help                   display this help and exit.\n\
    613       --index-search=STRING    go to node pointed by index entry STRING.\n\
    614   -n, --node=NODENAME          specify nodes in first visited Info file.\n\
    615   -o, --output=FILENAME        output selected nodes to FILENAME.\n\
    616   -R, --raw-escapes            output \"raw\" ANSI escapes (default).\n\
    617       --no-raw-escapes         output escapes as literal text.\n\
    618       --restore=FILENAME       read initial keystrokes from FILENAME.\n\
    619   -O, --show-options, --usage  go to command-line options node.\n%s\
    620       --subnodes               recursively output menu items.\n\
    621   -w, --where, --location      print physical location of Info file.\n\
    622       --vi-keys                use vi-like and less-like key bindings.\n\
    623       --version                display version information and exit.\n\
    624 \n\
    625 The first non-option argument, if present, is the menu entry to start from;\n\
    626 it is searched for in all `dir' files along INFOPATH.\n\
    627 If it is not present, info merges all `dir' files and shows the result.\n\
    628 Any remaining arguments are treated as the names of menu\n\
    629 items relative to the initial node visited.\n\
    630 \n\
    631 Examples:\n\
    632   info                       show top-level dir menu\n\
    633   info emacs                 start at emacs node from top-level dir\n\
    634   info emacs buffers         start at buffers node within emacs manual\n\
    635   info --show-options emacs  start at node with emacs' command line options\n\
    636   info -f ./foo.info         show file ./foo.info, not searching dir\n\
    637 "),
    638   program_name, speech_friendly_string);
    639 
    640   puts (_("\n\
    641 Email bug reports to bug-texinfo (at) gnu.org,\n\
    642 general questions and discussion to help-texinfo (at) gnu.org.\n\
    643 Texinfo home page: http://www.gnu.org/software/texinfo/"));
    644 
    645   xexit (0);
    646 }
    647 
    648 
    649 /* Initialize strings for gettext.  Because gettext doesn't handle N_ or
    651    _ within macro definitions, we put shared messages into variables and
    652    use them that way.  This also has the advantage that there's only one
    653    copy of the strings.  */
    654 
    655 const char *msg_cant_find_node;
    656 const char *msg_cant_file_node;
    657 const char *msg_cant_find_window;
    658 const char *msg_cant_find_point;
    659 const char *msg_cant_kill_last;
    660 const char *msg_no_menu_node;
    661 const char *msg_no_foot_node;
    662 const char *msg_no_xref_node;
    663 const char *msg_no_pointer;
    664 const char *msg_unknown_command;
    665 const char *msg_term_too_dumb;
    666 const char *msg_at_node_bottom;
    667 const char *msg_at_node_top;
    668 const char *msg_one_window;
    669 const char *msg_win_too_small;
    670 const char *msg_cant_make_help;
    671 
    672 static void
    673 init_messages (void)
    674 {
    675   msg_cant_find_node   = _("Cannot find node `%s'.");
    676   msg_cant_file_node   = _("Cannot find node `(%s)%s'.");
    677   msg_cant_find_window = _("Cannot find a window!");
    678   msg_cant_find_point  = _("Point doesn't appear within this window's node!");
    679   msg_cant_kill_last   = _("Cannot delete the last window.");
    680   msg_no_menu_node     = _("No menu in this node.");
    681   msg_no_foot_node     = _("No footnotes in this node.");
    682   msg_no_xref_node     = _("No cross references in this node.");
    683   msg_no_pointer       = _("No `%s' pointer for this node.");
    684   msg_unknown_command  = _("Unknown Info command `%c'; try `?' for help.");
    685   msg_term_too_dumb    = _("Terminal type `%s' is not smart enough to run Info.");
    686   msg_at_node_bottom   = _("You are already at the last page of this node.");
    687   msg_at_node_top      = _("You are already at the first page of this node.");
    688   msg_one_window       = _("Only one window.");
    689   msg_win_too_small    = _("Resulting window would be too small.");
    690   msg_cant_make_help   = _("Not enough room for a help window, please delete a window.");
    691 }
    692