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 "libavutil/avstring.h"
39 char *m_option_strerror(int code
)
43 return mp_gtext("Unrecognized option name");
44 case M_OPT_MISSING_PARAM
:
45 return mp_gtext("Required parameter for option missing");
47 return mp_gtext("Option parameter could not be parsed");
48 case M_OPT_OUT_OF_RANGE
:
49 return mp_gtext("Parameter is outside values allowed for option");
50 case M_OPT_PARSER_ERR
:
51 return mp_gtext("Parser error");
57 static const struct m_option
*m_option_list_findb(const struct m_option
*list
,
60 for (int i
= 0; list
[i
].name
; i
++) {
61 struct bstr lname
= bstr(list
[i
].name
);
62 if ((list
[i
].type
->flags
& M_OPT_TYPE_ALLOW_WILDCARD
)
63 && bstr_endswith0(lname
, "*")) {
65 if (bstrcasecmp(bstr_splice(name
, 0, lname
.len
), lname
) == 0)
67 } else if (bstrcasecmp(lname
, name
) == 0)
73 const m_option_t
*m_option_list_find(const m_option_t
*list
, const char *name
)
75 return m_option_list_findb(list
, bstr(name
));
78 // Default function that just does a memcpy
80 static void copy_opt(const m_option_t
*opt
, void *dst
, const void *src
)
83 memcpy(dst
, src
, opt
->type
->size
);
88 #define VAL(x) (*(int *)(x))
90 static int parse_flag(const m_option_t
*opt
, struct bstr name
,
91 struct bstr param
, bool ambiguous_param
, void *dst
)
93 if (param
.len
&& !ambiguous_param
) {
94 char * const enable
[] = { "yes", "on", "ja", "si", "igen", "y", "j",
95 "i", "tak", "ja", "true", "1" };
96 for (int i
= 0; i
< sizeof(enable
) / sizeof(enable
[0]); i
++) {
97 if (!bstrcasecmp0(param
, enable
[i
])) {
103 char * const disable
[] = { "no", "off", "nein", "nicht", "nem", "n",
104 "nie", "nej", "false", "0" };
105 for (int i
= 0; i
< sizeof(disable
) / sizeof(disable
[0]); i
++) {
106 if (!bstrcasecmp0(param
, disable
[i
])) {
112 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
113 "Invalid parameter for %.*s flag: %.*s\n",
114 BSTR_P(name
), BSTR_P(param
));
115 return M_OPT_INVALID
;
123 static char *print_flag(const m_option_t
*opt
, const void *val
)
125 if (VAL(val
) == opt
->min
)
126 return talloc_strdup(NULL
, "no");
128 return talloc_strdup(NULL
, "yes");
131 const m_option_type_t m_option_type_flag
= {
132 // need yes or no in config files
142 static int parse_longlong(const m_option_t
*opt
, struct bstr name
,
143 struct bstr param
, bool ambiguous_param
, void *dst
)
146 return M_OPT_MISSING_PARAM
;
149 long long tmp_int
= bstrtoll(param
, &rest
, 10);
151 tmp_int
= bstrtoll(param
, &rest
, 0);
153 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
154 "The %.*s option must be an integer: %.*s\n",
155 BSTR_P(name
), BSTR_P(param
));
156 return M_OPT_INVALID
;
159 if ((opt
->flags
& M_OPT_MIN
) && (tmp_int
< opt
->min
)) {
160 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
161 "The %.*s option must be >= %d: %.*s\n",
162 BSTR_P(name
), (int) opt
->min
, BSTR_P(param
));
163 return M_OPT_OUT_OF_RANGE
;
166 if ((opt
->flags
& M_OPT_MAX
) && (tmp_int
> opt
->max
)) {
167 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
168 "The %.*s option must be <= %d: %.*s\n",
169 BSTR_P(name
), (int) opt
->max
, BSTR_P(param
));
170 return M_OPT_OUT_OF_RANGE
;
174 *(long long *)dst
= tmp_int
;
179 static int parse_int(const m_option_t
*opt
, struct bstr name
,
180 struct bstr param
, bool ambiguous_param
, void *dst
)
183 int r
= parse_longlong(opt
, name
, param
, false, &tmp
);
189 static int parse_int64(const m_option_t
*opt
, struct bstr name
,
190 struct bstr param
, bool ambiguous_param
, void *dst
)
193 int r
= parse_longlong(opt
, name
, param
, false, &tmp
);
195 *(int64_t *)dst
= tmp
;
200 static char *print_int(const m_option_t
*opt
, const void *val
)
202 if (opt
->type
->size
== sizeof(int64_t))
203 return talloc_asprintf(NULL
, "%"PRId64
, *(const int64_t *)val
);
204 return talloc_asprintf(NULL
, "%d", VAL(val
));
207 const m_option_type_t m_option_type_int
= {
215 const m_option_type_t m_option_type_int64
= {
217 .size
= sizeof(int64_t),
218 .parse
= parse_int64
,
223 static int parse_intpair(const struct m_option
*opt
, struct bstr name
,
224 struct bstr param
, bool ambiguous_param
, void *dst
)
227 return M_OPT_MISSING_PARAM
;
229 struct bstr s
= param
;
231 int start
= bstrtoll(s
, &s
, 10);
232 if (s
.len
== param
.len
)
235 if (!bstr_startswith0(s
, "-"))
240 end
= bstrtoll(s
, &s
, 10);
253 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Invalid integer range "
254 "specification for option %.*s: %.*s\n",
255 BSTR_P(name
), BSTR_P(param
));
256 return M_OPT_INVALID
;
259 const struct m_option_type m_option_type_intpair
= {
261 .size
= sizeof(int[2]),
262 .parse
= parse_intpair
,
266 static int parse_choice(const struct m_option
*opt
, struct bstr name
,
267 struct bstr param
, bool ambiguous_param
, void *dst
)
270 return M_OPT_MISSING_PARAM
;
272 struct m_opt_choice_alternatives
*alt
;
273 for (alt
= opt
->priv
; alt
->name
; alt
++)
274 if (!bstrcasecmp0(param
, alt
->name
))
277 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
278 "Invalid value for option %.*s: %.*s\n",
279 BSTR_P(name
), BSTR_P(param
));
280 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Valid values are:");
281 for (alt
= opt
->priv
; alt
->name
; alt
++)
282 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, " %s", alt
->name
);
283 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "\n");
284 return M_OPT_INVALID
;
287 *(int *)dst
= alt
->value
;
292 static char *print_choice(const m_option_t
*opt
, const void *val
)
295 struct m_opt_choice_alternatives
*alt
;
296 for (alt
= opt
->priv
; alt
->name
; alt
++)
298 return talloc_strdup(NULL
, alt
->name
);
302 const struct m_option_type m_option_type_choice
= {
303 .name
= "String", // same as arbitrary strings in option list for now
305 .parse
= parse_choice
,
306 .print
= print_choice
,
313 #define VAL(x) (*(double *)(x))
315 static int parse_double(const m_option_t
*opt
, struct bstr name
,
316 struct bstr param
, bool ambiguous_param
, void *dst
)
319 return M_OPT_MISSING_PARAM
;
322 double tmp_float
= bstrtod(param
, &rest
);
324 switch (rest
.len
? rest
.start
[0] : 0) {
327 tmp_float
/= bstrtod(bstr_cut(rest
, 1), &rest
);
331 /* we also handle floats specified with
332 * non-locale decimal point ::atmos
334 rest
= bstr_cut(rest
, 1);
336 tmp_float
-= 1.0 / pow(10, rest
.len
) * bstrtod(rest
, &rest
);
338 tmp_float
+= 1.0 / pow(10, rest
.len
) * bstrtod(rest
, &rest
);
343 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
344 "The %.*s option must be a floating point number or a "
345 "ratio (numerator[:/]denominator): %.*s\n",
346 BSTR_P(name
), BSTR_P(param
));
347 return M_OPT_INVALID
;
350 if (opt
->flags
& M_OPT_MIN
)
351 if (tmp_float
< opt
->min
) {
352 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
353 "The %.*s option must be >= %f: %.*s\n",
354 BSTR_P(name
), opt
->min
, BSTR_P(param
));
355 return M_OPT_OUT_OF_RANGE
;
358 if (opt
->flags
& M_OPT_MAX
)
359 if (tmp_float
> opt
->max
) {
360 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
361 "The %.*s option must be <= %f: %.*s\n",
362 BSTR_P(name
), opt
->max
, BSTR_P(param
));
363 return M_OPT_OUT_OF_RANGE
;
367 VAL(dst
) = tmp_float
;
371 static char *print_double(const m_option_t
*opt
, const void *val
)
374 return talloc_asprintf(NULL
, "%f", VAL(val
));
377 const m_option_type_t m_option_type_double
= {
378 // double precision float or ratio (numerator[:/]denominator)
380 .size
= sizeof(double),
381 .parse
= parse_double
,
382 .print
= print_double
,
387 #define VAL(x) (*(float *)(x))
389 static int parse_float(const m_option_t
*opt
, struct bstr name
,
390 struct bstr param
, bool ambiguous_param
, void *dst
)
393 int r
= parse_double(opt
, name
, param
, false, &tmp
);
399 static char *print_float(const m_option_t
*opt
, const void *val
)
402 return talloc_asprintf(NULL
, "%f", VAL(val
));
405 const m_option_type_t m_option_type_float
= {
406 // floating point number or ratio (numerator[:/]denominator)
408 .size
= sizeof(float),
409 .parse
= parse_float
,
410 .print
= print_float
,
414 ///////////// Position
416 #define VAL(x) (*(off_t *)(x))
418 static int parse_position(const m_option_t
*opt
, struct bstr name
,
419 struct bstr param
, bool ambiguous_param
, void *dst
)
422 int r
= parse_longlong(opt
, name
, param
, false, &tmp
);
428 static char *print_position(const m_option_t
*opt
, const void *val
)
430 return talloc_asprintf(NULL
, "%"PRId64
, (int64_t)VAL(val
));
433 const m_option_type_t m_option_type_position
= {
436 .size
= sizeof(off_t
),
437 .parse
= parse_position
,
438 .print
= print_position
,
446 #define VAL(x) (*(char **)(x))
448 static int parse_str(const m_option_t
*opt
, struct bstr name
,
449 struct bstr param
, bool ambiguous_param
, void *dst
)
451 if ((opt
->flags
& M_OPT_MIN
) && (param
.len
< opt
->min
)) {
452 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
453 "Parameter must be >= %d chars: %.*s\n",
454 (int) opt
->min
, BSTR_P(param
));
455 return M_OPT_OUT_OF_RANGE
;
458 if ((opt
->flags
& M_OPT_MAX
) && (param
.len
> opt
->max
)) {
459 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
460 "Parameter must be <= %d chars: %.*s\n",
461 (int) opt
->max
, BSTR_P(param
));
462 return M_OPT_OUT_OF_RANGE
;
466 talloc_free(VAL(dst
));
467 VAL(dst
) = bstrdup0(NULL
, param
);
474 static char *print_str(const m_option_t
*opt
, const void *val
)
476 return (val
&& VAL(val
)) ? talloc_strdup(NULL
, VAL(val
)) : NULL
;
479 static void copy_str(const m_option_t
*opt
, void *dst
, const void *src
)
482 talloc_free(VAL(dst
));
483 VAL(dst
) = talloc_strdup(NULL
, VAL(src
));
487 static void free_str(void *src
)
489 if (src
&& VAL(src
)) {
490 talloc_free(VAL(src
));
495 const m_option_type_t m_option_type_string
= {
497 .size
= sizeof(char *),
498 .flags
= M_OPT_TYPE_DYNAMIC
,
505 //////////// String list
508 #define VAL(x) (*(char ***)(x))
516 static void free_str_list(void *dst
)
521 if (!dst
|| !VAL(dst
))
525 for (i
= 0; d
[i
] != NULL
; i
++)
531 static int str_list_add(char **add
, int n
, void *dst
, int pre
)
533 char **lst
= VAL(dst
);
537 return M_OPT_PARSER_ERR
;
540 for (ln
= 0; lst
&& lst
[ln
]; ln
++)
543 lst
= talloc_realloc(NULL
, lst
, char *, n
+ ln
+ 1);
546 memmove(&lst
[n
], lst
, ln
* sizeof(char *));
547 memcpy(lst
, add
, n
* sizeof(char *));
549 memcpy(&lst
[ln
], add
, n
* sizeof(char *));
550 // (re-)add NULL-termination
560 static int str_list_del(char **del
, int n
, void *dst
)
567 return M_OPT_PARSER_ERR
;
570 for (ln
= 0; lst
&& lst
[ln
]; ln
++)
574 for (i
= 0; del
[i
] != NULL
; i
++) {
575 idx
= strtol(del
[i
], &ep
, 0);
577 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Invalid index: %s\n", del
[i
]);
582 if (idx
< 0 || idx
>= ln
) {
583 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
584 "Index %ld is out of range.\n", idx
);
586 } else if (!lst
[idx
])
588 talloc_free(lst
[idx
]);
600 // Don't bother shrinking the list allocation
601 for (i
= 0, n
= 0; i
< ln
; i
++) {
612 static struct bstr
get_nextsep(struct bstr
*ptr
, char sep
, bool modify
)
614 struct bstr str
= *ptr
;
615 struct bstr orig
= str
;
617 int idx
= bstrchr(str
, sep
);
618 if (idx
> 0 && str
.start
[idx
- 1] == '\\') {
620 memmove(str
.start
+ idx
- 1, str
.start
+ idx
, str
.len
- idx
);
622 str
= bstr_cut(str
, idx
);
624 str
= bstr_cut(str
, idx
+ 1);
626 str
= bstr_cut(str
, idx
< 0 ? str
.len
: idx
);
631 return bstr_splice(orig
, 0, str
.start
- orig
.start
);
634 static int parse_str_list(const m_option_t
*opt
, struct bstr name
,
635 struct bstr param
, bool ambiguous_param
, void *dst
)
639 int len
= strlen(opt
->name
);
640 if (opt
->name
[len
- 1] == '*' && (name
.len
> len
- 1)) {
641 struct bstr suffix
= bstr_cut(name
, len
- 1);
642 if (bstrcasecmp0(suffix
, "-add") == 0)
644 else if (bstrcasecmp0(suffix
, "-pre") == 0)
646 else if (bstrcasecmp0(suffix
, "-del") == 0)
648 else if (bstrcasecmp0(suffix
, "-clr") == 0)
651 return M_OPT_UNKNOWN
;
661 // All other ops need a param
663 return M_OPT_MISSING_PARAM
;
665 // custom type for "profile" calls this but uses ->priv for something else
666 char separator
= opt
->type
== &m_option_type_string_list
&& opt
->priv
?
667 *(char *)opt
->priv
: OPTION_LIST_SEPARATOR
;
669 struct bstr str
= param
;
671 get_nextsep(&str
, separator
, 0);
672 str
= bstr_cut(str
, 1);
676 return M_OPT_INVALID
;
677 if (((opt
->flags
& M_OPT_MIN
) && (n
< opt
->min
)) ||
678 ((opt
->flags
& M_OPT_MAX
) && (n
> opt
->max
)))
679 return M_OPT_OUT_OF_RANGE
;
684 res
= talloc_array(NULL
, char *, n
+ 2);
685 str
= bstrdup(NULL
, param
);
686 char *ptr
= str
.start
;
690 struct bstr el
= get_nextsep(&str
, separator
, 1);
691 res
[n
] = bstrdup0(NULL
, el
);
695 str
= bstr_cut(str
, 1);
702 return str_list_add(res
, n
, dst
, 0);
704 return str_list_add(res
, n
, dst
, 1);
706 return str_list_del(res
, n
, dst
);
716 static void copy_str_list(const m_option_t
*opt
, void *dst
, const void *src
)
733 for (n
= 0; s
[n
] != NULL
; n
++)
735 d
= talloc_array(NULL
, char *, n
+ 1);
737 d
[n
] = talloc_strdup(NULL
, s
[n
]);
742 static char *print_str_list(const m_option_t
*opt
, const void *src
)
747 if (!(src
&& VAL(src
)))
751 for (int i
= 0; lst
[i
]; i
++) {
753 ret
= talloc_strdup_append_buffer(ret
, ",");
754 ret
= talloc_strdup_append_buffer(ret
, lst
[i
]);
759 const m_option_type_t m_option_type_string_list
= {
760 /* A list of strings separated by ','.
761 * Option with a name ending in '*' permits using the following suffixes:
762 * -add: Add the given parameters at the end of the list.
763 * -pre: Add the given parameters at the beginning of the list.
764 * -del: Remove the entry at the given indices.
765 * -clr: Clear the list.
766 * e.g: -vf-add flip,mirror -vf-del 2,5
768 .name
= "String list",
769 .size
= sizeof(char **),
770 .flags
= M_OPT_TYPE_DYNAMIC
| M_OPT_TYPE_ALLOW_WILDCARD
,
771 .parse
= parse_str_list
,
772 .print
= print_str_list
,
773 .copy
= copy_str_list
,
774 .free
= free_str_list
,
778 /////////////////// Print
780 static int parse_print(const m_option_t
*opt
, struct bstr name
,
781 struct bstr param
, bool ambiguous_param
, void *dst
)
783 if (opt
->type
== CONF_TYPE_PRINT_INDIRECT
)
784 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "%s", *(char **) opt
->p
);
785 else if (opt
->type
== CONF_TYPE_PRINT_FUNC
) {
786 char *name0
= bstrdup0(NULL
, name
);
787 char *param0
= bstrdup0(NULL
, param
);
788 int r
= ((m_opt_func_full_t
) opt
->p
)(opt
, name0
, param0
);
793 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "%s", mp_gtext(opt
->p
));
795 if (opt
->priv
== NULL
)
800 const m_option_type_t m_option_type_print
= {
802 .parse
= parse_print
,
805 const m_option_type_t m_option_type_print_indirect
= {
807 .parse
= parse_print
,
810 const m_option_type_t m_option_type_print_func
= {
812 .flags
= M_OPT_TYPE_ALLOW_WILDCARD
,
813 .parse
= parse_print
,
817 /////////////////////// Subconfig
819 #define VAL(x) (*(char ***)(x))
821 static int parse_subconf(const m_option_t
*opt
, struct bstr name
,
822 struct bstr param
, bool ambiguous_param
, void *dst
)
828 return M_OPT_MISSING_PARAM
;
830 struct bstr p
= param
;
831 const struct m_option
*subopts
= opt
->p
;
834 int optlen
= bstrcspn(p
, ":=");
835 struct bstr subopt
= bstr_splice(p
, 0, optlen
);
836 struct bstr subparam
= bstr(NULL
);
837 p
= bstr_cut(p
, optlen
);
838 if (bstr_startswith0(p
, "=")) {
840 if (bstr_startswith0(p
, "\"")) {
842 optlen
= bstrcspn(p
, "\"");
843 subparam
= bstr_splice(p
, 0, optlen
);
844 p
= bstr_cut(p
, optlen
);
845 if (!bstr_startswith0(p
, "\"")) {
846 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
847 "Terminating '\"' missing for '%.*s'\n",
849 return M_OPT_INVALID
;
852 } else if (bstr_startswith0(p
, "%")) {
854 optlen
= bstrtoll(p
, &p
, 0);
855 if (!bstr_startswith0(p
, "%") || (optlen
> p
.len
- 1)) {
856 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
857 "Invalid length %d for '%.*s'\n",
858 optlen
, BSTR_P(subopt
));
859 return M_OPT_INVALID
;
861 subparam
= bstr_splice(p
, 1, optlen
+ 1);
862 p
= bstr_cut(p
, optlen
+ 1);
864 optlen
= bstrcspn(p
, ":");
865 subparam
= bstr_splice(p
, 0, optlen
);
866 p
= bstr_cut(p
, optlen
);
869 if (bstr_startswith0(p
, ":"))
871 else if (p
.len
> 0) {
872 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
873 "Incorrect termination for '%.*s'\n", BSTR_P(subopt
));
874 return M_OPT_INVALID
;
877 for (i
= 0; subopts
[i
].name
; i
++)
878 if (!bstrcmp0(subopt
, subopts
[i
].name
))
880 if (!subopts
[i
].name
) {
881 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
882 "Option %.*s: Unknown suboption %.*s\n",
883 BSTR_P(name
), BSTR_P(subopt
));
884 return M_OPT_UNKNOWN
;
886 int r
= m_option_parse(&subopts
[i
], subopt
, subparam
, false, NULL
);
890 lst
= talloc_realloc(NULL
, lst
, char *, 2 * (nr
+ 2));
891 lst
[2 * nr
] = bstrdup0(NULL
, subopt
);
892 lst
[2 * nr
+ 1] = subparam
.len
== 0 ? NULL
:
893 bstrdup0(NULL
, subparam
);
894 memset(&lst
[2 * (nr
+ 1)], 0, 2 * sizeof(char *));
905 const m_option_type_t m_option_type_subconfig
= {
906 // The syntax is -option opt1=foo:flag:opt2=blah
908 .flags
= M_OPT_TYPE_HAS_CHILD
,
909 .parse
= parse_subconf
,
912 #include "libmpcodecs/img_format.h"
914 /* FIXME: snyc with img_format.h */
918 } mp_imgfmt_list
[] = {
919 {"444p16le", IMGFMT_444P16_LE
},
920 {"444p16be", IMGFMT_444P16_BE
},
921 {"444p10le", IMGFMT_444P10_LE
},
922 {"444p10be", IMGFMT_444P10_BE
},
923 {"444p9le", IMGFMT_444P9_LE
},
924 {"444p9be", IMGFMT_444P9_BE
},
925 {"422p16le", IMGFMT_422P16_LE
},
926 {"422p16be", IMGFMT_422P16_BE
},
927 {"422p10le", IMGFMT_422P10_LE
},
928 {"422p10be", IMGFMT_422P10_BE
},
929 {"420p16le", IMGFMT_420P16_LE
},
930 {"420p16be", IMGFMT_420P16_BE
},
931 {"420p10le", IMGFMT_420P10_LE
},
932 {"420p10be", IMGFMT_420P10_BE
},
933 {"420p9le", IMGFMT_420P9_LE
},
934 {"420p9be", IMGFMT_420P9_BE
},
935 {"444p16", IMGFMT_444P16
},
936 {"444p10", IMGFMT_444P10
},
937 {"444p9", IMGFMT_444P9
},
938 {"422p16", IMGFMT_422P16
},
939 {"422p10", IMGFMT_422P10
},
940 {"420p10", IMGFMT_420P10
},
941 {"420p9", IMGFMT_420P9
},
942 {"420p16", IMGFMT_420P16
},
943 {"420a", IMGFMT_420A
},
944 {"444p", IMGFMT_444P
},
945 {"422p", IMGFMT_422P
},
946 {"411p", IMGFMT_411P
},
947 {"440p", IMGFMT_440P
},
948 {"yuy2", IMGFMT_YUY2
},
949 {"yvyu", IMGFMT_YVYU
},
950 {"uyvy", IMGFMT_UYVY
},
951 {"yvu9", IMGFMT_YVU9
},
952 {"if09", IMGFMT_IF09
},
953 {"yv12", IMGFMT_YV12
},
954 {"i420", IMGFMT_I420
},
955 {"iyuv", IMGFMT_IYUV
},
956 {"clpl", IMGFMT_CLPL
},
957 {"hm12", IMGFMT_HM12
},
958 {"y800", IMGFMT_Y800
},
960 {"nv12", IMGFMT_NV12
},
961 {"nv21", IMGFMT_NV21
},
962 {"bgr24", IMGFMT_BGR24
},
963 {"bgr32", IMGFMT_BGR32
},
964 {"bgr16", IMGFMT_BGR16
},
965 {"bgr15", IMGFMT_BGR15
},
966 {"bgr12", IMGFMT_BGR12
},
967 {"bgr8", IMGFMT_BGR8
},
968 {"bgr4", IMGFMT_BGR4
},
969 {"bg4b", IMGFMT_BG4B
},
970 {"bgr1", IMGFMT_BGR1
},
971 {"rgb48be", IMGFMT_RGB48BE
},
972 {"rgb48le", IMGFMT_RGB48LE
},
973 {"rgb48ne", IMGFMT_RGB48NE
},
974 {"rgb24", IMGFMT_RGB24
},
975 {"rgb32", IMGFMT_RGB32
},
976 {"rgb16", IMGFMT_RGB16
},
977 {"rgb15", IMGFMT_RGB15
},
978 {"rgb12", IMGFMT_RGB12
},
979 {"rgb8", IMGFMT_RGB8
},
980 {"rgb4", IMGFMT_RGB4
},
981 {"rg4b", IMGFMT_RG4B
},
982 {"rgb1", IMGFMT_RGB1
},
983 {"rgba", IMGFMT_RGBA
},
984 {"argb", IMGFMT_ARGB
},
985 {"bgra", IMGFMT_BGRA
},
986 {"abgr", IMGFMT_ABGR
},
987 {"mjpeg", IMGFMT_MJPEG
},
988 {"mjpg", IMGFMT_MJPEG
},
992 static int parse_imgfmt(const m_option_t
*opt
, struct bstr name
,
993 struct bstr param
, bool ambiguous_param
, void *dst
)
999 return M_OPT_MISSING_PARAM
;
1001 if (!bstrcmp0(param
, "help")) {
1002 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available formats:");
1003 for (i
= 0; mp_imgfmt_list
[i
].name
; i
++)
1004 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, " %s", mp_imgfmt_list
[i
].name
);
1005 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1006 return M_OPT_EXIT
- 1;
1009 if (bstr_startswith0(param
, "0x"))
1010 fmt
= bstrtoll(param
, NULL
, 16);
1012 for (i
= 0; mp_imgfmt_list
[i
].name
; i
++) {
1013 if (!bstrcasecmp0(param
, mp_imgfmt_list
[i
].name
)) {
1014 fmt
= mp_imgfmt_list
[i
].fmt
;
1018 if (!mp_imgfmt_list
[i
].name
) {
1019 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1020 "Option %.*s: unknown format name: '%.*s'\n",
1021 BSTR_P(name
), BSTR_P(param
));
1022 return M_OPT_INVALID
;
1027 *((uint32_t *)dst
) = fmt
;
1032 const m_option_type_t m_option_type_imgfmt
= {
1033 // Please report any missing colorspaces
1034 .name
= "Image format",
1035 .size
= sizeof(uint32_t),
1036 .parse
= parse_imgfmt
,
1040 #include "libaf/af_format.h"
1042 /* FIXME: snyc with af_format.h */
1046 } mp_afmt_list
[] = {
1048 {"mulaw", AF_FORMAT_MU_LAW
},
1049 {"alaw", AF_FORMAT_A_LAW
},
1050 {"mpeg2", AF_FORMAT_MPEG2
},
1051 {"ac3le", AF_FORMAT_AC3_LE
},
1052 {"ac3be", AF_FORMAT_AC3_BE
},
1053 {"ac3ne", AF_FORMAT_AC3_NE
},
1054 {"imaadpcm", AF_FORMAT_IMA_ADPCM
},
1056 {"u8", AF_FORMAT_U8
},
1057 {"s8", AF_FORMAT_S8
},
1058 {"u16le", AF_FORMAT_U16_LE
},
1059 {"u16be", AF_FORMAT_U16_BE
},
1060 {"u16ne", AF_FORMAT_U16_NE
},
1061 {"s16le", AF_FORMAT_S16_LE
},
1062 {"s16be", AF_FORMAT_S16_BE
},
1063 {"s16ne", AF_FORMAT_S16_NE
},
1064 {"u24le", AF_FORMAT_U24_LE
},
1065 {"u24be", AF_FORMAT_U24_BE
},
1066 {"u24ne", AF_FORMAT_U24_NE
},
1067 {"s24le", AF_FORMAT_S24_LE
},
1068 {"s24be", AF_FORMAT_S24_BE
},
1069 {"s24ne", AF_FORMAT_S24_NE
},
1070 {"u32le", AF_FORMAT_U32_LE
},
1071 {"u32be", AF_FORMAT_U32_BE
},
1072 {"u32ne", AF_FORMAT_U32_NE
},
1073 {"s32le", AF_FORMAT_S32_LE
},
1074 {"s32be", AF_FORMAT_S32_BE
},
1075 {"s32ne", AF_FORMAT_S32_NE
},
1076 {"floatle", AF_FORMAT_FLOAT_LE
},
1077 {"floatbe", AF_FORMAT_FLOAT_BE
},
1078 {"floatne", AF_FORMAT_FLOAT_NE
},
1082 static int parse_afmt(const m_option_t
*opt
, struct bstr name
,
1083 struct bstr param
, bool ambiguous_param
, void *dst
)
1089 return M_OPT_MISSING_PARAM
;
1091 if (!bstrcmp0(param
, "help")) {
1092 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available formats:");
1093 for (i
= 0; mp_afmt_list
[i
].name
; i
++)
1094 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, " %s", mp_afmt_list
[i
].name
);
1095 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1096 return M_OPT_EXIT
- 1;
1099 if (bstr_startswith0(param
, "0x"))
1100 fmt
= bstrtoll(param
, NULL
, 16);
1102 for (i
= 0; mp_afmt_list
[i
].name
; i
++) {
1103 if (!bstrcasecmp0(param
, mp_afmt_list
[i
].name
)) {
1104 fmt
= mp_afmt_list
[i
].fmt
;
1108 if (!mp_afmt_list
[i
].name
) {
1109 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1110 "Option %.*s: unknown format name: '%.*s'\n",
1111 BSTR_P(name
), BSTR_P(param
));
1112 return M_OPT_INVALID
;
1117 *((uint32_t *)dst
) = fmt
;
1122 const m_option_type_t m_option_type_afmt
= {
1123 // Please report any missing formats
1124 .name
= "Audio format",
1125 .size
= sizeof(uint32_t),
1126 .parse
= parse_afmt
,
1131 static int parse_timestring(struct bstr str
, double *time
, char endchar
)
1135 *time
= 0; /* ensure initialization for error cases */
1136 if (bstr_sscanf(str
, "%d:%d:%lf%n", &a
, &b
, &d
, &len
) >= 3)
1137 *time
= 3600 * a
+ 60 * b
+ d
;
1138 else if (bstr_sscanf(str
, "%d:%lf%n", &a
, &d
, &len
) >= 2)
1140 else if (bstr_sscanf(str
, "%lf%n", &d
, &len
) >= 1)
1143 return 0; /* unsupported time format */
1144 if (len
< str
.len
&& str
.start
[len
] != endchar
)
1145 return 0; /* invalid extra characters at the end */
1150 static int parse_time(const m_option_t
*opt
, struct bstr name
,
1151 struct bstr param
, bool ambiguous_param
, void *dst
)
1156 return M_OPT_MISSING_PARAM
;
1158 if (!parse_timestring(param
, &time
, 0)) {
1159 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: invalid time: '%.*s'\n",
1160 BSTR_P(name
), BSTR_P(param
));
1161 return M_OPT_INVALID
;
1165 *(double *)dst
= time
;
1169 const m_option_type_t m_option_type_time
= {
1171 .size
= sizeof(double),
1172 .parse
= parse_time
,
1173 .print
= print_double
,
1178 // Time or size (-endpos)
1180 static int parse_time_size(const m_option_t
*opt
, struct bstr name
,
1181 struct bstr param
, bool ambiguous_param
, void *dst
)
1188 return M_OPT_MISSING_PARAM
;
1191 /* End at size parsing */
1192 if (bstr_sscanf(param
, "%lf%3s", &end_at
, unit
) == 2) {
1193 ts
.type
= END_AT_SIZE
;
1194 if (!strcasecmp(unit
, "b"))
1196 else if (!strcasecmp(unit
, "kb"))
1198 else if (!strcasecmp(unit
, "mb"))
1199 end_at
*= 1024 * 1024;
1200 else if (!strcasecmp(unit
, "gb"))
1201 end_at
*= 1024 * 1024 * 1024;
1203 ts
.type
= END_AT_NONE
;
1205 if (ts
.type
== END_AT_SIZE
) {
1211 /* End at time parsing. This has to be last because the parsing accepts
1212 * even a number followed by garbage */
1213 if (!parse_timestring(param
, &end_at
, 0)) {
1214 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1215 "Option %.*s: invalid time or size: '%.*s'\n",
1216 BSTR_P(name
), BSTR_P(param
));
1217 return M_OPT_INVALID
;
1220 ts
.type
= END_AT_TIME
;
1224 *(m_time_size_t
*)dst
= ts
;
1228 const m_option_type_t m_option_type_time_size
= {
1229 .name
= "Time or size",
1230 .size
= sizeof(m_time_size_t
),
1231 .parse
= parse_time_size
,
1236 //// Objects (i.e. filters, etc) settings
1238 #include "m_struct.h"
1241 #define VAL(x) (*(m_obj_settings_t **)(x))
1243 static int find_obj_desc(struct bstr name
, const m_obj_list_t
*l
,
1244 const m_struct_t
**ret
)
1249 for (i
= 0; l
->list
[i
]; i
++) {
1250 n
= M_ST_MB(char *, l
->list
[i
], l
->name_off
);
1251 if (!bstrcmp0(name
, n
)) {
1252 *ret
= M_ST_MB(m_struct_t
*, l
->list
[i
], l
->desc_off
);
1259 static int get_obj_param(struct bstr opt_name
, struct bstr obj_name
,
1260 const m_struct_t
*desc
, struct bstr str
, int *nold
,
1261 int oldmax
, char **dst
)
1263 const m_option_t
*opt
;
1266 int eq
= bstrchr(str
, '=');
1268 if (eq
> 0) { // eq == 0 ignored
1269 struct bstr p
= bstr_cut(str
, eq
+ 1);
1270 str
= bstr_splice(str
, 0, eq
);
1271 opt
= m_option_list_findb(desc
->fields
, str
);
1273 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1274 "Option %.*s: %.*s doesn't have a %.*s parameter.\n",
1275 BSTR_P(opt_name
), BSTR_P(obj_name
), BSTR_P(str
));
1276 return M_OPT_UNKNOWN
;
1278 r
= m_option_parse(opt
, str
, p
, false, NULL
);
1281 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: "
1282 "Error while parsing %.*s parameter %.*s (%.*s)\n",
1283 BSTR_P(opt_name
), BSTR_P(obj_name
), BSTR_P(str
),
1288 dst
[0] = bstrdup0(NULL
, str
);
1289 dst
[1] = bstrdup0(NULL
, p
);
1292 if ((*nold
) >= oldmax
) {
1293 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: %.*s has only %d params, so you can't give more than %d unnamed params.\n",
1294 BSTR_P(opt_name
), BSTR_P(obj_name
), oldmax
, oldmax
);
1295 return M_OPT_OUT_OF_RANGE
;
1297 opt
= &desc
->fields
[(*nold
)];
1298 r
= m_option_parse(opt
, bstr(opt
->name
), str
, false, NULL
);
1301 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: "
1302 "Error while parsing %.*s parameter %s (%.*s)\n",
1303 BSTR_P(opt_name
), BSTR_P(obj_name
), opt
->name
,
1308 dst
[0] = talloc_strdup(NULL
, opt
->name
);
1309 dst
[1] = bstrdup0(NULL
, str
);
1316 static int get_obj_params(struct bstr opt_name
, struct bstr name
,
1317 struct bstr params
, const m_struct_t
*desc
,
1318 char separator
, char ***_ret
)
1320 int n
= 0, nold
= 0, nopts
;
1323 if (!bstrcmp0(params
, "help")) { // Help
1324 char min
[50], max
[50];
1325 if (!desc
->fields
) {
1326 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1327 "%.*s doesn't have any options.\n\n", BSTR_P(name
));
1328 return M_OPT_EXIT
- 1;
1330 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1331 "\n Name Type Min Max\n\n");
1332 for (n
= 0; desc
->fields
[n
].name
; n
++) {
1333 const m_option_t
*opt
= &desc
->fields
[n
];
1334 if (opt
->type
->flags
& M_OPT_TYPE_HAS_CHILD
)
1336 if (opt
->flags
& M_OPT_MIN
)
1337 sprintf(min
, "%-8.0f", opt
->min
);
1340 if (opt
->flags
& M_OPT_MAX
)
1341 sprintf(max
, "%-8.0f", opt
->max
);
1344 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1345 " %-20.20s %-15.15s %-10.10s %-10.10s\n",
1346 opt
->name
, opt
->type
->name
, min
, max
);
1348 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1349 return M_OPT_EXIT
- 1;
1352 for (nopts
= 0; desc
->fields
[nopts
].name
; nopts
++)
1355 // TODO : Check that each opt can be parsed
1356 struct bstr s
= params
;
1359 int idx
= bstrchr(s
, separator
);
1364 struct bstr field
= bstr_splice(s
, 0, idx
);
1365 s
= bstr_cut(s
, idx
+ 1);
1366 if (field
.len
== 0) { // Empty field, count it and go on
1369 int r
= get_obj_param(opt_name
, name
, desc
, field
, &nold
, nopts
,
1379 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Too many options for %.*s\n",
1381 return M_OPT_OUT_OF_RANGE
;
1383 if (!_ret
) // Just test
1385 if (n
== 0) // No options or only empty options
1388 ret
= talloc_array(NULL
, char *, (n
+ 2) * 2);
1393 int idx
= bstrchr(s
, separator
);
1396 struct bstr field
= bstr_splice(s
, 0, idx
);
1397 s
= bstr_cut(s
, idx
+ 1);
1398 if (field
.len
== 0) { // Empty field, count it and go on
1401 get_obj_param(opt_name
, name
, desc
, field
, &nold
, nopts
,
1406 ret
[n
* 2] = ret
[n
* 2 + 1] = NULL
;
1412 static int parse_obj_params(const m_option_t
*opt
, struct bstr name
,
1413 struct bstr param
, bool ambiguous_param
, void *dst
)
1417 m_obj_params_t
*p
= opt
->priv
;
1418 const m_struct_t
*desc
;
1420 // We need the object desc
1422 return M_OPT_INVALID
;
1425 r
= get_obj_params(name
, bstr(desc
->name
), param
, desc
, p
->separator
,
1426 dst
? &opts
: NULL
);
1431 if (!opts
) // no arguments given
1434 for (r
= 0; opts
[r
]; r
+= 2)
1435 m_struct_set(desc
, dst
, opts
[r
], bstr(opts
[r
+ 1]));
1441 const m_option_type_t m_option_type_obj_params
= {
1442 .name
= "Object params",
1443 .parse
= parse_obj_params
,
1446 /// Some predefined types as a definition would be quite lengthy
1449 static const m_span_t m_span_params_dflts
= {
1452 static const m_option_t m_span_params_fields
[] = {
1453 {"start", M_ST_OFF(m_span_t
, start
), CONF_TYPE_INT
, M_OPT_MIN
, 1, 0, NULL
},
1454 {"end", M_ST_OFF(m_span_t
, end
), CONF_TYPE_INT
, M_OPT_MIN
, 1, 0, NULL
},
1455 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
1457 static const struct m_struct_st m_span_opts
= {
1460 &m_span_params_dflts
,
1461 m_span_params_fields
1463 const m_obj_params_t m_span_params_def
= {
1468 static int parse_obj_settings(struct bstr opt
, struct bstr str
,
1469 const m_obj_list_t
*list
,
1470 m_obj_settings_t
**_ret
, int ret_n
)
1473 char **plist
= NULL
;
1474 const m_struct_t
*desc
;
1475 m_obj_settings_t
*ret
= _ret
? *_ret
: NULL
;
1477 struct bstr param
= bstr(NULL
);
1478 int idx
= bstrchr(str
, '=');
1480 param
= bstr_cut(str
, idx
+ 1);
1481 str
= bstr_splice(str
, 0, idx
);
1484 if (!find_obj_desc(str
, list
, &desc
)) {
1485 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: %.*s doesn't exist.\n",
1486 BSTR_P(opt
), BSTR_P(str
));
1487 return M_OPT_INVALID
;
1491 if (!desc
&& _ret
) {
1492 if (!bstrcmp0(param
, "help")) {
1493 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1494 "Option %.*s: %.*s have no option description.\n",
1495 BSTR_P(opt
), BSTR_P(str
));
1496 return M_OPT_EXIT
- 1;
1498 plist
= talloc_zero_array(NULL
, char *, 4);
1499 plist
[0] = talloc_strdup(NULL
, "_oldargs_");
1500 plist
[1] = bstrdup0(NULL
, param
);
1502 r
= get_obj_params(opt
, str
, param
, desc
, ':',
1503 _ret
? &plist
: NULL
);
1511 ret
= talloc_realloc(NULL
, ret
, struct m_obj_settings
, ret_n
+ 2);
1512 memset(&ret
[ret_n
], 0, 2 * sizeof(m_obj_settings_t
));
1513 ret
[ret_n
].name
= bstrdup0(NULL
, str
);
1514 ret
[ret_n
].attribs
= plist
;
1520 static int obj_settings_list_del(struct bstr opt_name
, struct bstr param
,
1521 bool ambiguous_param
, void *dst
)
1523 char **str_list
= NULL
;
1524 int r
, i
, idx_max
= 0;
1525 char *rem_id
= "_removed_marker_";
1527 assert(opt_name
.len
< 100);
1528 memcpy(name
, opt_name
.start
, opt_name
.len
);
1529 name
[opt_name
.len
] = 0;
1530 const m_option_t list_opt
= {
1531 name
, NULL
, CONF_TYPE_STRING_LIST
,
1534 m_obj_settings_t
*obj_list
= dst
? VAL(dst
) : NULL
;
1536 if (dst
&& !obj_list
) {
1537 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
, "Option %.*s: the list is empty.\n",
1540 } else if (obj_list
) {
1541 for (idx_max
= 0; obj_list
[idx_max
].name
!= NULL
; idx_max
++)
1545 r
= m_option_parse(&list_opt
, opt_name
, param
, false, &str_list
);
1546 if (r
< 0 || !str_list
)
1549 for (r
= 0; str_list
[r
]; r
++) {
1552 id
= strtol(str_list
[r
], &endptr
, 0);
1553 if (endptr
== str_list
[r
]) {
1554 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
));
1555 m_option_free(&list_opt
, &str_list
);
1556 return M_OPT_INVALID
;
1560 if (id
>= idx_max
|| id
< -idx_max
) {
1561 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1562 "Option %.*s: Index %d is out of range.\n",
1563 BSTR_P(opt_name
), id
);
1568 talloc_free(obj_list
[id
].name
);
1569 free_str_list(&(obj_list
[id
].attribs
));
1570 obj_list
[id
].name
= rem_id
;
1574 m_option_free(&list_opt
, &str_list
);
1578 for (i
= 0; obj_list
[i
].name
; i
++) {
1579 while (obj_list
[i
].name
== rem_id
) {
1580 memmove(&obj_list
[i
], &obj_list
[i
+ 1],
1581 sizeof(m_obj_settings_t
) * (idx_max
- i
));
1585 obj_list
= talloc_realloc(NULL
, obj_list
, struct m_obj_settings
,
1587 VAL(dst
) = obj_list
;
1592 static void free_obj_settings_list(void *dst
)
1595 m_obj_settings_t
*d
;
1597 if (!dst
|| !VAL(dst
))
1601 for (n
= 0; d
[n
].name
; n
++) {
1602 talloc_free(d
[n
].name
);
1603 free_str_list(&(d
[n
].attribs
));
1609 static int parse_obj_settings_list(const m_option_t
*opt
, struct bstr name
,
1610 struct bstr param
, bool ambiguous_param
,
1613 int len
= strlen(opt
->name
);
1614 m_obj_settings_t
*res
= NULL
, *queue
= NULL
, *head
= NULL
;
1617 // We need the objects list
1619 return M_OPT_INVALID
;
1621 if (opt
->name
[len
- 1] == '*' && (name
.len
> len
- 1)) {
1622 struct bstr suffix
= bstr_cut(name
, len
- 1);
1623 if (bstrcasecmp0(suffix
, "-add") == 0)
1625 else if (bstrcasecmp0(suffix
, "-pre") == 0)
1627 else if (bstrcasecmp0(suffix
, "-del") == 0)
1629 else if (bstrcasecmp0(suffix
, "-clr") == 0)
1633 strncpy(prefix
, opt
->name
, len
- 1);
1634 prefix
[len
- 1] = '\0';
1635 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1636 "Option %.*s: unknown postfix %.*s\n"
1637 "Supported postfixes are:\n"
1639 " Append the given list to the current list\n\n"
1641 " Prepend the given list to the current list\n\n"
1643 " Remove the given elements. Take the list element index (starting from 0).\n"
1644 " Negative index can be used (i.e. -1 is the last element)\n\n"
1646 " Clear the current list.\n",
1647 BSTR_P(name
), BSTR_P(suffix
), prefix
, prefix
, prefix
, prefix
);
1649 return M_OPT_UNKNOWN
;
1653 // Clear the list ??
1656 free_obj_settings_list(dst
);
1661 return M_OPT_MISSING_PARAM
;
1673 return obj_settings_list_del(name
, param
, false, dst
);
1675 if (dst
&& VAL(dst
))
1676 free_obj_settings_list(dst
);
1679 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: FIXME\n", BSTR_P(name
));
1680 return M_OPT_UNKNOWN
;
1683 if (!bstrcmp0(param
, "help")) {
1684 m_obj_list_t
*ol
= opt
->priv
;
1685 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available video filters:\n");
1686 for (int n
= 0; ol
->list
[n
]; n
++)
1687 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, " %-15s: %s\n",
1688 M_ST_MB(char *, ol
->list
[n
], ol
->name_off
),
1689 M_ST_MB(char *, ol
->list
[n
], ol
->info_off
));
1690 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1691 return M_OPT_EXIT
- 1;
1694 struct bstr s
= bstrdup(NULL
, param
);
1695 char *allocptr
= s
.start
;
1698 struct bstr el
= get_nextsep(&s
, OPTION_LIST_SEPARATOR
, 1);
1699 int r
= parse_obj_settings(name
, el
, opt
->priv
, dst
? &res
: NULL
, n
);
1701 talloc_free(allocptr
);
1707 talloc_free(allocptr
);
1709 return M_OPT_INVALID
;
1711 if (((opt
->flags
& M_OPT_MIN
) && (n
< opt
->min
)) ||
1712 ((opt
->flags
& M_OPT_MAX
) && (n
> opt
->max
)))
1713 return M_OPT_OUT_OF_RANGE
;
1718 for (qsize
= 0; queue
[qsize
].name
; qsize
++)
1720 res
= talloc_realloc(NULL
, res
, struct m_obj_settings
,
1722 memcpy(&res
[n
], queue
, (qsize
+ 1) * sizeof(m_obj_settings_t
));
1728 for (hsize
= 0; head
[hsize
].name
; hsize
++)
1730 head
= talloc_realloc(NULL
, head
, struct m_obj_settings
,
1732 memcpy(&head
[hsize
], res
, (n
+ 1) * sizeof(m_obj_settings_t
));
1741 static void copy_obj_settings_list(const m_option_t
*opt
, void *dst
,
1744 m_obj_settings_t
*d
, *s
;
1753 free_obj_settings_list(dst
);
1759 for (n
= 0; s
[n
].name
; n
++)
1761 d
= talloc_array(NULL
, struct m_obj_settings
, n
+ 1);
1762 for (n
= 0; s
[n
].name
; n
++) {
1763 d
[n
].name
= talloc_strdup(NULL
, s
[n
].name
);
1764 d
[n
].attribs
= NULL
;
1765 copy_str_list(NULL
, &(d
[n
].attribs
), &(s
[n
].attribs
));
1768 d
[n
].attribs
= NULL
;
1772 const m_option_type_t m_option_type_obj_settings_list
= {
1773 .name
= "Object settings list",
1774 .size
= sizeof(m_obj_settings_t
*),
1775 .flags
= M_OPT_TYPE_DYNAMIC
| M_OPT_TYPE_ALLOW_WILDCARD
,
1776 .parse
= parse_obj_settings_list
,
1777 .copy
= copy_obj_settings_list
,
1778 .free
= free_obj_settings_list
,
1783 static int parse_obj_presets(const m_option_t
*opt
, struct bstr name
,
1784 struct bstr param
, bool ambiguous_param
,
1787 m_obj_presets_t
*obj_p
= (m_obj_presets_t
*)opt
->priv
;
1788 const m_struct_t
*in_desc
;
1789 const m_struct_t
*out_desc
;
1791 const unsigned char *pre
;
1792 char *pre_name
= NULL
;
1795 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: Presets need a "
1796 "pointer to a m_obj_presets_t in the priv field.\n",
1798 return M_OPT_PARSER_ERR
;
1802 return M_OPT_MISSING_PARAM
;
1804 pre
= obj_p
->presets
;
1805 in_desc
= obj_p
->in_desc
;
1806 out_desc
= obj_p
->out_desc
? obj_p
->out_desc
: obj_p
->in_desc
;
1809 if (!bstrcmp0(param
, "help")) {
1810 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available presets for %s->%.*s:",
1811 out_desc
->name
, BSTR_P(name
));
1812 for (pre
= obj_p
->presets
;
1813 (pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
)); pre
+= s
)
1814 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, " %s", pre_name
);
1815 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "\n");
1816 return M_OPT_EXIT
- 1;
1819 for (pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
); pre_name
;
1820 pre
+= s
, pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
))
1821 if (!bstrcmp0(param
, pre_name
))
1824 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1825 "Option %.*s: There is no preset named %.*s\n"
1826 "Available presets are:", BSTR_P(name
), BSTR_P(param
));
1827 for (pre
= obj_p
->presets
;
1828 (pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
)); pre
+= s
)
1829 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, " %s", pre_name
);
1830 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "\n");
1831 return M_OPT_INVALID
;
1837 for (i
= 0; in_desc
->fields
[i
].name
; i
++) {
1838 const m_option_t
*out_opt
= m_option_list_find(out_desc
->fields
,
1839 in_desc
->fields
[i
].name
);
1841 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1842 "Option %.*s: Unable to find the target option for field %s.\n"
1843 "Please report this to the developers.\n",
1844 BSTR_P(name
), in_desc
->fields
[i
].name
);
1845 return M_OPT_PARSER_ERR
;
1847 m_option_copy(out_opt
, M_ST_MB_P(dst
, out_opt
->p
),
1848 M_ST_MB_P(pre
, in_desc
->fields
[i
].p
));
1854 const m_option_type_t m_option_type_obj_presets
= {
1855 .name
= "Object presets",
1856 .parse
= parse_obj_presets
,
1859 static int parse_custom_url(const m_option_t
*opt
, struct bstr name
,
1860 struct bstr url
, bool ambiguous_param
, void *dst
)
1863 m_struct_t
*desc
= opt
->priv
;
1866 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: Custom URL needs "
1867 "a pointer to a m_struct_t in the priv field.\n", BSTR_P(name
));
1868 return M_OPT_PARSER_ERR
;
1871 // extract the protocol
1872 int idx
= bstr_find0(url
, "://");
1875 if (m_option_list_find(desc
->fields
, "filename")) {
1876 m_struct_set(desc
, dst
, "filename", url
);
1879 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1880 "Option %.*s: URL doesn't have a valid protocol!\n",
1882 return M_OPT_INVALID
;
1884 struct bstr ptr1
= bstr_cut(url
, idx
+ 3);
1885 if (m_option_list_find(desc
->fields
, "string")) {
1887 m_struct_set(desc
, dst
, "string", ptr1
);
1891 if (dst
&& m_option_list_find(desc
->fields
, "protocol")) {
1892 r
= m_struct_set(desc
, dst
, "protocol", bstr_splice(url
, 0, idx
));
1894 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1895 "Option %.*s: Error while setting protocol.\n",
1901 // check if a username:password is given
1902 idx
= bstrchr(ptr1
, '/');
1905 struct bstr hostpart
= bstr_splice(ptr1
, 0, idx
);
1906 struct bstr path
= bstr_cut(ptr1
, idx
);
1907 idx
= bstrchr(hostpart
, '@');
1909 // We got something, at least a username...
1910 if (!m_option_list_find(desc
->fields
, "username")) {
1911 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1912 "Option %.*s: This URL doesn't have a username part.\n",
1916 struct bstr userpass
= bstr_splice(hostpart
, 0, idx
);
1917 idx
= bstrchr(userpass
, ':');
1919 // We also have a password
1920 if (!m_option_list_find(desc
->fields
, "password")) {
1921 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1922 "Option %.*s: This URL doesn't have a password part.\n",
1925 } else { // Username and password
1927 r
= m_struct_set(desc
, dst
, "username",
1928 bstr_splice(userpass
, 0, idx
));
1930 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1931 "Option %.*s: Error while setting username.\n",
1935 r
= m_struct_set(desc
, dst
, "password",
1936 bstr_splice(userpass
, idx
+1,
1939 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1940 "Option %.*s: Error while setting password.\n",
1946 } else { // User name only
1947 r
= m_struct_set(desc
, dst
, "username", userpass
);
1949 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1950 "Option %.*s: Error while setting username.\n",
1956 hostpart
= bstr_cut(hostpart
, idx
+ 1);
1959 // Before looking for a port number check if we have an IPv6 type
1961 // In an IPv6 URL the numeric address should be inside square braces.
1962 int idx1
= bstrchr(hostpart
, '[');
1963 int idx2
= bstrchr(hostpart
, ']');
1964 struct bstr portstr
= hostpart
;
1965 bool v6addr
= false;
1966 if (idx1
>= 0 && idx2
>= 0 && idx1
< idx2
) {
1967 // we have an IPv6 numeric address
1968 portstr
= bstr_cut(hostpart
, idx2
);
1969 hostpart
= bstr_splice(hostpart
, idx1
+ 1, idx2
);
1973 idx
= bstrchr(portstr
, ':');
1976 hostpart
= bstr_splice(hostpart
, 0, idx
);
1977 // We have an URL beginning like http://www.hostname.com:1212
1978 // Get the port number
1979 if (!m_option_list_find(desc
->fields
, "port")) {
1980 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1981 "Option %.*s: This URL doesn't have a port part.\n",
1986 int p
= bstrtoll(bstr_cut(portstr
, idx
+ 1), NULL
, 0);
1988 snprintf(tmp
, 99, "%d", p
);
1989 r
= m_struct_set(desc
, dst
, "port", bstr(tmp
));
1991 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1992 "Option %.*s: Error while setting port.\n",
2000 if (hostpart
.len
> 0) {
2001 if (!m_option_list_find(desc
->fields
, "hostname")) {
2002 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
2003 "Option %.*s: This URL doesn't have a hostname part.\n",
2007 r
= m_struct_set(desc
, dst
, "hostname", hostpart
);
2009 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2010 "Option %.*s: Error while setting hostname.\n",
2016 // Look if a path is given
2017 if (path
.len
> 1) { // not just "/"
2018 // copy the path/filename in the URL container
2019 if (!m_option_list_find(desc
->fields
, "filename")) {
2020 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
2021 "Option %.*s: This URL doesn't have a filename part.\n",
2026 char *fname
= bstrdup0(NULL
, bstr_cut(path
, 1));
2027 url_unescape_string(fname
, fname
);
2028 r
= m_struct_set(desc
, dst
, "filename", bstr(fname
));
2031 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2032 "Option %.*s: Error while setting filename.\n",
2042 /// TODO : Write the other needed funcs for 'normal' options
2043 const m_option_type_t m_option_type_custom_url
= {
2044 .name
= "Custom URL",
2045 .parse
= parse_custom_url
,