vf_qp: enable compilation depending on libavutil eval API
[mplayer.git] / m_option.c
blob17d039f23bcddcacab17a0a3f43f0795335e4e28
1 /*
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.
19 /// \file
20 /// \ingroup Options
22 #include "config.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <math.h>
27 #include <stdio.h>
28 #include <stdarg.h>
29 #include <inttypes.h>
30 #include <unistd.h>
32 #include "talloc.h"
33 #include "m_option.h"
34 #include "mp_msg.h"
35 #include "stream/url.h"
36 #include "libavutil/avstring.h"
38 const m_option_t *m_option_list_find(const m_option_t *list, const char *name)
40 int i;
42 for (i = 0; list[i].name; i++) {
43 int l = strlen(list[i].name) - 1;
44 if ((list[i].type->flags & M_OPT_TYPE_ALLOW_WILDCARD)
45 && (l > 0) && (list[i].name[l] == '*')) {
46 if (strncasecmp(list[i].name, name, l) == 0)
47 return &list[i];
48 } else if (strcasecmp(list[i].name, name) == 0)
49 return &list[i];
51 return NULL;
54 // Default function that just does a memcpy
56 static void copy_opt(const m_option_t *opt, void *dst, const void *src)
58 if (dst && src)
59 memcpy(dst, src, opt->type->size);
62 // Flag
64 #define VAL(x) (*(int *)(x))
66 static int parse_flag(const m_option_t *opt, const char *name,
67 const char *param, void *dst, int src)
69 if (src == M_CONFIG_FILE) {
70 if (!param)
71 return M_OPT_MISSING_PARAM;
72 if (!strcasecmp(param, "yes") || /* any other language? */
73 !strcasecmp(param, "on") ||
74 !strcasecmp(param, "ja") ||
75 !strcasecmp(param, "si") ||
76 !strcasecmp(param, "igen") ||
77 !strcasecmp(param, "y") ||
78 !strcasecmp(param, "j") ||
79 !strcasecmp(param, "i") ||
80 !strcasecmp(param, "tak") ||
81 !strcasecmp(param, "ja") ||
82 !strcasecmp(param, "true") ||
83 !strcmp(param, "1")) {
84 if (dst)
85 VAL(dst) = opt->max;
86 } else if (!strcasecmp(param, "no") ||
87 !strcasecmp(param, "off") ||
88 !strcasecmp(param, "nein") ||
89 !strcasecmp(param, "nicht") ||
90 !strcasecmp(param, "nem") ||
91 !strcasecmp(param, "n") ||
92 !strcasecmp(param, "nie") ||
93 !strcasecmp(param, "nej") ||
94 !strcasecmp(param, "false") ||
95 !strcmp(param, "0")) {
96 if (dst)
97 VAL(dst) = opt->min;
98 } else {
99 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
100 "Invalid parameter for %s flag: %s\n", name, param);
101 return M_OPT_INVALID;
103 return 1;
104 } else {
105 if (dst)
106 VAL(dst) = opt->max;
107 return 0;
111 static char *print_flag(const m_option_t *opt, const void *val)
113 if (VAL(val) == opt->min)
114 return talloc_strdup(NULL, "no");
115 else
116 return talloc_strdup(NULL, "yes");
119 const m_option_type_t m_option_type_flag = {
120 "Flag",
121 "need yes or no in config files",
122 sizeof(int),
124 parse_flag,
125 print_flag,
126 copy_opt,
127 copy_opt,
128 NULL,
129 NULL
132 // Integer
134 static int parse_int(const m_option_t *opt, const char *name,
135 const char *param, void *dst, int src)
137 long long tmp_int;
138 char *endptr;
139 src = 0;
141 if (param == NULL)
142 return M_OPT_MISSING_PARAM;
144 tmp_int = strtoll(param, &endptr, 10);
145 if (*endptr)
146 tmp_int = strtoll(param, &endptr, 0);
147 if (*endptr) {
148 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
149 "The %s option must be an integer: %s\n", name, param);
150 return M_OPT_INVALID;
153 if ((opt->flags & M_OPT_MIN) && (tmp_int < opt->min)) {
154 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
155 "The %s option must be >= %d: %s\n",
156 name, (int) opt->min, param);
157 return M_OPT_OUT_OF_RANGE;
160 if ((opt->flags & M_OPT_MAX) && (tmp_int > opt->max)) {
161 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
162 "The %s option must be <= %d: %s\n",
163 name, (int) opt->max, param);
164 return M_OPT_OUT_OF_RANGE;
167 if (dst) {
168 if (opt->type->size == sizeof(int64_t))
169 *(int64_t *)dst = tmp_int;
170 else
171 VAL(dst) = tmp_int;
174 return 1;
177 static char *print_int(const m_option_t *opt, const void *val)
179 if (opt->type->size == sizeof(int64_t))
180 return talloc_asprintf(NULL, "%"PRId64, *(const int64_t *)val);
181 return talloc_asprintf(NULL, "%d", VAL(val));
184 const m_option_type_t m_option_type_int = {
185 "Integer",
187 sizeof(int),
189 parse_int,
190 print_int,
191 copy_opt,
192 copy_opt,
193 NULL,
194 NULL
197 const m_option_type_t m_option_type_int64 = {
198 "Integer64",
200 sizeof(int64_t),
202 parse_int,
203 print_int,
204 copy_opt,
205 copy_opt,
206 NULL,
207 NULL
210 static int parse_intpair(const struct m_option *opt, const char *name,
211 const char *param, void *dst, int src)
213 if (param == NULL)
214 return M_OPT_MISSING_PARAM;
216 char *s = (char *)param;
217 int start = -1;
218 int end = -1;
219 if (*s) {
220 start = strtol(s, &s, 10);
221 if (s == param)
222 goto bad;
224 if (*s) {
225 if (*s != '-')
226 goto bad;
227 s++;
229 if (*s)
230 end = strtol(s, &s, 10);
231 if (*s)
232 goto bad;
234 if (dst) {
235 int *p = dst;
236 p[0] = start;
237 p[1] = end;
240 return 1;
242 bad:
243 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid integer range "
244 "specification for option %s: %s\n", name, param);
245 return M_OPT_INVALID;
248 const struct m_option_type m_option_type_intpair = {
249 .name = "Int[-Int]",
250 .size = sizeof(int[2]),
251 .parse = parse_intpair,
252 .save = copy_opt,
253 .set = copy_opt,
256 static int parse_choice(const struct m_option *opt, const char *name,
257 const char *param, void *dst, int src)
259 if (param == NULL)
260 return M_OPT_MISSING_PARAM;
262 struct m_opt_choice_alternatives *alt;
263 for (alt = opt->priv; alt->name; alt++)
264 if (!strcmp(param, alt->name))
265 break;
266 if (!alt->name) {
267 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid value for option %s: %s\n",
268 name, param);
269 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Valid values are:");
270 for (alt = opt->priv; alt->name; alt++)
271 mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %s", alt->name);
272 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "\n");
273 return M_OPT_INVALID;
275 if (dst)
276 *(int *)dst = alt->value;
278 return 1;
281 static char *print_choice(const m_option_t *opt, const void *val)
283 int v = *(int *)val;
284 struct m_opt_choice_alternatives *alt;
285 for (alt = opt->priv; alt->name; alt++)
286 if (alt->value == v)
287 return talloc_strdup(NULL, alt->name);
288 abort();
291 const struct m_option_type m_option_type_choice = {
292 .name = "String", // same as arbitrary strings in option list for now
293 .size = sizeof(int),
294 .parse = parse_choice,
295 .print = print_choice,
296 .save = copy_opt,
297 .set = copy_opt,
300 // Float
302 #undef VAL
303 #define VAL(x) (*(double *)(x))
305 static int parse_double(const m_option_t *opt, const char *name,
306 const char *param, void *dst, int src)
308 double tmp_float;
309 char *endptr;
310 src = 0;
312 if (param == NULL)
313 return M_OPT_MISSING_PARAM;
315 tmp_float = strtod(param, &endptr);
317 switch (*endptr) {
318 case ':':
319 case '/':
320 tmp_float /= strtod(endptr + 1, &endptr);
321 break;
322 case '.':
323 case ',':
324 /* we also handle floats specified with
325 * non-locale decimal point ::atmos
327 if (tmp_float < 0)
328 tmp_float -= 1.0 / pow(10, strlen(endptr + 1)) *
329 strtod(endptr + 1, &endptr);
330 else
331 tmp_float += 1.0 / pow(10, strlen(endptr + 1)) *
332 strtod(endptr + 1, &endptr);
333 break;
336 if (*endptr) {
337 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
338 "The %s option must be a floating point number or a "
339 "ratio (numerator[:/]denominator): %s\n", name, param);
340 return M_OPT_INVALID;
343 if (opt->flags & M_OPT_MIN)
344 if (tmp_float < opt->min) {
345 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
346 "The %s option must be >= %f: %s\n", name, opt->min, param);
347 return M_OPT_OUT_OF_RANGE;
350 if (opt->flags & M_OPT_MAX)
351 if (tmp_float > opt->max) {
352 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
353 "The %s option must be <= %f: %s\n", name, opt->max, param);
354 return M_OPT_OUT_OF_RANGE;
357 if (dst)
358 VAL(dst) = tmp_float;
359 return 1;
362 static char *print_double(const m_option_t *opt, const void *val)
364 opt = NULL;
365 return talloc_asprintf(NULL, "%f", VAL(val));
368 const m_option_type_t m_option_type_double = {
369 "Double",
370 "double precision floating point number or ratio (numerator[:/]denominator)",
371 sizeof(double),
373 parse_double,
374 print_double,
375 copy_opt,
376 copy_opt,
377 NULL,
378 NULL
381 #undef VAL
382 #define VAL(x) (*(float *)(x))
384 static int parse_float(const m_option_t *opt, const char *name,
385 const char *param, void *dst, int src)
387 double tmp;
388 int r = parse_double(opt, name, param, &tmp, src);
389 if (r == 1 && dst)
390 VAL(dst) = tmp;
391 return r;
394 static char *print_float(const m_option_t *opt, const void *val)
396 opt = NULL;
397 return talloc_asprintf(NULL, "%f", VAL(val));
400 const m_option_type_t m_option_type_float = {
401 "Float",
402 "floating point number or ratio (numerator[:/]denominator)",
403 sizeof(float),
405 parse_float,
406 print_float,
407 copy_opt,
408 copy_opt,
409 NULL,
410 NULL
413 ///////////// Position
414 #undef VAL
415 #define VAL(x) (*(off_t *)(x))
417 static int parse_position(const m_option_t *opt, const char *name,
418 const char *param, void *dst, int src)
420 off_t tmp_off;
421 char dummy;
423 if (param == NULL)
424 return M_OPT_MISSING_PARAM;
425 if (sscanf(param, sizeof(off_t) == sizeof(int) ?
426 "%d%c" : "%"PRId64"%c", &tmp_off, &dummy) != 1) {
427 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
428 "The %s option must be an integer: %s\n", opt->name, param);
429 return M_OPT_INVALID;
432 if (opt->flags & M_OPT_MIN)
433 if (tmp_off < opt->min) {
434 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
435 "The %s option must be >= %"PRId64 ": %s\n",
436 name, (int64_t) opt->min, param);
437 return M_OPT_OUT_OF_RANGE;
440 if (opt->flags & M_OPT_MAX)
441 if (tmp_off > opt->max) {
442 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
443 "The %s option must be <= %"PRId64 ": %s\n",
444 name, (int64_t) opt->max, param);
445 return M_OPT_OUT_OF_RANGE;
448 if (dst)
449 VAL(dst) = tmp_off;
450 return 1;
453 static char *print_position(const m_option_t *opt, const void *val)
455 return talloc_asprintf(NULL, "%"PRId64, (int64_t)VAL(val));
458 const m_option_type_t m_option_type_position = {
459 "Position",
460 "Integer (off_t)",
461 sizeof(off_t),
463 parse_position,
464 print_position,
465 copy_opt,
466 copy_opt,
467 NULL,
468 NULL
472 ///////////// String
474 #undef VAL
475 #define VAL(x) (*(char **)(x))
477 static int parse_str(const m_option_t *opt, const char *name,
478 const char *param, void *dst, int src)
482 if (param == NULL)
483 return M_OPT_MISSING_PARAM;
485 if ((opt->flags & M_OPT_MIN) && (strlen(param) < opt->min)) {
486 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Parameter must be >= %d chars: %s\n",
487 (int) opt->min, param);
488 return M_OPT_OUT_OF_RANGE;
491 if ((opt->flags & M_OPT_MAX) && (strlen(param) > opt->max)) {
492 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Parameter must be <= %d chars: %s\n",
493 (int) opt->max, param);
494 return M_OPT_OUT_OF_RANGE;
497 if (dst) {
498 talloc_free(VAL(dst));
499 VAL(dst) = talloc_strdup(NULL, param);
502 return 1;
506 static char *print_str(const m_option_t *opt, const void *val)
508 return (val && VAL(val)) ? talloc_strdup(NULL, VAL(val)) : NULL;
511 static void copy_str(const m_option_t *opt, void *dst, const void *src)
513 if (dst && src) {
514 talloc_free(VAL(dst));
515 VAL(dst) = talloc_strdup(NULL, VAL(src));
519 static void free_str(void *src)
521 if (src && VAL(src)) {
522 talloc_free(VAL(src));
523 VAL(src) = NULL;
527 const m_option_type_t m_option_type_string = {
528 "String",
530 sizeof(char *),
531 M_OPT_TYPE_DYNAMIC,
532 parse_str,
533 print_str,
534 copy_str,
535 copy_str,
536 copy_str,
537 free_str
540 //////////// String list
542 #undef VAL
543 #define VAL(x) (*(char ***)(x))
545 #define OP_NONE 0
546 #define OP_ADD 1
547 #define OP_PRE 2
548 #define OP_DEL 3
549 #define OP_CLR 4
551 static void free_str_list(void *dst)
553 char **d;
554 int i;
556 if (!dst || !VAL(dst))
557 return;
558 d = VAL(dst);
560 for (i = 0; d[i] != NULL; i++)
561 talloc_free(d[i]);
562 talloc_free(d);
563 VAL(dst) = NULL;
566 static int str_list_add(char **add, int n, void *dst, int pre)
568 char **lst = VAL(dst);
569 int ln;
571 if (!dst)
572 return M_OPT_PARSER_ERR;
573 lst = VAL(dst);
575 for (ln = 0; lst && lst[ln]; ln++)
576 /**/;
578 lst = talloc_realloc(NULL, lst, char *, n + ln + 1);
580 if (pre) {
581 memmove(&lst[n], lst, ln * sizeof(char *));
582 memcpy(lst, add, n * sizeof(char *));
583 } else
584 memcpy(&lst[ln], add, n * sizeof(char *));
585 // (re-)add NULL-termination
586 lst[ln + n] = NULL;
588 talloc_free(add);
590 VAL(dst) = lst;
592 return 1;
595 static int str_list_del(char **del, int n, void *dst)
597 char **lst, *ep;
598 int i, ln, s;
599 long idx;
601 if (!dst)
602 return M_OPT_PARSER_ERR;
603 lst = VAL(dst);
605 for (ln = 0; lst && lst[ln]; ln++)
606 /**/;
607 s = ln;
609 for (i = 0; del[i] != NULL; i++) {
610 idx = strtol(del[i], &ep, 0);
611 if (*ep) {
612 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid index: %s\n", del[i]);
613 talloc_free(del[i]);
614 continue;
616 talloc_free(del[i]);
617 if (idx < 0 || idx >= ln) {
618 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
619 "Index %ld is out of range.\n", idx);
620 continue;
621 } else if (!lst[idx])
622 continue;
623 talloc_free(lst[idx]);
624 lst[idx] = NULL;
625 s--;
627 talloc_free(del);
629 if (s == 0) {
630 talloc_free(lst);
631 VAL(dst) = NULL;
632 return 1;
635 // Don't bother shrinking the list allocation
636 for (i = 0, n = 0; i < ln; i++) {
637 if (!lst[i])
638 continue;
639 lst[n] = lst[i];
640 n++;
642 lst[s] = NULL;
644 return 1;
647 static char *get_nextsep(char *ptr, char sep, int modify)
649 char *last_ptr = ptr;
650 for (;;) {
651 ptr = strchr(ptr, sep);
652 if (ptr && ptr > last_ptr && ptr[-1] == '\\') {
653 if (modify)
654 memmove(ptr - 1, ptr, strlen(ptr) + 1);
655 else
656 ptr++;
657 } else
658 break;
660 return ptr;
663 static int parse_str_list(const m_option_t *opt, const char *name,
664 const char *param, void *dst, int src)
666 int n = 0, len = strlen(opt->name);
667 char *str;
668 char *ptr = (char *)param, *last_ptr, **res;
669 int op = OP_NONE;
671 if (opt->name[len - 1] == '*' && ((int)strlen(name) > len - 1)) {
672 const char *n = &name[len - 1];
673 if (strcasecmp(n, "-add") == 0)
674 op = OP_ADD;
675 else if (strcasecmp(n, "-pre") == 0)
676 op = OP_PRE;
677 else if (strcasecmp(n, "-del") == 0)
678 op = OP_DEL;
679 else if (strcasecmp(n, "-clr") == 0)
680 op = OP_CLR;
681 else
682 return M_OPT_UNKNOWN;
685 // Clear the list ??
686 if (op == OP_CLR) {
687 if (dst)
688 free_str_list(dst);
689 return 0;
692 // All other ops need a param
693 if (param == NULL || strlen(param) == 0)
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;
699 while (ptr[0] != '\0') {
700 ptr = get_nextsep(ptr, separator, 0);
701 if (!ptr) {
702 n++;
703 break;
705 ptr++;
706 n++;
708 if (n == 0)
709 return M_OPT_INVALID;
710 if (((opt->flags & M_OPT_MIN) && (n < opt->min)) ||
711 ((opt->flags & M_OPT_MAX) && (n > opt->max)))
712 return M_OPT_OUT_OF_RANGE;
714 if (!dst)
715 return 1;
717 res = talloc_array(NULL, char *, n + 2);
718 ptr = str = talloc_strdup(NULL, param);
719 n = 0;
721 while (1) {
722 last_ptr = ptr;
723 ptr = get_nextsep(ptr, separator, 1);
724 if (!ptr) {
725 res[n] = talloc_strdup(NULL, last_ptr);
726 n++;
727 break;
729 len = ptr - last_ptr;
730 res[n] = talloc_strndup(NULL, last_ptr, len);
731 ptr++;
732 n++;
734 res[n] = NULL;
735 talloc_free(str);
737 switch (op) {
738 case OP_ADD:
739 return str_list_add(res, n, dst, 0);
740 case OP_PRE:
741 return str_list_add(res, n, dst, 1);
742 case OP_DEL:
743 return str_list_del(res, n, dst);
746 if (VAL(dst))
747 free_str_list(dst);
748 VAL(dst) = res;
750 return 1;
753 static void copy_str_list(const m_option_t *opt, void *dst, const void *src)
755 int n;
756 char **d, **s;
758 if (!(dst && src))
759 return;
760 s = VAL(src);
762 if (VAL(dst))
763 free_str_list(dst);
765 if (!s) {
766 VAL(dst) = NULL;
767 return;
770 for (n = 0; s[n] != NULL; n++)
771 /* NOTHING */;
772 d = talloc_array(NULL, char *, n + 1);
773 for (; n >= 0; n--)
774 d[n] = talloc_strdup(NULL, s[n]);
776 VAL(dst) = d;
779 static char *print_str_list(const m_option_t *opt, const void *src)
781 char **lst = NULL;
782 char *ret = NULL;
784 if (!(src && VAL(src)))
785 return NULL;
786 lst = VAL(src);
788 for (int i = 0; lst[i]; i++) {
789 if (ret)
790 ret = talloc_strdup_append_buffer(ret, ",");
791 ret = talloc_strdup_append_buffer(ret, lst[i]);
793 return ret;
796 const m_option_type_t m_option_type_string_list = {
797 "String list",
798 "A list of strings separated by ','\n"
799 "Option with a name ending in an * permits using the following suffix: \n"
800 "\t-add: Add the given parameters at the end of the list.\n"
801 "\t-pre: Add the given parameters at the beginning of the list.\n"
802 "\t-del: Remove the entry at the given indices.\n"
803 "\t-clr: Clear the list.\n"
804 "e.g: -vf-add flip,mirror -vf-del 2,5\n",
805 sizeof(char **),
806 M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD,
807 parse_str_list,
808 print_str_list,
809 copy_str_list,
810 copy_str_list,
811 copy_str_list,
812 free_str_list
816 /////////////////// Func based options
818 // A chained list to save the various calls for func_param
819 struct m_func_save {
820 struct m_func_save *next;
821 char *name;
822 char *param;
825 #undef VAL
826 #define VAL(x) (*(struct m_func_save **)(x))
828 static void free_func_pf(void *src)
830 struct m_func_save *s, *n;
832 if (!src)
833 return;
835 s = VAL(src);
837 while (s) {
838 n = s->next;
839 talloc_free(s->name);
840 talloc_free(s->param);
841 talloc_free(s);
842 s = n;
844 VAL(src) = NULL;
847 // Parser for func_param
848 static int parse_func_pf(const m_option_t *opt, const char *name,
849 const char *param, void *dst, int src)
851 struct m_func_save *s, *p;
853 if (!dst)
854 return 1;
856 s = talloc_zero(NULL, struct m_func_save);
857 s->name = talloc_strdup(NULL, name);
858 s->param = talloc_strdup(NULL, param);
860 p = VAL(dst);
861 if (p) {
862 for (; p->next != NULL; p = p->next)
863 /**/;
864 p->next = s;
865 } else
866 VAL(dst) = s;
868 return 1;
871 static void copy_func_pf(const m_option_t *opt, void *dst, const void *src)
873 struct m_func_save *d = NULL, *s, *last = NULL;
875 if (!(dst && src))
876 return;
877 s = VAL(src);
879 if (VAL(dst))
880 free_func_pf(dst);
882 while (s) {
883 d = talloc_zero(NULL, struct m_func_save);
884 d->name = talloc_strdup(NULL, s->name);
885 d->param = talloc_strdup(NULL, s->param);
886 if (last)
887 last->next = d;
888 else
889 VAL(dst) = d;
890 last = d;
891 s = s->next;
897 /////////////////// Func_param
899 static void set_func_param(const m_option_t *opt, void *dst, const void *src)
901 struct m_func_save *s;
903 if (!src)
904 return;
905 s = VAL(src);
907 if (!s)
908 return;
910 for (; s != NULL; s = s->next)
911 ((m_opt_func_param_t) opt->p)(opt, s->param);
914 const m_option_type_t m_option_type_func_param = {
915 "Func param",
917 sizeof(struct m_func_save *),
918 M_OPT_TYPE_INDIRECT,
919 parse_func_pf,
920 NULL,
921 NULL, // Nothing to do on save
922 set_func_param,
923 copy_func_pf,
924 free_func_pf
927 /////////////// Func
929 #undef VAL
931 static int parse_func(const m_option_t *opt, const char *name,
932 const char *param, void *dst, int src)
934 return 0;
937 static void set_func(const m_option_t *opt, void *dst, const void *src)
939 ((m_opt_func_t) opt->p)(opt);
942 const m_option_type_t m_option_type_func = {
943 "Func",
945 sizeof(int),
946 M_OPT_TYPE_INDIRECT,
947 parse_func,
948 NULL,
949 NULL, // Nothing to do on save
950 set_func,
951 NULL,
952 NULL
955 /////////////////// Print
957 static int parse_print(const m_option_t *opt, const char *name,
958 const char *param, void *dst, int src)
960 if (opt->type == CONF_TYPE_PRINT_INDIRECT)
961 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", *(char **) opt->p);
962 else if (opt->type == CONF_TYPE_PRINT_FUNC)
963 return ((m_opt_func_full_t) opt->p)(opt, name, param);
964 else
965 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", mp_gtext(opt->p));
967 if (opt->priv == NULL)
968 return M_OPT_EXIT;
969 return 0;
972 const m_option_type_t m_option_type_print = {
973 "Print",
977 parse_print,
978 NULL,
979 NULL,
980 NULL,
981 NULL,
982 NULL
985 const m_option_type_t m_option_type_print_indirect = {
986 "Print",
990 parse_print,
991 NULL,
992 NULL,
993 NULL,
994 NULL,
995 NULL
998 const m_option_type_t m_option_type_print_func = {
999 "Print",
1002 M_OPT_TYPE_ALLOW_WILDCARD,
1003 parse_print,
1004 NULL,
1005 NULL,
1006 NULL,
1007 NULL,
1008 NULL
1012 /////////////////////// Subconfig
1013 #undef VAL
1014 #define VAL(x) (*(char ***)(x))
1016 static int parse_subconf(const m_option_t *opt, const char *name,
1017 const char *param, void *dst, int src)
1019 char *subparam;
1020 char *subopt;
1021 int nr = 0, i, r;
1022 const m_option_t *subopts;
1023 const char *p;
1024 char **lst = NULL;
1026 if (param == NULL || strlen(param) == 0)
1027 return M_OPT_MISSING_PARAM;
1029 subparam = talloc_size(NULL, strlen(param) + 1);
1030 subopt = talloc_size(NULL, strlen(param) + 1);
1031 p = param;
1033 subopts = opt->p;
1035 while (p[0]) {
1036 int sscanf_ret = 1;
1037 int optlen = strcspn(p, ":=");
1038 /* clear out */
1039 subopt[0] = subparam[0] = 0;
1040 av_strlcpy(subopt, p, optlen + 1);
1041 p = &p[optlen];
1042 if (p[0] == '=') {
1043 sscanf_ret = 2;
1044 p = &p[1];
1045 if (p[0] == '"') {
1046 p = &p[1];
1047 optlen = strcspn(p, "\"");
1048 av_strlcpy(subparam, p, optlen + 1);
1049 p = &p[optlen];
1050 if (p[0] != '"') {
1051 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1052 "Terminating '\"' missing for '%s'\n", subopt);
1053 return M_OPT_INVALID;
1055 p = &p[1];
1056 } else if (p[0] == '%') {
1057 p = &p[1];
1058 optlen = (int)strtol(p, (char **)&p, 0);
1059 if (!p || p[0] != '%' || (optlen > strlen(p) - 1)) {
1060 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1061 "Invalid length %i for '%s'\n", optlen, subopt);
1062 return M_OPT_INVALID;
1064 p = &p[1];
1065 av_strlcpy(subparam, p, optlen + 1);
1066 p = &p[optlen];
1067 } else {
1068 optlen = strcspn(p, ":");
1069 av_strlcpy(subparam, p, optlen + 1);
1070 p = &p[optlen];
1073 if (p[0] == ':')
1074 p = &p[1];
1075 else if (p[0]) {
1076 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1077 "Incorrect termination for '%s'\n", subopt);
1078 return M_OPT_INVALID;
1081 switch (sscanf_ret) {
1082 case 1:
1083 subparam[0] = 0;
1084 case 2:
1085 for (i = 0; subopts[i].name; i++)
1086 if (!strcmp(subopts[i].name, subopt))
1087 break;
1088 if (!subopts[i].name) {
1089 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1090 "Option %s: Unknown suboption %s\n", name, subopt);
1091 return M_OPT_UNKNOWN;
1093 r = m_option_parse(&subopts[i], subopt,
1094 subparam[0] == 0 ? NULL : subparam, NULL, src);
1095 if (r < 0)
1096 return r;
1097 if (dst) {
1098 lst = talloc_realloc(NULL, lst, char *, 2 * (nr + 2));
1099 lst[2 * nr] = talloc_strdup(NULL, subopt);
1100 lst[2 * nr + 1] = subparam[0] == 0 ? NULL :
1101 talloc_strdup(NULL, subparam);
1102 memset(&lst[2 * (nr + 1)], 0, 2 * sizeof(char *));
1103 nr++;
1105 break;
1109 talloc_free(subparam);
1110 talloc_free(subopt);
1111 if (dst)
1112 VAL(dst) = lst;
1114 return 1;
1117 const m_option_type_t m_option_type_subconfig = {
1118 "Subconfig",
1119 "The syntax is -option opt1=foo:flag:opt2=blah",
1120 sizeof(int),
1121 M_OPT_TYPE_HAS_CHILD,
1122 parse_subconf,
1123 NULL,
1124 NULL,
1125 NULL,
1126 NULL,
1127 NULL
1130 #include "libmpcodecs/img_format.h"
1132 /* FIXME: snyc with img_format.h */
1133 static struct {
1134 const char *name;
1135 unsigned int fmt;
1136 } mp_imgfmt_list[] = {
1137 {"444p16le", IMGFMT_444P16_LE},
1138 {"444p16be", IMGFMT_444P16_BE},
1139 {"444p10le", IMGFMT_444P10_LE},
1140 {"444p10be", IMGFMT_444P10_BE},
1141 {"444p9le", IMGFMT_444P9_LE},
1142 {"444p9be", IMGFMT_444P9_BE},
1143 {"422p16le", IMGFMT_422P16_LE},
1144 {"422p16be", IMGFMT_422P16_BE},
1145 {"422p10le", IMGFMT_422P10_LE},
1146 {"422p10be", IMGFMT_422P10_BE},
1147 {"420p16le", IMGFMT_420P16_LE},
1148 {"420p16be", IMGFMT_420P16_BE},
1149 {"420p10le", IMGFMT_420P10_LE},
1150 {"420p10be", IMGFMT_420P10_BE},
1151 {"420p9le", IMGFMT_420P9_LE},
1152 {"420p9be", IMGFMT_420P9_BE},
1153 {"444p16", IMGFMT_444P16},
1154 {"444p10", IMGFMT_444P10},
1155 {"444p9", IMGFMT_444P9},
1156 {"422p16", IMGFMT_422P16},
1157 {"422p10", IMGFMT_422P10},
1158 {"420p10", IMGFMT_420P10},
1159 {"420p9", IMGFMT_420P9},
1160 {"420p16", IMGFMT_420P16},
1161 {"420a", IMGFMT_420A},
1162 {"444p", IMGFMT_444P},
1163 {"422p", IMGFMT_422P},
1164 {"411p", IMGFMT_411P},
1165 {"440p", IMGFMT_440P},
1166 {"yuy2", IMGFMT_YUY2},
1167 {"yvyu", IMGFMT_YVYU},
1168 {"uyvy", IMGFMT_UYVY},
1169 {"yvu9", IMGFMT_YVU9},
1170 {"if09", IMGFMT_IF09},
1171 {"yv12", IMGFMT_YV12},
1172 {"i420", IMGFMT_I420},
1173 {"iyuv", IMGFMT_IYUV},
1174 {"clpl", IMGFMT_CLPL},
1175 {"hm12", IMGFMT_HM12},
1176 {"y800", IMGFMT_Y800},
1177 {"y8", IMGFMT_Y8},
1178 {"nv12", IMGFMT_NV12},
1179 {"nv21", IMGFMT_NV21},
1180 {"bgr24", IMGFMT_BGR24},
1181 {"bgr32", IMGFMT_BGR32},
1182 {"bgr16", IMGFMT_BGR16},
1183 {"bgr15", IMGFMT_BGR15},
1184 {"bgr12", IMGFMT_BGR12},
1185 {"bgr8", IMGFMT_BGR8},
1186 {"bgr4", IMGFMT_BGR4},
1187 {"bg4b", IMGFMT_BG4B},
1188 {"bgr1", IMGFMT_BGR1},
1189 {"rgb48be", IMGFMT_RGB48BE},
1190 {"rgb48le", IMGFMT_RGB48LE},
1191 {"rgb48ne", IMGFMT_RGB48NE},
1192 {"rgb24", IMGFMT_RGB24},
1193 {"rgb32", IMGFMT_RGB32},
1194 {"rgb16", IMGFMT_RGB16},
1195 {"rgb15", IMGFMT_RGB15},
1196 {"rgb12", IMGFMT_RGB12},
1197 {"rgb8", IMGFMT_RGB8},
1198 {"rgb4", IMGFMT_RGB4},
1199 {"rg4b", IMGFMT_RG4B},
1200 {"rgb1", IMGFMT_RGB1},
1201 {"rgba", IMGFMT_RGBA},
1202 {"argb", IMGFMT_ARGB},
1203 {"bgra", IMGFMT_BGRA},
1204 {"abgr", IMGFMT_ABGR},
1205 {"mjpeg", IMGFMT_MJPEG},
1206 {"mjpg", IMGFMT_MJPEG},
1207 { NULL, 0 }
1210 static int parse_imgfmt(const m_option_t *opt, const char *name,
1211 const char *param, void *dst, int src)
1213 uint32_t fmt = 0;
1214 int i;
1216 if (param == NULL || strlen(param) == 0)
1217 return M_OPT_MISSING_PARAM;
1219 if (!strcmp(param, "help")) {
1220 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available formats:");
1221 for (i = 0; mp_imgfmt_list[i].name; i++)
1222 mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %s", mp_imgfmt_list[i].name);
1223 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n");
1224 return M_OPT_EXIT - 1;
1227 if (sscanf(param, "0x%x", &fmt) != 1) {
1228 for (i = 0; mp_imgfmt_list[i].name; i++) {
1229 if (!strcasecmp(param, mp_imgfmt_list[i].name)) {
1230 fmt = mp_imgfmt_list[i].fmt;
1231 break;
1234 if (!mp_imgfmt_list[i].name) {
1235 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1236 "Option %s: unknown format name: '%s'\n", name, param);
1237 return M_OPT_INVALID;
1241 if (dst)
1242 *((uint32_t *)dst) = fmt;
1244 return 1;
1247 const m_option_type_t m_option_type_imgfmt = {
1248 "Image format",
1249 "Please report any missing colorspaces.",
1250 sizeof(uint32_t),
1252 parse_imgfmt,
1253 NULL,
1254 copy_opt,
1255 copy_opt,
1256 NULL,
1257 NULL
1260 #include "libaf/af_format.h"
1262 /* FIXME: snyc with af_format.h */
1263 static struct {
1264 const char *name;
1265 unsigned int fmt;
1266 } mp_afmt_list[] = {
1267 // SPECIAL
1268 {"mulaw", AF_FORMAT_MU_LAW},
1269 {"alaw", AF_FORMAT_A_LAW},
1270 {"mpeg2", AF_FORMAT_MPEG2},
1271 {"ac3le", AF_FORMAT_AC3_LE},
1272 {"ac3be", AF_FORMAT_AC3_BE},
1273 {"ac3ne", AF_FORMAT_AC3_NE},
1274 {"imaadpcm", AF_FORMAT_IMA_ADPCM},
1275 // ORDINARY
1276 {"u8", AF_FORMAT_U8},
1277 {"s8", AF_FORMAT_S8},
1278 {"u16le", AF_FORMAT_U16_LE},
1279 {"u16be", AF_FORMAT_U16_BE},
1280 {"u16ne", AF_FORMAT_U16_NE},
1281 {"s16le", AF_FORMAT_S16_LE},
1282 {"s16be", AF_FORMAT_S16_BE},
1283 {"s16ne", AF_FORMAT_S16_NE},
1284 {"u24le", AF_FORMAT_U24_LE},
1285 {"u24be", AF_FORMAT_U24_BE},
1286 {"u24ne", AF_FORMAT_U24_NE},
1287 {"s24le", AF_FORMAT_S24_LE},
1288 {"s24be", AF_FORMAT_S24_BE},
1289 {"s24ne", AF_FORMAT_S24_NE},
1290 {"u32le", AF_FORMAT_U32_LE},
1291 {"u32be", AF_FORMAT_U32_BE},
1292 {"u32ne", AF_FORMAT_U32_NE},
1293 {"s32le", AF_FORMAT_S32_LE},
1294 {"s32be", AF_FORMAT_S32_BE},
1295 {"s32ne", AF_FORMAT_S32_NE},
1296 {"floatle", AF_FORMAT_FLOAT_LE},
1297 {"floatbe", AF_FORMAT_FLOAT_BE},
1298 {"floatne", AF_FORMAT_FLOAT_NE},
1299 { NULL, 0 }
1302 static int parse_afmt(const m_option_t *opt, const char *name,
1303 const char *param, void *dst, int src)
1305 uint32_t fmt = 0;
1306 int i;
1308 if (param == NULL || strlen(param) == 0)
1309 return M_OPT_MISSING_PARAM;
1311 if (!strcmp(param, "help")) {
1312 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available formats:");
1313 for (i = 0; mp_afmt_list[i].name; i++)
1314 mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %s", mp_afmt_list[i].name);
1315 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n");
1316 return M_OPT_EXIT - 1;
1319 if (sscanf(param, "0x%x", &fmt) != 1) {
1320 for (i = 0; mp_afmt_list[i].name; i++) {
1321 if (!strcasecmp(param, mp_afmt_list[i].name)) {
1322 fmt = mp_afmt_list[i].fmt;
1323 break;
1326 if (!mp_afmt_list[i].name) {
1327 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1328 "Option %s: unknown format name: '%s'\n", name, param);
1329 return M_OPT_INVALID;
1333 if (dst)
1334 *((uint32_t *)dst) = fmt;
1336 return 1;
1339 const m_option_type_t m_option_type_afmt = {
1340 "Audio format",
1341 "Please report any missing formats.",
1342 sizeof(uint32_t),
1344 parse_afmt,
1345 NULL,
1346 copy_opt,
1347 copy_opt,
1348 NULL,
1349 NULL
1353 int parse_timestring(const char *str, double *time, char endchar)
1355 int a, b, len;
1356 double d;
1357 *time = 0; /* ensure initialization for error cases */
1358 if (sscanf(str, "%d:%d:%lf%n", &a, &b, &d, &len) >= 3)
1359 *time = 3600 * a + 60 * b + d;
1360 else if (sscanf(str, "%d:%lf%n", &a, &d, &len) >= 2)
1361 *time = 60 * a + d;
1362 else if (sscanf(str, "%lf%n", &d, &len) >= 1)
1363 *time = d;
1364 else
1365 return 0; /* unsupported time format */
1366 if (str[len] && str[len] != endchar)
1367 return 0; /* invalid extra characters at the end */
1368 return len;
1372 static int parse_time(const m_option_t *opt, const char *name,
1373 const char *param, void *dst, int src)
1375 double time;
1377 if (param == NULL || strlen(param) == 0)
1378 return M_OPT_MISSING_PARAM;
1380 if (!parse_timestring(param, &time, 0)) {
1381 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: invalid time: '%s'\n",
1382 name, param);
1383 return M_OPT_INVALID;
1386 if (dst)
1387 *(double *)dst = time;
1388 return 1;
1391 const m_option_type_t m_option_type_time = {
1392 "Time",
1394 sizeof(double),
1396 parse_time,
1397 print_double,
1398 copy_opt,
1399 copy_opt,
1400 NULL,
1401 NULL
1405 // Time or size (-endpos)
1407 static int parse_time_size(const m_option_t *opt, const char *name,
1408 const char *param, void *dst, int src)
1410 m_time_size_t ts;
1411 char unit[4];
1412 double end_at;
1414 if (param == NULL || strlen(param) == 0)
1415 return M_OPT_MISSING_PARAM;
1417 ts.pos = 0;
1418 /* End at size parsing */
1419 if (sscanf(param, "%lf%3s", &end_at, unit) == 2) {
1420 ts.type = END_AT_SIZE;
1421 if (!strcasecmp(unit, "b"))
1423 else if (!strcasecmp(unit, "kb"))
1424 end_at *= 1024;
1425 else if (!strcasecmp(unit, "mb"))
1426 end_at *= 1024 * 1024;
1427 else if (!strcasecmp(unit, "gb"))
1428 end_at *= 1024 * 1024 * 1024;
1429 else
1430 ts.type = END_AT_NONE;
1432 if (ts.type == END_AT_SIZE) {
1433 ts.pos = end_at;
1434 goto out;
1438 /* End at time parsing. This has to be last because the parsing accepts
1439 * even a number followed by garbage */
1440 if (!parse_timestring(param, &end_at, 0)) {
1441 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1442 "Option %s: invalid time or size: '%s'\n",
1443 name, param);
1444 return M_OPT_INVALID;
1447 ts.type = END_AT_TIME;
1448 ts.pos = end_at;
1449 out:
1450 if (dst)
1451 *(m_time_size_t *)dst = ts;
1452 return 1;
1455 const m_option_type_t m_option_type_time_size = {
1456 "Time or size",
1458 sizeof(m_time_size_t),
1460 parse_time_size,
1461 NULL,
1462 copy_opt,
1463 copy_opt,
1464 NULL,
1465 NULL
1469 //// Objects (i.e. filters, etc) settings
1471 #include "m_struct.h"
1473 #undef VAL
1474 #define VAL(x) (*(m_obj_settings_t **)(x))
1476 static int find_obj_desc(const char *name, const m_obj_list_t *l,
1477 const m_struct_t **ret)
1479 int i;
1480 char *n;
1482 for (i = 0; l->list[i]; i++) {
1483 n = M_ST_MB(char *, l->list[i], l->name_off);
1484 if (!strcmp(n, name)) {
1485 *ret = M_ST_MB(m_struct_t *, l->list[i], l->desc_off);
1486 return 1;
1489 return 0;
1492 static int get_obj_param(const char *opt_name, const char *obj_name,
1493 const m_struct_t *desc, char *str, int *nold,
1494 int oldmax, char **dst)
1496 char *eq;
1497 const m_option_t *opt;
1498 int r;
1500 eq = strchr(str, '=');
1501 if (eq && eq == str)
1502 eq = NULL;
1504 if (eq) {
1505 char *p = eq + 1;
1506 if (p[0] == '\0')
1507 p = NULL;
1508 eq[0] = '\0';
1509 opt = m_option_list_find(desc->fields, str);
1510 if (!opt) {
1511 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1512 "Option %s: %s doesn't have a %s parameter.\n",
1513 opt_name, obj_name, str);
1514 return M_OPT_UNKNOWN;
1516 r = m_option_parse(opt, str, p, NULL, M_CONFIG_FILE);
1517 if (r < 0) {
1518 if (r > M_OPT_EXIT)
1519 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1520 "Option %s: Error while parsing %s parameter %s (%s)\n",
1521 opt_name, obj_name, str, p);
1522 eq[0] = '=';
1523 return r;
1525 if (dst) {
1526 dst[0] = talloc_strdup(NULL, str);
1527 dst[1] = talloc_strdup(NULL, p);
1529 eq[0] = '=';
1530 } else {
1531 if ((*nold) >= oldmax) {
1532 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: %s has only %d params, so you can't give more than %d unnamed params.\n",
1533 opt_name, obj_name, oldmax, oldmax);
1534 return M_OPT_OUT_OF_RANGE;
1536 opt = &desc->fields[(*nold)];
1537 r = m_option_parse(opt, opt->name, str, NULL, M_CONFIG_FILE);
1538 if (r < 0) {
1539 if (r > M_OPT_EXIT)
1540 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1541 "Option %s: Error while parsing %s parameter %s (%s)\n",
1542 opt_name, obj_name, opt->name, str);
1543 return r;
1545 if (dst) {
1546 dst[0] = talloc_strdup(NULL, opt->name);
1547 dst[1] = talloc_strdup(NULL, str);
1549 (*nold)++;
1551 return 1;
1554 static int get_obj_params(const char *opt_name, const char *name, char *params,
1555 const m_struct_t *desc, char separator, char ***_ret)
1557 int n = 0, nold = 0, nopts, r;
1558 char *ptr, *last_ptr = params;
1559 char **ret;
1561 if (!strcmp(params, "help")) { // Help
1562 char min[50], max[50];
1563 if (!desc->fields) {
1564 printf("%s doesn't have any options.\n\n", name);
1565 return M_OPT_EXIT - 1;
1567 printf("\n Name Type Min Max\n\n");
1568 for (n = 0; desc->fields[n].name; n++) {
1569 const m_option_t *opt = &desc->fields[n];
1570 if (opt->type->flags & M_OPT_TYPE_HAS_CHILD)
1571 continue;
1572 if (opt->flags & M_OPT_MIN)
1573 sprintf(min, "%-8.0f", opt->min);
1574 else
1575 strcpy(min, "No");
1576 if (opt->flags & M_OPT_MAX)
1577 sprintf(max, "%-8.0f", opt->max);
1578 else
1579 strcpy(max, "No");
1580 printf(" %-20.20s %-15.15s %-10.10s %-10.10s\n",
1581 opt->name,
1582 opt->type->name,
1583 min,
1584 max);
1586 printf("\n");
1587 return M_OPT_EXIT - 1;
1590 for (nopts = 0; desc->fields[nopts].name; nopts++)
1591 /* NOP */;
1593 // TODO : Check that each opt can be parsed
1594 r = 1;
1595 while (last_ptr && last_ptr[0] != '\0') {
1596 ptr = strchr(last_ptr, separator);
1597 if (!ptr) {
1598 r = get_obj_param(opt_name, name, desc, last_ptr, &nold, nopts,
1599 NULL);
1600 n++;
1601 break;
1603 if (ptr == last_ptr) { // Empty field, count it and go on
1604 nold++;
1605 last_ptr = ptr + 1;
1606 continue;
1608 ptr[0] = '\0';
1609 r = get_obj_param(opt_name, name, desc, last_ptr, &nold, nopts, NULL);
1610 ptr[0] = separator;
1611 if (r < 0)
1612 break;
1613 n++;
1614 last_ptr = ptr + 1;
1616 if (r < 0)
1617 return r;
1618 if (!last_ptr[0]) // count an empty field at the end, too
1619 nold++;
1620 if (nold > nopts) {
1621 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Too many options for %s\n", name);
1622 return M_OPT_OUT_OF_RANGE;
1624 if (!_ret) // Just test
1625 return 1;
1626 if (n == 0) // No options or only empty options
1627 return 1;
1629 ret = talloc_array(NULL, char *, (n + 2) * 2);
1630 n = nold = 0;
1631 last_ptr = params;
1633 while (last_ptr && last_ptr[0] != '\0') {
1634 ptr = strchr(last_ptr, separator);
1635 if (!ptr) {
1636 get_obj_param(opt_name, name, desc, last_ptr, &nold, nopts,
1637 &ret[n * 2]);
1638 n++;
1639 break;
1641 if (ptr == last_ptr) { // Empty field, count it and go on
1642 last_ptr = ptr + 1;
1643 nold++;
1644 continue;
1646 ptr[0] = '\0';
1647 get_obj_param(opt_name, name, desc, last_ptr, &nold, nopts,
1648 &ret[n * 2]);
1649 n++;
1650 last_ptr = ptr + 1;
1652 ret[n * 2] = ret[n * 2 + 1] = NULL;
1653 *_ret = ret;
1655 return 1;
1658 static int parse_obj_params(const m_option_t *opt, const char *name,
1659 const char *param, void *dst, int src)
1661 char **opts;
1662 int r;
1663 m_obj_params_t *p = opt->priv;
1664 const m_struct_t *desc;
1665 char *cpy;
1667 // We need the object desc
1668 if (!p)
1669 return M_OPT_INVALID;
1671 desc = p->desc;
1672 cpy = talloc_strdup(NULL, param);
1673 r = get_obj_params(name, desc->name, cpy, desc, p->separator,
1674 dst ? &opts : NULL);
1675 talloc_free(cpy);
1676 if (r < 0)
1677 return r;
1678 if (!dst)
1679 return 1;
1680 if (!opts) // no arguments given
1681 return 1;
1683 for (r = 0; opts[r]; r += 2)
1684 m_struct_set(desc, dst, opts[r], opts[r + 1]);
1686 return 1;
1690 const m_option_type_t m_option_type_obj_params = {
1691 "Object params",
1695 parse_obj_params,
1696 NULL,
1697 NULL,
1698 NULL,
1699 NULL,
1700 NULL
1703 /// Some predefined types as a definition would be quite lengthy
1705 /// Span arguments
1706 static const m_span_t m_span_params_dflts = {
1707 -1, -1
1709 static const m_option_t m_span_params_fields[] = {
1710 {"start", M_ST_OFF(m_span_t, start), CONF_TYPE_INT, M_OPT_MIN, 1, 0, NULL},
1711 {"end", M_ST_OFF(m_span_t, end), CONF_TYPE_INT, M_OPT_MIN, 1, 0, NULL},
1712 { NULL, NULL, 0, 0, 0, 0, NULL }
1714 static const struct m_struct_st m_span_opts = {
1715 "m_span",
1716 sizeof(m_span_t),
1717 &m_span_params_dflts,
1718 m_span_params_fields
1720 const m_obj_params_t m_span_params_def = {
1721 &m_span_opts,
1725 static int parse_obj_settings(const char *opt, char *str,
1726 const m_obj_list_t *list,
1727 m_obj_settings_t **_ret, int ret_n)
1729 int r;
1730 char *param, **plist = NULL;
1731 const m_struct_t *desc;
1732 m_obj_settings_t *ret = _ret ? *_ret : NULL;
1735 // Now check that the object exists
1736 param = strchr(str, '=');
1737 if (param) {
1738 param[0] = '\0';
1739 param++;
1740 if (strlen(param) <= 0)
1741 param = NULL;
1745 if (!find_obj_desc(str, list, &desc)) {
1746 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: %s doesn't exist.\n",
1747 opt, str);
1748 return M_OPT_INVALID;
1751 if (param) {
1752 if (!desc && _ret) {
1753 if (!strcmp(param, "help")) {
1754 mp_msg(MSGT_CFGPARSER, MSGL_INFO,
1755 "Option %s: %s have no option description.\n", opt, str);
1756 return M_OPT_EXIT - 1;
1758 plist = talloc_zero_array(NULL, char *, 4);
1759 plist[0] = talloc_strdup(NULL, "_oldargs_");
1760 plist[1] = talloc_strdup(NULL, param);
1761 } else if (desc) {
1762 r = get_obj_params(opt, str, param, desc, ':',
1763 _ret ? &plist : NULL);
1764 if (r < 0)
1765 return r;
1768 if (!_ret)
1769 return 1;
1771 ret = talloc_realloc(NULL, ret, struct m_obj_settings, ret_n + 2);
1772 memset(&ret[ret_n], 0, 2 * sizeof(m_obj_settings_t));
1773 ret[ret_n].name = talloc_strdup(NULL, str);
1774 ret[ret_n].attribs = plist;
1776 *_ret = ret;
1777 return 1;
1780 static int obj_settings_list_del(const char *opt_name, const char *param,
1781 void *dst, int src)
1783 char **str_list = NULL;
1784 int r, i, idx_max = 0;
1785 char *rem_id = "_removed_marker_";
1786 const m_option_t list_opt = {
1787 opt_name, NULL, CONF_TYPE_STRING_LIST,
1788 0, 0, 0, NULL
1790 m_obj_settings_t *obj_list = dst ? VAL(dst) : NULL;
1792 if (dst && !obj_list) {
1793 mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: the list is empty.\n",
1794 opt_name);
1795 return 1;
1796 } else if (obj_list) {
1797 for (idx_max = 0; obj_list[idx_max].name != NULL; idx_max++)
1798 /* NOP */;
1801 r = m_option_parse(&list_opt, opt_name, param, &str_list, src);
1802 if (r < 0 || !str_list)
1803 return r;
1805 for (r = 0; str_list[r]; r++) {
1806 int id;
1807 char *endptr;
1808 id = strtol(str_list[r], &endptr, 0);
1809 if (endptr == str_list[r]) {
1810 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", opt_name);
1811 m_option_free(&list_opt, &str_list);
1812 return M_OPT_INVALID;
1814 if (!obj_list)
1815 continue;
1816 if (id >= idx_max || id < -idx_max) {
1817 mp_msg(MSGT_CFGPARSER, MSGL_WARN,
1818 "Option %s: Index %d is out of range.\n", opt_name, id);
1819 continue;
1821 if (id < 0)
1822 id = idx_max + id;
1823 talloc_free(obj_list[id].name);
1824 free_str_list(&(obj_list[id].attribs));
1825 obj_list[id].name = rem_id;
1828 if (!dst) {
1829 m_option_free(&list_opt, &str_list);
1830 return 1;
1833 for (i = 0; obj_list[i].name; i++) {
1834 while (obj_list[i].name == rem_id) {
1835 memmove(&obj_list[i], &obj_list[i + 1],
1836 sizeof(m_obj_settings_t) * (idx_max - i));
1837 idx_max--;
1840 obj_list = talloc_realloc(NULL, obj_list, struct m_obj_settings,
1841 idx_max + 1);
1842 VAL(dst) = obj_list;
1844 return 1;
1847 static void free_obj_settings_list(void *dst)
1849 int n;
1850 m_obj_settings_t *d;
1852 if (!dst || !VAL(dst))
1853 return;
1855 d = VAL(dst);
1856 for (n = 0; d[n].name; n++) {
1857 talloc_free(d[n].name);
1858 free_str_list(&(d[n].attribs));
1860 talloc_free(d);
1861 VAL(dst) = NULL;
1864 static int parse_obj_settings_list(const m_option_t *opt, const char *name,
1865 const char *param, void *dst, int src)
1867 int n = 0, r, len = strlen(opt->name);
1868 char *str;
1869 char *ptr, *last_ptr;
1870 m_obj_settings_t *res = NULL, *queue = NULL, *head = NULL;
1871 int op = OP_NONE;
1873 // We need the objects list
1874 if (!opt->priv)
1875 return M_OPT_INVALID;
1877 if (opt->name[len - 1] == '*' && ((int)strlen(name) > len - 1)) {
1878 const char *n = &name[len - 1];
1879 if (strcasecmp(n, "-add") == 0)
1880 op = OP_ADD;
1881 else if (strcasecmp(n, "-pre") == 0)
1882 op = OP_PRE;
1883 else if (strcasecmp(n, "-del") == 0)
1884 op = OP_DEL;
1885 else if (strcasecmp(n, "-clr") == 0)
1886 op = OP_CLR;
1887 else {
1888 char prefix[len];
1889 strncpy(prefix, opt->name, len - 1);
1890 prefix[len - 1] = '\0';
1891 mp_msg(MSGT_VFILTER, MSGL_ERR, "Option %s: unknown postfix %s\n"
1892 "Supported postfixes are:\n"
1893 " %s-add\n"
1894 " Append the given list to the current list\n\n"
1895 " %s-pre\n"
1896 " Prepend the given list to the current list\n\n"
1897 " %s-del x,y,...\n"
1898 " Remove the given elements. Take the list element index (starting from 0).\n"
1899 " Negative index can be used (i.e. -1 is the last element)\n\n"
1900 " %s-clr\n"
1901 " Clear the current list.\n",
1902 name, n, prefix, prefix, prefix, prefix);
1904 return M_OPT_UNKNOWN;
1908 // Clear the list ??
1909 if (op == OP_CLR) {
1910 if (dst)
1911 free_obj_settings_list(dst);
1912 return 0;
1915 if (param == NULL || strlen(param) == 0)
1916 return M_OPT_MISSING_PARAM;
1918 switch (op) {
1919 case OP_ADD:
1920 if (dst)
1921 head = VAL(dst);
1922 break;
1923 case OP_PRE:
1924 if (dst)
1925 queue = VAL(dst);
1926 break;
1927 case OP_DEL:
1928 return obj_settings_list_del(name, param, dst, src);
1929 case OP_NONE:
1930 if (dst && VAL(dst))
1931 free_obj_settings_list(dst);
1932 break;
1933 default:
1934 mp_msg(MSGT_VFILTER, MSGL_ERR, "Option %s: FIXME\n", name);
1935 return M_OPT_UNKNOWN;
1938 if (!strcmp(param, "help")) {
1939 m_obj_list_t *ol = opt->priv;
1940 mp_msg(MSGT_VFILTER, MSGL_INFO, "Available video filters:\n");
1941 mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_FILTERS\n");
1942 for (n = 0; ol->list[n]; n++)
1943 mp_msg(MSGT_VFILTER, MSGL_INFO, " %-15s: %s\n",
1944 M_ST_MB(char *, ol->list[n], ol->name_off),
1945 M_ST_MB(char *, ol->list[n], ol->info_off));
1946 mp_msg(MSGT_VFILTER, MSGL_INFO, "\n");
1947 return M_OPT_EXIT - 1;
1949 ptr = str = talloc_strdup(NULL, param);
1951 while (ptr[0] != '\0') {
1952 last_ptr = ptr;
1953 ptr = get_nextsep(ptr, OPTION_LIST_SEPARATOR, 1);
1955 if (!ptr) {
1956 r = parse_obj_settings(name, last_ptr, opt->priv,
1957 dst ? &res : NULL, n);
1958 if (r < 0) {
1959 talloc_free(str);
1960 return r;
1962 n++;
1963 break;
1965 ptr[0] = '\0';
1966 r = parse_obj_settings(name, last_ptr, opt->priv, dst ? &res : NULL, n);
1967 if (r < 0) {
1968 talloc_free(str);
1969 return r;
1971 ptr++;
1972 n++;
1974 talloc_free(str);
1975 if (n == 0)
1976 return M_OPT_INVALID;
1978 if (((opt->flags & M_OPT_MIN) && (n < opt->min)) ||
1979 ((opt->flags & M_OPT_MAX) && (n > opt->max)))
1980 return M_OPT_OUT_OF_RANGE;
1982 if (dst) {
1983 if (queue) {
1984 int qsize;
1985 for (qsize = 0; queue[qsize].name; qsize++)
1986 /* NOP */;
1987 res = talloc_realloc(NULL, res, struct m_obj_settings,
1988 qsize + n + 1);
1989 memcpy(&res[n], queue, (qsize + 1) * sizeof(m_obj_settings_t));
1990 n += qsize;
1991 talloc_free(queue);
1993 if (head) {
1994 int hsize;
1995 for (hsize = 0; head[hsize].name; hsize++)
1996 /* NOP */;
1997 head = talloc_realloc(NULL, head, struct m_obj_settings,
1998 hsize + n + 1);
1999 memcpy(&head[hsize], res, (n + 1) * sizeof(m_obj_settings_t));
2000 talloc_free(res);
2001 res = head;
2003 VAL(dst) = res;
2005 return 1;
2008 static void copy_obj_settings_list(const m_option_t *opt, void *dst,
2009 const void *src)
2011 m_obj_settings_t *d, *s;
2012 int n;
2014 if (!(dst && src))
2015 return;
2017 s = VAL(src);
2019 if (VAL(dst))
2020 free_obj_settings_list(dst);
2021 if (!s)
2022 return;
2026 for (n = 0; s[n].name; n++)
2027 /* NOP */;
2028 d = talloc_array(NULL, struct m_obj_settings, n + 1);
2029 for (n = 0; s[n].name; n++) {
2030 d[n].name = talloc_strdup(NULL, s[n].name);
2031 d[n].attribs = NULL;
2032 copy_str_list(NULL, &(d[n].attribs), &(s[n].attribs));
2034 d[n].name = NULL;
2035 d[n].attribs = NULL;
2036 VAL(dst) = d;
2039 const m_option_type_t m_option_type_obj_settings_list = {
2040 "Object settings list",
2042 sizeof(m_obj_settings_t *),
2043 M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD,
2044 parse_obj_settings_list,
2045 NULL,
2046 copy_obj_settings_list,
2047 copy_obj_settings_list,
2048 copy_obj_settings_list,
2049 free_obj_settings_list,
2054 static int parse_obj_presets(const m_option_t *opt, const char *name,
2055 const char *param, void *dst, int src)
2057 m_obj_presets_t *obj_p = (m_obj_presets_t *)opt->priv;
2058 const m_struct_t *in_desc;
2059 const m_struct_t *out_desc;
2060 int s, i;
2061 const unsigned char *pre;
2062 char *pre_name = NULL;
2064 if (!obj_p) {
2065 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Presets need a "
2066 "pointer to a m_obj_presets_t in the priv field.\n", name);
2067 return M_OPT_PARSER_ERR;
2070 if (!param)
2071 return M_OPT_MISSING_PARAM;
2073 pre = obj_p->presets;
2074 in_desc = obj_p->in_desc;
2075 out_desc = obj_p->out_desc ? obj_p->out_desc : obj_p->in_desc;
2076 s = in_desc->size;
2078 if (!strcmp(param, "help")) {
2079 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available presets for %s->%s:",
2080 out_desc->name, name);
2081 for (pre = obj_p->presets;
2082 (pre_name = M_ST_MB(char *, pre, obj_p->name_off)); pre += s)
2083 mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %s", pre_name);
2084 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "\n");
2085 return M_OPT_EXIT - 1;
2088 for (pre_name = M_ST_MB(char *, pre, obj_p->name_off); pre_name;
2089 pre += s, pre_name = M_ST_MB(char *, pre, obj_p->name_off))
2090 if (!strcmp(pre_name, param))
2091 break;
2092 if (!pre_name) {
2093 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2094 "Option %s: There is no preset named %s\n"
2095 "Available presets are:", name, param);
2096 for (pre = obj_p->presets;
2097 (pre_name = M_ST_MB(char *, pre, obj_p->name_off)); pre += s)
2098 mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %s", pre_name);
2099 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "\n");
2100 return M_OPT_INVALID;
2103 if (!dst)
2104 return 1;
2106 for (i = 0; in_desc->fields[i].name; i++) {
2107 const m_option_t *out_opt = m_option_list_find(out_desc->fields,
2108 in_desc->fields[i].name);
2109 if (!out_opt) {
2110 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2111 "Option %s: Unable to find the target option for field %s.\n"
2112 "Please report this to the developers.\n",
2113 name, in_desc->fields[i].name);
2114 return M_OPT_PARSER_ERR;
2116 m_option_copy(out_opt, M_ST_MB_P(dst, out_opt->p),
2117 M_ST_MB_P(pre, in_desc->fields[i].p));
2119 return 1;
2123 const m_option_type_t m_option_type_obj_presets = {
2124 "Object presets",
2128 parse_obj_presets,
2129 NULL,
2130 NULL,
2131 NULL,
2132 NULL,
2133 NULL
2136 static int parse_custom_url(const m_option_t *opt, const char *name,
2137 const char *url, void *dst, int src)
2139 int pos1, pos2, r, v6addr = 0;
2140 char *ptr1 = NULL, *ptr2 = NULL, *ptr3 = NULL, *ptr4 = NULL;
2141 m_struct_t *desc = opt->priv;
2143 if (!desc) {
2144 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Custom URL needs "
2145 "a pointer to a m_struct_t in the priv field.\n", name);
2146 return M_OPT_PARSER_ERR;
2149 // extract the protocol
2150 ptr1 = strstr(url, "://");
2151 if (ptr1 == NULL) {
2152 // Filename only
2153 if (m_option_list_find(desc->fields, "filename")) {
2154 m_struct_set(desc, dst, "filename", url);
2155 return 1;
2157 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2158 "Option %s: URL doesn't have a valid protocol!\n", name);
2159 return M_OPT_INVALID;
2161 if (m_option_list_find(desc->fields, "string")) {
2162 if (strlen(ptr1) > 3) {
2163 m_struct_set(desc, dst, "string", ptr1 + 3);
2164 return 1;
2167 pos1 = ptr1 - url;
2168 if (dst && m_option_list_find(desc->fields, "protocol")) {
2169 ptr1[0] = '\0';
2170 r = m_struct_set(desc, dst, "protocol", url);
2171 ptr1[0] = ':';
2172 if (r < 0) {
2173 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2174 "Option %s: Error while setting protocol.\n", name);
2175 return r;
2179 // jump the "://"
2180 ptr1 += 3;
2181 pos1 += 3;
2183 // check if a username:password is given
2184 ptr2 = strstr(ptr1, "@");
2185 ptr3 = strstr(ptr1, "/");
2186 if (ptr3 != NULL && ptr3 < ptr2) {
2187 // it isn't really a username but rather a part of the path
2188 ptr2 = NULL;
2190 if (ptr2 != NULL) {
2192 // We got something, at least a username...
2193 if (!m_option_list_find(desc->fields, "username")) {
2194 mp_msg(MSGT_CFGPARSER, MSGL_WARN,
2195 "Option %s: This URL doesn't have a username part.\n", name);
2196 // skip
2197 } else {
2198 ptr3 = strstr(ptr1, ":");
2199 if (ptr3 != NULL && ptr3 < ptr2) {
2200 // We also have a password
2201 if (!m_option_list_find(desc->fields, "password")) {
2202 mp_msg(MSGT_CFGPARSER, MSGL_WARN,
2203 "Option %s: This URL doesn't have a password part.\n",
2204 name);
2205 // skip
2206 } else { // Username and password
2207 if (dst) {
2208 ptr3[0] = '\0';
2209 r = m_struct_set(desc, dst, "username", ptr1);
2210 ptr3[0] = ':';
2211 if (r < 0) {
2212 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2213 "Option %s: Error while setting username.\n",
2214 name);
2215 return r;
2217 ptr2[0] = '\0';
2218 r = m_struct_set(desc, dst, "password", ptr3 + 1);
2219 ptr2[0] = '@';
2220 if (r < 0) {
2221 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2222 "Option %s: Error while setting password.\n",
2223 name);
2224 return r;
2228 } else { // User name only
2229 ptr2[0] = '\0';
2230 r = m_struct_set(desc, dst, "username", ptr1);
2231 ptr2[0] = '@';
2232 if (r < 0) {
2233 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2234 "Option %s: Error while setting username.\n", name);
2235 return r;
2239 ptr1 = ptr2 + 1;
2240 pos1 = ptr1 - url;
2243 // Before looking for a port number check if we have an IPv6 type
2244 // numeric address.
2245 // In an IPv6 URL the numeric address should be inside square braces.
2246 ptr2 = strstr(ptr1, "[");
2247 ptr3 = strstr(ptr1, "]");
2248 // If the [] is after the first it isn't the hostname
2249 ptr4 = strstr(ptr1, "/");
2250 if (ptr2 != NULL && ptr3 != NULL && (ptr2 < ptr3)
2251 && (!ptr4 || ptr4 > ptr3)) {
2252 // we have an IPv6 numeric address
2253 ptr1++;
2254 pos1++;
2255 ptr2 = ptr3;
2256 v6addr = 1;
2257 } else
2258 ptr2 = ptr1;
2260 // look if the port is given
2261 ptr2 = strstr(ptr2, ":");
2262 // If the : is after the first / it isn't the port
2263 ptr3 = strstr(ptr1, "/");
2264 if (ptr3 && ptr3 - ptr2 < 0)
2265 ptr2 = NULL;
2266 if (ptr2 == NULL) {
2267 // No port is given
2268 // Look if a path is given
2269 if (ptr3 == NULL) {
2270 // No path/filename
2271 // So we have an URL like http://www.hostname.com
2272 pos2 = strlen(url);
2273 } else {
2274 // We have an URL like http://www.hostname.com/file.txt
2275 pos2 = ptr3 - url;
2277 } else {
2278 // We have an URL beginning like http://www.hostname.com:1212
2279 // Get the port number
2280 if (!m_option_list_find(desc->fields, "port")) {
2281 mp_msg(MSGT_CFGPARSER, MSGL_WARN,
2282 "Option %s: This URL doesn't have a port part.\n", name);
2283 // skip
2284 } else {
2285 if (dst) {
2286 int p = atoi(ptr2 + 1);
2287 char tmp[100];
2288 snprintf(tmp, 99, "%d", p);
2289 r = m_struct_set(desc, dst, "port", tmp);
2290 if (r < 0) {
2291 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2292 "Option %s: Error while setting port.\n", name);
2293 return r;
2297 pos2 = ptr2 - url;
2299 if (v6addr)
2300 pos2--;
2301 // Get the hostname
2302 if (pos2 - pos1 > 0) {
2303 if (!m_option_list_find(desc->fields, "hostname")) {
2304 mp_msg(MSGT_CFGPARSER, MSGL_WARN,
2305 "Option %s: This URL doesn't have a hostname part.\n", name);
2306 // skip
2307 } else {
2308 char tmp[pos2 - pos1 + 1];
2309 strncpy(tmp, ptr1, pos2 - pos1);
2310 tmp[pos2 - pos1] = '\0';
2311 r = m_struct_set(desc, dst, "hostname", tmp);
2312 if (r < 0) {
2313 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2314 "Option %s: Error while setting hostname.\n", name);
2315 return r;
2319 // Look if a path is given
2320 ptr2 = strstr(ptr1, "/");
2321 if (ptr2 != NULL) {
2322 // A path/filename is given
2323 // check if it's not a trailing '/'
2324 if (strlen(ptr2) > 1) {
2325 // copy the path/filename in the URL container
2326 if (!m_option_list_find(desc->fields, "filename")) {
2327 mp_msg(MSGT_CFGPARSER, MSGL_WARN,
2328 "Option %s: This URL doesn't have a hostname part.\n",
2329 name);
2330 // skip
2331 } else {
2332 if (dst) {
2333 int l = strlen(ptr2 + 1) + 1;
2334 char *fname = ptr2 + 1;
2335 if (l > 1) {
2336 fname = talloc_size(NULL, l);
2337 url_unescape_string(fname, ptr2 + 1);
2339 r = m_struct_set(desc, dst, "filename", fname);
2340 if (fname != ptr2 + 1)
2341 talloc_free(fname);
2342 if (r < 0) {
2343 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2344 "Option %s: Error while setting filename.\n",
2345 name);
2346 return r;
2352 return 1;
2355 /// TODO : Write the other needed funcs for 'normal' options
2356 const m_option_type_t m_option_type_custom_url = {
2357 "Custom URL",
2361 parse_custom_url,
2362 NULL,
2363 NULL,
2364 NULL,
2365 NULL,
2366 NULL