1998-05-16  Eli Zaretskii  <eliz@is.elta.co.il>

	* info/session.c (info_goto_node): Don't show the nodes of the
	current Info file twice in *Completions*.
	* info/echo-area.c (ea_possible_completions): Actually pass the
	number of completions to printf_to_message_buffer.

	* info/man.c (manpage_node_of_file_buffer): xstrdup the nodename
	member of manpage nodes, since the tags are freed and recomputed
	when a new man page is added to *manpages* file_buffer.
	(get_manpage_node): Recompute info_windows[]->nodes[] for all
	windows showing the man pages after nodes[]->contents are
	invalidated by reallocation of file_buffer->contents.

1998-05-15  Eli Zaretskii  <eliz@is.elta.co.il>

	* lib/system.h (DEFAULT_INFO_PRINT_COMMAND) [__MSDOS__]: Define to
	">PRN".
	* info/session.c (print_node): Support ">printer" in
	INFO_PRINT_COMMAND, to mean write to the named file/device insead
	of piping to it as a program.
	(kill_node): Compare window in addition to the nodename, when
	looking for the node to kill.

1998-05-09  Eli Zaretskii  <eliz@is.elta.co.il>

	* lib/system.h (SET_SCREEN_SIZE_HELPER) [__MSDOS__]: Define a new
	macro.
	* info/m-x.c (set_screen_height): Use SET_SCREEN_SIZE_HELPER, if
	defined.  If the screen size did'n change, redisplay the previous
	screen contents.

	* info/infomap.c (initialize_info_keymaps) [__MSDOS__]: Bind DEL
	to ea_delete in the echo-area keymap.
	* info/session.c (incremental_search): If the key is
	isearch_terminate_search_key, but buffered input is pending, don't
	gobble the ESC key.

	* info/info.c (main): Switch the order thet terminal_prep_terminal
	and terminal_clear_screen are called, to make it consistent with
	what initialize_info_session does when called with non-zero second
	argument.  Call terminal_unprep_terminal last, after moving the
	cursor to the bottom of the screen.  If user_filename is of the
	form "d:foo", add "d:." to the INFOPATH, not "d:".

	* info/signals.c (initialize_info_signal_handler): Save old
	SIGUSR1 handler.
	(info_signal_handler): Handle SIGUSR1.

	* info/indices.c (info_apropos): Print the results to stdout.

1998-05-02  Eli Zaretskii  <eliz@is.elta.co.il>

	* makeinfo/makeinfo.c (ALSO_NULL_DEVICE): New macro, for alternate
	null device name.

	* info/man.c (get_manpage_contents): Redirect stderr of the man
	page formatter to the null device.
	(executable_file_in_path): Use IS_SLASH.

	* info/session.c (info_gather_typeahead) [__DJGPP__]: Call
	pc_term_chars_avail to get the number of pending characters.

	* info/filesys.c (convert_eols): New function, converts DOS-style
	EOLs to a single Newline.
	(filesys_read_info_file, filesys_read_compressed): Call it.
	(filesys_read_compressed) [STRIP_DOT_EXE]: Use explicit .exe
	suffix.
	(filesys_read_compressed): Check return status of `pclose'.

1998-05-01  Eli Zaretskii  <eliz@is.elta.co.il>

	* info/filesys.c (filesys_read_info_file): Add additional
	parameter: is_compressed.  All callers changed.

	* makeinfo/makeinfo.c (convert_from_loaded_file): Compare file
	names with FILENAME_CMP.  Use NULL_DEVICE.
	(cm_node): Compare file names with FILENAME_CMP.
	* info/tilde.c (tilde_find_suffix, tilde_expand_word): Use
	IS_SLASH.

	* info/pc_term.c: New file, handles the PC terminal on MS-DOS and
	MS-Windows.
	* info/terminal.c [__MSDOS__]: Include pc_term.c.
	* info/Makefile.in (ginfo_SOURCES): Add pc_term.c
	Add pc_term.c to dependencies of terminal.o.

	* info/session.c (info_get_input_char): Reassign tty after EOF
	from a non-stdin input stream.

1998-04-30  Eli Zaretskii  <eliz@is.elta.co.il>

	* info/session.c (info_set_input_from_file): Use binary input.
	(info_gc_file_buffers): Compare file names with FILENAME_CMP.
	* info/search.c (skip_whitespace_and_newlines): Use
	whitespace_or_newline macro instead of reinventing the wheel.
	* info/nodes.c (info_find_file_internal): Use IS_ABSOLUTE and
	FILENAME_CMP.
	(info_load_file_internal): Call filename_non_directory to find out
	where the basename begins.
	(get_tags_of_indirect_tags_table): Call filename_non_directory.
	containing_dir of "d:foo" is "d:.", not "d:".
	(forget_info_file): Compare file names with FILENAME_CMP.
	* info/nodemenu.c (get_visited_nodes): Use FILENAME_CMP to find
	duplicate lines.

	* lib/system.h (PIPE_USE_FORK): New macro.
	* info/man.c (get_manpage_contents): Use it to determine whether
	to call pipe/fork/exec or popen/pclose to run the man page
	formatter.
	(executable_file_in_path): Search for the file with several known
	extensions such as .exe, where appropriate.

	* lib/system.h (NULL_DEVICE): A new macro.
	* info/makedoc.c (main): Use it.
	(maybe_dump_tags): Switch output strem to binary mode when
	appropriate.
	(process_one_file): Update file_size after reading the file.

	* info/infodoc.c: Add TAB, RET, and `i' to the list of important
	commands in info_internal_help_text.

	* info/info.c (main): Support the --speech-friendly option.  Use
	PATH_SEP to separate directories.
	(info_short_help) [__MSDOS__]: Mention the --speech-friendly
	option.

	* info/info-utils.c (filename_non_directory): Use HAVE_DRIVE and
	IS_SLASH.
	* info/indices.c (do_info_index_search, index_entry_exists): Use
	FILENAME_CMP to compare file names.
	* info/filesys.c: Add ".inf" to the list of known extensions.
	Look for .z before .Z, for the sake of case-insensitive
	filesystems.  Add DOS-specific extensions to work around 8+3
	namespace restrictions.
	(info_absolute_file): New function.
	(info_find_fullpath): Call it for candidates which are absolute
	file names.  Use IS_SLASH and IS_ABSOLUTE.
	(info_file_in_path): Use IS_SLASH.
	(extract_colon_unit, info_add_path): Use PATH_SEP instead of ":".
	(lookup_info_filename): Compare file names with FILENAME_CMP.
	(filesys_read_info_file): Read Info files in binary mode.
	(filesys_decompressor_for_file): Read Info files in binary mode.
	Compare file names with FILENAME_CMP.  On MS-DOS, allow files
	whose names end with a `z' be decompressed with gunzip.
	* info/dribble.c (open_dribble_file): Open dribble file in
	FOPEN_WBIN mode. 
	* info/dir.c (maybe_build_dir_node): Use IS_SLASH.
	* util/texindex.c (maketempname): Put the numeric suffix after the
	dot, to salvage 3 more characters on 8+3 filesystems.

1998-04-29  Eli Zaretskii  <eliz@is.elta.co.il>

	* util/texindex.c (main): Use IS_SLASH to find the basename of
	argv[0].  Lose the .exe suffix, if any.
	(decode_command): Look at $TEMP and $TMP in addition to $TMPDIR.
	Use DEFAULT_TMPDIR.
	* util/texi2dvi: Use either `:' or `;' as directory separator in
	TEXINPUTS, computed at run time.  Save previous versions of index
	files in a separate backup directory.
	* util/install-info.c (main): Support backslashes in file names by
	using IS_SLASH.  Avoid recomputing length of infile_basename
	unnecessarily.  Use FILENAME_CMP for comparing file names
	case-insensitively, where appropriate.  Allow foo.inf as well as
	foo.info to be an Info file name.
	* lib/system.h (PATH_SEP, STRIP_DOT_EXE, FILENAME_CMPN,
	DEFAULT_TMPDIR): New macros.

1998-04-25  Eli Zaretskii  <eliz@is.elta.co.il>

	* lib/system.h (O_BINARY, SET_BINARY, FOPEN_RBIN, FOPEN_WBIN,
	IS_SLASH, HAVE_DRIVE, IS_ABSOLUTE, FILENAME_CMP, PATH_SEP,
	HAVE_LONG_FILENAMES): New macros.
	* makeinfo/makeinfo.c (find_and_load): Use O_BINARY to decide when
	read returning a value different from what st_size says is not an
	error.  Realloc the buffer after we've read the file.
	(skip_directory_part): New function, skips leading directory in a
	way that works on DOSISH systems.
	(filename_non_directory, pathname_part): Call it.
	(filename_part): Call filename_non_directory.
	(expand_filename, full_pathname): Use IS_ABSOLUTE and IS_SLASH.
	(convert_from_file): Check .txi extension first.
	(split_file): Support splitting output files on 8+3 filesystems.
	(main, extract_colon_unit): Use PATH_SEP instead of ':'.
	(get_file_info_in_path): Use IS_ABSOLUTE and IS_SLASH.

*** lib/system.h~0	Sun May 10 00:30:32 1998
--- lib/system.h	Fri May 15 15:37:48 1998
***************
*** 97,102 ****
--- 97,173 ----
  #endif /* not HAVE_FCNTL_H */
  #endif /* not O_RDONLY */
  
+ /* MS-DOS and similar non-Posix systems have some peculiarities:
+     - they distinguish between binary and text files;
+     - they use both `/' and `\\' as directory separator in file names;
+     - they can have a drive letter X: prepended to a file name;
+     - they have a separate root directory on each drive;
+     - their filesystems are case-insensitive;
+     - directories in environment variables (like INFOPATH) are separated
+         by `;' rather than `:';
+     - text files can have their lines ended either with \n or with \r\n pairs;
+ 
+    These are all parameterized here except the last, which is
+    handled by the source code as appropriate (mostly, in info/ dir).  */
+ #ifndef O_BINARY
+ # ifdef _O_BINARY
+ #  define O_BINARY _O_BINARY
+ # else
+ #  define O_BINARY 0
+ # endif
+ #endif /* O_BINARY */
+ 
+ #if O_BINARY
+ # include <io.h>
+ # ifdef __MSDOS__
+ #  include <limits.h>
+ #  ifdef __DJGPP__
+ #   define HAVE_LONG_FILENAMES(dir)  (pathconf (dir, _PC_NAME_MAX) > 12)
+ #   define NULL_DEVICE	"/dev/null"
+ #  else  /* !__DJGPP__ */
+ #   define HAVE_LONG_FILENAMES(dir)  (0)
+ #   define NULL_DEVICE	"NUL"
+ #  endif /* !__DJGPP__ */
+ #  define SET_SCREEN_SIZE_HELPER terminal_prep_terminal()
+ #  define DEFAULT_INFO_PRINT_COMMAND ">PRN"
+ # else   /* !__MSDOS__ */
+ #  define setmode(f,m)  _setmode(f,m)
+ #  define HAVE_LONG_FILENAMES(dir)   (1)
+ #  define NULL_DEVICE	"NUL"
+ # endif  /* !__MSDOS__ */
+ # define SET_BINARY(f)  do {if (!isatty(f)) setmode(f,O_BINARY);} while(0)
+ # define FOPEN_RBIN	"rb"
+ # define FOPEN_WBIN	"wb"
+ # define IS_SLASH(c)	((c) == '/' || (c) == '\\')
+ # define HAVE_DRIVE(n)	((n)[0] && (n)[1] == ':')
+ # define IS_ABSOLUTE(n)	(IS_SLASH((n)[0]) || ((n)[0] && (n)[1] == ':'))
+ # define FILENAME_CMP	strcasecmp
+ # define FILENAME_CMPN	strncasecmp
+ # define PATH_SEP	";"
+ # define STRIP_DOT_EXE	1
+ # define DEFAULT_TMPDIR	"c:/"
+ # define PIPE_USE_FORK	0
+ #else  /* not O_BINARY */
+ # define SET_BINARY(f)	(void)0
+ # define FOPEN_RBIN	"r"
+ # define FOPEN_WBIN	"w"
+ # define IS_SLASH(c)	((c) == '/')
+ # define HAVE_DRIVE(n)	(0)
+ # define IS_ABSOLUTE(n)	((n)[0] == '/')
+ # define FILENAME_CMP	strcmp
+ # define FILENAME_CMPN	strncmp
+ # define HAVE_LONG_FILENAMES(dir)   (1)
+ # define PATH_SEP	":"
+ # define STRIP_DOT_EXE	0
+ # ifdef VMS
+ #  define DEFAULT_TMPDIR "sys$scratch:"
+ # else
+ #  define DEFAULT_TMPDIR "/tmp/"
+ # endif
+ # define NULL_DEVICE	"/dev/null"
+ # define PIPE_USE_FORK	1
+ #endif /* not O_BINARY */
+ 
  #ifdef HAVE_PWD_H
  #include <pwd.h>
  #endif
*** info/Makefile.i~0	Tue Mar  3 21:45:42 1998
--- info/Makefile.in	Fri May  1 20:36:04 1998
***************
*** 106,112 ****
    filesys.c filesys.h footnotes.c footnotes.h funs.h gc.c gc.h \
    indices.c indices.h info-utils.c info-utils.h info.c info.h infodoc.c \
    infomap.c infomap.h m-x.c man.c man.h nodemenu.c nodes.c nodes.h \
!   search.c search.h session.c session.h signals.c signals.h \
    termdep.h terminal.c terminal.h tilde.c tilde.h \
    variables.c variables.h window.c window.h
  
--- 106,112 ----
    filesys.c filesys.h footnotes.c footnotes.h funs.h gc.c gc.h \
    indices.c indices.h info-utils.c info-utils.h info.c info.h infodoc.c \
    infomap.c infomap.h m-x.c man.c man.h nodemenu.c nodes.c nodes.h \
!   pc_term.c search.c search.h session.c session.h signals.c signals.h \
    termdep.h terminal.c terminal.h tilde.c tilde.h \
    variables.c variables.h window.c window.h
  
***************
*** 345,351 ****
  terminal.o: terminal.c info.h ../lib/system.h ../config.h filesys.h \
  	display.h info-utils.h nodes.h window.h infomap.h search.h \
  	terminal.h session.h dribble.h echo-area.h doc.h footnotes.h \
! 	gc.h termdep.h
  tilde.o: tilde.c info.h ../lib/system.h ../config.h filesys.h display.h \
  	info-utils.h nodes.h window.h infomap.h search.h terminal.h \
  	session.h dribble.h echo-area.h doc.h footnotes.h gc.h
--- 345,351 ----
  terminal.o: terminal.c info.h ../lib/system.h ../config.h filesys.h \
  	display.h info-utils.h nodes.h window.h infomap.h search.h \
  	terminal.h session.h dribble.h echo-area.h doc.h footnotes.h \
! 	gc.h termdep.h pc_term.c
  tilde.o: tilde.c info.h ../lib/system.h ../config.h filesys.h display.h \
  	info-utils.h nodes.h window.h infomap.h search.h terminal.h \
  	session.h dribble.h echo-area.h doc.h footnotes.h gc.h
*** info/dir.c~0	Mon Jul 28 00:09:20 1997
--- info/dir.c	Fri May  1 23:22:10 1998
*************** maybe_build_dir_node (dirname)
*** 125,131 ****
            char *fullpath = xmalloc (3 + strlen (this_dir) + namelen);
            
            strcpy (fullpath, this_dir);
!           if (fullpath[strlen (fullpath) - 1] != '/')
              strcat (fullpath, "/");
            strcat (fullpath, from_file);
  
--- 125,131 ----
            char *fullpath = xmalloc (3 + strlen (this_dir) + namelen);
            
            strcpy (fullpath, this_dir);
!           if (!IS_SLASH (fullpath[strlen (fullpath) - 1]))
              strcat (fullpath, "/");
            strcat (fullpath, from_file);
  
