2012-01-22  Juan Manuel Guerrero  <juan.guerrero@gmx.de>

	* src/xz/suffix.c (uncompressed_name):  Use HAVE_LFN_SUPPORT to enable
	DJGPP specific support for plain DOS filename length limitations.
	(compressed_name):  Use HAVE_LFN_SUPPORT to enable DJGPP specific
	support for plain DOS filename length limitations.

	* src/common/sysdefs.h [__DJGPP__, __DJGPP_MINOR__]:  DJGPP 2.03 lacks
	inttypes.h so provide required values for PRIx32 and PRIx64.

	* src/xz/xz.1:  DJGPP specific info added.

	* src/common/tuklib_common.h [TUKLIB_DOSLIKE]:  Define the new macros
	IS_SLASH and HAVE_SLASH.  If TUKLIB_DOSLIKE defined it will check for
	slash and backslash else only for slash.
	[__DJGPP__]:  Define new macro HAVE_LFN_SUPPORT.  For DJGPP it will be
	checked at runtime if LFN support is available or not.  For all other
	systems HAVE_LFN_SUPPORT always returns true.







diff -aprNU5 xz-5.0.3.orig/src/common/sysdefs.h xz-5.0.3/src/common/sysdefs.h
--- xz-5.0.3.orig/src/common/sysdefs.h	2011-05-21 12:12:30 +0000
+++ xz-5.0.3/src/common/sysdefs.h	2012-01-22 00:08:16 +0000
@@ -32,10 +32,18 @@
 // size_t and NULL
 #include <stddef.h>
 
 #ifdef HAVE_INTTYPES_H
 #	include <inttypes.h>
+#else
+#	if __DJGPP__ == 2 && __DJGPP_MINOR__ < 4
+		/*
+		 * DJGPP 2.03 lacks inttypes.h
+		 */
+#		define PRIx32  "x"
+#		define PRIx64  "llx"
+#	endif
 #endif
 
 // C99 says that inttypes.h always includes stdint.h, but some systems
 // don't do that, and require including stdint.h separately.
 #ifdef HAVE_STDINT_H
diff -aprNU5 xz-5.0.3.orig/src/common/tuklib_common.h xz-5.0.3/src/common/tuklib_common.h
--- xz-5.0.3.orig/src/common/tuklib_common.h	2011-05-21 12:12:30 +0000
+++ xz-5.0.3/src/common/tuklib_common.h	2012-01-22 00:08:16 +0000
@@ -66,6 +66,21 @@
 #if (defined(_WIN32) && !defined(__CYGWIN__)) \
 		|| defined(__OS2__) || defined(__MSDOS__)
 #	define TUKLIB_DOSLIKE 1
 #endif
 
+#if defined TUKLIB_DOSLIKE
+#	define IS_SLASH(c)   ((c) == '/' || (c) == '\\')
+#	define HAVE_SLASH(p) (strchr(p, '/') != NULL || strchr(p, '\\') != NULL || strchr(p, ':') != NULL)
+#	if defined __DJGPP__
+#		include <unistd.h>
+#		define HAVE_LFN_SUPPORT(name) (pathconf((name), _PC_NAME_MAX) > 12)
+#	else
+#		define HAVE_LFN_SUPPORT(name) (1)
+#	endif
+#else
+#	define IS_SLASH(c)   ((c) == '/')
+#	define HAVE_SLASH(p) (strchr(p, '/') != NULL)
+#	define HAVE_LFN_SUPPORT(name) (1)
+#endif
+
 #endif
diff -aprNU5 xz-5.0.3.orig/src/xz/suffix.c xz-5.0.3/src/xz/suffix.c
--- xz-5.0.3.orig/src/xz/suffix.c	2011-05-21 12:12:30 +0000
+++ xz-5.0.3/src/xz/suffix.c	2012-01-22 00:34:38 +0000
@@ -115,24 +115,92 @@ uncompressed_name(const char *src_name,
 	}
 
 	if (new_len == 0 && custom_suffix != NULL)
 		new_len = test_suffix(custom_suffix, src_name, src_len);
 
