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

	* gzip.c (name_too_long): Replace the last character of the file
	name instead of truncating it, to avoid false alarms on Windows
	filesystems.
	(get_istat) [MAX_EXT_CHARS]: Append a dot only if z_suffix doesn't
	already begin with a dot.
	(get_suffix) [MAX_EXT_CHARS]: Remove the DOSish suffixes without a
	leading dot from known_suffixes[] and put them into a separate
	array known_dosish_suffixes[].  Don't check these suffixes when
	compressing if long file names aren't supported, or if the
	basename of the file doesn't have a dot.

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

	* tailor.h: [MSDOS, __GNUC__]: Define macros for DJGPP v2.x, so
	that long file names could be supported on Windows 9X.
	(LONG_FILE_NAMES, HAVE_LONG_FILE_NAMES): New macros.
	(MAX_SUFFIX): Define only if not defined above.

	* gzip.h: Include time.h or sys/time.h, to make sure we get
	definition of time_t.

	* gzip.c (PART_SEP): Define only if not defined already.
	(main): Downcase the program name here rather that inside
	basename.
	Switch stdout to binary mode only if it isn't the console, or if
	--force was specified.
	(treat_stdin): Never switch the console device to binary mode if
	the input is coming from the console.
	(get_suffix) [MAX_EXT_CHARS]: Add "gz" to the list of known
	suffixes.
	(get_istat, make_ofname) [NO_MULTIPLE_DOTS]: Support systems where
	long file name support is only known at run time.
	(shorten_name): Make sure we only shorten the basename of the file
	by working on what gbasename returns.

	* msdos/tailor.c (make_valid_dosw32_name): New function, to be
	called via MAKE_LEGAL_NAME macro.  Replaces all characers not
	allowed by DOS/Windows filesystems, and renames files whose names
	are reserved by character device drivers.

	* util.c (gbasename): Renamed from basename, since some systems
	declate basename on unistd.h with incompatible proptotype; all
	callers changed.  Don't downcase the base name; it is now done by
	those callers which need it.

	* zdiff.in (tmpdir): New variable, replaces the hard-wired "/tmp";
	defaults to "." if neither $TMPDIR nor "/tmp" is usable.

	* znew.in (tmpdir): New variable, replaces the hard-wired "/tmp";
	defaults to "." if neither $TMPDIR nor "/tmp" is usable.

	* gzip.tex: Use @file and @email instead of @samp where
	appropriate.

	* gzexe (tmpdir): Set the value dynamically; use $TMPDIR if
	defined, and default to "." as the last resort.
	(pathsep): New variable: directory separator in $PATH.
	(exe): New variable: the extension of executable files on target
	system.
	(cpmod): Use shorter temporary file names, so that they won't
	clash in 8+3 DOS namespace.
	(decompress): Don't use hardwired /bin/foo path names for
	programs.

	* msdos/Makefile.dj2, msdos/README.djgpp: New files.

*** gzexe.i~0	Thu Jun 24 13:25:04 1993
--- gzexe.in	Tue Sep 22 12:28:22 1998
***************
*** 21,26 ****
--- 21,38 ----
    exit 1
  fi
  
+ tmpdir=${TMPDIR-/tmp}
+ if test ! -d "${tmpdir}"; then
+ 	tmpdir=.
+ fi
+ 
+ pathsep=:
+ exe=
+ if test -n "${COMSPEC}"; then
+ 	pathsep=";"
+ 	exe=.exe
+ fi
+ 
  tmp=gz$$
  trap "rm -f $tmp; exit 1" 1 2 3 5 10 13 15
  
***************
*** 32,50 ****
    shift
  fi
  
! echo hi > zfoo1$$
! echo hi > zfoo2$$
! if test -z "`(${CPMOD-cpmod} zfoo1$$ zfoo2$$) 2>&1`"; then
    cpmod=${CPMOD-cpmod}
  fi
! rm -f zfoo[12]$$
  
  tail=""
! IFS="${IFS= 	}"; saveifs="$IFS"; IFS="${IFS}:"
  for dir in $PATH; do
    test -z "$dir" && dir=.
!   if test -f $dir/tail; then
!     tail="$dir/tail"
      break
    fi
  done
--- 44,62 ----
    shift
  fi
  
! echo hi > zf$$.1
! echo hi > zf$$.2
! if test -z "`(${CPMOD-cpmod} zf$$.1 zf$$.2) 2>&1`"; then
    cpmod=${CPMOD-cpmod}
  fi
! rm -f zf$$.[12]
  
  tail=""
! IFS="${IFS= 	}"; saveifs="$IFS"; IFS="${IFS}${pathsep}"
  for dir in $PATH; do
    test -z "$dir" && dir=.
!   if test -f $dir/tail"${exe}"; then
!     tail="$dir/tail${exe}"
      break
    fi
  done
***************
*** 91,114 ****
      sed 1q $0 > $tmp
      sed "s|^if tail|if $tail|" >> $tmp <<'EOF'
  skip=18
! if tail +$skip $0 | "BINDIR"/gzip -cd > /tmp/gztmp$$; then
!   /bin/chmod 700 /tmp/gztmp$$
!   prog="`echo $0 | /bin/sed 's|^.*/||'`"
!   if /bin/ln /tmp/gztmp$$ "/tmp/$prog" 2>/dev/null; then
!     trap '/bin/rm -f /tmp/gztmp$$ "/tmp/$prog"; exit $res' 0
!     (/bin/sleep 5; /bin/rm -f /tmp/gztmp$$ "/tmp/$prog") 2>/dev/null &
!     /tmp/"$prog" ${1+"$@"}; res=$?
    else
