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