-	if (new_len == 0) {
+	if (new_len == 0 && HAVE_LFN_SUPPORT(src_name)) {
 		message_warning(_("%s: Filename has an unknown suffix, "
 				"skipping"), src_name);
 		return NULL;
 	}
 
-	const size_t new_suffix_len = strlen(new_suffix);
-	char *dest_name = xmalloc(new_len + new_suffix_len + 1);
-
-	memcpy(dest_name, src_name, new_len);
-	memcpy(dest_name + new_len, new_suffix, new_suffix_len);
-	dest_name[new_len + new_suffix_len] = '\0';
-
-	return dest_name;
+	if (HAVE_LFN_SUPPORT(src_name)) {
+		const size_t new_suffix_len = strlen(new_suffix);
+		char *dest_name = xmalloc(new_len + new_suffix_len + 1);
+
+		memcpy(dest_name, src_name, new_len);
+		memcpy(dest_name + new_len, new_suffix, new_suffix_len);
+		dest_name[new_len + new_suffix_len] = '\0';
+
+		return dest_name;
+	} else {
+		// For plain DOS there are filename length limitations (8.3).
+		//
+		// compressed name       uncompressed name
+		//   filename.exx    -->   filename.ex
+		//   filename.exz    -->   filename.e
+		//   filename.xz     -->   filename
+		//
+		// compressed name       uncompressed name
+		//   filename.exl    -->   filename.ex
+		//   filename.elz    -->   filename.e
+		//   filename.lzm    -->   filename
+
+		size_t new_len1, new_len2, suffix_len;
+		for (new_len = src_len; new_len && src_name[new_len] != '.'; new_len--)
+			;
+		suffix_len = src_len - new_len;
+		new_len1 = suffix_len > 3 ? new_len + 3 : suffix_len - 1;  // Last suffix char.
+		new_len2 = new_len1 - 1;
+
+		if (suffix_len > 3) {
+			if (src_name[new_len1] == 'x' || src_name[new_len1] == 'X' || src_name[new_len1] == 'l' || src_name[new_len1] == 'L') {
+				char *dest_name = xmalloc(new_len1);
+
+				memcpy(dest_name, src_name, new_len1);
+				dest_name[new_len1] = '\0';  // Discard last suffix char.
+
+				return dest_name;
+			} else
+			if (((src_name[new_len2] == 'x' || src_name[new_len2] == 'l') && src_name[new_len1] == 'z') ||
+			    ((src_name[new_len2] == 'X' || src_name[new_len2] == 'L') && src_name[new_len1] == 'Z')) {
+				char *dest_name = xmalloc(new_len2);
+
+				memcpy(dest_name, src_name, new_len2);
+				dest_name[new_len2] = '\0';  // Discard last 2 suffix chars.
+
+				return dest_name;
+			} else 
+			if ((src_name[new_len + 1] == 'l' && src_name[new_len2] == 'z' && src_name[new_len1] == 'm') ||
+			    (src_name[new_len + 1] == 'L' && src_name[new_len2] == 'Z' && src_name[new_len1] == 'M')) {
+				char *dest_name = xmalloc(new_len + 1);
+
+				memcpy(dest_name, src_name, new_len);
+				dest_name[new_len] = '\0';  // Discard all 3 suffix chars.
+
+				return dest_name;
+			} else {
+				message_warning(_("%s: Filename has an unknown suffix, "
+						"skipping"), src_name);
+				return NULL;
+			}
+		} else {
+			if ((src_name[new_len2] == 'x' && src_name[new_len1] == 'z') ||
+			    (src_name[new_len2] == 'X' && src_name[new_len1] == 'Z')) {
+				char *dest_name = xmalloc(new_len2);
+
+				memcpy(dest_name, src_name, new_len);
+				dest_name[new_len] = '\0';
+
+				return dest_name;
+			} else {
+				message_warning(_("%s: Filename has an unknown suffix, "
+						"skipping"), src_name);
+				return NULL;
+			}
+		}
+	}
 }
 
 
 /// \brief      Appends suffix to src_name
 ///
@@ -197,19 +265,87 @@ compressed_name(const char *src_name, co
 		return NULL;
 	}
 
 	const char *suffix = custom_suffix != NULL
 			? custom_suffix : suffixes[0];
