]> icculus.org git repositories - icculus/xz.git/blob - src/xz/message.c
Fixes to progress message handling in xz:
[icculus/xz.git] / src / xz / message.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       message.c
4 /// \brief      Printing messages to stderr
5 //
6 //  Copyright (C) 2007-2008 Lasse Collin
7 //
8 //  This program is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Lesser General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2.1 of the License, or (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Lesser General Public License for more details.
17 //
18 ///////////////////////////////////////////////////////////////////////////////
19
20 #include "private.h"
21
22 #ifdef HAVE_SYS_TIME_H
23 #       include <sys/time.h>
24 #endif
25
26 #include <stdarg.h>
27
28
29 /// Name of the program which is prefixed to the error messages.
30 static const char *argv0;
31
32 /// Number of the current file
33 static unsigned int files_pos = 0;
34
35 /// Total number of input files; zero if unknown.
36 static unsigned int files_total;
37
38 /// Verbosity level
39 static enum message_verbosity verbosity = V_WARNING;
40
41 /// Filename which we will print with the verbose messages
42 static const char *filename;
43
44 /// True once the a filename has been printed to stderr as part of progress
45 /// message. If automatic progress updating isn't enabled, this becomes true
46 /// after the first progress message has been printed due to user sending
47 /// SIGINFO, SIGUSR1, or SIGALRM. Once this variable is true, we will print
48 /// an empty line before the next filename to make the output more readable.
49 static bool first_filename_printed = false;
50
51 /// This is set to true when we have printed the current filename to stderr
52 /// as part of a progress message. This variable is useful only if not
53 /// updating progress automatically: if user sends many SIGINFO, SIGUSR1, or
54 /// SIGALRM signals, we won't print the name of the same file multiple times.
55 static bool current_filename_printed = false;
56
57 /// True if we should print progress indicator and update it automatically
58 /// if also verbose >= V_VERBOSE.
59 static bool progress_automatic;
60
61 /// True if message_progress_start() has been called but
62 /// message_progress_end() hasn't been called yet.
63 static bool progress_started = false;
64
65 /// This is true when a progress message was printed and the cursor is still
66 /// on the same line with the progress message. In that case, a newline has
67 /// to be printed before any error messages.
68 static bool progress_active = false;
69
70 /// Pointer to lzma_stream used to do the encoding or decoding.
71 static lzma_stream *progress_strm;
72
73 /// Expected size of the input stream is needed to show completion percentage
74 /// and estimate remaining time.
75 static uint64_t expected_in_size;
76
77 /// Time when we started processing the file
78 static uint64_t start_time;
79
80
81 // Use alarm() and SIGALRM when they are supported. This has two minor
82 // advantages over the alternative of polling gettimeofday():
83 //  - It is possible for the user to send SIGINFO, SIGUSR1, or SIGALRM to
84 //    get intermediate progress information even when --verbose wasn't used
85 //    or stderr is not a terminal.
86 //  - alarm() + SIGALRM seems to have slightly less overhead than polling
87 //    gettimeofday().
88 #ifdef SIGALRM
89
90 /// The signal handler for SIGALRM sets this to true. It is set back to false
91 /// once the progress message has been updated.
92 static volatile sig_atomic_t progress_needs_updating = false;
93
94 /// Signal handler for SIGALRM
95 static void
96 progress_signal_handler(int sig lzma_attribute((unused)))
97 {
98         progress_needs_updating = true;
99         return;
100 }
101
102 #else
103
104 /// This is true when progress message printing is wanted. Using the same
105 /// variable name as above to avoid some ifdefs.
106 static bool progress_needs_updating = false;
107
108 /// Elapsed time when the next progress message update should be done.
109 static uint64_t progress_next_update;
110
111 #endif
112
113
114 /// Get the current time as microseconds since epoch
115 static uint64_t
116 my_time(void)
117 {
118         struct timeval tv;
119         gettimeofday(&tv, NULL);
120         return (uint64_t)(tv.tv_sec) * UINT64_C(1000000) + tv.tv_usec;
121 }
122
123
124 /// Wrapper for snprintf() to help constructing a string in pieces.
125 static void lzma_attribute((format(printf, 3, 4)))
126 my_snprintf(char **pos, size_t *left, const char *fmt, ...)
127 {
128         va_list ap;
129         va_start(ap, fmt);
130         const int len = vsnprintf(*pos, *left, fmt, ap);
131         va_end(ap);
132
133         // If an error occurred, we want the caller to think that the whole
134         // buffer was used. This way no more data will be written to the
135         // buffer. We don't need better error handling here.
136         if (len < 0 || (size_t)(len) >= *left) {
137                 *left = 0;
138         } else {
139                 *pos += len;
140                 *left -= len;
141         }
142
143         return;
144 }
145
146
147 extern void
148 message_init(const char *given_argv0)
149 {
150         // Name of the program
151         argv0 = given_argv0;
152
153         // If --verbose is used, we use a progress indicator if and only
154         // if stderr is a terminal. If stderr is not a terminal, we print
155         // verbose information only after finishing the file. As a special
156         // exception, even if --verbose was not used, user can send SIGALRM
157         // to make us print progress information once without automatic
158         // updating.
159         progress_automatic = isatty(STDERR_FILENO);
160
161         // Commented out because COLUMNS is rarely exported to environment.
162         // Most users have at least 80 columns anyway, let's think something
163         // fancy here if enough people complain.
164 /*
165         if (progress_automatic) {
166                 // stderr is a terminal. Check the COLUMNS environment
167                 // variable to see if the terminal is wide enough. If COLUMNS
168                 // doesn't exist or it has some unparseable value, we assume
169                 // that the terminal is wide enough.
170                 const char *columns_str = getenv("COLUMNS");
171                 if (columns_str != NULL) {
172                         char *endptr;
173                         const long columns = strtol(columns_str, &endptr, 10);
174                         if (*endptr != '\0' || columns < 80)
175                                 progress_automatic = false;
176                 }
177         }
178 */
179
180 #ifdef SIGALRM
181         // At least DJGPP lacks SA_RESTART. It's not essential for us (the
182         // rest of the code can handle interrupted system calls), so just
183         // define it zero.
184 #       ifndef SA_RESTART
185 #               define SA_RESTART 0
186 #       endif
187         // Establish the signal handlers which set a flag to tell us that
188         // progress info should be updated. Since these signals don't
189         // require any quick action, we set SA_RESTART.
190         static const int sigs[] = {
191 #ifdef SIGALRM
192                 SIGALRM,
193 #endif
194 #ifdef SIGINFO
195                 SIGINFO,
196 #endif
197 #ifdef SIGUSR1
198                 SIGUSR1,
199 #endif
200         };
201
202         struct sigaction sa;
203         sigemptyset(&sa.sa_mask);
204         sa.sa_flags = SA_RESTART;
205         sa.sa_handler = &progress_signal_handler;
206
207         for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i)
208                 if (sigaction(sigs[i], &sa, NULL))
209                         message_signal_handler();
210 #endif
211
212         return;
213 }
214
215
216 extern void
217 message_verbosity_increase(void)
218 {
219         if (verbosity < V_DEBUG)
220                 ++verbosity;
221
222         return;
223 }
224
225
226 extern void
227 message_verbosity_decrease(void)
228 {
229         if (verbosity > V_SILENT)
230                 --verbosity;
231
232         return;
233 }
234
235
236 extern void
237 message_set_files(unsigned int files)
238 {
239         files_total = files;
240         return;
241 }
242
243
244 /// Prints the name of the current file if it hasn't been printed already,
245 /// except if we are processing exactly one stream from stdin to stdout.
246 /// I think it looks nicer to not print "(stdin)" when --verbose is used
247 /// in a pipe and no other files are processed.
248 static void
249 print_filename(void)
250 {
251         if (!current_filename_printed
252                         && (files_total != 1 || filename != stdin_filename)) {
253                 signals_block();
254
255                 // If a file was already processed, put an empty line
256                 // before the next filename to improve readability.
257                 if (first_filename_printed)
258                         fputc('\n', stderr);
259
260                 first_filename_printed = true;
261                 current_filename_printed = true;
262
263                 // If we don't know how many files there will be due
264                 // to usage of --files or --files0.
265                 if (files_total == 0)
266                         fprintf(stderr, "%s (%u)\n", filename,
267                                         files_pos);
268                 else
269                         fprintf(stderr, "%s (%u/%u)\n", filename,
270                                         files_pos, files_total);
271
272                 signals_unblock();
273         }
274
275         return;
276 }
277
278
279 extern void
280 message_progress_start(
281                 lzma_stream *strm, const char *src_name, uint64_t in_size)
282 {
283         // Store the pointer to the lzma_stream used to do the coding.
284         // It is needed to find out the position in the stream.
285         progress_strm = strm;
286
287         // Store the processing start time of the file and its expected size.
288         // If we aren't printing any statistics, then these are unused. But
289         // since it is possible that the user sends us a signal to show
290         // statistics, we need to have these available anyway.
291         start_time = my_time();
292         filename = src_name;
293         expected_in_size = in_size;
294
295         // Indicate that progress info may need to be printed before
296         // printing error messages.
297         progress_started = true;
298
299         // Indicate the name of this file hasn't been printed to
300         // stderr yet.
301         current_filename_printed = false;
302
303         // Start numbering the files starting from one.
304         ++files_pos;
305
306         // If progress indicator is wanted, print the filename and possibly
307         // the file count now.
308         if (verbosity >= V_VERBOSE && progress_automatic) {
309                 // Print the filename to stderr if that is appropriate with
310                 // the current settings.
311                 print_filename();
312
313                 // Start the timer to display the first progress message
314                 // after one second. An alternative would be to show the
315                 // first message almost immediatelly, but delaying by one
316                 // second looks better to me, since extremely early
317                 // progress info is pretty much useless.
318 #ifdef SIGALRM
319                 // First disable a possibly existing alarm.
320                 alarm(0);
321                 progress_needs_updating = false;
322                 alarm(1);
323 #else
324                 progress_needs_updating = true;
325                 progress_next_update = 1000000;
326 #endif
327         }
328
329         return;
330 }
331
332
333 /// Make the string indicating completion percentage.
334 static const char *
335 progress_percentage(uint64_t in_pos, bool final)
336 {
337         static char buf[sizeof("100.0 %")];
338
339         double percentage;
340
341         if (final) {
342                 // Use floating point conversion of snprintf() also for
343                 // 100.0 % instead of fixed string, because the decimal
344                 // separator isn't a dot in all locales.
345                 percentage = 100.0;
346         } else {
347                 // If the size of the input file is unknown or the size told us is
348                 // clearly wrong since we have processed more data than the alleged
349                 // size of the file, show a static string indicating that we have
350                 // no idea of the completion percentage.
351                 if (expected_in_size == 0 || in_pos > expected_in_size)
352                         return "--- %";
353
354                 // Never show 100.0 % before we actually are finished.
355                 percentage = (double)(in_pos) / (double)(expected_in_size)
356                                 * 99.9;
357         }
358
359         snprintf(buf, sizeof(buf), "%.1f %%", percentage);
360
361         return buf;
362 }
363
364
365 static void
366 progress_sizes_helper(char **pos, size_t *left, uint64_t value, bool final)
367 {
368         // Allow high precision only for the final message, since it looks
369         // stupid for in-progress information.
370         if (final) {
371                 // At maximum of four digits is allowed for exact byte count.
372                 if (value < 10000) {
373                         my_snprintf(pos, left, "%'" PRIu64 " B", value);
374                         return;
375                 }
376
377                 // At maximum of five significant digits is allowed for KiB.
378                 if (value < UINT64_C(10239900)) {
379                         my_snprintf(pos, left, "%'.1f KiB",
380                                         (double)(value) / 1024.0);
381                         return;
382                 }
383         }
384
385         // Otherwise we use MiB.
386         my_snprintf(pos, left, "%'.1f MiB",
387                         (double)(value) / (1024.0 * 1024.0));
388
389         return;
390 }
391
392
393 /// Make the string containing the amount of input processed, amount of
394 /// output produced, and the compression ratio.
395 static const char *
396 progress_sizes(uint64_t compressed_pos, uint64_t uncompressed_pos, bool final)
397 {
398         // This is enough to hold sizes up to about 99 TiB if thousand
399         // separator is used, or about 1 PiB without thousand separator.
400         // After that the progress indicator will look a bit silly, since
401         // the compression ratio no longer fits with three decimal places.
402         static char buf[44];
403
404         char *pos = buf;
405         size_t left = sizeof(buf);
406
407         // Print the sizes. If this the final message, use more reasonable
408         // units than MiB if the file was small.
409         progress_sizes_helper(&pos, &left, compressed_pos, final);
410         my_snprintf(&pos, &left, " / ");
411         progress_sizes_helper(&pos, &left, uncompressed_pos, final);
412
413         // Avoid division by zero. If we cannot calculate the ratio, set
414         // it to some nice number greater than 10.0 so that it gets caught
415         // in the next if-clause.
416         const double ratio = uncompressed_pos > 0
417                         ? (double)(compressed_pos) / (double)(uncompressed_pos)
418                         : 16.0;
419
420         // If the ratio is very bad, just indicate that it is greater than
421         // 9.999. This way the length of the ratio field stays fixed.
422         if (ratio > 9.999)
423                 snprintf(pos, left, " > %.3f", 9.999);
424         else
425                 snprintf(pos, left, " = %.3f", ratio);
426
427         return buf;
428 }
429
430
431 /// Make the string containing the processing speed of uncompressed data.
432 static const char *
433 progress_speed(uint64_t uncompressed_pos, uint64_t elapsed)
434 {
435         // Don't print the speed immediatelly, since the early values look
436         // like somewhat random.
437         if (elapsed < 3000000)
438                 return "";
439
440         static const char unit[][8] = {
441                 "KiB/s",
442                 "MiB/s",
443                 "GiB/s",
444         };
445
446         size_t unit_index = 0;
447
448         // Calculate the speed as KiB/s.
449         double speed = (double)(uncompressed_pos)
450                         / ((double)(elapsed) * (1024.0 / 1e6));
451
452         // Adjust the unit of the speed if needed.
453         while (speed > 999.0) {
454                 speed /= 1024.0;
455                 if (++unit_index == ARRAY_SIZE(unit))
456                         return ""; // Way too fast ;-)
457         }
458
459         // Use decimal point only if the number is small. Examples:
460         //  - 0.1 KiB/s
461         //  - 9.9 KiB/s
462         //  - 99 KiB/s
463         //  - 999 KiB/s
464         static char buf[sizeof("999 GiB/s")];
465         snprintf(buf, sizeof(buf), "%.*f %s",
466                         speed > 9.9 ? 0 : 1, speed, unit[unit_index]);
467         return buf;
468 }
469
470
471 /// Make a string indicating elapsed or remaining time. The format is either
472 /// M:SS or H:MM:SS depending on if the time is an hour or more.
473 static const char *
474 progress_time(uint64_t useconds)
475 {
476         // 9999 hours = 416 days
477         static char buf[sizeof("9999:59:59")];
478
479         uint32_t seconds = useconds / 1000000;
480
481         // Don't show anything if the time is zero or ridiculously big.
482         if (seconds == 0 || seconds > ((9999 * 60) + 59) * 60 + 59)
483                 return "";
484
485         uint32_t minutes = seconds / 60;
486         seconds %= 60;
487
488         if (minutes >= 60) {
489                 const uint32_t hours = minutes / 60;
490                 minutes %= 60;
491                 snprintf(buf, sizeof(buf),
492                                 "%" PRIu32 ":%02" PRIu32 ":%02" PRIu32,
493                                 hours, minutes, seconds);
494         } else {
495                 snprintf(buf, sizeof(buf), "%" PRIu32 ":%02" PRIu32,
496                                 minutes, seconds);
497         }
498
499         return buf;
500 }
501
502
503 /// Make the string to contain the estimated remaining time, or if the amount
504 /// of input isn't known, how much time has elapsed.
505 static const char *
506 progress_remaining(uint64_t in_pos, uint64_t elapsed)
507 {
508         // Show the amount of time spent so far when making an estimate of
509         // remaining time wouldn't be reasonable:
510         //  - Input size is unknown.
511         //  - Input has grown bigger since we started (de)compressing.
512         //  - We haven't processed much data yet, so estimate would be
513         //    too inaccurate.
514         //  - Only a few seconds has passed since we started (de)compressing,
515         //    so estimate would be too inaccurate.
516         if (expected_in_size == 0 || in_pos > expected_in_size
517                         || in_pos < (UINT64_C(1) << 19) || elapsed < 8000000)
518                 return progress_time(elapsed);
519
520         // Calculate the estimate. Don't give an estimate of zero seconds,
521         // since it is possible that all the input has been already passed
522         // to the library, but there is still quite a bit of output pending.
523         uint32_t remaining = (double)(expected_in_size - in_pos)
524                         * ((double)(elapsed) / 1e6) / (double)(in_pos);
525         if (remaining < 1)
526                 remaining = 1;
527
528         static char buf[sizeof("9 h 55 min")];
529
530         // Select appropriate precision for the estimated remaining time.
531         if (remaining <= 10) {
532                 // At maximum of 10 seconds remaining.
533                 // Show the number of seconds as is.
534                 snprintf(buf, sizeof(buf), "%" PRIu32 " s", remaining);
535
536         } else if (remaining <= 50) {
537                 // At maximum of 50 seconds remaining.
538                 // Round up to the next multiple of five seconds.
539                 remaining = (remaining + 4) / 5 * 5;
540                 snprintf(buf, sizeof(buf), "%" PRIu32 " s", remaining);
541
542         } else if (remaining <= 590) {
543                 // At maximum of 9 minutes and 50 seconds remaining.
544                 // Round up to the next multiple of ten seconds.
545                 remaining = (remaining + 9) / 10 * 10;
546                 snprintf(buf, sizeof(buf), "%" PRIu32 " min %" PRIu32 " s",
547                                 remaining / 60, remaining % 60);
548
549         } else if (remaining <= 59 * 60) {
550                 // At maximum of 59 minutes remaining.
551                 // Round up to the next multiple of a minute.
552                 remaining = (remaining + 59) / 60;
553                 snprintf(buf, sizeof(buf), "%" PRIu32 " min", remaining);
554
555         } else if (remaining <= 9 * 3600 + 50 * 60) {
556                 // At maximum of 9 hours and 50 minutes left.
557                 // Round up to the next multiple of ten minutes.
558                 remaining = (remaining + 599) / 600 * 10;
559                 snprintf(buf, sizeof(buf), "%" PRIu32 " h %" PRIu32 " min",
560                                 remaining / 60, remaining % 60);
561
562         } else if (remaining <= 23 * 3600) {
563                 // At maximum of 23 hours remaining.
564                 // Round up to the next multiple of an hour.
565                 remaining = (remaining + 3599) / 3600;
566                 snprintf(buf, sizeof(buf), "%" PRIu32 " h", remaining);
567
568         } else if (remaining <= 9 * 24 * 3600 + 23 * 3600) {
569                 // At maximum of 9 days and 23 hours remaining.
570                 // Round up to the next multiple of an hour.
571                 remaining = (remaining + 3599) / 3600;
572                 snprintf(buf, sizeof(buf), "%" PRIu32 " d %" PRIu32 " h",
573                                 remaining / 24, remaining % 24);
574
575         } else if (remaining <= 999 * 24 * 3600) {
576                 // At maximum of 999 days remaining. ;-)
577                 // Round up to the next multiple of a day.
578                 remaining = (remaining + 24 * 3600 - 1) / (24 * 3600);
579                 snprintf(buf, sizeof(buf), "%" PRIu32 " d", remaining);
580
581         } else {
582                 // The estimated remaining time is so big that it's better
583                 // that we just show the elapsed time.
584                 return progress_time(elapsed);
585         }
586
587         return buf;
588 }
589
590
591 /// Calculate the elapsed time as microseconds.
592 static uint64_t
593 progress_elapsed(void)
594 {
595         return my_time() - start_time;
596 }
597
598
599 /// Get information about position in the stream. This is currently simple,
600 /// but it will become more complicated once we have multithreading support.
601 static void
602 progress_pos(uint64_t *in_pos,
603                 uint64_t *compressed_pos, uint64_t *uncompressed_pos)
604 {
605         *in_pos = progress_strm->total_in;
606
607         if (opt_mode == MODE_COMPRESS) {
608                 *compressed_pos = progress_strm->total_out;
609                 *uncompressed_pos = progress_strm->total_in;
610         } else {
611                 *compressed_pos = progress_strm->total_in;
612                 *uncompressed_pos = progress_strm->total_out;
613         }
614
615         return;
616 }
617
618
619 extern void
620 message_progress_update(void)
621 {
622         if (!progress_needs_updating)
623                 return;
624
625         // Calculate how long we have been processing this file.
626         const uint64_t elapsed = progress_elapsed();
627
628 #ifndef SIGALRM
629         if (progress_next_update > elapsed)
630                 return;
631
632         progress_next_update = elapsed + 1000000;
633 #endif
634
635         // Get our current position in the stream.
636         uint64_t in_pos;
637         uint64_t compressed_pos;
638         uint64_t uncompressed_pos;
639         progress_pos(&in_pos, &compressed_pos, &uncompressed_pos);
640
641         // Block signals so that fprintf() doesn't get interrupted.
642         signals_block();
643
644         // Print the filename if it hasn't been printed yet.
645         print_filename();
646
647         // Print the actual progress message. The idea is that there is at
648         // least three spaces between the fields in typical situations, but
649         // even in rare situations there is at least one space.
650         fprintf(stderr, "  %7s %43s   %9s   %10s\r",
651                 progress_percentage(in_pos, false),
652                 progress_sizes(compressed_pos, uncompressed_pos, false),
653                 progress_speed(uncompressed_pos, elapsed),
654                 progress_remaining(in_pos, elapsed));
655
656 #ifdef SIGALRM
657         // Updating the progress info was finished. Reset
658         // progress_needs_updating to wait for the next SIGALRM.
659         //
660         // NOTE: This has to be done before alarm(1) or with (very) bad
661         // luck we could be setting this to false after the alarm has already
662         // been triggered.
663         progress_needs_updating = false;
664
665         if (verbosity >= V_VERBOSE && progress_automatic) {
666                 // Mark that the progress indicator is active, so if an error
667                 // occurs, the error message gets printed cleanly.
668                 progress_active = true;
669
670                 // Restart the timer so that progress_needs_updating gets
671                 // set to true after about one second.
672                 alarm(1);
673         } else {
674                 // The progress message was printed because user had sent us
675                 // SIGALRM. In this case, each progress message is printed
676                 // on its own line.
677                 fputc('\n', stderr);
678         }
679 #else
680         // When SIGALRM isn't supported and we get here, it's always due to
681         // automatic progress update. We set progress_active here too like
682         // described above.
683         assert(verbosity >= V_VERBOSE);
684         assert(progress_automatic);
685         progress_active = true;
686 #endif
687
688         signals_unblock();
689
690         return;
691 }
692
693
694 static void
695 progress_flush(bool finished)
696 {
697         if (!progress_started || verbosity < V_VERBOSE)
698                 return;
699
700         uint64_t in_pos;
701         uint64_t compressed_pos;
702         uint64_t uncompressed_pos;
703         progress_pos(&in_pos, &compressed_pos, &uncompressed_pos);
704
705         // Avoid printing intermediate progress info if some error occurs
706         // in the beginning of the stream. (If something goes wrong later in
707         // the stream, it is sometimes useful to tell the user where the
708         // error approximately occurred, especially if the error occurs
709         // after a time-consuming operation.)
710         if (!finished && !progress_active
711                         && (compressed_pos == 0 || uncompressed_pos == 0))
712                 return;
713
714         progress_active = false;
715
716         const uint64_t elapsed = progress_elapsed();
717         const char *elapsed_str = progress_time(elapsed);
718
719         signals_block();
720
721         // When using the auto-updating progress indicator, the final
722         // statistics are printed in the same format as the progress
723         // indicator itself.
724         if (progress_automatic) {
725                 // Using floating point conversion for the percentage instead
726                 // of static "100.0 %" string, because the decimal separator
727                 // isn't a dot in all locales.
728                 fprintf(stderr, "  %7s %43s   %9s   %10s\n",
729                         progress_percentage(in_pos, finished),
730                         progress_sizes(compressed_pos, uncompressed_pos, true),
731                         progress_speed(uncompressed_pos, elapsed),
732                         elapsed_str);
733         } else {
734                 // The filename is always printed.
735                 fprintf(stderr, "%s: ", filename);
736
737                 // Percentage is printed only if we didn't finish yet.
738                 // FIXME: This may look weird when size of the input
739                 // isn't known.
740                 if (!finished)
741                         fprintf(stderr, "%s, ",
742                                         progress_percentage(in_pos, false));
743
744                 // Size information is always printed.
745                 fprintf(stderr, "%s", progress_sizes(
746                                 compressed_pos, uncompressed_pos, true));
747
748                 // The speed and elapsed time aren't always shown.
749                 const char *speed = progress_speed(uncompressed_pos, elapsed);
750                 if (speed[0] != '\0')
751                         fprintf(stderr, ", %s", speed);
752
753                 if (elapsed_str[0] != '\0')
754                         fprintf(stderr, ", %s", elapsed_str);
755
756                 fputc('\n', stderr);
757         }
758
759         signals_unblock();
760
761         return;
762 }
763
764
765 extern void
766 message_progress_end(bool success)
767 {
768         assert(progress_started);
769         progress_flush(success);
770         progress_started = false;
771         return;
772 }
773
774
775 static void
776 vmessage(enum message_verbosity v, const char *fmt, va_list ap)
777 {
778         if (v <= verbosity) {
779                 signals_block();
780
781                 progress_flush(false);
782
783                 fprintf(stderr, "%s: ", argv0);
784                 vfprintf(stderr, fmt, ap);
785                 fputc('\n', stderr);
786
787                 signals_unblock();
788         }
789
790         return;
791 }
792
793
794 extern void
795 message(enum message_verbosity v, const char *fmt, ...)
796 {
797         va_list ap;
798         va_start(ap, fmt);
799         vmessage(v, fmt, ap);
800         va_end(ap);
801         return;
802 }
803
804
805 extern void
806 message_warning(const char *fmt, ...)
807 {
808         va_list ap;
809         va_start(ap, fmt);
810         vmessage(V_WARNING, fmt, ap);
811         va_end(ap);
812
813         set_exit_status(E_WARNING);
814         return;
815 }
816
817
818 extern void
819 message_error(const char *fmt, ...)
820 {
821         va_list ap;
822         va_start(ap, fmt);
823         vmessage(V_ERROR, fmt, ap);
824         va_end(ap);
825
826         set_exit_status(E_ERROR);
827         return;
828 }
829
830
831 extern void
832 message_fatal(const char *fmt, ...)
833 {
834         va_list ap;
835         va_start(ap, fmt);
836         vmessage(V_ERROR, fmt, ap);
837         va_end(ap);
838
839         my_exit(E_ERROR);
840 }
841
842
843 extern void
844 message_bug(void)
845 {
846         message_fatal(_("Internal error (bug)"));
847 }
848
849
850 extern void
851 message_signal_handler(void)
852 {
853         message_fatal(_("Cannot establish signal handlers"));
854 }
855
856
857 extern const char *
858 message_strm(lzma_ret code)
859 {
860         switch (code) {
861         case LZMA_NO_CHECK:
862                 return _("No integrity check; not verifying file integrity");
863
864         case LZMA_UNSUPPORTED_CHECK:
865                 return _("Unsupported type of integrity check; "
866                                 "not verifying file integrity");
867
868         case LZMA_MEM_ERROR:
869                 return strerror(ENOMEM);
870
871         case LZMA_MEMLIMIT_ERROR:
872                 return _("Memory usage limit reached");
873
874         case LZMA_FORMAT_ERROR:
875                 return _("File format not recognized");
876
877         case LZMA_OPTIONS_ERROR:
878                 return _("Unsupported options");
879
880         case LZMA_DATA_ERROR:
881                 return _("Compressed data is corrupt");
882
883         case LZMA_BUF_ERROR:
884                 return _("Unexpected end of input");
885
886         case LZMA_OK:
887         case LZMA_STREAM_END:
888         case LZMA_GET_CHECK:
889         case LZMA_PROG_ERROR:
890                 return _("Internal error (bug)");
891         }
892
893         return NULL;
894 }
895
896
897 extern void
898 message_filters(enum message_verbosity v, const lzma_filter *filters)
899 {
900         if (v > verbosity)
901                 return;
902
903         fprintf(stderr, _("%s: Filter chain:"), argv0);
904
905         for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
906                 fprintf(stderr, " --");
907
908                 switch (filters[i].id) {
909                 case LZMA_FILTER_LZMA1:
910                 case LZMA_FILTER_LZMA2: {
911                         const lzma_options_lzma *opt = filters[i].options;
912                         const char *mode;
913                         const char *mf;
914
915                         switch (opt->mode) {
916                         case LZMA_MODE_FAST:
917                                 mode = "fast";
918                                 break;
919
920                         case LZMA_MODE_NORMAL:
921                                 mode = "normal";
922                                 break;
923
924                         default:
925                                 mode = "UNKNOWN";
926                                 break;
927                         }
928
929                         switch (opt->mf) {
930                         case LZMA_MF_HC3:
931                                 mf = "hc3";
932                                 break;
933
934                         case LZMA_MF_HC4:
935                                 mf = "hc4";
936                                 break;
937
938                         case LZMA_MF_BT2:
939                                 mf = "bt2";
940                                 break;
941
942                         case LZMA_MF_BT3:
943                                 mf = "bt3";
944                                 break;
945
946                         case LZMA_MF_BT4:
947                                 mf = "bt4";
948                                 break;
949
950                         default:
951                                 mf = "UNKNOWN";
952                                 break;
953                         }
954
955                         fprintf(stderr, "lzma%c=dict=%" PRIu32
956                                         ",lc=%" PRIu32 ",lp=%" PRIu32
957                                         ",pb=%" PRIu32
958                                         ",mode=%s,nice=%" PRIu32 ",mf=%s"
959                                         ",depth=%" PRIu32,
960                                         filters[i].id == LZMA_FILTER_LZMA2
961                                                 ? '2' : '1',
962                                         opt->dict_size,
963                                         opt->lc, opt->lp, opt->pb,
964                                         mode, opt->nice_len, mf, opt->depth);
965                         break;
966                 }
967
968                 case LZMA_FILTER_X86:
969                         fprintf(stderr, "x86");
970                         break;
971
972                 case LZMA_FILTER_POWERPC:
973                         fprintf(stderr, "powerpc");
974                         break;
975
976                 case LZMA_FILTER_IA64:
977                         fprintf(stderr, "ia64");
978                         break;
979
980                 case LZMA_FILTER_ARM:
981                         fprintf(stderr, "arm");
982                         break;
983
984                 case LZMA_FILTER_ARMTHUMB:
985                         fprintf(stderr, "armthumb");
986                         break;
987
988                 case LZMA_FILTER_SPARC:
989                         fprintf(stderr, "sparc");
990                         break;
991
992                 case LZMA_FILTER_DELTA: {
993                         const lzma_options_delta *opt = filters[i].options;
994                         fprintf(stderr, "delta=dist=%" PRIu32, opt->dist);
995                         break;
996                 }
997
998                 default:
999                         fprintf(stderr, "UNKNOWN");
1000                         break;
1001                 }
1002         }
1003
1004         fputc('\n', stderr);
1005         return;
1006 }
1007
1008
1009 extern void
1010 message_try_help(void)
1011 {
1012         // Print this with V_WARNING instead of V_ERROR to prevent it from
1013         // showing up when --quiet has been specified.
1014         message(V_WARNING, _("Try `%s --help' for more information."), argv0);
1015         return;
1016 }
1017
1018
1019 extern void
1020 message_version(void)
1021 {
1022         // It is possible that liblzma version is different than the command
1023         // line tool version, so print both.
1024         printf("xz " LZMA_VERSION_STRING "\n");
1025         printf("liblzma %s\n", lzma_version_string());
1026         my_exit(E_SUCCESS);
1027 }
1028
1029
1030 extern void
1031 message_help(bool long_help)
1032 {
1033         printf(_("Usage: %s [OPTION]... [FILE]...\n"
1034                         "Compress or decompress FILEs in the .xz format.\n\n"),
1035                         argv0);
1036
1037         puts(_("Mandatory arguments to long options are mandatory for "
1038                         "short options too.\n"));
1039
1040         if (long_help)
1041                 puts(_(" Operation mode:\n"));
1042
1043         puts(_(
1044 "  -z, --compress      force compression\n"
1045 "  -d, --decompress    force decompression\n"
1046 "  -t, --test          test compressed file integrity\n"
1047 "  -l, --list          list information about files"));
1048
1049         if (long_help)
1050                 puts(_("\n Operation modifiers:\n"));
1051
1052         puts(_(
1053 "  -k, --keep          keep (don't delete) input files\n"
1054 "  -f, --force         force overwrite of output file and (de)compress links\n"
1055 "  -c, --stdout        write to standard output and don't delete input files"));
1056
1057         if (long_help)
1058                 puts(_(
1059 "  -S, --suffix=.SUF   use the suffix `.SUF' on compressed files\n"
1060 "      --files=[FILE]  read filenames to process from FILE; if FILE is\n"
1061 "                      omitted, filenames are read from the standard input;\n"
1062 "                      filenames must be terminated with the newline character\n"
1063 "      --files0=[FILE] like --files but use the null character as terminator"));
1064
1065         if (long_help) {
1066                 puts(_("\n Basic file format and compression options:\n"));
1067                 puts(_(
1068 "  -F, --format=FMT    file format to encode or decode; possible values are\n"
1069 "                      `auto' (default), `xz', `lzma', and `raw'\n"
1070 "  -C, --check=CHECK   integrity check type: `crc32', `crc64' (default),\n"
1071 "                      or `sha256'"));
1072         }
1073
1074         puts(_(
1075 "  -0 .. -9            compression preset; 0-2 fast compression, 3-5 good\n"
1076 "                      compression, 6-9 excellent compression; default is 6"));
1077
1078         puts(_(
1079 "  -M, --memory=NUM    use roughly NUM bytes of memory at maximum; 0 indicates\n"
1080 "                      the default setting, which depends on the operation mode\n"
1081 "                      and the amount of physical memory (RAM)"));
1082
1083         if (long_help) {
1084                 puts(_(
1085 "\n Custom filter chain for compression (alternative for using presets):"));
1086
1087 #if defined(HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1) \
1088                 || defined(HAVE_ENCODER_LZMA2) || defined(HAVE_DECODER_LZMA2)
1089                 puts(_(
1090 "\n"
1091 "  --lzma1=[OPTS]      LZMA1 or LZMA2; OPTS is a comma-separated list of zero or\n"
1092 "  --lzma2=[OPTS]      more of the following options (valid values; default):\n"
1093 "                        preset=NUM reset options to preset number NUM (1-9)\n"
1094 "                        dict=NUM   dictionary size (4KiB - 1536MiB; 8MiB)\n"
1095 "                        lc=NUM     number of literal context bits (0-4; 3)\n"
1096 "                        lp=NUM     number of literal position bits (0-4; 0)\n"
1097 "                        pb=NUM     number of position bits (0-4; 2)\n"
1098 "                        mode=MODE  compression mode (fast, normal; normal)\n"
1099 "                        nice=NUM   nice length of a match (2-273; 64)\n"
1100 "                        mf=NAME    match finder (hc3, hc4, bt2, bt3, bt4; bt4)\n"
1101 "                        depth=NUM  maximum search depth; 0=automatic (default)"));
1102 #endif
1103
1104                 puts(_(
1105 "\n"
1106 "  --x86               x86 filter (sometimes called BCJ filter)\n"
1107 "  --powerpc           PowerPC (big endian) filter\n"
1108 "  --ia64              IA64 (Itanium) filter\n"
1109 "  --arm               ARM filter\n"
1110 "  --armthumb          ARM-Thumb filter\n"
1111 "  --sparc             SPARC filter"));
1112
1113 #if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
1114                 puts(_(
1115 "\n"
1116 "  --delta=[OPTS]      Delta filter; valid OPTS (valid values; default):\n"
1117 "                        dist=NUM   distance between bytes being subtracted\n"
1118 "                                   from each other (1-256; 1)"));
1119 #endif
1120
1121 #if defined(HAVE_ENCODER_SUBBLOCK) || defined(HAVE_DECODER_SUBBLOCK)
1122                 puts(_(
1123 "\n"
1124 "  --subblock=[OPTS]   Subblock filter; valid OPTS (valid values; default):\n"
1125 "                        size=NUM   number of bytes of data per subblock\n"
1126 "                                   (1 - 256Mi; 4Ki)\n"
1127 "                        rle=NUM    run-length encoder chunk size (0-256; 0)"));
1128 #endif
1129         }
1130
1131         if (long_help)
1132                 puts(_("\n Other options:\n"));
1133
1134         puts(_(
1135 "  -q, --quiet         suppress warnings; specify twice to suppress errors too\n"
1136 "  -v, --verbose       be verbose; specify twice for even more verbose"));
1137
1138         if (long_help)
1139                 puts(_(
1140 "\n"
1141 "  -h, --help          display the short help (lists only the basic options)\n"
1142 "  -H, --long-help     display this long help"));
1143         else
1144                 puts(_(
1145 "  -h, --help          display this short help\n"
1146 "  -H, --long-help     display the long help (lists also the advanced options)"));
1147
1148         puts(_(
1149 "  -V, --version       display the version number"));
1150
1151         puts(_("\nWith no FILE, or when FILE is -, read standard input.\n"));
1152
1153         if (long_help) {
1154                 printf(_(
1155 "On this system and configuration, the tool will use at maximum of\n"
1156 "  * roughly %'" PRIu64 " MiB RAM for compression;\n"
1157 "  * roughly %'" PRIu64 " MiB RAM for decompression; and\n"),
1158                                 hardware_memlimit_encoder() / (1024 * 1024),
1159                                 hardware_memlimit_decoder() / (1024 * 1024));
1160                 printf(N_("  * one thread for (de)compression.\n\n",
1161                         "  * %'" PRIu32 " threads for (de)compression.\n\n",
1162                         hardware_threadlimit_get()),
1163                         hardware_threadlimit_get());
1164         }
1165
1166         printf(_("Report bugs to <%s> (in English or Finnish).\n"),
1167                         PACKAGE_BUGREPORT);
1168
1169         my_exit(E_SUCCESS);
1170 }