*************** maybe_build_dir_node (dirname)
*** 135,142 ****
            if (statable && S_ISREG (finfo.st_mode) && new_dir_file_p (&finfo))
              {
                long filesize;
                char *contents = filesys_read_info_file (fullpath, &filesize,
!                                                        &finfo);
                if (contents)
                  {
                    update_tags++;
--- 135,143 ----
            if (statable && S_ISREG (finfo.st_mode) && new_dir_file_p (&finfo))
              {
                long filesize;
+ 	      int compressed;
                char *contents = filesys_read_info_file (fullpath, &filesize,
!                                                        &finfo, &compressed);
                if (contents)
                  {
                    update_tags++;
*** info/dribble.c~0	Tue Jul 15 21:32:22 1997
--- info/dribble.c	Thu Apr 30 11:37:58 1998
*************** open_dribble_file (name)
*** 37,43 ****
    /* Perhaps close existing dribble file. */
    close_dribble_file ();
  
!   info_dribble_file = fopen (name, "w");
  
  #if defined (HAVE_SETVBUF)
    if (info_dribble_file)
--- 37,44 ----
    /* Perhaps close existing dribble file. */
    close_dribble_file ();
  
!   /* Keystrokes can be non-printable characters, so we need binary I/O.  */
!   info_dribble_file = fopen (name, FOPEN_WBIN);
  
  #if defined (HAVE_SETVBUF)
    if (info_dribble_file)
*** info/echo-area.c~0	Fri Feb 27 00:47:02 1998
--- info/echo-area.c	Sat May 16 15:02:32 1998
*************** DECLARE_INFO_COMMAND (ea_possible_comple
*** 940,946 ****
        initialize_message_buffer ();
        printf_to_message_buffer (completions_found_index == 1
                                  ? _("One completion:\n")
!                                 : _("%d completions:\n"));
  
        /* Find the maximum length of a label. */
        for (i = 0; i < completions_found_index; i++)
--- 940,947 ----
        initialize_message_buffer ();
        printf_to_message_buffer (completions_found_index == 1
                                  ? _("One completion:\n")
!                                 : _("%d completions:\n"),
! 				completions_found_index);
  
        /* Find the maximum length of a label. */
        for (i = 0; i < completions_found_index; i++)
*** info/filesys.c~0	Sun Feb 22 00:52:46 1998
--- info/filesys.c	Sat May  2 18:11:38 1998
***************
*** 26,31 ****
--- 26,32 ----
  
  /* Local to this file. */
  static char *info_file_in_path (), *lookup_info_filename ();
+ static char *info_absolute_file ();
  static void remember_info_filename (), maybe_initialize_infopath ();
  
  typedef struct
*************** static char *info_suffixes[] = {
*** 39,52 ****
    ".info",
    "-info",
    "/index",
    (char *)NULL
  };
  
  static COMPRESSION_ALIST compress_suffixes[] = {
    { ".Z", "uncompress" },
    { ".Y", "unyabba" },
-   { ".z", "gunzip" },
    { ".gz", "gunzip" },
    { (char *)NULL, (char *)NULL }
  };
  
--- 40,63 ----
    ".info",
    "-info",
    "/index",
+   ".inf",       /* 8+3 file on filesystem which supports long file names */
+ #ifdef __MSDOS__
+   /* 8+3 file names strike again...  */
+   ".in",        /* for .inz, .igz etc. */
+   ".i",
+ #endif
    (char *)NULL
  };
  
  static COMPRESSION_ALIST compress_suffixes[] = {
+   { ".z", "gunzip" },
    { ".Z", "uncompress" },
    { ".Y", "unyabba" },
    { ".gz", "gunzip" },
+ #ifdef __MSDOS__
+   { "gz", "gunzip" },
+   { "z", "gunzip" },
+ #endif
    { (char *)NULL, (char *)NULL }
  };
  
*************** info_find_fullpath (partial)
*** 86,106 ****
        /* If we have the full path to this file, we still may have to add
           various extensions to it.  I guess we have to stat this file
           after all. */
!       if (initial_character == '/')
!         temp = info_file_in_path (partial + 1, "/");
        else if (initial_character == '~')
          {
            expansion = tilde_expand_word (partial);
!           if (*expansion == '/')
              {
!               temp = info_file_in_path (expansion + 1, "/");
                free (expansion);
              }
            else
              temp = expansion;
          }
        else if (initial_character == '.' &&
!                (partial[1] == '/' || (partial[1] == '.' && partial[2] == '/')))
          {
            if (local_temp_filename_size < 1024)
              local_temp_filename = (char *)xrealloc
--- 97,118 ----
        /* If we have the full path to this file, we still may have to add
           various extensions to it.  I guess we have to stat this file
           after all. */
!       if (IS_ABSOLUTE (partial))
! 	temp = info_absolute_file (partial);
        else if (initial_character == '~')
          {
            expansion = tilde_expand_word (partial);
!           if (IS_ABSOLUTE (expansion))
              {
!               temp = info_absolute_file (expansion);
                free (expansion);
              }
            else
              temp = expansion;
          }
        else if (initial_character == '.' &&
!                (IS_SLASH (partial[1]) ||
! 		(partial[1] == '.' && IS_SLASH (partial[2]))))
          {
            if (local_temp_filename_size < 1024)
              local_temp_filename = (char *)xrealloc
*************** info_find_fullpath (partial)
*** 117,123 ****
  
            strcat (local_temp_filename, "/");
            strcat (local_temp_filename, partial);
!           return (local_temp_filename);
          }
        else
          temp = info_file_in_path (partial, infopath);
--- 129,137 ----
  
            strcat (local_temp_filename, "/");
            strcat (local_temp_filename, partial);
! 	  temp = info_absolute_file (local_temp_filename); /* try extensions */
! 	  if (!temp)
! 	    partial = local_temp_filename;
          }
        else
          temp = info_file_in_path (partial, infopath);
*************** info_file_in_path (filename, path)
*** 167,173 ****
  
        temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename));
        strcpy (temp, temp_dirname);
!       if (temp[(strlen (temp)) - 1] != '/')
          strcat (temp, "/");
        strcat (temp, filename);
  
--- 181,187 ----
  
        temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename));
        strcpy (temp, temp_dirname);
!       if (!IS_SLASH (temp[(strlen (temp)) - 1]))
          strcat (temp, "/");
        strcat (temp, filename);
  
*************** info_file_in_path (filename, path)
*** 229,236 ****
    return ((char *)NULL);
  }
  
! /* Given a string containing units of information separated by colons,
!    return the next one pointed to by IDX, or NULL if there are no more.
     Advance IDX to the character after the colon. */
  char *
  extract_colon_unit (string, idx)
--- 243,268 ----
    return ((char *)NULL);
  }
  
! /* Assume FNAME is an absolute file name, and check whether it is
!    a regular file.  If it is, return it as a new string; otherwise
!    return a NULL pointer.  We do it by taking the file name apart
!    into its directory and basename parts, and calling info_file_in_path.*/
! static char *
! info_absolute_file (fname)
!      char *fname;
! {
!   char *containing_dir = xstrdup (fname);
!   char *base = filename_non_directory (containing_dir);
! 
!   if (base > containing_dir)
!     base[-1] = '\0';
! 
!   return info_file_in_path (filename_non_directory (fname), containing_dir);
! }
! 
! /* Given a string containing units of information separated by
!    the PATH_SEP character, return the next one pointed to by
!    IDX, or NULL if there are no more.
     Advance IDX to the character after the colon. */
  char *
  extract_colon_unit (string, idx)
*************** extract_colon_unit (string, idx)
*** 243,249 ****
    if ((i >= strlen (string)) || !string)
      return ((char *) NULL);
  
!   while (string[i] && string[i] != ':')
      i++;
    if (i == start)
      {
--- 275,281 ----
    if ((i >= strlen (string)) || !string)
      return ((char *) NULL);
  
!   while (string[i] && string[i] != PATH_SEP[0])
      i++;
    if (i == start)
      {
*************** lookup_info_filename (filename)
*** 285,291 ****
        register int i;
        for (i = 0; names_and_files[i]; i++)
          {
!           if (strcmp (names_and_files[i]->filename, filename) == 0)
              return (names_and_files[i]->expansion);
          }
      }
--- 317,323 ----
        register int i;
        for (i = 0; names_and_files[i]; i++)
          {
!           if (FILENAME_CMP (names_and_files[i]->filename, filename) == 0)
              return (names_and_files[i]->expansion);
          }
      }
*************** info_add_path (path, where)
*** 354,367 ****
      strcpy (infopath, path);
    else if (where == INFOPATH_APPEND)
      {
!       strcat (infopath, ":");
        strcat (infopath, path);
      }
    else if (where == INFOPATH_PREPEND)
      {
        char *temp = xstrdup (infopath);
        strcpy (infopath, path);
!       strcat (infopath, ":");
        strcat (infopath, temp);
        free (temp);
      }
--- 386,399 ----
      strcpy (infopath, path);
    else if (where == INFOPATH_APPEND)
      {
!       strcat (infopath, PATH_SEP);
        strcat (infopath, path);
      }
    else if (where == INFOPATH_PREPEND)
      {
        char *temp = xstrdup (infopath);
        strcpy (infopath, path);
!       strcat (infopath, PATH_SEP);
        strcat (infopath, temp);
        free (temp);
      }
*************** zap_infopath ()
*** 378,405 ****
    infopath_size = 0;
  }
  
  /* Read the contents of PATHNAME, returning a buffer with the contents of
     that file in it, and returning the size of that buffer in FILESIZE.
     FINFO is a stat struct which has already been filled in by the caller.
     If the file cannot be read, return a NULL pointer. */
  char *
! filesys_read_info_file (pathname, filesize, finfo)
       char *pathname;
       long *filesize;
       struct stat *finfo;
  {
    long st_size;
  
    *filesize = filesys_error_number = 0;
  
    if (compressed_filename_p (pathname))
!     return (filesys_read_compressed (pathname, filesize, finfo));
    else
      {
        int descriptor;
        char *contents;
  
!       descriptor = open (pathname, O_RDONLY, 0666);
  
        /* If the file couldn't be opened, give up. */
        if (descriptor < 0)
--- 410,479 ----
    infopath_size = 0;
  }
  
+ /* Given a chunk of text and its length, convert all CRLF pairs at every
+    end-of-line into a single Newline character.  Return the length of
+    produced text.
+ 
+    This is required because the rest of code is too entrenched in having
+    a single newline at each EOL; in particular, searching for various
+    Info headers and cookies can become extremely tricky if that assumption
+    breaks.
+ 
+    FIXME: this could also support Mac-style text files with a single CR
+    at the EOL, but what about random CR characters in non-Mac files?  Can
+    we afford converting them into newlines as well?  Maybe implement some
+    heuristics here, like in Emacs 20.
+ 
+    FIXME: is it a good idea to show the EOL type on the modeline?  */
+ long
+ convert_eols (text, textlen)
+      char *text;
+      long textlen;
+ {
+   register char *s = text;
+   register char *d = text;
+ 
+   while (textlen--)
+     {
+       if (*s == '\r' && textlen && s[1] == '\n')
+ 	{
+ 	  s++;
+ 	  textlen--;
+ 	}
+       *d++ = *s++;
+     }
+ 
+   return (long)(d - text);
+ }
+ 
  /* Read the contents of PATHNAME, returning a buffer with the contents of
     that file in it, and returning the size of that buffer in FILESIZE.
     FINFO is a stat struct which has already been filled in by the caller.
+    If the file turns out to be compressed, set IS_COMPRESSED to non-zero.
     If the file cannot be read, return a NULL pointer. */
  char *
! filesys_read_info_file (pathname, filesize, finfo, is_compressed)
       char *pathname;
       long *filesize;
       struct stat *finfo;
+      int *is_compressed;
  {
    long st_size;
  
    *filesize = filesys_error_number = 0;
  
    if (compressed_filename_p (pathname))
!     {
!       *is_compressed = 1;
!       return (filesys_read_compressed (pathname, filesize, finfo));
!     }
    else
      {
        int descriptor;
        char *contents;
  
!       *is_compressed = 0;
!       descriptor = open (pathname, O_RDONLY | O_BINARY, 0666);
  
        /* If the file couldn't be opened, give up. */
        if (descriptor < 0)
*************** filesys_read_info_file (pathname, filesi
*** 413,427 ****
        contents = (char *)xmalloc (1 + st_size);
        if ((read (descriptor, contents, st_size)) != st_size)
          {
!           filesys_error_number = errno;
!           close (descriptor);
!           free (contents);
!           return ((char *)NULL);
          }
  
        close (descriptor);
  
!       *filesize = st_size;
        return (contents);
      }
  }
--- 487,510 ----
        contents = (char *)xmalloc (1 + st_size);
        if ((read (descriptor, contents, st_size)) != st_size)
          {
! 	  filesys_error_number = errno;
! 	  close (descriptor);
! 	  free (contents);
! 	  return ((char *)NULL);
          }
  
        close (descriptor);
  
!       /* Convert any DOS-style CRLF EOLs into Unix-style NL.
! 	 Seems like a good idea to have even on Unix, in case the Info
! 	 files are coming from some Windows system across a network.  */
!       *filesize = convert_eols (contents, st_size);
! 
!       /* EOL conversion can shrink the text quite a bit.  We don't
! 	 want to waste storage.  */
!       if (*filesize < st_size)
! 	contents = (char *)xrealloc (contents, 1 + *filesize);
! 
        return (contents);
      }
  }
*************** filesys_read_compressed (pathname, files
*** 449,456 ****
    if (!decompressor)
      return ((char *)NULL);
  
!   command = (char *)xmalloc (10 + strlen (pathname) + strlen (decompressor));
!   sprintf (command, "%s < %s", decompressor, pathname);
  
  #if !defined (BUILDING_LIBRARY)
    if (info_windows_initialized_p)
--- 532,542 ----
    if (!decompressor)
      return ((char *)NULL);
  
!   command = (char *)xmalloc (15 + strlen (pathname) + strlen (decompressor));
!   /* Explicit .exe suffix makes the diagnostics of `popen'
!      better on systems where COMMAND.COM is the stock shell.  */
!   sprintf (command, "%s%s < %s",
! 	   decompressor, STRIP_DOT_EXE ? ".exe" : "", pathname);
  
  #if !defined (BUILDING_LIBRARY)
    if (info_windows_initialized_p)
*************** filesys_read_compressed (pathname, files
*** 464,470 ****
      }
  #endif /* !BUILDING_LIBRARY */
  
!   stream = popen (command, "r");
    free (command);
  
    /* Read chunks from this file until there are none left to read. */
--- 550,556 ----
      }
  #endif /* !BUILDING_LIBRARY */
  
!   stream = popen (command, FOPEN_RBIN);
    free (command);
  
    /* Read chunks from this file until there are none left to read. */
*************** filesys_read_compressed (pathname, files
*** 493,501 ****
          }
  
        free (chunk);
!       pclose (stream);
!       contents = (char *)xrealloc (contents, offset + 1);
!       *filesize = offset;
      }
    else
      {
--- 579,596 ----
          }
  
        free (chunk);
!       if (pclose (stream) == -1)
! 	{
! 	  if (contents)
! 	    free (contents);
! 	  contents = (char *)NULL;
! 	  filesys_error_number = errno;
! 	}
!       else
! 	{
! 	  *filesize = convert_eols (contents, offset);
! 	  contents = (char *)xrealloc (contents, 1 + *filesize);
! 	}
      }
    else
      {
*************** filesys_decompressor_for_file (filename)
*** 547,554 ****
      return ((char *)NULL);
  
    for (i = 0; compress_suffixes[i].suffix; i++)
!     if (strcmp (extension, compress_suffixes[i].suffix) == 0)
        return (compress_suffixes[i].decompressor);
  
    return ((char *)NULL);
  }
--- 642,659 ----
      return ((char *)NULL);
  
    for (i = 0; compress_suffixes[i].suffix; i++)
!     if (FILENAME_CMP (extension, compress_suffixes[i].suffix) == 0)
        return (compress_suffixes[i].decompressor);
+ 
+ #if defined (__MSDOS__)
+   /* If no other suffix matched, allow any extension which ends
+      with `z' to be decompressed by gunzip.  Due to limited 8+3 DOS
+      file namespace, we can expect many such cases, and supporting
+      every weird suffix thus produced would be a pain.  */
+   if (extension[strlen (extension) - 1] == 'z' ||
+       extension[strlen (extension) - 1] == 'Z')
+     return "gunzip";
+ #endif
  
    return ((char *)NULL);
  }
*** info/filesys.h~0	Mon Aug  4 23:21:34 1997
--- info/filesys.h	Sat May  2 08:50:58 1998
*************** extern void info_add_path ();
*** 46,51 ****
--- 46,56 ----
     If it can't find the file, it returns NULL. */
  extern char *info_find_fullpath ();
  
