Index: src/xz/message.c |
=================================================================== |
--- src/xz/message.c (revision 50504) |
+++ src/xz/message.c (working copy) |
@@ -77,13 +77,24 @@ |
// gettimeofday(). |
#ifdef SIGALRM |
+const int message_progress_sigs[] = { |
+ SIGALRM, |
+#ifdef SIGINFO |
+ SIGINFO, |
+#endif |
+#ifdef SIGUSR1 |
+ SIGUSR1, |
+#endif |
+ 0 |
+}; |
+ |
/// The signal handler for SIGALRM sets this to true. It is set back to false |
/// once the progress message has been updated. |
static volatile sig_atomic_t progress_needs_updating = false; |
/// Signal handler for SIGALRM |
static void |
-progress_signal_handler(int sig lzma_attribute((unused))) |
+progress_signal_handler(int sig lzma_attribute((__unused__))) |
{ |
progress_needs_updating = true; |
return; |
@@ -142,34 +153,15 @@ |
*/ |
#ifdef SIGALRM |
- // DJGPP lacks SA_RESTART, but it shouldn't give EINTR |
- // in most places either. |
-# if defined(__DJGPP__) && !defined(SA_RESTART) |
-# define SA_RESTART 0 |
-# endif |
- |
// Establish the signal handlers which set a flag to tell us that |
- // progress info should be updated. Since these signals don't |
- // require any quick action, we set SA_RESTART. That way we don't |
- // need to block them either in signals_block() to keep stdio |
- // functions from getting EINTR. |
- static const int sigs[] = { |
- SIGALRM, |
-#ifdef SIGINFO |
- SIGINFO, |
-#endif |
-#ifdef SIGUSR1 |
- SIGUSR1, |
-#endif |
- }; |
- |
+ // progress info should be updated. |
struct sigaction sa; |
sigemptyset(&sa.sa_mask); |
- sa.sa_flags = SA_RESTART; |
+ sa.sa_flags = 0; |
sa.sa_handler = &progress_signal_handler; |
- for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i) |
- if (sigaction(sigs[i], &sa, NULL)) |
+ for (size_t i = 0; message_progress_sigs[i] != 0; ++i) |
+ if (sigaction(message_progress_sigs[i], &sa, NULL)) |
message_signal_handler(); |
#endif |
@@ -321,7 +313,8 @@ |
double percentage = (double)(in_pos) / (double)(expected_in_size) |
* 99.9; |
- static char buf[sizeof("99.9 %")]; |
+ // Use big enough buffer to hold e.g. a multibyte decimal point. |
+ static char buf[16]; |
snprintf(buf, sizeof(buf), "%.1f %%", percentage); |
return buf; |
@@ -333,12 +326,8 @@ |
static const char * |
progress_sizes(uint64_t compressed_pos, uint64_t uncompressed_pos, bool final) |
{ |
- // This is enough to hold sizes up to about 99 TiB if thousand |
- // separator is used, or about 1 PiB without thousand separator. |
- // After that the progress indicator will look a bit silly, since |
- // the compression ratio no longer fits with three decimal places. |
- static char buf[36]; |
- |
+ // Use big enough buffer to hold e.g. a multibyte thousand separators. |
+ static char buf[128]; |
char *pos = buf; |
size_t left = sizeof(buf); |
@@ -402,7 +391,8 @@ |
// - 9.9 KiB/s |
// - 99 KiB/s |
// - 999 KiB/s |
- static char buf[sizeof("999 GiB/s")]; |
+ // Use big enough buffer to hold e.g. a multibyte decimal point. |
+ static char buf[16]; |
snprintf(buf, sizeof(buf), "%.*f %s", |
speed > 9.9 ? 0 : 1, speed, unit[unit_index]); |
return buf; |
@@ -588,12 +578,19 @@ |
// Print the actual progress message. The idea is that there is at |
// least three spaces between the fields in typical situations, but |
// even in rare situations there is at least one space. |
- fprintf(stderr, "\r %6s %35s %9s %10s %10s\r", |
+ const char *cols[5] = { |
progress_percentage(in_pos), |
progress_sizes(compressed_pos, uncompressed_pos, false), |
progress_speed(uncompressed_pos, elapsed), |
progress_time(elapsed), |
- progress_remaining(in_pos, elapsed)); |
+ progress_remaining(in_pos, elapsed), |
+ }; |
+ fprintf(stderr, "\r %*s %*s %*s %10s %10s\r", |
+ tuklib_mbstr_fw(cols[0], 6), cols[0], |
+ tuklib_mbstr_fw(cols[1], 35), cols[1], |
+ tuklib_mbstr_fw(cols[2], 9), cols[2], |
+ cols[3], |
+ cols[4]); |
#ifdef SIGALRM |
// Updating the progress info was finished. Reset |
@@ -663,12 +660,19 @@ |
// statistics are printed in the same format as the progress |
// indicator itself. |
if (progress_automatic) { |
- fprintf(stderr, "\r %6s %35s %9s %10s %10s\n", |
+ const char *cols[5] = { |
finished ? "100 %" : progress_percentage(in_pos), |
progress_sizes(compressed_pos, uncompressed_pos, true), |
progress_speed(uncompressed_pos, elapsed), |
progress_time(elapsed), |
- finished ? "" : progress_remaining(in_pos, elapsed)); |
+ finished ? "" : progress_remaining(in_pos, elapsed), |
+ }; |
+ fprintf(stderr, "\r %*s %*s %*s %10s %10s\n", |
+ tuklib_mbstr_fw(cols[0], 6), cols[0], |
+ tuklib_mbstr_fw(cols[1], 35), cols[1], |
+ tuklib_mbstr_fw(cols[2], 9), cols[2], |
+ cols[3], |
+ cols[4]); |
} else { |
// The filename is always printed. |
fprintf(stderr, "%s: ", filename); |
@@ -722,7 +726,11 @@ |
progress_flush(false); |
- fprintf(stderr, "%s: ", progname); |
+ // TRANSLATORS: This is the program name in the beginning |
+ // of the line in messages. Usually it becomes "xz: ". |
+ // This is a translatable string because French needs |
+ // a space before a colon. |
+ fprintf(stderr, _("%s: "), progname); |
vfprintf(stderr, fmt, ap); |
fputc('\n', stderr); |
@@ -829,10 +837,13 @@ |
case LZMA_STREAM_END: |
case LZMA_GET_CHECK: |
case LZMA_PROG_ERROR: |
- return _("Internal error (bug)"); |
+ // Without "default", compiler will warn if new constants |
+ // are added to lzma_ret, it is not too easy to forget to |
+ // add the new constants to this function. |
+ break; |
} |
- return NULL; |
+ return _("Internal error (bug)"); |
} |
@@ -848,13 +859,15 @@ |
// the user might need to +1 MiB to get high enough limit.) |
memusage = round_up_to_mib(memusage); |
+ // With US-ASCII: |
// 2^64 with thousand separators + " MiB" suffix + '\0' = 26 + 4 + 1 |
- char memlimitstr[32]; |
+ // But there may be multibyte chars so reserve enough space. |
+ char memlimitstr[128]; |
// Show the memory usage limit as MiB unless it is less than 1 MiB. |
// This way it's easy to notice errors where one has typed |
// --memory=123 instead of --memory=123MiB. |
- uint64_t memlimit = hardware_memlimit_get(); |
+ uint64_t memlimit = hardware_memlimit_get(opt_mode); |
if (memlimit < (UINT32_C(1) << 20)) { |
snprintf(memlimitstr, sizeof(memlimitstr), "%s B", |
uint64_to_str(memlimit, 1)); |
@@ -895,13 +908,12 @@ |
} |
-extern const char * |
-message_filters_to_str(const lzma_filter *filters, bool all_known) |
+extern void |
+message_filters_to_str(char buf[FILTERS_STR_SIZE], |
+ const lzma_filter *filters, bool all_known) |
{ |
- static char buf[512]; |
- |
char *pos = buf; |
- size_t left = sizeof(buf); |
+ size_t left = FILTERS_STR_SIZE; |
for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) { |
// Add the dashes for the filter option. A space is |
@@ -1025,7 +1037,7 @@ |
} |
} |
- return buf; |
+ return; |
} |
@@ -1035,8 +1047,9 @@ |
if (v > verbosity) |
return; |
- fprintf(stderr, _("%s: Filter chain: %s\n"), progname, |
- message_filters_to_str(filters, true)); |
+ char buf[FILTERS_STR_SIZE]; |
+ message_filters_to_str(buf, filters, true); |
+ fprintf(stderr, _("%s: Filter chain: %s\n"), progname, buf); |
return; |
} |
@@ -1053,27 +1066,12 @@ |
extern void |
-message_memlimit(void) |
-{ |
- if (opt_robot) |
- printf("%" PRIu64 "\n", hardware_memlimit_get()); |
- else |
- printf(_("%s MiB (%s bytes)\n"), |
- uint64_to_str( |
- round_up_to_mib(hardware_memlimit_get()), 0), |
- uint64_to_str(hardware_memlimit_get(), 1)); |
- |
- tuklib_exit(E_SUCCESS, E_ERROR, verbosity != V_SILENT); |
-} |
- |
- |
-extern void |
message_version(void) |
{ |
// It is possible that liblzma version is different than the command |
// line tool version, so print both. |
if (opt_robot) { |
- printf("XZ_VERSION=%d\nLIBLZMA_VERSION=%d\n", |
+ printf("XZ_VERSION=%" PRIu32 "\nLIBLZMA_VERSION=%" PRIu32 "\n", |
LZMA_VERSION, lzma_version_number()); |
} else { |
printf("xz (" PACKAGE_NAME ") " LZMA_VERSION_STRING "\n"); |
@@ -1091,8 +1089,11 @@ |
"Compress or decompress FILEs in the .xz format.\n\n"), |
progname); |
- puts(_("Mandatory arguments to long options are mandatory for " |
- "short options too.\n")); |
+ // NOTE: The short help doesn't currently have options that |
+ // take arguments. |
+ if (long_help) |
+ puts(_("Mandatory arguments to long options are mandatory " |
+ "for short options too.\n")); |
if (long_help) |
puts(_(" Operation mode:\n")); |
@@ -1101,7 +1102,7 @@ |
" -z, --compress force compression\n" |
" -d, --decompress force decompression\n" |
" -t, --test test compressed file integrity\n" |
-" -l, --list list information about files")); |
+" -l, --list list information about .xz files")); |
if (long_help) |
puts(_("\n Operation modifiers:\n")); |
@@ -1115,35 +1116,39 @@ |
puts(_( |
" --no-sparse do not create sparse files when decompressing\n" |
" -S, --suffix=.SUF use the suffix `.SUF' on compressed files\n" |
-" --files=[FILE] read filenames to process from FILE; if FILE is\n" |
+" --files[=FILE] read filenames to process from FILE; if FILE is\n" |
" omitted, filenames are read from the standard input;\n" |
" filenames must be terminated with the newline character\n" |
-" --files0=[FILE] like --files but use the null character as terminator")); |
+" --files0[=FILE] like --files but use the null character as terminator")); |
if (long_help) { |
puts(_("\n Basic file format and compression options:\n")); |
puts(_( |
" -F, --format=FMT file format to encode or decode; possible values are\n" |
" `auto' (default), `xz', `lzma', and `raw'\n" |
-" -C, --check=CHECK integrity check type: `crc32', `crc64' (default),\n" |
-" `sha256', or `none' (use with caution)")); |
+" -C, --check=CHECK integrity check type: `none' (use with caution),\n" |
+" `crc32', `crc64' (default), or `sha256'")); |
} |
puts(_( |
-" -0 .. -9 compression preset; 0-2 fast compression, 3-5 good\n" |
-" compression, 6-9 excellent compression; default is 6")); |
+" -0 ... -9 compression preset; default is 6; take compressor *and*\n" |
+" decompressor memory usage into account before using 7-9!")); |
puts(_( |
-" -e, --extreme use more CPU time when encoding to increase compression\n" |
-" ratio without increasing memory usage of the decoder")); |
+" -e, --extreme try to improve compression ratio by using more CPU time;\n" |
+" does not affect decompressor memory requirements")); |
if (long_help) { |
+ puts(_( // xgettext:no-c-format |
+" --memlimit-compress=LIMIT\n" |
+" --memlimit-decompress=LIMIT\n" |
+" -M, --memlimit=LIMIT\n" |
+" set memory usage limit for compression, decompression,\n" |
+" or both; LIMIT is in bytes, % of RAM, or 0 for defaults")); |
+ |
puts(_( |
" --no-adjust if compression settings exceed the memory usage limit,\n" |
" give an error instead of adjusting the settings downwards")); |
- puts(_( // xgettext:no-c-format |
-" -M, --memory=NUM use roughly NUM bytes of memory at maximum; 0 indicates\n" |
-" the default setting, which is 40 % of total RAM")); |
} |
if (long_help) { |
@@ -1152,11 +1157,15 @@ |
#if defined(HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1) \ |
|| defined(HAVE_ENCODER_LZMA2) || defined(HAVE_DECODER_LZMA2) |
+ // TRANSLATORS: The word "literal" in "literal context bits" |
+ // means how many "context bits" to use when encoding |
+ // literals. A literal is a single 8-bit byte. It doesn't |
+ // mean "literally" here. |
puts(_( |
"\n" |
" --lzma1[=OPTS] LZMA1 or LZMA2; OPTS is a comma-separated list of zero or\n" |
" --lzma2[=OPTS] more of the following options (valid values; default):\n" |
-" preset=NUM reset options to preset number NUM (0-9)\n" |
+" preset=PRE reset options to a preset (0-9[e])\n" |
" dict=NUM dictionary size (4KiB - 1536MiB; 8MiB)\n" |
" lc=NUM number of literal context bits (0-4; 3)\n" |
" lp=NUM number of literal position bits (0-4; 0)\n" |
@@ -1169,9 +1178,9 @@ |
puts(_( |
"\n" |
-" --x86[=OPTS] x86 BCJ filter\n" |
+" --x86[=OPTS] x86 BCJ filter (32-bit and 64-bit)\n" |
" --powerpc[=OPTS] PowerPC BCJ filter (big endian only)\n" |
-" --ia64[=OPTS] IA64 (Itanium) BCJ filter\n" |
+" --ia64[=OPTS] IA-64 (Itanium) BCJ filter\n" |
" --arm[=OPTS] ARM BCJ filter (little endian only)\n" |
" --armthumb[=OPTS] ARM-Thumb BCJ filter (little endian only)\n" |
" --sparc[=OPTS] SPARC BCJ filter\n" |
@@ -1201,7 +1210,8 @@ |
" --robot use machine-parsable messages (useful for scripts)")); |
puts(""); |
puts(_( |
-" --info-memory display the memory usage limit and exit")); |
+" --info-memory display the total amount of RAM and the currently active\n" |
+" memory usage limits, and exit")); |
puts(_( |
" -h, --help display the short help (lists only the basic options)\n" |
" -H, --long-help display this long help and exit")); |
@@ -1216,15 +1226,6 @@ |
puts(_("\nWith no FILE, or when FILE is -, read standard input.\n")); |
- if (long_help) { |
- printf(_( |
-"On this system and configuration, this program will use a maximum of roughly\n" |
-"%s MiB RAM and "), uint64_to_str(round_up_to_mib(hardware_memlimit_get()), 0)); |
- printf(N_("one thread.\n\n", "%s threads.\n\n", |
- hardware_threadlimit_get()), |
- uint64_to_str(hardware_threadlimit_get(), 0)); |
- } |
- |
// TRANSLATORS: This message indicates the bug reporting address |
// for this package. Please add _another line_ saying |
// "Report translation bugs to <...>\n" with the email or WWW |