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
= {
133 "need yes or no in config files",
146 static int parse_longlong(const m_option_t
*opt
, struct bstr name
,
147 struct bstr param
, bool ambiguous_param
, void *dst
)
150 return M_OPT_MISSING_PARAM
;
153 long long tmp_int
= bstrtoll(param
, &rest
, 10);
155 tmp_int
= bstrtoll(param
, &rest
, 0);
157 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
158 "The %.*s option must be an integer: %.*s\n",
159 BSTR_P(name
), BSTR_P(param
));
160 return M_OPT_INVALID
;
163 if ((opt
->flags
& M_OPT_MIN
) && (tmp_int
< opt
->min
)) {
164 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
165 "The %.*s option must be >= %d: %.*s\n",
166 BSTR_P(name
), (int) opt
->min
, BSTR_P(param
));
167 return M_OPT_OUT_OF_RANGE
;
170 if ((opt
->flags
& M_OPT_MAX
) && (tmp_int
> opt
->max
)) {
171 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
172 "The %.*s option must be <= %d: %.*s\n",
173 BSTR_P(name
), (int) opt
->max
, BSTR_P(param
));
174 return M_OPT_OUT_OF_RANGE
;
178 *(long long *)dst
= tmp_int
;
183 static int parse_int(const m_option_t
*opt
, struct bstr name
,
184 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
)
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
= {
224 const m_option_type_t m_option_type_int64
= {
237 static int parse_intpair(const struct m_option
*opt
, struct bstr name
,
238 struct bstr param
, bool ambiguous_param
, void *dst
)
241 return M_OPT_MISSING_PARAM
;
243 struct bstr s
= param
;
245 int start
= bstrtoll(s
, &s
, 10);
246 if (s
.len
== param
.len
)
249 if (!bstr_startswith0(s
, "-"))
254 end
= bstrtoll(s
, &s
, 10);
267 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Invalid integer range "
268 "specification for option %.*s: %.*s\n",
269 BSTR_P(name
), BSTR_P(param
));
270 return M_OPT_INVALID
;
273 const struct m_option_type m_option_type_intpair
= {
275 .size
= sizeof(int[2]),
276 .parse
= parse_intpair
,
281 static int parse_choice(const struct m_option
*opt
, struct bstr name
,
282 struct bstr param
, bool ambiguous_param
, void *dst
)
285 return M_OPT_MISSING_PARAM
;
287 struct m_opt_choice_alternatives
*alt
;
288 for (alt
= opt
->priv
; alt
->name
; alt
++)
289 if (!bstrcasecmp0(param
, alt
->name
))
292 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
293 "Invalid value for option %.*s: %.*s\n",
294 BSTR_P(name
), BSTR_P(param
));
295 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Valid values are:");
296 for (alt
= opt
->priv
; alt
->name
; alt
++)
297 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, " %s", alt
->name
);
298 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "\n");
299 return M_OPT_INVALID
;
302 *(int *)dst
= alt
->value
;
307 static char *print_choice(const m_option_t
*opt
, const void *val
)
310 struct m_opt_choice_alternatives
*alt
;
311 for (alt
= opt
->priv
; alt
->name
; alt
++)
313 return talloc_strdup(NULL
, alt
->name
);
317 const struct m_option_type m_option_type_choice
= {
318 .name
= "String", // same as arbitrary strings in option list for now
320 .parse
= parse_choice
,
321 .print
= print_choice
,
329 #define VAL(x) (*(double *)(x))
331 static int parse_double(const m_option_t
*opt
, struct bstr name
,
332 struct bstr param
, bool ambiguous_param
, void *dst
)
335 return M_OPT_MISSING_PARAM
;
338 double tmp_float
= bstrtod(param
, &rest
);
340 switch (rest
.len
? rest
.start
[0] : 0) {
343 tmp_float
/= bstrtod(bstr_cut(rest
, 1), &rest
);
347 /* we also handle floats specified with
348 * non-locale decimal point ::atmos
350 rest
= bstr_cut(rest
, 1);
352 tmp_float
-= 1.0 / pow(10, rest
.len
) * bstrtod(rest
, &rest
);
354 tmp_float
+= 1.0 / pow(10, rest
.len
) * bstrtod(rest
, &rest
);
359 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
360 "The %.*s option must be a floating point number or a "
361 "ratio (numerator[:/]denominator): %.*s\n",
362 BSTR_P(name
), BSTR_P(param
));
363 return M_OPT_INVALID
;
366 if (opt
->flags
& M_OPT_MIN
)
367 if (tmp_float
< opt
->min
) {
368 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
369 "The %.*s option must be >= %f: %.*s\n",
370 BSTR_P(name
), opt
->min
, BSTR_P(param
));
371 return M_OPT_OUT_OF_RANGE
;
374 if (opt
->flags
& M_OPT_MAX
)
375 if (tmp_float
> opt
->max
) {
376 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
377 "The %.*s option must be <= %f: %.*s\n",
378 BSTR_P(name
), opt
->max
, BSTR_P(param
));
379 return M_OPT_OUT_OF_RANGE
;
383 VAL(dst
) = tmp_float
;
387 static char *print_double(const m_option_t
*opt
, const void *val
)
390 return talloc_asprintf(NULL
, "%f", VAL(val
));
393 const m_option_type_t m_option_type_double
= {
395 "double precision floating point number or ratio (numerator[:/]denominator)",
407 #define VAL(x) (*(float *)(x))
409 static int parse_float(const m_option_t
*opt
, struct bstr name
,
410 struct bstr param
, bool ambiguous_param
, void *dst
)
413 int r
= parse_double(opt
, name
, param
, false, &tmp
);
419 static char *print_float(const m_option_t
*opt
, const void *val
)
422 return talloc_asprintf(NULL
, "%f", VAL(val
));
425 const m_option_type_t m_option_type_float
= {
427 "floating point number or ratio (numerator[:/]denominator)",
438 ///////////// Position
440 #define VAL(x) (*(off_t *)(x))
442 static int parse_position(const m_option_t
*opt
, struct bstr name
,
443 struct bstr param
, bool ambiguous_param
, void *dst
)
446 int r
= parse_longlong(opt
, name
, param
, false, &tmp
);
452 static char *print_position(const m_option_t
*opt
, const void *val
)
454 return talloc_asprintf(NULL
, "%"PRId64
, (int64_t)VAL(val
));
457 const m_option_type_t m_option_type_position
= {
474 #define VAL(x) (*(char **)(x))
476 static int parse_str(const m_option_t
*opt
, struct bstr name
,
477 struct bstr param
, bool ambiguous_param
, void *dst
)
479 if ((opt
->flags
& M_OPT_MIN
) && (param
.len
< opt
->min
)) {
480 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
481 "Parameter must be >= %d chars: %.*s\n",
482 (int) opt
->min
, BSTR_P(param
));
483 return M_OPT_OUT_OF_RANGE
;
486 if ((opt
->flags
& M_OPT_MAX
) && (param
.len
> opt
->max
)) {
487 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
488 "Parameter must be <= %d chars: %.*s\n",
489 (int) opt
->max
, BSTR_P(param
));
490 return M_OPT_OUT_OF_RANGE
;
494 talloc_free(VAL(dst
));
495 VAL(dst
) = bstrdup0(NULL
, param
);
502 static char *print_str(const m_option_t
*opt
, const void *val
)
504 return (val
&& VAL(val
)) ? talloc_strdup(NULL
, VAL(val
)) : NULL
;
507 static void copy_str(const m_option_t
*opt
, void *dst
, const void *src
)
510 talloc_free(VAL(dst
));
511 VAL(dst
) = talloc_strdup(NULL
, VAL(src
));
515 static void free_str(void *src
)
517 if (src
&& VAL(src
)) {
518 talloc_free(VAL(src
));
523 const m_option_type_t m_option_type_string
= {
536 //////////// String list
539 #define VAL(x) (*(char ***)(x))
547 static void free_str_list(void *dst
)
552 if (!dst
|| !VAL(dst
))
556 for (i
= 0; d
[i
] != NULL
; i
++)
562 static int str_list_add(char **add
, int n
, void *dst
, int pre
)
564 char **lst
= VAL(dst
);
568 return M_OPT_PARSER_ERR
;
571 for (ln
= 0; lst
&& lst
[ln
]; ln
++)
574 lst
= talloc_realloc(NULL
, lst
, char *, n
+ ln
+ 1);
577 memmove(&lst
[n
], lst
, ln
* sizeof(char *));
578 memcpy(lst
, add
, n
* sizeof(char *));
580 memcpy(&lst
[ln
], add
, n
* sizeof(char *));
581 // (re-)add NULL-termination
591 static int str_list_del(char **del
, int n
, void *dst
)
598 return M_OPT_PARSER_ERR
;
601 for (ln
= 0; lst
&& lst
[ln
]; ln
++)
605 for (i
= 0; del
[i
] != NULL
; i
++) {
606 idx
= strtol(del
[i
], &ep
, 0);
608 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Invalid index: %s\n", del
[i
]);
613 if (idx
< 0 || idx
>= ln
) {
614 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
615 "Index %ld is out of range.\n", idx
);
617 } else if (!lst
[idx
])
619 talloc_free(lst
[idx
]);
631 // Don't bother shrinking the list allocation
632 for (i
= 0, n
= 0; i
< ln
; i
++) {
643 static struct bstr
get_nextsep(struct bstr
*ptr
, char sep
, bool modify
)
645 struct bstr str
= *ptr
;
646 struct bstr orig
= str
;
648 int idx
= bstrchr(str
, sep
);
649 if (idx
> 0 && str
.start
[idx
- 1] == '\\') {
651 memmove(str
.start
+ idx
- 1, str
.start
+ idx
, str
.len
- idx
);
653 str
= bstr_cut(str
, idx
);
655 str
= bstr_cut(str
, idx
+ 1);
657 str
= bstr_cut(str
, idx
< 0 ? str
.len
: idx
);
662 return bstr_splice(orig
, 0, str
.start
- orig
.start
);
665 static int parse_str_list(const m_option_t
*opt
, struct bstr name
,
666 struct bstr param
, bool ambiguous_param
, void *dst
)
670 int len
= strlen(opt
->name
);
671 if (opt
->name
[len
- 1] == '*' && (name
.len
> len
- 1)) {
672 struct bstr suffix
= bstr_cut(name
, len
- 1);
673 if (bstrcasecmp0(suffix
, "-add") == 0)
675 else if (bstrcasecmp0(suffix
, "-pre") == 0)
677 else if (bstrcasecmp0(suffix
, "-del") == 0)
679 else if (bstrcasecmp0(suffix
, "-clr") == 0)
682 return M_OPT_UNKNOWN
;
692 // All other ops need a param
694 return M_OPT_MISSING_PARAM
;
696 // custom type for "profile" calls this but uses ->priv for something else
697 char separator
= opt
->type
== &m_option_type_string_list
&& opt
->priv
?
698 *(char *)opt
->priv
: OPTION_LIST_SEPARATOR
;
700 struct bstr str
= param
;
702 get_nextsep(&str
, separator
, 0);
703 str
= bstr_cut(str
, 1);
707 return M_OPT_INVALID
;
708 if (((opt
->flags
& M_OPT_MIN
) && (n
< opt
->min
)) ||
709 ((opt
->flags
& M_OPT_MAX
) && (n
> opt
->max
)))
710 return M_OPT_OUT_OF_RANGE
;
715 res
= talloc_array(NULL
, char *, n
+ 2);
716 str
= bstrdup(NULL
, param
);
717 char *ptr
= str
.start
;
721 struct bstr el
= get_nextsep(&str
, separator
, 1);
722 res
[n
] = bstrdup0(NULL
, el
);
726 str
= bstr_cut(str
, 1);
733 return str_list_add(res
, n
, dst
, 0);
735 return str_list_add(res
, n
, dst
, 1);
737 return str_list_del(res
, n
, dst
);
747 static void copy_str_list(const m_option_t
*opt
, void *dst
, const void *src
)
764 for (n
= 0; s
[n
] != NULL
; n
++)
766 d
= talloc_array(NULL
, char *, n
+ 1);
768 d
[n
] = talloc_strdup(NULL
, s
[n
]);
773 static char *print_str_list(const m_option_t
*opt
, const void *src
)
778 if (!(src
&& VAL(src
)))
782 for (int i
= 0; lst
[i
]; i
++) {
784 ret
= talloc_strdup_append_buffer(ret
, ",");
785 ret
= talloc_strdup_append_buffer(ret
, lst
[i
]);
790 const m_option_type_t m_option_type_string_list
= {
792 "A list of strings separated by ','\n"
793 "Option with a name ending in an * permits using the following suffix: \n"
794 "\t-add: Add the given parameters at the end of the list.\n"
795 "\t-pre: Add the given parameters at the beginning of the list.\n"
796 "\t-del: Remove the entry at the given indices.\n"
797 "\t-clr: Clear the list.\n"
798 "e.g: -vf-add flip,mirror -vf-del 2,5\n",
800 M_OPT_TYPE_DYNAMIC
| M_OPT_TYPE_ALLOW_WILDCARD
,
810 /////////////////// Func based options
812 // A chained list to save the various calls for func_param
814 struct m_func_save
*next
;
820 #define VAL(x) (*(struct m_func_save **)(x))
822 static void free_func_pf(void *src
)
824 struct m_func_save
*s
, *n
;
833 talloc_free(s
->name
);
834 talloc_free(s
->param
);
841 // Parser for func_param
842 static int parse_func_pf(const m_option_t
*opt
, struct bstr name
,
843 struct bstr param
, bool ambiguous_param
, void *dst
)
845 struct m_func_save
*s
, *p
;
850 s
= talloc_zero(NULL
, struct m_func_save
);
851 s
->name
= bstrdup0(NULL
, name
);
852 s
->param
= bstrdup0(NULL
, param
);
856 for (; p
->next
!= NULL
; p
= p
->next
)
865 static void copy_func_pf(const m_option_t
*opt
, void *dst
, const void *src
)
867 struct m_func_save
*d
= NULL
, *s
, *last
= NULL
;
877 d
= talloc_zero(NULL
, struct m_func_save
);
878 d
->name
= talloc_strdup(NULL
, s
->name
);
879 d
->param
= talloc_strdup(NULL
, s
->param
);
891 /////////////////// Func_param
893 static void set_func_param(const m_option_t
*opt
, void *dst
, const void *src
)
895 struct m_func_save
*s
;
904 for (; s
!= NULL
; s
= s
->next
)
905 ((m_opt_func_param_t
) opt
->p
)(opt
, s
->param
);
908 const m_option_type_t m_option_type_func_param
= {
911 sizeof(struct m_func_save
*),
915 NULL
, // Nothing to do on save
925 static int parse_func(const m_option_t
*opt
, struct bstr name
,
926 struct bstr param
, bool ambiguous_param
, void *dst
)
931 static void set_func(const m_option_t
*opt
, void *dst
, const void *src
)
933 ((m_opt_func_t
) opt
->p
)(opt
);
936 const m_option_type_t m_option_type_func
= {
943 NULL
, // Nothing to do on save
949 /////////////////// Print
951 static int parse_print(const m_option_t
*opt
, struct bstr name
,
952 struct bstr param
, bool ambiguous_param
, void *dst
)
954 if (opt
->type
== CONF_TYPE_PRINT_INDIRECT
)
955 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "%s", *(char **) opt
->p
);
956 else if (opt
->type
== CONF_TYPE_PRINT_FUNC
) {
957 char *name0
= bstrdup0(NULL
, name
);
958 char *param0
= bstrdup0(NULL
, param
);
959 int r
= ((m_opt_func_full_t
) opt
->p
)(opt
, name0
, param0
);
964 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "%s", mp_gtext(opt
->p
));
966 if (opt
->priv
== NULL
)
971 const m_option_type_t m_option_type_print
= {
984 const m_option_type_t m_option_type_print_indirect
= {
997 const m_option_type_t m_option_type_print_func
= {
1001 M_OPT_TYPE_ALLOW_WILDCARD
,
1011 /////////////////////// Subconfig
1013 #define VAL(x) (*(char ***)(x))
1015 static int parse_subconf(const m_option_t
*opt
, struct bstr name
,
1016 struct bstr param
, bool ambiguous_param
, void *dst
)
1022 return M_OPT_MISSING_PARAM
;
1024 struct bstr p
= param
;
1025 const struct m_option
*subopts
= opt
->p
;
1028 int optlen
= bstrcspn(p
, ":=");
1029 struct bstr subopt
= bstr_splice(p
, 0, optlen
);
1030 struct bstr subparam
= bstr(NULL
);
1031 p
= bstr_cut(p
, optlen
);
1032 if (bstr_startswith0(p
, "=")) {
1034 if (bstr_startswith0(p
, "\"")) {
1036 optlen
= bstrcspn(p
, "\"");
1037 subparam
= bstr_splice(p
, 0, optlen
);
1038 p
= bstr_cut(p
, optlen
);
1039 if (!bstr_startswith0(p
, "\"")) {
1040 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1041 "Terminating '\"' missing for '%.*s'\n",
1043 return M_OPT_INVALID
;
1046 } else if (bstr_startswith0(p
, "%")) {
1048 optlen
= bstrtoll(p
, &p
, 0);
1049 if (!bstr_startswith0(p
, "%") || (optlen
> p
.len
- 1)) {
1050 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1051 "Invalid length %d for '%.*s'\n",
1052 optlen
, BSTR_P(subopt
));
1053 return M_OPT_INVALID
;
1055 subparam
= bstr_splice(p
, 1, optlen
+ 1);
1056 p
= bstr_cut(p
, optlen
+ 1);
1058 optlen
= bstrcspn(p
, ":");
1059 subparam
= bstr_splice(p
, 0, optlen
);
1060 p
= bstr_cut(p
, optlen
);
1063 if (bstr_startswith0(p
, ":"))
1065 else if (p
.len
> 0) {
1066 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1067 "Incorrect termination for '%.*s'\n", BSTR_P(subopt
));
1068 return M_OPT_INVALID
;
1071 for (i
= 0; subopts
[i
].name
; i
++)
1072 if (!bstrcmp0(subopt
, subopts
[i
].name
))
1074 if (!subopts
[i
].name
) {
1075 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1076 "Option %.*s: Unknown suboption %.*s\n",
1077 BSTR_P(name
), BSTR_P(subopt
));
1078 return M_OPT_UNKNOWN
;
1080 int r
= m_option_parse(&subopts
[i
], subopt
, subparam
, false, NULL
);
1084 lst
= talloc_realloc(NULL
, lst
, char *, 2 * (nr
+ 2));
1085 lst
[2 * nr
] = bstrdup0(NULL
, subopt
);
1086 lst
[2 * nr
+ 1] = subparam
.len
== 0 ? NULL
:
1087 bstrdup0(NULL
, subparam
);
1088 memset(&lst
[2 * (nr
+ 1)], 0, 2 * sizeof(char *));
1099 const m_option_type_t m_option_type_subconfig
= {
1101 "The syntax is -option opt1=foo:flag:opt2=blah",
1103 M_OPT_TYPE_HAS_CHILD
,
1112 #include "libmpcodecs/img_format.h"
1114 /* FIXME: snyc with img_format.h */
1118 } mp_imgfmt_list
[] = {
1119 {"444p16le", IMGFMT_444P16_LE
},
1120 {"444p16be", IMGFMT_444P16_BE
},
1121 {"444p10le", IMGFMT_444P10_LE
},
1122 {"444p10be", IMGFMT_444P10_BE
},
1123 {"444p9le", IMGFMT_444P9_LE
},
1124 {"444p9be", IMGFMT_444P9_BE
},
1125 {"422p16le", IMGFMT_422P16_LE
},
1126 {"422p16be", IMGFMT_422P16_BE
},
1127 {"422p10le", IMGFMT_422P10_LE
},
1128 {"422p10be", IMGFMT_422P10_BE
},
1129 {"420p16le", IMGFMT_420P16_LE
},
1130 {"420p16be", IMGFMT_420P16_BE
},
1131 {"420p10le", IMGFMT_420P10_LE
},
1132 {"420p10be", IMGFMT_420P10_BE
},
1133 {"420p9le", IMGFMT_420P9_LE
},
1134 {"420p9be", IMGFMT_420P9_BE
},
1135 {"444p16", IMGFMT_444P16
},
1136 {"444p10", IMGFMT_444P10
},
1137 {"444p9", IMGFMT_444P9
},
1138 {"422p16", IMGFMT_422P16
},
1139 {"422p10", IMGFMT_422P10
},
1140 {"420p10", IMGFMT_420P10
},
1141 {"420p9", IMGFMT_420P9
},
1142 {"420p16", IMGFMT_420P16
},
1143 {"420a", IMGFMT_420A
},
1144 {"444p", IMGFMT_444P
},
1145 {"422p", IMGFMT_422P
},
1146 {"411p", IMGFMT_411P
},
1147 {"440p", IMGFMT_440P
},
1148 {"yuy2", IMGFMT_YUY2
},
1149 {"yvyu", IMGFMT_YVYU
},
1150 {"uyvy", IMGFMT_UYVY
},
1151 {"yvu9", IMGFMT_YVU9
},
1152 {"if09", IMGFMT_IF09
},
1153 {"yv12", IMGFMT_YV12
},
1154 {"i420", IMGFMT_I420
},
1155 {"iyuv", IMGFMT_IYUV
},
1156 {"clpl", IMGFMT_CLPL
},
1157 {"hm12", IMGFMT_HM12
},
1158 {"y800", IMGFMT_Y800
},
1160 {"nv12", IMGFMT_NV12
},
1161 {"nv21", IMGFMT_NV21
},
1162 {"bgr24", IMGFMT_BGR24
},
1163 {"bgr32", IMGFMT_BGR32
},
1164 {"bgr16", IMGFMT_BGR16
},
1165 {"bgr15", IMGFMT_BGR15
},
1166 {"bgr12", IMGFMT_BGR12
},
1167 {"bgr8", IMGFMT_BGR8
},
1168 {"bgr4", IMGFMT_BGR4
},
1169 {"bg4b", IMGFMT_BG4B
},
1170 {"bgr1", IMGFMT_BGR1
},
1171 {"rgb48be", IMGFMT_RGB48BE
},
1172 {"rgb48le", IMGFMT_RGB48LE
},
1173 {"rgb48ne", IMGFMT_RGB48NE
},
1174 {"rgb24", IMGFMT_RGB24
},
1175 {"rgb32", IMGFMT_RGB32
},
1176 {"rgb16", IMGFMT_RGB16
},
1177 {"rgb15", IMGFMT_RGB15
},
1178 {"rgb12", IMGFMT_RGB12
},
1179 {"rgb8", IMGFMT_RGB8
},
1180 {"rgb4", IMGFMT_RGB4
},
1181 {"rg4b", IMGFMT_RG4B
},
1182 {"rgb1", IMGFMT_RGB1
},
1183 {"rgba", IMGFMT_RGBA
},
1184 {"argb", IMGFMT_ARGB
},
1185 {"bgra", IMGFMT_BGRA
},
1186 {"abgr", IMGFMT_ABGR
},
1187 {"mjpeg", IMGFMT_MJPEG
},
1188 {"mjpg", IMGFMT_MJPEG
},
1192 static int parse_imgfmt(const m_option_t
*opt
, struct bstr name
,
1193 struct bstr param
, bool ambiguous_param
, void *dst
)
1199 return M_OPT_MISSING_PARAM
;
1201 if (!bstrcmp0(param
, "help")) {
1202 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available formats:");
1203 for (i
= 0; mp_imgfmt_list
[i
].name
; i
++)
1204 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, " %s", mp_imgfmt_list
[i
].name
);
1205 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1206 return M_OPT_EXIT
- 1;
1209 if (bstr_startswith0(param
, "0x"))
1210 fmt
= bstrtoll(param
, NULL
, 16);
1212 for (i
= 0; mp_imgfmt_list
[i
].name
; i
++) {
1213 if (!bstrcasecmp0(param
, mp_imgfmt_list
[i
].name
)) {
1214 fmt
= mp_imgfmt_list
[i
].fmt
;
1218 if (!mp_imgfmt_list
[i
].name
) {
1219 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1220 "Option %.*s: unknown format name: '%.*s'\n",
1221 BSTR_P(name
), BSTR_P(param
));
1222 return M_OPT_INVALID
;
1227 *((uint32_t *)dst
) = fmt
;
1232 const m_option_type_t m_option_type_imgfmt
= {
1234 "Please report any missing colorspaces.",
1245 #include "libaf/af_format.h"
1247 /* FIXME: snyc with af_format.h */
1251 } mp_afmt_list
[] = {
1253 {"mulaw", AF_FORMAT_MU_LAW
},
1254 {"alaw", AF_FORMAT_A_LAW
},
1255 {"mpeg2", AF_FORMAT_MPEG2
},
1256 {"ac3le", AF_FORMAT_AC3_LE
},
1257 {"ac3be", AF_FORMAT_AC3_BE
},
1258 {"ac3ne", AF_FORMAT_AC3_NE
},
1259 {"imaadpcm", AF_FORMAT_IMA_ADPCM
},
1261 {"u8", AF_FORMAT_U8
},
1262 {"s8", AF_FORMAT_S8
},
1263 {"u16le", AF_FORMAT_U16_LE
},
1264 {"u16be", AF_FORMAT_U16_BE
},
1265 {"u16ne", AF_FORMAT_U16_NE
},
1266 {"s16le", AF_FORMAT_S16_LE
},
1267 {"s16be", AF_FORMAT_S16_BE
},
1268 {"s16ne", AF_FORMAT_S16_NE
},
1269 {"u24le", AF_FORMAT_U24_LE
},
1270 {"u24be", AF_FORMAT_U24_BE
},
1271 {"u24ne", AF_FORMAT_U24_NE
},
1272 {"s24le", AF_FORMAT_S24_LE
},
1273 {"s24be", AF_FORMAT_S24_BE
},
1274 {"s24ne", AF_FORMAT_S24_NE
},
1275 {"u32le", AF_FORMAT_U32_LE
},
1276 {"u32be", AF_FORMAT_U32_BE
},
1277 {"u32ne", AF_FORMAT_U32_NE
},
1278 {"s32le", AF_FORMAT_S32_LE
},
1279 {"s32be", AF_FORMAT_S32_BE
},
1280 {"s32ne", AF_FORMAT_S32_NE
},
1281 {"floatle", AF_FORMAT_FLOAT_LE
},
1282 {"floatbe", AF_FORMAT_FLOAT_BE
},
1283 {"floatne", AF_FORMAT_FLOAT_NE
},
1287 static int parse_afmt(const m_option_t
*opt
, struct bstr name
,
1288 struct bstr param
, bool ambiguous_param
, void *dst
)
1294 return M_OPT_MISSING_PARAM
;
1296 if (!bstrcmp0(param
, "help")) {
1297 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available formats:");
1298 for (i
= 0; mp_afmt_list
[i
].name
; i
++)
1299 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, " %s", mp_afmt_list
[i
].name
);
1300 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1301 return M_OPT_EXIT
- 1;
1304 if (bstr_startswith0(param
, "0x"))
1305 fmt
= bstrtoll(param
, NULL
, 16);
1307 for (i
= 0; mp_afmt_list
[i
].name
; i
++) {
1308 if (!bstrcasecmp0(param
, mp_afmt_list
[i
].name
)) {
1309 fmt
= mp_afmt_list
[i
].fmt
;
1313 if (!mp_afmt_list
[i
].name
) {
1314 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1315 "Option %.*s: unknown format name: '%.*s'\n",
1316 BSTR_P(name
), BSTR_P(param
));
1317 return M_OPT_INVALID
;
1322 *((uint32_t *)dst
) = fmt
;
1327 const m_option_type_t m_option_type_afmt
= {
1329 "Please report any missing formats.",
1341 static int parse_timestring(struct bstr str
, double *time
, char endchar
)
1345 *time
= 0; /* ensure initialization for error cases */
1346 if (bstr_sscanf(str
, "%d:%d:%lf%n", &a
, &b
, &d
, &len
) >= 3)
1347 *time
= 3600 * a
+ 60 * b
+ d
;
1348 else if (bstr_sscanf(str
, "%d:%lf%n", &a
, &d
, &len
) >= 2)
1350 else if (bstr_sscanf(str
, "%lf%n", &d
, &len
) >= 1)
1353 return 0; /* unsupported time format */
1354 if (len
< str
.len
&& str
.start
[len
] != endchar
)
1355 return 0; /* invalid extra characters at the end */
1360 static int parse_time(const m_option_t
*opt
, struct bstr name
,
1361 struct bstr param
, bool ambiguous_param
, void *dst
)
1366 return M_OPT_MISSING_PARAM
;
1368 if (!parse_timestring(param
, &time
, 0)) {
1369 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: invalid time: '%.*s'\n",
1370 BSTR_P(name
), BSTR_P(param
));
1371 return M_OPT_INVALID
;
1375 *(double *)dst
= time
;
1379 const m_option_type_t m_option_type_time
= {
1393 // Time or size (-endpos)
1395 static int parse_time_size(const m_option_t
*opt
, struct bstr name
,
1396 struct bstr param
, bool ambiguous_param
, void *dst
)
1403 return M_OPT_MISSING_PARAM
;
1406 /* End at size parsing */
1407 if (bstr_sscanf(param
, "%lf%3s", &end_at
, unit
) == 2) {
1408 ts
.type
= END_AT_SIZE
;
1409 if (!strcasecmp(unit
, "b"))
1411 else if (!strcasecmp(unit
, "kb"))
1413 else if (!strcasecmp(unit
, "mb"))
1414 end_at
*= 1024 * 1024;
1415 else if (!strcasecmp(unit
, "gb"))
1416 end_at
*= 1024 * 1024 * 1024;
1418 ts
.type
= END_AT_NONE
;
1420 if (ts
.type
== END_AT_SIZE
) {
1426 /* End at time parsing. This has to be last because the parsing accepts
1427 * even a number followed by garbage */
1428 if (!parse_timestring(param
, &end_at
, 0)) {
1429 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1430 "Option %.*s: invalid time or size: '%.*s'\n",
1431 BSTR_P(name
), BSTR_P(param
));
1432 return M_OPT_INVALID
;
1435 ts
.type
= END_AT_TIME
;
1439 *(m_time_size_t
*)dst
= ts
;
1443 const m_option_type_t m_option_type_time_size
= {
1446 sizeof(m_time_size_t
),
1457 //// Objects (i.e. filters, etc) settings
1459 #include "m_struct.h"
1462 #define VAL(x) (*(m_obj_settings_t **)(x))
1464 static int find_obj_desc(struct bstr name
, const m_obj_list_t
*l
,
1465 const m_struct_t
**ret
)
1470 for (i
= 0; l
->list
[i
]; i
++) {
1471 n
= M_ST_MB(char *, l
->list
[i
], l
->name_off
);
1472 if (!bstrcmp0(name
, n
)) {
1473 *ret
= M_ST_MB(m_struct_t
*, l
->list
[i
], l
->desc_off
);
1480 static int get_obj_param(struct bstr opt_name
, struct bstr obj_name
,
1481 const m_struct_t
*desc
, struct bstr str
, int *nold
,
1482 int oldmax
, char **dst
)
1484 const m_option_t
*opt
;
1487 int eq
= bstrchr(str
, '=');
1489 if (eq
> 0) { // eq == 0 ignored
1490 struct bstr p
= bstr_cut(str
, eq
+ 1);
1491 str
= bstr_splice(str
, 0, eq
);
1492 opt
= m_option_list_findb(desc
->fields
, str
);
1494 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1495 "Option %.*s: %.*s doesn't have a %.*s parameter.\n",
1496 BSTR_P(opt_name
), BSTR_P(obj_name
), BSTR_P(str
));
1497 return M_OPT_UNKNOWN
;
1499 r
= m_option_parse(opt
, str
, p
, false, NULL
);
1502 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: "
1503 "Error while parsing %.*s parameter %.*s (%.*s)\n",
1504 BSTR_P(opt_name
), BSTR_P(obj_name
), BSTR_P(str
),
1509 dst
[0] = bstrdup0(NULL
, str
);
1510 dst
[1] = bstrdup0(NULL
, p
);
1513 if ((*nold
) >= oldmax
) {
1514 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: %.*s has only %d params, so you can't give more than %d unnamed params.\n",
1515 BSTR_P(opt_name
), BSTR_P(obj_name
), oldmax
, oldmax
);
1516 return M_OPT_OUT_OF_RANGE
;
1518 opt
= &desc
->fields
[(*nold
)];
1519 r
= m_option_parse(opt
, bstr(opt
->name
), str
, false, NULL
);
1522 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: "
1523 "Error while parsing %.*s parameter %s (%.*s)\n",
1524 BSTR_P(opt_name
), BSTR_P(obj_name
), opt
->name
,
1529 dst
[0] = talloc_strdup(NULL
, opt
->name
);
1530 dst
[1] = bstrdup0(NULL
, str
);
1537 static int get_obj_params(struct bstr opt_name
, struct bstr name
,
1538 struct bstr params
, const m_struct_t
*desc
,
1539 char separator
, char ***_ret
)
1541 int n
= 0, nold
= 0, nopts
;
1544 if (!bstrcmp0(params
, "help")) { // Help
1545 char min
[50], max
[50];
1546 if (!desc
->fields
) {
1547 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1548 "%.*s doesn't have any options.\n\n", BSTR_P(name
));
1549 return M_OPT_EXIT
- 1;
1551 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1552 "\n Name Type Min Max\n\n");
1553 for (n
= 0; desc
->fields
[n
].name
; n
++) {
1554 const m_option_t
*opt
= &desc
->fields
[n
];
1555 if (opt
->type
->flags
& M_OPT_TYPE_HAS_CHILD
)
1557 if (opt
->flags
& M_OPT_MIN
)
1558 sprintf(min
, "%-8.0f", opt
->min
);
1561 if (opt
->flags
& M_OPT_MAX
)
1562 sprintf(max
, "%-8.0f", opt
->max
);
1565 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1566 " %-20.20s %-15.15s %-10.10s %-10.10s\n",
1567 opt
->name
, opt
->type
->name
, min
, max
);
1569 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1570 return M_OPT_EXIT
- 1;
1573 for (nopts
= 0; desc
->fields
[nopts
].name
; nopts
++)
1576 // TODO : Check that each opt can be parsed
1577 struct bstr s
= params
;
1580 int idx
= bstrchr(s
, separator
);
1585 struct bstr field
= bstr_splice(s
, 0, idx
);
1586 s
= bstr_cut(s
, idx
+ 1);
1587 if (field
.len
== 0) { // Empty field, count it and go on
1590 int r
= get_obj_param(opt_name
, name
, desc
, field
, &nold
, nopts
,
1600 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Too many options for %.*s\n",
1602 return M_OPT_OUT_OF_RANGE
;
1604 if (!_ret
) // Just test
1606 if (n
== 0) // No options or only empty options
1609 ret
= talloc_array(NULL
, char *, (n
+ 2) * 2);
1614 int idx
= bstrchr(s
, separator
);
1617 struct bstr field
= bstr_splice(s
, 0, idx
);
1618 s
= bstr_cut(s
, idx
+ 1);
1619 if (field
.len
== 0) { // Empty field, count it and go on
1622 get_obj_param(opt_name
, name
, desc
, field
, &nold
, nopts
,
1627 ret
[n
* 2] = ret
[n
* 2 + 1] = NULL
;
1633 static int parse_obj_params(const m_option_t
*opt
, struct bstr name
,
1634 struct bstr param
, bool ambiguous_param
, void *dst
)
1638 m_obj_params_t
*p
= opt
->priv
;
1639 const m_struct_t
*desc
;
1641 // We need the object desc
1643 return M_OPT_INVALID
;
1646 r
= get_obj_params(name
, bstr(desc
->name
), param
, desc
, p
->separator
,
1647 dst
? &opts
: NULL
);
1652 if (!opts
) // no arguments given
1655 for (r
= 0; opts
[r
]; r
+= 2)
1656 m_struct_set(desc
, dst
, opts
[r
], bstr(opts
[r
+ 1]));
1662 const m_option_type_t m_option_type_obj_params
= {
1675 /// Some predefined types as a definition would be quite lengthy
1678 static const m_span_t m_span_params_dflts
= {
1681 static const m_option_t m_span_params_fields
[] = {
1682 {"start", M_ST_OFF(m_span_t
, start
), CONF_TYPE_INT
, M_OPT_MIN
, 1, 0, NULL
},
1683 {"end", M_ST_OFF(m_span_t
, end
), CONF_TYPE_INT
, M_OPT_MIN
, 1, 0, NULL
},
1684 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
1686 static const struct m_struct_st m_span_opts
= {
1689 &m_span_params_dflts
,
1690 m_span_params_fields
1692 const m_obj_params_t m_span_params_def
= {
1697 static int parse_obj_settings(struct bstr opt
, struct bstr str
,
1698 const m_obj_list_t
*list
,
1699 m_obj_settings_t
**_ret
, int ret_n
)
1702 char **plist
= NULL
;
1703 const m_struct_t
*desc
;
1704 m_obj_settings_t
*ret
= _ret
? *_ret
: NULL
;
1706 struct bstr param
= bstr(NULL
);
1707 int idx
= bstrchr(str
, '=');
1709 param
= bstr_cut(str
, idx
+ 1);
1710 str
= bstr_splice(str
, 0, idx
);
1713 if (!find_obj_desc(str
, list
, &desc
)) {
1714 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: %.*s doesn't exist.\n",
1715 BSTR_P(opt
), BSTR_P(str
));
1716 return M_OPT_INVALID
;
1720 if (!desc
&& _ret
) {
1721 if (!bstrcmp0(param
, "help")) {
1722 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
,
1723 "Option %.*s: %.*s have no option description.\n",
1724 BSTR_P(opt
), BSTR_P(str
));
1725 return M_OPT_EXIT
- 1;
1727 plist
= talloc_zero_array(NULL
, char *, 4);
1728 plist
[0] = talloc_strdup(NULL
, "_oldargs_");
1729 plist
[1] = bstrdup0(NULL
, param
);
1731 r
= get_obj_params(opt
, str
, param
, desc
, ':',
1732 _ret
? &plist
: NULL
);
1740 ret
= talloc_realloc(NULL
, ret
, struct m_obj_settings
, ret_n
+ 2);
1741 memset(&ret
[ret_n
], 0, 2 * sizeof(m_obj_settings_t
));
1742 ret
[ret_n
].name
= bstrdup0(NULL
, str
);
1743 ret
[ret_n
].attribs
= plist
;
1749 static int obj_settings_list_del(struct bstr opt_name
, struct bstr param
,
1750 bool ambiguous_param
, void *dst
)
1752 char **str_list
= NULL
;
1753 int r
, i
, idx_max
= 0;
1754 char *rem_id
= "_removed_marker_";
1756 assert(opt_name
.len
< 100);
1757 memcpy(name
, opt_name
.start
, opt_name
.len
);
1758 name
[opt_name
.len
] = 0;
1759 const m_option_t list_opt
= {
1760 name
, NULL
, CONF_TYPE_STRING_LIST
,
1763 m_obj_settings_t
*obj_list
= dst
? VAL(dst
) : NULL
;
1765 if (dst
&& !obj_list
) {
1766 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
, "Option %.*s: the list is empty.\n",
1769 } else if (obj_list
) {
1770 for (idx_max
= 0; obj_list
[idx_max
].name
!= NULL
; idx_max
++)
1774 r
= m_option_parse(&list_opt
, opt_name
, param
, false, &str_list
);
1775 if (r
< 0 || !str_list
)
1778 for (r
= 0; str_list
[r
]; r
++) {
1781 id
= strtol(str_list
[r
], &endptr
, 0);
1782 if (endptr
== str_list
[r
]) {
1783 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
));
1784 m_option_free(&list_opt
, &str_list
);
1785 return M_OPT_INVALID
;
1789 if (id
>= idx_max
|| id
< -idx_max
) {
1790 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
1791 "Option %.*s: Index %d is out of range.\n",
1792 BSTR_P(opt_name
), id
);
1797 talloc_free(obj_list
[id
].name
);
1798 free_str_list(&(obj_list
[id
].attribs
));
1799 obj_list
[id
].name
= rem_id
;
1803 m_option_free(&list_opt
, &str_list
);
1807 for (i
= 0; obj_list
[i
].name
; i
++) {
1808 while (obj_list
[i
].name
== rem_id
) {
1809 memmove(&obj_list
[i
], &obj_list
[i
+ 1],
1810 sizeof(m_obj_settings_t
) * (idx_max
- i
));
1814 obj_list
= talloc_realloc(NULL
, obj_list
, struct m_obj_settings
,
1816 VAL(dst
) = obj_list
;
1821 static void free_obj_settings_list(void *dst
)
1824 m_obj_settings_t
*d
;
1826 if (!dst
|| !VAL(dst
))
1830 for (n
= 0; d
[n
].name
; n
++) {
1831 talloc_free(d
[n
].name
);
1832 free_str_list(&(d
[n
].attribs
));
1838 static int parse_obj_settings_list(const m_option_t
*opt
, struct bstr name
,
1839 struct bstr param
, bool ambiguous_param
,
1842 int len
= strlen(opt
->name
);
1843 m_obj_settings_t
*res
= NULL
, *queue
= NULL
, *head
= NULL
;
1846 // We need the objects list
1848 return M_OPT_INVALID
;
1850 if (opt
->name
[len
- 1] == '*' && (name
.len
> len
- 1)) {
1851 struct bstr suffix
= bstr_cut(name
, len
- 1);
1852 if (bstrcasecmp0(suffix
, "-add") == 0)
1854 else if (bstrcasecmp0(suffix
, "-pre") == 0)
1856 else if (bstrcasecmp0(suffix
, "-del") == 0)
1858 else if (bstrcasecmp0(suffix
, "-clr") == 0)
1862 strncpy(prefix
, opt
->name
, len
- 1);
1863 prefix
[len
- 1] = '\0';
1864 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
1865 "Option %.*s: unknown postfix %.*s\n"
1866 "Supported postfixes are:\n"
1868 " Append the given list to the current list\n\n"
1870 " Prepend the given list to the current list\n\n"
1872 " Remove the given elements. Take the list element index (starting from 0).\n"
1873 " Negative index can be used (i.e. -1 is the last element)\n\n"
1875 " Clear the current list.\n",
1876 BSTR_P(name
), BSTR_P(suffix
), prefix
, prefix
, prefix
, prefix
);
1878 return M_OPT_UNKNOWN
;
1882 // Clear the list ??
1885 free_obj_settings_list(dst
);
1890 return M_OPT_MISSING_PARAM
;
1902 return obj_settings_list_del(name
, param
, false, dst
);
1904 if (dst
&& VAL(dst
))
1905 free_obj_settings_list(dst
);
1908 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: FIXME\n", BSTR_P(name
));
1909 return M_OPT_UNKNOWN
;
1912 if (!bstrcmp0(param
, "help")) {
1913 m_obj_list_t
*ol
= opt
->priv
;
1914 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available video filters:\n");
1915 for (int n
= 0; ol
->list
[n
]; n
++)
1916 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, " %-15s: %s\n",
1917 M_ST_MB(char *, ol
->list
[n
], ol
->name_off
),
1918 M_ST_MB(char *, ol
->list
[n
], ol
->info_off
));
1919 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "\n");
1920 return M_OPT_EXIT
- 1;
1923 struct bstr s
= bstrdup(NULL
, param
);
1924 char *allocptr
= s
.start
;
1927 struct bstr el
= get_nextsep(&s
, OPTION_LIST_SEPARATOR
, 1);
1928 int r
= parse_obj_settings(name
, el
, opt
->priv
, dst
? &res
: NULL
, n
);
1930 talloc_free(allocptr
);
1936 talloc_free(allocptr
);
1938 return M_OPT_INVALID
;
1940 if (((opt
->flags
& M_OPT_MIN
) && (n
< opt
->min
)) ||
1941 ((opt
->flags
& M_OPT_MAX
) && (n
> opt
->max
)))
1942 return M_OPT_OUT_OF_RANGE
;
1947 for (qsize
= 0; queue
[qsize
].name
; qsize
++)
1949 res
= talloc_realloc(NULL
, res
, struct m_obj_settings
,
1951 memcpy(&res
[n
], queue
, (qsize
+ 1) * sizeof(m_obj_settings_t
));
1957 for (hsize
= 0; head
[hsize
].name
; hsize
++)
1959 head
= talloc_realloc(NULL
, head
, struct m_obj_settings
,
1961 memcpy(&head
[hsize
], res
, (n
+ 1) * sizeof(m_obj_settings_t
));
1970 static void copy_obj_settings_list(const m_option_t
*opt
, void *dst
,
1973 m_obj_settings_t
*d
, *s
;
1982 free_obj_settings_list(dst
);
1988 for (n
= 0; s
[n
].name
; n
++)
1990 d
= talloc_array(NULL
, struct m_obj_settings
, n
+ 1);
1991 for (n
= 0; s
[n
].name
; n
++) {
1992 d
[n
].name
= talloc_strdup(NULL
, s
[n
].name
);
1993 d
[n
].attribs
= NULL
;
1994 copy_str_list(NULL
, &(d
[n
].attribs
), &(s
[n
].attribs
));
1997 d
[n
].attribs
= NULL
;
2001 const m_option_type_t m_option_type_obj_settings_list
= {
2002 "Object settings list",
2004 sizeof(m_obj_settings_t
*),
2005 M_OPT_TYPE_DYNAMIC
| M_OPT_TYPE_ALLOW_WILDCARD
,
2006 parse_obj_settings_list
,
2008 copy_obj_settings_list
,
2009 copy_obj_settings_list
,
2010 copy_obj_settings_list
,
2011 free_obj_settings_list
,
2016 static int parse_obj_presets(const m_option_t
*opt
, struct bstr name
,
2017 struct bstr param
, bool ambiguous_param
,
2020 m_obj_presets_t
*obj_p
= (m_obj_presets_t
*)opt
->priv
;
2021 const m_struct_t
*in_desc
;
2022 const m_struct_t
*out_desc
;
2024 const unsigned char *pre
;
2025 char *pre_name
= NULL
;
2028 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: Presets need a "
2029 "pointer to a m_obj_presets_t in the priv field.\n",
2031 return M_OPT_PARSER_ERR
;
2035 return M_OPT_MISSING_PARAM
;
2037 pre
= obj_p
->presets
;
2038 in_desc
= obj_p
->in_desc
;
2039 out_desc
= obj_p
->out_desc
? obj_p
->out_desc
: obj_p
->in_desc
;
2042 if (!bstrcmp0(param
, "help")) {
2043 mp_msg(MSGT_CFGPARSER
, MSGL_INFO
, "Available presets for %s->%.*s:",
2044 out_desc
->name
, BSTR_P(name
));
2045 for (pre
= obj_p
->presets
;
2046 (pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
)); pre
+= s
)
2047 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, " %s", pre_name
);
2048 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "\n");
2049 return M_OPT_EXIT
- 1;
2052 for (pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
); pre_name
;
2053 pre
+= s
, pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
))
2054 if (!bstrcmp0(param
, pre_name
))
2057 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2058 "Option %.*s: There is no preset named %.*s\n"
2059 "Available presets are:", BSTR_P(name
), BSTR_P(param
));
2060 for (pre
= obj_p
->presets
;
2061 (pre_name
= M_ST_MB(char *, pre
, obj_p
->name_off
)); pre
+= s
)
2062 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, " %s", pre_name
);
2063 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "\n");
2064 return M_OPT_INVALID
;
2070 for (i
= 0; in_desc
->fields
[i
].name
; i
++) {
2071 const m_option_t
*out_opt
= m_option_list_find(out_desc
->fields
,
2072 in_desc
->fields
[i
].name
);
2074 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2075 "Option %.*s: Unable to find the target option for field %s.\n"
2076 "Please report this to the developers.\n",
2077 BSTR_P(name
), in_desc
->fields
[i
].name
);
2078 return M_OPT_PARSER_ERR
;
2080 m_option_copy(out_opt
, M_ST_MB_P(dst
, out_opt
->p
),
2081 M_ST_MB_P(pre
, in_desc
->fields
[i
].p
));
2087 const m_option_type_t m_option_type_obj_presets
= {
2100 static int parse_custom_url(const m_option_t
*opt
, struct bstr name
,
2101 struct bstr url
, bool ambiguous_param
, void *dst
)
2104 m_struct_t
*desc
= opt
->priv
;
2107 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Option %.*s: Custom URL needs "
2108 "a pointer to a m_struct_t in the priv field.\n", BSTR_P(name
));
2109 return M_OPT_PARSER_ERR
;
2112 // extract the protocol
2113 int idx
= bstr_find0(url
, "://");
2116 if (m_option_list_find(desc
->fields
, "filename")) {
2117 m_struct_set(desc
, dst
, "filename", url
);
2120 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2121 "Option %.*s: URL doesn't have a valid protocol!\n",
2123 return M_OPT_INVALID
;
2125 struct bstr ptr1
= bstr_cut(url
, idx
+ 3);
2126 if (m_option_list_find(desc
->fields
, "string")) {
2128 m_struct_set(desc
, dst
, "string", ptr1
);
2132 if (dst
&& m_option_list_find(desc
->fields
, "protocol")) {
2133 r
= m_struct_set(desc
, dst
, "protocol", bstr_splice(url
, 0, idx
));
2135 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2136 "Option %.*s: Error while setting protocol.\n",
2142 // check if a username:password is given
2143 idx
= bstrchr(ptr1
, '/');
2146 struct bstr hostpart
= bstr_splice(ptr1
, 0, idx
);
2147 struct bstr path
= bstr_cut(ptr1
, idx
);
2148 idx
= bstrchr(hostpart
, '@');
2150 // We got something, at least a username...
2151 if (!m_option_list_find(desc
->fields
, "username")) {
2152 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
2153 "Option %.*s: This URL doesn't have a username part.\n",
2157 struct bstr userpass
= bstr_splice(hostpart
, 0, idx
);
2158 idx
= bstrchr(userpass
, ':');
2160 // We also have a password
2161 if (!m_option_list_find(desc
->fields
, "password")) {
2162 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
2163 "Option %.*s: This URL doesn't have a password part.\n",
2166 } else { // Username and password
2168 r
= m_struct_set(desc
, dst
, "username",
2169 bstr_splice(userpass
, 0, idx
));
2171 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2172 "Option %.*s: Error while setting username.\n",
2176 r
= m_struct_set(desc
, dst
, "password",
2177 bstr_splice(userpass
, idx
+1,
2180 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2181 "Option %.*s: Error while setting password.\n",
2187 } else { // User name only
2188 r
= m_struct_set(desc
, dst
, "username", userpass
);
2190 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2191 "Option %.*s: Error while setting username.\n",
2197 hostpart
= bstr_cut(hostpart
, idx
+ 1);
2200 // Before looking for a port number check if we have an IPv6 type
2202 // In an IPv6 URL the numeric address should be inside square braces.
2203 int idx1
= bstrchr(hostpart
, '[');
2204 int idx2
= bstrchr(hostpart
, ']');
2205 struct bstr portstr
= hostpart
;
2206 bool v6addr
= false;
2207 if (idx1
>= 0 && idx2
>= 0 && idx1
< idx2
) {
2208 // we have an IPv6 numeric address
2209 portstr
= bstr_cut(hostpart
, idx2
);
2210 hostpart
= bstr_splice(hostpart
, idx1
+ 1, idx2
);
2214 idx
= bstrchr(portstr
, ':');
2217 hostpart
= bstr_splice(hostpart
, 0, idx
);
2218 // We have an URL beginning like http://www.hostname.com:1212
2219 // Get the port number
2220 if (!m_option_list_find(desc
->fields
, "port")) {
2221 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
2222 "Option %.*s: This URL doesn't have a port part.\n",
2227 int p
= bstrtoll(bstr_cut(portstr
, idx
+ 1), NULL
, 0);
2229 snprintf(tmp
, 99, "%d", p
);
2230 r
= m_struct_set(desc
, dst
, "port", bstr(tmp
));
2232 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2233 "Option %.*s: Error while setting port.\n",
2241 if (hostpart
.len
> 0) {
2242 if (!m_option_list_find(desc
->fields
, "hostname")) {
2243 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
2244 "Option %.*s: This URL doesn't have a hostname part.\n",
2248 r
= m_struct_set(desc
, dst
, "hostname", hostpart
);
2250 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2251 "Option %.*s: Error while setting hostname.\n",
2257 // Look if a path is given
2258 if (path
.len
> 1) { // not just "/"
2259 // copy the path/filename in the URL container
2260 if (!m_option_list_find(desc
->fields
, "filename")) {
2261 mp_msg(MSGT_CFGPARSER
, MSGL_WARN
,
2262 "Option %.*s: This URL doesn't have a filename part.\n",
2267 char *fname
= bstrdup0(NULL
, bstr_cut(path
, 1));
2268 url_unescape_string(fname
, fname
);
2269 r
= m_struct_set(desc
, dst
, "filename", bstr(fname
));
2272 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,
2273 "Option %.*s: Error while setting filename.\n",
2283 /// TODO : Write the other needed funcs for 'normal' options
2284 const m_option_type_t m_option_type_custom_url
= {