!     trap '/bin/rm -f /tmp/gztmp$$; exit $res' 0
!     (/bin/sleep 5; /bin/rm -f /tmp/gztmp$$) 2>/dev/null &
!     /tmp/gztmp$$ ${1+"$@"}; res=$?
    fi
  else
    echo Cannot decompress $0; exit 1
  fi; exit $res
  EOF
      "BINDIR"/gzip -cv9 "$i" >> $tmp || {
!       /bin/rm -f $tmp
        echo ${x}: compression not possible for $i, file unchanged.
        res=1
        continue
--- 103,126 ----
      sed 1q $0 > $tmp
      sed "s|^if tail|if $tail|" >> $tmp <<'EOF'
  skip=18
! if tail +$skip $0 | "BINDIR"/gzip -cd > "${tmpdir}"/gt$$; then
!   chmod 700 "${tmpdir}"/gt$$
!   prog="`echo $0 | sed 's|^.*/||'`"
!   if ln "${tmpdir}"/gt$$ "${tmpdir}/$prog" 2>/dev/null; then
!     trap 'rm -f "${tmpdir}"/gt$$ "${tmpdir}/$prog"; exit $res' 0
!     (sleep 5; rm -f "${tmpdir}"/gt$$ "${tmpdir}/$prog") 2>/dev/null &
!     "${tmpdir}/$prog" ${1+"$@"}; res=$?
    else
!     trap 'rm -f "${tmpdir}"/gt$$; exit $res' 0
!     (sleep 5; rm -f "${tmpdir}"/gt$$) 2>/dev/null &
!     "${tmpdir}"/gt$$ ${1+"$@"}; res=$?
    fi
  else
    echo Cannot decompress $0; exit 1
  fi; exit $res
  EOF
      "BINDIR"/gzip -cv9 "$i" >> $tmp || {
!       rm -f $tmp
        echo ${x}: compression not possible for $i, file unchanged.
        res=1
        continue
***************
*** 128,136 ****
        continue
      fi
    fi
!   rm -f "$i~"
!   mv "$i" "$i~" || {
!     echo ${x}: cannot backup $i as $i~
      rm -f $tmp
      res=1
      continue
--- 140,148 ----
        continue
      fi
    fi
!   rm -f "$i.~"
!   mv "$i" "$i.~" || {
!     echo ${x}: cannot backup $i as $i.~
      rm -f $tmp
      res=1
      continue
***************
*** 143,149 ****
    }
    rm -f $tmp
    if test -n "$cpmod"; then
!     $cpmod "$i~" "$i" 2>/dev/null
    elif test $writable -eq 0; then
      chmod u-w $i 2>/dev/null
    fi
--- 155,161 ----
    }
    rm -f $tmp
    if test -n "$cpmod"; then
!     $cpmod "$i.~" "$i" 2>/dev/null
    elif test $writable -eq 0; then
      chmod u-w $i 2>/dev/null
    fi
*** gzip.c~0	Thu Sep 17 02:39:56 1998
--- gzip.c	Sat Sep 26 19:05:04 1998
*************** typedef RETSIGTYPE (*sig_type) OF((int))
*** 194,200 ****
  #ifdef NO_MULTIPLE_DOTS
  #  define PART_SEP "-"
  #else
! #  define PART_SEP "."
  #endif
  
  		/* global buffers */
--- 194,202 ----
  #ifdef NO_MULTIPLE_DOTS
  #  define PART_SEP "-"
  #else
! #  ifndef PART_SEP
! #    define PART_SEP "."
! #  endif
  #endif
  
  		/* global buffers */
*************** int main (argc, argv)
*** 445,451 ****
  
      EXPAND(argc, argv); /* wild card expansion if necessary */
  
!     progname = basename(argv[0]);
      proglen = strlen(progname);
  
      /* Suppress .exe for MSDOS, OS/2 and VMS: */
--- 447,454 ----
  
      EXPAND(argc, argv); /* wild card expansion if necessary */
  
!     progname = gbasename(argv[0]);
!     if (casemap('A') == 'a') strlwr(progname);
      proglen = strlen(progname);
  
      /* Suppress .exe for MSDOS, OS/2 and VMS: */
*************** int main (argc, argv)
*** 601,607 ****
      /* And get to work */
      if (file_count != 0) {
  	if (to_stdout && !test && !list && (!decompress || !ascii)) {
! 	    SET_BINARY_MODE(fileno(stdout));
  	}
          while (optind < argc) {
  	    treat_file(argv[optind++]);
--- 604,613 ----
      /* And get to work */
      if (file_count != 0) {
  	if (to_stdout && !test && !list && (!decompress || !ascii)) {
! 	    /* Switching console device to binary mode has nasty
! 	       side-effects on some systems, and is mostly unnecessary.  */
! 	    if (force || !isatty(fileno(stdout)))
! 		SET_BINARY_MODE(fileno(stdout));
  	}
          while (optind < argc) {
  	    treat_file(argv[optind++]);
*************** local void treat_stdin()
*** 644,653 ****
      }
  
      if (decompress || !ascii) {
! 	SET_BINARY_MODE(fileno(stdin));
      }
      if (!test && !list && (!decompress || !ascii)) {
! 	SET_BINARY_MODE(fileno(stdout));
      }
      strcpy(ifname, "stdin");
      strcpy(ofname, "stdout");
--- 650,671 ----
      }
  
      if (decompress || !ascii) {
!         /* Do not ever switch console input into binary mode, even if
! 	   they've said --force.  Doing so will attempt to read from
! 	   the console with no echo and no way to signal EOF or even
! 	   interrupt the program (since special characters like ^Z and ^C
! 	   are not special in binary mode).  For all practical purposes,
! 	   a program which does that, wedges the machine.  */
!         if (!isatty(fileno(stdin)))
! 	    SET_BINARY_MODE(fileno(stdin));
      }
      if (!test && !list && (!decompress || !ascii)) {
!         /* If both stdin and stdout are the console device, don't switch
! 	   stdout into binary mode either, since that will switch the
! 	   console device into raw mode, with the same sad consequences
! 	   as described above.  */
!         if (!isatty(fileno(stdout)) || (force && !isatty(fileno(stdin))))
! 	    SET_BINARY_MODE(fileno(stdout));
      }
      strcpy(ifname, "stdin");
      strcpy(ofname, "stdout");
*************** local char *get_suffix(name)
*** 975,981 ****
      static char *known_suffixes[] =
         {z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
  #ifdef MAX_EXT_CHARS
!           "z",
  #endif
            NULL};
      char **suf = known_suffixes;
--- 996,1002 ----
      static char *known_suffixes[] =
         {z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
  #ifdef MAX_EXT_CHARS
!           "gz", "z",
  #endif
            NULL};
      char **suf = known_suffixes;
*************** local char *get_suffix(name)
*** 1013,1019 ****
   * Set ifname to the input file name (with a suffix appended if necessary)
   * and istat to its stats. For decompression, if no file exists with the
   * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
!  * For MSDOS, we try only z_suffix and z.
   * Return OK or ERROR.
   */
  local int get_istat(iname, sbuf)
--- 1034,1045 ----
   * Set ifname to the input file name (with a suffix appended if necessary)
   * and istat to its stats. For decompression, if no file exists with the
   * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
!  * For systems that disallow multiple dots, remove the dot from each
!  * suffix we try if ifname already has a dot in its basename.
!  * DJGPP supports long file names when they are available (Windows 9X), so
!  * we try both the normal concatenation, like .tar.gz, and the DOS-ish
!  * butchered .tgz etc.; this will make happy those people who move DOS
!  * files to Windows filesystems or set up dual-boot DOS/Windows systems.
   * Return OK or ERROR.
   */
  local int get_istat(iname, sbuf)
*************** local int get_istat(iname, sbuf)
*** 1024,1031 ****
      static char *suffixes[] = {z_suffix, ".gz", ".z", "-z", ".Z", NULL};
      char **suf = suffixes;
      char *s;
! #ifdef NO_MULTIPLE_DOTS
!     char *dot; /* pointer to ifname extension, or NULL */
  #endif
  
      strcpy(ifname, iname);
--- 1050,1057 ----
      static char *suffixes[] = {z_suffix, ".gz", ".z", "-z", ".Z", NULL};
      char **suf = suffixes;
      char *s;
! #if defined(MAX_EXT_CHARS) || defined(NO_MULTIPLE_DOTS)
!     char *dot = NULL; /* pointer to ifname extension, or NULL */
  #endif
  
      strcpy(ifname, iname);
*************** local int get_istat(iname, sbuf)
*** 1047,1078 ****
  	exit_code = ERROR;
  	return ERROR;
      }
! #ifdef NO_MULTIPLE_DOTS
!     dot = strrchr(ifname, '.');
      if (dot == NULL) {
          strcat(ifname, ".");
!         dot = strrchr(ifname, '.');
      }
  #endif
-     ilen = strlen(ifname);
      if (strequ(z_suffix, ".gz")) suf++;
  
      /* Search for all suffixes */
      do {
          s = *suf;
  #ifdef NO_MULTIPLE_DOTS
!         if (*s == '.') s++;
  #endif
  #ifdef MAX_EXT_CHARS
!         strcpy(ifname, iname);
!         /* Needed if the suffixes are not sorted by increasing length */
! 
          if (*dot == '\0') strcpy(dot, ".");
          dot[MAX_EXT_CHARS+1-strlen(s)] = '\0';
! #endif
!         strcat(ifname, s);
          if (do_stat(ifname, sbuf) == 0) return OK;
! 	ifname[ilen] = '\0';
      } while (*++suf != NULL);
  
      /* No suffix found, complain using z_suffix: */
--- 1073,1112 ----
  	exit_code = ERROR;
  	return ERROR;
      }
!     ilen = strlen(ifname);
! #if defined(MAX_EXT_CHARS) || defined(NO_MULTIPLE_DOTS)
!     dot = strrchr(gbasename(ifname), '.');
      if (dot == NULL) {
+         dot = ifname + ilen;
+ #ifdef NO_MULTIPLE_DOTS
          strcat(ifname, ".");
! #endif
      }
  #endif
      if (strequ(z_suffix, ".gz")) suf++;
  
      /* Search for all suffixes */
      do {
          s = *suf;
  #ifdef NO_MULTIPLE_DOTS
!         if (*s == '.' && *dot == '.') s++;
! #endif
! #ifdef LONG_FILE_NAMES
! 	strcat(ifname, s);
! 	if (do_stat(ifname, sbuf) == 0) return OK;
! 	ifname[ilen] = '\0';
  #endif
  #ifdef MAX_EXT_CHARS
! #ifndef NO_MULTIPLE_DOTS
! 	if (*dot == '\0') continue; /* already tried under LONG_FILE_NAMES */
! #endif
          if (*dot == '\0') strcpy(dot, ".");
+         if (*s == '.') s++;
          dot[MAX_EXT_CHARS+1-strlen(s)] = '\0';
! 	strcat(ifname, s);
          if (do_stat(ifname, sbuf) == 0) return OK;
! 	strcpy(ifname, iname);
! #endif
      } while (*++suf != NULL);
  
      /* No suffix found, complain using z_suffix: */
*************** local int make_ofname()
*** 1101,1107 ****
  
      if (decompress) {
  	if (suff == NULL) {
! 	    /* Whith -t or -l, try all files (even without .gz suffix)
  	     * except with -r (behave as with just -dr).
               */
              if (!recursive && (list || test)) return OK;
--- 1135,1141 ----
  
      if (decompress) {
  	if (suff == NULL) {
! 	    /* With -t or -l, try all files (even without .gz suffix)
  	     * except with -r (behave as with just -dr).
               */
              if (!recursive && (list || test)) return OK;
*************** local int make_ofname()
*** 1131,1158 ****
  	if (exit_code == OK) exit_code = WARNING;
  	return WARNING;
      } else {
          save_orig_name = 0;
  
! #ifdef NO_MULTIPLE_DOTS
! 	suff = strrchr(ofname, '.');
! 	if (suff == NULL) {
              strcat(ofname, ".");
  #  ifdef MAX_EXT_CHARS
! 	    if (strequ(z_suffix, "z")) {
! 		strcat(ofname, "gz"); /* enough room */
! 		return OK;
! 	    }
          /* On the Atari and some versions of MSDOS, name_too_long()
           * does not work correctly because of a bug in stat(). So we
           * must truncate here.
           */
!         } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
!             suff[MAX_SUFFIX+1-z_len] = '\0';
              save_orig_name = 1;
  #  endif
          }
  #endif /* NO_MULTIPLE_DOTS */
! 	strcat(ofname, z_suffix);
  
      } /* decompress ? */
      return OK;
--- 1165,1209 ----
  	if (exit_code == OK) exit_code = WARNING;
  	return WARNING;
      } else {
+         char *pzs = z_suffix;
+         int zslen = z_len;
+ 
          save_orig_name = 0;
  
! #if defined(NO_MULTIPLE_DOTS) || defined(MAX_EXT_CHARS)
! #  ifdef HAVE_LONG_NAMES
!         /* This is for systems where the availability of the long file name
!            support is only known at run time, and depends on the filesystem
!            where the target file OFNAME will be written.  DJGPP running on
!            Windows 9X is an example of such a system.  */
!         if (HAVE_LONG_NAMES(ofname)) {
!             strcat(ofname, pzs);
!             return OK;
!         }
! #  endif
!         if (*pzs == '.') {
!             pzs++;
!             zslen--;
!         }
!         suff = strrchr(gbasename(ofname), '.');
!         if (suff == NULL) {
              strcat(ofname, ".");
  #  ifdef MAX_EXT_CHARS
!             if (strequ(pzs, "z")) {
!                 strcat(ofname, "gz"); /* enough room */
!                 return OK;
!             }
          /* On the Atari and some versions of MSDOS, name_too_long()
           * does not work correctly because of a bug in stat(). So we
           * must truncate here.
           */
!         } else if (strlen(suff)-1 + zslen > MAX_EXT_CHARS) {
!             suff[MAX_EXT_CHARS+1-zslen] = '\0';
              save_orig_name = 1;
  #  endif
          }
  #endif /* NO_MULTIPLE_DOTS */
! 	strcat(ofname, pzs);
  
      } /* decompress ? */
      return OK;
*************** local int get_method(in)
*** 1264,1270 ****
  		do {c=get_byte();} while (c != 0);
  	    } else {
  		/* Copy the base name. Keep a directory prefix intact. */
!                 char *p = basename(ofname);
                  char *base = p;
  		for (;;) {
  		    *p = (char)get_char();
--- 1315,1321 ----
  		do {c=get_byte();} while (c != 0);
  	    } else {
  		/* Copy the base name. Keep a directory prefix intact. */
!                 char *p = gbasename(ofname);
                  char *base = p;
  		for (;;) {
  		    *p = (char)get_char();
*************** local void shorten_name(name)
*** 1517,1524 ****
       * 1234.678.012.gz -> 123.678.012.gz
       */
      do {
! 	p = strrchr(name, PATH_SEP);
! 	p = p ? p+1 : name;
  	while (*p) {
  	    plen = strcspn(p, PART_SEP);
  	    p += plen;
--- 1568,1574 ----
       * 1234.678.012.gz -> 123.678.012.gz
       */
      do {
! 	p = gbasename(name);
  	while (*p) {
  	    plen = strcspn(p, PART_SEP);
  	    p += plen;
*************** local void shorten_name(name)
*** 1533,1539 ****
  	} while (*trunc++);
  	trunc--;
      } else {
! 	trunc = strrchr(name, PART_SEP[0]);
  	if (trunc == NULL) error("internal error in shorten_name");
  	if (trunc[1] == '\0') trunc--; /* force truncation */
      }
--- 1583,1589 ----
  	} while (*trunc++);
  	trunc--;
      } else {
! 	trunc = strrchr(gbasename(name), PART_SEP[0]);
  	if (trunc == NULL) error("internal error in shorten_name");
  	if (trunc[1] == '\0') trunc--; /* force truncation */
      }
*** gzip.h~0	Thu Sep 17 02:39:56 1998
--- gzip.h	Sat Sep 26 13:47:30 1998
***************
*** 20,26 ****
   * too often
   */
  #include <stdio.h>
! #include <sys/types.h> /* for off_t, time_t */
  #if !defined(NO_STRING_H) || defined(STDC_HEADERS)
  #  include <string.h>
  #  if !defined(STDC_HEADERS) && !defined(NO_MEMORY_H) && !defined(__GNUC__)
--- 20,31 ----
   * too often
   */
  #include <stdio.h>
! #include <sys/types.h>  /* for off_t, time_t */
! #ifdef NO_TIME_H
! #  include <sys/time.h>	/* some systems only have time_t here */
! #else
! #  include <time.h>	/* some systems only have time_t here */
! #endif
  #if !defined(NO_STRING_H) || defined(STDC_HEADERS)
  #  include <string.h>
  #  if !defined(STDC_HEADERS) && !defined(NO_MEMORY_H) && !defined(__GNUC__)
***************
*** 299,305 ****
  extern void flush_window  OF((void));
  extern void write_buf     OF((int fd, voidp buf, unsigned cnt));
  extern char *strlwr       OF((char *s));
! extern char *basename     OF((char *fname));
  extern int xunlink        OF((char *fname));
  extern void make_simple_name OF((char *name));
  extern char *add_envopt   OF((int *argcp, char ***argvp, char *env));
--- 304,310 ----
  extern void flush_window  OF((void));
  extern void write_buf     OF((int fd, voidp buf, unsigned cnt));
  extern char *strlwr       OF((char *s));
! extern char *gbasename    OF((char *fname));
  extern int xunlink        OF((char *fname));
  extern void make_simple_name OF((char *name));
  extern char *add_envopt   OF((int *argcp, char ***argvp, char *env));
*** gzip.t~0	Wed Aug 18 23:42:50 1993
--- gzip.texi	Sat Sep 26 13:27:02 1998
***************
*** 86,94 ****
  
  @code{gzip} reduces the size of the named files using Lempel-Ziv coding
  (LZ77).  Whenever possible, each file is replaced by one with the
! extension @samp{.gz}, while keeping the same ownership modes, access and
! modification times.  (The default extension is @samp{-gz} for VMS,
! @samp{z} for MSDOS, OS/2 FAT and Atari.)  If no files are specified or
  if a file name is "-", the standard input is compressed to the standard
  output. @code{gzip} will only attempt to compress regular files.  In
  particular, it will ignore symbolic links.
--- 86,94 ----
  
  @code{gzip} reduces the size of the named files using Lempel-Ziv coding
  (LZ77).  Whenever possible, each file is replaced by one with the
! extension @file{.gz}, while keeping the same ownership modes, access and
! modification times.  (The default extension is @file{-gz} for VMS,
! @file{z} for MSDOS, OS/2 FAT and Atari.)  If no files are specified or
  if a file name is "-", the standard input is compressed to the standard
  output. @code{gzip} will only attempt to compress regular files.  In
  particular, it will ignore symbolic links.
***************
*** 97,105 ****
  truncates it.  @code{gzip} attempts to truncate only the parts of the
  file name longer than 3 characters.  (A part is delimited by dots.) If
  the name consists of small parts only, the longest parts are truncated.
! For example, if file names are limited to 14 characters, gzip.msdos.exe
! is compressed to gzi.msd.exe.gz.  Names are not truncated on systems
! which do not have a limit on file name length.
  
  By default, @code{gzip} keeps the original file name and timestamp in
  the compressed file. These are used when decompressing the file with the
--- 97,105 ----
  truncates it.  @code{gzip} attempts to truncate only the parts of the
  file name longer than 3 characters.  (A part is delimited by dots.) If
  the name consists of small parts only, the longest parts are truncated.
! For example, if file names are limited to 14 characters,
! @file{gzip.msdos.exe} is compressed to @file{gzi.msd.exe.gz}.  Names are
! not truncated on systems which do not have a limit on file name length.
  
  By default, @code{gzip} keeps the original file name and timestamp in
  the compressed file. These are used when decompressing the file with the
***************
*** 113,125 ****
  constructed from the original one to make it legal.
  
  @code{gunzip} takes a list of files on its command line and replaces
! each file whose name ends with @samp{.gz}, @samp{.z}, @samp{.Z},
! @samp{-gz}, @samp{-z} or @samp{_z} and which begins with the correct
  magic number with an uncompressed file without the original extension.
! @code{gunzip} also recognizes the special extensions @samp{.tgz} and
! @samp{.taz} as shorthands for @samp{.tar.gz} and @samp{.tar.Z}
! respectively. When compressing, @code{gzip} uses the @samp{.tgz}
! extension if necessary instead of truncating a file with a @samp{.tar}
  extension.
  
  @code{gunzip} can currently decompress files created by @code{gzip},
--- 113,125 ----
  constructed from the original one to make it legal.
  
  @code{gunzip} takes a list of files on its command line and replaces
! each file whose name ends with @file{.gz}, @file{.z}, @file{.Z},
! @file{-gz}, @file{-z} or @file{_z} and which begins with the correct
  magic number with an uncompressed file without the original extension.
! @code{gunzip} also recognizes the special extensions @file{.tgz} and
! @file{.taz} as shorthands for @file{.tar.gz} and @file{.tar.Z}
! respectively. When compressing, @code{gzip} uses the @file{.tgz}
! extension if necessary instead of truncating a file with a @file{.tar}
  extension.
  
  @code{gunzip} can currently decompress files created by @code{gzip},
***************
*** 128,135 ****
  checks a 32 bit CRC (cyclic redundancy check). For @code{pack},
  @code{gunzip} checks the uncompressed length. The @code{compress} format
  was not designed to allow consistency checks. However @code{gunzip} is
! sometimes able to detect a bad @samp{.Z} file. If you get an error when
! uncompressing a @samp{.Z} file, do not assume that the @samp{.Z} file is
  correct simply because the standard @code{uncompress} does not complain.
  This generally means that the standard @code{uncompress} does not check
  its input, and happily generates garbage output.  The SCO @samp{compress
--- 128,135 ----
  checks a 32 bit CRC (cyclic redundancy check). For @code{pack},
  @code{gunzip} checks the uncompressed length. The @code{compress} format
  was not designed to allow consistency checks. However @code{gunzip} is
! sometimes able to detect a bad @file{.Z} file. If you get an error when
! uncompressing a @file{.Z} file, do not assume that the @file{.Z} file is
  correct simply because the standard @code{uncompress} does not complain.
  This generally means that the standard @code{uncompress} does not check
  its input, and happily generates garbage output.  The SCO @samp{compress
***************
*** 146,152 ****
  uncompresses either a list of files on the command line or its standard
  input and writes the uncompressed data on standard output.  @code{zcat}
  will uncompress files that have the correct magic number whether they
! have a @samp{.gz} suffix or not.
  
  @code{gzip} uses the Lempel-Ziv algorithm used in @code{zip} and PKZIP.
  The amount of compression obtained depends on the size of the input and
--- 146,152 ----
  uncompresses either a list of files on the command line or its standard
  input and writes the uncompressed data on standard output.  @code{zcat}
  will uncompress files that have the correct magic number whether they
! have a @file{.gz} suffix or not.
  
  @code{gzip} uses the Lempel-Ziv algorithm used in @code{zip} and PKZIP.
  The amount of compression obtained depends on the size of the input and
***************
*** 261,267 ****
  @end example
  
  The uncompressed size is given as @samp{-1} for files not in @code{gzip}
! format, such as compressed @samp{.Z} files. To get the uncompressed size for
  such a file, you can use:
  
  @example
--- 261,267 ----
  @end example
  
  The uncompressed size is given as @samp{-1} for files not in @code{gzip}
! format, such as compressed @file{.Z} files. To get the uncompressed size for
  such a file, you can use:
  
  @example
***************
*** 318,325 ****
  
  @item --suffix @var{suf}
  @itemx -S @var{suf}
! Use suffix @samp{@var{suf}} instead of @samp{.gz}. Any suffix can be
! given, but suffixes other than @samp{.z} and @samp{.gz} should be
  avoided to avoid confusion when files are transferred to other systems.
  A null suffix forces gunzip to try decompression on all given files
  regardless of suffix, as in:
--- 318,325 ----
  
  @item --suffix @var{suf}
  @itemx -S @var{suf}
! Use suffix @file{@var{suf}} instead of @file{.gz}. Any suffix can be
! given, but suffixes other than @file{.z} and @file{.gz} should be
  avoided to avoid confusion when files are transferred to other systems.
  A null suffix forces gunzip to try decompression on all given files
  regardless of suffix, as in:
***************
*** 328,334 ****
  gunzip -S "" *        (*.* for MSDOS)
  @end example
  
! Previous versions of gzip used the @samp{.z} suffix. This was changed to
  avoid a conflict with @code{pack}.
  
  @item --test
--- 328,334 ----
  gunzip -S "" *        (*.* for MSDOS)
  @end example
  
! Previous versions of gzip used the @file{.z} suffix. This was changed to
  avoid a conflict with @code{pack}.
  
  @item --test
***************
*** 383,389 ****
  cat file1 file2
  @end example
  
! In case of damage to one member of a @samp{.gz} file, other members can
  still be recovered (if the damaged member is removed). However,
  you can get better compression by compressing all members at once:
  
--- 383,389 ----
  cat file1 file2
  @end example
  
! In case of damage to one member of a @file{.gz} file, other members can
  still be recovered (if the damaged member is removed). However,
  you can get better compression by compressing all members at once:
  
***************
*** 462,469 ****
  @cindex bugs
  
  If you find a bug in @code{gzip}, please send electronic mail to
! @w{@samp{jloup@@chorus.fr}} or, if this fails, to
! @w{@samp{bug-gnu-utils@@prep.ai.mit.edu}}.  Include the version number,
  which you can find by running @w{@samp{gzip -V}}.  Also include in your
  message the hardware and operating system, the compiler used to compile
  @code{gzip},
--- 462,469 ----
  @cindex bugs
  
  If you find a bug in @code{gzip}, please send electronic mail to
! @email{jloup@@chorus.fr, Jean-loup Gailly} or, if this fails, to
! @w{@email{bug-gnu-utils@@gnu.org}}.  Include the version number,
  which you can find by running @w{@samp{gzip -V}}.  Also include in your
  message the hardware and operating system, the compiler used to compile
  @code{gzip},
*** msdos/tailor.c~0	Thu Jul  8 01:54:50 1993
--- msdos/tailor.c	Sat Sep 26 12:10:38 1998
*************** void fcfree(ptr)
*** 56,58 ****
--- 56,112 ----
   }
  
  #endif /* __TURBOC__ */
+ 
+ #ifdef __DJGPP__
+ 
+ #include <string.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ 
+ /* ============================================================
+  * Make a file name valid for file systems supported by DJGPP.
+  * This includes replacing characters that aren't allowed in
+  * file names, and renaming files whose names are reserved by
+  * character device drivers.  Characters that aren't allowed
+  * depend on the filesystem where the file resides.
+  */
+ void make_valid_dosw32_name(name)
+     char *name;
+ {
+     /* The following characters aren't allowed in DOS file names.
+        Some of them aren't allowed by Windows 9X; these begin at
+        offset 7 (zero-based) in the string below.  */
+     static char disallowed_chars[] = "+, ;=[]|<>\\\":?*";
+     static char replacement_char[] = "x'_`_{}!()%'-^#";
+     int long_names = HAVE_LONG_NAMES(ofname);
+     struct stat st;
+     register char *p = name;
+ 
+     /* If the filesystem disallows multiple dots, remove
+        all but the last one.  */
+     if (!long_names)
+         make_simple_name(name);
+ 
+     /* If there are any more invalid characters, replace them.  */
+     for ( ; *p != '\0'; p++) {
+         register int i;
+ 
+         for (i = long_names ? 7 : 0; i < sizeof(disallowed_chars); i++) {
+ 	    if (*p == disallowed_chars[i]) {
+ 	        *p = replacement_char[i];
+ 		break;
+ 	    }
+ 	}
+     }
+ 
+     /* The list of character devices is not constant: it depends on
+        what device drivers did they install in their CONFIG.SYS.
+        `stat' will tell us if the file name is a character device.  */
+     if (stat(name, &st) == 0 && S_ISCHR(st.st_mode)) {
+         /* If it's a reserved name, prepend a '_' to it.  */
+         memmove(name + 1, name, strlen(name) + 1);
+ 	name[0] = '_';
+     }
+ }
+ 
+ #endif /* __DJGPP__ */
*** tailor.h~0	Thu Sep 17 02:39:56 1998
--- tailor.h	Sat Sep 26 15:21:46 1998
***************
*** 27,40 ****
       /* DJGPP version 1.09+ on MS-DOS.
        * The DJGPP 1.09 stat() function must be upgraded before gzip will
        * fully work.
-       * No need for DIRENT, since <unistd.h> defines POSIX_SOURCE which
-       * implies DIRENT.
        */
  #    define near
  #  else
  #    define MAXSEG_64K
  #    ifdef __TURBOC__
  #      define off_t long
  #      ifdef __BORLANDC__
  #        define DIRENT
  #      else
--- 27,73 ----
       /* DJGPP version 1.09+ on MS-DOS.
        * The DJGPP 1.09 stat() function must be upgraded before gzip will
        * fully work.
        */
  #    define near
+ #    define DIRENT
+ #    define HAVE_LIMITS_H
+ #    define HAVE_UNISTD_H
+ #    define fcalloc(items,size) malloc((size_t)(items)*(size_t)(size))
+ #    define fcfree(ptr) free(ptr)
+ #    ifdef __DJGPP__
+        /* DJGPP version 2.x or later supports long file names on Windows.  */
+ #      define LONG_FILE_NAMES
+ #      define HAVE_LONG_NAMES(f)    (_use_lfn(f))
+ #      define MAX_PATH_LEN          PATH_MAX
+ #      define MAX_EXT_CHARS         3
+ #      define MAX_SUFFIX            30
+ #      define OS_CODE               (HAVE_LONG_NAMES(ifname) ? 0x0e : 0x00)
+ #      define NO_FSTAT
+ #      define PART_SEP              "._- "
+ #      define MAKE_LEGAL_NAME(name) make_valid_dosw32_name(name)
+ #    else /* DJGPP version 1.x */
+ #      define MAX_PATH_LEN  128
+ #      define NO_MULTIPLE_DOTS
+ #      define MAX_EXT_CHARS 3
+ #      define Z_SUFFIX "z"
+ #      define OS_CODE            0x00
+ #    endif
  #  else
  #    define MAXSEG_64K
+ #    define MAX_PATH_LEN  128
+ #    define NO_MULTIPLE_DOTS
+ #    define MAX_EXT_CHARS 3
+ #    define Z_SUFFIX "z"
+ #    define NO_SIZE_CHECK
+ #    define UNLINK_READONLY_BUG
+ #    define OS_CODE  0x00
  #    ifdef __TURBOC__
  #      define off_t long
+ #      include <alloc.h>
+ #      define DYN_ALLOC
+        /* Turbo C 2.0 does not accept static allocations of large arrays */
+        void * fcalloc (unsigned items, unsigned size);
+        void fcfree (void *ptr);
  #      ifdef __BORLANDC__
  #        define DIRENT
  #      else
***************
*** 43,64 ****
  #    else /* MSC */
  #      define HAVE_SYS_UTIME_H
  #      define NO_UTIME_H
  #    endif
  #  endif
  #  define PATH_SEP2 '\\'
  #  define PATH_SEP3 ':'
- #  define MAX_PATH_LEN  128
- #  define NO_MULTIPLE_DOTS
- #  define MAX_EXT_CHARS 3
- #  define Z_SUFFIX "z"
  #  define NO_CHOWN
  #  define PROTO
  #  define STDC_HEADERS
- #  define NO_SIZE_CHECK
- #  define UNLINK_READONLY_BUG
  #  define casemap(c) tolow(c) /* Force file names to lower case */
  #  include <io.h>
- #  define OS_CODE  0x00
  #  define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
  #  if !defined(NO_ASM) && !defined(ASMV)
  #    define ASMV
--- 76,93 ----
  #    else /* MSC */
  #      define HAVE_SYS_UTIME_H
  #      define NO_UTIME_H
+ #      include <malloc.h>
+ #      define fcalloc(nitems,itemsize) halloc((long)(nitems),(itemsize))
+ #      define fcfree(ptr) hfree(ptr)
  #    endif
  #  endif
  #  define PATH_SEP2 '\\'
  #  define PATH_SEP3 ':'
  #  define NO_CHOWN
  #  define PROTO
  #  define STDC_HEADERS
  #  define casemap(c) tolow(c) /* Force file names to lower case */
  #  include <io.h>
  #  define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
  #  if !defined(NO_ASM) && !defined(ASMV)
  #    define ASMV
***************
*** 132,150 ****
  #  define OS_CODE  0x0b
  #endif
  
! #ifdef MSDOS
! #  ifdef __TURBOC__
! #    include <alloc.h>
! #    define DYN_ALLOC
!      /* Turbo C 2.0 does not accept static allocations of large arrays */
!      void * fcalloc (unsigned items, unsigned size);
!      void fcfree (void *ptr);
! #  else /* MSC */
! #    include <malloc.h>
! #    define fcalloc(nitems,itemsize) halloc((long)(nitems),(itemsize))
! #    define fcfree(ptr) hfree(ptr)
! #  endif
! #else
  #  ifdef MAXSEG_64K
  #    define fcalloc(items,size) calloc((items),(size))
  #  else
--- 161,167 ----
  #  define OS_CODE  0x0b
  #endif
  
! #ifndef MSDOS
  #  ifdef MAXSEG_64K
  #    define fcalloc(items,size) calloc((items),(size))
  #  else
***************
*** 288,296 ****
  #endif
  
  #ifdef MAX_EXT_CHARS
! #  define MAX_SUFFIX  MAX_EXT_CHARS
  #else
  #  define MAX_SUFFIX  30
  #endif
  
  #ifndef MAKE_LEGAL_NAME
--- 305,316 ----
  #endif
  
  #ifdef MAX_EXT_CHARS
! #  ifndef MAX_SUFFIX
! #    define MAX_SUFFIX  MAX_EXT_CHARS
! #  endif
  #else
  #  define MAX_SUFFIX  30
+ #  define LONG_FILE_NAMES
  #endif
  
  #ifndef MAKE_LEGAL_NAME
*** util.c~0	Thu Sep 17 02:39:56 1998
--- util.c	Sat Sep 26 14:05:44 1998
*************** char *strlwr(s)
*** 184,205 ****
   * any version suffix). For systems with file names that are not
   * case sensitive, force the base name to lower case.
   */
! char *basename(fname)
      char *fname;
  {
!     char *p;
  
!     if ((p = strrchr(fname, PATH_SEP))  != NULL) fname = p+1;
  #ifdef PATH_SEP2
!     if ((p = strrchr(fname, PATH_SEP2)) != NULL) fname = p+1;
  #endif
  #ifdef PATH_SEP3
!     if ((p = strrchr(fname, PATH_SEP3)) != NULL) fname = p+1;
! #endif
! #ifdef SUFFIX_SEP
!     if ((p = strrchr(fname, SUFFIX_SEP)) != NULL) *p = '\0';
  #endif
!     if (casemap('A') == 'a') strlwr(fname);
      return fname;
  }
  
--- 184,209 ----
   * any version suffix). For systems with file names that are not
   * case sensitive, force the base name to lower case.
   */
! char *gbasename(fname)
      char *fname;
  {
!     register char *p;
  
!     for (p = fname + strlen(fname); p > fname; p--) {
! #ifdef SUFFIX_SEP
!          if (p[-1] == SUFFIX_SEP)
!              p[-1] = '\0';
! #endif
!          if (p[-1] == PATH_SEP
  #ifdef PATH_SEP2
! 	       || p[-1] == PATH_SEP2
  #endif
  #ifdef PATH_SEP3
! 	       || p[-1] == PATH_SEP3
  #endif
! 	       )
!              return p;
!     }
      return fname;
  }
  
*** zdiff.i~0	Tue Aug 17 01:32:16 1993
--- zdiff.in	Tue Sep 22 11:54:58 1998
***************
*** 11,16 ****
--- 11,20 ----
  # or diff is preserved.
  
  PATH="BINDIR:$PATH"; export PATH
+ tmpdir=${TMPDIR-/tmp}
+ if test ! -d "${tmpdir}"; then
+ 	tmpdir=.
+ fi
  prog=`echo $0 | sed 's|.*/||'`
  case "$prog" in
    *cmp) comp=${CMP-cmp}   ;;
***************
*** 47,56 ****
                  case "$2" in
  	        *[-.]gz* | *[-.][zZ] | *.t[ga]z)
  			F=`echo "$2" | sed 's|.*/||;s|[-.][zZtga]*||'`
!                         gzip -cdfq "$2" > /tmp/"$F".$$
!                         gzip -cdfq "$1" | $comp $OPTIONS - /tmp/"$F".$$
                          STAT="$?"
! 			/bin/rm -f /tmp/"$F".$$;;
  
                  *)      gzip -cdfq "$1" | $comp $OPTIONS - "$2"
                          STAT="$?";;
--- 51,60 ----
                  case "$2" in
  	        *[-.]gz* | *[-.][zZ] | *.t[ga]z)
  			F=`echo "$2" | sed 's|.*/||;s|[-.][zZtga]*||'`
