diff options
author | Nicolas George <nicolas.george@normalesup.org> | 2012-08-13 18:39:56 +0400 |
---|---|---|
committer | Nicolas George <nicolas.george@normalesup.org> | 2012-09-30 11:21:29 +0400 |
commit | 438978fb4b4663c404e7474e8ef98f3c856cd31a (patch) | |
tree | 78575942c2afcdccbf890a4d2fba8c37570bd1cf /libavutil/opt.c | |
parent | 5f1c3c785c786f3c78c350d4503fcfd794fa3c64 (diff) |
opt: implement av_opt_set_from_string().
It is similar to av_set_options_string() but accepts a list
of options that can be in shorthand: if the key is omitted
on the first fields, the keys from the shorthand list are
assumed, in order.
Diffstat (limited to 'libavutil/opt.c')
-rw-r--r-- | libavutil/opt.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/libavutil/opt.c b/libavutil/opt.c index 0957281076..d826b4bcd3 100644 --- a/libavutil/opt.c +++ b/libavutil/opt.c @@ -790,6 +790,91 @@ int av_set_options_string(void *ctx, const char *opts, return count; } +#define WHITESPACES " \n\t" + +static int is_key_char(char c) +{ + return (unsigned)((c | 32) - 'a') < 26 || + (unsigned)(c - '0') < 10 || + c == '-' || c == '_' || c == '/' || c == '.'; +} + +/** + * Read a key from a string. The key consists of is_key_char characters and + * must be terminated by a character from the delim string; spaces are + * ignored. The key buffer must be 4 bytes larger than the longest + * acceptable key. If the key is too long, an ellipsis will be written at + * the end. @return 0 for success (even with ellipsis), <0 for failure + */ +static int get_key(const char **ropts, const char *delim, char *key, unsigned key_size) +{ + unsigned key_pos = 0; + const char *opts = *ropts; + + opts += strspn(opts, WHITESPACES); + while (is_key_char(*opts)) { + key[key_pos++] = *opts; + if (key_pos == key_size) + key_pos--; + (opts)++; + } + opts += strspn(opts, WHITESPACES); + if (!*opts || !strchr(delim, *opts)) + return AVERROR(EINVAL); + opts++; + key[key_pos++] = 0; + if (key_pos == key_size) + key[key_pos - 4] = key[key_pos - 3] = key[key_pos - 2] = '.'; + *ropts = opts; + return 0; +} + +int av_opt_set_from_string(void *ctx, const char *opts, + const char *const *shorthand, + const char *key_val_sep, const char *pairs_sep) +{ + int ret, count = 0; + const char *dummy_shorthand = NULL; + char key_buf[68], *value; + const char *key; + + if (!opts) + return 0; + if (!shorthand) + shorthand = &dummy_shorthand; + + while (*opts) { + if ((ret = get_key(&opts, key_val_sep, key_buf, sizeof(key_buf))) < 0) { + if (*shorthand) { + key = *(shorthand++); + } else { + av_log(ctx, AV_LOG_ERROR, "No option name near '%s'\n", opts); + return AVERROR(EINVAL); + } + } else { + key = key_buf; + while (*shorthand) /* discard all remaining shorthand */ + shorthand++; + } + + if (!(value = av_get_token(&opts, pairs_sep))) + return AVERROR(ENOMEM); + if (*opts && strchr(pairs_sep, *opts)) + opts++; + + av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value); + if ((ret = av_opt_set(ctx, key, value, 0)) < 0) { + if (ret == AVERROR_OPTION_NOT_FOUND) + av_log(ctx, AV_LOG_ERROR, "Option '%s' not found\n", key); + return ret; + } + + av_free(value); + count++; + } + return count; +} + void av_opt_free(void *obj) { const AVOption *o = NULL; @@ -986,6 +1071,37 @@ int main(void) av_freep(&test_ctx.string); } + printf("\nTesting av_opt_set_from_string()\n"); + { + TestContext test_ctx = { 0 }; + const char *options[] = { + "", + "5", + "5:hello", + "5:hello:size=pal", + "5:size=pal:hello", + ":", + "=", + " 5 : hello : size = pal ", + "a_very_long_option_name_that_will_need_to_be_ellipsized_around_here=42" + }; + const char *shorthand[] = { "num", "string", NULL }; + + test_ctx.class = &test_class; + av_opt_set_defaults(&test_ctx); + test_ctx.string = av_strdup("default"); + + av_log_set_level(AV_LOG_DEBUG); + + for (i=0; i < FF_ARRAY_ELEMS(options); i++) { + av_log(&test_ctx, AV_LOG_DEBUG, "Setting options string '%s'\n", options[i]); + if (av_opt_set_from_string(&test_ctx, options[i], shorthand, "=", ":") < 0) + av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]); + printf("\n"); + } + av_freep(&test_ctx.string); + } + return 0; } |