1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief Parser for filter-specific options
6 // Copyright (C) 2007 Lasse Collin
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
18 ///////////////////////////////////////////////////////////////////////////////
35 const name_id_map *map;
41 /// Parses option=value pairs that are separated with colons, semicolons,
42 /// or commas: opt=val:opt=val;opt=val,opt=val
44 /// Each option is a string, that is converted to an integer using the
45 /// index where the option string is in the array.
47 /// Value can be either a number with minimum and maximum value limit, or
48 /// a string-id map mapping a list of possible string values to integers.
50 /// When parsing both option and value succeed, a filter-specific function
51 /// is called, which should update the given value to filter-specific
52 /// options structure.
54 /// \param str String containing the options from the command line
55 /// \param opts Filter-specific option map
56 /// \param set Filter-specific function to update filter_options
57 /// \param filter_options Pointer to filter-specific options structure
59 /// \return Returns only if no errors occur.
62 parse_options(const char *str, const option_map *opts,
63 void (*set)(void *filter_options,
64 uint32_t key, uint64_t value),
67 if (str == NULL || str[0] == '\0')
70 char *s = xstrdup(str);
74 char *split = strchr(name, ',');
78 char *value = strchr(name, '=');
82 if (value == NULL || value[0] == '\0')
83 message_fatal(_("%s: Options must be `name=value' "
84 "pairs separated with commas"), str);
86 // Look for the option name from the option map.
88 for (size_t i = 0; opts[i].name != NULL; ++i) {
89 if (strcmp(name, opts[i].name) != 0)
92 if (opts[i].map == NULL) {
93 // value is an integer.
94 const uint64_t v = str_to_uint64(name, value,
95 opts[i].min, opts[i].max);
96 set(filter_options, i, v);
98 // value is a string which we should map
101 for (j = 0; opts[i].map[j].name != NULL; ++j) {
102 if (strcmp(opts[i].map[j].name, value)
107 if (opts[i].map[j].name == NULL)
108 message_fatal(_("%s: Invalid option "
111 set(filter_options, i, opts[i].map[j].id);
119 message_fatal(_("%s: Invalid option name"), name);
144 set_subblock(void *options, uint32_t key, uint64_t value)
146 lzma_options_subblock *opt = options;
150 opt->subblock_data_size = value;
158 opt->alignment = value;
164 extern lzma_options_subblock *
165 options_subblock(const char *str)
167 static const option_map opts[] = {
168 { "size", NULL, LZMA_SUBBLOCK_DATA_SIZE_MIN,
169 LZMA_SUBBLOCK_DATA_SIZE_MAX },
170 { "rle", NULL, LZMA_SUBBLOCK_RLE_OFF,
171 LZMA_SUBBLOCK_RLE_MAX },
172 { "align",NULL, LZMA_SUBBLOCK_ALIGNMENT_MIN,
173 LZMA_SUBBLOCK_ALIGNMENT_MAX },
177 lzma_options_subblock *options
178 = xmalloc(sizeof(lzma_options_subblock));
179 *options = (lzma_options_subblock){
180 .allow_subfilters = false,
181 .alignment = LZMA_SUBBLOCK_ALIGNMENT_DEFAULT,
182 .subblock_data_size = LZMA_SUBBLOCK_DATA_SIZE_DEFAULT,
183 .rle = LZMA_SUBBLOCK_RLE_OFF,
186 parse_options(str, opts, &set_subblock, options);
202 set_delta(void *options, uint32_t key, uint64_t value)
204 lzma_options_delta *opt = options;
213 extern lzma_options_delta *
214 options_delta(const char *str)
216 static const option_map opts[] = {
217 { "dist", NULL, LZMA_DELTA_DIST_MIN,
218 LZMA_DELTA_DIST_MAX },
222 lzma_options_delta *options = xmalloc(sizeof(lzma_options_delta));
223 *options = (lzma_options_delta){
224 // It's hard to give a useful default for this.
225 .type = LZMA_DELTA_TYPE_BYTE,
226 .dist = LZMA_DELTA_DIST_MIN,
229 parse_options(str, opts, &set_delta, options);
253 set_lzma(void *options, uint32_t key, uint64_t value)
255 lzma_options_lzma *opt = options;
259 if (lzma_lzma_preset(options, (uint32_t)(value)))
260 message_fatal("LZMA1/LZMA2 preset %u is not supported",
261 (unsigned int)(value));
265 opt->dict_size = value;
285 opt->nice_len = value;
299 extern lzma_options_lzma *
300 options_lzma(const char *str)
302 static const name_id_map modes[] = {
303 { "fast", LZMA_MODE_FAST },
304 { "normal", LZMA_MODE_NORMAL },
308 static const name_id_map mfs[] = {
309 { "hc3", LZMA_MF_HC3 },
310 { "hc4", LZMA_MF_HC4 },
311 { "bt2", LZMA_MF_BT2 },
312 { "bt3", LZMA_MF_BT3 },
313 { "bt4", LZMA_MF_BT4 },
317 static const option_map opts[] = {
318 { "preset", NULL, 0, 9 },
319 { "dict", NULL, LZMA_DICT_SIZE_MIN,
320 (UINT32_C(1) << 30) + (UINT32_C(1) << 29) },
321 { "lc", NULL, LZMA_LCLP_MIN, LZMA_LCLP_MAX },
322 { "lp", NULL, LZMA_LCLP_MIN, LZMA_LCLP_MAX },
323 { "pb", NULL, LZMA_PB_MIN, LZMA_PB_MAX },
324 { "mode", modes, 0, 0 },
325 { "nice", NULL, 2, 273 },
327 { "depth", NULL, 0, UINT32_MAX },
331 // TODO There should be a way to take some preset as the base for
333 lzma_options_lzma *options = xmalloc(sizeof(lzma_options_lzma));
334 *options = (lzma_options_lzma){
335 .dict_size = LZMA_DICT_SIZE_DEFAULT,
337 .preset_dict_size = 0,
338 .lc = LZMA_LC_DEFAULT,
339 .lp = LZMA_LP_DEFAULT,
340 .pb = LZMA_PB_DEFAULT,
342 .mode = LZMA_MODE_NORMAL,
348 parse_options(str, opts, &set_lzma, options);
350 if (options->lc + options->lp > LZMA_LCLP_MAX)
351 message_fatal(_("The sum of lc and lp must be at "
354 const uint32_t nice_len_min = options->mf & 0x0F;
355 if (options->nice_len < nice_len_min)
356 message_fatal(_("The selected match finder requires at "
357 "least nice=%" PRIu32), nice_len_min);