1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
6 /// \brief Parser for filter-specific options
8 // Author: Lasse Collin
10 ///////////////////////////////////////////////////////////////////////////////
27 const name_id_map
*map
;
33 /// Parses option=value pairs that are separated with commas:
34 /// opt=val,opt=val,opt=val
36 /// Each option is a string, that is converted to an integer using the
37 /// index where the option string is in the array.
40 /// - a string-id map mapping a list of possible string values to integers
41 /// (opts[i].map != NULL, opts[i].min and opts[i].max are ignored);
42 /// - a number with minimum and maximum value limit
43 /// (opts[i].map == NULL && opts[i].min != UINT64_MAX);
44 /// - a string that will be parsed by the filter-specific code
45 /// (opts[i].map == NULL && opts[i].min == UINT64_MAX, opts[i].max ignored)
47 /// When parsing both option and value succeed, a filter-specific function
48 /// is called, which should update the given value to filter-specific
49 /// options structure.
51 /// This returns only if no errors occur.
53 /// \param str String containing the options from the command line
54 /// \param opts Filter-specific option map
55 /// \param set Filter-specific function to update filter_options
56 /// \param filter_options Pointer to filter-specific options structure
59 parse_options(const char *str
, const option_map
*opts
,
60 void (*set
)(void *filter_options
,
61 unsigned key
, uint64_t value
, const char *valuestr
),
64 if (str
== NULL
|| str
[0] == '\0')
67 char *s
= xstrdup(str
);
70 while (*name
!= '\0') {
76 char *split
= strchr(name
, ',');
80 char *value
= strchr(name
, '=');
84 if (value
== NULL
|| value
[0] == '\0')
85 message_fatal(_("%s: Options must be 'name=value' "
86 "pairs separated with commas"), str
);
88 // Look for the option name from the option map.
91 if (opts
[i
].name
== NULL
)
92 message_fatal(_("%s: Invalid option name"),
95 if (strcmp(name
, opts
[i
].name
) == 0)
101 // Option was found from the map. See how we should handle it.
102 if (opts
[i
].map
!= NULL
) {
103 // value is a string which we should map
106 for (j
= 0; opts
[i
].map
[j
].name
!= NULL
; ++j
) {
107 if (strcmp(opts
[i
].map
[j
].name
, value
) == 0)
111 if (opts
[i
].map
[j
].name
== NULL
)
112 message_fatal(_("%s: Invalid option value"),
115 set(filter_options
, i
, opts
[i
].map
[j
].id
, value
);
117 } else if (opts
[i
].min
== UINT64_MAX
) {
118 // value is a special string that will be
120 set(filter_options
, i
, 0, value
);
123 // value is an integer.
124 const uint64_t v
= str_to_uint64(name
, value
,
125 opts
[i
].min
, opts
[i
].max
);
126 set(filter_options
, i
, v
, value
);
129 // Check if it was the last option.
151 set_delta(void *options
, unsigned key
, uint64_t value
,
152 const char *valuestr
lzma_attribute((__unused__
)))
154 lzma_options_delta
*opt
= options
;
163 extern lzma_options_delta
*
164 options_delta(const char *str
)
166 static const option_map opts
[] = {
167 { "dist", NULL
, LZMA_DELTA_DIST_MIN
,
168 LZMA_DELTA_DIST_MAX
},
172 lzma_options_delta
*options
= xmalloc(sizeof(lzma_options_delta
));
173 *options
= (lzma_options_delta
){
174 // It's hard to give a useful default for this.
175 .type
= LZMA_DELTA_TYPE_BYTE
,
176 .dist
= LZMA_DELTA_DIST_MIN
,
179 parse_options(str
, opts
, &set_delta
, options
);
195 set_bcj(void *options
, unsigned key
, uint64_t value
,
196 const char *valuestr
lzma_attribute((__unused__
)))
198 lzma_options_bcj
*opt
= options
;
200 case OPT_START_OFFSET
:
201 opt
->start_offset
= value
;
207 extern lzma_options_bcj
*
208 options_bcj(const char *str
)
210 static const option_map opts
[] = {
211 { "start", NULL
, 0, UINT32_MAX
},
215 lzma_options_bcj
*options
= xmalloc(sizeof(lzma_options_bcj
));
216 *options
= (lzma_options_bcj
){
220 parse_options(str
, opts
, &set_bcj
, options
);
245 error_lzma_preset(const char *valuestr
)
247 message_fatal(_("Unsupported LZMA1/LZMA2 preset: %s"), valuestr
);
252 set_lzma(void *options
, unsigned 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
= (uint32_t)(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"));