2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
36 #include "stream/url.h"
37 #include "libmpcodecs/img_format.h"
40 char *m_option_strerror(int code
)
44 return mp_gtext("Unrecognized option name");
45 case M_OPT_MISSING_PARAM
:
46 return mp_gtext("Required parameter for option missing");
48 return mp_gtext("Option parameter could not be parsed");
49 case M_OPT_OUT_OF_RANGE
:
50 return mp_gtext("Parameter is outside values allowed for option");
51 case M_OPT_PARSER_ERR
:
52 return mp_gtext("Parser error");
58 static const struct m_option
*m_option_list_findb(const struct m_option
*list
,
61 for (int i
= 0; list
[i
].name
; i
++) {
62 struct bstr lname
= bstr(list
[i
].name
);
63 if ((list
[i
].type
->flags
& M_OPT_TYPE_ALLOW_WILDCARD
)
64 && bstr_endswith0(lname
, "*")) {
66 if (bstrcasecmp(bstr_splice(name
, 0, lname
.len
), lname
) == 0)
68 } else if (bstrcasecmp(lname
, name
) == 0)
74 const m_option_t
*m_option_list_find(const m_option_t
*list
, const char *name
)
76 return m_option_list_findb(list
, bstr(name
));
79 // Default function that just does a memcpy
81 static void copy_opt(const m_option_t
*opt
, void *dst
, const void *src
,
85 memcpy(dst
, src
, opt
->type
->size
);
90 #define VAL(x) (*(int *)(x))
92 static int parse_flag(const m_option_t
*opt
, struct bstr name
,
93 struct bstr param
, bool ambiguous_param
, void *dst
,
96 if (param
.len
&& !ambiguous_param
) {
97 char * const enable
[] = { "yes", "on", "ja", "si", "igen", "y", "j",
98 "i", "tak", "ja", "true", "1" };
99 for (int i
= 0; i
< sizeof(enable
) / sizeof(enable
[0]); i
++) {
100 if (!bstrcasecmp0(param
, enable
[i
])) {
106 char * const disable
[] = { "no", "off", "nein", "nicht", "nem", "n",
107 "nie", "nej", "false", "0" };
108 for (int i
= 0; i
< sizeof(disable
) / sizeof(disable
[0]); i
++) {
109 if (!bstrcasecmp0(param
, disable
[i
])) {
115 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
116 "Invalid parameter for %.*s flag: %.*s\n",
117 BSTR_P(name
), BSTR_P(param
));
118 return M_OPT_INVALID
;
126 static char *print_flag(const m_option_t
*opt
, const void *val
)
128 if (VAL(val
) == opt
->min
)
129 return talloc_strdup(NULL
, "no");
131 return talloc_strdup(NULL
, "yes");
134 const m_option_type_t m_option_type_flag
= {
135 // need yes or no in config files
145 static int parse_longlong(const m_option_t
*opt
, struct bstr name
,
146 struct bstr param
, bool ambiguous_param
, void *dst
)
149 return M_OPT_MISSING_PARAM
;
152 long long tmp_int
= bstrtoll(param
, &rest
, 10);
154 tmp_int
= bstrtoll(param
, &rest
, 0);
156 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
157 "The %.*s option must be an integer: %.*s\n",
158 BSTR_P(name
), BSTR_P(param
));
159 return M_OPT_INVALID
;
162 if ((opt
->flags
& M_OPT_MIN
) && (tmp_int
< opt
->min
)) {
163 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
164 "The %.*s option must be >= %d: %.*s\n",
165 BSTR_P(name
), (int) opt
->min
, BSTR_P(param
));
166 return M_OPT_OUT_OF_RANGE
;
169 if ((opt
->flags
& M_OPT_MAX
) && (tmp_int
> opt
->max
)) {
170 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
171 "The %.*s option must be <= %d: %.*s\n",
172 BSTR_P(name
), (int) opt
->max
, BSTR_P(param
));
173 return M_OPT_OUT_OF_RANGE
;
177 *(long long *)dst
= tmp_int
;
182 static int parse_int(const m_option_t
*opt
, struct bstr name
,
183 struct bstr param
, bool ambiguous_param
, void *dst
,
187 int r
= parse_longlong(opt
, name
, param
, false, &tmp
);
193 static int parse_int64(const m_option_t
*opt
, struct bstr name
,
194 struct bstr param
, bool ambiguous_param
, void *dst
,
198 int r
= parse_longlong(opt
, name
, param
, false, &tmp
);
200 *(int64_t *)dst
= tmp
;
205 static char *print_int(const m_option_t
*opt
, const void *val
)
207 if (opt
->type
->size
== sizeof(int64_t))
208 return talloc_asprintf(NULL
, "%"PRId64
, *(const int64_t *)val
);
209 return talloc_asprintf(NULL
, "%d", VAL(val
));
212 const m_option_type_t m_option_type_int
= {
220 const m_option_type_t m_option_type_int64
= {
222 .size
= sizeof(int64_t),
223 .parse
= parse_int64
,
228 static int parse_intpair(const struct m_option
*opt
, struct bstr name
,
229 struct bstr param
, bool ambiguous_param
, void *dst
,
233 return M_OPT_MISSING_PARAM
;
235 struct bstr s
= param
;
237 int start
= bstrtoll(s
, &s
, 10);
238 if (s
.len
== param
.len
)
241 if (!bstr_startswith0(s
, "-"))
246 end
= bstrtoll(s
, &s
, 10);
259 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Invalid integer range "
260 "specification for option %.*s: %.*s\n",
261 BSTR_P(name
), BSTR_P(param
));
262 return M_OPT_INVALID
;
265 const struct m_option_type m_option_type_intpair
= {
267 .size
= sizeof(int[2]),
268 .parse
= parse_intpair
,
272 static int parse_choice(const struct m_option
*opt
, struct bstr name
,
273 struct bstr param
, bool ambiguous_param
, void *dst
,
277 return M_OPT_MISSING_PARAM
;
279 struct m_opt_choice_alternatives
*alt
;
280 for (alt
= opt
->priv
; alt
->name
; alt
++)
281 if (!bstrcasecmp0(param
, alt
->name
))
284 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
285 "Invalid value for option %.*s: %.*s\n",
286 BSTR_P(name
), BSTR_P(param
));
287 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Valid values are:");
288 for (alt
= opt
->priv
; alt
->name
; alt
++)
289 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, " %s", alt
->name
);
290 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "\n");
291 return M_OPT_INVALID
;
294 *(int *)dst
= alt
->value
;
299 static char *print_choice(const m_option_t
*opt
, const void *val
)
302 struct m_opt_choice_alternatives
*alt
;
303 for (alt
= opt
->priv
; alt
->name
; alt
++)
305 return talloc_strdup(NULL
, alt
->name
);
309 const struct m_option_type m_option_type_choice
= {
310 .name
= "String", // same as arbitrary strings in option list for now
312 .parse
= parse_choice
,
313 .print
= print_choice
,
320 #define VAL(x) (*(double *)(x))
322 static int parse_double(const m_option_t
*opt
, struct bstr name
,
323 struct bstr param
, bool ambiguous_param
, void *dst
,
327 return M_OPT_MISSING_PARAM
;
330 double tmp_float
= bstrtod(param
, &rest
);
332 switch (rest
.len
? rest
.start
[0] : 0) {
335 tmp_float
/= bstrtod(bstr_cut(rest
, 1), &rest
);
339 /* we also handle floats specified with
340 * non-locale decimal point ::atmos
342 rest
= bstr_cut(rest
, 1);
344 tmp_float
-= 1.0 / pow(10, rest
.len
) * bstrtod(rest
, &rest
);
346 tmp_float
+= 1.0 / pow(10, rest
.len
) * bstrtod(rest
, &rest
);
351 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
352 "The %.*s option must be a floating point number or a "
353 "ratio (numerator[:/]denominator): %.*s\n",
354 BSTR_P(name
), BSTR_P(param
));
355 return M_OPT_INVALID
;
358 if (opt
->flags
& M_OPT_MIN
)
359 if (tmp_float
< opt
->min
) {
360 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
361 "The %.*s option must be >= %f: %.*s\n",
362 BSTR_P(name
), opt
->min
, BSTR_P(param
));
363 return M_OPT_OUT_OF_RANGE
;
366 if (opt
->flags
& M_OPT_MAX
)
367 if (tmp_float
> opt
->max
) {
368 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
369 "The %.*s option must be <= %f: %.*s\n",
370 BSTR_P(name
), opt
->max
, BSTR_P(param
));
371 return M_OPT_OUT_OF_RANGE
;
375 VAL(dst
) = tmp_float
;
379 static char *print_double(const m_option_t
*opt
, const void *val
)
382 return talloc_asprintf(NULL
, "%f", VAL(val
));
385 const m_option_type_t m_option_type_double
= {
386 // double precision float or ratio (numerator[:/]denominator)
388 .size
= sizeof(double),
389 .parse
= parse_double
,
390 .print
= print_double
,
395 #define VAL(x) (*(float *)(x))
397 static int parse_float(const m_option_t
*opt
, struct bstr name
,
398 struct bstr param
, bool ambiguous_param
, void *dst
,
402 int r
= parse_double(opt
, name
, param
, false, &tmp
, NULL
);
408 static char *print_float(const m_option_t
*opt
, const void *val
)
411 return talloc_asprintf(NULL
, "%f", VAL(val
));
414 const m_option_type_t m_option_type_float
= {
415 // floating point number or ratio (numerator[:/]denominator)
417 .size
= sizeof(float),
418 .parse
= parse_float
,
419 .print
= print_float
,
423 ///////////// Position
425 #define VAL(x) (*(off_t *)(x))
427 static int parse_position(const m_option_t
*opt
, struct bstr name
,
428 struct bstr param
, bool ambiguous_param
, void *dst
,
432 int r
= parse_longlong(opt
, name
, param
, false, &tmp
);
438 static char *print_position(const m_option_t
*opt
, const void *val
)
440 return talloc_asprintf(NULL
, "%"PRId64
, (int64_t)VAL(val
));
443 const m_option_type_t m_option_type_position
= {
446 .size
= sizeof(off_t
),
447 .parse
= parse_position
,
448 .print
= print_position
,
456 #define VAL(x) (*(char **)(x))
458 static int parse_str(const m_option_t
*opt
, struct bstr name
,
459 struct bstr param
, bool ambiguous_param
, void *dst
,
462 if (param
.start
== NULL
)
463 return M_OPT_MISSING_PARAM
;
465 if ((opt
->flags
& M_OPT_MIN
) && (param
.len
< opt
->min
)) {
466 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
467 "Parameter must be >= %d chars: %.*s\n",
468 (int) opt
->min
, BSTR_P(param
));
469 return M_OPT_OUT_OF_RANGE
;
472 if ((opt
->flags
& M_OPT_MAX
) && (param
.len
> opt
->max
)) {
473 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
474 "Parameter must be <= %d chars: %.*s\n",
475 (int) opt
->max
, BSTR_P(param
));
476 return M_OPT_OUT_OF_RANGE
;
480 talloc_free(VAL(dst
));
481 VAL(dst
) = bstrdup0(talloc_ctx
, param
);
488 static char *print_str(const m_option_t
*opt
, const void *val
)
490 return (val
&& VAL(val
)) ? talloc_strdup(NULL
, VAL(val
)) : NULL
;
493 static void copy_str(const m_option_t
*opt
, void *dst
, const void *src
,
497 talloc_free(VAL(dst
));
498 VAL(dst
) = talloc_strdup(talloc_ctx
, VAL(src
));
502 static void free_str(void *src
)
504 if (src
&& VAL(src
)) {
505 talloc_free(VAL(src
));
510 const m_option_type_t m_option_type_string
= {
512 .size
= sizeof(char *),
513 .flags
= M_OPT_TYPE_DYNAMIC
,
520 //////////// String list
523 #define VAL(x) (*(char ***)(x))
531 static void free_str_list(void *dst
)
536 if (!dst
|| !VAL(dst
))
540 for (i
= 0; d
[i
] != NULL
; i
++)
546 static int str_list_add(char **add
, int n
, void *dst
, int pre
, void *talloc_ctx
)
548 char **lst
= VAL(dst
);
552 return M_OPT_PARSER_ERR
;
555 for (ln
= 0; lst
&& lst
[ln
]; ln
++)
558 lst
= talloc_realloc(NULL
, lst
, char *, n
+ ln
+ 1);
561 memmove(&lst
[n
], lst
, ln
* sizeof(char *));
562 memcpy(lst
, add
, n
* sizeof(char *));
564 memcpy(&lst
[ln
], add
, n
* sizeof(char *));
565 // (re-)add NULL-termination
575 static int str_list_del(char **del
, int n
, void *dst
)
582 return M_OPT_PARSER_ERR
;
585 for (ln
= 0; lst
&& lst
[ln
]; ln
++)
589 for (i
= 0; del
[i
] != NULL
; i
++) {
590 idx
= strtol(del
[i
], &ep
, 0);
592 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Invalid index: %s\n", del
[i
]);
597 if (idx
< 0 || idx
>= ln
) {
598 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
599 "Index %ld is out of range.\n", idx
);
601 } else if (!lst
[idx
])
603 talloc_free(lst
[idx
]);
615 // Don't bother shrinking the list allocation
616 for (i
= 0, n
= 0; i
< ln
; i
++) {
627 static struct bstr
get_nextsep(struct bstr
*ptr
, char sep
, bool modify
)
629 struct bstr str
= *ptr
;
630 struct bstr orig
= str
;
632 int idx
= bstrchr(str
, sep
);
633 if (idx
> 0 && str
.start
[idx
- 1] == '\\') {
635 memmove(str
.start
+ idx
- 1, str
.start
+ idx
, str
.len
- idx
);
637 str
= bstr_cut(str
, idx
);
639 str
= bstr_cut(str
, idx
+ 1);
641 str
= bstr_cut(str
, idx
< 0 ? str
.len
: idx
);
646 return bstr_splice(orig
, 0, str
.start
- orig
.start
);
649 static int parse_str_list(const m_option_t
*opt
, struct bstr name
,
650 struct bstr param
, bool ambiguous_param
, void *dst
,
655 int len
= strlen(opt
->name
);
656 if (opt
->name
[len
- 1] == '*' && (name
.len
> len
- 1)) {
657 struct bstr suffix
= bstr_cut(name
, len
- 1);
658 if (bstrcasecmp0(suffix
, "-add") == 0)
660 else if (bstrcasecmp0(suffix
, "-pre") == 0)
662 else if (bstrcasecmp0(suffix
, "-del") == 0)
664 else if (bstrcasecmp0(suffix
, "-clr") == 0)
667 return M_OPT_UNKNOWN
;
677 // All other ops need a param
679 return M_OPT_MISSING_PARAM
;
681 // custom type for "profile" calls this but uses ->priv for something else
682 char separator
= opt
->type
== &m_option_type_string_list
&& opt
->priv
?
683 *(char *)opt
->priv
: OPTION_LIST_SEPARATOR
;
685 struct bstr str
= param
;
687 get_nextsep(&str
, separator
, 0);
688 str
= bstr_cut(str
, 1);
692 return M_OPT_INVALID
;
693 if (((opt
->flags
& M_OPT_MIN
) && (n
< opt
->min
)) ||
694 ((opt
->flags
& M_OPT_MAX
) && (n
> opt
->max
)))
695 return M_OPT_OUT_OF_RANGE
;
700 res
= talloc_array(talloc_ctx
, char *, n
+ 2);
701 str
= bstrdup(NULL
, param
);
702 char *ptr
= str
.start
;
706 struct bstr el
= get_nextsep(&str
, separator
, 1);
707 res
[n
] = bstrdup0(talloc_ctx
, el
);
711 str
= bstr_cut(str
, 1);
718 return str_list_add(res
, n
, dst
, 0, talloc_ctx
);
720 return str_list_add(res
, n
, dst
, 1, talloc_ctx
);
722 return str_list_del(res
, n
, dst
);
732 static void copy_str_list(const m_option_t
*opt
, void *dst
, const void *src
,
750 for (n
= 0; s
[n
] != NULL
; n
++)
752 d
= talloc_array(talloc_ctx
, char *, n
+ 1);
754 d
[n
] = talloc_strdup(talloc_ctx
, s
[n
]);
759 static char *print_str_list(const m_option_t
*opt
, const void *src
)
764 if (!(src
&& VAL(src
)))
768 for (int i
= 0; lst
[i
]; i
++) {
770 ret
= talloc_strdup_append_buffer(ret
, ",");
771 ret
= talloc_strdup_append_buffer(ret
, lst
[i
]);
776 const m_option_type_t m_option_type_string_list
= {
777 /* A list of strings separated by ','.
778 * Option with a name ending in '*' permits using the following suffixes:
779 * -add: Add the given parameters at the end of the list.
780 * -pre: Add the given parameters at the beginning of the list.
781 * -del: Remove the entry at the given indices.
782 * -clr: Clear the list.
783 * e.g: -vf-add flip,mirror -vf-del 2,5
785 .name
= "String list",
786 .size
= sizeof(char **),
787 .flags
= M_OPT_TYPE_DYNAMIC
| M_OPT_TYPE_ALLOW_WILDCARD
,
788 .parse
= parse_str_list
,
789 .print
= print_str_list
,
790 .copy
= copy_str_list
,
791 .free
= free_str_list
,
795 /////////////////// Print
797 static int parse_print(const m_option_t
*opt
, struct bstr name
,
798 struct bstr param
, bool ambiguous_param
, void *dst
,
801 if (opt
->type
== CONF_TYPE_PRINT_INDIRECT
)
802 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "%s", *(char **) opt
->p
);
803 else if (opt
->type
== CONF_TYPE_PRINT_FUNC
) {
804 char *name0
= bstrdup0(NULL
, name
);
805 char *param0
= bstrdup0(NULL
, param
);
806 int r
= ((m_opt_func_full_t
) opt
->p
)(opt
, name0
, param0
);
811 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "%s", mp_gtext(opt
->p
));
813 if (opt
->priv
== NULL
)
818 const m_option_type_t m_option_type_print
= {
820 .parse
= parse_print
,
823 const m_option_type_t m_option_type_print_indirect
= {
825 .parse
= parse_print
,
828 const m_option_type_t m_option_type_print_func
= {
830 .flags
= M_OPT_TYPE_ALLOW_WILDCARD
,
831 .parse
= parse_print
,
835 /////////////////////// Subconfig
837 #define VAL(x) (*(char ***)(x))
839 static int parse_subconf(const m_option_t
*opt
, struct bstr name
,
840 struct bstr param
, bool ambiguous_param
, void *dst
,
847 return M_OPT_MISSING_PARAM
;
849 struct bstr p
= param
;
852 int optlen
= bstrcspn(p
, ":=");
853 struct bstr subopt
= bstr_splice(p
, 0, optlen
);
854 struct bstr subparam
= bstr(NULL
);
855 p
= bstr_cut(p
, optlen
);
856 if (bstr_startswith0(p
, "=")) {
858 if (bstr_startswith0(p
, "\"")) {
860 optlen
= bstrcspn(p
, "\"");
861 subparam
= bstr_splice(p
, 0, optlen
);
862 p
= bstr_cut(p
, optlen
);
863 if (!bstr_startswith0(p
, "\"")) {
864 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
865 "Terminating '\"' missing for '%.*s'\n",
867 return M_OPT_INVALID
;
870 } else if (bstr_startswith0(p
, "%")) {
872 optlen
= bstrtoll(p
, &p
, 0);
873 if (!bstr_startswith0(p
, "%") || (optlen
> p
.len
- 1)) {
874 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
875 "Invalid length %d for '%.*s'\n",
876 optlen
, BSTR_P(subopt
));
877 return M_OPT_INVALID
;
879 subparam
= bstr_splice(p
, 1, optlen
+ 1);
880 p
= bstr_cut(p
, optlen
+ 1);
882 optlen
= bstrcspn(p
, ":");
883 subparam
= bstr_splice(p
, 0, optlen
);
884 p
= bstr_cut(p
, optlen
);
887 if (bstr_startswith0(p
, ":"))
889 else if (p
.len
> 0) {
890 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
891 "Incorrect termination for '%.*s'\n", BSTR_P(subopt
));
892 return M_OPT_INVALID
;
896 lst
= talloc_realloc(NULL
, lst
, char *, 2 * (nr
+ 2));
897 lst
[2 * nr
] = bstrdup0(lst
, subopt
);
898 lst
[2 * nr
+ 1] = bstrdup0(lst
, subparam
);
899 memset(&lst
[2 * (nr
+ 1)], 0, 2 * sizeof(char *));
910 const m_option_type_t m_option_type_subconfig
= {
911 // The syntax is -option opt1=foo:flag:opt2=blah
913 .flags
= M_OPT_TYPE_HAS_CHILD
,
914 .parse
= parse_subconf
,
917 static int parse_imgfmt(const m_option_t
*opt
, struct bstr name
,
918 struct bstr param
, bool ambiguous_param
, void *dst
,
924 return M_OPT_MISSING_PARAM
;
926 if (!bstrcmp0(param
, "help")) {
927 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available formats:");
928 for (int i
= 0; mp_imgfmt_list
[i
].name
; i
++)
929 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, " %s", mp_imgfmt_list
[i
].name
);
930 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
931 return M_OPT_EXIT
- 1;
934 if (bstr_startswith0(param
, "0x"))
935 fmt
= bstrtoll(param
, NULL
, 16);
937 fmt
= imgfmt_parse(param
, false);
939 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
940 "Option %.*s: unknown format name: '%.*s'\n",
941 BSTR_P(name
), BSTR_P(param
));
942 return M_OPT_INVALID
;
947 *((uint32_t *)dst
) = fmt
;
952 const m_option_type_t m_option_type_imgfmt
= {
953 // Please report any missing colorspaces
954 .name
= "Image format",
955 .size
= sizeof(uint32_t),
956 .parse
= parse_imgfmt
,
960 #include "libaf/af_format.h"
962 /* FIXME: snyc with af_format.h */
968 {"mulaw", AF_FORMAT_MU_LAW
},
969 {"alaw", AF_FORMAT_A_LAW
},
970 {"mpeg2", AF_FORMAT_MPEG2
},
971 {"ac3le", AF_FORMAT_AC3_LE
},
972 {"ac3be", AF_FORMAT_AC3_BE
},
973 {"ac3ne", AF_FORMAT_AC3_NE
},
974 {"imaadpcm", AF_FORMAT_IMA_ADPCM
},
976 {"u8", AF_FORMAT_U8
},
977 {"s8", AF_FORMAT_S8
},
978 {"u16le", AF_FORMAT_U16_LE
},
979 {"u16be", AF_FORMAT_U16_BE
},
980 {"u16ne", AF_FORMAT_U16_NE
},
981 {"s16le", AF_FORMAT_S16_LE
},
982 {"s16be", AF_FORMAT_S16_BE
},
983 {"s16ne", AF_FORMAT_S16_NE
},
984 {"u24le", AF_FORMAT_U24_LE
},
985 {"u24be", AF_FORMAT_U24_BE
},
986 {"u24ne", AF_FORMAT_U24_NE
},
987 {"s24le", AF_FORMAT_S24_LE
},
988 {"s24be", AF_FORMAT_S24_BE
},
989 {"s24ne", AF_FORMAT_S24_NE
},
990 {"u32le", AF_FORMAT_U32_LE
},
991 {"u32be", AF_FORMAT_U32_BE
},
992 {"u32ne", AF_FORMAT_U32_NE
},
993 {"s32le", AF_FORMAT_S32_LE
},
994 {"s32be", AF_FORMAT_S32_BE
},
995 {"s32ne", AF_FORMAT_S32_NE
},
996 {"floatle", AF_FORMAT_FLOAT_LE
},
997 {"floatbe", AF_FORMAT_FLOAT_BE
},
998 {"floatne", AF_FORMAT_FLOAT_NE
},
1002 static int parse_afmt(const m_option_t
*opt
, struct bstr name
,
1003 struct bstr param
, bool ambiguous_param
, void *dst
,
1010 return M_OPT_MISSING_PARAM
;
1012 if (!bstrcmp0(param
, "help")) {
1013 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available formats:");
1014 for (i
= 0; mp_afmt_list
[i
].name
; i
++)
1015 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, " %s", mp_afmt_list
[i
].name
);
1016 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1017 return M_OPT_EXIT
- 1;
1020 if (bstr_startswith0(param
, "0x"))
1021 fmt
= bstrtoll(param
, NULL
, 16);
1023 for (i
= 0; mp_afmt_list
[i
].name
; i
++) {
1024 if (!bstrcasecmp0(param
, mp_afmt_list
[i
].name
)) {
1025 fmt
= mp_afmt_list
[i
].fmt
;
1029 if (!mp_afmt_list
[i
].name
) {
1030 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1031 "Option %.*s: unknown format name: '%.*s'\n",
1032 BSTR_P(name
), BSTR_P(param
));
1033 return M_OPT_INVALID
;
1038 *((uint32_t *)dst
) = fmt
;
1043 const m_option_type_t m_option_type_afmt
= {
1044 // Please report any missing formats
1045 .name
= "Audio format",
1046 .size
= sizeof(uint32_t),
1047 .parse
= parse_afmt
,
1052 static int parse_timestring(struct bstr str
, double *time
, char endchar
)
1056 *time
= 0; /* ensure initialization for error cases */
1057 if (bstr_sscanf(str
, "%d:%d:%lf%n", &a
, &b
, &d
, &len
) >= 3)
1058 *time
= 3600 * a
+ 60 * b
+ d
;
1059 else if (bstr_sscanf(str
, "%d:%lf%n", &a
, &d
, &len
) >= 2)
1061 else if (bstr_sscanf(str
, "%lf%n", &d
, &len
) >= 1)
1064 return 0; /* unsupported time format */
1065 if (len
< str
.len
&& str
.start
[len
] != endchar
)
1066 return 0; /* invalid extra characters at the end */
1071 static int parse_time(const m_option_t
*opt
, struct bstr name
,
1072 struct bstr param
, bool ambiguous_param
, void *dst
,
1078 return M_OPT_MISSING_PARAM
;
1080 if (!parse_timestring(param
, &time
, 0)) {
1081 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: invalid time: '%.*s'\n",
1082 BSTR_P(name
), BSTR_P(param
));
1083 return M_OPT_INVALID
;
1087 *(double *)dst
= time
;
1091 const m_option_type_t m_option_type_time
= {
1093 .size
= sizeof(double),
1094 .parse
= parse_time
,
1095 .print
= print_double
,
1100 // Time or size (-endpos)
1102 static int parse_time_size(const m_option_t
*opt
, struct bstr name
,
1103 struct bstr param
, bool ambiguous_param
, void *dst
,
1111 return M_OPT_MISSING_PARAM
;
1114 /* End at size parsing */
1115 if (bstr_sscanf(param
, "%lf%3s", &end_at
, unit
) == 2) {
1116 ts
.type
= END_AT_SIZE
;
1117 if (!strcasecmp(unit
, "b"))
1119 else if (!strcasecmp(unit
, "kb"))
1121 else if (!strcasecmp(unit
, "mb"))
1122 end_at
*= 1024 * 1024;
1123 else if (!strcasecmp(unit
, "gb"))
1124 end_at
*= 1024 * 1024 * 1024;
1126 ts
.type
= END_AT_NONE
;
1128 if (ts
.type
== END_AT_SIZE
) {
1134 /* End at time parsing. This has to be last because the parsing accepts
1135 * even a number followed by garbage */
1136 if (!parse_timestring(param
, &end_at
, 0)) {
1137 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1138 "Option %.*s: invalid time or size: '%.*s'\n",
1139 BSTR_P(name
), BSTR_P(param
));
1140 return M_OPT_INVALID
;
1143 ts
.type
= END_AT_TIME
;
1147 *(m_time_size_t
*)dst
= ts
;
1151 const m_option_type_t m_option_type_time_size
= {
1152 .name
= "Time or size",
1153 .size
= sizeof(m_time_size_t
),
1154 .parse
= parse_time_size
,
1159 //// Objects (i.e. filters, etc) settings
1161 #include "m_struct.h"
1164 #define VAL(x) (*(m_obj_settings_t **)(x))
1166 static int find_obj_desc(struct bstr name
, const m_obj_list_t
*l
,
1167 const m_struct_t
**ret
)
1172 for (i
= 0; l
->list
[i
]; i
++) {
1173 n
= M_ST_MB(char *, l
->list
[i
], l
->name_off
);
1174 if (!bstrcmp0(name
, n
)) {
1175 *ret
= M_ST_MB(m_struct_t
*, l
->list
[i
], l
->desc_off
);
1182 static int get_obj_param(struct bstr opt_name
, struct bstr obj_name
,
1183 const m_struct_t
*desc
, struct bstr str
, int *nold
,
1184 int oldmax
, char **dst
)
1186 const m_option_t
*opt
;
1189 int eq
= bstrchr(str
, '=');
1191 if (eq
> 0) { // eq == 0 ignored
1192 struct bstr p
= bstr_cut(str
, eq
+ 1);
1193 str
= bstr_splice(str
, 0, eq
);
1194 opt
= m_option_list_findb(desc
->fields
, str
);
1196 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1197 "Option %.*s: %.*s doesn't have a %.*s parameter.\n",
1198 BSTR_P(opt_name
), BSTR_P(obj_name
), BSTR_P(str
));
1199 return M_OPT_UNKNOWN
;
1201 r
= m_option_parse(opt
, str
, p
, false, NULL
);
1204 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: "
1205 "Error while parsing %.*s parameter %.*s (%.*s)\n",
1206 BSTR_P(opt_name
), BSTR_P(obj_name
), BSTR_P(str
),
1211 dst
[0] = bstrdup0(NULL
, str
);
1212 dst
[1] = bstrdup0(NULL
, p
);
1215 if ((*nold
) >= oldmax
) {
1216 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: %.*s has only %d params, so you can't give more than %d unnamed params.\n",
1217 BSTR_P(opt_name
), BSTR_P(obj_name
), oldmax
, oldmax
);
1218 return M_OPT_OUT_OF_RANGE
;
1220 opt
= &desc
->fields
[(*nold
)];
1221 r
= m_option_parse(opt
, bstr(opt
->name
), str
, false, NULL
);
1224 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: "
1225 "Error while parsing %.*s parameter %s (%.*s)\n",
1226 BSTR_P(opt_name
), BSTR_P(obj_name
), opt
->name
,
1231 dst
[0] = talloc_strdup(NULL
, opt
->name
);
1232 dst
[1] = bstrdup0(NULL
, str
);
1239 static int get_obj_params(struct bstr opt_name
, struct bstr name
,
1240 struct bstr params
, const m_struct_t
*desc
,
1241 char separator
, char ***_ret
)
1243 int n
= 0, nold
= 0, nopts
;
1246 if (!bstrcmp0(params
, "help")) { // Help
1247 char min
[50], max
[50];
1248 if (!desc
->fields
) {
1249 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1250 "%.*s doesn't have any options.\n\n", BSTR_P(name
));
1251 return M_OPT_EXIT
- 1;
1253 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1254 "\n Name Type Min Max\n\n");
1255 for (n
= 0; desc
->fields
[n
].name
; n
++) {
1256 const m_option_t
*opt
= &desc
->fields
[n
];
1257 if (opt
->type
->flags
& M_OPT_TYPE_HAS_CHILD
)
1259 if (opt
->flags
& M_OPT_MIN
)
1260 sprintf(min
, "%-8.0f", opt
->min
);
1263 if (opt
->flags
& M_OPT_MAX
)
1264 sprintf(max
, "%-8.0f", opt
->max
);
1267 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1268 " %-20.20s %-15.15s %-10.10s %-10.10s\n",
1269 opt
->name
, opt
->type
->name
, min
, max
);
1271 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1272 return M_OPT_EXIT
- 1;
1275 for (nopts
= 0; desc
->fields
[nopts
].name
; nopts
++)
1278 // TODO : Check that each opt can be parsed
1279 struct bstr s
= params
;
1282 int idx
= bstrchr(s
, separator
);
1287 struct bstr field
= bstr_splice(s
, 0, idx
);
1288 s
= bstr_cut(s
, idx
+ 1);
1289 if (field
.len
== 0) { // Empty field, count it and go on
1292 int r
= get_obj_param(opt_name
, name
, desc
, field
, &nold
, nopts
,
1302 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Too many options for %.*s\n",
1304 return M_OPT_OUT_OF_RANGE
;
1306 if (!_ret
) // Just test
1308 if (n
== 0) // No options or only empty options
1311 ret
= talloc_array(NULL
, char *, (n
+ 2) * 2);
1316 int idx
= bstrchr(s
, separator
);
1319 struct bstr field
= bstr_splice(s
, 0, idx
);
1320 s
= bstr_cut(s
, idx
+ 1);
1321 if (field
.len
== 0) { // Empty field, count it and go on
1324 get_obj_param(opt_name
, name
, desc
, field
, &nold
, nopts
,
1329 ret
[n
* 2] = ret
[n
* 2 + 1] = NULL
;
1335 static int parse_obj_params(const m_option_t
*opt
, struct bstr name
,
1336 struct bstr param
, bool ambiguous_param
, void *dst
,
1341 m_obj_params_t
*p
= opt
->priv
;
1342 const m_struct_t
*desc
;
1344 // We need the object desc
1346 return M_OPT_INVALID
;
1349 r
= get_obj_params(name
, bstr(desc
->name
), param
, desc
, p
->separator
,
1350 dst
? &opts
: NULL
);
1355 if (!opts
) // no arguments given
1358 for (r
= 0; opts
[r
]; r
+= 2)
1359 m_struct_set(desc
, dst
, opts
[r
], bstr(opts
[r
+ 1]));
1365 const m_option_type_t m_option_type_obj_params
= {
1366 .name
= "Object params",
1367 .parse
= parse_obj_params
,
1370 /// Some predefined types as a definition would be quite lengthy
1373 static const m_span_t m_span_params_dflts
= {
1376 static const m_option_t m_span_params_fields
[] = {
1377 {"start", M_ST_OFF(m_span_t
, start
), CONF_TYPE_INT
, M_OPT_MIN
, 1, 0, NULL
},
1378 {"end", M_ST_OFF(m_span_t
, end
), CONF_TYPE_INT
, M_OPT_MIN
, 1, 0, NULL
},
1379 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
1381 static const struct m_struct_st m_span_opts
= {
1384 &m_span_params_dflts
,
1385 m_span_params_fields
1387 const m_obj_params_t m_span_params_def
= {
1392 static int parse_obj_settings(struct bstr opt
, struct bstr str
,
1393 const m_obj_list_t
*list
,
1394 m_obj_settings_t
**_ret
, int ret_n
)
1397 char **plist
= NULL
;
1398 const m_struct_t
*desc
;
1399 m_obj_settings_t
*ret
= _ret
? *_ret
: NULL
;
1401 struct bstr param
= bstr(NULL
);
1402 int idx
= bstrchr(str
, '=');
1404 param
= bstr_cut(str
, idx
+ 1);
1405 str
= bstr_splice(str
, 0, idx
);
1408 if (!find_obj_desc(str
, list
, &desc
)) {
1409 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: %.*s doesn't exist.\n",
1410 BSTR_P(opt
), BSTR_P(str
));
1411 return M_OPT_INVALID
;
1415 if (!desc
&& _ret
) {
1416 if (!bstrcmp0(param
, "help")) {
1417 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1418 "Option %.*s: %.*s have no option description.\n",
1419 BSTR_P(opt
), BSTR_P(str
));
1420 return M_OPT_EXIT
- 1;
1422 plist
= talloc_zero_array(NULL
, char *, 4);
1423 plist
[0] = talloc_strdup(NULL
, "_oldargs_");
1424 plist
[1] = bstrdup0(NULL
, param
);
1426 r
= get_obj_params(opt
, str
, param
, desc
, ':',
1427 _ret
? &plist
: NULL
);
1435 ret
= talloc_realloc(NULL
, ret
, struct m_obj_settings
, ret_n
+ 2);
1436 memset(&ret
[ret_n
], 0, 2 * sizeof(m_obj_settings_t
));
1437 ret
[ret_n
].name
= bstrdup0(NULL
, str
);
1438 ret
[ret_n
].attribs
= plist
;
1444 static int obj_settings_list_del(struct bstr opt_name
, struct bstr param
,
1445 bool ambiguous_param
, void *dst
)
1447 char **str_list
= NULL
;
1448 int r
, i
, idx_max
= 0;
1449 char *rem_id
= "_removed_marker_";
1451 assert(opt_name
.len
< 100);
1452 memcpy(name
, opt_name
.start
, opt_name
.len
);
1453 name
[opt_name
.len
] = 0;
1454 const m_option_t list_opt
= {
1455 name
, NULL
, CONF_TYPE_STRING_LIST
,
1458 m_obj_settings_t
*obj_list
= dst
? VAL(dst
) : NULL
;
1460 if (dst
&& !obj_list
) {
1461 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
, "Option %.*s: the list is empty.\n",
1464 } else if (obj_list
) {
1465 for (idx_max
= 0; obj_list
[idx_max
].name
!= NULL
; idx_max
++)
1469 r
= m_option_parse(&list_opt
, opt_name
, param
, false, &str_list
);
1470 if (r
< 0 || !str_list
)
1473 for (r
= 0; str_list
[r
]; r
++) {
1476 id
= strtol(str_list
[r
], &endptr
, 0);
1477 if (endptr
== str_list
[r
]) {
1478 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: invalid parameter. We need a list of integers which are the indices of the elements to remove.\n", BSTR_P(opt_name
));
1479 m_option_free(&list_opt
, &str_list
);
1480 return M_OPT_INVALID
;
1484 if (id
>= idx_max
|| id
< -idx_max
) {
1485 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1486 "Option %.*s: Index %d is out of range.\n",
1487 BSTR_P(opt_name
), id
);
1492 talloc_free(obj_list
[id
].name
);
1493 free_str_list(&(obj_list
[id
].attribs
));
1494 obj_list
[id
].name
= rem_id
;
1498 m_option_free(&list_opt
, &str_list
);
1502 for (i
= 0; obj_list
[i
].name
; i
++) {
1503 while (obj_list
[i
].name
== rem_id
) {
1504 memmove(&obj_list
[i
], &obj_list
[i
+ 1],
1505 sizeof(m_obj_settings_t
) * (idx_max
- i
));
1509 obj_list
= talloc_realloc(NULL
, obj_list
, struct m_obj_settings
,
1511 VAL(dst
) = obj_list
;
1516 static void free_obj_settings_list(void *dst
)
1519 m_obj_settings_t
*d
;
1521 if (!dst
|| !VAL(dst
))
1525 for (n
= 0; d
[n
].name
; n
++) {
1526 talloc_free(d
[n
].name
);
1527 free_str_list(&(d
[n
].attribs
));
1533 static int parse_obj_settings_list(const m_option_t
*opt
, struct bstr name
,
1534 struct bstr param
, bool ambiguous_param
,
1535 void *dst
, void *talloc_ctx
)
1537 int len
= strlen(opt
->name
);
1538 m_obj_settings_t
*res
= NULL
, *queue
= NULL
, *head
= NULL
;
1541 // We need the objects list
1543 return M_OPT_INVALID
;
1545 if (opt
->name
[len
- 1] == '*' && (name
.len
> len
- 1)) {
1546 struct bstr suffix
= bstr_cut(name
, len
- 1);
1547 if (bstrcasecmp0(suffix
, "-add") == 0)
1549 else if (bstrcasecmp0(suffix
, "-pre") == 0)
1551 else if (bstrcasecmp0(suffix
, "-del") == 0)
1553 else if (bstrcasecmp0(suffix
, "-clr") == 0)
1557 strncpy(prefix
, opt
->name
, len
- 1);
1558 prefix
[len
- 1] = '\0';
1559 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1560 "Option %.*s: unknown postfix %.*s\n"
1561 "Supported postfixes are:\n"
1563 " Append the given list to the current list\n\n"
1565 " Prepend the given list to the current list\n\n"
1567 " Remove the given elements. Take the list element index (starting from 0).\n"
1568 " Negative index can be used (i.e. -1 is the last element)\n\n"
1570 " Clear the current list.\n",
1571 BSTR_P(name
), BSTR_P(suffix
), prefix
, prefix
, prefix
, prefix
);
1573 return M_OPT_UNKNOWN
;
1577 // Clear the list ??
1580 free_obj_settings_list(dst
);
1585 return M_OPT_MISSING_PARAM
;
1597 return obj_settings_list_del(name
, param
, false, dst
);
1599 if (dst
&& VAL(dst
))
1600 free_obj_settings_list(dst
);
1603 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: FIXME\n", BSTR_P(name
));
1604 return M_OPT_UNKNOWN
;
1607 if (!bstrcmp0(param
, "help")) {
1608 m_obj_list_t
*ol
= opt
->priv
;
1609 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available video filters:\n");
1610 for (int n
= 0; ol
->list
[n
]; n
++)
1611 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, " %-15s: %s\n",
1612 M_ST_MB(char *, ol
->list
[n
], ol
->name_off
),
1613 M_ST_MB(char *, ol
->list
[n
], ol
->info_off
));
1614 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1615 return M_OPT_EXIT
- 1;
1618 struct bstr s
= bstrdup(NULL
, param
);
1619 char *allocptr
= s
.start
;
1622 struct bstr el
= get_nextsep(&s
, OPTION_LIST_SEPARATOR
, 1);
1623 int r
= parse_obj_settings(name
, el
, opt
->priv
, dst
? &res
: NULL
, n
);
1625 talloc_free(allocptr
);
1631 talloc_free(allocptr
);
1633 return M_OPT_INVALID
;
1635 if (((opt
->flags
& M_OPT_MIN
) && (n
< opt
->min
)) ||
1636 ((opt
->flags
& M_OPT_MAX
) && (n
> opt
->max
)))
1637 return M_OPT_OUT_OF_RANGE
;
1642 for (qsize
= 0; queue
[qsize
].name
; qsize
++)
1644 res
= talloc_realloc(NULL
, res
, struct m_obj_settings
,
1646 memcpy(&res
[n
], queue
, (qsize
+ 1) * sizeof(m_obj_settings_t
));
1652 for (hsize
= 0; head
[hsize
].name
; hsize
++)
1654 head
= talloc_realloc(NULL
, head
, struct m_obj_settings
,
1656 memcpy(&head
[hsize
], res
, (n
+ 1) * sizeof(m_obj_settings_t
));
1665 static void copy_obj_settings_list(const m_option_t
*opt
, void *dst
,
1666 const void *src
, void *talloc_ctx
)
1668 m_obj_settings_t
*d
, *s
;
1677 free_obj_settings_list(dst
);
1683 for (n
= 0; s
[n
].name
; n
++)
1685 d
= talloc_array(NULL
, struct m_obj_settings
, n
+ 1);
1686 for (n
= 0; s
[n
].name
; n
++) {
1687 d
[n
].name
= talloc_strdup(NULL
, s
[n
].name
);
1688 d
[n
].attribs
= NULL
;
1689 copy_str_list(NULL
, &(d
[n
].attribs
), &(s
[n
].attribs
), NULL
);
1692 d
[n
].attribs
= NULL
;
1696 const m_option_type_t m_option_type_obj_settings_list
= {
1697 .name
= "Object settings list",
1698 .size
= sizeof(m_obj_settings_t
*),
1699 .flags
= M_OPT_TYPE_DYNAMIC
| M_OPT_TYPE_ALLOW_WILDCARD
,
1700 .parse
= parse_obj_settings_list
,
1701 .copy
= copy_obj_settings_list
,
1702 .free
= free_obj_settings_list
,
1707 static int parse_obj_presets(const m_option_t
*opt
, struct bstr name
,
1708 struct bstr param
, bool ambiguous_param
,
1709 void *dst
, void *talloc_ctx
)
1711 m_obj_presets_t
*obj_p
= (m_obj_presets_t
*)opt
->priv
;
1712 const m_struct_t
*in_desc
;
1713 const m_struct_t
*out_desc
;
1715 const unsigned char *pre
;
1716 char *pre_name
= NULL
;
1719 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: Presets need a "
1720 "pointer to a m_obj_presets_t in the priv field.\n",
1722 return M_OPT_PARSER_ERR
;
1726 return M_OPT_MISSING_PARAM
;
1728 pre
= obj_p
->presets
;
1729 in_desc
= obj_p
->in_desc
;
1730 out_desc
= obj_p
->out_desc
? obj_p
->out_desc
: obj_p
->in_desc
;
1733 if (!bstrcmp0(param
, "help")) {
1734 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available presets for %s->%.*s:",
1735 out_desc
->name
, BSTR_P(name
));
1736 for (pre
= obj_p
->presets
;
1737 (pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
)); pre
+= s
)
1738 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, " %s", pre_name
);
1739 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "\n");
1740 return M_OPT_EXIT
- 1;
1743 for (pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
); pre_name
;
1744 pre
+= s
, pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
))
1745 if (!bstrcmp0(param
, pre_name
))
1748 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1749 "Option %.*s: There is no preset named %.*s\n"
1750 "Available presets are:", BSTR_P(name
), BSTR_P(param
));
1751 for (pre
= obj_p
->presets
;
1752 (pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
)); pre
+= s
)
1753 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, " %s", pre_name
);
1754 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "\n");
1755 return M_OPT_INVALID
;
1761 for (i
= 0; in_desc
->fields
[i
].name
; i
++) {
1762 const m_option_t
*out_opt
= m_option_list_find(out_desc
->fields
,
1763 in_desc
->fields
[i
].name
);
1765 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1766 "Option %.*s: Unable to find the target option for field %s.\n"
1767 "Please report this to the developers.\n",
1768 BSTR_P(name
), in_desc
->fields
[i
].name
);
1769 return M_OPT_PARSER_ERR
;
1771 m_option_copy(out_opt
, M_ST_MB_P(dst
, out_opt
->p
),
1772 M_ST_MB_P(pre
, in_desc
->fields
[i
].p
));
1778 const m_option_type_t m_option_type_obj_presets
= {
1779 .name
= "Object presets",
1780 .parse
= parse_obj_presets
,
1783 static int parse_custom_url(const m_option_t
*opt
, struct bstr name
,
1784 struct bstr url
, bool ambiguous_param
, void *dst
,
1788 m_struct_t
*desc
= opt
->priv
;
1791 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: Custom URL needs "
1792 "a pointer to a m_struct_t in the priv field.\n", BSTR_P(name
));
1793 return M_OPT_PARSER_ERR
;
1796 // extract the protocol
1797 int idx
= bstr_find0(url
, "://");
1800 if (m_option_list_find(desc
->fields
, "filename")) {
1801 m_struct_set(desc
, dst
, "filename", url
);
1804 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1805 "Option %.*s: URL doesn't have a valid protocol!\n",
1807 return M_OPT_INVALID
;
1809 struct bstr ptr1
= bstr_cut(url
, idx
+ 3);
1810 if (m_option_list_find(desc
->fields
, "string")) {
1812 m_struct_set(desc
, dst
, "string", ptr1
);
1816 if (dst
&& m_option_list_find(desc
->fields
, "protocol")) {
1817 r
= m_struct_set(desc
, dst
, "protocol", bstr_splice(url
, 0, idx
));
1819 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1820 "Option %.*s: Error while setting protocol.\n",
1826 // check if a username:password is given
1827 idx
= bstrchr(ptr1
, '/');
1830 struct bstr hostpart
= bstr_splice(ptr1
, 0, idx
);
1831 struct bstr path
= bstr_cut(ptr1
, idx
);
1832 idx
= bstrchr(hostpart
, '@');
1834 // We got something, at least a username...
1835 if (!m_option_list_find(desc
->fields
, "username")) {
1836 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1837 "Option %.*s: This URL doesn't have a username part.\n",
1841 struct bstr userpass
= bstr_splice(hostpart
, 0, idx
);
1842 idx
= bstrchr(userpass
, ':');
1844 // We also have a password
1845 if (!m_option_list_find(desc
->fields
, "password")) {
1846 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1847 "Option %.*s: This URL doesn't have a password part.\n",
1850 } else { // Username and password
1852 r
= m_struct_set(desc
, dst
, "username",
1853 bstr_splice(userpass
, 0, idx
));
1855 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1856 "Option %.*s: Error while setting username.\n",
1860 r
= m_struct_set(desc
, dst
, "password",
1861 bstr_splice(userpass
, idx
+1,
1864 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1865 "Option %.*s: Error while setting password.\n",
1871 } else { // User name only
1872 r
= m_struct_set(desc
, dst
, "username", userpass
);
1874 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1875 "Option %.*s: Error while setting username.\n",
1881 hostpart
= bstr_cut(hostpart
, idx
+ 1);
1884 // Before looking for a port number check if we have an IPv6 type
1886 // In an IPv6 URL the numeric address should be inside square braces.
1887 int idx1
= bstrchr(hostpart
, '[');
1888 int idx2
= bstrchr(hostpart
, ']');
1889 struct bstr portstr
= hostpart
;
1890 bool v6addr
= false;
1891 if (idx1
>= 0 && idx2
>= 0 && idx1
< idx2
) {
1892 // we have an IPv6 numeric address
1893 portstr
= bstr_cut(hostpart
, idx2
);
1894 hostpart
= bstr_splice(hostpart
, idx1
+ 1, idx2
);
1898 idx
= bstrchr(portstr
, ':');
1901 hostpart
= bstr_splice(hostpart
, 0, idx
);
1902 // We have an URL beginning like http://www.hostname.com:1212
1903 // Get the port number
1904 if (!m_option_list_find(desc
->fields
, "port")) {
1905 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1906 "Option %.*s: This URL doesn't have a port part.\n",
1911 int p
= bstrtoll(bstr_cut(portstr
, idx
+ 1), NULL
, 0);
1913 snprintf(tmp
, 99, "%d", p
);
1914 r
= m_struct_set(desc
, dst
, "port", bstr(tmp
));
1916 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1917 "Option %.*s: Error while setting port.\n",
1925 if (hostpart
.len
> 0) {
1926 if (!m_option_list_find(desc
->fields
, "hostname")) {
1927 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1928 "Option %.*s: This URL doesn't have a hostname part.\n",
1932 r
= m_struct_set(desc
, dst
, "hostname", hostpart
);
1934 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1935 "Option %.*s: Error while setting hostname.\n",
1941 // Look if a path is given
1942 if (path
.len
> 1) { // not just "/"
1943 // copy the path/filename in the URL container
1944 if (!m_option_list_find(desc
->fields
, "filename")) {
1945 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1946 "Option %.*s: This URL doesn't have a filename part.\n",
1951 char *fname
= bstrdup0(NULL
, bstr_cut(path
, 1));
1952 url_unescape_string(fname
, fname
);
1953 r
= m_struct_set(desc
, dst
, "filename", bstr(fname
));
1956 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1957 "Option %.*s: Error while setting filename.\n",
1967 /// TODO : Write the other needed funcs for 'normal' options
1968 const m_option_type_t m_option_type_custom_url
= {
1969 .name
= "Custom URL",
1970 .parse
= parse_custom_url
,