+ /* Given a chunk of text and its length, convert all CRLF pairs at the
+    EOLs into a single Newline character.  Return the length of produced
+    text.  */
+ long convert_eols ();
+ 
  /* Read the contents of PATHNAME, returning a buffer with the contents of
     that file in it, and returning the size of that buffer in FILESIZE.
     FINFO is a stat struct which has already been filled in by the caller.
*** info/indices.c~0	Fri Jul 25 00:25:54 1997
--- info/indices.c	Sat May  9 09:51:22 1998
*************** do_info_index_search (window, count, sea
*** 199,205 ****
       index for, build and remember an index now. */
    fb = file_buffer_of_window (window);
    if (!initial_index_filename ||
!       (strcmp (initial_index_filename, fb->filename) != 0))
      {
        info_free_references (index_index);
        window_message_in_echo_area (_("Finding index entries..."));
--- 199,205 ----
       index for, build and remember an index now. */
    fb = file_buffer_of_window (window);
    if (!initial_index_filename ||
!       (FILENAME_CMP (initial_index_filename, fb->filename) != 0))
      {
        info_free_references (index_index);
        window_message_in_echo_area (_("Finding index entries..."));
*************** index_entry_exists (window, string)
*** 296,302 ****
  
    fb = file_buffer_of_window (window);
    if (!initial_index_filename
!       || (strcmp (initial_index_filename, fb->filename) != 0))
      {
        info_free_references (index_index);
        index_index = info_indices_of_file_buffer (fb);
--- 296,302 ----
  
    fb = file_buffer_of_window (window);
    if (!initial_index_filename
!       || (FILENAME_CMP (initial_index_filename, fb->filename) != 0))
      {
        info_free_references (index_index);
        index_index = info_indices_of_file_buffer (fb);
*************** info_apropos (string)
*** 604,610 ****
        REFERENCE *entry;
  
        for (i = 0; (entry = apropos_list[i]); i++)
!         fprintf (stderr, "\"(%s)%s\" -- %s\n",
                   entry->filename, entry->nodename, entry->label);
      }
    info_free_references (apropos_list);
--- 604,610 ----
        REFERENCE *entry;
  
        for (i = 0; (entry = apropos_list[i]); i++)
!         fprintf (stdout, "\"(%s)%s\" -- %s\n",
                   entry->filename, entry->nodename, entry->label);
      }
    info_free_references (apropos_list);
*** info/info-utils.c~0	Tue Jul 15 21:33:54 1997
--- info/info-utils.c	Thu Apr 30 15:56:32 1998
*************** info_references_internal (label, binding
*** 300,307 ****
    return (refs);
  }
  
! /* Get the entry associated with LABEL in MENU.  Return a pointer to the
!    REFERENCE if found, or NULL. */
  REFERENCE *
  info_get_labeled_reference (label, references)
       char *label;
--- 300,307 ----
    return (refs);
  }
  
! /* Get the entry associated with LABEL in REFERENCES.  Return a pointer
!    to the ENTRY if found, or NULL. */
  REFERENCE *
  info_get_labeled_reference (label, references)
       char *label;
*************** char *
*** 604,617 ****
  filename_non_directory (pathname)
       char *pathname;
  {
!   char *filename;
  
!   filename = (char *) strrchr (pathname, '/');
  
!   if (filename)
!     filename++;
!   else
!     filename = pathname;
  
    return (filename);
  }
--- 604,616 ----
  filename_non_directory (pathname)
       char *pathname;
  {
!   register char *filename = pathname + strlen (pathname);
  
!   if (HAVE_DRIVE (pathname))
!     pathname += 2;
  
!   while (filename > pathname && !IS_SLASH (filename[-1]))
!     filename--;
  
    return (filename);
  }
*** info/info.c~0	Sun May 10 00:27:38 1998
--- info/info.c	Sun May 10 00:28:00 1998
***************
*** 1,5 ****
  /* info.c -- Display nodes of Info files in multiple windows.
!    $Id: info.c,v 1.18 1998/02/27 21:37:27 karl Exp $
  
     Copyright (C) 1993, 96, 97, 98 Free Software Foundation, Inc.
  
--- 1,5 ----
  /* info.c -- Display nodes of Info files in multiple windows.
!    $Id: info.c,v 1.19 1998/04/03 23:59:14 karl Exp $
  
     Copyright (C) 1993, 96, 97, 98 Free Software Foundation, Inc.
  
*************** static char *user_output_filename = (cha
*** 73,78 ****
--- 73,87 ----
     dumped in the order encountered.  This basically can print a book. */
  int dump_subnodes = 0;
  
+ #ifdef __MSDOS__
+ /* Non-zero indicates that screen output should be made 'speech-friendly'.
+    Since on MSDOS the usual behavior is to write directly to the video
+    memory, speech synthesizer software cannot grab the output.  Therefore,
+    we provide a user option which tells us to avoid direct screen output
+    and use stdout instead (which loses the color output).  */
+ int speech_friendly = 0;
+ #endif
+ 
  /* 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. */
*************** static struct option long_options[] = {
*** 91,102 ****
--- 100,118 ----
    { "version", 0, &print_version_p, 1 },
    { "dribble", 1, 0, DRIBBLE_OPTION },
    { "restore", 1, 0, RESTORE_OPTION },
+ #ifdef __MSDOS__
+   { "speech-friendly", 0, &speech_friendly, 1 },
+ #endif
    { "index-search", 1, 0, IDXSRCH_OPTION },
    {NULL, 0, NULL, 0}
  };
  
  /* String describing the shorthand versions of the long options found above. */
+ #ifdef __MSDOS__
+ static char *short_options = "d:n:f:o:sb";
+ #else
  static char *short_options = "d:n:f:o:s";
+ #endif
  
  /* When non-zero, the Info window system has been initialized. */
  int info_windows_initialized_p = 0;
*************** main (argc, argv)
*** 183,188 ****
--- 199,211 ----
            dump_subnodes = 1;
            break;
  
+ #ifdef __MSDOS__
+ 	  /* User specifies that she wants speech-friendly output.  */
+ 	case 'b':
+ 	  speech_friendly = 1;
+ 	  break;
+ #endif /* __MSDOS__ */
+ 
            /* User has specified a string to search all indices for. */
          case APROPOS_OPTION:
            apropos_p = 1;
*************** For more information about these matters
*** 255,261 ****
          {
            unsigned len = strlen (path_from_env);
            /* Trailing : on INFOPATH means insert the default path.  */
!           if (len && path_from_env[len - 1] == ':')
              {
                path_from_env[len - 1] = 0;
                info_add_path (DEFAULT_INFOPATH, INFOPATH_PREPEND);
--- 278,284 ----
          {
            unsigned len = strlen (path_from_env);
            /* Trailing : on INFOPATH means insert the default path.  */
!           if (len && path_from_env[len - 1] == PATH_SEP[0])
              {
                path_from_env[len - 1] = 0;
                info_add_path (DEFAULT_INFOPATH, INFOPATH_PREPEND);
*************** For more information about these matters
*** 283,289 ****
  
        if (temp != directory_name)
          {
!           *temp = 0;
            info_add_path (directory_name, INFOPATH_PREPEND);
          }
  
--- 306,319 ----
  
        if (temp != directory_name)
          {
! 	  if (HAVE_DRIVE (directory_name) && temp == directory_name + 2)
! 	    {
! 	      /* The directory of "d:foo" is stored as "d:.", to avoid
! 		 mixing it with "d:/" when a slash is appended.  */
! 	      *temp = '.';
! 	      temp += 2;
! 	    }
!           temp[-1] = 0;
            info_add_path (directory_name, INFOPATH_PREPEND);
          }
  
*************** For more information about these matters
*** 341,348 ****
  
        if (index_entry_exists (windows, index_search_string))
          {
-           terminal_clear_screen ();
            terminal_prep_terminal ();
            display_update_display (windows);
            info_last_executed_command = (VFunction *)NULL;
  
--- 371,378 ----
  
        if (index_entry_exists (windows, index_search_string))
          {
            terminal_prep_terminal ();
+           terminal_clear_screen ();
            display_update_display (windows);
            info_last_executed_command = (VFunction *)NULL;
  
*************** For more information about these matters
*** 350,362 ****
  
            info_read_and_dispatch ();
  
-           terminal_unprep_terminal ();
- 
            /* On program exit, leave the cursor at the bottom of the
               window, and restore the terminal IO. */
            terminal_goto_xy (0, screenheight - 1);
            terminal_clear_to_eol ();
            fflush (stdout);
          }
        else
          {
--- 380,391 ----
  
            info_read_and_dispatch ();
  
            /* On program exit, leave the cursor at the bottom of the
               window, and restore the terminal IO. */
            terminal_goto_xy (0, screenheight - 1);
            terminal_clear_to_eol ();
            fflush (stdout);
+           terminal_unprep_terminal ();
          }
        else
          {
*************** For more information about these matters
*** 474,485 ****
        node = info_get_node (entry->filename, entry->nodename);
  
  #if defined (HANDLE_MAN_PAGES)
!           if ((first_arg == arg) && !node)
!             {
!               node = make_manpage_node (first_arg);
!               if (node)
!                 goto maybe_got_node;
!             }
  #endif /* HANDLE_MAN_PAGES */
  
        if (!node && entry->nodename &&
--- 503,514 ----
        node = info_get_node (entry->filename, entry->nodename);
  
  #if defined (HANDLE_MAN_PAGES)
!       if ((first_arg == arg) && !node)
! 	{
! 	  node = make_manpage_node (first_arg);
! 	  if (node)
! 	    goto maybe_got_node;
! 	}
  #endif /* HANDLE_MAN_PAGES */
  
        if (!node && entry->nodename &&
*************** remember_info_program_name (fullpath)
*** 548,553 ****
--- 577,591 ----
  
    filename = filename_non_directory (fullpath);
    program_name = xstrdup (filename);
+ 
+ #if STRIP_DOT_EXE
+   {
+     char *dot = strrchr (program_name, '.');
+ 
+     if (dot && FILENAME_CMP (dot, ".exe") == 0)
+       *dot = 0;
+   }
+ #endif
  }
  
  /* Non-zero if an error has been signalled. */
*************** Options:\n\
*** 609,618 ****
  --directory DIR              add DIR to INFOPATH.\n\
  --dribble FILENAME           remember user keystrokes in FILENAME.\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\
  --restore FILENAME           read initial keystrokes from FILENAME.\n\
! --subnodes                   recursively output menu items.\n\
  --help                       display this help and exit.\n\
  --version                    display version information and exit.\n\
  \n\
--- 647,657 ----
  --directory DIR              add DIR to INFOPATH.\n\
  --dribble FILENAME           remember user keystrokes in FILENAME.\n\
  --file FILENAME              specify Info file to visit.\n\
+ --index-search STRING        go to node pointed by index entry STRING.\n\
  --node NODENAME              specify nodes in first visited Info file.\n\
  --output FILENAME            output selected nodes to FILENAME.\n\
  --restore FILENAME           read initial keystrokes from FILENAME.\n\
! --subnodes                   recursively output menu items.\n%s\
  --help                       display this help and exit.\n\
  --version                    display version information and exit.\n\
  \n\
*************** Any remaining arguments are treated as t
*** 621,627 ****
  items in the initial node visited.  For example, `info emacs buffers'\n\
  moves to the node `buffers' in the info file `emacs'.\n\
  \n\
! Email bug reports to bug-texinfo@gnu.org."), program_name);
  
    exit (0);
  }
--- 660,673 ----
  items in the initial node visited.  For example, `info emacs buffers'\n\
  moves to the node `buffers' in the info file `emacs'.\n\
  \n\
! Email bug reports to bug-texinfo@gnu.org."), program_name,
! #ifdef __MSDOS__
! "\
! --speech-friendly            be friendly to speech synthesizers.\n"
! #else
! ""
! #endif
! 	  );
  
    exit (0);
  }
*** info/infodoc.c~0	Sat Jul 26 00:08:40 1997
--- info/infodoc.c	Fri May  1 17:26:54 1998
*************** static char *info_internal_help_text[] =
*** 63,68 ****
--- 63,70 ----
    "      Picking a menu item causes another node to be selected.",
    "  f   Follow a cross reference.  Reads name of reference.",
    "  l   Move to the last node seen in this window.",
+   "  TAB Skip to next hypertext link within this node.",
+   "  RET Follow the hypertext link under cursor.",
    "  d   Move to the `directory' node.  Equivalent to `g(DIR)'.",
    "",
    "Moving within a node:",
*************** static char *info_internal_help_text[] =
*** 77,82 ****
--- 79,86 ----
    "  1   Pick first item in node's menu.",
    "  2-9 Pick second ... ninth item in node's menu.",
    "  0   Pick last item in node's menu.",
+   "  i   Search for a specified string in the Index entries of this",
+   "      Info file, and select the node referenced by the first entry found.",
    "  g   Move to node specified by name.",
    "      You may include a filename as well, as in (FILENAME)NODENAME.",
    "  s   Search through this Info file for a specified string,",
*** info/infomap.c~0	Sun May 10 00:28:28 1998
--- info/infomap.c	Sun May 10 00:28:38 1998
*************** initialize_info_keymaps ()
*** 203,209 ****
--- 203,214 ----
    map[SPC].function = ea_complete;
    map[TAB].function = ea_complete;
    map['?'].function = ea_possible_completions;
+ #ifdef __MSDOS__
+   /* PC users will lynch me if I don't give them their usual DEL effect...  */
+   map[DEL].function = ea_delete;
+ #else
    map[DEL].function = ea_rubout;
+ #endif
  
    /* Bind the echo area ESC keymap. */
    map = (Keymap)echo_area_keymap[ESC].function;
*** info/m-x.c~0	Fri Jul 25 00:28:00 1997
--- info/m-x.c	Sat May 16 17:35:10 1998
*************** DECLARE_INFO_COMMAND (info_execute_comma
*** 149,155 ****
  DECLARE_INFO_COMMAND (set_screen_height,
    _("Set the height of the displayed window"))
  {
!   int new_height;
  
    if (info_explicit_arg || count != 1)
      new_height = count;
--- 149,155 ----
  DECLARE_INFO_COMMAND (set_screen_height,
    _("Set the height of the displayed window"))
  {
!   int new_height, old_height = screenheight;
  
    if (info_explicit_arg || count != 1)
      new_height = count;
*************** DECLARE_INFO_COMMAND (set_screen_height,
*** 185,190 ****
    terminal_clear_screen ();
    display_clear_display (the_display);
    screenheight = new_height;
!   display_initialize_display (screenwidth, screenheight);
!   window_new_screen_size (screenwidth, screenheight);
  }
--- 185,204 ----
    terminal_clear_screen ();
    display_clear_display (the_display);
    screenheight = new_height;
! #ifdef SET_SCREEN_SIZE_HELPER
!   SET_SCREEN_SIZE_HELPER;
! #endif
!   if (screenheight == old_height)
!     {
!       /* Display dimensions didn't actually change, so
! 	 window_new_screen_size won't do anything, but we've
! 	 already cleared the display above.  Undo the damage.  */
!       window_mark_chain (windows, W_UpdateWindow);
!       display_update_display (windows);
!     }
!   else
!     {
!       display_initialize_display (screenwidth, screenheight);
!       window_new_screen_size (screenwidth, screenheight);
!     }
  }
*** info/makedoc.c~0	Tue Jul 15 21:36:02 1997
--- info/makedoc.c	Thu Apr 30 17:08:22 1998
*************** main (argc, argv)
*** 105,112 ****
  
    if (tags_only)
      {
!       funs_filename = "/dev/null";
!       doc_filename = "/dev/null";
      }
    
    funs_stream = must_fopen (funs_filename, "w");
--- 105,112 ----
  
    if (tags_only)
      {
!       funs_filename = NULL_DEVICE;
!       doc_filename = NULL_DEVICE;
      }
    
    funs_stream = must_fopen (funs_filename, "w");
*************** maybe_dump_tags (stream)
*** 167,172 ****
--- 167,178 ----
  {
    register int i;
  
+   /* Emacs needs its TAGS file to be in Unix text format (i.e., only
+      newline at end of every line, no CR), so when we generate a
+      TAGS table, we must switch the output stream to binary mode.
+      (If the table is written to a terminal, this is obviously not needed.) */
+   SET_BINARY (fileno (stream));
+ 
    /* Print out the information for each block. */
    for (i = 0; i < emacs_tags_index; i++)
      {
*************** process_one_file (filename, doc_stream, 
*** 261,267 ****
  
    file_size = (long) finfo.st_size;
    buffer = (char *)xmalloc (1 + file_size);
!   read (descriptor, buffer, file_size);
    close (descriptor);
  
    offset = 0;
--- 267,276 ----
  
    file_size = (long) finfo.st_size;
    buffer = (char *)xmalloc (1 + file_size);
!   /* On some systems, the buffer will actually contain
!      less characters than the full file's size, because
!      the CR characters are removed from line endings.  */
!   file_size = read (descriptor, buffer, file_size);
    close (descriptor);
  
    offset = 0;
*** info/man.c~0	Fri Aug  1 02:49:58 1997
--- info/man.c	Sat May 16 14:24:26 1998
***************
*** 44,49 ****
--- 44,57 ----
  #  endif /* !hpux */
  #endif /* FD_SET */
  
+ #if STRIP_DOT_EXE
+ static char const * const exec_extensions[] = {
+   ".exe", ".com", ".bat", ".btm", ".sh", ".ksh", ".pl", ".sed", "", NULL
+ };
+ #else
+ static char const * const exec_extensions[] = { "", NULL };
+ #endif
+ 
  static char *read_from_fd ();
  static void clean_manpage ();
  static NODE *manpage_node_of_file_buffer ();
*************** get_manpage_node (file_buffer, pagename)
*** 76,81 ****
--- 84,90 ----
            char header[1024];
            long oldsize, newsize;
            int hlen, plen;
+ 	  char *old_contents = file_buffer->contents;
  
            sprintf (header, "\n\n%c\n%s %s,  %s %s,  %s (dir)\n\n",
                     INFO_COOKIE,
*************** get_manpage_node (file_buffer, pagename)
*** 89,101 ****
            file_buffer->contents =
              (char *)xrealloc (file_buffer->contents, 1 + newsize);
            memcpy (file_buffer->contents + oldsize, header, hlen);
!           oldsize += hlen;
!           memcpy (file_buffer->contents + oldsize, page, plen);
            file_buffer->contents[newsize] = '\0';
            file_buffer->filesize = newsize;
            file_buffer->finfo.st_size = newsize;
            build_tags_and_nodes (file_buffer);
            free (page);
          }
  
        node = manpage_node_of_file_buffer (file_buffer, pagename);
--- 98,146 ----
            file_buffer->contents =
              (char *)xrealloc (file_buffer->contents, 1 + newsize);
            memcpy (file_buffer->contents + oldsize, header, hlen);
!           memcpy (file_buffer->contents + oldsize + hlen, page, plen);
            file_buffer->contents[newsize] = '\0';
            file_buffer->filesize = newsize;
            file_buffer->finfo.st_size = newsize;
            build_tags_and_nodes (file_buffer);
            free (page);
+ 	  /* We have just relocated file_buffer->contents from under
+ 	     the feet of info_windows[] array.  Therefore, all the
+ 	     nodes on that list which are showing man pages have their
+ 	     contents member pointing into the blue.  Undo that harm.  */
+ 	  if (old_contents && oldsize && old_contents != file_buffer->contents)
+ 	    {
+ 	      int iw;
+ 	      INFO_WINDOW *info_win;
+ 	      char *old_contents_end = old_contents + oldsize;
+ 
+ 	      for (iw = 0; (info_win = info_windows[iw]); iw++)
+ 		{
+ 		  int in;
+ 
+ 		  for (in = 0; in < info_win->nodes_index; in++)
+ 		    {
+ 		      NODE *node = info_win->nodes[in];
+ 
+ 		      /* It really only suffices to see that node->filename
+ 			 is "*manpages*".  But after several hours of
+ 			 debugging this, would you blame me for being a bit
+ 			 paranoid?  */
+ 		      if (node && node->filename && node->contents &&
+ 			  strcmp (node->filename,
+ 				  MANPAGE_FILE_BUFFER_NAME) == 0 &&
+ 			  node->contents >= old_contents &&
+ 			  node->contents + node->nodelen <= old_contents_end)
+ 			{
+ 			  info_win->nodes[in] =
+ 			    manpage_node_of_file_buffer (file_buffer,
+ 							 node->nodename);
+ 			  free (node->nodename);
+ 			  free (node);
+ 			}
+ 		    }
+ 		}
+ 	    }
          }
  
        node = manpage_node_of_file_buffer (file_buffer, pagename);
*************** executable_file_in_path (filename, path)
*** 134,139 ****
--- 179,186 ----
    while ((temp_dirname = extract_colon_unit (path, &dirname_index)))
      {
        char *temp;
+       char *temp_end;
+       int i;
  
        /* Expand a leading tilde if one is present. */
        if (*temp_dirname == '~')
*************** executable_file_in_path (filename, path)
*** 145,166 ****
            temp_dirname = expanded_dirname;
          }
  
!       temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename));
        strcpy (temp, temp_dirname);
!       if (temp[(strlen (temp)) - 1] != '/')
          strcat (temp, "/");
        strcat (temp, filename);
  
        free (temp_dirname);
  
!       statable = (stat (temp, &finfo) == 0);
  
!       /* If we have found a regular executable file, then use it. */
!       if ((statable) && (S_ISREG (finfo.st_mode)) &&
!           (access (temp, X_OK) == 0))
!         return (temp);
!       else
!         free (temp);
      }
    return ((char *)NULL);
  }
--- 192,221 ----
            temp_dirname = expanded_dirname;
          }
  
!       temp = (char *)xmalloc (34 + strlen (temp_dirname) + strlen (filename));
        strcpy (temp, temp_dirname);
!       if (!IS_SLASH (temp[(strlen (temp)) - 1]))
          strcat (temp, "/");
        strcat (temp, filename);
+       temp_end = temp + strlen (temp);
  
        free (temp_dirname);
  
!       /* Look for FILENAME, possibly with any of the extensions
! 	 in EXEC_EXTENSIONS[].  */
!       for (i = 0; exec_extensions[i]; i++)
! 	{
! 	  if (exec_extensions[i][0])
! 	    strcpy (temp_end, exec_extensions[i]);
! 	  statable = (stat (temp, &finfo) == 0);
! 
! 	  /* If we have found a regular executable file, then use it. */
! 	  if ((statable) && (S_ISREG (finfo.st_mode)) &&
! 	      (access (temp, X_OK) == 0))
! 	    return (temp);
! 	}
  
!       free (temp);
      }
    return ((char *)NULL);
  }
*************** get_page_and_section (pagename)
*** 210,215 ****
--- 265,271 ----
      }
  }
  
