xz: Make xz buildable even when encoders or decoders are disabled.

The patch is quite long but it's mostly about adding new #ifdefs
to omit code when encoders or decoders have been disabled.

This adds two new #defines to config.h: HAVE_ENCODERS and
HAVE_DECODERS.
diff --git a/configure.ac b/configure.ac
index 5842882..26b6f70 100644
--- a/configure.ac
+++ b/configure.ac
@@ -114,6 +114,8 @@
 				;;
 		esac
 	done
+	AC_DEFINE([HAVE_ENCODERS], [1],
+		[Define to 1 if any of HAVE_ENCODER_foo have been defined.])
 	AC_MSG_RESULT([$enable_encoders])
 fi
 
@@ -141,6 +143,8 @@
 				;;
 		esac
 	done
+	AC_DEFINE([HAVE_DECODERS], [1],
+		[Define to 1 if any of HAVE_DECODER_foo have been defined.])
 	AC_MSG_RESULT([$enable_decoders])
 fi
 
diff --git a/src/xz/Makefile.am b/src/xz/Makefile.am
index 1f4a279..9520503 100644
--- a/src/xz/Makefile.am
+++ b/src/xz/Makefile.am
@@ -16,8 +16,6 @@
 	file_io.h \
 	hardware.c \
 	hardware.h \
-	list.c \
-	list.h \
 	main.c \
 	main.h \
 	message.c \
@@ -39,6 +37,12 @@
 	../common/tuklib_mbstr_width.c \
 	../common/tuklib_mbstr_fw.c
 
+if COND_MAIN_DECODER
+xz_SOURCES = \
+	list.c \
+	list.h
+endif
+
 if COND_W32
 xz_SOURCES += xz_w32res.rc
 endif
diff --git a/src/xz/args.c b/src/xz/args.c
index 041c800..341f29e 100644
--- a/src/xz/args.c
+++ b/src/xz/args.c
@@ -635,6 +635,22 @@
 	// Then from the command line
 	parse_real(args, argc, argv);
 
+	// If encoder or decoder support was omitted at build time,
+	// show an error now so that the rest of the code can rely on
+	// that whatever is in opt_mode is also supported.
+#ifndef HAVE_ENCODERS
+	if (opt_mode == MODE_COMPRESS)
+		message_fatal(_("Compression support was disabled "
+				"at build time"));
+#endif
+#ifndef HAVE_DECODERS
+	// Even MODE_LIST cannot work without decoder support so MODE_COMPRESS
+	// is the only valid choice.
+	if (opt_mode != MODE_COMPRESS)
+		message_fatal(_("Decompression support was disabled "
+				"at build time"));
+#endif
+
 	// Never remove the source file when the destination is not on disk.
 	// In test mode the data is written nowhere, but setting opt_stdout
 	// will make the rest of the code behave well.
diff --git a/src/xz/coder.c b/src/xz/coder.c
index a94bdb8..3c6a01c 100644
--- a/src/xz/coder.c
+++ b/src/xz/coder.c
@@ -51,7 +51,7 @@
 /// This becomes false if the --check=CHECK option is used.
 static bool check_default = true;
 
-#ifdef MYTHREAD_ENABLED
+#if defined(HAVE_ENCODERS) && defined(MYTHREAD_ENABLED)
 static lzma_mt mt_options = {
 	.flags = 0,
 	.timeout = 300,
@@ -221,9 +221,10 @@
 	// Get the memory usage. Note that if --format=raw was used,
 	// we can be decompressing.
 	const uint64_t memory_limit = hardware_memlimit_get(opt_mode);
-	uint64_t memory_usage;
+	uint64_t memory_usage = UINT64_MAX;
 	if (opt_mode == MODE_COMPRESS) {
-#ifdef MYTHREAD_ENABLED
+#ifdef HAVE_ENCODERS
+#	ifdef MYTHREAD_ENABLED
 		if (opt_format == FORMAT_XZ && hardware_threads_get() > 1) {
 			mt_options.threads = hardware_threads_get();
 			mt_options.block_size = opt_block_size;
@@ -235,12 +236,15 @@
 						" threads."),
 						mt_options.threads);
 		} else
-#endif
+#	endif
 		{
 			memory_usage = lzma_raw_encoder_memusage(filters);
 		}
+#endif
 	} else {
+#ifdef HAVE_DECODERS
 		memory_usage = lzma_raw_decoder_memusage(filters);
+#endif
 	}
 
 	if (memory_usage == UINT64_MAX)
@@ -248,7 +252,11 @@
 
 	// Print memory usage info before possible dictionary
 	// size auto-adjusting.
