1207753Smm/////////////////////////////////////////////////////////////////////////////// 2207753Smm// 3207753Smm/// \file args.c 4207753Smm/// \brief Argument parsing 5207753Smm/// 6207753Smm/// \note Filter-specific options parsing is in options.c. 7207753Smm// 8207753Smm// Author: Lasse Collin 9207753Smm// 10207753Smm// This file has been put into the public domain. 11207753Smm// You can do whatever you want with this file. 12207753Smm// 13207753Smm/////////////////////////////////////////////////////////////////////////////// 14207753Smm 15207753Smm#include "private.h" 16207753Smm 17207753Smm#include "getopt.h" 18207753Smm#include <ctype.h> 19207753Smm 20207753Smm 21207753Smmbool opt_stdout = false; 22207753Smmbool opt_force = false; 23207753Smmbool opt_keep_original = false; 24207753Smmbool opt_robot = false; 25292588Sdelphijbool opt_ignore_check = false; 26207753Smm 27207753Smm// We don't modify or free() this, but we need to assign it in some 28207753Smm// non-const pointers. 29213700Smmconst char stdin_filename[] = "(stdin)"; 30207753Smm 31207753Smm 32213700Smm/// Parse and set the memory usage limit for compression and/or decompression. 33207753Smmstatic void 34213700Smmparse_memlimit(const char *name, const char *name_percentage, char *str, 35213700Smm bool set_compress, bool set_decompress) 36213700Smm{ 37213700Smm bool is_percentage = false; 38213700Smm uint64_t value; 39213700Smm 40213700Smm const size_t len = strlen(str); 41213700Smm if (len > 0 && str[len - 1] == '%') { 42213700Smm str[len - 1] = '\0'; 43213700Smm is_percentage = true; 44213700Smm value = str_to_uint64(name_percentage, str, 1, 100); 45213700Smm } else { 46213700Smm // On 32-bit systems, SIZE_MAX would make more sense than 47213700Smm // UINT64_MAX. But use UINT64_MAX still so that scripts 48213700Smm // that assume > 4 GiB values don't break. 49213700Smm value = str_to_uint64(name, str, 0, UINT64_MAX); 50213700Smm } 51213700Smm 52213700Smm hardware_memlimit_set( 53213700Smm value, set_compress, set_decompress, is_percentage); 54213700Smm return; 55213700Smm} 56213700Smm 57213700Smm 58213700Smmstatic void 59292588Sdelphijparse_block_list(char *str) 60292588Sdelphij{ 61292588Sdelphij // It must be non-empty and not begin with a comma. 62292588Sdelphij if (str[0] == '\0' || str[0] == ',') 63292588Sdelphij message_fatal(_("%s: Invalid argument to --block-list"), str); 64292588Sdelphij 65292588Sdelphij // Count the number of comma-separated strings. 66292588Sdelphij size_t count = 1; 67292588Sdelphij for (size_t i = 0; str[i] != '\0'; ++i) 68292588Sdelphij if (str[i] == ',') 69292588Sdelphij ++count; 70292588Sdelphij 71292588Sdelphij // Prevent an unlikely integer overflow. 72292588Sdelphij if (count > SIZE_MAX / sizeof(uint64_t) - 1) 73292588Sdelphij message_fatal(_("%s: Too many arguments to --block-list"), 74292588Sdelphij str); 75292588Sdelphij 76292588Sdelphij // Allocate memory to hold all the sizes specified. 77292588Sdelphij // If --block-list was specified already, its value is forgotten. 78292588Sdelphij free(opt_block_list); 79292588Sdelphij opt_block_list = xmalloc((count + 1) * sizeof(uint64_t)); 80292588Sdelphij 81292588Sdelphij for (size_t i = 0; i < count; ++i) { 82292588Sdelphij // Locate the next comma and replace it with \0. 83292588Sdelphij char *p = strchr(str, ','); 84292588Sdelphij if (p != NULL) 85292588Sdelphij *p = '\0'; 86292588Sdelphij 87292588Sdelphij if (str[0] == '\0') { 88292588Sdelphij // There is no string, that is, a comma follows 89292588Sdelphij // another comma. Use the previous value. 90292588Sdelphij // 91292588Sdelphij // NOTE: We checked earler that the first char 92292588Sdelphij // of the whole list cannot be a comma. 93292588Sdelphij assert(i > 0); 94292588Sdelphij opt_block_list[i] = opt_block_list[i - 1]; 95292588Sdelphij } else { 96292588Sdelphij opt_block_list[i] = str_to_uint64("block-list", str, 97292588Sdelphij 0, UINT64_MAX); 98292588Sdelphij 99292588Sdelphij // Zero indicates no more new Blocks. 100292588Sdelphij if (opt_block_list[i] == 0) { 101292588Sdelphij if (i + 1 != count) 102292588Sdelphij message_fatal(_("0 can only be used " 103292588Sdelphij "as the last element " 104292588Sdelphij "in --block-list")); 105292588Sdelphij 106292588Sdelphij opt_block_list[i] = UINT64_MAX; 107292588Sdelphij } 108292588Sdelphij } 109292588Sdelphij 110292588Sdelphij str = p + 1; 111292588Sdelphij } 112292588Sdelphij 113292588Sdelphij // Terminate the array. 114292588Sdelphij opt_block_list[count] = 0; 115292588Sdelphij return; 116292588Sdelphij} 117292588Sdelphij 118292588Sdelphij 119292588Sdelphijstatic void 120207753Smmparse_real(args_info *args, int argc, char **argv) 121207753Smm{ 122207753Smm enum { 123213700Smm OPT_X86 = INT_MIN, 124207753Smm OPT_POWERPC, 125207753Smm OPT_IA64, 126207753Smm OPT_ARM, 127207753Smm OPT_ARMTHUMB, 128207753Smm OPT_SPARC, 129207753Smm OPT_DELTA, 130207753Smm OPT_LZMA1, 131207753Smm OPT_LZMA2, 132207753Smm 133292588Sdelphij OPT_SINGLE_STREAM, 134207753Smm OPT_NO_SPARSE, 135207753Smm OPT_FILES, 136207753Smm OPT_FILES0, 137292588Sdelphij OPT_BLOCK_SIZE, 138292588Sdelphij OPT_BLOCK_LIST, 139213700Smm OPT_MEM_COMPRESS, 140213700Smm OPT_MEM_DECOMPRESS, 141213700Smm OPT_NO_ADJUST, 142207753Smm OPT_INFO_MEMORY, 143207753Smm OPT_ROBOT, 144292588Sdelphij OPT_FLUSH_TIMEOUT, 145292588Sdelphij OPT_IGNORE_CHECK, 146207753Smm }; 147207753Smm 148207753Smm static const char short_opts[] 149207753Smm = "cC:defF:hHlkM:qQrS:tT:vVz0123456789"; 150207753Smm 151207753Smm static const struct option long_opts[] = { 152207753Smm // Operation mode 153207753Smm { "compress", no_argument, NULL, 'z' }, 154207753Smm { "decompress", no_argument, NULL, 'd' }, 155207753Smm { "uncompress", no_argument, NULL, 'd' }, 156207753Smm { "test", no_argument, NULL, 't' }, 157207753Smm { "list", no_argument, NULL, 'l' }, 158207753Smm 159207753Smm // Operation modifiers 160207753Smm { "keep", no_argument, NULL, 'k' }, 161207753Smm { "force", no_argument, NULL, 'f' }, 162207753Smm { "stdout", no_argument, NULL, 'c' }, 163207753Smm { "to-stdout", no_argument, NULL, 'c' }, 164292588Sdelphij { "single-stream", no_argument, NULL, OPT_SINGLE_STREAM }, 165207753Smm { "no-sparse", no_argument, NULL, OPT_NO_SPARSE }, 166207753Smm { "suffix", required_argument, NULL, 'S' }, 167207753Smm // { "recursive", no_argument, NULL, 'r' }, // TODO 168207753Smm { "files", optional_argument, NULL, OPT_FILES }, 169207753Smm { "files0", optional_argument, NULL, OPT_FILES0 }, 170207753Smm 171207753Smm // Basic compression settings 172207753Smm { "format", required_argument, NULL, 'F' }, 173207753Smm { "check", required_argument, NULL, 'C' }, 174292588Sdelphij { "ignore-check", no_argument, NULL, OPT_IGNORE_CHECK }, 175292588Sdelphij { "block-size", required_argument, NULL, OPT_BLOCK_SIZE }, 176292588Sdelphij { "block-list", required_argument, NULL, OPT_BLOCK_LIST }, 177213700Smm { "memlimit-compress", required_argument, NULL, OPT_MEM_COMPRESS }, 178213700Smm { "memlimit-decompress", required_argument, NULL, OPT_MEM_DECOMPRESS }, 179213700Smm { "memlimit", required_argument, NULL, 'M' }, 180213700Smm { "memory", required_argument, NULL, 'M' }, // Old alias 181213700Smm { "no-adjust", no_argument, NULL, OPT_NO_ADJUST }, 182207753Smm { "threads", required_argument, NULL, 'T' }, 183292588Sdelphij { "flush-timeout", required_argument, NULL, OPT_FLUSH_TIMEOUT }, 184207753Smm 185207753Smm { "extreme", no_argument, NULL, 'e' }, 186207753Smm { "fast", no_argument, NULL, '0' }, 187207753Smm { "best", no_argument, NULL, '9' }, 188207753Smm 189207753Smm // Filters 190207753Smm { "lzma1", optional_argument, NULL, OPT_LZMA1 }, 191207753Smm { "lzma2", optional_argument, NULL, OPT_LZMA2 }, 192207753Smm { "x86", optional_argument, NULL, OPT_X86 }, 193207753Smm { "powerpc", optional_argument, NULL, OPT_POWERPC }, 194207753Smm { "ia64", optional_argument, NULL, OPT_IA64 }, 195207753Smm { "arm", optional_argument, NULL, OPT_ARM }, 196207753Smm { "armthumb", optional_argument, NULL, OPT_ARMTHUMB }, 197207753Smm { "sparc", optional_argument, NULL, OPT_SPARC }, 198207753Smm { "delta", optional_argument, NULL, OPT_DELTA }, 199207753Smm 200207753Smm // Other options 201207753Smm { "quiet", no_argument, NULL, 'q' }, 202207753Smm { "verbose", no_argument, NULL, 'v' }, 203207753Smm { "no-warn", no_argument, NULL, 'Q' }, 204207753Smm { "robot", no_argument, NULL, OPT_ROBOT }, 205207753Smm { "info-memory", no_argument, NULL, OPT_INFO_MEMORY }, 206207753Smm { "help", no_argument, NULL, 'h' }, 207207753Smm { "long-help", no_argument, NULL, 'H' }, 208207753Smm { "version", no_argument, NULL, 'V' }, 209207753Smm 210213700Smm { NULL, 0, NULL, 0 } 211207753Smm }; 212207753Smm 213207753Smm int c; 214207753Smm 215207753Smm while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) 216207753Smm != -1) { 217207753Smm switch (c) { 218207753Smm // Compression preset (also for decompression if --format=raw) 219207753Smm case '0': case '1': case '2': case '3': case '4': 220207753Smm case '5': case '6': case '7': case '8': case '9': 221207753Smm coder_set_preset(c - '0'); 222207753Smm break; 223207753Smm 224213700Smm // --memlimit-compress 225213700Smm case OPT_MEM_COMPRESS: 226213700Smm parse_memlimit("memlimit-compress", 227213700Smm "memlimit-compress%", optarg, 228213700Smm true, false); 229213700Smm break; 230207753Smm 231213700Smm // --memlimit-decompress 232213700Smm case OPT_MEM_DECOMPRESS: 233213700Smm parse_memlimit("memlimit-decompress", 234213700Smm "memlimit-decompress%", optarg, 235213700Smm false, true); 236207753Smm break; 237207753Smm 238213700Smm // --memlimit 239213700Smm case 'M': 240213700Smm parse_memlimit("memlimit", "memlimit%", optarg, 241213700Smm true, true); 242213700Smm break; 243213700Smm 244207753Smm // --suffix 245207753Smm case 'S': 246207753Smm suffix_set(optarg); 247207753Smm break; 248207753Smm 249207753Smm case 'T': 250292588Sdelphij // The max is from src/liblzma/common/common.h. 251292588Sdelphij hardware_threads_set(str_to_uint64("threads", 252292588Sdelphij optarg, 0, 16384)); 253207753Smm break; 254207753Smm 255207753Smm // --version 256207753Smm case 'V': 257207753Smm // This doesn't return. 258207753Smm message_version(); 259207753Smm 260207753Smm // --stdout 261207753Smm case 'c': 262207753Smm opt_stdout = true; 263207753Smm break; 264207753Smm 265207753Smm // --decompress 266207753Smm case 'd': 267207753Smm opt_mode = MODE_DECOMPRESS; 268207753Smm break; 269207753Smm 270207753Smm // --extreme 271207753Smm case 'e': 272207753Smm coder_set_extreme(); 273207753Smm break; 274207753Smm 275207753Smm // --force 276207753Smm case 'f': 277207753Smm opt_force = true; 278207753Smm break; 279207753Smm 280207753Smm // --info-memory 281207753Smm case OPT_INFO_MEMORY: 282207753Smm // This doesn't return. 283213700Smm hardware_memlimit_show(); 284207753Smm 285207753Smm // --help 286207753Smm case 'h': 287207753Smm // This doesn't return. 288207753Smm message_help(false); 289207753Smm 290207753Smm // --long-help 291207753Smm case 'H': 292207753Smm // This doesn't return. 293207753Smm message_help(true); 294207753Smm 295207753Smm // --list 296207753Smm case 'l': 297207753Smm opt_mode = MODE_LIST; 298207753Smm break; 299207753Smm 300207753Smm // --keep 301207753Smm case 'k': 302207753Smm opt_keep_original = true; 303207753Smm break; 304207753Smm 305207753Smm // --quiet 306207753Smm case 'q': 307207753Smm message_verbosity_decrease(); 308207753Smm break; 309207753Smm 310207753Smm case 'Q': 311207753Smm set_exit_no_warn(); 312207753Smm break; 313207753Smm 314207753Smm case 't': 315207753Smm opt_mode = MODE_TEST; 316207753Smm break; 317207753Smm 318207753Smm // --verbose 319207753Smm case 'v': 320207753Smm message_verbosity_increase(); 321207753Smm break; 322207753Smm 323207753Smm // --robot 324207753Smm case OPT_ROBOT: 325207753Smm opt_robot = true; 326207753Smm 327207753Smm // This is to make sure that floating point numbers 328207753Smm // always have a dot as decimal separator. 329207753Smm setlocale(LC_NUMERIC, "C"); 330207753Smm break; 331207753Smm 332207753Smm case 'z': 333207753Smm opt_mode = MODE_COMPRESS; 334207753Smm break; 335207753Smm 336207753Smm // Filter setup 337207753Smm 338207753Smm case OPT_X86: 339207753Smm coder_add_filter(LZMA_FILTER_X86, 340207753Smm options_bcj(optarg)); 341207753Smm break; 342207753Smm 343207753Smm case OPT_POWERPC: 344207753Smm coder_add_filter(LZMA_FILTER_POWERPC, 345207753Smm options_bcj(optarg)); 346207753Smm break; 347207753Smm 348207753Smm case OPT_IA64: 349207753Smm coder_add_filter(LZMA_FILTER_IA64, 350207753Smm options_bcj(optarg)); 351207753Smm break; 352207753Smm 353207753Smm case OPT_ARM: 354207753Smm coder_add_filter(LZMA_FILTER_ARM, 355207753Smm options_bcj(optarg)); 356207753Smm break; 357207753Smm 358207753Smm case OPT_ARMTHUMB: 359207753Smm coder_add_filter(LZMA_FILTER_ARMTHUMB, 360207753Smm options_bcj(optarg)); 361207753Smm break; 362207753Smm 363207753Smm case OPT_SPARC: 364207753Smm coder_add_filter(LZMA_FILTER_SPARC, 365207753Smm options_bcj(optarg)); 366207753Smm break; 367207753Smm 368207753Smm case OPT_DELTA: 369207753Smm coder_add_filter(LZMA_FILTER_DELTA, 370207753Smm options_delta(optarg)); 371207753Smm break; 372207753Smm 373207753Smm case OPT_LZMA1: 374207753Smm coder_add_filter(LZMA_FILTER_LZMA1, 375207753Smm options_lzma(optarg)); 376207753Smm break; 377207753Smm 378207753Smm case OPT_LZMA2: 379207753Smm coder_add_filter(LZMA_FILTER_LZMA2, 380207753Smm options_lzma(optarg)); 381207753Smm break; 382207753Smm 383207753Smm // Other 384207753Smm 385207753Smm // --format 386207753Smm case 'F': { 387207753Smm // Just in case, support both "lzma" and "alone" since 388207753Smm // the latter was used for forward compatibility in 389207753Smm // LZMA Utils 4.32.x. 390207753Smm static const struct { 391207753Smm char str[8]; 392207753Smm enum format_type format; 393207753Smm } types[] = { 394207753Smm { "auto", FORMAT_AUTO }, 395207753Smm { "xz", FORMAT_XZ }, 396207753Smm { "lzma", FORMAT_LZMA }, 397207753Smm { "alone", FORMAT_LZMA }, 398207753Smm // { "gzip", FORMAT_GZIP }, 399207753Smm // { "gz", FORMAT_GZIP }, 400207753Smm { "raw", FORMAT_RAW }, 401207753Smm }; 402207753Smm 403207753Smm size_t i = 0; 404207753Smm while (strcmp(types[i].str, optarg) != 0) 405207753Smm if (++i == ARRAY_SIZE(types)) 406207753Smm message_fatal(_("%s: Unknown file " 407207753Smm "format type"), 408207753Smm optarg); 409207753Smm 410207753Smm opt_format = types[i].format; 411207753Smm break; 412207753Smm } 413207753Smm 414207753Smm // --check 415207753Smm case 'C': { 416207753Smm static const struct { 417207753Smm char str[8]; 418207753Smm lzma_check check; 419207753Smm } types[] = { 420207753Smm { "none", LZMA_CHECK_NONE }, 421207753Smm { "crc32", LZMA_CHECK_CRC32 }, 422207753Smm { "crc64", LZMA_CHECK_CRC64 }, 423207753Smm { "sha256", LZMA_CHECK_SHA256 }, 424207753Smm }; 425207753Smm 426207753Smm size_t i = 0; 427207753Smm while (strcmp(types[i].str, optarg) != 0) { 428207753Smm if (++i == ARRAY_SIZE(types)) 429207753Smm message_fatal(_("%s: Unsupported " 430207753Smm "integrity " 431207753Smm "check type"), optarg); 432207753Smm } 433207753Smm 434207753Smm // Use a separate check in case we are using different 435207753Smm // liblzma than what was used to compile us. 436207753Smm if (!lzma_check_is_supported(types[i].check)) 437207753Smm message_fatal(_("%s: Unsupported integrity " 438207753Smm "check type"), optarg); 439207753Smm 440207753Smm coder_set_check(types[i].check); 441207753Smm break; 442207753Smm } 443207753Smm 444292588Sdelphij case OPT_IGNORE_CHECK: 445292588Sdelphij opt_ignore_check = true; 446292588Sdelphij break; 447292588Sdelphij 448292588Sdelphij case OPT_BLOCK_SIZE: 449292588Sdelphij opt_block_size = str_to_uint64("block-size", optarg, 450292588Sdelphij 0, LZMA_VLI_MAX); 451292588Sdelphij break; 452292588Sdelphij 453292588Sdelphij case OPT_BLOCK_LIST: { 454292588Sdelphij parse_block_list(optarg); 455292588Sdelphij break; 456292588Sdelphij } 457292588Sdelphij 458292588Sdelphij case OPT_SINGLE_STREAM: 459292588Sdelphij opt_single_stream = true; 460292588Sdelphij break; 461292588Sdelphij 462207753Smm case OPT_NO_SPARSE: 463207753Smm io_no_sparse(); 464207753Smm break; 465207753Smm 466207753Smm case OPT_FILES: 467207753Smm args->files_delim = '\n'; 468207753Smm 469207753Smm // Fall through 470207753Smm 471207753Smm case OPT_FILES0: 472207753Smm if (args->files_name != NULL) 473207753Smm message_fatal(_("Only one file can be " 474207753Smm "specified with `--files' " 475207753Smm "or `--files0'.")); 476207753Smm 477207753Smm if (optarg == NULL) { 478207753Smm args->files_name = (char *)stdin_filename; 479207753Smm args->files_file = stdin; 480207753Smm } else { 481207753Smm args->files_name = optarg; 482207753Smm args->files_file = fopen(optarg, 483207753Smm c == OPT_FILES ? "r" : "rb"); 484207753Smm if (args->files_file == NULL) 485207753Smm message_fatal("%s: %s", optarg, 486207753Smm strerror(errno)); 487207753Smm } 488207753Smm 489207753Smm break; 490207753Smm 491213700Smm case OPT_NO_ADJUST: 492213700Smm opt_auto_adjust = false; 493213700Smm break; 494213700Smm 495292588Sdelphij case OPT_FLUSH_TIMEOUT: 496292588Sdelphij opt_flush_timeout = str_to_uint64("flush-timeout", 497292588Sdelphij optarg, 0, UINT64_MAX); 498292588Sdelphij break; 499292588Sdelphij 500207753Smm default: 501207753Smm message_try_help(); 502207753Smm tuklib_exit(E_ERROR, E_ERROR, false); 503207753Smm } 504207753Smm } 505207753Smm 506207753Smm return; 507207753Smm} 508207753Smm 509207753Smm 510207753Smmstatic void 511213700Smmparse_environment(args_info *args, char *argv0, const char *varname) 512207753Smm{ 513213700Smm char *env = getenv(varname); 514207753Smm if (env == NULL) 515207753Smm return; 516207753Smm 517207753Smm // We modify the string, so make a copy of it. 518207753Smm env = xstrdup(env); 519207753Smm 520207753Smm // Calculate the number of arguments in env. argc stats at one 521207753Smm // to include space for the program name. 522207753Smm int argc = 1; 523207753Smm bool prev_was_space = true; 524207753Smm for (size_t i = 0; env[i] != '\0'; ++i) { 525207753Smm // NOTE: Cast to unsigned char is needed so that correct 526207753Smm // value gets passed to isspace(), which expects 527207753Smm // unsigned char cast to int. Casting to int is done 528207753Smm // automatically due to integer promotion, but we need to 529207753Smm // force char to unsigned char manually. Otherwise 8-bit 530207753Smm // characters would get promoted to wrong value if 531207753Smm // char is signed. 532207753Smm if (isspace((unsigned char)env[i])) { 533207753Smm prev_was_space = true; 534207753Smm } else if (prev_was_space) { 535207753Smm prev_was_space = false; 536207753Smm 537244601Smm // Keep argc small enough to fit into a signed int 538207753Smm // and to keep it usable for memory allocation. 539213700Smm if (++argc == my_min( 540213700Smm INT_MAX, SIZE_MAX / sizeof(char *))) 541207753Smm message_fatal(_("The environment variable " 542213700Smm "%s contains too many " 543213700Smm "arguments"), varname); 544207753Smm } 545207753Smm } 546207753Smm 547207753Smm // Allocate memory to hold pointers to the arguments. Add one to get 548207753Smm // space for the terminating NULL (if some systems happen to need it). 549207753Smm char **argv = xmalloc(((size_t)(argc) + 1) * sizeof(char *)); 550207753Smm argv[0] = argv0; 551207753Smm argv[argc] = NULL; 552207753Smm 553207753Smm // Go through the string again. Split the arguments using '\0' 554207753Smm // characters and add pointers to the resulting strings to argv. 555207753Smm argc = 1; 556207753Smm prev_was_space = true; 557207753Smm for (size_t i = 0; env[i] != '\0'; ++i) { 558207753Smm if (isspace((unsigned char)env[i])) { 559207753Smm prev_was_space = true; 560207753Smm env[i] = '\0'; 561207753Smm } else if (prev_was_space) { 562207753Smm prev_was_space = false; 563207753Smm argv[argc++] = env + i; 564207753Smm } 565207753Smm } 566207753Smm 567207753Smm // Parse the argument list we got from the environment. All non-option 568207753Smm // arguments i.e. filenames are ignored. 569207753Smm parse_real(args, argc, argv); 570207753Smm 571207753Smm // Reset the state of the getopt_long() so that we can parse the 572207753Smm // command line options too. There are two incompatible ways to 573207753Smm // do it. 574207753Smm#ifdef HAVE_OPTRESET 575207753Smm // BSD 576207753Smm optind = 1; 577207753Smm optreset = 1; 578207753Smm#else 579207753Smm // GNU, Solaris 580207753Smm optind = 0; 581207753Smm#endif 582207753Smm 583207753Smm // We don't need the argument list from environment anymore. 584207753Smm free(argv); 585207753Smm free(env); 586207753Smm 587207753Smm return; 588207753Smm} 589207753Smm 590207753Smm 591207753Smmextern void 592207753Smmargs_parse(args_info *args, int argc, char **argv) 593207753Smm{ 594207753Smm // Initialize those parts of *args that we need later. 595207753Smm args->files_name = NULL; 596207753Smm args->files_file = NULL; 597207753Smm args->files_delim = '\0'; 598207753Smm 599207753Smm // Check how we were called. 600207753Smm { 601207753Smm // Remove the leading path name, if any. 602207753Smm const char *name = strrchr(argv[0], '/'); 603207753Smm if (name == NULL) 604207753Smm name = argv[0]; 605207753Smm else 606207753Smm ++name; 607207753Smm 608207753Smm // NOTE: It's possible that name[0] is now '\0' if argv[0] 609207753Smm // is weird, but it doesn't matter here. 610207753Smm 611207753Smm // Look for full command names instead of substrings like 612207753Smm // "un", "cat", and "lz" to reduce possibility of false 613207753Smm // positives when the programs have been renamed. 614207753Smm if (strstr(name, "xzcat") != NULL) { 615207753Smm opt_mode = MODE_DECOMPRESS; 616207753Smm opt_stdout = true; 617207753Smm } else if (strstr(name, "unxz") != NULL) { 618207753Smm opt_mode = MODE_DECOMPRESS; 619207753Smm } else if (strstr(name, "lzcat") != NULL) { 620207753Smm opt_format = FORMAT_LZMA; 621207753Smm opt_mode = MODE_DECOMPRESS; 622207753Smm opt_stdout = true; 623207753Smm } else if (strstr(name, "unlzma") != NULL) { 624207753Smm opt_format = FORMAT_LZMA; 625207753Smm opt_mode = MODE_DECOMPRESS; 626207753Smm } else if (strstr(name, "lzma") != NULL) { 627207753Smm opt_format = FORMAT_LZMA; 628207753Smm } 629207753Smm } 630207753Smm 631213700Smm // First the flags from the environment 632213700Smm parse_environment(args, argv[0], "XZ_DEFAULTS"); 633213700Smm parse_environment(args, argv[0], "XZ_OPT"); 634207753Smm 635207753Smm // Then from the command line 636207753Smm parse_real(args, argc, argv); 637207753Smm 638312518Sdelphij // If encoder or decoder support was omitted at build time, 639312518Sdelphij // show an error now so that the rest of the code can rely on 640312518Sdelphij // that whatever is in opt_mode is also supported. 641312518Sdelphij#ifndef HAVE_ENCODERS 642312518Sdelphij if (opt_mode == MODE_COMPRESS) 643312518Sdelphij message_fatal(_("Compression support was disabled " 644312518Sdelphij "at build time")); 645312518Sdelphij#endif 646312518Sdelphij#ifndef HAVE_DECODERS 647312518Sdelphij // Even MODE_LIST cannot work without decoder support so MODE_COMPRESS 648312518Sdelphij // is the only valid choice. 649312518Sdelphij if (opt_mode != MODE_COMPRESS) 650312518Sdelphij message_fatal(_("Decompression support was disabled " 651312518Sdelphij "at build time")); 652312518Sdelphij#endif 653312518Sdelphij 654207753Smm // Never remove the source file when the destination is not on disk. 655207753Smm // In test mode the data is written nowhere, but setting opt_stdout 656207753Smm // will make the rest of the code behave well. 657207753Smm if (opt_stdout || opt_mode == MODE_TEST) { 658207753Smm opt_keep_original = true; 659207753Smm opt_stdout = true; 660207753Smm } 661207753Smm 662207753Smm // When compressing, if no --format flag was used, or it 663207753Smm // was --format=auto, we compress to the .xz format. 664207753Smm if (opt_mode == MODE_COMPRESS && opt_format == FORMAT_AUTO) 665207753Smm opt_format = FORMAT_XZ; 666207753Smm 667207753Smm // Compression settings need to be validated (options themselves and 668207753Smm // their memory usage) when compressing to any file format. It has to 669207753Smm // be done also when uncompressing raw data, since for raw decoding 670207753Smm // the options given on the command line are used to know what kind 671207753Smm // of raw data we are supposed to decode. 672207753Smm if (opt_mode == MODE_COMPRESS || opt_format == FORMAT_RAW) 673207753Smm coder_set_compression_settings(); 674207753Smm 675207753Smm // If no filenames are given, use stdin. 676207753Smm if (argv[optind] == NULL && args->files_name == NULL) { 677207753Smm // We don't modify or free() the "-" constant. The caller 678207753Smm // modifies this so don't make the struct itself const. 679207753Smm static char *names_stdin[2] = { (char *)"-", NULL }; 680207753Smm args->arg_names = names_stdin; 681207753Smm args->arg_count = 1; 682207753Smm } else { 683207753Smm // We got at least one filename from the command line, or 684207753Smm // --files or --files0 was specified. 685207753Smm args->arg_names = argv + optind; 686207753Smm args->arg_count = argc - optind; 687207753Smm } 688207753Smm 689207753Smm return; 690207753Smm} 691292588Sdelphij 692292588Sdelphij 693292588Sdelphij#ifndef NDEBUG 694292588Sdelphijextern void 695292588Sdelphijargs_free(void) 696292588Sdelphij{ 697292588Sdelphij free(opt_block_list); 698292588Sdelphij return; 699292588Sdelphij} 700292588Sdelphij#endif 701