+ #if PIPE_USE_FORK
  static void
  reap_children (sig)
       int sig;
*************** reap_children (sig)
*** 217,222 ****
--- 273,279 ----
    int status;
    wait (&status);
  }
+ #endif
  
  static char *
  get_manpage_contents (pagename)
*************** get_manpage_contents (pagename)
*** 245,250 ****
--- 302,308 ----
    /* Open a pipe to this program, read the output, and save it away
       in FORMATTED_PAGE.  The reader end of the pipe is pipes[0]; the
       writer end is pipes[1]. */
+ #if PIPE_USE_FORK
    pipe (pipes);
  
    signal (SIGCHLD, reap_children);
*************** get_manpage_contents (pagename)
*** 278,283 ****
--- 336,371 ----
        close (pipes[1]);
        exit (0);
      }
+ #else  /* !PIPE_USE_FORK */
+   /* Cannot fork/exec, but can popen/pclose.  */
+   {
+     FILE *fpipe;
+     char *cmdline = alloca (strlen (formatter_args[0])
+ 			    + strlen (manpage_pagename)
+ 			    + (arg_index > 2 ? strlen (manpage_section) : 0)
+ 			    + 3);
+     int save_stderr = dup (fileno (stderr));
+     int fd_err = open (NULL_DEVICE, O_WRONLY, 0666);
+ 
+     if (fd_err > 2)
+       dup2 (fd_err, fileno (stderr)); /* Don't print errors. */
+     sprintf (cmdline, "%s %s %s", formatter_args[0], manpage_pagename,
+ 				  arg_index > 2 ? manpage_section : "");
+     fpipe = popen (cmdline, "r");
+     if (fd_err > 2)
+       close (fd_err);
+     dup2 (save_stderr, fileno (stderr));
+     if (fpipe == 0)
+       return ((char *)NULL);
+     formatted_page = read_from_fd (fileno (fpipe));
+     if (pclose (fpipe) == -1)
+       {
+ 	if (formatted_page)
+ 	  free (formatted_page);
+ 	return ((char *)NULL);
+       }
+   }
+ #endif /* !PIPE_USE_FORK */
  
    /* If we have the page, then clean it up. */
    if (formatted_page)