-	const size_t suffix_len = strlen(suffix);
+	if (HAVE_LFN_SUPPORT(src_name)) {
+		const size_t suffix_len = strlen(suffix);
 
-	char *dest_name = xmalloc(src_len + suffix_len + 1);
+		char *dest_name = xmalloc(src_len + suffix_len + 1);
 
-	memcpy(dest_name, src_name, src_len);
-	memcpy(dest_name + src_len, suffix, suffix_len);
-	dest_name[src_len + suffix_len] = '\0';
+		memcpy(dest_name, src_name, src_len);
+		memcpy(dest_name + src_len, suffix, suffix_len);
+		dest_name[src_len + suffix_len] = '\0';
+
+		return dest_name;
+	} else {
+		// For plain DOS there are filename length limitations (8.3).
+		//
+		// uncompressed name     compressed name
+		//   filename.ext    -->   filename.exx
+		//   filename.ex     -->   filename.exx
+		//   filename.e      -->   filename.exz
+		//
+		// uncompressed name     compressed name
+		//   filename.ext    -->   filename.exl
+		//   filename.ex     -->   filename.exl
+		//   filename.e      -->   filename.elz
+
+		size_t len;
+		for (len = src_len; len && src_name[len] != '.'; len--)
+			;
+
+		if (len) {
+			// File name has an extension so only a part of the suffix can be appended.
+			if (src_len - len > 2) {
+				// Only one character left for suffix.
+				const size_t name_len = len + 1 + 2;          // Dot plus 2 extension chars
+
+				char *dest_name = xmalloc(name_len + 1 + 1);  // and 1 suffix char.
+
+				memcpy(dest_name, src_name, name_len);
+				if (suffix[0] == '.')
+					memcpy(dest_name + name_len,  suffix + 1, 1);
+				else
+					memcpy(dest_name + name_len,  suffix, 1);
+				dest_name[name_len + 1] = '\0';
+
+				return dest_name;
+			} else {
+				// Two characters left for suffix.
+				const size_t name_len = len + 1 + 1;          // Dot plus 1 extension char
+
+				char *dest_name = xmalloc(name_len + 2 + 1);  // and 2 suffix chars.
+
+				memcpy(dest_name, src_name, name_len);
+				if (suffix[0] == '.')
+					memcpy(dest_name + name_len,  suffix + 1, 2);
+				else
+					memcpy(dest_name + name_len,  suffix, 2);
+				dest_name[name_len + 2] = '\0';
+
+				return dest_name;
+			}
+		} else {
+			// File name has no extension so simply append the whole suffix.
+			const size_t name_len = suffix[0] == '.' ? src_len : src_len + 1;  // custom suffix may have no leading dot.
+			const size_t suffix_len = strlen(suffix);
+
+			char *dest_name = xmalloc(name_len + suffix_len + 1);
+
+			memcpy(dest_name, src_name, src_len);
+			if (suffix[0] != '.')
+				memcpy(dest_name + src_len, ".", 1);
+			memcpy(dest_name + name_len, suffix, suffix_len);
+			if (suffix_len > 3)
+				dest_name[name_len + ((name_len != src_len) ? 3 : 4)] = '\0';
+			else
+				dest_name[name_len + suffix_len] = '\0';
 
-	return dest_name;
+			return dest_name;
+		}
+	}
 }
 
 
 extern char *
 suffix_get_dest_name(const char *src_name)
diff -aprNU5 xz-5.0.3.orig/src/xz/xz.1 xz-5.0.3/src/xz/xz.1
--- xz-5.0.3.orig/src/xz/xz.1	2011-05-21 12:12:30 +0000
+++ xz-5.0.3/src/xz/xz.1	2012-01-22 00:08:16 +0000
@@ -112,10 +112,112 @@ and
 .BR .tlz ,
 and replaces them with the
 .B .tar
 suffix.
 .PP
+
+The
+.BR DJGPP
+port of
+.BR xz
+will detect at run time if
+.IR LFN
+support is available or not.  If
+.IR LFN
+support is available, then the program will work as described above.
+But if only
+.IR SFN
+support is available, like on plain
+.BR DOS
+, then it will
+.IR not
+be possible to append one extension more if the original
+filename has already an extension.  Appart from this the extension cannot be
+longer than
+.IR 3
+characters.  This has the consequence that 
+.IR 1
+or
+.IR 2
+characters
+of the original extension will be overwritten by the character sequence
+.BR x
+or
+.BR xz
+for the
+.BR .xz
+format and
+.BR l
+or
+.BR lz
+for the
+.BR .lzma
+format and there will be
+.IR no
+way to recreate the original extension when the file is uncompressed.  The
+.BR DJGPP
+port will try to preserve as much characters as possible from the original
+extension.
+.IP \(bu 3
+When compressing using the
+.BR .xz
+format the following naming schema will be used:
+
+uncompressed name     compressed name
+  filename.ex\fIt\fR    -->   filename.ex\fIx\fR
+  filename.ex     -->   filename.ex\fIx\fR
+  filename.e      -->   filename.e\fIxz\fR
+  filename        -->   filename.\fIxz\fR
+.IP \(bu 3
+When decompressing using the
+.BR .xz
+format the following naming schema will be used:
+
+compressed name       uncompressed name
+  filename.ex\fIx\fR    -->   filename.ex
+  filename.e\fIxz\fR    -->   filename.e
+  filename.\fIxz\fR     -->   filename
+
+
+.IP \(bu 3
+When compressing using the
+.BR .lzma
+format the following naming schema will be used:
+
+uncompressed name     compressed name
+  filename.ex\fIt\fR    -->   filename.ex\fIl\fR
+  filename.ex     -->   filename.ex\fIl\fR
+  filename.e      -->   filename.e\fIlz\fR
+  filename        -->   filename.\fIlzm\fR
+.IP \(bu 3
+When decompressing using the
+.BR .lzma
+format the following naming schema will be used:
+
+compressed name       uncompressed name
+  filename.ex\fIl\fR    -->   filename.ex
+  filename.e\fIlz\fR    -->   filename.e
+  filename.\fIlzm\fR    -->   filename
+
+.PP
+For
+.IR LFN
+and
+.IR SFN
+systems the
+.BR DJGPP
+port will always recognize the suffixes
+.B .txz
+and
+.BR .tlz
+as
+.IR tar
+archives and will replace them with the
+.B .tar
+suffix.
+.PP
+
 If the target file already exists, an error is displayed and the
 .I file
 is skipped.
 .PP
 Unless writing to standard output,
