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;
25 // We don't modify or free() this, but we need to assign it in some
26 // non-const pointers.
27 const char *stdin_filename = "(stdin)";
31 parse_real(args_info *args, int argc, char **argv)
34 OPT_SUBBLOCK = INT_MIN,
49 static const char short_opts[] = "cC:defF:hHlkM:qrS:tT:vVz0123456789";
51 static const struct option long_opts[] = {
53 { "compress", no_argument, NULL, 'z' },
54 { "decompress", no_argument, NULL, 'd' },
55 { "uncompress", no_argument, NULL, 'd' },
56 { "test", no_argument, NULL, 't' },
57 { "list", no_argument, NULL, 'l' },
59 // Operation modifiers
60 { "keep", no_argument, NULL, 'k' },
61 { "force", no_argument, NULL, 'f' },
62 { "stdout", no_argument, NULL, 'c' },
63 { "to-stdout", no_argument, NULL, 'c' },
64 { "suffix", required_argument, NULL, 'S' },
65 // { "recursive", no_argument, NULL, 'r' }, // TODO
66 { "files", optional_argument, NULL, OPT_FILES },
67 { "files0", optional_argument, NULL, OPT_FILES0 },
69 // Basic compression settings
70 { "format", required_argument, NULL, 'F' },
71 { "check", required_argument, NULL, 'C' },
72 { "memory", required_argument, NULL, 'M' },
73 { "threads", required_argument, NULL, 'T' },
75 { "extreme", no_argument, NULL, 'e' },
76 { "fast", no_argument, NULL, '0' },
77 { "best", no_argument, NULL, '9' },
80 { "lzma1", optional_argument, NULL, OPT_LZMA1 },
81 { "lzma2", optional_argument, NULL, OPT_LZMA2 },
82 { "x86", no_argument, NULL, OPT_X86 },
83 { "bcj", no_argument, NULL, OPT_X86 },
84 { "powerpc", no_argument, NULL, OPT_POWERPC },
85 { "ppc", no_argument, NULL, OPT_POWERPC },
86 { "ia64", no_argument, NULL, OPT_IA64 },
87 { "itanium", no_argument, NULL, OPT_IA64 },
88 { "arm", no_argument, NULL, OPT_ARM },
89 { "armthumb", no_argument, NULL, OPT_ARMTHUMB },
90 { "sparc", no_argument, NULL, OPT_SPARC },
91 { "delta", optional_argument, NULL, OPT_DELTA },
92 { "subblock", optional_argument, NULL, OPT_SUBBLOCK },
95 { "quiet", no_argument, NULL, 'q' },
96 { "verbose", no_argument, NULL, 'v' },
97 { "help", no_argument, NULL, 'h' },
98 { "long-help", no_argument, NULL, 'H' },
99 { "version", no_argument, NULL, 'V' },
106 while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL))
109 // Compression preset (also for decompression if --format=raw)
110 case '0': case '1': case '2': case '3': case '4':
111 case '5': case '6': case '7': case '8': case '9':
112 coder_set_preset(c - '0');
117 // Support specifying the limit as a percentage of
118 // installed physical RAM.
119 size_t len = strlen(optarg);
120 if (len > 0 && optarg[len - 1] == '%') {
121 optarg[len - 1] = '\0';
122 hardware_memlimit_set_percentage(
124 "memory%", optarg, 1, 100));
126 // On 32-bit systems, SIZE_MAX would make more
127 // sense than UINT64_MAX. But use UINT64_MAX
128 // still so that scripts that assume > 4 GiB
129 // values don't break.
130 hardware_memlimit_set(str_to_uint64(
144 hardware_threadlimit_set(str_to_uint64(
145 "threads", optarg, 0, UINT32_MAX));
150 // This doesn't return.
160 opt_mode = MODE_DECOMPRESS;
175 // This doesn't return.
180 // This doesn't return.
185 opt_mode = MODE_LIST;
190 opt_keep_original = true;
195 message_verbosity_decrease();
199 opt_mode = MODE_TEST;
204 message_verbosity_increase();
208 opt_mode = MODE_COMPRESS;
214 coder_add_filter(LZMA_FILTER_SUBBLOCK,
215 options_subblock(optarg));
219 coder_add_filter(LZMA_FILTER_X86, NULL);
223 coder_add_filter(LZMA_FILTER_POWERPC, NULL);
227 coder_add_filter(LZMA_FILTER_IA64, NULL);
231 coder_add_filter(LZMA_FILTER_ARM, NULL);
235 coder_add_filter(LZMA_FILTER_ARMTHUMB, NULL);
239 coder_add_filter(LZMA_FILTER_SPARC, NULL);
243 coder_add_filter(LZMA_FILTER_DELTA,
244 options_delta(optarg));
248 coder_add_filter(LZMA_FILTER_LZMA1,
249 options_lzma(optarg));
253 coder_add_filter(LZMA_FILTER_LZMA2,
254 options_lzma(optarg));
261 // Just in case, support both "lzma" and "alone" since
262 // the latter was used for forward compatibility in
263 // LZMA Utils 4.32.x.
264 static const struct {
266 enum format_type format;
268 { "auto", FORMAT_AUTO },
270 { "lzma", FORMAT_LZMA },
271 { "alone", FORMAT_LZMA },
272 // { "gzip", FORMAT_GZIP },
273 // { "gz", FORMAT_GZIP },
274 { "raw", FORMAT_RAW },
278 while (strcmp(types[i].str, optarg) != 0)
279 if (++i == ARRAY_SIZE(types))
280 message_fatal(_("%s: Unknown file "
284 opt_format = types[i].format;
290 static const struct {
294 { "none", LZMA_CHECK_NONE },
295 { "crc32", LZMA_CHECK_CRC32 },
296 { "crc64", LZMA_CHECK_CRC64 },
297 { "sha256", LZMA_CHECK_SHA256 },
301 while (strcmp(types[i].str, optarg) != 0) {
302 if (++i == ARRAY_SIZE(types))
303 message_fatal(_("%s: Unsupported "
305 "check type"), optarg);
308 // Use a separate check in case we are using different
309 // liblzma than what was used to compile us.
310 if (!lzma_check_is_supported(types[i].check))
311 message_fatal(_("%s: Unsupported integrity "
312 "check type"), optarg);
314 coder_set_check(types[i].check);
319 args->files_delim = '\n';
324 if (args->files_name != NULL)
325 message_fatal(_("Only one file can be "
326 "specified with `--files'"
329 if (optarg == NULL) {
330 args->files_name = (char *)stdin_filename;
331 args->files_file = stdin;
333 args->files_name = optarg;
334 args->files_file = fopen(optarg,
335 c == OPT_FILES ? "r" : "rb");
336 if (args->files_file == NULL)
337 message_fatal("%s: %s", optarg,
354 parse_environment(args_info *args, char *argv0)
356 char *env = getenv("XZ_OPT");
360 // We modify the string, so make a copy of it.
363 // Calculate the number of arguments in env. argc stats at one
364 // to include space for the program name.
366 bool prev_was_space = true;
367 for (size_t i = 0; env[i] != '\0'; ++i) {
368 if (isspace(env[i])) {
369 prev_was_space = true;
370 } else if (prev_was_space) {
371 prev_was_space = false;
373 // Keep argc small enough to fit into a singed int
374 // and to keep it usable for memory allocation.
375 if (++argc == MIN(INT_MAX, SIZE_MAX / sizeof(char *)))
376 message_fatal(_("The environment variable "
377 "XZ_OPT contains too many "
382 // Allocate memory to hold pointers to the arguments. Add one to get
383 // space for the terminating NULL (if some systems happen to need it).
384 char **argv = xmalloc(((size_t)(argc) + 1) * sizeof(char *));
388 // Go through the string again. Split the arguments using '\0'
389 // characters and add pointers to the resulting strings to argv.
391 prev_was_space = true;
392 for (size_t i = 0; env[i] != '\0'; ++i) {
393 if (isspace(env[i])) {
394 prev_was_space = true;
396 } else if (prev_was_space) {
397 prev_was_space = false;
398 argv[argc++] = env + i;
402 // Parse the argument list we got from the environment. All non-option
403 // arguments i.e. filenames are ignored.
404 parse_real(args, argc, argv);
406 // Reset the state of the getopt_long() so that we can parse the
407 // command line options too. There are two incompatible ways to
418 // We don't need the argument list from environment anymore.
427 args_parse(args_info *args, int argc, char **argv)
429 // Initialize those parts of *args that we need later.
430 args->files_name = NULL;
431 args->files_file = NULL;
432 args->files_delim = '\0';
434 // Check how we were called.
437 // We adjusted argv[0] in the beginning of main() so we don't
438 // need to do anything here.
439 const char *name = argv[0];
441 // Remove the leading path name, if any.
442 const char *name = strrchr(argv[0], '/');
449 // NOTE: It's possible that name[0] is now '\0' if argv[0]
450 // is weird, but it doesn't matter here.
452 // If the command name contains "lz",
453 // it implies --format=lzma.
454 if (strstr(name, "lz") != NULL)
455 opt_format = FORMAT_LZMA;
458 if (strstr(name, "cat") != NULL) {
459 // Imply --decompress --stdout
460 opt_mode = MODE_DECOMPRESS;
462 } else if (strstr(name, "un") != NULL) {
463 // Imply --decompress
464 opt_mode = MODE_DECOMPRESS;
468 // First the flags from environment
469 parse_environment(args, argv[0]);
471 // Then from the command line
473 parse_real(args, argc, argv);
475 // Never remove the source file when the destination is not on disk.
476 // In test mode the data is written nowhere, but setting opt_stdout
477 // will make the rest of the code behave well.
478 if (opt_stdout || opt_mode == MODE_TEST) {
479 opt_keep_original = true;
483 // When compressing, if no --format flag was used, or it
484 // was --format=auto, we compress to the .xz format.
485 if (opt_mode == MODE_COMPRESS && opt_format == FORMAT_AUTO)
486 opt_format = FORMAT_XZ;
488 // Compression settings need to be validated (options themselves and
489 // their memory usage) when compressing to any file format. It has to
490 // be done also when uncompressing raw data, since for raw decoding
491 // the options given on the command line are used to know what kind
492 // of raw data we are supposed to decode.
493 if (opt_mode == MODE_COMPRESS || opt_format == FORMAT_RAW)
494 coder_set_compression_settings();
496 // If no filenames are given, use stdin.
497 if (argv[optind] == NULL && args->files_name == NULL) {
498 // We don't modify or free() the "-" constant. The caller
499 // modifies this so don't make the struct itself const.
500 static char *names_stdin[2] = { (char *)"-", NULL };
501 args->arg_names = names_stdin;
504 // We got at least one filename from the command line, or
505 // --files or --files0 was specified.
506 args->arg_names = argv + optind;
507 args->arg_count = argc - optind;