*************** manpage_node_of_file_buffer (file_buffer
*** 342,348 ****
      {
        node = (NODE *)xmalloc (sizeof (NODE));
        node->filename = file_buffer->filename;
!       node->nodename = tag->nodename;
        node->contents = file_buffer->contents + tag->nodestart;
        node->nodelen = tag->nodelen;
        node->flags    = 0;
--- 430,436 ----
      {
        node = (NODE *)xmalloc (sizeof (NODE));
        node->filename = file_buffer->filename;
!       node->nodename = xstrdup (tag->nodename);
        node->contents = file_buffer->contents + tag->nodestart;
        node->nodelen = tag->nodelen;
        node->flags    = 0;
*** info/nodemenu.c~0	Fri Jul 25 00:30:30 1997
--- info/nodemenu.c	Sat May  2 18:56:30 1998
*************** get_visited_nodes (filter_func)
*** 168,174 ****
        /* Delete duplicates. */
        for (i = 0, newlen = 1; i < lines_index - 1; i++)
          {
!           if (strcmp (lines[i], lines[i + 1]) == 0)
              {
                free (lines[i]);
                lines[i] = (char *)NULL;
--- 168,176 ----
        /* Delete duplicates. */
        for (i = 0, newlen = 1; i < lines_index - 1; i++)
          {
! 	  /* Use FILENAME_CMP here, since the most important piece
! 	     of info in each line is the file name of the node.  */
!           if (FILENAME_CMP (lines[i], lines[i + 1]) == 0)
              {
                free (lines[i]);
                lines[i] = (char *)NULL;
*** info/nodes.c~0	Fri Jul 25 00:31:34 1997
--- info/nodes.c	Sat May  9 16:12:36 1998
*************** info_find_file_internal (filename, get_t
*** 243,253 ****
    if (info_loaded_files)
      {
        for (i = 0; (file_buffer = info_loaded_files[i]); i++)
!         if ((strcmp (filename, file_buffer->filename) == 0) ||
!             (strcmp (filename, file_buffer->fullpath) == 0) ||
!             ((*filename != '/') &&
!              strcmp (filename,
!                      filename_non_directory (file_buffer->fullpath)) == 0))
            {
              struct stat new_info, *old_info;
  
--- 243,253 ----
    if (info_loaded_files)
      {
        for (i = 0; (file_buffer = info_loaded_files[i]); i++)
!         if ((FILENAME_CMP (filename, file_buffer->filename) == 0) ||
!             (FILENAME_CMP (filename, file_buffer->fullpath) == 0) ||
!             (!IS_ABSOLUTE (filename) &&
!              FILENAME_CMP (filename,
! 			   filename_non_directory (file_buffer->fullpath)) == 0))
            {
              struct stat new_info, *old_info;
  
*************** info_load_file_internal (filename, get_t
*** 325,331 ****
    char *fullpath, *contents;
    long filesize;
    struct stat finfo;
!   int retcode;
    FILE_BUFFER *file_buffer = (FILE_BUFFER *)NULL;
  
    /* Get the full pathname of this file, as known by the info system.
--- 325,331 ----
    char *fullpath, *contents;
    long filesize;
    struct stat finfo;
!   int retcode, compressed;
    FILE_BUFFER *file_buffer = (FILE_BUFFER *)NULL;
  
    /* Get the full pathname of this file, as known by the info system.
*************** info_load_file_internal (filename, get_t
*** 338,355 ****
    /* If the file referenced by the name returned from info_find_fullpath ()
       doesn't exist, then try again with the last part of the filename
       appearing in lowercase. */
    if (retcode < 0)
      {
        char *lowered_name;
        char *basename;
  
        lowered_name = xstrdup (filename);
!       basename = (char *) strrchr (lowered_name, '/');
! 
!       if (basename)
!         basename++;
!       else
!         basename = lowered_name;
  
        while (*basename)
          {
--- 338,353 ----
    /* If the file referenced by the name returned from info_find_fullpath ()
       doesn't exist, then try again with the last part of the filename
       appearing in lowercase. */
+   /* This is probably not needed at all on those systems which define
+      FILENAME_CMP to be strcasecmp.  But let's do it anyway, lest some
+      network redirector supports case sensitivity.  */
    if (retcode < 0)
      {
        char *lowered_name;
        char *basename;
  
        lowered_name = xstrdup (filename);
!       basename = filename_non_directory (lowered_name);
  
        while (*basename)
          {
*************** info_load_file_internal (filename, get_t
*** 373,379 ****
      }
  
    /* Otherwise, try to load the file. */
!   contents = filesys_read_info_file (fullpath, &filesize, &finfo);
  
    if (!contents)
      return ((FILE_BUFFER *)NULL);
--- 371,377 ----
      }
  
    /* Otherwise, try to load the file. */
!   contents = filesys_read_info_file (fullpath, &filesize, &finfo, &compressed);
  
    if (!contents)
      return ((FILE_BUFFER *)NULL);
*************** info_load_file_internal (filename, get_t
*** 386,392 ****
    file_buffer->finfo = finfo;
    file_buffer->filesize = filesize;
    file_buffer->contents = contents;
!   if (file_buffer->filesize != file_buffer->finfo.st_size)
      file_buffer->flags |= N_IsCompressed;
  
    /* If requested, build the tags and nodes for this file buffer. */
--- 384,390 ----
    file_buffer->finfo = finfo;
    file_buffer->filesize = filesize;
    file_buffer->contents = contents;
!   if (compressed)
      file_buffer->flags |= N_IsCompressed;
  
    /* If requested, build the tags and nodes for this file buffer. */
*************** get_tags_of_indirect_tags_table (file_bu
*** 762,775 ****
  
        /* Build the file buffer's list of subfiles. */
        {
!         char *containing_dir, *temp;
          int len_containing_dir;
  
!         containing_dir = xstrdup (file_buffer->fullpath);
!         temp = (char *) strrchr (containing_dir, '/');
! 
!         if (temp)
!           *temp = '\0';
  
          len_containing_dir = strlen (containing_dir);
  
--- 760,780 ----
  
        /* Build the file buffer's list of subfiles. */
        {
!         char *containing_dir = xstrdup (file_buffer->fullpath);
! 	char *temp = filename_non_directory (containing_dir);
          int len_containing_dir;
  
! 	if (temp > containing_dir)
! 	  {
! 	    if (HAVE_DRIVE (file_buffer->fullpath) &&
! 		temp == containing_dir + 2)
! 	      {
! 		/* Avoid converting "d:foo" into "d:/foo" below.  */
! 		*temp = '.';
! 		temp += 2;
! 	      }
! 	    temp[-1] = '\0';
! 	  }
  
          len_containing_dir = strlen (containing_dir);
  
*************** forget_info_file (filename)
*** 1011,1018 ****
      return;
  
    for (i = 0; (file_buffer = info_loaded_files[i]); i++)
!     if ((strcmp (filename, file_buffer->filename) == 0) ||
!         (strcmp (filename, file_buffer->fullpath) == 0))
        {
          free (file_buffer->filename);
          free (file_buffer->fullpath);
--- 1016,1023 ----
      return;
  
    for (i = 0; (file_buffer = info_loaded_files[i]); i++)
!     if ((FILENAME_CMP (filename, file_buffer->filename) == 0) ||
!         (FILENAME_CMP (filename, file_buffer->fullpath) == 0))
        {
          free (file_buffer->filename);
          free (file_buffer->fullpath);
*************** static void
*** 1084,1089 ****
--- 1089,1095 ----
  info_reload_file_buffer_contents (fb)
       FILE_BUFFER *fb;
  {
+   int is_compressed;
  
  #if defined (HANDLE_MAN_PAGES)
    /* If this is the magic manpage node, don't try to reload, just give up. */
*************** info_reload_file_buffer_contents (fb)
*** 1095,1102 ****
  
    /* Let the filesystem do all the work for us. */
    fb->contents =
!     filesys_read_info_file (fb->fullpath, &(fb->filesize), &(fb->finfo));
!   if (fb->filesize != (long) (fb->finfo.st_size))
      fb->flags |= N_IsCompressed;
  }
  
--- 1101,1109 ----
  
    /* Let the filesystem do all the work for us. */
    fb->contents =
!     filesys_read_info_file (fb->fullpath, &(fb->filesize), &(fb->finfo),
! 			    &is_compressed);
!   if (is_compressed)
      fb->flags |= N_IsCompressed;
  }
  
*** info/search.c~0	Tue Jul 15 21:35:50 1997
--- info/search.c	Fri May  1 22:11:52 1998
*************** skip_whitespace_and_newlines (string)
*** 292,298 ****
  {
    register int i;
  
!   for (i = 0; string && (whitespace (string[i]) || string[i] == '\n'); i++);
    return (i);
  }
  
--- 292,298 ----
  {
    register int i;
  
!   for (i = 0; string && whitespace_or_newline (string[i]); i++);
    return (i);
  }
  
*** info/session.c~0	Mon Feb 23 00:38:32 1998
--- info/session.c	Sat May 16 17:44:56 1998
*************** info_set_input_from_file (filename)
*** 305,311 ****
  {
    FILE *stream;
  
!   stream = fopen (filename, "r");
  
    if (!stream)
      return;
--- 305,312 ----
  {
    FILE *stream;
  
!   /* Input may include binary characters.  */
!   stream = fopen (filename, FOPEN_RBIN);
  
    if (!stream)
      return;
*************** DECLARE_INFO_COMMAND (info_beginning_of_
*** 686,692 ****
  
    for (; (point) && (buffer[point - 1] != '\n'); point--);
  
!   /* If at a line start alreay, do nothing. */
    if (point != window->point)
      {
        window->point = point;
--- 687,693 ----
  
    for (; (point) && (buffer[point - 1] != '\n'); point--);
  
!   /* If at a line start already, do nothing. */
    if (point != window->point)
      {
        window->point = point;
*************** DECLARE_INFO_COMMAND (info_goto_node, _(
*** 2144,2169 ****
                {
                  entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
                  entry->filename = entry->nodename = (char *)NULL;
!                 entry->label = (char *) xmalloc
!                   (4 + strlen (fb->filename) + strlen (fb->tags[i]->nodename));
!                 sprintf (entry->label, "(%s)%s",
!                          fb->filename, fb->tags[i]->nodename);
  
                  add_pointer_to_array
                    (entry, items_index, items, items_slots, 100, REFERENCE *);
                }         
- 
-             if (this_is_the_current_fb)
-               {
-                 for (i = 0; fb->tags[i]; i++)
-                   {
-                     entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
-                     entry->filename = entry->nodename = (char *)NULL;
-                     entry->label = xstrdup (fb->tags[i]->nodename);
-                     add_pointer_to_array (entry, items_index, items,
-                                           items_slots, 100, REFERENCE *);
-                   }
-               }
            }
        }
      line = info_read_maybe_completing (window, _("Goto Node: "), items);
--- 2145,2164 ----
                {
                  entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
                  entry->filename = entry->nodename = (char *)NULL;
! 		if (this_is_the_current_fb)
! 		  entry->label = xstrdup (fb->tags[i]->nodename);
! 		else
! 		  {
! 		    entry->label = (char *) xmalloc
! 		      (4 + strlen (fb->filename) +
! 		       strlen (fb->tags[i]->nodename));
! 		    sprintf (entry->label, "(%s)%s",
! 			     fb->filename, fb->tags[i]->nodename);
! 		  }
  
                  add_pointer_to_array
                    (entry, items_index, items, items_slots, 100, REFERENCE *);
                }         
            }
        }
      line = info_read_maybe_completing (window, _("Goto Node: "), items);
*************** kill_node (window, nodename)
*** 2298,2304 ****
  
    /* If there is a nodename, find it in our window list. */
    for (iw = 0; (info_win = info_windows[iw]); iw++)
!     if (strcmp (nodename, info_win->nodes[info_win->current]->nodename) == 0)
        break;
  
    if (!info_win)
--- 2293,2300 ----
  
    /* If there is a nodename, find it in our window list. */
    for (iw = 0; (info_win = info_windows[iw]); iw++)
!     if (strcmp (nodename, info_win->nodes[info_win->current]->nodename) == 0
! 	&& info_win->window == window)
        break;
  
    if (!info_win)
*************** kill_node (window, nodename)
*** 2321,2327 ****
    /* INFO_WIN contains the node that the user wants to stop viewing.  Delete
       this node from the list of nodes previously shown in this window. */
    for (i = info_win->current; i < info_win->nodes_index; i++)
!     info_win->nodes[i] = info_win->nodes[i++];
  
    /* There is one less node in this window's history list. */
    info_win->nodes_index--;
--- 2317,2323 ----
    /* INFO_WIN contains the node that the user wants to stop viewing.  Delete
       this node from the list of nodes previously shown in this window. */
    for (i = info_win->current; i < info_win->nodes_index; i++)
!     info_win->nodes[i] = info_win->nodes[i + 1];
  
    /* There is one less node in this window's history list. */
    info_win->nodes_index--;
*************** print_node (node)
*** 2643,2653 ****
  {
    FILE *printer_pipe;
    char *print_command = getenv ("INFO_PRINT_COMMAND");
  
    if (!print_command || !*print_command)
      print_command = DEFAULT_INFO_PRINT_COMMAND;
  
!   printer_pipe = popen (print_command, "w");
  
    if (!printer_pipe)
      {
--- 2639,2665 ----
  {
    FILE *printer_pipe;
    char *print_command = getenv ("INFO_PRINT_COMMAND");
+   int piping = 0;
  
    if (!print_command || !*print_command)
      print_command = DEFAULT_INFO_PRINT_COMMAND;
  
!   /* Note that on MS-DOS/MS-Windows, this MUST open the pipe in the
!      (default) text mode, since the printer drivers there need to see
!      DOS-style CRLF pairs at the end of each line.
! 
!      FIXME: if we are to support Mac-style text files, we might need
!      to convert the text here.  */
! 
!   /* INFO_PRINT_COMMAND which says ">file" means write to that file.
!      Presumably, the name of the file is the local printer device.  */
!   if (*print_command == '>')
!     printer_pipe = fopen (++print_command, "w");
!   else
!     {
!       printer_pipe = popen (print_command, "w");
!       piping = 1;
!     }
  
    if (!printer_pipe)
      {
*************** print_node (node)
*** 2665,2671 ****
  #endif /* VERBOSE_NODE_DUMPING */
  
    write_node_to_stream (node, printer_pipe);
!   pclose (printer_pipe);
  
  #if defined (VERBOSE_NODE_DUMPING)
    info_error (_("Done."));
--- 2677,2686 ----
  #endif /* VERBOSE_NODE_DUMPING */
  
    write_node_to_stream (node, printer_pipe);
!   if (piping)
!     pclose (printer_pipe);
!   else
!     fclose (printer_pipe);
  
  #if defined (VERBOSE_NODE_DUMPING)
    info_error (_("Done."));
*************** incremental_search (window, count, ignor
*** 3320,3326 ****
                last_isearch_accepted = xstrdup (isearch_string);
              }
  
!           if (key != isearch_terminate_search_key)
              info_set_pending_input (key);
  
            if (func == info_abort_key)
--- 3335,3350 ----
                last_isearch_accepted = xstrdup (isearch_string);
              }
  
! 	  /* If the key is the isearch_terminate_search_key, but some buffered
! 	     input is pending, it is almost invariably because the ESC key is
! 	     actually the beginning of an escape sequence, like in case they
! 	     pressed an arrow key.  So don't gobble the ESC key, push it back
! 	     into pending input.  */
! 	  /* FIXME: this seems like a kludge!  We need a more reliable
! 	     mechanism to know when ESC is a separate key and when it is
! 	     part of an escape sequence.  */
!           if (key != isearch_terminate_search_key ||
! 	      info_any_buffered_input_p ())
              info_set_pending_input (key);
  
            if (func == info_abort_key)
*************** info_gc_file_buffers ()
*** 3437,3444 ****
          {
            for (i = 0; iw->nodes && iw->nodes[i]; i++)
              {
!               if ((strcmp (fb->fullpath, iw->nodes[i]->filename) == 0) ||
!                   (strcmp (fb->filename, iw->nodes[i]->filename) == 0))
                  {
                    fb_referenced_p = 1;
                    break;
--- 3461,3468 ----
          {
            for (i = 0; iw->nodes && iw->nodes[i]; i++)
              {
!               if ((FILENAME_CMP (fb->fullpath, iw->nodes[i]->filename) == 0) ||
!                   (FILENAME_CMP (fb->filename, iw->nodes[i]->filename) == 0))
                  {
                    fb_referenced_p = 1;
                    break;
*************** DECLARE_INFO_COMMAND (info_abort_key, _(
*** 3633,3639 ****
  
  /* Move the cursor to the desired line of the window. */
  DECLARE_INFO_COMMAND (info_move_to_window_line,
!    _("Move to the cursor to a specific line of the window"))
  {
    int line;
  
--- 3657,3663 ----
  
  /* Move the cursor to the desired line of the window. */
  DECLARE_INFO_COMMAND (info_move_to_window_line,
!    _("Move the cursor to a specific line of the window"))
  {
    int line;
  
*************** info_gather_typeahead ()
*** 4172,4177 ****
--- 4196,4226 ----
      if (chars_avail == -1)
        chars_avail = 0;
    }
+ #  else  /* !O_NDELAY */
+ #   ifdef __DJGPP__
+   {
+     extern long pc_term_chars_avail (void);
+ 
+     if (isatty (tty))
+       chars_avail = pc_term_chars_avail ();
+     else
+       {
+ 	/* We could be more accurate by calling ltell, but we have no idea
+ 	   whether tty is buffered by stdio functions, and if so, how many
+ 	   characters are already waiting in the buffer.  So we punt.  */
+ 	struct stat st;
+ 
+ 	if (fstat (tty, &st) < 0)
+ 	  chars_avail = 1;
+ 	else
+ 	  chars_avail = st.st_size;
+       }
+     if (chars_avail > space_avail)
+       chars_avail = space_avail;
+     if (chars_avail)
+       chars_avail = read (tty, &input[0], chars_avail);
+   }
+ #   endif/* __DJGPP__ */
  #  endif /* O_NDELAY */
  #endif /* !FIONREAD */
  
*************** info_get_input_char ()
*** 4229,4234 ****
--- 4278,4284 ----
              {
                fclose (info_input_stream);
                info_input_stream = stdin;
+ 	      tty = fileno (info_input_stream);
                display_inhibited = 0;
                display_update_display (windows);
                display_cursor_at_point (active_window);
*** info/signals.c~0	Tue Jul 15 21:35:50 1997
--- info/signals.c	Sat May  9 11:12:20 1998
*************** typedef RETSIGTYPE signal_handler ();
*** 66,72 ****
  
  static RETSIGTYPE info_signal_handler ();
  static signal_handler *old_TSTP, *old_TTOU, *old_TTIN;
! static signal_handler *old_WINCH, *old_INT;
  
  void
  initialize_info_signal_handler ()
--- 66,72 ----
  
  static RETSIGTYPE info_signal_handler ();
  static signal_handler *old_TSTP, *old_TTOU, *old_TTIN;
! static signal_handler *old_WINCH, *old_INT, *old_USR1;
  
  void
  initialize_info_signal_handler ()
*************** initialize_info_signal_handler ()
*** 84,89 ****
--- 84,94 ----
  #if defined (SIGINT)
    old_INT = (signal_handler *) signal (SIGINT, info_signal_handler);
  #endif
+ 
+ #if defined (SIGUSR1)
+   /* Used by DJGPP to simulate SIGTSTP on Ctrl-Z.  */
+   old_USR1 = (signal_handler *) signal (SIGUSR1, info_signal_handler);
+ #endif
  }
  
  static void
*************** info_signal_handler (sig)
*** 145,156 ****
        }
        break;
  
  #if defined (SIGWINCH)
      case SIGWINCH:
        {
          /* Turn off terminal IO, tell our parent that the window has changed,
             then reinitialize the terminal and rebuild our windows. */
!         old_signal_handler = &old_WINCH;
          terminal_goto_xy (0, 0);
          fflush (stdout);
          terminal_unprep_terminal ();
--- 150,173 ----
        }
        break;
  
+ #if defined (SIGWINCH) || defined (SIGUSR1)
  #if defined (SIGWINCH)
      case SIGWINCH:
+ #endif
+ #if defined (SIGUSR1)
+     case SIGUSR1:
+ #endif
        {
          /* Turn off terminal IO, tell our parent that the window has changed,
             then reinitialize the terminal and rebuild our windows. */
! #if defined SIGWINCH
! 	if (sig == SIGWINCH)
! 	  old_signal_handler = &old_WINCH;
! #endif
! #if defined (SIGUSR1)
! 	if (sig == SIGUSR1)
! 	  old_signal_handler = &old_USR1;
! #endif
          terminal_goto_xy (0, 0);
          fflush (stdout);
          terminal_unprep_terminal ();
*************** info_signal_handler (sig)
*** 167,172 ****
          redisplay_after_signal ();
        }
        break;
! #endif /* SIGWINCH */
      }
  }
--- 184,189 ----
          redisplay_after_signal ();
        }
        break;
! #endif /* SIGWINCH || SIGUSR1 */
      }
  }
*** info/terminal.c~0	Sun Feb 22 02:05:14 1998
--- info/terminal.c	Fri May  1 11:12:28 1998
*************** terminal_unprep_terminal ()
*** 835,837 ****
--- 835,841 ----
    terminal_end_using_terminal ();
  }
  
+ #ifdef __MSDOS__
+ # include "pc_term.c"
+ #endif
+ 
*** /dev/null	Sat May 16 17:58:34 1998
--- info/pc_term.c	Sat May 16 17:50:08 1998
***************
*** 0 ****
--- 1,747 ----
+ /* pc_term.c -- How to handle the PC terminal for Info under MS-DOS/MS-Windows.
+    $Id: pc_term.c,v 1.1 1998/05/16 17:55:15 eliz Exp $
+ 
+    Copyright (C) 1998
+    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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+ 
+ 
+ /* WARNING WARNING WARNING!!!
+    This probably won't work as is with anything but DJGPP!  However, Borland
+    should come close, and other PC compilers will need minor modifications.  */
+ 
+ /* intl/libintl.h defines a macro `gettext' which
+    conflicts with conio.h header.  */
+ #ifdef gettext
+ # undef gettext
+ # define gettext _gettext
+ #endif
+ 
+ #include <pc.h>
+ #include <keys.h>
+ #include <conio.h>
+ 
+ #include "variables.h"
+ 
+ extern int speech_friendly;	/* defined in info.c */
+ 
+ #ifdef max
+ # undef max
+ #endif
+ #ifdef min
+ # undef min
+ #endif
+ #define max(x,y) ((x)>(y) ? (x) : (y))
+ #define min(x,y) ((x)<(y) ? (x) : (y))
+ 
+ /* **************************************************************** */
+ /*                                                                  */
+ /*                PC Terminal Output Functions                      */
+ /*                                                                  */
+ /* **************************************************************** */
+ 
+ static struct text_info outside_info;  /* holds screen params outside Info */
+ static unsigned char    norm_attr, inv_attr;
+ 
+ static unsigned const char * find_sequence (int);
+ 
+ /* Turn on reverse video. */
+ static void
+ pc_begin_inverse (void)
+ {
+   textattr (inv_attr);
+ }
+ 
+ /* Turn off reverse video. */
+ static void
+ pc_end_inverse (void)
+ {
+   textattr (norm_attr);
+ }
+ 
+ /* Move the cursor up one line. */
+ static void
+ pc_up_line (void)
+ {
+   int x, y;
+   ScreenGetCursor (&y, &x);
+   ScreenSetCursor (max (y-1, 0), x);
+ }
+ 
+ /* Move the cursor down one line. */
+ static void
+ pc_down_line (void)
+ {
+   int x, y;
+   ScreenGetCursor (&y, &x);
+   ScreenSetCursor (min (screenheight-1, y+1), x);
+ }
+ 
+ /* Clear the entire terminal screen. */
+ static void
+ pc_clear_screen (void)
+ {
+   ScreenClear ();
+ }
+ 
+ /* Clear from the current position of the cursor to the end of the line. */
+ static void
+ pc_clear_to_eol (void)
+ {
+   clreol (); /* perhaps to be replaced by a loop */
+ }
+ 
+ /* Set the global variables SCREENWIDTH and SCREENHEIGHT. */
+ static void
+ pc_get_screen_size(void)
+ {
+   /* Current screen dimensions are the default.  */
+   if (!outside_info.screenheight)	/* paranoia */
+     gettextinfo (&outside_info);
+   screenwidth  = outside_info.screenwidth;
+   screenheight = outside_info.screenheight;
+ 
+   /* Environment variable "LINES" overrides the default.  */
+   if (getenv ("LINES") != NULL)
+     screenheight = atoi (getenv ("LINES"));
+ 
+   /* Environment variable "INFO_LINES" overrides "LINES".  */
+   if (getenv ("INFO_LINES") != NULL)
+     screenheight = atoi (getenv ("INFO_LINES"));
+ }
+ 
+ /* Move the cursor to the terminal location of X and Y. */
+ static void
+ pc_goto_xy (x, y)
+      int x, y;
+ {
+   ScreenSetCursor (y, x); /* yes, pc.h says ScreenSetCursor (row, column) !! */
+ }
+ 
+ /* Print STRING to the terminal at the current position. */
+ static void
+ pc_put_text (string)
+      char *string;
+ {
+   if (speech_friendly)
+     fputs (string, stdout);
+   else
+     cputs (string);
+ }
+ 
+ /* Ring the terminal bell.  The bell is rung visibly if the terminal is
+    capable of doing that, and if terminal_use_visible_bell_p is non-zero. */
+ static void
+ pc_ring_bell(void)
+ {
+   if (terminal_has_visible_bell_p && terminal_use_visible_bell_p)
+     ScreenVisualBell ();
+   else
+     {
+       printf ("%c",'\a');
+       fflush (stdout);
+     }
+ }
+ 
+ /* Print NCHARS from STRING to the terminal at the current position. */
+ static void
+ pc_write_chars (string, nchars)
+     char *string;
+     int nchars;
+ {
+   if (!nchars)
+     return;
+ 
+   if (speech_friendly)
+     printf ("%.*s",nchars, string);
+   else
+     cprintf ("%.*s",nchars, string);
+ }
+ 
+ /* Scroll an area of the terminal from START to (and excluding) END,
+    AMOUNT lines.  If AMOUNT is negative, the lines are scrolled
+    towards the top of the screen, else they are scrolled towards the
+    bottom of the screen.  The lines of the old region which do not
+    overlap the new region are cleared, to mimic terminal operation.  */
+ static void
+ pc_scroll_terminal (start, end, amount)
+     int start, end, amount;
+ {
+   int line_to_clear = amount > 0 ? start : end + amount;
+ 
+   /* Move the text.  Note that `movetext' expects 1-based coordinates.  */
+   movetext (1, start + 1, ScreenCols (), end, 1, start + amount + 1);
+ 
+   /* Now clear the lines which were left unoccupied.  */
+   if (amount < 0)
+     amount = -amount;
+   while (amount--)
+     {
+       ScreenSetCursor (line_to_clear++, 0);
+       clreol ();
+     }
+ }
+ 
+ /* Put the screen in the video mode and colors which Info will use.
+    Prepare to start using the terminal to read characters singly.  */
+ static void
+ pc_prep_terminal (void)
+ {
+   int tty;
+ 
+   /* Do not set screen height if we already have it, because
+      doing so erases the screen.  */
+   if (screenheight != ScreenRows ())
+     _set_screen_lines (screenheight);
+ 
+   /* Don't fail if they asked for screen dimensions that their
+      hardware cannot support.  */
+   screenheight = ScreenRows ();
+   screenwidth  = ScreenCols ();
+ 
+   /* Try setting the colors user asked for.  */
+   textattr (norm_attr);
+   ScreenClear ();
+ 
+   /* Switch console reads to binary mode.  */
+   tty = fileno (stdin);
+ #ifdef __DJGPP__
+   setmode (tty, O_BINARY);
+   __djgpp_set_ctrl_c (1);	/* re-enable SIGINT generation by Ctrl-C */
+ #endif
+ }
+ 
+ /* Restore the tty settings back to what they were before we started using
+    this terminal. */
+ static void
+ pc_unprep_terminal (void)
+ {
+   int tty;
+ 
+   textattr (outside_info.normattr);
+ 
+   /* Do not set screen height if we already have it, because
+      doing so erases the screen.  */
+   if (outside_info.screenheight != ScreenRows ())
+     {
+       _set_screen_lines (outside_info.screenheight);
+       textmode (LASTMODE);
+     }
+   else
+     pc_clear_to_eol ();	/* for text attributes to really take effect */
+ 
+   /* Switch back to text mode on stdin.  */
+   tty = fileno (stdin);
+ #ifdef __DJGPP__
+   setmode (tty, O_TEXT);
+ #endif
+ }
+ 
+ /* Initialize the terminal which is known as TERMINAL_NAME.  If this
+    terminal doesn't have cursor addressability, `terminal_is_dumb_p'
+    becomes nonzero.  The variables SCREENHEIGHT and SCREENWIDTH are set
+    to the dimensions that this terminal actually has.  The variable
+    TERMINAL_HAS_META_P becomes nonzero if this terminal supports a Meta
+    key.  Finally, the terminal screen is cleared. */
+ static void
+ pc_initialize_terminal (term_name)
+     char *term_name;
+ {
+   char *info_colors;
+ 
+   if (!term_name)
+     {
+       term_name = getenv ("TERM");
+       if (!term_name)
+ 	term_name = "pc-dos";	/* ``what's in a name?'' */
+     }
+ 
+   /* Get current video information, to be restored later.  */
+   if (outside_info.screenwidth == 0)
+     gettextinfo (&outside_info);
+ 
+   /* Current screen colors are the default.  */
+   norm_attr    = outside_info.normattr;
+   inv_attr     = (((outside_info.normattr &    7) << 4) |
+                   ((outside_info.normattr & 0x7f) >> 4));
+ 
+   /* Does the user want non-default colors?  */
+   info_colors = getenv ("INFO_COLORS");
+   if ((info_colors != (char *)0) && !speech_friendly)
+     {
+       /* Decode a color from a string descriptor.
+ 	 The descriptor string is a sequence of color specifiers separated
+ 	 by a non-numeric character.  Each color specifier should represent
+ 	 a small integer which fits into an unsigned char, and can be given
+ 	 in any base supported by strtoul.  Examples of valid descriptors:
+ 
+ 		"10 31"
+ 		"0x13/0x45"
+ 		"007.077"
+ 
+ 	The character that separates two color specifiers can be any character
+ 	which cannot be used in a printed represent of an integer number.  */
+       char *endp;
+       unsigned long color_desc = strtoul (info_colors, &endp, 0);
+ 
+       if (color_desc <= UCHAR_MAX)
+ 	{
+ 	  norm_attr = (unsigned char)color_desc;
+ 	  color_desc = strtoul (endp + 1, &endp, 0);
+ 	  if (color_desc <= UCHAR_MAX)
+ 	    inv_attr = (unsigned char)color_desc;
+ 	}
+     }
+ 
+   /* We can scroll.  */
+   terminal_can_scroll = 1;
+ 
+   /* We know how to produce a visible bell, if somebody's looking...  */
+   if (!speech_friendly)
+     terminal_has_visible_bell_p = 1;
+ 
+   /* We have a Meta key.  */
+   terminal_has_meta_p = 1;
+ 
+   /* We are *certainly* NOT dumb!  */
+   terminal_is_dumb_p = 0;
+ 
+   /* We can display the full 1..255 range of characters.  */
+   ISO_Latin_p = 1;
+ 
+   pc_get_screen_size ();
+ 
+   /* Store the arrow keys.  */
+   term_ku = (char *)find_sequence (K_Up);
+   term_kd = (char *)find_sequence (K_Down);
+   term_kr = (char *)find_sequence (K_Right);
+   term_kl = (char *)find_sequence (K_Left);
+ 
+   term_kP = (char *)find_sequence (K_PageUp);
+   term_kN = (char *)find_sequence (K_PageDown);
+ 
+   /* Set all the hooks to our PC-specific functions.  */
+   terminal_begin_inverse_hook       = pc_begin_inverse;
+   terminal_end_inverse_hook         = pc_end_inverse;
+   terminal_prep_terminal_hook       = pc_prep_terminal;
+   terminal_unprep_terminal_hook     = pc_unprep_terminal;
+   terminal_up_line_hook             = pc_up_line;
+   terminal_down_line_hook           = pc_down_line;
+   terminal_clear_screen_hook        = pc_clear_screen;
+   terminal_clear_to_eol_hook        = pc_clear_to_eol;
+   terminal_get_screen_size_hook     = pc_get_screen_size;
+   terminal_goto_xy_hook             = pc_goto_xy;
+   terminal_put_text_hook            = pc_put_text;
+   terminal_ring_bell_hook           = pc_ring_bell;
+   terminal_write_chars_hook         = pc_write_chars;
+   terminal_scroll_terminal_hook     = pc_scroll_terminal;
+ }
+ 
+ /* **************************************************************** */
+ /*                                                                  */
+ /*            How to Read Characters From the PC Terminal           */
+ /*                                                                  */
+ /* **************************************************************** */
+ 
+ /* This will most certainly work ONLY with DJGPP.  */
+ #ifdef __DJGPP__
+ 
+ #include <errno.h>
+ #include <sys/fsext.h>
+ #include <dpmi.h>
+ 
+ /* Translation table for some special keys.
+    Arrow keys which are standard on other keyboards are translated into
+    standard ESC-sequences, in case somebody rebinds the simple keys
+    (like C-f, C-b, C-n, etc.).
+ 
+    The strange "\033\061" prefix in some keys is a numeric argument of
+    one, which means ``do the next command once''.  It is here so that
+    when the according PC key is pressed in the middle of an incremental
+    search, Info doesn't see just an ASCII character like `n' or `B',
+    and doesn't add it to the search string; instead, it will exit the
+    incremental search and then perform the command.  */
+ static struct
+ {
+   int inkey;
+   unsigned char const * const sequence;
+ } DJGPP_keytab[] = {		   /* these are for moving between nodes... */
+   {K_Control_PageDown,  "\033\061n"},
+   {K_Control_PageUp,    "\033\061p"},
+   {K_Control_Up,        "\033\061u"},
+   {K_Control_Down,      "\033\061m"},
+   {K_Control_Center,    "\033\061l"},
+ 
+   {K_Home,              "\001"},   /* ...and these are for moving IN a node */
+   {K_End,               "\005"},   /* they're Numeric-Keypad-Keys, so       */
+   {K_Left,              "\033[D"}, /* NUMLOCK should be off !!              */
+   {K_Right,             "\033[C"},
+   {K_Down,              "\033[B"},
+   {K_Up,                "\033[A"},
+   {K_PageDown,          "\033[G"},
+   {K_PageUp,            "\033[I"},
+   {K_Control_Left,      "\033b"},
+   {K_Control_Right,     "\033f"},
+   {K_Control_Home,      "\033<"},
+   {K_Control_End,       "\033>"},
+ 
+   {K_EHome,             "\001"},   /* these are also for moving IN a node */
+   {K_EEnd,              "\005"},   /* they're the "extended" (Grey) keys  */
+   {K_ELeft,             "\033[D"},
+   {K_ERight,            "\033[C"},
+   {K_EDown,             "\033[B"},
+   {K_EUp,               "\033[A"},
+   {K_EPageDown,         "\033[G"},
+   {K_EPageUp,           "\033[I"},
+   {K_Control_ELeft,     "\033b"},
+   {K_Control_ERight,    "\033f"},
+   {K_Control_EHome,     "\033<"},
+   {K_Control_EEnd,      "\033>"},
+ 
+   {K_BackTab,           "\033\011"},
+   {K_F1,                "\10"},    /* YEAH, gimme that good old F-one-thing */
+   {K_Delete,            "\177"},   /* to make Kp-Del be DEL (0x7f)          */
+   {K_EDelete,           "\177"},   /* to make Delete be DEL (0x7f)          */
+ 
+   /* These are here to map more Alt-X keys to ESC X sequences.  */
+   {K_Alt_Q,             "\033q"},
+   {K_Alt_W,             "\033w"},
+   {K_Alt_E,             "\033e"},
+   {K_Alt_R,             "\033r"},
+   {K_Alt_T,             "\033t"},
+   {K_Alt_Y,             "\033y"},
+   {K_Alt_U,             "\033u"},
+   {K_Alt_I,             "\033i"},
+   {K_Alt_O,             "\033o"},
+   {K_Alt_P,             "\033p"},
+   {K_Alt_LBracket,      "\033["},
+   {K_Alt_RBracket,      "\033]"},
+   {K_Alt_Return,        "\033\015"},
+   {K_Alt_A,             "\033a"},
+   {K_Alt_S,             "\033s"},
+   {K_Alt_D,             "\033d"},
+   {K_Alt_F,             "\033f"},
+   {K_Alt_G,             "\033g"},
+   {K_Alt_H,             "\033h"},
+   {K_Alt_J,             "\033j"},
+   {K_Alt_K,             "\033k"},
+   {K_Alt_L,             "\033l"},
+   {K_Alt_Semicolon,     "\033;"},
+   {K_Alt_Quote,         "\033'"},
+   {K_Alt_Backquote,     "\033`"},
+   {K_Alt_Backslash,     "\033\\"},
+   {K_Alt_Z,             "\033z"},
+   {K_Alt_X,             "\033x"},
+   {K_Alt_C,             "\033c"},
+   {K_Alt_V,             "\033v"},
+   {K_Alt_B,             "\033b"},
+   {K_Alt_N,             "\033n"},
+   {K_Alt_M,             "\033m"},
+   {K_Alt_Comma,         "\033<"}, /* our reader cannot distinguish between */
+   {K_Alt_Period,        "\033>"}, /* Alt-. and Alt->, so we cheat a little */
+   {K_Alt_Slash,         "\033?"}, /* ditto, to get Alt-?                   */
+   {K_Alt_Backspace,     "\033\177"}, /* M-DEL, to delete word backwards */
+   {K_Alt_1,             "\033\061"},
+   {K_Alt_2,             "\033\062"},
+   {K_Alt_3,             "\033\063"},
+   {K_Alt_4,             "\033\064"},
+   {K_Alt_5,             "\033\065"},
+   {K_Alt_6,             "\033\066"},
+   {K_Alt_7,             "\033\067"},
+   {K_Alt_8,             "\033\070"},
+   {K_Alt_9,             "\033\071"},
+   {K_Alt_0,             "\033\060"},
+   {K_Alt_Dash,          "\033\055"},
+   {K_Alt_Equals,        "\033\075"},
+   {K_Alt_EDelete,       "\033\177"},
+   {K_Alt_Tab,           "\033\011"},
+   {0, 0}
+ };
+ 
+ /* Given a key, return the sequence of characters which
+    our keyboard driver generates.  */
+ static unsigned const char *
+ find_sequence (int key)
+ {
+   int i;
+ 
+   for (i = 0; DJGPP_keytab[i].inkey; i++)
+     if (key == DJGPP_keytab[i].inkey)
+       return DJGPP_keytab[i].sequence;
+ 
+   return (unsigned const char *)NULL;
+ }
+ 
+ /* Return zero if a key is pending in the
+    keyboard buffer, non-zero otherwise.  */
+ static int
+ kbd_buffer_empty (void)
+ {
+   __dpmi_regs r;
+   int retval;
+ 
+   r.h.ah = 0x11;	/* Get enhanced keyboard status */
+   __dpmi_int (0x16, &r);
+ 
+   /* If the keyboard buffer is empty, the Zero Flag will be set.  */
+   return (r.x.flags & 0x40) == 0x40;
+ }
+ 
+ /* The buffered characters pending to be read.
+    Actually, Info usually reads a single character, but when we
+    translate a key into a sequence of characters, we keep them here.  */
+ static unsigned char buffered[512];
+ 
+ /* Index of the next buffered character to be returned.  */
+ static int buf_idx;
+ 
+ /* Return the number of characters waiting to be read.  */
+ long
+ pc_term_chars_avail (void)
+ {
+   if (buf_idx >= sizeof (buffered)) /* paranoia */
+     {
+       buf_idx = 0;
+       buffered[buf_idx] = '\0';
+       return 0;
+     }
+   else
+     return (long)strlen (buffered + buf_idx);
+ }
+ 
+ /* Our special terminal keyboard reader.  It will be called by
+    low-level libc functions when the application calls `read' or
+    the ANSI-standard stream-oriented read functions.  If the
+    caller wants to read the terminal, we redirect the call to
+    the BIOS keyboard functions, since that lets us recognize more
+    keys then DOS does.  */
+ static int
+ keyboard_read (__FSEXT_Fnumber func, int *retval, va_list rest_args)
+ {
+   /* When we are called, REST_ARGS are: file_descriptor, buf, nbytes.  */
+   unsigned char *buf;
+   size_t nbytes, nread = 0;
+   int fd = va_arg (rest_args, int);
+ 
+   /* Is this call for us?  */
+   if (func != __FSEXT_read || !isatty (fd))
+     return 0;	/* and the usual DOS call will be issued */
+ 
+   buf = va_arg (rest_args, unsigned char *);
+   nbytes = va_arg (rest_args, size_t);
+ 
+   if (!buf)
+     {
+       errno = EINVAL;
+       *retval = -1;
+       return 1;
+     }
+   if (!nbytes)
+     {
+       *retval = 0;
+       return 1;
+     }
+ 
+   /* Loop here until enough bytes has been read.  */
+   do
+     {
+       int key;
+ 
+       /* If any ``buffered characters'' are left, return as much
+ 	 of them as the caller wanted.  */
+       while (buffered[buf_idx] && nbytes)
+ 	{
+ 	  *buf++ = buffered[buf_idx++];
+ 	  nread++;
+ 	  nbytes--;
+ 	}
+ 
+       if (nbytes <= 0)
+ 	break;
+ 
+       /* Wait for another key.
+ 	 We do that in a busy-waiting loop so we don't get parked
+ 	 inside a BIOS call, which will effectively disable signals.  */
+       while (kbd_buffer_empty ())
+ 	__dpmi_yield ();
+ 
+       key = getxkey ();
+ 
+       /* Translate the key if necessary.
+ 	 Untranslated non-ASCII keys are silently ignored.  */
+       if ((key & 0x300) != 0)
+ 	{
+ 	  unsigned char const * key_sequence = find_sequence (key);
+ 
+ 	  if (key_sequence != NULL)
+ 	    {
+ 	      strcpy (buffered, key_sequence);
+ 	      buf_idx = 0;
+ 	    }
+ 	}
+       else if (key == K_Control_Z)
+ 	raise (SIGUSR1);	/* we don't have SIGTSTP, so simulate it */
+       else if (key <= 0xff)
+ 	{
+ 	  *buf++ = key;
+ 	  nbytes--;
+ 	  nread++;
+ 	}
+     }
+   while (nbytes > 0);
+ 
+   *retval = nread;
+   return 1;	/* meaning that we handled the call */
+ }
+ 
+ /* Install our keyboard handler.
+    This is called by the startup code before `main'.  */
+ static void __attribute__((constructor))
+ install_keyboard_handler (void)
+ {
+   __FSEXT_set_function (fileno (stdin), keyboard_read);
+ 
+   /* We need to set this single hook here; the rest
+      will be set by pc_initialize_terminal when it is called.  */
+   terminal_initialize_terminal_hook = pc_initialize_terminal;
+ }
+ 
+ #endif /* __DJGPP__ */
+ 
+ /* **************************************************************** */
+ /*                                                                  */
+ /*                Emulation of SIGTSTP on Ctrl-Z                    */
+ /*                                                                  */
+ /* **************************************************************** */
+ 
+ #include <limits.h>
+ #include "signals.h"
+ #include "session.h"
+ 
+ #ifndef PATH_MAX
+ # define PATH_MAX 512
+ #endif
+ 
+ /* Effectively disable signals which aren't defined
+    (assuming no signal can ever be zero).
+    SIGINT is ANSI, so we expect it to be always defined.  */
+ #ifndef SIGUSR1
+ # define SIGUSR1 0
+ #endif
+ #ifndef SIGQUIT
+ # define SIGQUIT 0
+ #endif
+ 
+ int
+ kill (pid_t pid, int sig)
+ {
+   static char interrupted_msg[] = "Interrupted\r\n";
+   static char stopped_msg[] = "Stopped.  Type \"exit RET\" to return.\r\n";
+   char cwd[PATH_MAX + 1];
+ 
+   if (pid == getpid ()
+       || pid == 0
+       || pid == -1
+       || pid == -getpid ())
+     {
+       switch (sig)
+ 	{
+ 	RETSIGTYPE (*old_INT)(int), (*old_QUIT)(int);
+ 
+ 	case SIGINT:
+ #ifdef __DJGPP__
+ 	  /* If SIGINT was generated by a readable key, we want to remove
+ 	     it from the PC keyboard buffer, so that DOS and other
+ 	     programs never see it.  DJGPP signal-handling mechanism
+ 	     doesn't remove the INT key from the keyboard buffer.  */
+ 	  if (!kbd_buffer_empty ())
+ 	    getxkey ();
+ #endif
+ 	  pc_write_chars (interrupted_msg, sizeof (interrupted_msg) - 1);
+ 	  exit (1);
+ 	case SIGUSR1:
+ 	  /* Simulate SIGTSTP by invoking a subsidiary shell.  */
+ 	  pc_goto_xy (0, outside_info.screenheight - 1);
+ 	  pc_clear_to_eol ();
+ 	  pc_write_chars (stopped_msg, sizeof (stopped_msg) - 1);
+ 
+ 	  /* The child shell can change the working directory, so
+ 	     we need to save and restore it, since it is global.  */
+ 	  if (!getcwd (cwd, PATH_MAX)) /* should never happen */
+ 	    cwd[0] = '\0';
+ 
+ 	  /* We don't want to get fatal signals while the subshell runs.  */
+ 	  old_INT = signal (SIGINT, SIG_IGN);
+ 	  old_QUIT = signal (SIGQUIT, SIG_IGN);
+ 	  system ("");
+ 	  if (*cwd)
+ 	    chdir (cwd);
+ 	  signal (SIGINT, old_INT);
+ 	  signal (SIGQUIT, old_QUIT);
+ 	  break;
+ 	default:
+ 	  if (sig)
+ 	    raise (sig);
+ 	  break;
+ 	}
+       return 0;
+     }
+   else
+     return -1;
+ }
+ 
+ /* These should never be called, but they make the linker happy.  */
+ 
+ void       tputs (char *a, int b, int (*c)())
+ {
+   perror ("tputs");
+ }
+ 
+ char*     tgoto (char*a, int b, int c)
+ {
+   perror ("tgoto"); return 0; /* here and below, added dummy retvals */
+ }
+ 
+ int       tgetnum (char*a)
+ {
+   perror ("tgetnum"); return 0;
+ }
+ 
+ int       tgetflag (char*a)
+ {
+   perror ("tgetflag"); return 0;
+ }
+ 
+ char*     tgetstr (char *a, char **b)
+ {
+   perror ("tgetstr"); return 0;
+ }
+ 
+ int       tgetent (char*a, char*b)
+ {
+   perror ("tgetent"); return 0;
+ }
+ 
+ int	tcgetattr(int fildes, struct termios *termios_p)
+ {
+   perror ("tcgetattr"); return 0;
+ }
+ 
+ int	tcsetattr(int fd, int opt_actions, const struct termios *termios_p)
+ {
+   perror ("tcsetattr"); return 0;
+ }
*** info/tilde.c~0	Mon Feb 23 01:03:22 1998
--- info/tilde.c	Fri May  1 19:02:46 1998
*************** tilde_find_suffix (string)
*** 123,129 ****
  
    for (i = 0; i < string_len; i++)
      {
!       if (string[i] == '/' || !string[i])
          break;
  
        for (j = 0; suffixes && suffixes[j]; j++)
--- 123,129 ----
  
    for (i = 0; i < string_len; i++)
      {
!       if (IS_SLASH (string[i]) || !string[i])
          break;
  
        for (j = 0; suffixes && suffixes[j]; j++)
*************** tilde_expand_word (filename)
*** 210,216 ****
    if (dirname && *dirname == '~')
      {
        char *temp_name;
!       if (!dirname[1] || dirname[1] == '/')
          {
            /* Prepend $HOME to the rest of the string. */
            char *temp_home = getenv ("HOME");
--- 210,216 ----
    if (dirname && *dirname == '~')
      {
        char *temp_name;
!       if (!dirname[1] || IS_SLASH (dirname[1]))
          {
            /* Prepend $HOME to the rest of the string. */
            char *temp_home = getenv ("HOME");
*************** tilde_expand_word (filename)
*** 244,250 ****
  
            for (i = 1; (c = dirname[i]); i++)
              {
!               if (c == '/')
                  break;
                else
                  username[i - 1] = c;
--- 244,250 ----
  
            for (i = 1; (c = dirname[i]); i++)
              {
!               if (IS_SLASH (c))
                  break;
                else
                  username[i - 1] = c;
*** info/window.c~0	Tue Feb 24 00:43:38 1998
--- info/window.c	Fri May  1 22:18:30 1998
*************** string_width (string, hpos)
*** 766,772 ****
    return (width);
  }
  
! /* Quickly guess the approximate number of lines to that NODE would
     take to display.  This really only counts carriage returns. */
  int
  window_physical_lines (node)
--- 766,772 ----
    return (width);
  }
  
! /* Quickly guess the approximate number of lines that NODE would
     take to display.  This really only counts carriage returns. */
  int
  window_physical_lines (node)
*** makeinfo/makeinfo.c~0	Sun May 10 00:32:06 1998
--- makeinfo/makeinfo.c	Sun May 10 00:32:12 1998
*************** char *alloca ();
*** 69,74 ****
--- 69,83 ----
  # define va_end(args)
  #endif
  
+ /* DJGPP supports /dev/null, which is okay for Unix aficionados,
+    shell scripts and Makefiles, but interactive DOS die-hards
+    would probably want to have NUL as well.  */
+ #ifdef __DJGPP__
+ # define ALSO_NULL_DEVICE  "NUL"
+ #else
+ # define ALSO_NULL_DEVICE  ""
+ #endif
+ 
  /* You can change some of the behavior of Makeinfo by changing the
     following defines: */
  
*************** main (argc, argv)
*** 1019,1025 ****
            include_files_path = (char *)
              xrealloc (include_files_path,
                        2 + strlen (include_files_path) + strlen (optarg));
!           strcat (include_files_path, ":");
            strcat (include_files_path, optarg);
            break;
  
--- 1028,1034 ----
            include_files_path = (char *)
              xrealloc (include_files_path,
                        2 + strlen (include_files_path) + strlen (optarg));
!           strcat (include_files_path, PATH_SEP);
            strcat (include_files_path, optarg);
            break;
  
*************** main (argc, argv)
*** 1046,1052 ****
                include_files_path = xstrdup (optarg);
                include_files_path = (char *) xrealloc (include_files_path,
                             strlen (include_files_path) + 3); /* 3 for ":.\0" */
!               strcat (include_files_path, ":.");
              }
            else
              {
--- 1055,1061 ----
                include_files_path = xstrdup (optarg);
                include_files_path = (char *) xrealloc (include_files_path,
                             strlen (include_files_path) + 3); /* 3 for ":.\0" */
!               strcat (strcat (include_files_path, PATH_SEP), ".");
              }
            else
              {
*************** find_and_load (filename)
*** 1238,1243 ****
--- 1247,1255 ----
    long file_size;
    int file = -1, count = 0;
    char *fullpath, *result, *get_file_info_in_path ();
+ #if O_BINARY || defined (VMS)
+   int n;
+ #endif
  
    result = fullpath = (char *)NULL;
  
*************** find_and_load (filename)
*** 1260,1276 ****
       readable bytes is always less than this value.  The arcane
       mysteries of VMS/RMS are too much to probe, so this hack
      suffices to make things work. */
! #if defined (VMS) || defined (WIN32)
  #ifdef VMS
    while ((n = read (file, result + count, file_size)) > 0)
  #else /* WIN32 */
    while ((n = read (file, result + count, 1)) > 0)
  #endif /* WIN32 */
      count += n;
!   if (n == -1)
! #else /* !VMS && !WIN32 */
!     count = file_size;
!     if (read (file, result, file_size) != file_size)
  #endif /* !VMS && !WIN32 */
    error_exit:
      {
--- 1272,1295 ----
       readable bytes is always less than this value.  The arcane
       mysteries of VMS/RMS are too much to probe, so this hack
      suffices to make things work. */
! #if O_BINARY || defined (VMS)
  #ifdef VMS
    while ((n = read (file, result + count, file_size)) > 0)
+ #else  /* !VMS */
+ #ifndef WIN32
+   while ((n = read (file, result + count, file_size)) > 0)
  #else /* WIN32 */
+   /* Does WIN32 really need reading 1 character at a time??  */
    while ((n = read (file, result + count, 1)) > 0)
  #endif /* WIN32 */
+ #endif /* !VMS */
      count += n;
!   if (0 < count && count < file_size)
!     result = xrealloc (result, count + 2); /* why waste the slack? */
!   else if (n == -1)
! #else /* !VMS && !O_BINARY */
!   count = file_size;
!   if (read (file, result, file_size) != file_size)
  #endif /* !VMS && !WIN32 */
    error_exit:
      {
*************** pop_node_filename ()
*** 1390,1395 ****
--- 1409,1439 ----
    node_filename = node_filename_stack[--node_filename_stack_index];
  }
  
+ /* Return the index of the first character in the filename
+    which is past all the leading directory characters.  */
+ static int
+ skip_directory_part (filename)
+      char *filename;
+ {
+   register int i = strlen (filename) - 1;
+ 
+   while (i && !IS_SLASH (filename[i]))
+     i--;
+   if (IS_SLASH (filename[i]))
+     i++;
+   else if (filename[i] && HAVE_DRIVE (filename))
+     i = 2;
+ 
+   return i;
+ }
+ 
+ char *
+ filename_non_directory (name)
+      char *name;
+ {
+   return xstrdup (name + skip_directory_part (name));
+ }
+ 
  /* Return just the simple part of the filename; i.e. the
     filename without the path information, or extensions.
     This conses up a new string. */
*************** char *
*** 1397,1411 ****
  filename_part (filename)
       char *filename;
  {
!   char *basename;
  
-   basename = strrchr (filename, '/');
-   if (!basename)
-     basename = filename;
-   else
-     basename++;
- 
-   basename = xstrdup (basename);
  #if defined (REMOVE_OUTPUT_EXTENSIONS)
  
    /* See if there is an extension to remove.  If so, remove it. */
--- 1441,1448 ----
  filename_part (filename)
       char *filename;
  {
!   char *basename = filename_non_directory (filename);
  
  #if defined (REMOVE_OUTPUT_EXTENSIONS)
  
    /* See if there is an extension to remove.  If so, remove it. */
*************** pathname_part (filename)
*** 1431,1442 ****
  
    filename = expand_filename (filename, "");
  
!   i = strlen (filename) - 1;
! 
!   while (i && filename[i] != '/')
!     i--;
!   if (filename[i] == '/')
!     i++;
  
    if (i)
      {
--- 1468,1474 ----
  
    filename = expand_filename (filename, "");
  
!   i = skip_directory_part (filename);
  
    if (i)
      {
*************** pathname_part (filename)
*** 1448,1466 ****
    return (result);
  }
  
- char *
- filename_non_directory (name)
-      char *name;
- {
-   register int i;
- 
-   for (i = strlen (name) - 1; i; i--)
-     if (name[i] == '/')
-       return (xstrdup (name + i + 1));
- 
-   return (xstrdup (name));
- }
- 
  /* Return the expansion of FILENAME. */
  char *
  expand_filename (filename, input_name)
--- 1480,1485 ----
*************** expand_filename (filename, input_name)
*** 1494,1503 ****
        return (filename);
      }
          
!   if (filename[0] == '.' || filename[0] == '/')
      return (filename);
  
!   if (filename[0] != '/' && input_name[0] == '/')
      {
        /* Make it so that relative names work. */
        char *result;
--- 1513,1522 ----
        return (filename);
      }
          
!   if (filename[0] == '.' || IS_ABSOLUTE (filename))
      return (filename);
  
!   if (!IS_ABSOLUTE (filename) && IS_ABSOLUTE (input_name))
      {
        /* Make it so that relative names work. */
        char *result;
*************** expand_filename (filename, input_name)
*** 1507,1516 ****
        result = (char *)xmalloc (1 + strlen (input_name) + strlen (filename));
        strcpy (result, input_name);
  
!       while (result[i] != '/' && i)
          i--;
  
!       if (result[i] == '/')
          i++;
  
        strcpy (&result[i], filename);
--- 1526,1535 ----
        result = (char *)xmalloc (1 + strlen (input_name) + strlen (filename));
        strcpy (result, input_name);
  
!       while (!IS_SLASH (result[i]) && i)
          i--;
  
!       if (IS_SLASH (result[i]))
          i++;
  
        strcpy (&result[i], filename);
*************** full_pathname (filename)
*** 1533,1541 ****
      return (xstrdup (""));
    
    /* Already absolute? */
!   if ((initial_character == '/') ||
!       ((strncmp (filename, "./", 2) == 0) ||
!        (strncmp (filename, "../", 3) == 0)))
      return (xstrdup (filename));
  
    if (initial_character != '~')
--- 1552,1561 ----
      return (xstrdup (""));
    
    /* Already absolute? */
!   if (IS_ABSOLUTE (filename) ||
!       (*filename == '.' &&
!        (IS_SLASH (filename[1]) ||
! 	(filename[1] == '.' && IS_SLASH (filename[2])))))
      return (xstrdup (filename));
  
    if (initial_character != '~')
*************** full_pathname (filename)
*** 1561,1568 ****
      }
    else
      {
  #ifndef WIN32
!       if (filename[1] == '/')
          {
            /* Return the concatenation of the environment variable HOME
               and the rest of the string. */
--- 1581,1591 ----
      }
    else
      {
+       /* Does anybody know why WIN32 doesn't want to support $HOME?
+          If the reason is they don't have getpwnam, they should
+          only disable the else clause below.  */
  #ifndef WIN32
!       if (IS_SLASH (filename[1]))
          {
            /* Return the concatenation of the environment variable HOME
               and the rest of the string. */
*************** full_pathname (filename)
*** 1588,1594 ****
  
            for (i = 1; (c = filename[i]); i++)
              {
!               if (c == '/')
                  break;
                else
                  username[i - 1] = c;
--- 1611,1617 ----
  
            for (i = 1; (c = filename[i]); i++)
              {
!               if (IS_SLASH (c))
                  break;
                else
                  username[i - 1] = c;
*************** get_until_in_braces (match, string)
*** 1929,1934 ****
--- 1952,1961 ----
  /* Convert the file named by NAME.  The output is saved on the file
     named as the argument to the @setfilename command. */
  static char *suffixes[] = {
+   /* ".txi" is checked first so that on 8+3 DOS filesystems, if they
+      have "texinfo.txi" and "texinfo.tex" in the same directory, the
+      former is used rather than the latter, due to file name truncation.  */
+   ".txi",
    ".texinfo",
    ".texi",
    ".txinfo",
*************** finished:
*** 2197,2203 ****
        fclose (macro_expansion_output_stream);
        if (errors_printed && !force
            && strcmp (macro_expansion_filename, "-") != 0
!           && strcmp (macro_expansion_filename, "/dev/null") != 0)
          {
            fprintf (stderr, _("%s: Removing macro output file `%s' due to errors; use --force to preserve.\n"),
                     progname, macro_expansion_filename);
--- 2224,2231 ----
        fclose (macro_expansion_output_stream);
        if (errors_printed && !force
            && strcmp (macro_expansion_filename, "-") != 0
!           && FILENAME_CMP (macro_expansion_filename, NULL_DEVICE) != 0
! 	  && FILENAME_CMP (macro_expansion_filename, ALSO_NULL_DEVICE) != 0)
          {
            fprintf (stderr, _("%s: Removing macro output file `%s' due to errors; use --force to preserve.\n"),
                     progname, macro_expansion_filename);
*************** finished:
*** 2229,2235 ****
          split_file (real_output_filename, 0);
        else if (errors_printed && !force
                 && strcmp (real_output_filename, "-") != 0
!                && strcmp (real_output_filename, "/dev/null") != 0)
          { /* If there were errors, and no --force, remove the output.  */
            fprintf (stderr, _("%s: Removing output file `%s' due to errors; use --force to preserve.\n"),
                     progname, real_output_filename);
--- 2257,2264 ----
          split_file (real_output_filename, 0);
        else if (errors_printed && !force
                 && strcmp (real_output_filename, "-") != 0
!                && FILENAME_CMP (real_output_filename, NULL_DEVICE) != 0
! 	       && FILENAME_CMP (real_output_filename, ALSO_NULL_DEVICE) != 0)
          { /* If there were errors, and no --force, remove the output.  */
            fprintf (stderr, _("%s: Removing output file `%s' due to errors; use --force to preserve.\n"),
                     progname, real_output_filename);
*************** cm_node ()
*** 4830,4836 ****
                    /* We got here, so it hasn't been found yet.  Try
                       the next file on the filestack if there is one. */
                    if (next_file &&
!                       (strcmp (next_file->filename, input_filename) == 0))
                      {
                        input_text = next_file->text;
                        input_text_offset = next_file->offset;
--- 4859,4865 ----
                    /* We got here, so it hasn't been found yet.  Try
                       the next file on the filestack if there is one. */
                    if (next_file &&
!                       (FILENAME_CMP (next_file->filename, input_filename) == 0))
                      {
                        input_text = next_file->text;
                        input_text_offset = next_file->offset;
*************** split_file (filename, size)
*** 5250,5255 ****
--- 5279,5285 ----
    long file_size;
    char *the_header;
    int header_size;
+   int dos_file_names = 0;	/* if non-zero, don't exceed 8+3 limits */
  
    /* Can only do this to files with tag tables. */
    if (!tag_table)
*************** split_file (filename, size)
*** 5270,5275 ****
--- 5300,5308 ----
    root_filename = filename_part (filename);
    root_pathname = pathname_part (filename);
  
+   /* Do we need to generate names of subfiles which don't exceed 8+3 limits? */
+   dos_file_names = !HAVE_LONG_FILENAMES (root_pathname ? root_pathname : ".");
+ 
    if (!root_pathname)
      root_pathname = xstrdup ("");
  
*************** split_file (filename, size)
*** 5366,5378 ****
                write_region:
                  {
                    int fd;
!                   char *split_filename;
  
                    split_filename = (char *) xmalloc
!                     (10 + strlen (root_pathname) + strlen (root_filename));
!                   sprintf
!                     (split_filename,
!                      "%s%s-%d", root_pathname, root_filename, which_file);
  
                    fd = open
                      (split_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
--- 5399,5435 ----
                write_region:
                  {
                    int fd;
!                   char *split_filename, *split_basename;
! 		  size_t root_len = strlen (root_filename);
  
                    split_filename = (char *) xmalloc
!                     (10 + strlen (root_pathname) + root_len);
! 		  split_basename = (char *) xmalloc (10 + root_len);
! 		  sprintf (split_basename, "%s-%d", root_filename, which_file);
! 		  if (dos_file_names)
! 		    {
! 		      char *dot = strchr (root_filename, '.');
! 		      size_t base_len = strlen (split_basename);
! 
! 		      if (dot)
! 			{
! 			  /* Make foobar.i1, .., foobar.i99, foobar.100, ... */
! 			  dot[1] = 'i';
! 			  memmove (which_file <= 99 ? dot + 2 : dot + 1,
! 				   split_basename + root_len + 1,
! 				   strlen (split_basename + root_len + 1) + 1);
! 			}
! 		      else if (base_len > 8)
! 			{
! 			  /* Make foobar-1, .., fooba-10, .., foob-100, ... */
! 			  size_t numlen = base_len - root_len;
! 
! 			  memmove (split_basename + 8 - numlen,
! 				   split_basename + root_len, numlen + 1);
! 			}
! 		    }
!                   sprintf (split_filename,
!                      "%s%s", root_pathname, split_basename);
  
                    fd = open
                      (split_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
*************** split_file (filename, size)
*** 5396,5404 ****
                        indirect_info += strlen (indirect_info);
                      }
  
!                   sprintf (indirect_info, "%s-%d: %d\n",
!                            root_filename, which_file, file_top);
  
                    free (split_filename);
                    indirect_info += strlen (indirect_info);
                    which_file++;
--- 5453,5462 ----
                        indirect_info += strlen (indirect_info);
                      }
  
!                   sprintf (indirect_info, "%s: %d\n",
!                            split_basename, file_top);
  
+ 		  free (split_basename);
                    free (split_filename);
                    indirect_info += strlen (indirect_info);
                    which_file++;
*************** set_footnote_style (string)
*** 8338,8343 ****
--- 8396,8403 ----
       char *string;
  {
    if ((strcasecmp (string, "separate") == 0) ||
+       /* Huh? MN?? Don't we mean SN, for SeparateNode?
+ 	 And why aren't EN and MN/SN documented anywhere?  */
        (strcasecmp (string, "MN") == 0))
      footnote_style = SeparateNode;
    else if ((strcasecmp (string, "end") == 0) ||
*************** extract_colon_unit (string, index)
*** 9458,9463 ****
--- 9518,9524 ----
       int *index;
  {
    int i, start;
+   int path_sep_char = PATH_SEP[0];
  
    i = *index;
  
*************** extract_colon_unit (string, index)
*** 9469,9480 ****
       `:'.  If I is 0, then the path has a leading colon.  Trailing colons
       are handled OK by the `else' part of the if statement; an empty
       string is returned in that case. */
!   if (i && string[i] == ':')
      i++;
  
    start = i;
  
!   while (string[i] && string[i] != ':') i++;
  
    *index = i;
  
--- 9530,9541 ----
       `:'.  If I is 0, then the path has a leading colon.  Trailing colons
       are handled OK by the `else' part of the if statement; an empty
       string is returned in that case. */
!   if (i && string[i] == path_sep_char)
      i++;
  
    start = i;
  
!   while (string[i] && string[i] != path_sep_char) i++;
  
    *index = i;
  
*************** get_file_info_in_path (filename, path, f
*** 9514,9529 ****
      path = ".";
  
    /* Handle absolute pathnames. "./foo", "/foo", "../foo". */
!   if (*filename == '/' ||
        (*filename == '.' &&
!        (filename[1] == '/' ||
!         (filename[1] == '.' && filename[2] == '/')))
! #ifdef WIN32
!       /* Handle names that look like "d:/foo/bar" */
!       || (isalpha (*filename) && filename [1] == ':' 
!           && (filename [2] == '/' || filename [2] == '\\'))
! #endif
!      )
      {
        if (stat (filename, finfo) == 0)
          return (xstrdup (filename));
--- 9575,9584 ----
      path = ".";
  
    /* Handle absolute pathnames. "./foo", "/foo", "../foo". */
!   if (IS_ABSOLUTE (filename) ||
        (*filename == '.' &&
!        (IS_SLASH (filename[1]) ||
!         (filename[1] == '.' && IS_SLASH (filename[2])))))
      {
        if (stat (filename, finfo) == 0)
          return (xstrdup (filename));
*** util/install-info.c~0	Sun May 10 00:32:58 1998
--- util/install-info.c	Sun May 10 00:33:06 1998
*************** For more information about these matters
*** 652,669 ****
       .info suffix.  */
    {
      unsigned basename_len;
!     char *infile_basename = strrchr (infile, '/');
!     if (infile_basename)
!       infile_basename++;
!     else
!       infile_basename = infile;
      
      basename_len = strlen (infile_basename);
      infile_sans_info
!       = (strlen (infile_basename) > 5
!          && strcmp (infile_basename + basename_len - 5, ".info") == 0)
          ? copy_string (infile_basename, basename_len - 5)
!         : infile_basename;
  
      infilelen_sans_info = strlen (infile_sans_info);
    }
--- 652,674 ----
       .info suffix.  */
    {
      unsigned basename_len;
!     char *infile_basename = infile + strlen (infile);
! 
!     if (HAVE_DRIVE (infile))
!       infile += 2;	/* get past the drive spec X: */
! 
!     while (infile_basename > infile && !IS_SLASH (infile_basename[-1]))
!       infile_basename--;
      
      basename_len = strlen (infile_basename);
      infile_sans_info
!       = (basename_len > 5
!          && FILENAME_CMP (infile_basename + basename_len - 5, ".info") == 0)
          ? copy_string (infile_basename, basename_len - 5)
!         : (basename_len > 4
! 	    && FILENAME_CMP (infile_basename + basename_len - 4, ".inf") == 0)
! 	   ? copy_string (infile_basename, basename_len - 4)
! 	   : infile_basename;
  
      infilelen_sans_info = strlen (infile_sans_info);
    }
*************** For more information about these matters
*** 771,779 ****
                p++;
                if ((dir_lines[i].size
                     > (p - dir_lines[i].start + infilelen_sans_info))
!                   && !strncmp (p, infile_sans_info, infilelen_sans_info)
                    && (p[infilelen_sans_info] == ')'
!                       || !strncmp (p + infilelen_sans_info, ".info)", 6)))
                  {
                    dir_lines[i].delete = 1;
                    something_deleted = 1;
--- 776,785 ----
                p++;
                if ((dir_lines[i].size
                     > (p - dir_lines[i].start + infilelen_sans_info))
!                   && !FILENAME_CMPN (p, infile_sans_info, infilelen_sans_info)
                    && (p[infilelen_sans_info] == ')'
!                       || !FILENAME_CMPN (p + infilelen_sans_info, ".info)", 6)
! 		      || !FILENAME_CMPN (p + infilelen_sans_info, ".inf)", 5)))
                  {
                    dir_lines[i].delete = 1;
                    something_deleted = 1;
*** util/texindex.c~0	Fri Feb 27 23:15:58 1998
--- util/texindex.c	Fri May  1 20:48:22 1998
*************** main (argc, argv)
*** 161,175 ****
       char **argv;
  {
    int i;
  
    tempcount = 0;
    last_deleted_tempcount = 0;
  
!   program_name = strrchr (argv[0], '/');
!   if (program_name != (char *)NULL)
!     program_name++;
!   else
!     program_name = argv[0];
  
  #ifdef HAVE_SETLOCALE
    /* Set locale via LC_ALL.  */
--- 161,186 ----
       char **argv;
  {
    int i;
+   char *pgm_full_name = argv[0];
  
    tempcount = 0;
    last_deleted_tempcount = 0;
  
!   program_name = pgm_full_name + strlen (pgm_full_name);
!   if (HAVE_DRIVE (pgm_full_name))
!     pgm_full_name += 2;
! 
!   while (program_name > pgm_full_name && !IS_SLASH (program_name[-1]))
!     program_name--;
! 
! #if STRIP_DOT_EXE
!   {
!     size_t pgm_len = strlen (program_name);
! 
!     if (FILENAME_CMP (program_name + pgm_len - 4, ".exe") == 0)
!       program_name[pgm_len - 4] = 0;
!   }
! #endif
  
  #ifdef HAVE_SETLOCALE
    /* Set locale via LC_ALL.  */
*************** decode_command (argc, argv)
*** 307,321 ****
    /* Store default values into parameter variables. */
  
    tempdir = getenv ("TMPDIR");
- #ifdef VMS
    if (tempdir == NULL)
!     tempdir = "sys$scratch:";
! #else
    if (tempdir == NULL)
!     tempdir = "/tmp/";
    else
      tempdir = concat (tempdir, "/", "");
- #endif
  
    keep_tempfiles = 0;
  
--- 318,331 ----
    /* Store default values into parameter variables. */
  
    tempdir = getenv ("TMPDIR");
    if (tempdir == NULL)
!     tempdir = getenv ("TEMP");
    if (tempdir == NULL)
!     tempdir = getenv ("TMP");
!   if (tempdir == NULL)
!     tempdir = DEFAULT_TMPDIR;
    else
      tempdir = concat (tempdir, "/", "");
  
    keep_tempfiles = 0;
  
*************** maketempname (count)
*** 388,394 ****
       int count;
  {
    char tempsuffix[10];
!   sprintf (tempsuffix, "%d", count);
    return concat (tempdir, tempbase, tempsuffix);
  }
  
--- 398,406 ----
       int count;
  {
    char tempsuffix[10];
!   /* Use the extension for the numeric suffix, for the sake of 8+3
!      filesystems: it gives 3 more characters before risking a collision.  */
!   sprintf (tempsuffix, ".%d", count);
    return concat (tempdir, tempbase, tempsuffix);
  }
  
*** util/texi2dvi.~0	Sun May 10 00:34:18 1998
--- util/texi2dvi	Sun May 10 00:37:46 1998
***************
*** 73,79 ****
  # Don't use `unset' since old bourne shells don't have this command.
  # Instead, assign them an empty value.
  # Some of these, like TEX and TEXINDEX, may be inherited from the environment.
- backup_extension=.bak # these files get deleted if all goes well.
  batch=
  clean=
  debug=
--- 73,78 ----
***************
*** 84,89 ****
--- 83,96 ----
  texindex="${TEXINDEX-texindex}"
  tex="${TEX-tex}"
  
+ # Systems which define $COMSPEC or $ComSpec use semi-colons
+ # to separate directories in TEXINPUTS.
+ if test -n "$COMSPEC""$ComSpec"; then
+   path_sep = ";"
+ else
+   path_sep = ":"
+ fi
+ 
  # Save this so we can construct a new TEXINPUTS path for each file.
  TEXINPUTS_orig="$TEXINPUTS"
  export TEXINPUTS
***************
*** 164,177 ****
    # Output the macro-expanded file to here.  The vastly abbreviated
    # temporary directory name is so we don't have collisions on 8.3 or
    # 14-character filesystems.
!   tmp_dir=${TMPDIR-/tmp}/txi2d.$$
    filename_tmp=$tmp_dir/$filename_noext.texi
    # Output the file with the user's extra commands to here.
    tmp_dir2=${tmp_dir}.2
    filename_tmp2=$tmp_dir2/$filename_noext.texi
!   mkdir $tmp_dir $tmp_dir2
    # Always remove the temporary directories.
!   trap "rm -rf $tmp_dir $tmp_dir2" 1 2 15
  
    # If directory and file are the same, then it's probably because there's
    # no pathname component.  Set dirname to `.', the current directory.
--- 171,190 ----
    # Output the macro-expanded file to here.  The vastly abbreviated
    # temporary directory name is so we don't have collisions on 8.3 or
    # 14-character filesystems.
!   tmp_dir=${TMPDIR-/tmp}/t2d$$
    filename_tmp=$tmp_dir/$filename_noext.texi
    # Output the file with the user's extra commands to here.
    tmp_dir2=${tmp_dir}.2
    filename_tmp2=$tmp_dir2/$filename_noext.texi
!   # Save the previous index files in a separate directory $tmp_dir.bak,
!   # since 8+3 filesystems don't allow multiple dots in the basename.
!   tmp_dir_bak=${tmp_dir}.bak
!   mkdir $tmp_dir $tmp_dir2 $tmp_dir_bak
    # Always remove the temporary directories.
!   # The funky "cd /" is for systems such as MS-Windows where there
!   # is a separate working directory on each drive which cannot be
!   # removed as long as we don't chdir out of it.
!   trap "cd /; rm -rf $tmp_dir $tmp_dir2 $tmp_dir_bak" 1 2 15
  
    # If directory and file are the same, then it's probably because there's
    # no pathname component.  Set dirname to `.', the current directory.
***************
*** 183,189 ****
    # directory where source file(s) reside in TEXINPUTS before anything
    # else.  `.' goes first to ensure that any old .aux, .cps, etc. files in
    # ${directory} don't get used in preference to fresher files in `.'.
!   TEXINPUTS=".:${directory}:${TEXINPUTS_orig}"
  
    # Expand macro commands in the original source file using Makeinfo;
    #   the macro syntax bfox implemented is impossible to implement in TeX.
--- 196,202 ----
    # directory where source file(s) reside in TEXINPUTS before anything
    # else.  `.' goes first to ensure that any old .aux, .cps, etc. files in
    # ${directory} don't get used in preference to fresher files in `.'.
!   TEXINPUTS=".${path_sep}${directory}${path_sep}${TEXINPUTS_orig}"
  
    # Expand macro commands in the original source file using Makeinfo;
    #   the macro syntax bfox implemented is impossible to implement in TeX.
***************
*** 252,258 ****
      # comparison later.
      $verbose "Backing up current index files: $orig_index_files ..."  
      for index_file_to_save in ${orig_index_files}; do
!       cp "${index_file_to_save}" "${index_file_to_save}${backup_extension}"
      done
  
      # Run texindex on current index files.  If they already exist, and
--- 265,271 ----
      # comparison later.
      $verbose "Backing up current index files: $orig_index_files ..."  
      for index_file_to_save in ${orig_index_files}; do
!       cp "${index_file_to_save}" "${tmp_dir_bak}/${index_file_to_save}"
      done
  
      # Run texindex on current index files.  If they already exist, and
***************
*** 311,317 ****
        for this_file in ${new_index_files}; do
          $verbose "Comparing index file $this_file ..."
          # cmp -s will return nonzero exit status if files differ.
!         cmp -s "${this_file}" "${this_file}${backup_extension}"
          if test $? -ne 0; then
            # We only need to keep comparing until we find *one* that
            # differs, because we'll have to run texindex & tex no
--- 324,330 ----
        for this_file in ${new_index_files}; do
          $verbose "Comparing index file $this_file ..."
          # cmp -s will return nonzero exit status if files differ.
!         cmp -s "${this_file}" "${tmp_dir_bak}/${this_file}"
          if test $? -ne 0; then
            # We only need to keep comparing until we find *one* that
            # differs, because we'll have to run texindex & tex no
***************
*** 319,325 ****
            index_files_changed_p=t
            $verbose "Index file $this_file differed:"
            test $verbose = echo \
!           && diff -c "${this_file}${backup_extension}" "${this_file}"
            break
          fi
        done
--- 332,338 ----
            index_files_changed_p=t
            $verbose "Index file $this_file differed:"
            test $verbose = echo \
!           && diff -c "${tmp_dir_bak}/${this_file}" "${this_file}"
            break
          fi
        done
***************
*** 349,362 ****
    # list.  This is significantly faster than multiple executions of rm.
    file_list=
    for file in ${orig_index_files}; do
!     file_list="${file_list} ${file}${backup_extension}"
    done
    if test -n "${file_list}"; then
      $verbose "Removing $file_list ..."
      rm -f ${file_list}
    fi
-   $verbose "Removing $tmp_dir $tmp_dir.2 ..."
-   rm -rf $tmp_dir $tmp_dir.2
  done
  
  $verbose "$0 done."
--- 362,375 ----
    # list.  This is significantly faster than multiple executions of rm.
    file_list=
    for file in ${orig_index_files}; do
!     file_list="${file_list} ${tmp_dir_bak}/${file}"
    done
    if test -n "${file_list}"; then
      $verbose "Removing $file_list ..."
      rm -f ${file_list}
+     $verbose "Removing $tmp_dir $tmp_dir.2 $tmp_dir.bak ..."
+     rm -rf $tmp_dir $tmp_dir.2 $tmp_dir.bak
    fi
  done
  
  $verbose "$0 done."
*** README.~1	Sun May 10 00:19:20 1998
--- README	Sun May 10 00:20:38 1998
***************
*** 44,49 ****
--- 44,51 ----
  #define DEFAULT_INFOPATH "/mydir1:/mydir2:/etc"
        to config.h after running configure.
  
+ For instructions on compiling this distribution with DJGPP tools for MS-DOS
+ and MS-Windows, please see the file `README' in the djgpp subdirectory.
  
  This distribution includes the following files, among others:
  
1998-05-23  Eli Zaretskii  <eliz@is.elta.co.il>

	* info/indices.c (info_next_index_match): Call
	info_set_node_of_window to display the node, so that footnotes are
	displayed as well.

	* makeinfo/makeinfo.c (split_file): Fix bug in generating *.iNN
	file names.

*** info/indices.c~1	Sat May  9 09:51:22 1998
--- info/indices.c	Sat May 23 13:54:12 1998
*************** DECLARE_INFO_COMMAND (info_next_index_ma
*** 445,453 ****
      }
  
    set_remembered_pagetop_and_point (window);
!   window_set_node_of_window (window, node);
!   remember_window_and_node (window, node);
! 
  
    /* Try to find an occurence of LABEL in this node. */
    {
--- 445,451 ----
      }
  
    set_remembered_pagetop_and_point (window);
!   info_set_node_of_window (window, node);
  
    /* Try to find an occurence of LABEL in this node. */
    {
*** makeinfo/makeinfo.c~1	Sun May 10 00:32:12 1998
--- makeinfo/makeinfo.c	Sat May 23 13:13:02 1998
*************** split_file (filename, size)
*** 5408,5414 ****
  		  sprintf (split_basename, "%s-%d", root_filename, which_file);
  		  if (dos_file_names)
  		    {
! 		      char *dot = strchr (root_filename, '.');
  		      size_t base_len = strlen (split_basename);
  
  		      if (dot)
--- 5408,5414 ----
  		  sprintf (split_basename, "%s-%d", root_filename, which_file);
  		  if (dos_file_names)
  		    {
! 		      char *dot = strchr (split_basename, '.');
  		      size_t base_len = strlen (split_basename);
  
  		      if (dot)
