1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief Argument parsing
6 /// \note Filter-specific options parsing is in options.c.
8 // Copyright (C) 2007 Lasse Collin
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
20 ///////////////////////////////////////////////////////////////////////////////
28 enum tool_mode opt_mode = MODE_COMPRESS;
29 enum header_type opt_header = HEADER_AUTO;
31 char *opt_suffix = NULL;
33 char *opt_files_name = NULL;
34 char opt_files_split = '\0';
35 FILE *opt_files_file = NULL;
37 bool opt_stdout = false;
38 bool opt_force = false;
39 bool opt_keep_original = false;
40 bool opt_preserve_name = false;
42 lzma_check opt_check = LZMA_CHECK_CRC64;
43 lzma_filter opt_filters[8];
45 // We don't modify or free() this, but we need to assign it in some
46 // non-const pointers.
47 const char *stdin_filename = "(stdin)";
49 static size_t preset_number = 7 - 1;
50 static bool preset_default = true;
51 static size_t filter_count = 0;
55 OPT_SUBBLOCK = INT_MIN,
71 static const char short_opts[] = "cC:dfF:hlLkM:qrS:tT:vVz123456789";
74 static const struct option long_opts[] = {
76 { "fast", no_argument, NULL, '1' },
77 { "best", no_argument, NULL, '9' },
78 { "memory", required_argument, NULL, 'M' },
79 { "name", no_argument, NULL, 'N' },
80 { "suffix", required_argument, NULL, 'S' },
81 { "threads", required_argument, NULL, 'T' },
82 { "version", no_argument, NULL, 'V' },
83 { "stdout", no_argument, NULL, 'c' },
84 { "to-stdout", no_argument, NULL, 'c' },
85 { "decompress", no_argument, NULL, 'd' },
86 { "uncompress", no_argument, NULL, 'd' },
87 { "force", no_argument, NULL, 'f' },
88 { "help", no_argument, NULL, 'h' },
89 { "list", no_argument, NULL, 'l' },
90 { "info", no_argument, NULL, 'l' },
91 { "keep", no_argument, NULL, 'k' },
92 { "no-name", no_argument, NULL, 'n' },
93 { "quiet", no_argument, NULL, 'q' },
94 // { "recursive", no_argument, NULL, 'r' }, // TODO
95 { "test", no_argument, NULL, 't' },
96 { "verbose", no_argument, NULL, 'v' },
97 { "compress", no_argument, NULL, 'z' },
100 { "subblock", optional_argument, NULL, OPT_SUBBLOCK },
101 { "x86", no_argument, NULL, OPT_X86 },
102 { "bcj", no_argument, NULL, OPT_X86 },
103 { "powerpc", no_argument, NULL, OPT_POWERPC },
104 { "ppc", no_argument, NULL, OPT_POWERPC },
105 { "ia64", no_argument, NULL, OPT_IA64 },
106 { "itanium", no_argument, NULL, OPT_IA64 },
107 { "arm", no_argument, NULL, OPT_ARM },
108 { "armthumb", no_argument, NULL, OPT_ARMTHUMB },
109 { "sparc", no_argument, NULL, OPT_SPARC },
110 { "delta", optional_argument, NULL, OPT_DELTA },
111 { "lzma1", optional_argument, NULL, OPT_LZMA1 },
112 { "lzma2", optional_argument, NULL, OPT_LZMA2 },
115 { "format", required_argument, NULL, 'F' },
116 { "check", required_argument, NULL, 'C' },
117 { "files", optional_argument, NULL, OPT_FILES },
118 { "files0", optional_argument, NULL, OPT_FILES0 },
125 add_filter(lzma_vli id, const char *opt_str)
127 if (filter_count == LZMA_BLOCK_FILTERS_MAX) {
128 errmsg(V_ERROR, _("Maximum number of filters is seven"));
132 opt_filters[filter_count].id = id;
135 case LZMA_FILTER_SUBBLOCK:
136 opt_filters[filter_count].options
137 = parse_options_subblock(opt_str);
140 case LZMA_FILTER_DELTA:
141 opt_filters[filter_count].options
142 = parse_options_delta(opt_str);
145 case LZMA_FILTER_LZMA1:
146 case LZMA_FILTER_LZMA2:
147 opt_filters[filter_count].options
148 = parse_options_lzma(opt_str);
152 assert(opt_str == NULL);
153 opt_filters[filter_count].options = NULL;
158 preset_default = false;
164 parse_real(int argc, char **argv)
168 while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL))
173 case '1': case '2': case '3': case '4':
174 case '5': case '6': case '7': case '8': case '9':
175 preset_number = c - '1';
176 preset_default = false;
181 opt_memory = str_to_uint64("memory", optarg,
186 opt_preserve_name = true;
191 // Empty suffix and suffixes having a slash are
192 // rejected. Such suffixes would break things later.
193 if (optarg[0] == '\0' || strchr(optarg, '/') != NULL) {
194 errmsg(V_ERROR, _("%s: Invalid filename "
200 opt_suffix = xstrdup(optarg);
204 opt_threads = str_to_uint64("threads", optarg,
210 // This doesn't return.
220 opt_mode = MODE_DECOMPRESS;
230 // This doesn't return.
235 opt_mode = MODE_LIST;
240 opt_keep_original = true;
244 opt_preserve_name = false;
249 if (verbosity > V_SILENT)
255 opt_mode = MODE_TEST;
260 if (verbosity < V_DEBUG)
266 opt_mode = MODE_COMPRESS;
272 add_filter(LZMA_FILTER_SUBBLOCK, optarg);
276 add_filter(LZMA_FILTER_X86, NULL);
280 add_filter(LZMA_FILTER_POWERPC, NULL);
284 add_filter(LZMA_FILTER_IA64, NULL);
288 add_filter(LZMA_FILTER_ARM, NULL);
292 add_filter(LZMA_FILTER_ARMTHUMB, NULL);
296 add_filter(LZMA_FILTER_SPARC, NULL);
300 add_filter(LZMA_FILTER_DELTA, optarg);
304 add_filter(LZMA_FILTER_LZMA1, optarg);
308 add_filter(LZMA_FILTER_LZMA2, optarg);
315 static const char *types[] = {
325 while (strcmp(types[opt_header], optarg) != 0) {
326 if (types[++opt_header] == NULL) {
327 errmsg(V_ERROR, _("%s: Unknown file "
339 static const struct {
343 { "none", LZMA_CHECK_NONE },
344 { "crc32", LZMA_CHECK_CRC32 },
345 { "crc64", LZMA_CHECK_CRC64 },
346 { "sha256", LZMA_CHECK_SHA256 },
351 while (strcmp(types[i].str, optarg) != 0) {
352 if (types[++i].str == NULL) {
353 errmsg(V_ERROR, _("%s: Unknown "
360 opt_check = types[i].value;
365 opt_files_split = '\n';
370 if (opt_files_name != NULL) {
371 errmsg(V_ERROR, _("Only one file can be "
372 "specified with `--files'"
377 if (optarg == NULL) {
378 opt_files_name = (char *)stdin_filename;
379 opt_files_file = stdin;
381 opt_files_name = optarg;
382 opt_files_file = fopen(optarg,
383 c == OPT_FILES ? "r" : "rb");
384 if (opt_files_file == NULL) {
385 errmsg(V_ERROR, "%s: %s", optarg,
404 parse_environment(void)
406 char *env = getenv("LZMA_OPT");
412 // Calculate the number of arguments in env.
413 unsigned int argc = 1;
414 bool prev_was_space = true;
415 for (size_t i = 0; env[i] != '\0'; ++i) {
416 if (isspace(env[i])) {
417 prev_was_space = true;
418 } else if (prev_was_space) {
419 prev_was_space = false;
420 if (++argc > (unsigned int)(INT_MAX)) {
421 errmsg(V_ERROR, _("The environment variable "
422 "LZMA_OPT contains too many "
429 char **argv = xmalloc((argc + 1) * sizeof(char*));
434 prev_was_space = true;
435 for (size_t i = 0; env[i] != '\0'; ++i) {
436 if (isspace(env[i])) {
437 prev_was_space = true;
438 } else if (prev_was_space) {
439 prev_was_space = false;
440 argv[argc++] = env + i;
444 parse_real((int)(argc), argv);
453 set_compression_settings(void)
455 static lzma_options_lzma opt_lzma;
457 if (filter_count == 0) {
458 if (lzma_lzma_preset(&opt_lzma, preset_number)) {
459 errmsg(V_ERROR, _("Internal error (bug)"));
463 opt_filters[0].id = opt_header == HEADER_ALONE
464 ? LZMA_FILTER_LZMA1 : LZMA_FILTER_LZMA2;
465 opt_filters[0].options = &opt_lzma;
469 // Terminate the filter options array.
470 opt_filters[filter_count].id = LZMA_VLI_UNKNOWN;
472 // If we are using the LZMA_Alone format, allow exactly one filter
473 // which has to be LZMA.
474 if (opt_header == HEADER_ALONE && (filter_count != 1
475 || opt_filters[0].id != LZMA_FILTER_LZMA1)) {
476 errmsg(V_ERROR, _("With --format=alone only the LZMA1 filter "
481 // TODO: liblzma probably needs an API to validate the filter chain.
483 // If using --format=raw, we can be decoding.
484 uint64_t memory_usage = opt_mode == MODE_COMPRESS
485 ? lzma_memusage_encoder(opt_filters)
486 : lzma_memusage_decoder(opt_filters);
488 // Don't go over the memory limits when the default
490 if (preset_default) {
491 while (memory_usage > opt_memory) {
492 if (preset_number == 0) {
493 errmsg(V_ERROR, _("Memory usage limit is too "
494 "small for any internal "
499 if (lzma_lzma_preset(&opt_lzma, --preset_number)) {
500 errmsg(V_ERROR, _("Internal error (bug)"));
504 memory_usage = lzma_memusage_encoder(opt_filters);
507 if (memory_usage > opt_memory) {
508 errmsg(V_ERROR, _("Memory usage limit is too small "
509 "for the given filter setup"));
514 // Limit the number of worked threads so that memory usage
515 // limit isn't exceeded.
516 assert(memory_usage > 0);
517 size_t thread_limit = opt_memory / memory_usage;
518 if (thread_limit == 0)
521 if (opt_threads > thread_limit)
522 opt_threads = thread_limit;
529 parse_args(int argc, char **argv)
531 // Check how we were called.
533 const char *name = str_filename(argv[0]);
535 if (strstr(name, "cat") != NULL) {
536 opt_mode = MODE_DECOMPRESS;
538 } else if (strstr(name, "un") != NULL) {
539 opt_mode = MODE_DECOMPRESS;
544 // First the flags from environment
547 // Then from the command line
549 parse_real(argc, argv);
551 // Never remove the source file when the destination is not on disk.
552 // In test mode the data is written nowhere, but setting opt_stdout
553 // will make the rest of the code behave well.
554 if (opt_stdout || opt_mode == MODE_TEST) {
555 opt_keep_original = true;
559 if (opt_mode == MODE_COMPRESS || opt_header == HEADER_RAW)
560 set_compression_settings();
562 // If no filenames are given, use stdin.
563 if (argv[optind] == NULL && opt_files_name == NULL) {
564 // We don't modify or free() the "-" constant.
565 static char *argv_stdin[2] = { (char *)"-", NULL };
569 return argv + optind;