1 // SPDX-License-Identifier: 0BSD 2 3 /////////////////////////////////////////////////////////////////////////////// 4 // 5 /// \file args.c 6 /// \brief Argument parsing 7 /// 8 /// \note Filter-specific options parsing is in options.c. 9 // 10 // Authors: Lasse Collin 11 // Jia Tan 12 // 13 /////////////////////////////////////////////////////////////////////////////// 14 15 #include "private.h" 16 17 #include "getopt.h" 18 #include <ctype.h> 19 20 21 bool opt_stdout = false; 22 bool opt_force = false; 23 bool opt_keep_original = false; 24 bool opt_robot = false; 25 bool opt_ignore_check = false; 26 27 // We don't modify or free() this, but we need to assign it in some 28 // non-const pointers. 29 const char stdin_filename[] = "(stdin)"; 30 31 32 /// Parse and set the memory usage limit for compression, decompression, 33 /// and/or multithreaded decompression. 34 static void 35 parse_memlimit(const char *name, const char *name_percentage, const char *str, 36 bool set_compress, bool set_decompress, bool set_mtdec) 37 { 38 bool is_percentage = false; 39 uint64_t value; 40 41 const size_t len = strlen(str); 42 if (len > 0 && str[len - 1] == '%') { 43 // Make a copy so that we can get rid of %. 44 // 45 // In the past str wasn't const and we modified it directly 46 // but that modified argv[] and thus affected what was visible 47 // in "ps auxf" or similar tools which was confusing. For 48 // example, --memlimit=50% would show up as --memlimit=50 49 // since the percent sign was overwritten here. 50 char *s = xstrdup(str); 51 s[len - 1] = '\0'; 52 is_percentage = true; 53 value = str_to_uint64(name_percentage, s, 1, 100); 54 free(s); 55 } else { 56 // On 32-bit systems, SIZE_MAX would make more sense than 57 // UINT64_MAX. But use UINT64_MAX still so that scripts 58 // that assume > 4 GiB values don't break. 59 value = str_to_uint64(name, str, 0, UINT64_MAX); 60 } 61 62 hardware_memlimit_set(value, set_compress, set_decompress, set_mtdec, 63 is_percentage); 64 return; 65 } 66 67 68 static void 69 parse_block_list(const char *str_const) 70 { 71 // We need a modifiable string in the for-loop. 72 char *str_start = xstrdup(str_const); 73 char *str = str_start; 74 75 // It must be non-empty and not begin with a comma. 76 if (str[0] == '\0' || str[0] == ',') 77 message_fatal(_("%s: Invalid argument to --block-list"), str); 78 79 // Count the number of comma-separated strings. 80 size_t count = 1; 81 for (size_t i = 0; str[i] != '\0'; ++i) 82 if (str[i] == ',') 83 ++count; 84 85 // Prevent an unlikely integer overflow. 86 if (count > SIZE_MAX / sizeof(block_list_entry) - 1) 87 message_fatal(_("%s: Too many arguments to --block-list"), 88 str); 89 90 // Allocate memory to hold all the sizes specified. 91 // If --block-list was specified already, its value is forgotten. 92 free(opt_block_list); 93 opt_block_list = xmalloc((count + 1) * sizeof(block_list_entry)); 94 95 for (size_t i = 0; i < count; ++i) { 96 // Locate the next comma and replace it with \0. 97 char *p = strchr(str, ','); 98 if (p != NULL) 99 *p = '\0'; 100 101 // Use the default filter chain unless overridden. 102 opt_block_list[i].filters_index = 0; 103 104 // To specify a filter chain, the block list entry may be 105 // prepended with "[filter-chain-number]:". The size is 106 // still required for every block. 107 // For instance: 108 // --block-list=2:10MiB,1:5MiB,,8MiB,0:0 109 // 110 // Translates to: 111 // 1. Block of 10 MiB using filter chain 2 112 // 2. Block of 5 MiB using filter chain 1 113 // 3. Block of 5 MiB using filter chain 1 114 // 4. Block of 8 MiB using the default filter chain 115 // 5. The last block uses the default filter chain 116 // 117 // The block list: 118 // --block-list=2:MiB,1:,0 119 // 120 // Is not allowed because the second block does not specify 121 // the block size, only the filter chain. 122 if (str[0] >= '0' && str[0] <= '9' && str[1] == ':') { 123 if (str[2] == '\0') 124 message_fatal(_("In --block-list, block " 125 "size is missing after " 126 "filter chain number '%c:'"), 127 str[0]); 128 129 int filter_num = str[0] - '0'; 130 opt_block_list[i].filters_index = 131 (uint32_t)filter_num; 132 str += 2; 133 } 134 135 if (str[0] == '\0') { 136 // There is no string, that is, a comma follows 137 // another comma. Use the previous value. 138 // 139 // NOTE: We checked earlier that the first char 140 // of the whole list cannot be a comma. 141 assert(i > 0); 142 opt_block_list[i] = opt_block_list[i - 1]; 143 } else { 144 opt_block_list[i].size = str_to_uint64("block-list", 145 str, 0, UINT64_MAX); 146 147 // Zero indicates no more new Blocks. 148 if (opt_block_list[i].size == 0) { 149 if (i + 1 != count) 150 message_fatal(_("0 can only be used " 151 "as the last element " 152 "in --block-list")); 153 154 opt_block_list[i].size = UINT64_MAX; 155 } 156 } 157 158 str = p + 1; 159 } 160 161 // Terminate the array. 162 opt_block_list[count].size = 0; 163 164 free(str_start); 165 return; 166 } 167 168 169 static void 170 parse_real(args_info *args, int argc, char **argv) 171 { 172 enum { 173 OPT_FILTERS = INT_MIN, 174 OPT_FILTERS1, 175 OPT_FILTERS2, 176 OPT_FILTERS3, 177 OPT_FILTERS4, 178 OPT_FILTERS5, 179 OPT_FILTERS6, 180 OPT_FILTERS7, 181 OPT_FILTERS8, 182 OPT_FILTERS9, 183 OPT_FILTERS_HELP, 184 185 OPT_X86, 186 OPT_POWERPC, 187 OPT_IA64, 188 OPT_ARM, 189 OPT_ARMTHUMB, 190 OPT_ARM64, 191 OPT_SPARC, 192 OPT_RISCV, 193 OPT_DELTA, 194 OPT_LZMA1, 195 OPT_LZMA2, 196 197 OPT_SINGLE_STREAM, 198 OPT_NO_SPARSE, 199 OPT_FILES, 200 OPT_FILES0, 201 OPT_BLOCK_SIZE, 202 OPT_BLOCK_LIST, 203 OPT_MEM_COMPRESS, 204 OPT_MEM_DECOMPRESS, 205 OPT_MEM_MT_DECOMPRESS, 206 OPT_NO_ADJUST, 207 OPT_INFO_MEMORY, 208 OPT_ROBOT, 209 OPT_FLUSH_TIMEOUT, 210 OPT_IGNORE_CHECK, 211 }; 212 213 static const char short_opts[] 214 = "cC:defF:hHlkM:qQrS:tT:vVz0123456789"; 215 216 static const struct option long_opts[] = { 217 // Operation mode 218 { "compress", no_argument, NULL, 'z' }, 219 { "decompress", no_argument, NULL, 'd' }, 220 { "uncompress", no_argument, NULL, 'd' }, 221 { "test", no_argument, NULL, 't' }, 222 { "list", no_argument, NULL, 'l' }, 223 224 // Operation modifiers 225 { "keep", no_argument, NULL, 'k' }, 226 { "force", no_argument, NULL, 'f' }, 227 { "stdout", no_argument, NULL, 'c' }, 228 { "to-stdout", no_argument, NULL, 'c' }, 229 { "single-stream", no_argument, NULL, OPT_SINGLE_STREAM }, 230 { "no-sparse", no_argument, NULL, OPT_NO_SPARSE }, 231 { "suffix", required_argument, NULL, 'S' }, 232 // { "recursive", no_argument, NULL, 'r' }, // TODO 233 { "files", optional_argument, NULL, OPT_FILES }, 234 { "files0", optional_argument, NULL, OPT_FILES0 }, 235 236 // Basic compression settings 237 { "format", required_argument, NULL, 'F' }, 238 { "check", required_argument, NULL, 'C' }, 239 { "ignore-check", no_argument, NULL, OPT_IGNORE_CHECK }, 240 { "block-size", required_argument, NULL, OPT_BLOCK_SIZE }, 241 { "block-list", required_argument, NULL, OPT_BLOCK_LIST }, 242 { "memlimit-compress", required_argument, NULL, OPT_MEM_COMPRESS }, 243 { "memlimit-decompress", required_argument, NULL, OPT_MEM_DECOMPRESS }, 244 { "memlimit-mt-decompress", required_argument, NULL, OPT_MEM_MT_DECOMPRESS }, 245 { "memlimit", required_argument, NULL, 'M' }, 246 { "memory", required_argument, NULL, 'M' }, // Old alias 247 { "no-adjust", no_argument, NULL, OPT_NO_ADJUST }, 248 { "threads", required_argument, NULL, 'T' }, 249 { "flush-timeout", required_argument, NULL, OPT_FLUSH_TIMEOUT }, 250 251 { "extreme", no_argument, NULL, 'e' }, 252 { "fast", no_argument, NULL, '0' }, 253 { "best", no_argument, NULL, '9' }, 254 255 // Filters 256 { "filters", optional_argument, NULL, OPT_FILTERS}, 257 { "filters1", optional_argument, NULL, OPT_FILTERS1}, 258 { "filters2", optional_argument, NULL, OPT_FILTERS2}, 259 { "filters3", optional_argument, NULL, OPT_FILTERS3}, 260 { "filters4", optional_argument, NULL, OPT_FILTERS4}, 261 { "filters5", optional_argument, NULL, OPT_FILTERS5}, 262 { "filters6", optional_argument, NULL, OPT_FILTERS6}, 263 { "filters7", optional_argument, NULL, OPT_FILTERS7}, 264 { "filters8", optional_argument, NULL, OPT_FILTERS8}, 265 { "filters9", optional_argument, NULL, OPT_FILTERS9}, 266 { "filters-help", optional_argument, NULL, OPT_FILTERS_HELP}, 267 268 { "lzma1", optional_argument, NULL, OPT_LZMA1 }, 269 { "lzma2", optional_argument, NULL, OPT_LZMA2 }, 270 { "x86", optional_argument, NULL, OPT_X86 }, 271 { "powerpc", optional_argument, NULL, OPT_POWERPC }, 272 { "ia64", optional_argument, NULL, OPT_IA64 }, 273 { "arm", optional_argument, NULL, OPT_ARM }, 274 { "armthumb", optional_argument, NULL, OPT_ARMTHUMB }, 275 { "arm64", optional_argument, NULL, OPT_ARM64 }, 276 { "sparc", optional_argument, NULL, OPT_SPARC }, 277 { "riscv", optional_argument, NULL, OPT_RISCV }, 278 { "delta", optional_argument, NULL, OPT_DELTA }, 279 280 // Other options 281 { "quiet", no_argument, NULL, 'q' }, 282 { "verbose", no_argument, NULL, 'v' }, 283 { "no-warn", no_argument, NULL, 'Q' }, 284 { "robot", no_argument, NULL, OPT_ROBOT }, 285 { "info-memory", no_argument, NULL, OPT_INFO_MEMORY }, 286 { "help", no_argument, NULL, 'h' }, 287 { "long-help", no_argument, NULL, 'H' }, 288 { "version", no_argument, NULL, 'V' }, 289 290 { NULL, 0, NULL, 0 } 291 }; 292 293 int c; 294 295 while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) 296 != -1) { 297 switch (c) { 298 // Compression preset (also for decompression if --format=raw) 299 case '0': case '1': case '2': case '3': case '4': 300 case '5': case '6': case '7': case '8': case '9': 301 coder_set_preset((uint32_t)(c - '0')); 302 break; 303 304 // --memlimit-compress 305 case OPT_MEM_COMPRESS: 306 parse_memlimit("memlimit-compress", 307 "memlimit-compress%", optarg, 308 true, false, false); 309 break; 310 311 // --memlimit-decompress 312 case OPT_MEM_DECOMPRESS: 313 parse_memlimit("memlimit-decompress", 314 "memlimit-decompress%", optarg, 315 false, true, false); 316 break; 317 318 // --memlimit-mt-decompress 319 case OPT_MEM_MT_DECOMPRESS: 320 parse_memlimit("memlimit-mt-decompress", 321 "memlimit-mt-decompress%", optarg, 322 false, false, true); 323 break; 324 325 // --memlimit 326 case 'M': 327 parse_memlimit("memlimit", "memlimit%", optarg, 328 true, true, true); 329 break; 330 331 // --suffix 332 case 'S': 333 suffix_set(optarg); 334 break; 335 336 case 'T': { 337 // Since xz 5.4.0: Ignore leading '+' first. 338 const char *s = optarg; 339 if (optarg[0] == '+') 340 ++s; 341 342 // The max is from src/liblzma/common/common.h. 343 uint32_t t = str_to_uint64("threads", s, 0, 16384); 344 345 // If leading '+' was used then use multi-threaded 346 // mode even if exactly one thread was specified. 347 if (t == 1 && optarg[0] == '+') 348 t = UINT32_MAX; 349 350 hardware_threads_set(t); 351 break; 352 } 353 354 // --version 355 case 'V': 356 // This doesn't return. 357 message_version(); 358 359 // --stdout 360 case 'c': 361 opt_stdout = true; 362 break; 363 364 // --decompress 365 case 'd': 366 opt_mode = MODE_DECOMPRESS; 367 break; 368 369 // --extreme 370 case 'e': 371 coder_set_extreme(); 372 break; 373 374 // --force 375 case 'f': 376 opt_force = true; 377 break; 378 379 // --info-memory 380 case OPT_INFO_MEMORY: 381 // This doesn't return. 382 hardware_memlimit_show(); 383 384 // --help 385 case 'h': 386 // This doesn't return. 387 message_help(false); 388 389 // --long-help 390 case 'H': 391 // This doesn't return. 392 message_help(true); 393 394 // --list 395 case 'l': 396 opt_mode = MODE_LIST; 397 break; 398 399 // --keep 400 case 'k': 401 opt_keep_original = true; 402 break; 403 404 // --quiet 405 case 'q': 406 message_verbosity_decrease(); 407 break; 408 409 case 'Q': 410 set_exit_no_warn(); 411 break; 412 413 case 't': 414 opt_mode = MODE_TEST; 415 break; 416 417 // --verbose 418 case 'v': 419 message_verbosity_increase(); 420 break; 421 422 // --robot 423 case OPT_ROBOT: 424 opt_robot = true; 425 426 // This is to make sure that floating point numbers 427 // always have a dot as decimal separator. 428 setlocale(LC_NUMERIC, "C"); 429 break; 430 431 case 'z': 432 opt_mode = MODE_COMPRESS; 433 break; 434 435 // --filters 436 case OPT_FILTERS: 437 coder_add_filters_from_str(optarg); 438 break; 439 440 // --filters1...--filters9 441 case OPT_FILTERS1: 442 case OPT_FILTERS2: 443 case OPT_FILTERS3: 444 case OPT_FILTERS4: 445 case OPT_FILTERS5: 446 case OPT_FILTERS6: 447 case OPT_FILTERS7: 448 case OPT_FILTERS8: 449 case OPT_FILTERS9: 450 coder_add_block_filters(optarg, 451 (size_t)(c - OPT_FILTERS)); 452 break; 453 454 // --filters-help 455 case OPT_FILTERS_HELP: 456 // This doesn't return. 457 message_filters_help(); 458 break; 459 460 case OPT_X86: 461 coder_add_filter(LZMA_FILTER_X86, 462 options_bcj(optarg)); 463 break; 464 465 case OPT_POWERPC: 466 coder_add_filter(LZMA_FILTER_POWERPC, 467 options_bcj(optarg)); 468 break; 469 470 case OPT_IA64: 471 coder_add_filter(LZMA_FILTER_IA64, 472 options_bcj(optarg)); 473 break; 474 475 case OPT_ARM: 476 coder_add_filter(LZMA_FILTER_ARM, 477 options_bcj(optarg)); 478 break; 479 480 case OPT_ARMTHUMB: 481 coder_add_filter(LZMA_FILTER_ARMTHUMB, 482 options_bcj(optarg)); 483 break; 484 485 case OPT_ARM64: 486 coder_add_filter(LZMA_FILTER_ARM64, 487 options_bcj(optarg)); 488 break; 489 490 case OPT_SPARC: 491 coder_add_filter(LZMA_FILTER_SPARC, 492 options_bcj(optarg)); 493 break; 494 495 case OPT_RISCV: 496 coder_add_filter(LZMA_FILTER_RISCV, 497 options_bcj(optarg)); 498 break; 499 500 case OPT_DELTA: 501 coder_add_filter(LZMA_FILTER_DELTA, 502 options_delta(optarg)); 503 break; 504 505 case OPT_LZMA1: 506 coder_add_filter(LZMA_FILTER_LZMA1, 507 options_lzma(optarg)); 508 break; 509 510 case OPT_LZMA2: 511 coder_add_filter(LZMA_FILTER_LZMA2, 512 options_lzma(optarg)); 513 break; 514 515 // Other 516 517 // --format 518 case 'F': { 519 // Just in case, support both "lzma" and "alone" since 520 // the latter was used for forward compatibility in 521 // LZMA Utils 4.32.x. 522 static const struct { 523 char str[8]; 524 enum format_type format; 525 } types[] = { 526 { "auto", FORMAT_AUTO }, 527 { "xz", FORMAT_XZ }, 528 { "lzma", FORMAT_LZMA }, 529 { "alone", FORMAT_LZMA }, 530 #ifdef HAVE_LZIP_DECODER 531 { "lzip", FORMAT_LZIP }, 532 #endif 533 { "raw", FORMAT_RAW }, 534 }; 535 536 size_t i = 0; 537 while (strcmp(types[i].str, optarg) != 0) 538 if (++i == ARRAY_SIZE(types)) 539 message_fatal(_("%s: Unknown file " 540 "format type"), 541 optarg); 542 543 opt_format = types[i].format; 544 break; 545 } 546 547 // --check 548 case 'C': { 549 static const struct { 550 char str[8]; 551 lzma_check check; 552 } types[] = { 553 { "none", LZMA_CHECK_NONE }, 554 { "crc32", LZMA_CHECK_CRC32 }, 555 { "crc64", LZMA_CHECK_CRC64 }, 556 { "sha256", LZMA_CHECK_SHA256 }, 557 }; 558 559 size_t i = 0; 560 while (strcmp(types[i].str, optarg) != 0) { 561 if (++i == ARRAY_SIZE(types)) 562 message_fatal(_("%s: Unsupported " 563 "integrity " 564 "check type"), optarg); 565 } 566 567 // Use a separate check in case we are using different 568 // liblzma than what was used to compile us. 569 if (!lzma_check_is_supported(types[i].check)) 570 message_fatal(_("%s: Unsupported integrity " 571 "check type"), optarg); 572 573 coder_set_check(types[i].check); 574 break; 575 } 576 577 case OPT_IGNORE_CHECK: 578 opt_ignore_check = true; 579 break; 580 581 case OPT_BLOCK_SIZE: 582 opt_block_size = str_to_uint64("block-size", optarg, 583 0, LZMA_VLI_MAX); 584 break; 585 586 case OPT_BLOCK_LIST: { 587 parse_block_list(optarg); 588 break; 589 } 590 591 case OPT_SINGLE_STREAM: 592 opt_single_stream = true; 593 break; 594 595 case OPT_NO_SPARSE: 596 io_no_sparse(); 597 break; 598 599 case OPT_FILES: 600 args->files_delim = '\n'; 601 602 // Fall through 603 604 case OPT_FILES0: 605 if (args->files_name != NULL) 606 message_fatal(_("Only one file can be " 607 "specified with '--files' " 608 "or '--files0'.")); 609 610 if (optarg == NULL) { 611 args->files_name = stdin_filename; 612 args->files_file = stdin; 613 } else { 614 args->files_name = optarg; 615 args->files_file = fopen(optarg, 616 c == OPT_FILES ? "r" : "rb"); 617 if (args->files_file == NULL) 618 // TRANSLATORS: This is a translatable 619 // string because French needs a space 620 // before the colon ("%s : %s"). 621 message_fatal(_("%s: %s"), optarg, 622 strerror(errno)); 623 } 624 625 break; 626 627 case OPT_NO_ADJUST: 628 opt_auto_adjust = false; 629 break; 630 631 case OPT_FLUSH_TIMEOUT: 632 opt_flush_timeout = str_to_uint64("flush-timeout", 633 optarg, 0, UINT64_MAX); 634 break; 635 636 default: 637 message_try_help(); 638 tuklib_exit(E_ERROR, E_ERROR, false); 639 } 640 } 641 642 return; 643 } 644 645 646 static void 647 parse_environment(args_info *args, char *argv0, const char *varname) 648 { 649 char *env = getenv(varname); 650 if (env == NULL) 651 return; 652 653 // We modify the string, so make a copy of it. 654 env = xstrdup(env); 655 656 // Calculate the number of arguments in env. argc stats at one 657 // to include space for the program name. 658 int argc = 1; 659 bool prev_was_space = true; 660 for (size_t i = 0; env[i] != '\0'; ++i) { 661 // NOTE: Cast to unsigned char is needed so that correct 662 // value gets passed to isspace(), which expects 663 // unsigned char cast to int. Casting to int is done 664 // automatically due to integer promotion, but we need to 665 // force char to unsigned char manually. Otherwise 8-bit 666 // characters would get promoted to wrong value if 667 // char is signed. 668 if (isspace((unsigned char)env[i])) { 669 prev_was_space = true; 670 } else if (prev_was_space) { 671 prev_was_space = false; 672 673 // Keep argc small enough to fit into a signed int 674 // and to keep it usable for memory allocation. 675 if (++argc == my_min( 676 INT_MAX, SIZE_MAX / sizeof(char *))) 677 message_fatal(_("The environment variable " 678 "%s contains too many " 679 "arguments"), varname); 680 } 681 } 682 683 // Allocate memory to hold pointers to the arguments. Add one to get 684 // space for the terminating NULL (if some systems happen to need it). 685 char **argv = xmalloc(((size_t)(argc) + 1) * sizeof(char *)); 686 argv[0] = argv0; 687 argv[argc] = NULL; 688 689 // Go through the string again. Split the arguments using '\0' 690 // characters and add pointers to the resulting strings to argv. 691 argc = 1; 692 prev_was_space = true; 693 for (size_t i = 0; env[i] != '\0'; ++i) { 694 if (isspace((unsigned char)env[i])) { 695 prev_was_space = true; 696 env[i] = '\0'; 697 } else if (prev_was_space) { 698 prev_was_space = false; 699 argv[argc++] = env + i; 700 } 701 } 702 703 // Parse the argument list we got from the environment. All non-option 704 // arguments i.e. filenames are ignored. 705 parse_real(args, argc, argv); 706 707 // Reset the state of the getopt_long() so that we can parse the 708 // command line options too. There are two incompatible ways to 709 // do it. 710 #ifdef HAVE_OPTRESET 711 // BSD 712 optind = 1; 713 optreset = 1; 714 #else 715 // GNU, Solaris 716 optind = 0; 717 #endif 718 719 // We don't need the argument list from environment anymore. 720 free(argv); 721 free(env); 722 723 return; 724 } 725 726 727 extern void 728 args_parse(args_info *args, int argc, char **argv) 729 { 730 // Initialize those parts of *args that we need later. 731 args->files_name = NULL; 732 args->files_file = NULL; 733 args->files_delim = '\0'; 734 735 // Check how we were called. 736 { 737 // Remove the leading path name, if any. 738 const char *name = strrchr(argv[0], '/'); 739 if (name == NULL) 740 name = argv[0]; 741 else 742 ++name; 743 744 // NOTE: It's possible that name[0] is now '\0' if argv[0] 745 // is weird, but it doesn't matter here. 746 747 // Look for full command names instead of substrings like 748 // "un", "cat", and "lz" to reduce possibility of false 749 // positives when the programs have been renamed. 750 if (strstr(name, "xzcat") != NULL) { 751 opt_mode = MODE_DECOMPRESS; 752 opt_stdout = true; 753 } else if (strstr(name, "unxz") != NULL) { 754 opt_mode = MODE_DECOMPRESS; 755 } else if (strstr(name, "lzcat") != NULL) { 756 opt_format = FORMAT_LZMA; 757 opt_mode = MODE_DECOMPRESS; 758 opt_stdout = true; 759 } else if (strstr(name, "unlzma") != NULL) { 760 opt_format = FORMAT_LZMA; 761 opt_mode = MODE_DECOMPRESS; 762 } else if (strstr(name, "lzma") != NULL) { 763 opt_format = FORMAT_LZMA; 764 } 765 } 766 767 // First the flags from the environment 768 parse_environment(args, argv[0], "XZ_DEFAULTS"); 769 parse_environment(args, argv[0], "XZ_OPT"); 770 771 // Then from the command line 772 parse_real(args, argc, argv); 773 774 // If encoder or decoder support was omitted at build time, 775 // show an error now so that the rest of the code can rely on 776 // that whatever is in opt_mode is also supported. 777 #ifndef HAVE_ENCODERS 778 if (opt_mode == MODE_COMPRESS) 779 message_fatal(_("Compression support was disabled " 780 "at build time")); 781 #endif 782 #ifndef HAVE_DECODERS 783 // Even MODE_LIST cannot work without decoder support so MODE_COMPRESS 784 // is the only valid choice. 785 if (opt_mode != MODE_COMPRESS) 786 message_fatal(_("Decompression support was disabled " 787 "at build time")); 788 #endif 789 790 #ifdef HAVE_LZIP_DECODER 791 if (opt_mode == MODE_COMPRESS && opt_format == FORMAT_LZIP) 792 message_fatal(_("Compression of lzip files (.lz) " 793 "is not supported")); 794 #endif 795 796 // Never remove the source file when the destination is not on disk. 797 // In test mode the data is written nowhere, but setting opt_stdout 798 // will make the rest of the code behave well. 799 if (opt_stdout || opt_mode == MODE_TEST) { 800 opt_keep_original = true; 801 opt_stdout = true; 802 } 803 804 // When compressing, if no --format flag was used, or it 805 // was --format=auto, we compress to the .xz format. 806 if (opt_mode == MODE_COMPRESS && opt_format == FORMAT_AUTO) 807 opt_format = FORMAT_XZ; 808 809 // Set opt_block_list to NULL if we are not compressing to the .xz 810 // format. This option cannot be used outside of this case, and 811 // simplifies the implementation later. 812 if ((opt_mode != MODE_COMPRESS || opt_format != FORMAT_XZ) 813 && opt_block_list != NULL) { 814 message(V_WARNING, _("--block-list is ignored unless " 815 "compressing to the .xz format")); 816 free(opt_block_list); 817 opt_block_list = NULL; 818 } 819 820 // If raw format is used and a custom suffix is not provided, 821 // then only stdout mode can be used when compressing or 822 // decompressing. 823 if (opt_format == FORMAT_RAW && !suffix_is_set() && !opt_stdout 824 && (opt_mode == MODE_COMPRESS 825 || opt_mode == MODE_DECOMPRESS)) { 826 if (args->files_name != NULL) 827 message_fatal(_("With --format=raw, " 828 "--suffix=.SUF is required " 829 "unless writing to stdout")); 830 831 // If all of the filenames provided are "-" (more than one 832 // "-" could be specified) or no filenames are provided, 833 // then we are only going to be writing to standard out. 834 for (int i = optind; i < argc; i++) { 835 if (strcmp(argv[i], "-") != 0) 836 message_fatal(_("With --format=raw, " 837 "--suffix=.SUF is required " 838 "unless writing to stdout")); 839 } 840 } 841 842 // Compression settings need to be validated (options themselves and 843 // their memory usage) when compressing to any file format. It has to 844 // be done also when uncompressing raw data, since for raw decoding 845 // the options given on the command line are used to know what kind 846 // of raw data we are supposed to decode. 847 if (opt_mode == MODE_COMPRESS || (opt_format == FORMAT_RAW 848 && opt_mode != MODE_LIST)) 849 coder_set_compression_settings(); 850 851 // If no filenames are given, use stdin. 852 if (argv[optind] == NULL && args->files_name == NULL) { 853 // We don't modify or free() the "-" constant. The caller 854 // modifies this so don't make the struct itself const. 855 static char *names_stdin[2] = { (char *)"-", NULL }; 856 args->arg_names = names_stdin; 857 args->arg_count = 1; 858 } else { 859 // We got at least one filename from the command line, or 860 // --files or --files0 was specified. 861 args->arg_names = argv + optind; 862 args->arg_count = (unsigned int)(argc - optind); 863 } 864 865 return; 866 } 867 868 869 #ifndef NDEBUG 870 extern void 871 args_free(void) 872 { 873 free(opt_block_list); 874 return; 875 } 876 #endif 877