options.c revision 213700
143045Sdillon/////////////////////////////////////////////////////////////////////////////// 243045Sdillon// 3132935Simp/// \file options.c 443045Sdillon/// \brief Parser for filter-specific options 543045Sdillon// 6132935Simp// Author: Lasse Collin 7132935Simp// 8132935Simp// This file has been put into the public domain. 9132935Simp// You can do whatever you want with this file. 10132935Simp// 11132935Simp/////////////////////////////////////////////////////////////////////////////// 12132935Simp 13132935Simp#include "private.h" 14132935Simp 15132935Simp 16132935Simp/////////////////// 17132935Simp// Generic stuff // 18132935Simp/////////////////// 19132935Simp 20132935Simptypedef struct { 21132935Simp const char *name; 22132935Simp uint64_t id; 23132935Simp} name_id_map; 24132935Simp 2543045Sdillon 2643045Sdillontypedef struct { 2783551Sdillon const char *name; 2883551Sdillon const name_id_map *map; 2943045Sdillon uint64_t min; 3043045Sdillon uint64_t max; 3143045Sdillon} option_map; 3243045Sdillon 3343045Sdillon 3472950Srwatson/// Parses option=value pairs that are separated with colons, semicolons, 3543045Sdillon/// or commas: opt=val:opt=val;opt=val,opt=val 36166550Sjhb/// 3777605Stmm/// Each option is a string, that is converted to an integer using the 3877605Stmm/// index where the option string is in the array. 3943045Sdillon/// 4077605Stmm/// Value can be 4143045Sdillon/// - a string-id map mapping a list of possible string values to integers 4243045Sdillon/// (opts[i].map != NULL, opts[i].min and opts[i].max are ignored); 4343045Sdillon/// - a number with minimum and maximum value limit 4469793Sobrien/// (opts[i].map == NULL && opts[i].min != UINT64_MAX); 4543045Sdillon/// - a string that will be parsed by the filter-specific code 4643045Sdillon/// (opts[i].map == NULL && opts[i].min == UINT64_MAX, opts[i].max ignored) 4743045Sdillon/// 4843045Sdillon/// When parsing both option and value succeed, a filter-specific function 4972950Srwatson/// is called, which should update the given value to filter-specific 5043045Sdillon/// options structure. 5172950Srwatson/// 5272950Srwatson/// \param str String containing the options from the command line 53166550Sjhb/// \param opts Filter-specific option map 54217744Suqs/// \param set Filter-specific function to update filter_options 55217744Suqs/// \param filter_options Pointer to filter-specific options structure 56217744Suqs/// 57166550Sjhb/// \return Returns only if no errors occur. 5843045Sdillon/// 59166550Sjhbstatic void 60166550Sjhbparse_options(const char *str, const option_map *opts, 61166550Sjhb void (*set)(void *filter_options, 6243045Sdillon uint32_t key, uint64_t value, const char *valuestr), 6372950Srwatson void *filter_options) 6443045Sdillon{ 6543045Sdillon if (str == NULL || str[0] == '\0') 66166550Sjhb return; 6772950Srwatson 68166550Sjhb char *s = xstrdup(str); 69217744Suqs char *name = s; 7043045Sdillon 71166550Sjhb while (*name != '\0') { 72166550Sjhb if (*name == ',') { 73166550Sjhb ++name; 74166550Sjhb continue; 75166550Sjhb } 76166550Sjhb 77166550Sjhb char *split = strchr(name, ','); 78166550Sjhb if (split != NULL) 79166550Sjhb *split = '\0'; 80166550Sjhb 8177605Stmm char *value = strchr(name, '='); 8277605Stmm if (value != NULL) 8377605Stmm *value++ = '\0'; 8477605Stmm 8577605Stmm if (value == NULL || value[0] == '\0') 8677605Stmm message_fatal(_("%s: Options must be `name=value' " 8777605Stmm "pairs separated with commas"), str); 8877605Stmm 8977605Stmm // Look for the option name from the option map. 9072950Srwatson size_t i = 0; 9172950Srwatson while (true) { 9243045Sdillon if (opts[i].name == NULL) 93217744Suqs message_fatal(_("%s: Invalid option name"), 94217744Suqs name); 9543045Sdillon 9643045Sdillon if (strcmp(name, opts[i].name) == 0) 9743045Sdillon break; 9843045Sdillon 9943045Sdillon ++i; 10043045Sdillon } 10143045Sdillon 10243045Sdillon // Option was found from the map. See how we should handle it. 10343045Sdillon if (opts[i].map != NULL) { 10472950Srwatson // value is a string which we should map 10572950Srwatson // to an integer. 10672950Srwatson size_t j; 107166550Sjhb for (j = 0; opts[i].map[j].name != NULL; ++j) { 10872950Srwatson if (strcmp(opts[i].map[j].name, value) == 0) 10972950Srwatson break; 11043045Sdillon } 111166550Sjhb 112217744Suqs if (opts[i].map[j].name == NULL) 113217744Suqs message_fatal(_("%s: Invalid option value"), 114217744Suqs value); 115166550Sjhb 116166550Sjhb set(filter_options, i, opts[i].map[j].id, value); 117166550Sjhb 118166550Sjhb } else if (opts[i].min == UINT64_MAX) { 119166550Sjhb // value is a special string that will be 120166550Sjhb // parsed by set(). 121166550Sjhb set(filter_options, i, 0, value); 122166550Sjhb 123166550Sjhb } else { 124166550Sjhb // value is an integer. 125166550Sjhb const uint64_t v = str_to_uint64(name, value, 126166550Sjhb opts[i].min, opts[i].max); 127166550Sjhb set(filter_options, i, v, value); 128166550Sjhb } 129166550Sjhb 130166550Sjhb // Check if it was the last option. 131166550Sjhb if (split == NULL) 132166550Sjhb break; 133166550Sjhb 134166550Sjhb name = split + 1; 135166550Sjhb } 136166550Sjhb 137166550Sjhb free(s); 138166550Sjhb return; 139166550Sjhb} 140166550Sjhb 141166550Sjhb 142166550Sjhb/////////// 143166550Sjhb// Delta // 144166550Sjhb/////////// 145166550Sjhb 146166550Sjhbenum { 147166550Sjhb OPT_DIST, 148166550Sjhb}; 149166550Sjhb 15077605Stmm 15177605Stmmstatic void 15272950Srwatsonset_delta(void *options, uint32_t key, uint64_t value, 15377605Stmm const char *valuestr lzma_attribute((unused))) 15477605Stmm{ 15577605Stmm lzma_options_delta *opt = options; 15672950Srwatson switch (key) { 157217744Suqs case OPT_DIST: 158217744Suqs opt->dist = value; 159217744Suqs break; 16077605Stmm } 16177605Stmm} 16277605Stmm 16377605Stmm 16477605Stmmextern lzma_options_delta * 16572950Srwatsonoptions_delta(const char *str) 16677605Stmm{ 16772950Srwatson static const option_map opts[] = { 16872950Srwatson { "dist", NULL, LZMA_DELTA_DIST_MIN, 16977605Stmm LZMA_DELTA_DIST_MAX }, 17077605Stmm { NULL, NULL, 0, 0 } 17177605Stmm }; 17277605Stmm 17372950Srwatson lzma_options_delta *options = xmalloc(sizeof(lzma_options_delta)); 17477605Stmm *options = (lzma_options_delta){ 17577605Stmm // It's hard to give a useful default for this. 17677605Stmm .type = LZMA_DELTA_TYPE_BYTE, 17777605Stmm .dist = LZMA_DELTA_DIST_MIN, 17877605Stmm }; 17977605Stmm 18077605Stmm parse_options(str, opts, &set_delta, options); 18177605Stmm 18277605Stmm return options; 18377605Stmm} 18472950Srwatson 18572950Srwatson 18677605Stmm///////// 18777605Stmm// BCJ // 18877605Stmm///////// 18972950Srwatson 19077605Stmmenum { 19177605Stmm OPT_START_OFFSET, 19277605Stmm}; 19377605Stmm 19472950Srwatson 19577605Stmmstatic void 19672950Srwatsonset_bcj(void *options, uint32_t key, uint64_t value, 19777605Stmm const char *valuestr lzma_attribute((unused))) 19877605Stmm{ 19977605Stmm lzma_options_bcj *opt = options; 20077605Stmm switch (key) { 20177605Stmm case OPT_START_OFFSET: 20277605Stmm opt->start_offset = value; 20377605Stmm break; 20477605Stmm } 20572950Srwatson} 20677605Stmm 20777605Stmm 20872950Srwatsonextern lzma_options_bcj * 20972950Srwatsonoptions_bcj(const char *str) 21077605Stmm{ 21177605Stmm static const option_map opts[] = { 21277605Stmm { "start", NULL, 0, UINT32_MAX }, 21377605Stmm { NULL, NULL, 0, 0 } 21477605Stmm }; 21577605Stmm 21672950Srwatson lzma_options_bcj *options = xmalloc(sizeof(lzma_options_bcj)); 21772950Srwatson *options = (lzma_options_bcj){ 21872950Srwatson .start_offset = 0, 21972950Srwatson }; 220166550Sjhb 221166550Sjhb parse_options(str, opts, &set_bcj, options); 222166550Sjhb 223166550Sjhb return options; 224166550Sjhb} 225166550Sjhb 226166550Sjhb 227166550Sjhb////////// 228166550Sjhb// LZMA // 229166550Sjhb////////// 230166550Sjhb 231166550Sjhbenum { 232166550Sjhb OPT_PRESET, 233166550Sjhb OPT_DICT, 234166550Sjhb OPT_LC, 235166550Sjhb OPT_LP, 236166550Sjhb OPT_PB, 237166550Sjhb OPT_MODE, 238166550Sjhb OPT_NICE, 239166550Sjhb OPT_MF, 240166550Sjhb OPT_DEPTH, 241166550Sjhb}; 242166550Sjhb 243166550Sjhb 244166550Sjhbstatic void lzma_attribute((noreturn)) 245166550Sjhberror_lzma_preset(const char *valuestr) 246166550Sjhb{ 247166550Sjhb message_fatal(_("Unsupported LZMA1/LZMA2 preset: %s"), valuestr); 248217744Suqs} 249217744Suqs 25077605Stmm 25172950Srwatsonstatic void 25277605Stmmset_lzma(void *options, uint32_t key, uint64_t value, const char *valuestr) 25377605Stmm{ 25472950Srwatson lzma_options_lzma *opt = options; 25572950Srwatson 25672950Srwatson switch (key) { 25772950Srwatson case OPT_PRESET: { 25872950Srwatson if (valuestr[0] < '0' || valuestr[0] > '9') 25972950Srwatson error_lzma_preset(valuestr); 26072950Srwatson 26172950Srwatson uint32_t preset = valuestr[0] - '0'; 262 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; 268 else 269 error_lzma_preset(valuestr); 270 271 if (valuestr[2] != '\0') 272 error_lzma_preset(valuestr); 273 } 274 275 if (lzma_lzma_preset(options, preset)) 276 error_lzma_preset(valuestr); 277 278 break; 279 } 280 281 case OPT_DICT: 282 opt->dict_size = value; 283 break; 284 285 case OPT_LC: 286 opt->lc = value; 287 break; 288 289 case OPT_LP: 290 opt->lp = value; 291 break; 292 293 case OPT_PB: 294 opt->pb = value; 295 break; 296 297 case OPT_MODE: 298 opt->mode = value; 299 break; 300 301 case OPT_NICE: 302 opt->nice_len = value; 303 break; 304 305 case OPT_MF: 306 opt->mf = value; 307 break; 308 309 case OPT_DEPTH: 310 opt->depth = value; 311 break; 312 } 313} 314 315 316extern lzma_options_lzma * 317options_lzma(const char *str) 318{ 319 static const name_id_map modes[] = { 320 { "fast", LZMA_MODE_FAST }, 321 { "normal", LZMA_MODE_NORMAL }, 322 { NULL, 0 } 323 }; 324 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 }, 331 { NULL, 0 } 332 }; 333 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 }, 343 { "mf", mfs, 0, 0 }, 344 { "depth", NULL, 0, UINT32_MAX }, 345 { NULL, NULL, 0, 0 } 346 }; 347 348 lzma_options_lzma *options = xmalloc(sizeof(lzma_options_lzma)); 349 if (lzma_lzma_preset(options, LZMA_PRESET_DEFAULT)) 350 message_bug(); 351 352 parse_options(str, opts, &set_lzma, options); 353 354 if (options->lc + options->lp > LZMA_LCLP_MAX) 355 message_fatal(_("The sum of lc and lp must not exceed 4")); 356 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); 361 362 return options; 363} 364