diff --git a/src/xz/message.c b/src/xz/message.c index 040147c4..d9733742 100644 --- a/src/xz/message.c +++ b/src/xz/message.c @@ -123,15 +123,6 @@ my_snprintf(char **pos, size_t *left, const char *fmt, ...) return; } -// Ugly hack to make it possible to use lzma_attribute((format(printf, 3, 4))) -// and thus catch stupid things, while still allowing format characters that -// are not in ISO C but are in POSIX. This has to be done after my_snprintf() -// has been defined. -#ifdef __GNUC__ -# define my_snprintf __extension__ my_snprintf -# define my_printf __extension__ printf -#endif - extern void message_init(const char *given_argv0) @@ -722,6 +713,118 @@ message_strm(lzma_ret code) } +extern void +message_filters(enum message_verbosity v, const lzma_filter *filters) +{ + if (v > verbosity) + return; + + fprintf(stderr, _("%s: Filter chain:"), argv0); + + for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) { + fprintf(stderr, " --"); + + switch (filters[i].id) { + case LZMA_FILTER_LZMA1: + case LZMA_FILTER_LZMA2: { + const lzma_options_lzma *opt = filters[i].options; + const char *mode; + const char *mf; + + switch (opt->mode) { + case LZMA_MODE_FAST: + mode = "fast"; + break; + + case LZMA_MODE_NORMAL: + mode = "normal"; + break; + + default: + mode = "UNKNOWN"; + break; + } + + switch (opt->mf) { + case LZMA_MF_HC3: + mf = "hc3"; + break; + + case LZMA_MF_HC4: + mf = "hc4"; + break; + + case LZMA_MF_BT2: + mf = "bt2"; + break; + + case LZMA_MF_BT3: + mf = "bt3"; + break; + + case LZMA_MF_BT4: + mf = "bt4"; + break; + + default: + mf = "UNKNOWN"; + break; + } + + fprintf(stderr, "lzma%c=dict=%" PRIu32 + ",lc=%" PRIu32 ",lp=%" PRIu32 + ",pb=%" PRIu32 + ",mode=%s,nice=%" PRIu32 ",mf=%s" + ",depth=%" PRIu32, + filters[i].id == LZMA_FILTER_LZMA2 + ? '2' : '1', + opt->dict_size, + opt->lc, opt->lp, opt->pb, + mode, opt->nice_len, mf, opt->depth); + break; + } + + case LZMA_FILTER_X86: + fprintf(stderr, "x86"); + break; + + case LZMA_FILTER_POWERPC: + fprintf(stderr, "powerpc"); + break; + + case LZMA_FILTER_IA64: + fprintf(stderr, "ia64"); + break; + + case LZMA_FILTER_ARM: + fprintf(stderr, "arm"); + break; + + case LZMA_FILTER_ARMTHUMB: + fprintf(stderr, "armthumb"); + break; + + case LZMA_FILTER_SPARC: + fprintf(stderr, "sparc"); + break; + + case LZMA_FILTER_DELTA: { + const lzma_options_delta *opt = filters[i].options; + fprintf(stderr, "delta=dist=%" PRIu32, opt->dist); + break; + } + + default: + fprintf(stderr, "UNKNOWN"); + break; + } + } + + fputc('\n', stderr); + return; +} + + extern void message_try_help(void) { @@ -867,13 +970,13 @@ message_help(bool long_help) puts(_("\nWith no FILE, or when FILE is -, read standard input.\n")); if (long_help) { - my_printf(_( + printf(_( "On this system and configuration, the tool will use at maximum of\n" " * roughly %'" PRIu64 " MiB RAM for compression;\n" " * roughly %'" PRIu64 " MiB RAM for decompression; and\n"), hardware_memlimit_encoder() / (1024 * 1024), hardware_memlimit_decoder() / (1024 * 1024)); - my_printf(N_(" * one thread for (de)compression.\n\n", + printf(N_(" * one thread for (de)compression.\n\n", " * %'" PRIu64 " threads for (de)compression.\n\n", (uint64_t)(opt_threads)), (uint64_t)(opt_threads)); } diff --git a/src/xz/message.h b/src/xz/message.h index 7ef9b165..d67fecc7 100644 --- a/src/xz/message.h +++ b/src/xz/message.h @@ -94,10 +94,15 @@ extern void message_bug(void) lzma_attribute((noreturn)); extern void message_signal_handler(void) lzma_attribute((noreturn)); -/// Converts lzma_ret to a string. +/// Convert lzma_ret to a string. extern const char *message_strm(lzma_ret code); +/// Print the filter chain. +extern void message_filters( + enum message_verbosity v, const lzma_filter *filters); + + /// Print a message that user should try --help. extern void message_try_help(void); diff --git a/src/xz/process.c b/src/xz/process.c index 4a028751..191dfc09 100644 --- a/src/xz/process.c +++ b/src/xz/process.c @@ -119,6 +119,9 @@ coder_set_compression_settings(void) message_fatal(_("With --format=lzma only the LZMA1 filter " "is supported")); + // Print the selected filter chain. + message_filters(V_DEBUG, filters); + // If using --format=raw, we can be decoding. The memusage function // also validates the filter chain and the options used for the // filters. @@ -135,6 +138,12 @@ coder_set_compression_settings(void) if (memory_usage == UINT64_MAX) message_fatal("Unsupported filter chain or filter options"); + // Print memory usage info. + message(V_DEBUG, _("%" PRIu64 " MiB of memory is required per thread, " + "limit is %" PRIu64 " MiB"), + memory_usage / (1024 * 1024), + memory_limit / (1024 * 1024)); + if (preset_default) { // When no preset was explicitly requested, we use the default // preset only if the memory usage limit allows. Otherwise we @@ -348,9 +357,24 @@ coder_run(file_pair *pair) } if (ret == LZMA_MEMLIMIT_ERROR) { - // Figure out how much memory would have + // Figure out how much memory it would have // actually needed. - // TODO + uint64_t memusage = lzma_memusage(&strm); + uint64_t memlimit + = hardware_memlimit_decoder(); + + // Round the memory limit down and usage up. + // This way we don't display a ridiculous + // message like "Limit was 9 MiB, but 9 MiB + // would have been needed". + memusage = (memusage + 1024 * 1024 - 1) + / (1024 * 1024); + memlimit /= 1024 * 1024; + + message_error(_("Limit was %'" PRIu64 " MiB, " + "but %'" PRIu64 " MiB would " + "have been needed"), + memlimit, memusage); } if (stop)