diff options
Diffstat (limited to 'core/m_option.c')
-rw-r--r-- | core/m_option.c | 274 |
1 files changed, 26 insertions, 248 deletions
diff --git a/core/m_option.c b/core/m_option.c index 02258416ec..41916befeb 100644 --- a/core/m_option.c +++ b/core/m_option.c @@ -1776,8 +1776,6 @@ const m_option_type_t m_option_type_rel_time = { //// Objects (i.e. filters, etc) settings -#include "core/m_struct.h" - #undef VAL #define VAL(x) (*(m_obj_settings_t **)(x)) @@ -1963,7 +1961,7 @@ static void copy_obj_settings_list(const m_option_t *opt, void *dst, // option names/values are correct. Try to determine whether an option // without '=' sets a flag, or whether it's a positional argument. static int get_obj_param(bstr opt_name, bstr obj_name, struct m_config *config, - bstr name, bstr val, int *nold, + bstr name, bstr val, int flags, int *nold, bstr *out_name, bstr *out_val) { int r; @@ -1975,7 +1973,7 @@ static int get_obj_param(bstr opt_name, bstr obj_name, struct m_config *config, // If it's just "name", and the associated option exists and is a flag, // don't accept it as positional argument. if (val.start || m_config_option_requires_param(config, name) == 0) { - r = m_config_set_option(config, name, val); + r = m_config_set_option_ext(config, name, val, flags); if (r < 0) { if (r == M_OPT_UNKNOWN) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, @@ -2007,7 +2005,7 @@ static int get_obj_param(bstr opt_name, bstr obj_name, struct m_config *config, BSTR_P(opt_name), BSTR_P(obj_name), *nold, *nold); return M_OPT_OUT_OF_RANGE; } - r = m_config_set_option(config, bstr0(opt), val); + r = m_config_set_option_ext(config, bstr0(opt), val, flags); if (r < 0) { if (r > M_OPT_EXIT) mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %.*s: " @@ -2023,11 +2021,14 @@ static int get_obj_param(bstr opt_name, bstr obj_name, struct m_config *config, } // Consider -vf a=b:c:d. This parses "b:c:d" into name/value pairs, stored as -// linear array in *_ret. In particular, desc contains what options a the +// linear array in *_ret. In particular, config contains what options a the // object takes, and verifies the option values as well. -static int get_obj_params(struct bstr opt_name, struct bstr name, - struct bstr *pstr, struct m_obj_desc *desc, - char ***ret) +// If config is NULL, all parameters are accepted without checking. +// _ret set to NULL can be used for checking-only. +// flags can contain any M_SETOPT_* flag. +int m_obj_parse_sub_config(struct bstr opt_name, struct bstr name, + struct bstr *pstr, struct m_config *config, + int flags, char ***ret) { int nold = 0; char **args = NULL; @@ -2040,8 +2041,6 @@ static int get_obj_params(struct bstr opt_name, struct bstr name, num_args++; } - struct m_config *config = m_config_from_obj_desc(NULL, desc); - while (pstr->len > 0) { bstr fname, fval; r = split_subconf(opt_name, pstr, &fname, &fval); @@ -2049,7 +2048,7 @@ static int get_obj_params(struct bstr opt_name, struct bstr name, goto exit; if (bstr_equals0(fname, "help")) goto print_help; - r = get_obj_param(opt_name, name, config, fname, fval, &nold, + r = get_obj_param(opt_name, name, config, fname, fval, flags, &nold, &fname, &fval); if (r < 0) goto exit; @@ -2088,7 +2087,6 @@ print_help: ; exit: free_str_list(&args); - talloc_free(config); return r; } @@ -2121,26 +2119,22 @@ static int parse_obj_settings(struct bstr opt, struct bstr *pstr, if (bstr_eatstart0(pstr, "=") || bstr_eatstart0(pstr, ":")) has_param = true; - if (!m_obj_list_find(&desc, list, str)) { + bool legacy = false; + bool skip = false; + if (m_obj_list_find(&desc, list, str)) { + legacy = !desc.priv_size && list->legacy_hacks; + } else { if (!list->allow_unknown_entries) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %.*s: %.*s doesn't exist.\n", BSTR_P(opt), BSTR_P(str)); return M_OPT_INVALID; } desc = (struct m_obj_desc){0}; - } - - if (desc.init_options && desc.options && _ret) { - bstr s = bstr0(desc.init_options); - r = get_obj_params(opt, str, &s, &desc, &plist); - if (r < 0 || s.len > 0) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Internal error: preset broken\n"); - return r; - } + skip = true; } if (has_param) { - if (!desc.options && list->legacy_hacks) { + if (legacy) { // Should perhaps be parsed as escape-able string. But this is a // compatibility path, so it's not worth the trouble. int next = bstrcspn(*pstr, ","); @@ -2158,7 +2152,13 @@ static int parse_obj_settings(struct bstr opt, struct bstr *pstr, plist[1] = bstrto0(NULL, param); } } else { - r = get_obj_params(opt, str, pstr, &desc, _ret ? &plist : NULL); + struct m_config *config = NULL; + if (!skip) + config = m_config_from_obj_desc(NULL, &desc); + r = m_obj_parse_sub_config(opt, str, pstr, config, + M_SETOPT_CHECK_ONLY, + _ret ? &plist : NULL); + talloc_free(config); if (r < 0) return r; } @@ -2379,7 +2379,7 @@ static int parse_obj_settings_list(const m_option_t *opt, struct bstr name, int found = obj_settings_find_by_content(list, &res[n]); if (found < 0) { mp_msg(MSGT_CFGPARSER, MSGL_WARN, - "Option %.*s: Item bot found\n", BSTR_P(name)); + "Option %.*s: Item not found\n", BSTR_P(name)); } else { obj_settings_list_del_at(&list, found); } @@ -2405,225 +2405,3 @@ const m_option_type_t m_option_type_obj_settings_list = { .copy = copy_obj_settings_list, .free = free_obj_settings_list, }; - - -/* Replace escape sequences in an URL (or a part of an URL) */ -/* works like strcpy(), but without return argument, - except that outbuf == inbuf is allowed */ -static void url_unescape_string(char *outbuf, const char *inbuf) -{ - unsigned char c,c1,c2; - int i,len=strlen(inbuf); - for (i=0;i<len;i++) { - c = inbuf[i]; - if (c == '%' && i<len-2) { //must have 2 more chars - c1 = toupper(inbuf[i+1]); // we need uppercase characters - c2 = toupper(inbuf[i+2]); - if (((c1>='0' && c1<='9') || (c1>='A' && c1<='F')) && - ((c2>='0' && c2<='9') || (c2>='A' && c2<='F')) ) - { - if (c1>='0' && c1<='9') - c1-='0'; - else - c1-='A'-10; - if (c2>='0' && c2<='9') - c2-='0'; - else - c2-='A'-10; - c = (c1<<4) + c2; - i=i+2; //only skip next 2 chars if valid esc - } - } - *outbuf++ = c; - } - *outbuf++='\0'; //add nullterm to string -} - -static int parse_custom_url(const m_option_t *opt, struct bstr name, - struct bstr url, void *dst) -{ - int r; - m_struct_t *desc = opt->priv; - - if (!desc) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %.*s: Custom URL needs " - "a pointer to a m_struct_t in the priv field.\n", BSTR_P(name)); - return M_OPT_PARSER_ERR; - } - - // extract the protocol - int idx = bstr_find0(url, "://"); - if (idx < 0) { - // Filename only - if (m_option_list_find(desc->fields, "filename")) { - m_struct_set(desc, dst, "filename", url); - return 1; - } - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: URL doesn't have a valid protocol!\n", - BSTR_P(name)); - return M_OPT_INVALID; - } - struct bstr ptr1 = bstr_cut(url, idx + 3); - if (m_option_list_find(desc->fields, "string")) { - if (ptr1.len > 0) { - m_struct_set(desc, dst, "string", ptr1); - return 1; - } - } - if (dst && m_option_list_find(desc->fields, "protocol")) { - r = m_struct_set(desc, dst, "protocol", bstr_splice(url, 0, idx)); - if (r < 0) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: Error while setting protocol.\n", - BSTR_P(name)); - return r; - } - } - - // check if a username:password is given - idx = bstrchr(ptr1, '/'); - if (idx < 0) - idx = ptr1.len; - struct bstr hostpart = bstr_splice(ptr1, 0, idx); - struct bstr path = bstr_cut(ptr1, idx); - idx = bstrchr(hostpart, '@'); - if (idx >= 0) { - struct bstr userpass = bstr_splice(hostpart, 0, idx); - hostpart = bstr_cut(hostpart, idx + 1); - // We got something, at least a username... - if (!m_option_list_find(desc->fields, "username")) { - mp_msg(MSGT_CFGPARSER, MSGL_WARN, - "Option %.*s: This URL doesn't have a username part.\n", - BSTR_P(name)); - // skip - } else { - idx = bstrchr(userpass, ':'); - if (idx >= 0) { - // We also have a password - if (!m_option_list_find(desc->fields, "password")) { - mp_msg(MSGT_CFGPARSER, MSGL_WARN, - "Option %.*s: This URL doesn't have a password part.\n", - BSTR_P(name)); - // skip - } else { // Username and password - if (dst) { - r = m_struct_set(desc, dst, "username", - bstr_splice(userpass, 0, idx)); - if (r < 0) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: Error while setting username.\n", - BSTR_P(name)); - return r; - } - r = m_struct_set(desc, dst, "password", - bstr_splice(userpass, idx+1, - userpass.len)); - if (r < 0) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: Error while setting password.\n", - BSTR_P(name)); - return r; - } - } - } - } else { // User name only - r = m_struct_set(desc, dst, "username", userpass); - if (r < 0) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: Error while setting username.\n", - BSTR_P(name)); - return r; - } - } - } - } - - // Before looking for a port number check if we have an IPv6 type - // numeric address. - // In an IPv6 URL the numeric address should be inside square braces. - int idx1 = bstrchr(hostpart, '['); - int idx2 = bstrchr(hostpart, ']'); - struct bstr portstr = hostpart; - bool v6addr = false; - if (idx1 >= 0 && idx2 >= 0 && idx1 < idx2) { - // we have an IPv6 numeric address - portstr = bstr_cut(hostpart, idx2); - hostpart = bstr_splice(hostpart, idx1 + 1, idx2); - v6addr = true; - } - - idx = bstrchr(portstr, ':'); - if (idx >= 0) { - if (!v6addr) - hostpart = bstr_splice(hostpart, 0, idx); - // We have an URL beginning like http://www.hostname.com:1212 - // Get the port number - if (!m_option_list_find(desc->fields, "port")) { - mp_msg(MSGT_CFGPARSER, MSGL_WARN, - "Option %.*s: This URL doesn't have a port part.\n", - BSTR_P(name)); - // skip - } else { - if (dst) { - int p = bstrtoll(bstr_cut(portstr, idx + 1), NULL, 0); - char tmp[100]; - snprintf(tmp, 99, "%d", p); - r = m_struct_set(desc, dst, "port", bstr0(tmp)); - if (r < 0) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: Error while setting port.\n", - BSTR_P(name)); - return r; - } - } - } - } - // Get the hostname - if (hostpart.len > 0) { - if (!m_option_list_find(desc->fields, "hostname")) { - mp_msg(MSGT_CFGPARSER, MSGL_WARN, - "Option %.*s: This URL doesn't have a hostname part.\n", - BSTR_P(name)); - // skip - } else { - r = m_struct_set(desc, dst, "hostname", hostpart); - if (r < 0) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: Error while setting hostname.\n", - BSTR_P(name)); - return r; - } - } - } - // Look if a path is given - if (path.len > 1) { // not just "/" - // copy the path/filename in the URL container - if (!m_option_list_find(desc->fields, "filename")) { - mp_msg(MSGT_CFGPARSER, MSGL_WARN, - "Option %.*s: This URL doesn't have a filename part.\n", - BSTR_P(name)); - // skip - } else { - if (dst) { - char *fname = bstrdup0(NULL, bstr_cut(path, 1)); - url_unescape_string(fname, fname); - r = m_struct_set(desc, dst, "filename", bstr0(fname)); - talloc_free(fname); - if (r < 0) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: Error while setting filename.\n", - BSTR_P(name)); - return r; - } - } - } - } - return 1; -} - -/// TODO : Write the other needed funcs for 'normal' options -const m_option_type_t m_option_type_custom_url = { - .name = "Custom URL", - .parse = parse_custom_url, -}; |