1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief Parser for filter-specific options
6 // Author: Lasse Collin
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
11 ///////////////////////////////////////////////////////////////////////////////
28 const name_id_map
*map
;
34 /// Parses option=value pairs that are separated with colons, semicolons,
35 /// or commas: opt=val:opt=val;opt=val,opt=val
37 /// Each option is a string, that is converted to an integer using the
38 /// index where the option string is in the array.
41 /// - a string-id map mapping a list of possible string values to integers
42 /// (opts[i].map != NULL, opts[i].min and opts[i].max are ignored);
43 /// - a number with minimum and maximum value limit
44 /// (opts[i].map == NULL && opts[i].min != UINT64_MAX);
45 /// - a string that will be parsed by the filter-specific code
46 /// (opts[i].map == NULL && opts[i].min == UINT64_MAX, opts[i].max ignored)
48 /// When parsing both option and value succeed, a filter-specific function
49 /// is called, which should update the given value to filter-specific
50 /// options structure.
52 /// \param str String containing the options from the command line
53 /// \param opts Filter-specific option map
54 /// \param set Filter-specific function to update filter_options
55 /// \param filter_options Pointer to filter-specific options structure
57 /// \return Returns only if no errors occur.
60 parse_options(const char *str
, const option_map
*opts
,
61 void (*set
)(void *filter_options
,
62 uint32_t key
, uint64_t value
, const char *valuestr
),
65 if (str
== NULL
|| str
[0] == '\0')
68 char *s
= xstrdup(str
);
71 while (*name
!= '\0') {
77 char *split
= strchr(name
, ',');
81 char *value
= strchr(name
, '=');
85 if (value
== NULL
|| value
[0] == '\0')
86 message_fatal(_("%s: Options must be `name=value' "
87 "pairs separated with commas"), str
);
89 // Look for the option name from the option map.
92 if (opts
[i
].name
== NULL
)
93 message_fatal(_("%s: Invalid option name"),
96 if (strcmp(name
, opts
[i
].name
) == 0)
102 // Option was found from the map. See how we should handle it.
103 if (opts
[i
].map
!= NULL
) {
104 // value is a string which we should map
107 for (j
= 0; opts
[i
].map
[j
].name
!= NULL
; ++j
) {
108 if (strcmp(opts
[i
].map
[j
].name
, value
) == 0)
112 if (opts
[i
].map
[j
].name
== NULL
)
113 message_fatal(_("%s: Invalid option value"),
116 set(filter_options
, i
, opts
[i
].map
[j
].id
, value
);
118 } else if (opts
[i
].min
== UINT64_MAX
) {
119 // value is a special string that will be
121 set(filter_options
, i
, 0, value
);
124 // value is an integer.
125 const uint64_t v
= str_to_uint64(name
, value
,
126 opts
[i
].min
, opts
[i
].max
);
127 set(filter_options
, i
, v
, value
);
130 // Check if it was the last option.
152 set_delta(void *options
, uint32_t key
, uint64_t value
,
153 const char *valuestr
lzma_attribute((__unused__
)))
155 lzma_options_delta
*opt
= options
;
164 extern lzma_options_delta
*
165 options_delta(const char *str
)
167 static const option_map opts
[] = {
168 { "dist", NULL
, LZMA_DELTA_DIST_MIN
,
169 LZMA_DELTA_DIST_MAX
},
173 lzma_options_delta
*options
= xmalloc(sizeof(lzma_options_delta
));
174 *options
= (lzma_options_delta
){
175 // It's hard to give a useful default for this.
176 .type
= LZMA_DELTA_TYPE_BYTE
,
177 .dist
= LZMA_DELTA_DIST_MIN
,
180 parse_options(str
, opts
, &set_delta
, options
);
196 set_bcj(void *options
, uint32_t key
, uint64_t value
,
197 const char *valuestr
lzma_attribute((__unused__
)))
199 lzma_options_bcj
*opt
= options
;
201 case OPT_START_OFFSET
:
202 opt
->start_offset
= value
;
208 extern lzma_options_bcj
*
209 options_bcj(const char *str
)
211 static const option_map opts
[] = {
212 { "start", NULL
, 0, UINT32_MAX
},
216 lzma_options_bcj
*options
= xmalloc(sizeof(lzma_options_bcj
));
217 *options
= (lzma_options_bcj
){
221 parse_options(str
, opts
, &set_bcj
, options
);
244 static void lzma_attribute((__noreturn__
))
245 error_lzma_preset(const char *valuestr
)
247 message_fatal(_("Unsupported LZMA1/LZMA2 preset: %s"), valuestr
);
252 set_lzma(void *options
, uint32_t key
, uint64_t value
, const char *valuestr
)
254 lzma_options_lzma
*opt
= options
;
258 if (valuestr
[0] < '0' || valuestr
[0] > '9')
259 error_lzma_preset(valuestr
);
261 uint32_t preset
= valuestr
[0] - '0';
263 // Currently only "e" is supported as a modifier,
264 // so keep this simple for now.
265 if (valuestr
[1] != '\0') {
266 if (valuestr
[1] == 'e')
267 preset
|= LZMA_PRESET_EXTREME
;
269 error_lzma_preset(valuestr
);
271 if (valuestr
[2] != '\0')
272 error_lzma_preset(valuestr
);
275 if (lzma_lzma_preset(options
, preset
))
276 error_lzma_preset(valuestr
);
282 opt
->dict_size
= value
;
302 opt
->nice_len
= value
;
316 extern lzma_options_lzma
*
317 options_lzma(const char *str
)
319 static const name_id_map modes
[] = {
320 { "fast", LZMA_MODE_FAST
},
321 { "normal", LZMA_MODE_NORMAL
},
325 static const name_id_map mfs
[] = {
326 { "hc3", LZMA_MF_HC3
},
327 { "hc4", LZMA_MF_HC4
},
328 { "bt2", LZMA_MF_BT2
},
329 { "bt3", LZMA_MF_BT3
},
330 { "bt4", LZMA_MF_BT4
},
334 static const option_map opts
[] = {
335 { "preset", NULL
, UINT64_MAX
, 0 },
336 { "dict", NULL
, LZMA_DICT_SIZE_MIN
,
337 (UINT32_C(1) << 30) + (UINT32_C(1) << 29) },
338 { "lc", NULL
, LZMA_LCLP_MIN
, LZMA_LCLP_MAX
},
339 { "lp", NULL
, LZMA_LCLP_MIN
, LZMA_LCLP_MAX
},
340 { "pb", NULL
, LZMA_PB_MIN
, LZMA_PB_MAX
},
341 { "mode", modes
, 0, 0 },
342 { "nice", NULL
, 2, 273 },
344 { "depth", NULL
, 0, UINT32_MAX
},
348 lzma_options_lzma
*options
= xmalloc(sizeof(lzma_options_lzma
));
349 if (lzma_lzma_preset(options
, LZMA_PRESET_DEFAULT
))
352 parse_options(str
, opts
, &set_lzma
, options
);
354 if (options
->lc
+ options
->lp
> LZMA_LCLP_MAX
)
355 message_fatal(_("The sum of lc and lp must not exceed 4"));
357 const uint32_t nice_len_min
= options
->mf
& 0x0F;
358 if (options
->nice_len
< nice_len_min
)
359 message_fatal(_("The selected match finder requires at "
360 "least nice=%" PRIu32
), nice_len_min
);