1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief Argument parsing
6 /// \note Filter-specific options parsing is in options.c.
8 // Author: Lasse Collin
10 // This file has been put into the public domain.
11 // You can do whatever you want with this file.
13 ///////////////////////////////////////////////////////////////////////////////
21 bool opt_stdout = false;
22 bool opt_force = false;
23 bool opt_keep_original = false;
24 bool opt_robot = false;
26 // We don't modify or free() this, but we need to assign it in some
27 // non-const pointers.
28 const char *stdin_filename = "(stdin)";
32 parse_real(args_info *args, int argc, char **argv)
52 static const char short_opts[]
53 = "cC:defF:hHlkM:qQrS:tT:vVz0123456789";
55 static const struct option long_opts[] = {
57 { "compress", no_argument, NULL, 'z' },
58 { "decompress", no_argument, NULL, 'd' },
59 { "uncompress", no_argument, NULL, 'd' },
60 { "test", no_argument, NULL, 't' },
61 { "list", no_argument, NULL, 'l' },
63 // Operation modifiers
64 { "keep", no_argument, NULL, 'k' },
65 { "force", no_argument, NULL, 'f' },
66 { "stdout", no_argument, NULL, 'c' },
67 { "to-stdout", no_argument, NULL, 'c' },
68 { "no-sparse", no_argument, NULL, OPT_NO_SPARSE },
69 { "suffix", required_argument, NULL, 'S' },
70 // { "recursive", no_argument, NULL, 'r' }, // TODO
71 { "files", optional_argument, NULL, OPT_FILES },
72 { "files0", optional_argument, NULL, OPT_FILES0 },
74 // Basic compression settings
75 { "format", required_argument, NULL, 'F' },
76 { "check", required_argument, NULL, 'C' },
77 { "memory", required_argument, NULL, 'M' },
78 { "threads", required_argument, NULL, 'T' },
80 { "extreme", no_argument, NULL, 'e' },
81 { "fast", no_argument, NULL, '0' },
82 { "best", no_argument, NULL, '9' },
85 { "lzma1", optional_argument, NULL, OPT_LZMA1 },
86 { "lzma2", optional_argument, NULL, OPT_LZMA2 },
87 { "x86", optional_argument, NULL, OPT_X86 },
88 { "powerpc", optional_argument, NULL, OPT_POWERPC },
89 { "ia64", optional_argument, NULL, OPT_IA64 },
90 { "arm", optional_argument, NULL, OPT_ARM },
91 { "armthumb", optional_argument, NULL, OPT_ARMTHUMB },
92 { "sparc", optional_argument, NULL, OPT_SPARC },
93 { "delta", optional_argument, NULL, OPT_DELTA },
96 { "quiet", no_argument, NULL, 'q' },
97 { "verbose", no_argument, NULL, 'v' },
98 { "no-warn", no_argument, NULL, 'Q' },
99 { "robot", no_argument, NULL, OPT_ROBOT },
100 { "info-memory", no_argument, NULL, OPT_INFO_MEMORY },
101 { "help", no_argument, NULL, 'h' },
102 { "long-help", no_argument, NULL, 'H' },
103 { "version", no_argument, NULL, 'V' },
110 while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL))
113 // Compression preset (also for decompression if --format=raw)
114 case '0': case '1': case '2': case '3': case '4':
115 case '5': case '6': case '7': case '8': case '9':
116 coder_set_preset(c - '0');
121 // Support specifying the limit as a percentage of
122 // installed physical RAM.
123 size_t len = strlen(optarg);
124 if (len > 0 && optarg[len - 1] == '%') {
125 optarg[len - 1] = '\0';
126 hardware_memlimit_set_percentage(
128 "memory%", optarg, 1, 100));
130 // On 32-bit systems, SIZE_MAX would make more
131 // sense than UINT64_MAX. But use UINT64_MAX
132 // still so that scripts that assume > 4 GiB
133 // values don't break.
134 hardware_memlimit_set(str_to_uint64(
148 hardware_threadlimit_set(str_to_uint64(
149 "threads", optarg, 0, UINT32_MAX));
154 // This doesn't return.
164 opt_mode = MODE_DECOMPRESS;
178 case OPT_INFO_MEMORY:
179 // This doesn't return.
184 // This doesn't return.
189 // This doesn't return.
194 opt_mode = MODE_LIST;
199 opt_keep_original = true;
204 message_verbosity_decrease();
212 opt_mode = MODE_TEST;
217 message_verbosity_increase();
224 // This is to make sure that floating point numbers
225 // always have a dot as decimal separator.
226 setlocale(LC_NUMERIC, "C");
230 opt_mode = MODE_COMPRESS;
236 coder_add_filter(LZMA_FILTER_X86,
237 options_bcj(optarg));
241 coder_add_filter(LZMA_FILTER_POWERPC,
242 options_bcj(optarg));
246 coder_add_filter(LZMA_FILTER_IA64,
247 options_bcj(optarg));
251 coder_add_filter(LZMA_FILTER_ARM,
252 options_bcj(optarg));
256 coder_add_filter(LZMA_FILTER_ARMTHUMB,
257 options_bcj(optarg));
261 coder_add_filter(LZMA_FILTER_SPARC,
262 options_bcj(optarg));
266 coder_add_filter(LZMA_FILTER_DELTA,
267 options_delta(optarg));
271 coder_add_filter(LZMA_FILTER_LZMA1,
272 options_lzma(optarg));
276 coder_add_filter(LZMA_FILTER_LZMA2,
277 options_lzma(optarg));
284 // Just in case, support both "lzma" and "alone" since
285 // the latter was used for forward compatibility in
286 // LZMA Utils 4.32.x.
287 static const struct {
289 enum format_type format;
291 { "auto", FORMAT_AUTO },
293 { "lzma", FORMAT_LZMA },
294 { "alone", FORMAT_LZMA },
295 // { "gzip", FORMAT_GZIP },
296 // { "gz", FORMAT_GZIP },
297 { "raw", FORMAT_RAW },
301 while (strcmp(types[i].str, optarg) != 0)
302 if (++i == ARRAY_SIZE(types))
303 message_fatal(_("%s: Unknown file "
307 opt_format = types[i].format;
313 static const struct {
317 { "none", LZMA_CHECK_NONE },
318 { "crc32", LZMA_CHECK_CRC32 },
319 { "crc64", LZMA_CHECK_CRC64 },
320 { "sha256", LZMA_CHECK_SHA256 },
324 while (strcmp(types[i].str, optarg) != 0) {
325 if (++i == ARRAY_SIZE(types))
326 message_fatal(_("%s: Unsupported "
328 "check type"), optarg);
331 // Use a separate check in case we are using different
332 // liblzma than what was used to compile us.
333 if (!lzma_check_is_supported(types[i].check))
334 message_fatal(_("%s: Unsupported integrity "
335 "check type"), optarg);
337 coder_set_check(types[i].check);
346 args->files_delim = '\n';
351 if (args->files_name != NULL)
352 message_fatal(_("Only one file can be "
353 "specified with `--files' "
356 if (optarg == NULL) {
357 args->files_name = (char *)stdin_filename;
358 args->files_file = stdin;
360 args->files_name = optarg;
361 args->files_file = fopen(optarg,
362 c == OPT_FILES ? "r" : "rb");
363 if (args->files_file == NULL)
364 message_fatal("%s: %s", optarg,
372 tuklib_exit(E_ERROR, E_ERROR, false);
381 parse_environment(args_info *args, char *argv0)
383 char *env = getenv("XZ_OPT");
387 // We modify the string, so make a copy of it.
390 // Calculate the number of arguments in env. argc stats at one
391 // to include space for the program name.
393 bool prev_was_space = true;
394 for (size_t i = 0; env[i] != '\0'; ++i) {
395 // NOTE: Cast to unsigned char is needed so that correct
396 // value gets passed to isspace(), which expects
397 // unsigned char cast to int. Casting to int is done
398 // automatically due to integer promotion, but we need to
399 // force char to unsigned char manually. Otherwise 8-bit
400 // characters would get promoted to wrong value if
402 if (isspace((unsigned char)env[i])) {
403 prev_was_space = true;
404 } else if (prev_was_space) {
405 prev_was_space = false;
407 // Keep argc small enough to fit into a singed int
408 // and to keep it usable for memory allocation.
409 if (++argc == my_min(
410 INT_MAX, SIZE_MAX / sizeof(char *)))
411 message_fatal(_("The environment variable "
412 "XZ_OPT contains too many "
417 // Allocate memory to hold pointers to the arguments. Add one to get
418 // space for the terminating NULL (if some systems happen to need it).
419 char **argv = xmalloc(((size_t)(argc) + 1) * sizeof(char *));
423 // Go through the string again. Split the arguments using '\0'
424 // characters and add pointers to the resulting strings to argv.
426 prev_was_space = true;
427 for (size_t i = 0; env[i] != '\0'; ++i) {
428 if (isspace((unsigned char)env[i])) {
429 prev_was_space = true;
431 } else if (prev_was_space) {
432 prev_was_space = false;
433 argv[argc++] = env + i;
437 // Parse the argument list we got from the environment. All non-option
438 // arguments i.e. filenames are ignored.
439 parse_real(args, argc, argv);
441 // Reset the state of the getopt_long() so that we can parse the
442 // command line options too. There are two incompatible ways to
453 // We don't need the argument list from environment anymore.
462 args_parse(args_info *args, int argc, char **argv)
464 // Initialize those parts of *args that we need later.
465 args->files_name = NULL;
466 args->files_file = NULL;
467 args->files_delim = '\0';
469 // Check how we were called.
471 // Remove the leading path name, if any.
472 const char *name = strrchr(argv[0], '/');
478 // NOTE: It's possible that name[0] is now '\0' if argv[0]
479 // is weird, but it doesn't matter here.
481 // Look for full command names instead of substrings like
482 // "un", "cat", and "lz" to reduce possibility of false
483 // positives when the programs have been renamed.
484 if (strstr(name, "xzcat") != NULL) {
485 opt_mode = MODE_DECOMPRESS;
487 } else if (strstr(name, "unxz") != NULL) {
488 opt_mode = MODE_DECOMPRESS;
489 } else if (strstr(name, "lzcat") != NULL) {
490 opt_format = FORMAT_LZMA;
491 opt_mode = MODE_DECOMPRESS;
493 } else if (strstr(name, "unlzma") != NULL) {
494 opt_format = FORMAT_LZMA;
495 opt_mode = MODE_DECOMPRESS;
496 } else if (strstr(name, "lzma") != NULL) {
497 opt_format = FORMAT_LZMA;
501 // First the flags from environment
502 parse_environment(args, argv[0]);
504 // Then from the command line
505 parse_real(args, argc, argv);
507 // Never remove the source file when the destination is not on disk.
508 // In test mode the data is written nowhere, but setting opt_stdout
509 // will make the rest of the code behave well.
510 if (opt_stdout || opt_mode == MODE_TEST) {
511 opt_keep_original = true;
515 // When compressing, if no --format flag was used, or it
516 // was --format=auto, we compress to the .xz format.
517 if (opt_mode == MODE_COMPRESS && opt_format == FORMAT_AUTO)
518 opt_format = FORMAT_XZ;
520 // Compression settings need to be validated (options themselves and
521 // their memory usage) when compressing to any file format. It has to
522 // be done also when uncompressing raw data, since for raw decoding
523 // the options given on the command line are used to know what kind
524 // of raw data we are supposed to decode.
525 if (opt_mode == MODE_COMPRESS || opt_format == FORMAT_RAW)
526 coder_set_compression_settings();
528 // If no filenames are given, use stdin.
529 if (argv[optind] == NULL && args->files_name == NULL) {
530 // We don't modify or free() the "-" constant. The caller
531 // modifies this so don't make the struct itself const.
532 static char *names_stdin[2] = { (char *)"-", NULL };
533 args->arg_names = names_stdin;
536 // We got at least one filename from the command line, or
537 // --files or --files0 was specified.
538 args->arg_names = argv + optind;
539 args->arg_count = argc - optind;