!                         gzip -cdfq "$2" > "${tmpdir}"/"$F".$$
!                         gzip -cdfq "$1" | $comp $OPTIONS - "${tmpdir}"/"$F".$$
                          STAT="$?"
! 			rm -f "${tmpdir}"/"$F".$$;;
  
                  *)      gzip -cdfq "$1" | $comp $OPTIONS - "$2"
                          STAT="$?";;
*** zip.c~0	Sat Oct  4 02:33:18 1997
--- zip.c	Sat Sep 26 13:35:40 1998
*************** int zip(in, out)
*** 65,71 ****
      put_byte(OS_CODE);            /* OS identifier */
  
      if (save_orig_name) {
! 	char *p = basename(ifname); /* Don't save the directory part. */
  	do {
  	    put_char(*p);
  	} while (*p++);
--- 65,71 ----
      put_byte(OS_CODE);            /* OS identifier */
  
      if (save_orig_name) {
! 	char *p = gbasename(ifname); /* Don't save the directory part. */
  	do {
  	    put_char(*p);
  	} while (*p++);
*** znew.i~0	Wed Jun 23 11:00:24 1993
--- znew.in	Sat Sep 26 16:13:32 1998
***************
*** 2,7 ****
--- 2,11 ----
  #!/bin/sh
  
  PATH="BINDIR:$PATH"; export PATH
+ tmpdir=${TMPDIR-/tmp}
+ if test ! -d "${tmpdir}"; then
+ 	tmpdir=.
+ fi
  check=0
  pipe=0
  opt=
***************
*** 14,20 ****
  # block is the disk block size (best guess, need not be exact)
  
  warn="(does not preserve modes and timestamp)"
! tmp=/tmp/zfoo.$$
  echo hi > $tmp.1
  echo hi > $tmp.2
  if test -z "`(${CPMOD-cpmod} $tmp.1 $tmp.2) 2>&1`"; then
--- 18,24 ----
  # block is the disk block size (best guess, need not be exact)
  
  warn="(does not preserve modes and timestamp)"
! tmp="${tmpdir}/zf$$"
  echo hi > $tmp.1
  echo hi > $tmp.2
  if test -z "`(${CPMOD-cpmod} $tmp.1 $tmp.2) 2>&1`"; then
*** gzip.c~1	Wed Sep 30 19:01:54 1998
--- gzip.c	Fri Oct 16 15:11:58 1998
*************** local char *get_suffix(name)
*** 991,1001 ****
      int nlen, slen;
      char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
      static char *known_suffixes[] =
!        {z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
  #ifdef MAX_EXT_CHARS
!           "gz", "z",
  #endif
-           NULL};
      char **suf = known_suffixes;
  
      if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */
--- 991,1000 ----
      int nlen, slen;
      char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
      static char *known_suffixes[] =
!        {z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z", NULL};
  #ifdef MAX_EXT_CHARS
!     static char *known_dosish_suffixes[] = {"gz", "z", NULL};
  #endif
      char **suf = known_suffixes;
  
      if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */
*************** local char *get_suffix(name)
*** 1022,1027 ****
--- 1021,1054 ----
             return name+nlen-s;
         }
      } while (*++suf != NULL);
+ #ifdef MAX_EXT_CHARS
+ #ifdef HAVE_LONG_NAMES
+     /* If long file names are supported, only check DOSish
+        butchered suffixes when decompressing.  This allows to
+        compress, e.g., foo.baz into foo.baz.gz instead of punting.  */
+     {
+ 	int e = errno;	/* HAVE_LONG_NAMES might set errno */
+ 	if (HAVE_LONG_NAMES(name) && !decompress) {
+ 	    errno = e;
+ 	    return NULL;
+ 	}
+ 	errno = e;
+     }
+ #endif /* HAVE_LONG_NAMES */
+     /* If the file name doesn't have a dot in its basename, don't
+        check the DOSish suffixes.  This allows to compress foobaz
+        into foobaz.gz and decompress it back.  */
+     if (strchr(gbasename(name), '.') == NULL)
+ 	return NULL;
+     suf = known_dosish_suffixes;
+     do {
+        int s = strlen(*suf);
+        if (slen > s && suffix[slen-s-1] != PATH_SEP
+            && strequ(suffix + slen - s, *suf)) {
+            return name+nlen-s;
+        }
+     } while (*++suf != NULL);
+ #endif /* MAX_EXT_CHARS */
  
      return NULL;
  }
