diff options
Diffstat (limited to 'm_option.c')
-rw-r--r-- | m_option.c | 1093 |
1 files changed, 501 insertions, 592 deletions
diff --git a/m_option.c b/m_option.c index a1cc139f8d..64a06d8971 100644 --- a/m_option.c +++ b/m_option.c @@ -28,6 +28,7 @@ #include <stdarg.h> #include <inttypes.h> #include <unistd.h> +#include <assert.h> #include "talloc.h" #include "m_option.h" @@ -35,22 +36,27 @@ #include "stream/url.h" #include "libavutil/avstring.h" -const m_option_t *m_option_list_find(const m_option_t *list, const char *name) +static const struct m_option *m_option_list_findb(const struct m_option *list, + struct bstr name) { - int i; - - for (i = 0; list[i].name; i++) { - int l = strlen(list[i].name) - 1; + for (int i = 0; list[i].name; i++) { + struct bstr lname = bstr(list[i].name); if ((list[i].type->flags & M_OPT_TYPE_ALLOW_WILDCARD) - && (l > 0) && (list[i].name[l] == '*')) { - if (strncasecmp(list[i].name, name, l) == 0) + && bstr_endswith0(lname, "*")) { + lname.len--; + if (bstrcasecmp(bstr_splice(name, 0, lname.len), lname) == 0) return &list[i]; - } else if (strcasecmp(list[i].name, name) == 0) + } else if (bstrcasecmp(lname, name) == 0) return &list[i]; } return NULL; } +const m_option_t *m_option_list_find(const m_option_t *list, const char *name) +{ + return m_option_list_findb(list, bstr(name)); +} + // Default function that just does a memcpy static void copy_opt(const m_option_t *opt, void *dst, const void *src) @@ -63,42 +69,32 @@ static void copy_opt(const m_option_t *opt, void *dst, const void *src) #define VAL(x) (*(int *)(x)) -static int parse_flag(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_flag(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { - if (param && !ambiguous_param) { - if (!strcasecmp(param, "yes") || /* any other language? */ - !strcasecmp(param, "on") || - !strcasecmp(param, "ja") || - !strcasecmp(param, "si") || - !strcasecmp(param, "igen") || - !strcasecmp(param, "y") || - !strcasecmp(param, "j") || - !strcasecmp(param, "i") || - !strcasecmp(param, "tak") || - !strcasecmp(param, "ja") || - !strcasecmp(param, "true") || - !strcmp(param, "1")) { - if (dst) - VAL(dst) = opt->max; - } else if (!strcasecmp(param, "no") || - !strcasecmp(param, "off") || - !strcasecmp(param, "nein") || - !strcasecmp(param, "nicht") || - !strcasecmp(param, "nem") || - !strcasecmp(param, "n") || - !strcasecmp(param, "nie") || - !strcasecmp(param, "nej") || - !strcasecmp(param, "false") || - !strcmp(param, "0")) { - if (dst) - VAL(dst) = opt->min; - } else { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Invalid parameter for %s flag: %s\n", name, param); - return M_OPT_INVALID; + if (param.len && !ambiguous_param) { + char * const enable[] = { "yes", "on", "ja", "si", "igen", "y", "j", + "i", "tak", "ja", "true", "1" }; + for (int i = 0; i < sizeof(enable) / sizeof(enable[0]); i++) { + if (!bstrcasecmp0(param, enable[i])) { + if (dst) + VAL(dst) = opt->max; + return 1; + } } - return 1; + char * const disable[] = { "no", "off", "nein", "nicht", "nem", "n", + "nie", "nej", "false", "0" }; + for (int i = 0; i < sizeof(disable) / sizeof(disable[0]); i++) { + if (!bstrcasecmp0(param, disable[i])) { + if (dst) + VAL(dst) = opt->min; + return 1; + } + } + mp_msg(MSGT_CFGPARSER, MSGL_ERR, + "Invalid parameter for %.*s flag: %.*s\n", + BSTR_P(name), BSTR_P(param)); + return M_OPT_INVALID; } else { if (dst) VAL(dst) = opt->max; @@ -129,48 +125,64 @@ const m_option_type_t m_option_type_flag = { // Integer -static int parse_int(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_longlong(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { - long long tmp_int; - char *endptr; - - if (param == NULL) + if (param.len == 0) return M_OPT_MISSING_PARAM; - tmp_int = strtoll(param, &endptr, 10); - if (*endptr) - tmp_int = strtoll(param, &endptr, 0); - if (*endptr) { + struct bstr rest; + long long tmp_int = bstrtoll(param, &rest, 10); + if (rest.len) + tmp_int = bstrtoll(param, &rest, 0); + if (rest.len) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %s option must be an integer: %s\n", name, param); + "The %.*s option must be an integer: %.*s\n", + BSTR_P(name), BSTR_P(param)); return M_OPT_INVALID; } if ((opt->flags & M_OPT_MIN) && (tmp_int < opt->min)) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %s option must be >= %d: %s\n", - name, (int) opt->min, param); + "The %.*s option must be >= %d: %.*s\n", + BSTR_P(name), (int) opt->min, BSTR_P(param)); return M_OPT_OUT_OF_RANGE; } if ((opt->flags & M_OPT_MAX) && (tmp_int > opt->max)) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %s option must be <= %d: %s\n", - name, (int) opt->max, param); + "The %.*s option must be <= %d: %.*s\n", + BSTR_P(name), (int) opt->max, BSTR_P(param)); return M_OPT_OUT_OF_RANGE; } - if (dst) { - if (opt->type->size == sizeof(int64_t)) - *(int64_t *)dst = tmp_int; - else - VAL(dst) = tmp_int; - } + if (dst) + *(long long *)dst = tmp_int; return 1; } +static int parse_int(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) +{ + long long tmp; + int r = parse_longlong(opt, name, param, false, &tmp); + if (r >= 0 && dst) + *(int *)dst = tmp; + return r; +} + +static int parse_int64(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) +{ + long long tmp; + int r = parse_longlong(opt, name, param, false, &tmp); + if (r >= 0 && dst) + *(int64_t *)dst = tmp; + return r; +} + + static char *print_int(const m_option_t *opt, const void *val) { if (opt->type->size == sizeof(int64_t)) @@ -196,7 +208,7 @@ const m_option_type_t m_option_type_int64 = { "", sizeof(int64_t), 0, - parse_int, + parse_int64, print_int, copy_opt, copy_opt, @@ -204,28 +216,25 @@ const m_option_type_t m_option_type_int64 = { NULL }; -static int parse_intpair(const struct m_option *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_intpair(const struct m_option *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { - if (param == NULL) + if (param.len == 0) return M_OPT_MISSING_PARAM; - char *s = (char *)param; - int start = -1; + struct bstr s = param; int end = -1; - if (*s) { - start = strtol(s, &s, 10); - if (s == param) - goto bad; - } - if (*s) { - if (*s != '-') + int start = bstrtoll(s, &s, 10); + if (s.len == param.len) + goto bad; + if (s.len > 0) { + if (!bstr_startswith0(s, "-")) goto bad; - s++; + s = bstr_cut(s, 1); } - if (*s) - end = strtol(s, &s, 10); - if (*s) + if (s.len > 0) + end = bstrtoll(s, &s, 10); + if (s.len > 0) goto bad; if (dst) { @@ -238,7 +247,8 @@ static int parse_intpair(const struct m_option *opt, const char *name, bad: mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid integer range " - "specification for option %s: %s\n", name, param); + "specification for option %.*s: %.*s\n", + BSTR_P(name), BSTR_P(param)); return M_OPT_INVALID; } @@ -250,19 +260,20 @@ const struct m_option_type m_option_type_intpair = { .set = copy_opt, }; -static int parse_choice(const struct m_option *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_choice(const struct m_option *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { - if (param == NULL) + if (param.len == 0) return M_OPT_MISSING_PARAM; struct m_opt_choice_alternatives *alt; for (alt = opt->priv; alt->name; alt++) - if (!strcmp(param, alt->name)) + if (!bstrcmp0(param, alt->name)) break; if (!alt->name) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid value for option %s: %s\n", - name, param); + mp_msg(MSGT_CFGPARSER, MSGL_ERR, + "Invalid value for option %.*s: %.*s\n", + BSTR_P(name), BSTR_P(param)); mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Valid values are:"); for (alt = opt->priv; alt->name; alt++) mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %s", alt->name); @@ -299,54 +310,54 @@ const struct m_option_type m_option_type_choice = { #undef VAL #define VAL(x) (*(double *)(x)) -static int parse_double(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_double(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { - double tmp_float; - char *endptr; - - if (param == NULL) + if (param.len == 0) return M_OPT_MISSING_PARAM; - tmp_float = strtod(param, &endptr); + struct bstr rest; + double tmp_float = bstrtod(param, &rest); - switch (*endptr) { + switch (rest.len ? rest.start[0] : 0) { case ':': case '/': - tmp_float /= strtod(endptr + 1, &endptr); + tmp_float /= bstrtod(bstr_cut(rest, 1), &rest); break; case '.': case ',': /* we also handle floats specified with * non-locale decimal point ::atmos */ + rest = bstr_cut(rest, 1); if (tmp_float < 0) - tmp_float -= 1.0 / pow(10, strlen(endptr + 1)) * - strtod(endptr + 1, &endptr); + tmp_float -= 1.0 / pow(10, rest.len) * bstrtod(rest, &rest); else - tmp_float += 1.0 / pow(10, strlen(endptr + 1)) * - strtod(endptr + 1, &endptr); + tmp_float += 1.0 / pow(10, rest.len) * bstrtod(rest, &rest); break; } - if (*endptr) { + if (rest.len) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %s option must be a floating point number or a " - "ratio (numerator[:/]denominator): %s\n", name, param); + "The %.*s option must be a floating point number or a " + "ratio (numerator[:/]denominator): %.*s\n", + BSTR_P(name), BSTR_P(param)); return M_OPT_INVALID; } if (opt->flags & M_OPT_MIN) if (tmp_float < opt->min) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %s option must be >= %f: %s\n", name, opt->min, param); + "The %.*s option must be >= %f: %.*s\n", + BSTR_P(name), opt->min, BSTR_P(param)); return M_OPT_OUT_OF_RANGE; } if (opt->flags & M_OPT_MAX) if (tmp_float > opt->max) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %s option must be <= %f: %s\n", name, opt->max, param); + "The %.*s option must be <= %f: %.*s\n", + BSTR_P(name), opt->max, BSTR_P(param)); return M_OPT_OUT_OF_RANGE; } @@ -377,8 +388,8 @@ const m_option_type_t m_option_type_double = { #undef VAL #define VAL(x) (*(float *)(x)) -static int parse_float(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_float(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { double tmp; int r = parse_double(opt, name, param, false, &tmp); @@ -410,40 +421,14 @@ const m_option_type_t m_option_type_float = { #undef VAL #define VAL(x) (*(off_t *)(x)) -static int parse_position(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_position(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { - off_t tmp_off; - char dummy; - - if (param == NULL) - return M_OPT_MISSING_PARAM; - if (sscanf(param, sizeof(off_t) == sizeof(int) ? - "%d%c" : "%"PRId64"%c", &tmp_off, &dummy) != 1) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %s option must be an integer: %s\n", opt->name, param); - return M_OPT_INVALID; - } - - if (opt->flags & M_OPT_MIN) - if (tmp_off < opt->min) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %s option must be >= %"PRId64 ": %s\n", - name, (int64_t) opt->min, param); - return M_OPT_OUT_OF_RANGE; - } - - if (opt->flags & M_OPT_MAX) - if (tmp_off > opt->max) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "The %s option must be <= %"PRId64 ": %s\n", - name, (int64_t) opt->max, param); - return M_OPT_OUT_OF_RANGE; - } - - if (dst) - VAL(dst) = tmp_off; - return 1; + long long tmp; + int r = parse_longlong(opt, name, param, false, &tmp); + if (r >= 0 && dst) + *(off_t *)dst = tmp; + return r; } static char *print_position(const m_option_t *opt, const void *val) @@ -470,29 +455,26 @@ const m_option_type_t m_option_type_position = { #undef VAL #define VAL(x) (*(char **)(x)) -static int parse_str(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_str(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { - - - if (param == NULL) - return M_OPT_MISSING_PARAM; - - if ((opt->flags & M_OPT_MIN) && (strlen(param) < opt->min)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Parameter must be >= %d chars: %s\n", - (int) opt->min, param); + if ((opt->flags & M_OPT_MIN) && (param.len < opt->min)) { + mp_msg(MSGT_CFGPARSER, MSGL_ERR, + "Parameter must be >= %d chars: %.*s\n", + (int) opt->min, BSTR_P(param)); return M_OPT_OUT_OF_RANGE; } - if ((opt->flags & M_OPT_MAX) && (strlen(param) > opt->max)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Parameter must be <= %d chars: %s\n", - (int) opt->max, param); + if ((opt->flags & M_OPT_MAX) && (param.len > opt->max)) { + mp_msg(MSGT_CFGPARSER, MSGL_ERR, + "Parameter must be <= %d chars: %.*s\n", + (int) opt->max, BSTR_P(param)); return M_OPT_OUT_OF_RANGE; } if (dst) { talloc_free(VAL(dst)); - VAL(dst) = talloc_strdup(NULL, param); + VAL(dst) = bstrdup0(NULL, param); } return 1; @@ -640,39 +622,43 @@ static int str_list_del(char **del, int n, void *dst) return 1; } -static char *get_nextsep(char *ptr, char sep, int modify) +static struct bstr get_nextsep(struct bstr *ptr, char sep, bool modify) { - char *last_ptr = ptr; + struct bstr str = *ptr; + struct bstr orig = str; for (;;) { - ptr = strchr(ptr, sep); - if (ptr && ptr > last_ptr && ptr[-1] == '\\') { - if (modify) - memmove(ptr - 1, ptr, strlen(ptr) + 1); - else - ptr++; - } else + int idx = bstrchr(str, sep); + if (idx > 0 && str.start[idx - 1] == '\\') { + if (modify) { + memmove(str.start + idx - 1, str.start + idx, str.len - idx); + str.len--; + str = bstr_cut(str, idx); + } else + str = bstr_cut(str, idx + 1); + } else { + str = bstr_cut(str, idx < 0 ? str.len : idx); break; + } } - return ptr; + *ptr = str; + return bstr_splice(orig, 0, str.start - orig.start); } -static int parse_str_list(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_str_list(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { - int n = 0, len = strlen(opt->name); - char *str; - char *ptr = (char *)param, *last_ptr, **res; + char **res; int op = OP_NONE; - - if (opt->name[len - 1] == '*' && ((int)strlen(name) > len - 1)) { - const char *n = &name[len - 1]; - if (strcasecmp(n, "-add") == 0) + int len = strlen(opt->name); + if (opt->name[len - 1] == '*' && (name.len > len - 1)) { + struct bstr suffix = bstr_cut(name, len - 1); + if (bstrcasecmp0(suffix, "-add") == 0) op = OP_ADD; - else if (strcasecmp(n, "-pre") == 0) + else if (bstrcasecmp0(suffix, "-pre") == 0) op = OP_PRE; - else if (strcasecmp(n, "-del") == 0) + else if (bstrcasecmp0(suffix, "-del") == 0) op = OP_DEL; - else if (strcasecmp(n, "-clr") == 0) + else if (bstrcasecmp0(suffix, "-clr") == 0) op = OP_CLR; else return M_OPT_UNKNOWN; @@ -686,19 +672,17 @@ static int parse_str_list(const m_option_t *opt, const char *name, } // All other ops need a param - if (param == NULL || strlen(param) == 0) + if (param.len == 0) return M_OPT_MISSING_PARAM; // custom type for "profile" calls this but uses ->priv for something else char separator = opt->type == &m_option_type_string_list && opt->priv ? *(char *)opt->priv : OPTION_LIST_SEPARATOR; - while (ptr[0] != '\0') { - ptr = get_nextsep(ptr, separator, 0); - if (!ptr) { - n++; - break; - } - ptr++; + int n = 0; + struct bstr str = param; + while (str.len) { + get_nextsep(&str, separator, 0); + str = bstr_cut(str, 1); n++; } if (n == 0) @@ -711,24 +695,18 @@ static int parse_str_list(const m_option_t *opt, const char *name, return 1; res = talloc_array(NULL, char *, n + 2); - ptr = str = talloc_strdup(NULL, param); + str = bstrdup(NULL, param); + char *ptr = str.start; n = 0; - while (1) { - last_ptr = ptr; - ptr = get_nextsep(ptr, separator, 1); - if (!ptr) { - res[n] = talloc_strdup(NULL, last_ptr); - n++; - break; - } - len = ptr - last_ptr; - res[n] = talloc_strndup(NULL, last_ptr, len); - ptr++; + while (str.len) { + struct bstr el = get_nextsep(&str, separator, 1); + res[n] = bstrdup0(NULL, el); + str = bstr_cut(str, 1); n++; } res[n] = NULL; - talloc_free(str); + talloc_free(ptr); switch (op) { case OP_ADD: @@ -841,8 +819,8 @@ static void free_func_pf(void *src) } // Parser for func_param -static int parse_func_pf(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_func_pf(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { struct m_func_save *s, *p; @@ -850,8 +828,8 @@ static int parse_func_pf(const m_option_t *opt, const char *name, return 1; s = talloc_zero(NULL, struct m_func_save); - s->name = talloc_strdup(NULL, name); - s->param = talloc_strdup(NULL, param); + s->name = bstrdup0(NULL, name); + s->param = bstrdup0(NULL, param); p = VAL(dst); if (p) { @@ -924,8 +902,8 @@ const m_option_type_t m_option_type_func_param = { #undef VAL -static int parse_func(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_func(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { return 0; } @@ -950,14 +928,19 @@ const m_option_type_t m_option_type_func = { /////////////////// Print -static int parse_print(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_print(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { if (opt->type == CONF_TYPE_PRINT_INDIRECT) mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", *(char **) opt->p); - else if (opt->type == CONF_TYPE_PRINT_FUNC) - return ((m_opt_func_full_t) opt->p)(opt, name, param); - else + else if (opt->type == CONF_TYPE_PRINT_FUNC) { + char *name0 = bstrdup0(NULL, name); + char *param0 = bstrdup0(NULL, param); + int r = ((m_opt_func_full_t) opt->p)(opt, name0, param0); + talloc_free(name0); + talloc_free(param0); + return r; + } else mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", mp_gtext(opt->p)); if (opt->priv == NULL) @@ -1009,102 +992,84 @@ const m_option_type_t m_option_type_print_func = { #undef VAL #define VAL(x) (*(char ***)(x)) -static int parse_subconf(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_subconf(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { - char *subparam; - char *subopt; - int nr = 0, i, r; - const m_option_t *subopts; - const char *p; + int nr = 0, i; char **lst = NULL; - if (param == NULL || strlen(param) == 0) + if (param.len == 0) return M_OPT_MISSING_PARAM; - subparam = talloc_size(NULL, strlen(param) + 1); - subopt = talloc_size(NULL, strlen(param) + 1); - p = param; - - subopts = opt->p; - - while (p[0]) { - int sscanf_ret = 1; - int optlen = strcspn(p, ":="); - /* clear out */ - subopt[0] = subparam[0] = 0; - av_strlcpy(subopt, p, optlen + 1); - p = &p[optlen]; - if (p[0] == '=') { - sscanf_ret = 2; - p = &p[1]; - if (p[0] == '"') { - p = &p[1]; - optlen = strcspn(p, "\""); - av_strlcpy(subparam, p, optlen + 1); - p = &p[optlen]; - if (p[0] != '"') { + struct bstr p = param; + const struct m_option *subopts = opt->p; + + while (p.len) { + int optlen = bstrcspn(p, ":="); + struct bstr subopt = bstr_splice(p, 0, optlen); + struct bstr subparam = bstr(NULL); + p = bstr_cut(p, optlen); + if (bstr_startswith0(p, "=")) { + p = bstr_cut(p, 1); + if (bstr_startswith0(p, "\"")) { + p = bstr_cut(p, 1); + optlen = bstrcspn(p, "\""); + subparam = bstr_splice(p, 0, optlen); + p = bstr_cut(p, optlen); + if (!bstr_startswith0(p, "\"")) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Terminating '\"' missing for '%s'\n", subopt); + "Terminating '\"' missing for '%.*s'\n", + BSTR_P(subopt)); return M_OPT_INVALID; } - p = &p[1]; - } else if (p[0] == '%') { - p = &p[1]; - optlen = (int)strtol(p, (char **)&p, 0); - if (!p || p[0] != '%' || (optlen > strlen(p) - 1)) { + p = bstr_cut(p, 1); + } else if (bstr_startswith0(p, "%")) { + p = bstr_cut(p, 1); + optlen = bstrtoll(p, &p, 0); + if (!bstr_startswith0(p, "%") || (optlen > p.len - 1)) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Invalid length %i for '%s'\n", optlen, subopt); + "Invalid length %d for '%.*s'\n", + optlen, BSTR_P(subopt)); return M_OPT_INVALID; } - p = &p[1]; - av_strlcpy(subparam, p, optlen + 1); - p = &p[optlen]; + subparam = bstr_splice(p, 1, optlen + 1); + p = bstr_cut(p, optlen + 1); } else { - optlen = strcspn(p, ":"); - av_strlcpy(subparam, p, optlen + 1); - p = &p[optlen]; + optlen = bstrcspn(p, ":"); + subparam = bstr_splice(p, 0, optlen); + p = bstr_cut(p, optlen); } } - if (p[0] == ':') - p = &p[1]; - else if (p[0]) { + if (bstr_startswith0(p, ":")) + p = bstr_cut(p, 1); + else if (p.len > 0) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Incorrect termination for '%s'\n", subopt); + "Incorrect termination for '%.*s'\n", BSTR_P(subopt)); return M_OPT_INVALID; } - switch (sscanf_ret) { - case 1: - subparam[0] = 0; - case 2: - for (i = 0; subopts[i].name; i++) - if (!strcmp(subopts[i].name, subopt)) - break; - if (!subopts[i].name) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %s: Unknown suboption %s\n", name, subopt); - return M_OPT_UNKNOWN; - } - r = m_option_parse(&subopts[i], subopt, - subparam[0] == 0 ? NULL : subparam, false, - NULL); - if (r < 0) - return r; - if (dst) { - lst = talloc_realloc(NULL, lst, char *, 2 * (nr + 2)); - lst[2 * nr] = talloc_strdup(NULL, subopt); - lst[2 * nr + 1] = subparam[0] == 0 ? NULL : - talloc_strdup(NULL, subparam); - memset(&lst[2 * (nr + 1)], 0, 2 * sizeof(char *)); - nr++; - } - break; + for (i = 0; subopts[i].name; i++) + if (!bstrcmp0(subopt, subopts[i].name)) + break; + if (!subopts[i].name) { + mp_msg(MSGT_CFGPARSER, MSGL_ERR, + "Option %.*s: Unknown suboption %.*s\n", + BSTR_P(name), BSTR_P(subopt)); + return M_OPT_UNKNOWN; + } + int r = m_option_parse(&subopts[i], subopt, subparam, false, NULL); + if (r < 0) + return r; + if (dst) { + lst = talloc_realloc(NULL, lst, char *, 2 * (nr + 2)); + lst[2 * nr] = bstrdup0(NULL, subopt); + lst[2 * nr + 1] = subparam.len == 0 ? NULL : + bstrdup0(NULL, subparam); + memset(&lst[2 * (nr + 1)], 0, 2 * sizeof(char *)); + nr++; } } - talloc_free(subparam); - talloc_free(subopt); if (dst) VAL(dst) = lst; @@ -1204,16 +1169,16 @@ static struct { { NULL, 0 } }; -static int parse_imgfmt(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_imgfmt(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { uint32_t fmt = 0; int i; - if (param == NULL || strlen(param) == 0) + if (param.len == 0) return M_OPT_MISSING_PARAM; - if (!strcmp(param, "help")) { + if (!bstrcmp0(param, "help")) { mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available formats:"); for (i = 0; mp_imgfmt_list[i].name; i++) mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %s", mp_imgfmt_list[i].name); @@ -1221,16 +1186,19 @@ static int parse_imgfmt(const m_option_t *opt, const char *name, return M_OPT_EXIT - 1; } - if (sscanf(param, "0x%x", &fmt) != 1) { + if (bstr_startswith0(param, "0x")) + fmt = bstrtoll(param, NULL, 16); + else { for (i = 0; mp_imgfmt_list[i].name; i++) { - if (!strcasecmp(param, mp_imgfmt_list[i].name)) { + if (!bstrcasecmp0(param, mp_imgfmt_list[i].name)) { fmt = mp_imgfmt_list[i].fmt; break; } } if (!mp_imgfmt_list[i].name) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %s: unknown format name: '%s'\n", name, param); + "Option %.*s: unknown format name: '%.*s'\n", + BSTR_P(name), BSTR_P(param)); return M_OPT_INVALID; } } @@ -1296,16 +1264,16 @@ static struct { { NULL, 0 } }; -static int parse_afmt(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_afmt(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { uint32_t fmt = 0; int i; - if (param == NULL || strlen(param) == 0) + if (param.len == 0) return M_OPT_MISSING_PARAM; - if (!strcmp(param, "help")) { + if (!bstrcmp0(param, "help")) { mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available formats:"); for (i = 0; mp_afmt_list[i].name; i++) mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %s", mp_afmt_list[i].name); @@ -1313,16 +1281,19 @@ static int parse_afmt(const m_option_t *opt, const char *name, return M_OPT_EXIT - 1; } - if (sscanf(param, "0x%x", &fmt) != 1) { + if (bstr_startswith0(param, "0x")) + fmt = bstrtoll(param, NULL, 16); + else { for (i = 0; mp_afmt_list[i].name; i++) { - if (!strcasecmp(param, mp_afmt_list[i].name)) { + if (!bstrcasecmp0(param, mp_afmt_list[i].name)) { fmt = mp_afmt_list[i].fmt; break; } } if (!mp_afmt_list[i].name) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %s: unknown format name: '%s'\n", name, param); + "Option %.*s: unknown format name: '%.*s'\n", + BSTR_P(name), BSTR_P(param)); return M_OPT_INVALID; } } @@ -1347,36 +1318,36 @@ const m_option_type_t m_option_type_afmt = { }; -int parse_timestring(const char *str, double *time, char endchar) +static int parse_timestring(struct bstr str, double *time, char endchar) { int a, b, len; double d; *time = 0; /* ensure initialization for error cases */ - if (sscanf(str, "%d:%d:%lf%n", &a, &b, &d, &len) >= 3) + if (bstr_sscanf(str, "%d:%d:%lf%n", &a, &b, &d, &len) >= 3) *time = 3600 * a + 60 * b + d; - else if (sscanf(str, "%d:%lf%n", &a, &d, &len) >= 2) + else if (bstr_sscanf(str, "%d:%lf%n", &a, &d, &len) >= 2) *time = 60 * a + d; - else if (sscanf(str, "%lf%n", &d, &len) >= 1) + else if (bstr_sscanf(str, "%lf%n", &d, &len) >= 1) *time = d; else return 0; /* unsupported time format */ - if (str[len] && str[len] != endchar) + if (len < str.len && str.start[len] != endchar) return 0; /* invalid extra characters at the end */ return len; } -static int parse_time(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_time(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { double time; - if (param == NULL || strlen(param) == 0) + if (param.len == 0) return M_OPT_MISSING_PARAM; if (!parse_timestring(param, &time, 0)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: invalid time: '%s'\n", - name, param); + mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %.*s: invalid time: '%.*s'\n", + BSTR_P(name), BSTR_P(param)); return M_OPT_INVALID; } @@ -1401,19 +1372,19 @@ const m_option_type_t m_option_type_time = { // Time or size (-endpos) -static int parse_time_size(const m_option_t *opt, const char *name, - const char *param, bool ambiguous_param, void *dst) +static int parse_time_size(const m_option_t *opt, struct bstr name, + struct bstr param, bool ambiguous_param, void *dst) { m_time_size_t ts; char unit[4]; double end_at; - if (param == NULL || strlen(param) == 0) + if (param.len == 0) return M_OPT_MISSING_PARAM; ts.pos = 0; /* End at size parsing */ - if (sscanf(param, "%lf%3s", &end_at, unit) == 2) { + if (bstr_sscanf(param, "%lf%3s", &end_at, unit) == 2) { ts.type = END_AT_SIZE; if (!strcasecmp(unit, "b")) ; @@ -1436,8 +1407,8 @@ static int parse_time_size(const m_option_t *opt, const char *name, * even a number followed by garbage */ if (!parse_timestring(param, &end_at, 0)) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %s: invalid time or size: '%s'\n", - name, param); + "Option %.*s: invalid time or size: '%.*s'\n", + BSTR_P(name), BSTR_P(param)); return M_OPT_INVALID; } @@ -1470,7 +1441,7 @@ const m_option_type_t m_option_type_time_size = { #undef VAL #define VAL(x) (*(m_obj_settings_t **)(x)) -static int find_obj_desc(const char *name, const m_obj_list_t *l, +static int find_obj_desc(struct bstr name, const m_obj_list_t *l, const m_struct_t **ret) { int i; @@ -1478,7 +1449,7 @@ static int find_obj_desc(const char *name, const m_obj_list_t *l, for (i = 0; l->list[i]; i++) { n = M_ST_MB(char *, l->list[i], l->name_off); - if (!strcmp(n, name)) { + if (!bstrcmp0(name, n)) { *ret = M_ST_MB(m_struct_t *, l->list[i], l->desc_off); |