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
,
84 memcpy(dst
, src
, opt
->type
->size
);
89 #define VAL(x) (*(int *)(x))
91 static int parse_flag(const m_option_t
*opt
, struct bstr name
,
92 struct bstr param
, bool ambiguous_param
, void *dst
,
95 if (param
.len
&& !ambiguous_param
) {
96 char * const enable
[] = { "yes", "on", "ja", "si", "igen", "y", "j",
97 "i", "tak", "ja", "true", "1" };
98 for (int i
= 0; i
< sizeof(enable
) / sizeof(enable
[0]); i
++) {
99 if (!bstrcasecmp0(param
, enable
[i
])) {
105 char * const disable
[] = { "no", "off", "nein", "nicht", "nem", "n",
106 "nie", "nej", "false", "0" };
107 for (int i
= 0; i
< sizeof(disable
) / sizeof(disable
[0]); i
++) {
108 if (!bstrcasecmp0(param
, disable
[i
])) {
114 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
115 "Invalid parameter for %.*s flag: %.*s\n",
116 BSTR_P(name
), BSTR_P(param
));
117 return M_OPT_INVALID
;
125 static char *print_flag(const m_option_t
*opt
, const void *val
)
127 if (VAL(val
) == opt
->min
)
128 return talloc_strdup(NULL
, "no");
130 return talloc_strdup(NULL
, "yes");
133 const m_option_type_t m_option_type_flag
= {
134 // need yes or no in config files
144 static int parse_longlong(const m_option_t
*opt
, struct bstr name
,
145 struct bstr param
, bool ambiguous_param
, void *dst
)
148 return M_OPT_MISSING_PARAM
;
151 long long tmp_int
= bstrtoll(param
, &rest
, 10);
153 tmp_int
= bstrtoll(param
, &rest
, 0);
155 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
156 "The %.*s option must be an integer: %.*s\n",
157 BSTR_P(name
), BSTR_P(param
));
158 return M_OPT_INVALID
;
161 if ((opt
->flags
& M_OPT_MIN
) && (tmp_int
< opt
->min
)) {
162 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
163 "The %.*s option must be >= %d: %.*s\n",
164 BSTR_P(name
), (int) opt
->min
, BSTR_P(param
));
165 return M_OPT_OUT_OF_RANGE
;
168 if ((opt
->flags
& M_OPT_MAX
) && (tmp_int
> opt
->max
)) {
169 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
170 "The %.*s option must be <= %d: %.*s\n",
171 BSTR_P(name
), (int) opt
->max
, BSTR_P(param
));
172 return M_OPT_OUT_OF_RANGE
;
176 *(long long *)dst
= tmp_int
;
181 static int parse_int(const m_option_t
*opt
, struct bstr name
,
182 struct bstr param
, bool ambiguous_param
, void *dst
,
186 int r
= parse_longlong(opt
, name
, param
, false, &tmp
);
192 static int parse_int64(const m_option_t
*opt
, struct bstr name
,
193 struct bstr param
, bool ambiguous_param
, void *dst
,
197 int r
= parse_longlong(opt
, name
, param
, false, &tmp
);
199 *(int64_t *)dst
= tmp
;
204 static char *print_int(const m_option_t
*opt
, const void *val
)
206 if (opt
->type
->size
== sizeof(int64_t))
207 return talloc_asprintf(NULL
, "%"PRId64
, *(const int64_t *)val
);
208 return talloc_asprintf(NULL
, "%d", VAL(val
));
211 const m_option_type_t m_option_type_int
= {
219 const m_option_type_t m_option_type_int64
= {
221 .size
= sizeof(int64_t),
222 .parse
= parse_int64
,
227 static int parse_intpair(const struct m_option
*opt
, struct bstr name
,
228 struct bstr param
, bool ambiguous_param
, void *dst
,
232 return M_OPT_MISSING_PARAM
;
234 struct bstr s
= param
;
236 int start
= bstrtoll(s
, &s
, 10);
237 if (s
.len
== param
.len
)
240 if (!bstr_startswith0(s
, "-"))
245 end
= bstrtoll(s
, &s
, 10);
258 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Invalid integer range "
259 "specification for option %.*s: %.*s\n",
260 BSTR_P(name
), BSTR_P(param
));
261 return M_OPT_INVALID
;
264 const struct m_option_type m_option_type_intpair
= {
266 .size
= sizeof(int[2]),
267 .parse
= parse_intpair
,
271 static int parse_choice(const struct m_option
*opt
, struct bstr name
,
272 struct bstr param
, bool ambiguous_param
, void *dst
,
276 return M_OPT_MISSING_PARAM
;
278 struct m_opt_choice_alternatives
*alt
;
279 for (alt
= opt
->priv
; alt
->name
; alt
++)
280 if (!bstrcasecmp0(param
, alt
->name
))
283 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
284 "Invalid value for option %.*s: %.*s\n",
285 BSTR_P(name
), BSTR_P(param
));
286 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Valid values are:");
287 for (alt
= opt
->priv
; alt
->name
; alt
++)
288 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, " %s", alt
->name
);
289 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "\n");
290 return M_OPT_INVALID
;
293 *(int *)dst
= alt
->value
;
298 static char *print_choice(const m_option_t
*opt
, const void *val
)
301 struct m_opt_choice_alternatives
*alt
;
302 for (alt
= opt
->priv
; alt
->name
; alt
++)
304 return talloc_strdup(NULL
, alt
->name
);
308 const struct m_option_type m_option_type_choice
= {
309 .name
= "String", // same as arbitrary strings in option list for now
311 .parse
= parse_choice
,
312 .print
= print_choice
,
319 #define VAL(x) (*(double *)(x))
321 static int parse_double(const m_option_t
*opt
, struct bstr name
,
322 struct bstr param
, bool ambiguous_param
, void *dst
,
326 return M_OPT_MISSING_PARAM
;
329 double tmp_float
= bstrtod(param
, &rest
);
331 switch (rest
.len
? rest
.start
[0] : 0) {
334 tmp_float
/= bstrtod(bstr_cut(rest
, 1), &rest
);
338 /* we also handle floats specified with
339 * non-locale decimal point ::atmos
341 rest
= bstr_cut(rest
, 1);
343 tmp_float
-= 1.0 / pow(10, rest
.len
) * bstrtod(rest
, &rest
);
345 tmp_float
+= 1.0 / pow(10, rest
.len
) * bstrtod(rest
, &rest
);
350 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
351 "The %.*s option must be a floating point number or a "
352 "ratio (numerator[:/]denominator): %.*s\n",
353 BSTR_P(name
), BSTR_P(param
));
354 return M_OPT_INVALID
;
357 if (opt
->flags
& M_OPT_MIN
)
358 if (tmp_float
< opt
->min
) {
359 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
360 "The %.*s option must be >= %f: %.*s\n",
361 BSTR_P(name
), opt
->min
, BSTR_P(param
));
362 return M_OPT_OUT_OF_RANGE
;
365 if (opt
->flags
& M_OPT_MAX
)
366 if (tmp_float
> opt
->max
) {
367 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
368 "The %.*s option must be <= %f: %.*s\n",
369 BSTR_P(name
), opt
->max
, BSTR_P(param
));
370 return M_OPT_OUT_OF_RANGE
;
374 VAL(dst
) = tmp_float
;
378 static char *print_double(const m_option_t
*opt
, const void *val
)
381 return talloc_asprintf(NULL
, "%f", VAL(val
));
384 const m_option_type_t m_option_type_double
= {
385 // double precision float or ratio (numerator[:/]denominator)
387 .size
= sizeof(double),
388 .parse
= parse_double
,
389 .print
= print_double
,
394 #define VAL(x) (*(float *)(x))
396 static int parse_float(const m_option_t
*opt
, struct bstr name
,
397 struct bstr param
, bool ambiguous_param
, void *dst
,
401 int r
= parse_double(opt
, name
, param
, false, &tmp
, NULL
);
407 static char *print_float(const m_option_t
*opt
, const void *val
)
410 return talloc_asprintf(NULL
, "%f", VAL(val
));
413 const m_option_type_t m_option_type_float
= {
414 // floating point number or ratio (numerator[:/]denominator)
416 .size
= sizeof(float),
417 .parse
= parse_float
,
418 .print
= print_float
,
422 ///////////// Position
424 #define VAL(x) (*(off_t *)(x))
426 static int parse_position(const m_option_t
*opt
, struct bstr name
,
427 struct bstr param
, bool ambiguous_param
, void *dst
,
431 int r
= parse_longlong(opt
, name
, param
, false, &tmp
);
437 static char *print_position(const m_option_t
*opt
, const void *val
)
439 return talloc_asprintf(NULL
, "%"PRId64
, (int64_t)VAL(val
));
442 const m_option_type_t m_option_type_position
= {
445 .size
= sizeof(off_t
),
446 .parse
= parse_position
,
447 .print
= print_position
,
455 #define VAL(x) (*(char **)(x))
457 static int parse_str(const m_option_t
*opt
, struct bstr name
,
458 struct bstr param
, bool ambiguous_param
, void *dst
,
461 if (param
.start
== NULL
)
462 return M_OPT_MISSING_PARAM
;
464 if ((opt
->flags
& M_OPT_MIN
) && (param
.len
< opt
->min
)) {
465 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
466 "Parameter must be >= %d chars: %.*s\n",
467 (int) opt
->min
, BSTR_P(param
));
468 return M_OPT_OUT_OF_RANGE
;
471 if ((opt
->flags
& M_OPT_MAX
) && (param
.len
> opt
->max
)) {
472 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
473 "Parameter must be <= %d chars: %.*s\n",
474 (int) opt
->max
, BSTR_P(param
));
475 return M_OPT_OUT_OF_RANGE
;
479 talloc_free(VAL(dst
));
480 VAL(dst
) = bstrdup0(talloc_ctx
, param
);
487 static char *print_str(const m_option_t
*opt
, const void *val
)
489 return (val
&& VAL(val
)) ? talloc_strdup(NULL
, VAL(val
)) : NULL
;
492 static void copy_str(const m_option_t
*opt
, void *dst
, const void *src
,
496 talloc_free(VAL(dst
));
497 VAL(dst
) = talloc_strdup(talloc_ctx
, VAL(src
));
501 static void free_str(void *src
)
503 if (src
&& VAL(src
)) {
504 talloc_free(VAL(src
));
509 const m_option_type_t m_option_type_string
= {
511 .size
= sizeof(char *),
512 .flags
= M_OPT_TYPE_DYNAMIC
,
519 //////////// String list
522 #define VAL(x) (*(char ***)(x))
530 static void free_str_list(void *dst
)
535 if (!dst
|| !VAL(dst
))
539 for (i
= 0; d
[i
] != NULL
; i
++)
545 static int str_list_add(char **add
, int n
, void *dst
, int pre
, void *talloc_ctx
)
547 char **lst
= VAL(dst
);
551 return M_OPT_PARSER_ERR
;
554 for (ln
= 0; lst
&& lst
[ln
]; ln
++)
557 lst
= talloc_realloc(NULL
, lst
, char *, n
+ ln
+ 1);
560 memmove(&lst
[n
], lst
, ln
* sizeof(char *));
561 memcpy(lst
, add
, n
* sizeof(char *));
563 memcpy(&lst
[ln
], add
, n
* sizeof(char *));
564 // (re-)add NULL-termination
574 static int str_list_del(char **del
, int n
, void *dst
)
581 return M_OPT_PARSER_ERR
;
584 for (ln
= 0; lst
&& lst
[ln
]; ln
++)
588 for (i
= 0; del
[i
] != NULL
; i
++) {
589 idx
= strtol(del
[i
], &ep
, 0);
591 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Invalid index: %s\n", del
[i
]);
596 if (idx
< 0 || idx
>= ln
) {
597 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
598 "Index %ld is out of range.\n", idx
);
600 } else if (!lst
[idx
])
602 talloc_free(lst
[idx
]);
614 // Don't bother shrinking the list allocation
615 for (i
= 0, n
= 0; i
< ln
; i
++) {
626 static struct bstr
get_nextsep(struct bstr
*ptr
, char sep
, bool modify
)
628 struct bstr str
= *ptr
;
629 struct bstr orig
= str
;
631 int idx
= bstrchr(str
, sep
);
632 if (idx
> 0 && str
.start
[idx
- 1] == '\\') {
634 memmove(str
.start
+ idx
- 1, str
.start
+ idx
, str
.len
- idx
);
636 str
= bstr_cut(str
, idx
);
638 str
= bstr_cut(str
, idx
+ 1);
640 str
= bstr_cut(str
, idx
< 0 ? str
.len
: idx
);
645 return bstr_splice(orig
, 0, str
.start
- orig
.start
);
648 static int parse_str_list(const m_option_t
*opt
, struct bstr name
,
649 struct bstr param
, bool ambiguous_param
, void *dst
,
654 int len
= strlen(opt
->name
);
655 if (opt
->name
[len
- 1] == '*' && (name
.len
> len
- 1)) {
656 struct bstr suffix
= bstr_cut(name
, len
- 1);
657 if (bstrcasecmp0(suffix
, "-add") == 0)
659 else if (bstrcasecmp0(suffix
, "-pre") == 0)
661 else if (bstrcasecmp0(suffix
, "-del") == 0)
663 else if (bstrcasecmp0(suffix
, "-clr") == 0)
666 return M_OPT_UNKNOWN
;
676 // All other ops need a param
678 return M_OPT_MISSING_PARAM
;
680 // custom type for "profile" calls this but uses ->priv for something else
681 char separator
= opt
->type
== &m_option_type_string_list
&& opt
->priv
?
682 *(char *)opt
->priv
: OPTION_LIST_SEPARATOR
;
684 struct bstr str
= param
;
686 get_nextsep(&str
, separator
, 0);
687 str
= bstr_cut(str
, 1);
691 return M_OPT_INVALID
;
692 if (((opt
->flags
& M_OPT_MIN
) && (n
< opt
->min
)) ||
693 ((opt
->flags
& M_OPT_MAX
) && (n
> opt
->max
)))
694 return M_OPT_OUT_OF_RANGE
;
699 res
= talloc_array(talloc_ctx
, char *, n
+ 2);
700 str
= bstrdup(NULL
, param
);
701 char *ptr
= str
.start
;
705 struct bstr el
= get_nextsep(&str
, separator
, 1);
706 res
[n
] = bstrdup0(talloc_ctx
, el
);
710 str
= bstr_cut(str
, 1);
717 return str_list_add(res
, n
, dst
, 0, talloc_ctx
);
719 return str_list_add(res
, n
, dst
, 1, talloc_ctx
);
721 return str_list_del(res
, n
, dst
);
731 static void copy_str_list(const m_option_t
*opt
, void *dst
, const void *src
,
749 for (n
= 0; s
[n
] != NULL
; n
++)
751 d
= talloc_array(talloc_ctx
, char *, n
+ 1);
753 d
[n
] = talloc_strdup(talloc_ctx
, s
[n
]);
758 static char *print_str_list(const m_option_t
*opt
, const void *src
)
763 if (!(src
&& VAL(src
)))
767 for (int i
= 0; lst
[i
]; i
++) {
769 ret
= talloc_strdup_append_buffer(ret
, ",");
770 ret
= talloc_strdup_append_buffer(ret
, lst
[i
]);
775 const m_option_type_t m_option_type_string_list
= {
776 /* A list of strings separated by ','.
777 * Option with a name ending in '*' permits using the following suffixes:
778 * -add: Add the given parameters at the end of the list.
779 * -pre: Add the given parameters at the beginning of the list.
780 * -del: Remove the entry at the given indices.
781 * -clr: Clear the list.
782 * e.g: -vf-add flip,mirror -vf-del 2,5
784 .name
= "String list",
785 .size
= sizeof(char **),
786 .flags
= M_OPT_TYPE_DYNAMIC
| M_OPT_TYPE_ALLOW_WILDCARD
,
787 .parse
= parse_str_list
,
788 .print
= print_str_list
,
789 .copy
= copy_str_list
,
790 .free
= free_str_list
,
794 /////////////////// Print
796 static int parse_print(const m_option_t
*opt
, struct bstr name
,
797 struct bstr param
, bool ambiguous_param
, void *dst
,
800 if (opt
->type
== CONF_TYPE_PRINT_INDIRECT
)
801 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "%s", *(char **) opt
->p
);
802 else if (opt
->type
== CONF_TYPE_PRINT_FUNC
) {
803 char *name0
= bstrdup0(NULL
, name
);
804 char *param0
= bstrdup0(NULL
, param
);
805 int r
= ((m_opt_func_full_t
) opt
->p
)(opt
, name0
, param0
);
810 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "%s", mp_gtext(opt
->p
));
812 if (opt
->priv
== NULL
)
817 const m_option_type_t m_option_type_print
= {
819 .parse
= parse_print
,
822 const m_option_type_t m_option_type_print_indirect
= {
824 .parse
= parse_print
,
827 const m_option_type_t m_option_type_print_func
= {
829 .flags
= M_OPT_TYPE_ALLOW_WILDCARD
,
830 .parse
= parse_print
,
834 /////////////////////// Subconfig
836 #define VAL(x) (*(char ***)(x))
838 static int parse_subconf(const m_option_t
*opt
, struct bstr name
,
839 struct bstr param
, bool ambiguous_param
, void *dst
,
846 return M_OPT_MISSING_PARAM
;
848 struct bstr p
= param
;
851 int optlen
= bstrcspn(p
, ":=");
852 struct bstr subopt
= bstr_splice(p
, 0, optlen
);
853 struct bstr subparam
= bstr(NULL
);
854 p
= bstr_cut(p
, optlen
);
855 if (bstr_startswith0(p
, "=")) {
857 if (bstr_startswith0(p
, "\"")) {
859 optlen
= bstrcspn(p
, "\"");
860 subparam
= bstr_splice(p
, 0, optlen
);
861 p
= bstr_cut(p
, optlen
);
862 if (!bstr_startswith0(p
, "\"")) {
863 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
864 "Terminating '\"' missing for '%.*s'\n",
866 return M_OPT_INVALID
;
869 } else if (bstr_startswith0(p
, "%")) {
871 optlen
= bstrtoll(p
, &p
, 0);
872 if (!bstr_startswith0(p
, "%") || (optlen
> p
.len
- 1)) {
873 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
874 "Invalid length %d for '%.*s'\n",
875 optlen
, BSTR_P(subopt
));
876 return M_OPT_INVALID
;
878 subparam
= bstr_splice(p
, 1, optlen
+ 1);
879 p
= bstr_cut(p
, optlen
+ 1);
881 optlen
= bstrcspn(p
, ":");
882 subparam
= bstr_splice(p
, 0, optlen
);
883 p
= bstr_cut(p
, optlen
);
886 if (bstr_startswith0(p
, ":"))
888 else if (p
.len
> 0) {
889 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
890 "Incorrect termination for '%.*s'\n", BSTR_P(subopt
));
891 return M_OPT_INVALID
;
895 lst
= talloc_realloc(NULL
, lst
, char *, 2 * (nr
+ 2));
896 lst
[2 * nr
] = bstrdup0(lst
, subopt
);
897 lst
[2 * nr
+ 1] = bstrdup0(lst
, subparam
);
898 memset(&lst
[2 * (nr
+ 1)], 0, 2 * sizeof(char *));
909 const m_option_type_t m_option_type_subconfig
= {
910 // The syntax is -option opt1=foo:flag:opt2=blah
912 .flags
= M_OPT_TYPE_HAS_CHILD
,
913 .parse
= parse_subconf
,
916 #include "libmpcodecs/img_format.h"
918 /* FIXME: snyc with img_format.h */
922 } mp_imgfmt_list
[] = {
923 {"444p16le", IMGFMT_444P16_LE
},
924 {"444p16be", IMGFMT_444P16_BE
},
925 {"444p10le", IMGFMT_444P10_LE
},
926 {"444p10be", IMGFMT_444P10_BE
},
927 {"444p9le", IMGFMT_444P9_LE
},
928 {"444p9be", IMGFMT_444P9_BE
},
929 {"422p16le", IMGFMT_422P16_LE
},
930 {"422p16be", IMGFMT_422P16_BE
},
931 {"422p10le", IMGFMT_422P10_LE
},
932 {"422p10be", IMGFMT_422P10_BE
},
933 {"420p16le", IMGFMT_420P16_LE
},
934 {"420p16be", IMGFMT_420P16_BE
},
935 {"420p10le", IMGFMT_420P10_LE
},
936 {"420p10be", IMGFMT_420P10_BE
},
937 {"420p9le", IMGFMT_420P9_LE
},
938 {"420p9be", IMGFMT_420P9_BE
},
939 {"444p16", IMGFMT_444P16
},
940 {"444p10", IMGFMT_444P10
},
941 {"444p9", IMGFMT_444P9
},
942 {"422p16", IMGFMT_422P16
},
943 {"422p10", IMGFMT_422P10
},
944 {"420p10", IMGFMT_420P10
},
945 {"420p9", IMGFMT_420P9
},
946 {"420p16", IMGFMT_420P16
},
947 {"420a", IMGFMT_420A
},
948 {"444p", IMGFMT_444P
},
949 {"422p", IMGFMT_422P
},
950 {"411p", IMGFMT_411P
},
951 {"440p", IMGFMT_440P
},
952 {"yuy2", IMGFMT_YUY2
},
953 {"yvyu", IMGFMT_YVYU
},
954 {"uyvy", IMGFMT_UYVY
},
955 {"yvu9", IMGFMT_YVU9
},
956 {"if09", IMGFMT_IF09
},
957 {"yv12", IMGFMT_YV12
},
958 {"i420", IMGFMT_I420
},
959 {"iyuv", IMGFMT_IYUV
},
960 {"clpl", IMGFMT_CLPL
},
961 {"hm12", IMGFMT_HM12
},
962 {"y800", IMGFMT_Y800
},
964 {"nv12", IMGFMT_NV12
},
965 {"nv21", IMGFMT_NV21
},
966 {"bgr24", IMGFMT_BGR24
},
967 {"bgr32", IMGFMT_BGR32
},
968 {"bgr16", IMGFMT_BGR16
},
969 {"bgr15", IMGFMT_BGR15
},
970 {"bgr12", IMGFMT_BGR12
},
971 {"bgr8", IMGFMT_BGR8
},
972 {"bgr4", IMGFMT_BGR4
},
973 {"bg4b", IMGFMT_BG4B
},
974 {"bgr1", IMGFMT_BGR1
},
975 {"rgb48be", IMGFMT_RGB48BE
},
976 {"rgb48le", IMGFMT_RGB48LE
},
977 {"rgb48ne", IMGFMT_RGB48NE
},
978 {"rgb24", IMGFMT_RGB24
},
979 {"rgb32", IMGFMT_RGB32
},
980 {"rgb16", IMGFMT_RGB16
},
981 {"rgb15", IMGFMT_RGB15
},
982 {"rgb12", IMGFMT_RGB12
},
983 {"rgb8", IMGFMT_RGB8
},
984 {"rgb4", IMGFMT_RGB4
},
985 {"rg4b", IMGFMT_RG4B
},
986 {"rgb1", IMGFMT_RGB1
},
987 {"rgba", IMGFMT_RGBA
},
988 {"argb", IMGFMT_ARGB
},
989 {"bgra", IMGFMT_BGRA
},
990 {"abgr", IMGFMT_ABGR
},
991 {"mjpeg", IMGFMT_MJPEG
},
992 {"mjpg", IMGFMT_MJPEG
},
996 static int parse_imgfmt(const m_option_t
*opt
, struct bstr name
,
997 struct bstr param
, bool ambiguous_param
, void *dst
,
1004 return M_OPT_MISSING_PARAM
;
1006 if (!bstrcmp0(param
, "help")) {
1007 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available formats:");
1008 for (i
= 0; mp_imgfmt_list
[i
].name
; i
++)
1009 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, " %s", mp_imgfmt_list
[i
].name
);
1010 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1011 return M_OPT_EXIT
- 1;
1014 if (bstr_startswith0(param
, "0x"))
1015 fmt
= bstrtoll(param
, NULL
, 16);
1017 for (i
= 0; mp_imgfmt_list
[i
].name
; i
++) {
1018 if (!bstrcasecmp0(param
, mp_imgfmt_list
[i
].name
)) {
1019 fmt
= mp_imgfmt_list
[i
].fmt
;
1023 if (!mp_imgfmt_list
[i
].name
) {
1024 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1025 "Option %.*s: unknown format name: '%.*s'\n",
1026 BSTR_P(name
), BSTR_P(param
));
1027 return M_OPT_INVALID
;
1032 *((uint32_t *)dst
) = fmt
;
1037 const m_option_type_t m_option_type_imgfmt
= {
1038 // Please report any missing colorspaces
1039 .name
= "Image format",
1040 .size
= sizeof(uint32_t),
1041 .parse
= parse_imgfmt
,
1045 #include "libaf/af_format.h"
1047 /* FIXME: snyc with af_format.h */
1051 } mp_afmt_list
[] = {
1053 {"mulaw", AF_FORMAT_MU_LAW
},
1054 {"alaw", AF_FORMAT_A_LAW
},
1055 {"mpeg2", AF_FORMAT_MPEG2
},
1056 {"ac3le", AF_FORMAT_AC3_LE
},
1057 {"ac3be", AF_FORMAT_AC3_BE
},
1058 {"ac3ne", AF_FORMAT_AC3_NE
},
1059 {"imaadpcm", AF_FORMAT_IMA_ADPCM
},
1061 {"u8", AF_FORMAT_U8
},
1062 {"s8", AF_FORMAT_S8
},
1063 {"u16le", AF_FORMAT_U16_LE
},
1064 {"u16be", AF_FORMAT_U16_BE
},
1065 {"u16ne", AF_FORMAT_U16_NE
},
1066 {"s16le", AF_FORMAT_S16_LE
},
1067 {"s16be", AF_FORMAT_S16_BE
},
1068 {"s16ne", AF_FORMAT_S16_NE
},
1069 {"u24le", AF_FORMAT_U24_LE
},
1070 {"u24be", AF_FORMAT_U24_BE
},
1071 {"u24ne", AF_FORMAT_U24_NE
},
1072 {"s24le", AF_FORMAT_S24_LE
},
1073 {"s24be", AF_FORMAT_S24_BE
},
1074 {"s24ne", AF_FORMAT_S24_NE
},
1075 {"u32le", AF_FORMAT_U32_LE
},
1076 {"u32be", AF_FORMAT_U32_BE
},
1077 {"u32ne", AF_FORMAT_U32_NE
},
1078 {"s32le", AF_FORMAT_S32_LE
},
1079 {"s32be", AF_FORMAT_S32_BE
},
1080 {"s32ne", AF_FORMAT_S32_NE
},
1081 {"floatle", AF_FORMAT_FLOAT_LE
},
1082 {"floatbe", AF_FORMAT_FLOAT_BE
},
1083 {"floatne", AF_FORMAT_FLOAT_NE
},
1087 static int parse_afmt(const m_option_t
*opt
, struct bstr name
,
1088 struct bstr param
, bool ambiguous_param
, void *dst
,
1095 return M_OPT_MISSING_PARAM
;
1097 if (!bstrcmp0(param
, "help")) {
1098 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available formats:");
1099 for (i
= 0; mp_afmt_list
[i
].name
; i
++)
1100 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, " %s", mp_afmt_list
[i
].name
);
1101 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1102 return M_OPT_EXIT
- 1;
1105 if (bstr_startswith0(param
, "0x"))
1106 fmt
= bstrtoll(param
, NULL
, 16);
1108 for (i
= 0; mp_afmt_list
[i
].name
; i
++) {
1109 if (!bstrcasecmp0(param
, mp_afmt_list
[i
].name
)) {
1110 fmt
= mp_afmt_list
[i
].fmt
;
1114 if (!mp_afmt_list
[i
].name
) {
1115 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1116 "Option %.*s: unknown format name: '%.*s'\n",
1117 BSTR_P(name
), BSTR_P(param
));
1118 return M_OPT_INVALID
;
1123 *((uint32_t *)dst
) = fmt
;
1128 const m_option_type_t m_option_type_afmt
= {
1129 // Please report any missing formats
1130 .name
= "Audio format",
1131 .size
= sizeof(uint32_t),
1132 .parse
= parse_afmt
,
1137 static int parse_timestring(struct bstr str
, double *time
, char endchar
)
1141 *time
= 0; /* ensure initialization for error cases */
1142 if (bstr_sscanf(str
, "%d:%d:%lf%n", &a
, &b
, &d
, &len
) >= 3)
1143 *time
= 3600 * a
+ 60 * b
+ d
;
1144 else if (bstr_sscanf(str
, "%d:%lf%n", &a
, &d
, &len
) >= 2)
1146 else if (bstr_sscanf(str
, "%lf%n", &d
, &len
) >= 1)
1149 return 0; /* unsupported time format */
1150 if (len
< str
.len
&& str
.start
[len
] != endchar
)
1151 return 0; /* invalid extra characters at the end */
1156 static int parse_time(const m_option_t
*opt
, struct bstr name
,
1157 struct bstr param
, bool ambiguous_param
, void *dst
,
1163 return M_OPT_MISSING_PARAM
;
1165 if (!parse_timestring(param
, &time
, 0)) {
1166 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: invalid time: '%.*s'\n",
1167 BSTR_P(name
), BSTR_P(param
));
1168 return M_OPT_INVALID
;
1172 *(double *)dst
= time
;
1176 const m_option_type_t m_option_type_time
= {
1178 .size
= sizeof(double),
1179 .parse
= parse_time
,
1180 .print
= print_double
,
1185 // Time or size (-endpos)
1187 static int parse_time_size(const m_option_t
*opt
, struct bstr name
,
1188 struct bstr param
, bool ambiguous_param
, void *dst
,
1196 return M_OPT_MISSING_PARAM
;
1199 /* End at size parsing */
1200 if (bstr_sscanf(param
, "%lf%3s", &end_at
, unit
) == 2) {
1201 ts
.type
= END_AT_SIZE
;
1202 if (!strcasecmp(unit
, "b"))
1204 else if (!strcasecmp(unit
, "kb"))
1206 else if (!strcasecmp(unit
, "mb"))
1207 end_at
*= 1024 * 1024;
1208 else if (!strcasecmp(unit
, "gb"))
1209 end_at
*= 1024 * 1024 * 1024;
1211 ts
.type
= END_AT_NONE
;
1213 if (ts
.type
== END_AT_SIZE
) {
1219 /* End at time parsing. This has to be last because the parsing accepts
1220 * even a number followed by garbage */
1221 if (!parse_timestring(param
, &end_at
, 0)) {
1222 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1223 "Option %.*s: invalid time or size: '%.*s'\n",
1224 BSTR_P(name
), BSTR_P(param
));
1225 return M_OPT_INVALID
;
1228 ts
.type
= END_AT_TIME
;
1232 *(m_time_size_t
*)dst
= ts
;
1236 const m_option_type_t m_option_type_time_size
= {
1237 .name
= "Time or size",
1238 .size
= sizeof(m_time_size_t
),
1239 .parse
= parse_time_size
,
1244 //// Objects (i.e. filters, etc) settings
1246 #include "m_struct.h"
1249 #define VAL(x) (*(m_obj_settings_t **)(x))
1251 static int find_obj_desc(struct bstr name
, const m_obj_list_t
*l
,
1252 const m_struct_t
**ret
)
1257 for (i
= 0; l
->list
[i
]; i
++) {
1258 n
= M_ST_MB(char *, l
->list
[i
], l
->name_off
);
1259 if (!bstrcmp0(name
, n
)) {
1260 *ret
= M_ST_MB(m_struct_t
*, l
->list
[i
], l
->desc_off
);
1267 static int get_obj_param(struct bstr opt_name
, struct bstr obj_name
,
1268 const m_struct_t
*desc
, struct bstr str
, int *nold
,
1269 int oldmax
, char **dst
)
1271 const m_option_t
*opt
;
1274 int eq
= bstrchr(str
, '=');
1276 if (eq
> 0) { // eq == 0 ignored
1277 struct bstr p
= bstr_cut(str
, eq
+ 1);
1278 str
= bstr_splice(str
, 0, eq
);
1279 opt
= m_option_list_findb(desc
->fields
, str
);
1281 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1282 "Option %.*s: %.*s doesn't have a %.*s parameter.\n",
1283 BSTR_P(opt_name
), BSTR_P(obj_name
), BSTR_P(str
));
1284 return M_OPT_UNKNOWN
;
1286 r
= m_option_parse(opt
, str
, p
, false, NULL
);
1289 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: "
1290 "Error while parsing %.*s parameter %.*s (%.*s)\n",
1291 BSTR_P(opt_name
), BSTR_P(obj_name
), BSTR_P(str
),
1296 dst
[0] = bstrdup0(NULL
, str
);
1297 dst
[1] = bstrdup0(NULL
, p
);
1300 if ((*nold
) >= oldmax
) {
1301 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: %.*s has only %d params, so you can't give more than %d unnamed params.\n",
1302 BSTR_P(opt_name
), BSTR_P(obj_name
), oldmax
, oldmax
);
1303 return M_OPT_OUT_OF_RANGE
;
1305 opt
= &desc
->fields
[(*nold
)];
1306 r
= m_option_parse(opt
, bstr(opt
->name
), str
, false, NULL
);
1309 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: "
1310 "Error while parsing %.*s parameter %s (%.*s)\n",
1311 BSTR_P(opt_name
), BSTR_P(obj_name
), opt
->name
,
1316 dst
[0] = talloc_strdup(NULL
, opt
->name
);
1317 dst
[1] = bstrdup0(NULL
, str
);
1324 static int get_obj_params(struct bstr opt_name
, struct bstr name
,
1325 struct bstr params
, const m_struct_t
*desc
,
1326 char separator
, char ***_ret
)
1328 int n
= 0, nold
= 0, nopts
;
1331 if (!bstrcmp0(params
, "help")) { // Help
1332 char min
[50], max
[50];
1333 if (!desc
->fields
) {
1334 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1335 "%.*s doesn't have any options.\n\n", BSTR_P(name
));
1336 return M_OPT_EXIT
- 1;
1338 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1339 "\n Name Type Min Max\n\n");
1340 for (n
= 0; desc
->fields
[n
].name
; n
++) {
1341 const m_option_t
*opt
= &desc
->fields
[n
];
1342 if (opt
->type
->flags
& M_OPT_TYPE_HAS_CHILD
)
1344 if (opt
->flags
& M_OPT_MIN
)
1345 sprintf(min
, "%-8.0f", opt
->min
);
1348 if (opt
->flags
& M_OPT_MAX
)
1349 sprintf(max
, "%-8.0f", opt
->max
);
1352 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1353 " %-20.20s %-15.15s %-10.10s %-10.10s\n",
1354 opt
->name
, opt
->type
->name
, min
, max
);
1356 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1357 return M_OPT_EXIT
- 1;
1360 for (nopts
= 0; desc
->fields
[nopts
].name
; nopts
++)
1363 // TODO : Check that each opt can be parsed
1364 struct bstr s
= params
;
1367 int idx
= bstrchr(s
, separator
);
1372 struct bstr field
= bstr_splice(s
, 0, idx
);
1373 s
= bstr_cut(s
, idx
+ 1);
1374 if (field
.len
== 0) { // Empty field, count it and go on
1377 int r
= get_obj_param(opt_name
, name
, desc
, field
, &nold
, nopts
,
1387 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Too many options for %.*s\n",
1389 return M_OPT_OUT_OF_RANGE
;
1391 if (!_ret
) // Just test
1393 if (n
== 0) // No options or only empty options
1396 ret
= talloc_array(NULL
, char *, (n
+ 2) * 2);
1401 int idx
= bstrchr(s
, separator
);
1404 struct bstr field
= bstr_splice(s
, 0, idx
);
1405 s
= bstr_cut(s
, idx
+ 1);
1406 if (field
.len
== 0) { // Empty field, count it and go on
1409 get_obj_param(opt_name
, name
, desc
, field
, &nold
, nopts
,
1414 ret
[n
* 2] = ret
[n
* 2 + 1] = NULL
;
1420 static int parse_obj_params(const m_option_t
*opt
, struct bstr name
,
1421 struct bstr param
, bool ambiguous_param
, void *dst
,
1426 m_obj_params_t
*p
= opt
->priv
;
1427 const m_struct_t
*desc
;
1429 // We need the object desc
1431 return M_OPT_INVALID
;
1434 r
= get_obj_params(name
, bstr(desc
->name
), param
, desc
, p
->separator
,
1435 dst
? &opts
: NULL
);
1440 if (!opts
) // no arguments given
1443 for (r
= 0; opts
[r
]; r
+= 2)
1444 m_struct_set(desc
, dst
, opts
[r
], bstr(opts
[r
+ 1]));
1450 const m_option_type_t m_option_type_obj_params
= {
1451 .name
= "Object params",
1452 .parse
= parse_obj_params
,
1455 /// Some predefined types as a definition would be quite lengthy
1458 static const m_span_t m_span_params_dflts
= {
1461 static const m_option_t m_span_params_fields
[] = {
1462 {"start", M_ST_OFF(m_span_t
, start
), CONF_TYPE_INT
, M_OPT_MIN
, 1, 0, NULL
},
1463 {"end", M_ST_OFF(m_span_t
, end
), CONF_TYPE_INT
, M_OPT_MIN
, 1, 0, NULL
},
1464 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
1466 static const struct m_struct_st m_span_opts
= {
1469 &m_span_params_dflts
,
1470 m_span_params_fields
1472 const m_obj_params_t m_span_params_def
= {
1477 static int parse_obj_settings(struct bstr opt
, struct bstr str
,
1478 const m_obj_list_t
*list
,
1479 m_obj_settings_t
**_ret
, int ret_n
)
1482 char **plist
= NULL
;
1483 const m_struct_t
*desc
;
1484 m_obj_settings_t
*ret
= _ret
? *_ret
: NULL
;
1486 struct bstr param
= bstr(NULL
);
1487 int idx
= bstrchr(str
, '=');
1489 param
= bstr_cut(str
, idx
+ 1);
1490 str
= bstr_splice(str
, 0, idx
);
1493 if (!find_obj_desc(str
, list
, &desc
)) {
1494 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: %.*s doesn't exist.\n",
1495 BSTR_P(opt
), BSTR_P(str
));
1496 return M_OPT_INVALID
;
1500 if (!desc
&& _ret
) {
1501 if (!bstrcmp0(param
, "help")) {
1502 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1503 "Option %.*s: %.*s have no option description.\n",
1504 BSTR_P(opt
), BSTR_P(str
));
1505 return M_OPT_EXIT
- 1;
1507 plist
= talloc_zero_array(NULL
, char *, 4);
1508 plist
[0] = talloc_strdup(NULL
, "_oldargs_");
1509 plist
[1] = bstrdup0(NULL
, param
);
1511 r
= get_obj_params(opt
, str
, param
, desc
, ':',
1512 _ret
? &plist
: NULL
);
1520 ret
= talloc_realloc(NULL
, ret
, struct m_obj_settings
, ret_n
+ 2);
1521 memset(&ret
[ret_n
], 0, 2 * sizeof(m_obj_settings_t
));
1522 ret
[ret_n
].name
= bstrdup0(NULL
, str
);
1523 ret
[ret_n
].attribs
= plist
;
1529 static int obj_settings_list_del(struct bstr opt_name
, struct bstr param
,
1530 bool ambiguous_param
, void *dst
)
1532 char **str_list
= NULL
;
1533 int r
, i
, idx_max
= 0;
1534 char *rem_id
= "_removed_marker_";
1536 assert(opt_name
.len
< 100);
1537 memcpy(name
, opt_name
.start
, opt_name
.len
);
1538 name
[opt_name
.len
] = 0;
1539 const m_option_t list_opt
= {
1540 name
, NULL
, CONF_TYPE_STRING_LIST
,
1543 m_obj_settings_t
*obj_list
= dst
? VAL(dst
) : NULL
;
1545 if (dst
&& !obj_list
) {
1546 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
, "Option %.*s: the list is empty.\n",
1549 } else if (obj_list
) {
1550 for (idx_max
= 0; obj_list
[idx_max
].name
!= NULL
; idx_max
++)
1554 r
= m_option_parse(&list_opt
, opt_name
, param
, false, &str_list
);
1555 if (r
< 0 || !str_list
)
1558 for (r
= 0; str_list
[r
]; r
++) {
1561 id
= strtol(str_list
[r
], &endptr
, 0);
1562 if (endptr
== str_list
[r
]) {
1563 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
));
1564 m_option_free(&list_opt
, &str_list
);
1565 return M_OPT_INVALID
;
1569 if (id
>= idx_max
|| id
< -idx_max
) {
1570 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1571 "Option %.*s: Index %d is out of range.\n",
1572 BSTR_P(opt_name
), id
);
1577 talloc_free(obj_list
[id
].name
);
1578 free_str_list(&(obj_list
[id
].attribs
));
1579 obj_list
[id
].name
= rem_id
;
1583 m_option_free(&list_opt
, &str_list
);
1587 for (i
= 0; obj_list
[i
].name
; i
++) {
1588 while (obj_list
[i
].name
== rem_id
) {
1589 memmove(&obj_list
[i
], &obj_list
[i
+ 1],
1590 sizeof(m_obj_settings_t
) * (idx_max
- i
));
1594 obj_list
= talloc_realloc(NULL
, obj_list
, struct m_obj_settings
,
1596 VAL(dst
) = obj_list
;
1601 static void free_obj_settings_list(void *dst
)
1604 m_obj_settings_t
*d
;
1606 if (!dst
|| !VAL(dst
))
1610 for (n
= 0; d
[n
].name
; n
++) {
1611 talloc_free(d
[n
].name
);
1612 free_str_list(&(d
[n
].attribs
));
1618 static int parse_obj_settings_list(const m_option_t
*opt
, struct bstr name
,
1619 struct bstr param
, bool ambiguous_param
,
1620 void *dst
, void *talloc_ctx
)
1622 int len
= strlen(opt
->name
);
1623 m_obj_settings_t
*res
= NULL
, *queue
= NULL
, *head
= NULL
;
1626 // We need the objects list
1628 return M_OPT_INVALID
;
1630 if (opt
->name
[len
- 1] == '*' && (name
.len
> len
- 1)) {
1631 struct bstr suffix
= bstr_cut(name
, len
- 1);
1632 if (bstrcasecmp0(suffix
, "-add") == 0)
1634 else if (bstrcasecmp0(suffix
, "-pre") == 0)
1636 else if (bstrcasecmp0(suffix
, "-del") == 0)
1638 else if (bstrcasecmp0(suffix
, "-clr") == 0)
1642 strncpy(prefix
, opt
->name
, len
- 1);
1643 prefix
[len
- 1] = '\0';
1644 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1645 "Option %.*s: unknown postfix %.*s\n"
1646 "Supported postfixes are:\n"
1648 " Append the given list to the current list\n\n"
1650 " Prepend the given list to the current list\n\n"
1652 " Remove the given elements. Take the list element index (starting from 0).\n"
1653 " Negative index can be used (i.e. -1 is the last element)\n\n"
1655 " Clear the current list.\n",
1656 BSTR_P(name
), BSTR_P(suffix
), prefix
, prefix
, prefix
, prefix
);
1658 return M_OPT_UNKNOWN
;
1662 // Clear the list ??
1665 free_obj_settings_list(dst
);
1670 return M_OPT_MISSING_PARAM
;
1682 return obj_settings_list_del(name
, param
, false, dst
);
1684 if (dst
&& VAL(dst
))
1685 free_obj_settings_list(dst
);
1688 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: FIXME\n", BSTR_P(name
));
1689 return M_OPT_UNKNOWN
;
1692 if (!bstrcmp0(param
, "help")) {
1693 m_obj_list_t
*ol
= opt
->priv
;
1694 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available video filters:\n");
1695 for (int n
= 0; ol
->list
[n
]; n
++)
1696 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, " %-15s: %s\n",
1697 M_ST_MB(char *, ol
->list
[n
], ol
->name_off
),
1698 M_ST_MB(char *, ol
->list
[n
], ol
->info_off
));
1699 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1700 return M_OPT_EXIT
- 1;
1703 struct bstr s
= bstrdup(NULL
, param
);
1704 char *allocptr
= s
.start
;
1707 struct bstr el
= get_nextsep(&s
, OPTION_LIST_SEPARATOR
, 1);
1708 int r
= parse_obj_settings(name
, el
, opt
->priv
, dst
? &res
: NULL
, n
);
1710 talloc_free(allocptr
);
1716 talloc_free(allocptr
);
1718 return M_OPT_INVALID
;
1720 if (((opt
->flags
& M_OPT_MIN
) && (n
< opt
->min
)) ||
1721 ((opt
->flags
& M_OPT_MAX
) && (n
> opt
->max
)))
1722 return M_OPT_OUT_OF_RANGE
;
1727 for (qsize
= 0; queue
[qsize
].name
; qsize
++)
1729 res
= talloc_realloc(NULL
, res
, struct m_obj_settings
,
1731 memcpy(&res
[n
], queue
, (qsize
+ 1) * sizeof(m_obj_settings_t
));
1737 for (hsize
= 0; head
[hsize
].name
; hsize
++)
1739 head
= talloc_realloc(NULL
, head
, struct m_obj_settings
,
1741 memcpy(&head
[hsize
], res
, (n
+ 1) * sizeof(m_obj_settings_t
));
1750 static void copy_obj_settings_list(const m_option_t
*opt
, void *dst
,
1751 const void *src
, void *talloc_ctx
)
1753 m_obj_settings_t
*d
, *s
;
1762 free_obj_settings_list(dst
);
1768 for (n
= 0; s
[n
].name
; n
++)
1770 d
= talloc_array(NULL
, struct m_obj_settings
, n
+ 1);
1771 for (n
= 0; s
[n
].name
; n
++) {
1772 d
[n
].name
= talloc_strdup(NULL
, s
[n
].name
);
1773 d
[n
].attribs
= NULL
;
1774 copy_str_list(NULL
, &(d
[n
].attribs
), &(s
[n
].attribs
), NULL
);
1777 d
[n
].attribs
= NULL
;
1781 const m_option_type_t m_option_type_obj_settings_list
= {
1782 .name
= "Object settings list",
1783 .size
= sizeof(m_obj_settings_t
*),
1784 .flags
= M_OPT_TYPE_DYNAMIC
| M_OPT_TYPE_ALLOW_WILDCARD
,
1785 .parse
= parse_obj_settings_list
,
1786 .copy
= copy_obj_settings_list
,
1787 .free
= free_obj_settings_list
,
1792 static int parse_obj_presets(const m_option_t
*opt
, struct bstr name
,
1793 struct bstr param
, bool ambiguous_param
,
1794 void *dst
, void *talloc_ctx
)
1796 m_obj_presets_t
*obj_p
= (m_obj_presets_t
*)opt
->priv
;
1797 const m_struct_t
*in_desc
;
1798 const m_struct_t
*out_desc
;
1800 const unsigned char *pre
;
1801 char *pre_name
= NULL
;
1804 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: Presets need a "
1805 "pointer to a m_obj_presets_t in the priv field.\n",
1807 return M_OPT_PARSER_ERR
;
1811 return M_OPT_MISSING_PARAM
;
1813 pre
= obj_p
->presets
;
1814 in_desc
= obj_p
->in_desc
;
1815 out_desc
= obj_p
->out_desc
? obj_p
->out_desc
: obj_p
->in_desc
;
1818 if (!bstrcmp0(param
, "help")) {
1819 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available presets for %s->%.*s:",
1820 out_desc
->name
, BSTR_P(name
));
1821 for (pre
= obj_p
->presets
;
1822 (pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
)); pre
+= s
)
1823 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, " %s", pre_name
);
1824 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "\n");
1825 return M_OPT_EXIT
- 1;
1828 for (pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
); pre_name
;
1829 pre
+= s
, pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
))
1830 if (!bstrcmp0(param
, pre_name
))
1833 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1834 "Option %.*s: There is no preset named %.*s\n"
1835 "Available presets are:", BSTR_P(name
), BSTR_P(param
));
1836 for (pre
= obj_p
->presets
;
1837 (pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
)); pre
+= s
)
1838 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, " %s", pre_name
);
1839 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "\n");
1840 return M_OPT_INVALID
;
1846 for (i
= 0; in_desc
->fields
[i
].name
; i
++) {
1847 const m_option_t
*out_opt
= m_option_list_find(out_desc
->fields
,
1848 in_desc
->fields
[i
].name
);
1850 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1851 "Option %.*s: Unable to find the target option for field %s.\n"
1852 "Please report this to the developers.\n",
1853 BSTR_P(name
), in_desc
->fields
[i
].name
);
1854 return M_OPT_PARSER_ERR
;
1856 m_option_copy(out_opt
, M_ST_MB_P(dst
, out_opt
->p
),
1857 M_ST_MB_P(pre
, in_desc
->fields
[i
].p
));
1863 const m_option_type_t m_option_type_obj_presets
= {
1864 .name
= "Object presets",
1865 .parse
= parse_obj_presets
,
1868 static int parse_custom_url(const m_option_t
*opt
, struct bstr name
,
1869 struct bstr url
, bool ambiguous_param
, void *dst
,
1873 m_struct_t
*desc
= opt
->priv
;
1876 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: Custom URL needs "
1877 "a pointer to a m_struct_t in the priv field.\n", BSTR_P(name
));
1878 return M_OPT_PARSER_ERR
;
1881 // extract the protocol
1882 int idx
= bstr_find0(url
, "://");
1885 if (m_option_list_find(desc
->fields
, "filename")) {
1886 m_struct_set(desc
, dst
, "filename", url
);
1889 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1890 "Option %.*s: URL doesn't have a valid protocol!\n",
1892 return M_OPT_INVALID
;
1894 struct bstr ptr1
= bstr_cut(url
, idx
+ 3);
1895 if (m_option_list_find(desc
->fields
, "string")) {
1897 m_struct_set(desc
, dst
, "string", ptr1
);
1901 if (dst
&& m_option_list_find(desc
->fields
, "protocol")) {
1902 r
= m_struct_set(desc
, dst
, "protocol", bstr_splice(url
, 0, idx
));
1904 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1905 "Option %.*s: Error while setting protocol.\n",
1911 // check if a username:password is given
1912 idx
= bstrchr(ptr1
, '/');
1915 struct bstr hostpart
= bstr_splice(ptr1
, 0, idx
);
1916 struct bstr path
= bstr_cut(ptr1
, idx
);
1917 idx
= bstrchr(hostpart
, '@');
1919 // We got something, at least a username...
1920 if (!m_option_list_find(desc
->fields
, "username")) {
1921 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1922 "Option %.*s: This URL doesn't have a username part.\n",
1926 struct bstr userpass
= bstr_splice(hostpart
, 0, idx
);
1927 idx
= bstrchr(userpass
, ':');
1929 // We also have a password
1930 if (!m_option_list_find(desc
->fields
, "password")) {
1931 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1932 "Option %.*s: This URL doesn't have a password part.\n",
1935 } else { // Username and password
1937 r
= m_struct_set(desc
, dst
, "username",
1938 bstr_splice(userpass
, 0, idx
));
1940 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1941 "Option %.*s: Error while setting username.\n",
1945 r
= m_struct_set(desc
, dst
, "password",
1946 bstr_splice(userpass
, idx
+1,
1949 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1950 "Option %.*s: Error while setting password.\n",
1956 } else { // User name only
1957 r
= m_struct_set(desc
, dst
, "username", userpass
);
1959 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1960 "Option %.*s: Error while setting username.\n",
1966 hostpart
= bstr_cut(hostpart
, idx
+ 1);
1969 // Before looking for a port number check if we have an IPv6 type
1971 // In an IPv6 URL the numeric address should be inside square braces.
1972 int idx1
= bstrchr(hostpart
, '[');
1973 int idx2
= bstrchr(hostpart
, ']');
1974 struct bstr portstr
= hostpart
;
1975 bool v6addr
= false;
1976 if (idx1
>= 0 && idx2
>= 0 && idx1
< idx2
) {
1977 // we have an IPv6 numeric address
1978 portstr
= bstr_cut(hostpart
, idx2
);
1979 hostpart
= bstr_splice(hostpart
, idx1
+ 1, idx2
);
1983 idx
= bstrchr(portstr
, ':');
1986 hostpart
= bstr_splice(hostpart
, 0, idx
);
1987 // We have an URL beginning like http://www.hostname.com:1212
1988 // Get the port number
1989 if (!m_option_list_find(desc
->fields
, "port")) {
1990 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1991 "Option %.*s: This URL doesn't have a port part.\n",
1996 int p
= bstrtoll(bstr_cut(portstr
, idx
+ 1), NULL
, 0);
1998 snprintf(tmp
, 99, "%d", p
);
1999 r
= m_struct_set(desc
, dst
, "port", bstr(tmp
));
2001 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2002 "Option %.*s: Error while setting port.\n",
2010 if (hostpart
.len
> 0) {
2011 if (!m_option_list_find(desc
->fields
, "hostname")) {
2012 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
2013 "Option %.*s: This URL doesn't have a hostname part.\n",
2017 r
= m_struct_set(desc
, dst
, "hostname", hostpart
);
2019 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2020 "Option %.*s: Error while setting hostname.\n",
2026 // Look if a path is given
2027 if (path
.len
> 1) { // not just "/"
2028 // copy the path/filename in the URL container
2029 if (!m_option_list_find(desc
->fields
, "filename")) {
2030 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
2031 "Option %.*s: This URL doesn't have a filename part.\n",
2036 char *fname
= bstrdup0(NULL
, bstr_cut(path
, 1));
2037 url_unescape_string(fname
, fname
);
2038 r
= m_struct_set(desc
, dst
, "filename", bstr(fname
));
2041 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2042 "Option %.*s: Error while setting filename.\n",
2052 /// TODO : Write the other needed funcs for 'normal' options
2053 const m_option_type_t m_option_type_custom_url
= {
2054 .name
= "Custom URL",
2055 .parse
= parse_custom_url
,