*************** local int get_istat(iname, sbuf)
*** 1080,1086 ****
  #endif
      }
  #endif
!     if (strequ(z_suffix, ".gz")) suf++;
  
      /* Search for all suffixes */
      do {
--- 1107,1113 ----
  #endif
      }
  #endif
!     if (strequ(z_suffix, suffixes[1])) suf++;
  
      /* Search for all suffixes */
      do {
*************** local int get_istat(iname, sbuf)
*** 1109,1115 ****
      /* No suffix found, complain using z_suffix: */
  #ifdef MAX_EXT_CHARS
      strcpy(ifname, iname);
!     if (*dot == '\0') strcpy(dot, ".");
      dot[MAX_EXT_CHARS+1-z_len] = '\0';
  #endif
      strcat(ifname, z_suffix);
--- 1136,1142 ----
      /* No suffix found, complain using z_suffix: */
  #ifdef MAX_EXT_CHARS
      strcpy(ifname, iname);
!     if (*dot == '\0' && z_suffix[0] != '.') strcpy(dot, ".");
      dot[MAX_EXT_CHARS+1-z_len] = '\0';
  #endif
      strcat(ifname, z_suffix);
*************** local int name_too_long(name, statb)
*** 1516,1526 ****
  {
      int s = strlen(name);
      char c = name[s-1];
!     struct stat	tstat; /* stat for truncated name */
      int res;
  
      tstat = *statb;      /* Just in case OS does not fill all fields */
!     name[s-1] = '\0';
      res = stat(name, &tstat) == 0 && same_file(statb, &tstat);
      name[s-1] = c;
      Trace((stderr, " too_long(%s) => %d\n", name, res));
--- 1543,1564 ----
  {
      int s = strlen(name);
      char c = name[s-1];
!     struct stat	tstat; /* stat buf for a file name with last char replaced */
      int res;
  
      tstat = *statb;      /* Just in case OS does not fill all fields */
!     /* Windows 9X VFAT and NTFS filesystems create two names for each
!        file: the original long name, and a short 8+3 alias (for consumption
!        by legacy DOS programs).  In some cases, the short alias is a proper
!        truncation of the long name; for example, `foobar.shar' gets an
!        alias `foobar.sha', and both names point to the same file.  For this
!        reason, checking whether a truncated name points to the same file
!        will produce false alarms for some file names.  To work around these
!        cases, we instead REPLACE the last character of the original file
!        name with a different character and stat the name thus produced to see
!        whether it points to the same file.  The replacement character is
!        deliberately chosen to be one that should be allowed on every OS.  */
!     name[s-1] = c == 'a' ? 'b' : 'a';
      res = stat(name, &tstat) == 0 && same_file(statb, &tstat);
      name[s-1] = c;
      Trace((stderr, " too_long(%s) => %d\n", name, res));
