Squash  0.7.0
options.c
1 /* Copyright (c) 2013 The Squash Authors
2  *
3  * Permission is hereby granted, free of charge, to any person
4  * obtaining a copy of this software and associated documentation
5  * files (the "Software"), to deal in the Software without
6  * restriction, including without limitation the rights to use, copy,
7  * modify, merge, publish, distribute, sublicense, and/or sell copies
8  * of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be
12  * included in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  *
23  * Authors:
24  * Evan Nemerson <evan@nemerson.com>
25  */
26 
27 /* For strdup */
28 #define _POSIX_C_SOURCE 200809L
29 
30 #include <assert.h>
31 #include <strings.h>
32 #include <string.h>
33 
34 #include "internal.h"
35 
36 static void squash_options_free (void* options);
37 
154 static int
155 squash_options_find (SquashOptions* options, const char* key) {
156  assert (options != NULL);
157  assert (key != NULL);
158 
159  const SquashOptionInfo* info = squash_codec_get_option_info (options->codec);
160  unsigned int option_n = 0;
161 
162  {
163  while (info->name != NULL) {
164  if (strcasecmp (key, info->name) == 0)
165  return option_n;
166 
167  option_n++;
168  info++;
169  }
170  }
171 
172  return -1;
173 }
174 
185 const char*
186 squash_options_get_string (SquashOptions* options, const char* key) {
187  if (options == NULL)
188  return NULL;
189 
190  const int option_n = squash_options_find (options, key);
191  if (option_n == -1)
192  return NULL;
193 
194  const SquashOptionInfo* info = squash_codec_get_option_info (options->codec) + option_n;
195  const SquashOptionValue* val = &(options->values[option_n]);
196 
197  switch ((int) info->type) {
198  case SQUASH_OPTION_TYPE_ENUM_STRING:
199  return info->info.enum_string.values[val->int_value].name;
200  case SQUASH_OPTION_TYPE_STRING:
201  return val->string_value;
202  default:
203  return NULL;
204  }
205 
206  squash_assert_unreachable ();
207 }
208 
216 bool
217 squash_options_get_bool (SquashOptions* options, const char* key) {
218  if (options == NULL)
219  return false;
220 
221  const int option_n = squash_options_find (options, key);
222  if (option_n == -1)
223  return NULL;
224 
225  const SquashOptionInfo* info = squash_codec_get_option_info (options->codec) + option_n;
226  const SquashOptionValue* val = &(options->values[option_n]);
227 
228  switch ((int) info->type) {
229  case SQUASH_OPTION_TYPE_BOOL:
230  return val->bool_value;
231  default:
232  return false;
233  }
234 
235  squash_assert_unreachable ();
236 }
237 
245 int
246 squash_options_get_int (SquashOptions* options, const char* key) {
247  if (options == NULL)
248  return -1;
249 
250  const int option_n = squash_options_find (options, key);
251  if (option_n == -1)
252  return -1;
253 
254  const SquashOptionInfo* info = squash_codec_get_option_info (options->codec) + option_n;
255  const SquashOptionValue* val = &(options->values[option_n]);
256 
257  switch ((int) info->type) {
258  case SQUASH_OPTION_TYPE_INT:
259  case SQUASH_OPTION_TYPE_ENUM_INT:
260  case SQUASH_OPTION_TYPE_RANGE_INT:
261  return val->int_value;
262  default:
263  return -1;
264  }
265 
266  squash_assert_unreachable ();
267 }
268 
276 size_t
277 squash_options_get_size (SquashOptions* options, const char* key) {
278  if (options == NULL)
279  return 0;
280 
281  const int option_n = squash_options_find (options, key);
282  if (option_n == -1)
283  return 0;
284 
285  const SquashOptionInfo* info = squash_codec_get_option_info (options->codec) + option_n;
286  const SquashOptionValue* val = &(options->values[option_n]);
287 
288  switch ((int) info->type) {
289  case SQUASH_OPTION_TYPE_SIZE:
290  case SQUASH_OPTION_TYPE_RANGE_SIZE:
291  return val->size_value;
292  default:
293  return 0;
294  }
295 
296  squash_assert_unreachable ();
297 }
298 
311 squash_options_parse_option (SquashOptions* options, const char* key, const char* value) {
312  assert (options != NULL);
313  assert (key != NULL);
314  assert (options->codec != NULL);
315 
316  const SquashOptionInfo* info = squash_codec_get_option_info (options->codec);
317 
318  if (info == NULL)
319  return SQUASH_BAD_PARAM;
320  else
321  assert (options->values != NULL);
322 
323  const int option_n = squash_options_find (options, key);
324  if (option_n < 0)
325  return SQUASH_BAD_PARAM;
326 
327  SquashOptionValue* val = &(options->values[option_n]);
328  info = info + option_n;
329 
330  switch (info->type) {
331  case SQUASH_OPTION_TYPE_RANGE_INT:
332  case SQUASH_OPTION_TYPE_INT: {
333  int res = atoi (value);
334  if (info->type == SQUASH_OPTION_TYPE_RANGE_INT) {
335  if (!((res == 0 && info->info.range_int.allow_zero) ||
336  (res >= info->info.range_int.min && res <= info->info.range_int.max)))
338  }
339  val->int_value = res;
340  return SQUASH_OK;
341  }
342  break;
343 
344  case SQUASH_OPTION_TYPE_RANGE_SIZE:
345  case SQUASH_OPTION_TYPE_SIZE: {
346  char* endptr = NULL;
347  unsigned long long int res = strtoull (value, &endptr, 10);
348 
349  /* Parse X(KMG)[i[B]] into a size in bytes. */
350  if (*endptr != '\0') {
351  switch (*endptr++) {
352  case 'g':
353  case 'G':
354  res *= 1024;
355  /* Fall through */
356  case 'm':
357  case 'M':
358  res *= 1024;
359  /* Fall through */
360  case 'k':
361  case 'K':
362  res *= 1024;
363  break;
364  default:
366  }
367 
368  if (*endptr != '\0') {
369  if (*endptr == 'i' || *endptr == 'I')
370  endptr++;
371 
372  if (*endptr == 'b' || *endptr == 'B')
373  endptr++;
374  else
376 
377  if (*endptr != '\0')
379  }
380  }
381 
382  if (info->type == SQUASH_OPTION_TYPE_RANGE_SIZE) {
383  if (!((res == 0 && info->info.range_size.allow_zero) ||
384  (res >= info->info.range_size.min && res <= info->info.range_size.max)))
386  }
387  val->size_value = (size_t) res;
388  return SQUASH_OK;
389  }
390  break;
391 
392  case SQUASH_OPTION_TYPE_ENUM_STRING: {
393  for (unsigned int i = 0 ; info->info.enum_string.values[i].name != NULL ; i++) {
394  if (strcasecmp (value, info->info.enum_string.values[i].name) == 0) {
395  val->int_value = info->info.enum_string.values[i].value;
396  return SQUASH_OK;
397  }
398  }
400  }
401  break;
402 
403  case SQUASH_OPTION_TYPE_BOOL: {
404  if (strcasecmp (value, "true") == 0 ||
405  strcasecmp (value, "yes") == 0 ||
406  strcasecmp (value, "on") == 0 ||
407  strcasecmp (value, "t") == 0 ||
408  strcasecmp (value, "y") == 0 ||
409  strcasecmp (value, "1") == 0) {
410  val->bool_value = true;
411  } else if (strcasecmp (value, "false") == 0 ||
412  strcasecmp (value, "no") == 0 ||
413  strcasecmp (value, "off") == 0 ||
414  strcasecmp (value, "f") == 0 ||
415  strcasecmp (value, "n") == 0 ||
416  strcasecmp (value, "0") == 0) {
417  val->bool_value = false;
418  } else {
420  }
421  return SQUASH_OK;
422  }
423  break;
424 
425  case SQUASH_OPTION_TYPE_ENUM_INT: {
426  int res = atoi (value);
427  for (unsigned int i = 0 ; i < info->info.enum_int.values_length ; i++) {
428  if (res == info->info.enum_int.values[i]) {
429  val->int_value = res;
430  return SQUASH_OK;
431  }
432  }
434  }
435  break;
436 
437  case SQUASH_OPTION_TYPE_STRING:
438  val->string_value = strdup (value);
439  break;
440 
441  case SQUASH_OPTION_TYPE_NONE:
442  default:
443  squash_assert_unreachable();
444  }
445 
446  return squash_error (SQUASH_FAILED);
447 }
448 
458 squash_options_parsea (SquashOptions* options, const char* const* keys, const char* const* values) {
459  SquashStatus status = SQUASH_OK;
460  int n;
461 
462  assert (options != NULL);
463 
464  if (keys == NULL || values == NULL)
465  return SQUASH_OK;
466 
467  for ( n = 0 ; keys[n] != NULL ; n++ ) {
468  status = squash_options_parse_option (options, keys[n], values[n]);
469  if (status != SQUASH_OK) {
470  break;
471  }
472  }
473 
474  return status;
475 }
476 
486 squash_options_parsev (SquashOptions* options, va_list options_list) {
487  const char* key;
488  const char* value;
489  SquashStatus status = SQUASH_OK;
490 
491  assert (options != NULL);
492 
493  while ( (key = va_arg (options_list, char*)) != NULL ) {
494  value = va_arg (options_list, char*);
495 
496  status = squash_options_parse_option (options, key, value);
497  if (status != SQUASH_OK)
498  break;
499  }
500 
501  return status;
502 }
503 
514 squash_options_parse (SquashOptions* options, ...) {
515  va_list options_list;
516  SquashStatus status;
517 
518  va_start (options_list, options);
519  status = squash_options_parsev (options, options_list);
520  va_end (options_list);
521 
522  return status;
523 }
524 
532 SquashOptions*
533 squash_options_new (SquashCodec* codec, ...) {
534  va_list options_list;
535  SquashOptions* options;
536 
537  va_start (options_list, codec);
538  options = squash_options_newv (codec, options_list);
539  va_end (options_list);
540 
541  return options;
542 }
543 
544 static SquashOptions*
545 squash_options_create (SquashCodec* codec) {
546  SquashOptions* options = malloc (sizeof (SquashOptions));
547  squash_options_init (options, codec, squash_options_free);
548  return options;
549 }
550 
559 SquashOptions*
560 squash_options_newv (SquashCodec* codec, va_list options) {
561  SquashOptions* opts = NULL;
562 
563  assert (codec != NULL);
564 
565  if (squash_codec_get_option_info (codec) != NULL) {
566  opts = squash_options_create (codec);
567  squash_options_parsev (opts, options);
568  }
569 
570  return opts;
571 }
572 
581 SquashOptions*
582 squash_options_newa (SquashCodec* codec, const char* const* keys, const char* const* values) {
583  SquashOptions* opts = NULL;
584 
585  assert (codec != NULL);
586 
587  if (squash_codec_get_option_info (codec) != NULL) {
588  opts = squash_options_create (codec);
589  squash_options_parsea (opts, keys, values);
590  }
591 
592  return opts;
593 }
594 
606 void
607 squash_options_init (void* options,
608  SquashCodec* codec,
609  SquashDestroyNotify destroy_notify) {
610  SquashOptions* o;
611 
612  assert (options != NULL);
613  assert (codec != NULL);
614 
615  o = (SquashOptions*) options;
616 
617  squash_object_init (o, true, destroy_notify);
618  o->codec = codec;
619 
620  const SquashOptionInfo* info = squash_codec_get_option_info (codec);
621  if (info != NULL) {
622  size_t n_options;
623  for (n_options = 0 ; info[n_options].name != NULL ; n_options++) { }
624 
625  o->values = calloc (n_options, sizeof (SquashOptionValue));
626  for (size_t c_option = 0 ; c_option < n_options ; c_option++) {
627  switch (info[c_option].type) {
628  case SQUASH_OPTION_TYPE_ENUM_STRING:
629  case SQUASH_OPTION_TYPE_RANGE_INT:
630  case SQUASH_OPTION_TYPE_INT:
631  case SQUASH_OPTION_TYPE_ENUM_INT:
632  o->values[c_option].int_value = info[c_option].default_value.int_value;
633  break;
634  case SQUASH_OPTION_TYPE_BOOL:
635  o->values[c_option].bool_value = info[c_option].default_value.bool_value;
636  break;
637  case SQUASH_OPTION_TYPE_SIZE:
638  case SQUASH_OPTION_TYPE_RANGE_SIZE:
639  o->values[c_option].size_value = info[c_option].default_value.size_value;
640  break;
641  case SQUASH_OPTION_TYPE_STRING:
642  o->values[c_option].string_value = strdup (info[c_option].default_value.string_value);
643  break;
644  case SQUASH_OPTION_TYPE_NONE:
645  default:
646  squash_assert_unreachable();
647  }
648  }
649  }
650 }
651 
660 void
661 squash_options_destroy (void* options) {
662  SquashOptions* o;
663 
664  assert (options != NULL);
665 
666  o = (SquashOptions*) options;
667 
668  SquashOptionValue* values = o->values;
669  if (values != NULL) {
670  const SquashOptionInfo* info = squash_codec_get_option_info (o->codec);
671  assert (info != NULL);
672 
673  for (int i = 0 ; info[i].name != NULL ; i++)
674  if (info[i].type == SQUASH_OPTION_TYPE_STRING)
675  free (values[i].string_value);
676 
677  free (values);
678  }
679 
681 }
682 
683 static void
684 squash_options_free (void* options) {
685  squash_options_destroy ((SquashOptions*) options);
686  free (options);
687 }
688 
void squash_options_init(void *options, SquashCodec *codec, SquashDestroyNotify destroy_notify)
Initialize a new SquashOptions instance.
Definition: options.c:607
SquashStatus squash_options_parse(SquashOptions *options,...)
Parse a variadic list of options.
Definition: options.c:514
int squash_options_get_int(SquashOptions *options, const char *key)
Definition: options.c:246
SquashStatus squash_options_parsev(SquashOptions *options, va_list options_list)
Parse a va_list of options.
Definition: options.c:486
Operation failed.
Definition: status.h:41
SquashStatus squash_options_parsea(SquashOptions *options, const char *const *keys, const char *const *values)
Parse an array of options.
Definition: options.c:458
SquashOptions * squash_options_new(SquashCodec *codec,...)
Create a new group of options.
Definition: options.c:533
void(* SquashDestroyNotify)(void *data)
Callback to be invoked when information data is no longer needed.
Definition: object.h:43
const char * squash_options_get_string(SquashOptions *options, const char *key)
Definition: options.c:186
SquashStatus squash_options_parse_option(SquashOptions *options, const char *key, const char *value)
Parse a single option.
Definition: options.c:311
SquashOptions * squash_options_newv(SquashCodec *codec, va_list options)
Create a new group of options from a variadic list.
Definition: options.c:560
bool squash_options_get_bool(SquashOptions *options, const char *key)
Definition: options.c:217
SquashOptions * squash_options_newa(SquashCodec *codec, const char *const *keys, const char *const *values)
Create a new group of options from key and value arrays.
Definition: options.c:582
const SquashOptionInfo * squash_codec_get_option_info(SquashCodec *codec)
Get a list of options applicable to the codec.
Definition: codec.c:1032
SquashStatus
Status codes.
Definition: status.h:36
SquashStatus squash_error(SquashStatus status)
Emit an error.
Definition: status.c:173
One or more parameter values was not valid.
Definition: status.h:44
void squash_options_destroy(void *options)
Destroy a SquashOptions instance.
Definition: options.c:661
Operation completed successfully.
Definition: status.h:37
void squash_object_destroy(void *obj)
Destroy an object.
Definition: object.c:325
size_t squash_options_get_size(SquashOptions *options, const char *key)
Definition: options.c:277
One or more of the parameters were not valid.
Definition: status.h:43
void squash_object_init(void *obj, bool is_floating, SquashDestroyNotify destroy_notify)
Initialize a new object.
Definition: object.c:302