+	//
+	// NOTE: If only encoder support was built, we cannot show the
+	// what the decoder memory usage will be.
 	message_mem_needed(V_DEBUG, memory_usage);
+#ifdef HAVE_DECODERS
 	if (opt_mode == MODE_COMPRESS) {
 		const uint64_t decmem = lzma_raw_decoder_memusage(filters);
 		if (decmem != UINT64_MAX)
@@ -256,6 +264,7 @@
 					"%s MiB of memory."), uint64_to_str(
 						round_up_to_mib(decmem), 0));
 	}
+#endif
 
 	if (memory_usage <= memory_limit)
 		return;
@@ -268,7 +277,8 @@
 
 	assert(opt_mode == MODE_COMPRESS);
 
-#ifdef MYTHREAD_ENABLED
+#ifdef HAVE_ENCODERS
+#	ifdef MYTHREAD_ENABLED
 	if (opt_format == FORMAT_XZ && mt_options.threads > 1) {
 		// Try to reduce the number of threads before
 		// adjusting the compression settings down.
@@ -295,7 +305,7 @@
 			uint64_to_str(round_up_to_mib(
 				memory_limit), 2));
 	}
-#endif
+#	endif
 
 	if (memory_usage <= memory_limit)
 		return;
@@ -349,11 +359,13 @@
 			uint64_to_str(orig_dict_size >> 20, 0),
 			uint64_to_str(opt->dict_size >> 20, 1),
 			uint64_to_str(round_up_to_mib(memory_limit), 2));
+#endif
 
 	return;
 }
 
 
+#ifdef HAVE_DECODERS
 /// Return true if the data in in_buf seems to be in the .xz format.
 static bool
 is_format_xz(void)
@@ -411,6 +423,7 @@
 
 	return true;
 }
+#endif
 
 
 /// Detect the input file type (for now, this done only when decompressing),
@@ -424,6 +437,7 @@
 	lzma_ret ret = LZMA_PROG_ERROR;
 
 	if (opt_mode == MODE_COMPRESS) {
+#ifdef HAVE_ENCODERS
 		switch (opt_format) {
 		case FORMAT_AUTO:
 			// args.c ensures this.
@@ -431,12 +445,12 @@
 			break;
 
 		case FORMAT_XZ:
-#ifdef MYTHREAD_ENABLED
+#	ifdef MYTHREAD_ENABLED
 			if (hardware_threads_get() > 1)
 				ret = lzma_stream_encoder_mt(
 						&strm, &mt_options);
 			else
-#endif
+#	endif
 				ret = lzma_stream_encoder(
 						&strm, filters, check);
 			break;
@@ -449,7 +463,9 @@
 			ret = lzma_raw_encoder(&strm, filters);
 			break;
 		}
+#endif
 	} else {
+#ifdef HAVE_DECODERS
 		uint32_t flags = 0;
 
 		// It seems silly to warn about unsupported check if the
@@ -531,6 +547,7 @@
 			strm.avail_out = 0;
 			ret = lzma_code(&strm, LZMA_RUN);
 		}
+#endif
 	}
 
 	if (ret != LZMA_OK) {
diff --git a/src/xz/main.c b/src/xz/main.c
index 5608229..c2465cf 100644
--- a/src/xz/main.c
+++ b/src/xz/main.c
@@ -207,8 +207,11 @@
 
 	// coder_run() handles compression, decompression, and testing.
 	// list_file() is for --list.
-	void (*run)(const char *filename) = opt_mode == MODE_LIST
-			 ? &list_file : &coder_run;
+	void (*run)(const char *filename) = &coder_run;
+#ifdef HAVE_DECODERS
+	if (opt_mode == MODE_LIST)
+		run = &list_file;
+#endif
 
 	// Process the files given on the command line. Note that if no names
 	// were given, args_parse() gave us a fake "-" filename.
@@ -267,6 +270,7 @@
 			(void)fclose(args.files_file);
 	}
 
+#ifdef HAVE_DECODERS
 	// All files have now been handled. If in --list mode, display
 	// the totals before exiting. We don't have signal handlers
 	// enabled in --list mode, so we don't need to check user_abort.
@@ -274,6 +278,7 @@
 		assert(!user_abort);
 		list_totals();
 	}
+#endif
 
 #ifndef NDEBUG
 	coder_free();
diff --git a/src/xz/private.h b/src/xz/private.h
index 4acfa8d..1da9653 100644
--- a/src/xz/private.h
+++ b/src/xz/private.h
@@ -56,4 +56,7 @@
 #include "signals.h"
 #include "suffix.h"
 #include "util.h"
-#include "list.h"
+
+#ifdef HAVE_DECODERS
+#	include "list.h"
+#endif