VO: clean up aspect.c, remove aspecttest tool
[mplayer.git] / m_option.c
blobefdba636b15657197e8c79cc50536e02e78afad4
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 // Don't free for 'production' atm
39 #ifndef MP_DEBUG
40 //#define NO_FREE
41 #endif
43 const m_option_t *m_option_list_find(const m_option_t *list, const char *name)
45 int i;
47 for (i = 0; list[i].name; i++) {
48 int l = strlen(list[i].name) - 1;
49 if ((list[i].type->flags & M_OPT_TYPE_ALLOW_WILDCARD)
50 && (l > 0) && (list[i].name[l] == '*')) {
51 if (strncasecmp(list[i].name, name, l) == 0)
52 return &list[i];
53 } else if (strcasecmp(list[i].name, name) == 0)
54 return &list[i];
56 return NULL;
59 // Default function that just does a memcpy
61 static void copy_opt(const m_option_t *opt, void *dst, const void *src)
63 if (dst && src)
64 memcpy(dst, src, opt->type->size);
67 // Flag
69 #define VAL(x) (*(int *)(x))
71 static int parse_flag(const m_option_t *opt, const char *name,
72 const char *param, void *dst, int src)
74 if (src == M_CONFIG_FILE) {
75 if (!param)
76 return M_OPT_MISSING_PARAM;
77 if (!strcasecmp(param, "yes") || /* any other language? */
78 !strcasecmp(param, "on") ||
79 !strcasecmp(param, "ja") ||
80 !strcasecmp(param, "si") ||
81 !strcasecmp(param, "igen") ||
82 !strcasecmp(param, "y") ||
83 !strcasecmp(param, "j") ||
84 !strcasecmp(param, "i") ||
85 !strcasecmp(param, "tak") ||
86 !strcasecmp(param, "ja") ||
87 !strcasecmp(param, "true") ||
88 !strcmp(param, "1")) {
89 if (dst)
90 VAL(dst) = opt->max;
91 } else if (!strcasecmp(param, "no") ||
92 !strcasecmp(param, "off") ||
93 !strcasecmp(param, "nein") ||
94 !strcasecmp(param, "nicht") ||
95 !strcasecmp(param, "nem") ||
96 !strcasecmp(param, "n") ||
97 !strcasecmp(param, "nie") ||
98 !strcasecmp(param, "nej") ||
99 !strcasecmp(param, "false") ||
100 !strcmp(param, "0")) {
101 if (dst)
102 VAL(dst) = opt->min;
103 } else {
104 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
105 "Invalid parameter for %s flag: %s\n", name, param);
106 return M_OPT_INVALID;
108 return 1;
109 } else {
110 if (dst)
111 VAL(dst) = opt->max;
112 return 0;
116 static char *print_flag(const m_option_t *opt, const void *val)
118 if (VAL(val) == opt->min)
119 return talloc_strdup(NULL, "no");
120 else
121 return talloc_strdup(NULL, "yes");
124 const m_option_type_t m_option_type_flag = {
125 "Flag",
126 "need yes or no in config files",
127 sizeof(int),
129 parse_flag,
130 print_flag,
131 copy_opt,
132 copy_opt,
133 NULL,
134 NULL
137 // Integer
139 static int parse_int(const m_option_t *opt, const char *name,
140 const char *param, void *dst, int src)
142 long long tmp_int;
143 char *endptr;
144 src = 0;
146 if (param == NULL)
147 return M_OPT_MISSING_PARAM;
149 tmp_int = strtoll(param, &endptr, 10);
150 if (*endptr)
151 tmp_int = strtoll(param, &endptr, 0);
152 if (*endptr) {
153 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
154 "The %s option must be an integer: %s\n", name, param);
155 return M_OPT_INVALID;
158 if ((opt->flags & M_OPT_MIN) && (tmp_int < opt->min)) {
159 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
160 "The %s option must be >= %d: %s\n",
161 name, (int) opt->min, param);
162 return M_OPT_OUT_OF_RANGE;
165 if ((opt->flags & M_OPT_MAX) && (tmp_int > opt->max)) {
166 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
167 "The %s option must be <= %d: %s\n",
168 name, (int) opt->max, param);
169 return M_OPT_OUT_OF_RANGE;
172 if (dst) {
173 if (opt->type->size == sizeof(int64_t))
174 *(int64_t *)dst = tmp_int;
175 else
176 VAL(dst) = tmp_int;
179 return 1;
182 static char *print_int(const m_option_t *opt, const void *val)
184 if (opt->type->size == sizeof(int64_t))
185 return talloc_asprintf(NULL, "%"PRId64, *(const int64_t *)val);
186 return talloc_asprintf(NULL, "%d", VAL(val));
189 const m_option_type_t m_option_type_int = {
190 "Integer",
192 sizeof(int),
194 parse_int,
195 print_int,
196 copy_opt,
197 copy_opt,
198 NULL,
199 NULL
202 const m_option_type_t m_option_type_int64 = {
203 "Integer64",
205 sizeof(int64_t),
207 parse_int,
208 print_int,
209 copy_opt,
210 copy_opt,
211 NULL,
212 NULL
215 static int parse_intpair(const struct m_option *opt, const char *name,
216 const char *param, void *dst, int src)
218 if (param == NULL)
219 return M_OPT_MISSING_PARAM;
221 char *s = (char *)param;
222 int start = -1;
223 int end = -1;
224 if (*s) {
225 start = strtol(s, &s, 10);
226 if (s == param)
227 goto bad;
229 if (*s) {
230 if (*s != '-')
231 goto bad;
232 s++;
234 if (*s)
235 end = strtol(s, &s, 10);
236 if (*s)
237 goto bad;
239 if (dst) {
240 int *p = dst;
241 p[0] = start;
242 p[1] = end;
245 return 1;
247 bad:
248 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid integer range "
249 "specification for option %s: %s\n", name, param);
250 return M_OPT_INVALID;
253 const struct m_option_type m_option_type_intpair = {
254 .name = "Int[-Int]",
255 .size = sizeof(int[2]),
256 .parse = parse_intpair,
257 .save = copy_opt,
258 .set = copy_opt,
261 static int parse_choice(const struct m_option *opt, const char *name,
262 const char *param, void *dst, int src)
264 if (param == NULL)
265 return M_OPT_MISSING_PARAM;
267 struct m_opt_choice_alternatives *alt;
268 for (alt = opt->priv; alt->name; alt++)
269 if (!strcmp(param, alt->name))
270 break;
271 if (!alt->name) {
272 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid value for option %s: %s\n",
273 name, param);
274 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Valid values are:");
275 for (alt = opt->priv; alt->name; alt++)
276 mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %s", alt->name);
277 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "\n");
278 return M_OPT_INVALID;
280 if (dst)
281 *(int *)dst = alt->value;
283 return 1;
286 static char *print_choice(const m_option_t *opt, const void *val)
288 int v = *(int *)val;
289 struct m_opt_choice_alternatives *alt;
290 for (alt = opt->priv; alt->name; alt++)
291 if (alt->value == v)
292 return talloc_strdup(NULL, alt->name);
293 abort();
296 const struct m_option_type m_option_type_choice = {
297 .name = "String", // same as arbitrary strings in option list for now
298 .size = sizeof(int),
299 .parse = parse_choice,
300 .print = print_choice,
301 .save = copy_opt,
302 .set = copy_opt,
305 // Float
307 #undef VAL
308 #define VAL(x) (*(double *)(x))
310 static int parse_double(const m_option_t *opt, const char *name,
311 const char *param, void *dst, int src)
313 double tmp_float;
314 char *endptr;
315 src = 0;
317 if (param == NULL)
318 return M_OPT_MISSING_PARAM;
320 tmp_float = strtod(param, &endptr);
322 switch (*endptr) {
323 case ':':
324 case '/':
325 tmp_float /= strtod(endptr + 1, &endptr);
326 break;
327 case '.':
328 case ',':
329 /* we also handle floats specified with
330 * non-locale decimal point ::atmos
332 if (tmp_float < 0)
333 tmp_float -= 1.0 / pow(10, strlen(endptr + 1)) *
334 strtod(endptr + 1, &endptr);
335 else
336 tmp_float += 1.0 / pow(10, strlen(endptr + 1)) *
337 strtod(endptr + 1, &endptr);
338 break;
341 if (*endptr) {
342 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
343 "The %s option must be a floating point number or a "
344 "ratio (numerator[:/]denominator): %s\n", name, param);
345 return M_OPT_INVALID;
348 if (opt->flags & M_OPT_MIN)
349 if (tmp_float < opt->min) {
350 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
351 "The %s option must be >= %f: %s\n", name, opt->min, param);
352 return M_OPT_OUT_OF_RANGE;
355 if (opt->flags & M_OPT_MAX)
356 if (tmp_float > opt->max) {
357 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
358 "The %s option must be <= %f: %s\n", name, opt->max, param);
359 return M_OPT_OUT_OF_RANGE;
362 if (dst)
363 VAL(dst) = tmp_float;
364 return 1;
367 static char *print_double(const m_option_t *opt, const void *val)
369 opt = NULL;
370 return talloc_asprintf(NULL, "%f", VAL(val));
373 const m_option_type_t m_option_type_double = {
374 "Double",
375 "double precision floating point number or ratio (numerator[:/]denominator)",
376 sizeof(double),
378 parse_double,
379 print_double,
380 copy_opt,
381 copy_opt,
382 NULL,
383 NULL
386 #undef VAL
387 #define VAL(x) (*(float *)(x))
389 static int parse_float(const m_option_t *opt, const char *name,
390 const char *param, void *dst, int src)
392 double tmp;
393 int r = parse_double(opt, name, param, &tmp, src);
394 if (r == 1 && dst)
395 VAL(dst) = tmp;
396 return r;
399 static char *print_float(const m_option_t *opt, const void *val)
401 opt = NULL;
402 return talloc_asprintf(NULL, "%f", VAL(val));
405 const m_option_type_t m_option_type_float = {
406 "Float",
407 "floating point number or ratio (numerator[:/]denominator)",
408 sizeof(float),
410 parse_float,
411 print_float,
412 copy_opt,
413 copy_opt,
414 NULL,
415 NULL
418 ///////////// Position
419 #undef VAL
420 #define VAL(x) (*(off_t *)(x))
422 static int parse_position(const m_option_t *opt, const char *name,
423 const char *param, void *dst, int src)
425 off_t tmp_off;
426 char dummy;
428 if (param == NULL)
429 return M_OPT_MISSING_PARAM;
430 if (sscanf(param, sizeof(off_t) == sizeof(int) ?
431 "%d%c" : "%"PRId64"%c", &tmp_off, &dummy) != 1) {
432 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
433 "The %s option must be an integer: %s\n", opt->name, param);
434 return M_OPT_INVALID;
437 if (opt->flags & M_OPT_MIN)
438 if (tmp_off < opt->min) {
439 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
440 "The %s option must be >= %"PRId64 ": %s\n",
441 name, (int64_t) opt->min, param);
442 return M_OPT_OUT_OF_RANGE;
445 if (opt->flags & M_OPT_MAX)
446 if (tmp_off > opt->max) {
447 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
448 "The %s option must be <= %"PRId64 ": %s\n",
449 name, (int64_t) opt->max, param);
450 return M_OPT_OUT_OF_RANGE;
453 if (dst)
454 VAL(dst) = tmp_off;
455 return 1;
458 static char *print_position(const m_option_t *opt, const void *val)
460 return talloc_asprintf(NULL, "%"PRId64, (int64_t)VAL(val));
463 const m_option_type_t m_option_type_position = {
464 "Position",
465 "Integer (off_t)",
466 sizeof(off_t),
468 parse_position,
469 print_position,
470 copy_opt,
471 copy_opt,
472 NULL,
473 NULL
477 ///////////// String
479 #undef VAL
480 #define VAL(x) (*(char **)(x))
482 static int parse_str(const m_option_t *opt, const char *name,
483 const char *param, void *dst, int src)
487 if (param == NULL)
488 return M_OPT_MISSING_PARAM;
490 if ((opt->flags & M_OPT_MIN) && (strlen(param) < opt->min)) {
491 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Parameter must be >= %d chars: %s\n",
492 (int) opt->min, param);
493 return M_OPT_OUT_OF_RANGE;
496 if ((opt->flags & M_OPT_MAX) && (strlen(param) > opt->max)) {
497 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Parameter must be <= %d chars: %s\n",
498 (int) opt->max, param);
499 return M_OPT_OUT_OF_RANGE;
502 if (dst) {
503 free(VAL(dst));
504 VAL(dst) = strdup(param);
507 return 1;
511 static char *print_str(const m_option_t *opt, const void *val)
513 return (val && VAL(val)) ? talloc_strdup(NULL, VAL(val)) : NULL;
516 static void copy_str(const m_option_t *opt, void *dst, const void *src)
518 if (dst && src) {
519 #ifndef NO_FREE
520 free(VAL(dst)); //FIXME!!!
521 #endif
522 VAL(dst) = VAL(src) ? strdup(VAL(src)) : NULL;
526 static void free_str(void *src)
528 if (src && VAL(src)) {
529 #ifndef NO_FREE
530 free(VAL(src)); //FIXME!!!
531 #endif
532 VAL(src) = NULL;
536 const m_option_type_t m_option_type_string = {
537 "String",
539 sizeof(char *),
540 M_OPT_TYPE_DYNAMIC,
541 parse_str,
542 print_str,
543 copy_str,
544 copy_str,
545 copy_str,
546 free_str
549 //////////// String list
551 #undef VAL
552 #define VAL(x) (*(char ***)(x))
554 #define OP_NONE 0
555 #define OP_ADD 1
556 #define OP_PRE 2
557 #define OP_DEL 3
558 #define OP_CLR 4
560 static void free_str_list(void *dst)
562 char **d;
563 int i;
565 if (!dst || !VAL(dst))
566 return;
567 d = VAL(dst);
569 // FIXME!!!
570 #ifndef NO_FREE
571 for (i = 0; d[i] != NULL; i++)
572 free(d[i]);
573 free(d);
574 #endif
575 VAL(dst) = NULL;
578 static int str_list_add(char **add, int n, void *dst, int pre)
580 char **lst = VAL(dst);
581 int ln;
583 if (!dst)
584 return M_OPT_PARSER_ERR;
585 lst = VAL(dst);
587 for (ln = 0; lst && lst[ln]; ln++)
588 /**/;
590 lst = realloc(lst, (n + ln + 1) * sizeof(char *));
592 if (pre) {
593 memmove(&lst[n], lst, ln * sizeof(char *));
594 memcpy(lst, add, n * sizeof(char *));
595 } else
596 memcpy(&lst[ln], add, n * sizeof(char *));
597 // (re-)add NULL-termination
598 lst[ln + n] = NULL;
600 free(add);
602 VAL(dst) = lst;
604 return 1;
607 static int str_list_del(char **del, int n, void *dst)
609 char **lst, *ep, **d;
610 int i, ln, s;
611 long idx;
613 if (!dst)
614 return M_OPT_PARSER_ERR;
615 lst = VAL(dst);
617 for (ln = 0; lst && lst[ln]; ln++)
618 /**/;
619 s = ln;
621 for (i = 0; del[i] != NULL; i++) {
622 idx = strtol(del[i], &ep, 0);
623 if (*ep) {
624 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid index: %s\n", del[i]);
625 free(del[i]);
626 continue;
628 free(del[i]);
629 if (idx < 0 || idx >= ln) {
630 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
631 "Index %ld is out of range.\n", idx);
632 continue;
633 } else if (!lst[idx])
634 continue;
635 free(lst[idx]);
636 lst[idx] = NULL;
637 s--;
639 free(del);
641 if (s == 0) {
642 free(lst);
643 VAL(dst) = NULL;
644 return 1;
647 d = calloc(s + 1, sizeof(char *));
648 for (i = 0, n = 0; i < ln; i++) {
649 if (!lst[i])
650 continue;
651 d[n] = lst[i];
652 n++;
654 d[s] = NULL;
656 free(lst);
657 VAL(dst) = d;
659 return 1;
662 static char *get_nextsep(char *ptr, char sep, int modify)
664 char *last_ptr = ptr;
665 for (;;) {
666 ptr = strchr(ptr, sep);
667 if (ptr && ptr > last_ptr && ptr[-1] == '\\') {
668 if (modify)
669 memmove(ptr - 1, ptr, strlen(ptr) + 1);
670 else
671 ptr++;
672 } else
673 break;
675 return ptr;
678 static int parse_str_list(const m_option_t *opt, const char *name,
679 const char *param, void *dst, int src)
681 int n = 0, len = strlen(opt->name);
682 char *str;
683 char *ptr = (char *)param, *last_ptr, **res;
684 int op = OP_NONE;
686 if (opt->name[len - 1] == '*' && ((int)strlen(name) > len - 1)) {
687 const char *n = &name[len - 1];
688 if (strcasecmp(n, "-add") == 0)
689 op = OP_ADD;
690 else if (strcasecmp(n, "-pre") == 0)
691 op = OP_PRE;
692 else if (strcasecmp(n, "-del") == 0)
693 op = OP_DEL;
694 else if (strcasecmp(n, "-clr") == 0)
695 op = OP_CLR;
696 else
697 return M_OPT_UNKNOWN;
700 // Clear the list ??
701 if (op == OP_CLR) {
702 if (dst)
703 free_str_list(dst);
704 return 0;
707 // All other ops need a param
708 if (param == NULL || strlen(param) == 0)
709 return M_OPT_MISSING_PARAM;
711 // custom type for "profile" calls this but uses ->priv for something else
712 char separator = opt->type == &m_option_type_string_list && opt->priv ?
713 *(char *)opt->priv : OPTION_LIST_SEPARATOR;
714 while (ptr[0] != '\0') {
715 ptr = get_nextsep(ptr, separator, 0);
716 if (!ptr) {
717 n++;
718 break;
720 ptr++;
721 n++;
723 if (n == 0)
724 return M_OPT_INVALID;
725 if (((opt->flags & M_OPT_MIN) && (n < opt->min)) ||
726 ((opt->flags & M_OPT_MAX) && (n > opt->max)))
727 return M_OPT_OUT_OF_RANGE;
729 if (!dst)
730 return 1;
732 res = malloc((n + 2) * sizeof(char *));
733 ptr = str = strdup(param);
734 n = 0;
736 while (1) {
737 last_ptr = ptr;
738 ptr = get_nextsep(ptr, separator, 1);
739 if (!ptr) {
740 res[n] = strdup(last_ptr);
741 n++;
742 break;
744 len = ptr - last_ptr;
745 res[n] = malloc(len + 1);
746 if (len)
747 strncpy(res[n], last_ptr, len);
748 res[n][len] = '\0';
749 ptr++;
750 n++;
752 res[n] = NULL;
753 free(str);
755 switch (op) {
756 case OP_ADD:
757 return str_list_add(res, n, dst, 0);
758 case OP_PRE:
759 return str_list_add(res, n, dst, 1);
760 case OP_DEL:
761 return str_list_del(res, n, dst);
764 if (VAL(dst))
765 free_str_list(dst);
766 VAL(dst) = res;
768 return 1;
771 static void copy_str_list(const m_option_t *opt, void *dst, const void *src)
773 int n;
774 char **d, **s;
776 if (!(dst && src))
777 return;
778 s = VAL(src);
780 if (VAL(dst))
781 free_str_list(dst);
783 if (!s) {
784 VAL(dst) = NULL;
785 return;
788 for (n = 0; s[n] != NULL; n++)
789 /* NOTHING */;
790 d = malloc((n + 1) * sizeof(char *));
791 for (; n >= 0; n--)
792 d[n] = s[n] ? strdup(s[n]) : NULL;
794 VAL(dst) = d;
797 static char *print_str_list(const m_option_t *opt, const void *src)
799 char **lst = NULL;
800 char *ret = NULL;
802 if (!(src && VAL(src)))
803 return NULL;
804 lst = VAL(src);
806 for (int i = 0; lst[i]; i++) {
807 if (ret)
808 ret = talloc_strdup_append_buffer(ret, ",");
809 ret = talloc_strdup_append_buffer(ret, lst[i]);
811 return ret;
814 const m_option_type_t m_option_type_string_list = {
815 "String list",
816 "A list of strings separated by ','\n"
817 "Option with a name ending in an * permits using the following suffix: \n"
818 "\t-add: Add the given parameters at the end of the list.\n"
819 "\t-pre: Add the given parameters at the beginning of the list.\n"
820 "\t-del: Remove the entry at the given indices.\n"
821 "\t-clr: Clear the list.\n"
822 "e.g: -vf-add flip,mirror -vf-del 2,5\n",
823 sizeof(char **),
824 M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD,
825 parse_str_list,
826 print_str_list,
827 copy_str_list,
828 copy_str_list,
829 copy_str_list,
830 free_str_list
834 /////////////////// Func based options
836 // A chained list to save the various calls for func_param
837 typedef struct m_func_save m_func_save_t;
838 struct m_func_save {
839 m_func_save_t *next;
840 char *name;
841 char *param;
844 #undef VAL
845 #define VAL(x) (*(m_func_save_t **)(x))
847 static void free_func_pf(void *src)
849 m_func_save_t *s, *n;
851 if (!src)
852 return;
854 s = VAL(src);
856 while (s) {
857 n = s->next;
858 free(s->name);
859 free(s->param);
860 free(s);
861 s = n;
863 VAL(src) = NULL;
866 // Parser for func_param
867 static int parse_func_pf(const m_option_t *opt, const char *name,
868 const char *param, void *dst, int src)
870 m_func_save_t *s, *p;
872 if (!dst)
873 return 1;
875 s = calloc(1, sizeof(m_func_save_t));
876 s->name = strdup(name);
877 s->param = param ? strdup(param) : NULL;
879 p = VAL(dst);
880 if (p) {
881 for (; p->next != NULL; p = p->next)
882 /**/;
883 p->next = s;
884 } else
885 VAL(dst) = s;
887 return 1;
890 static void copy_func_pf(const m_option_t *opt, void *dst, const void *src)
892 m_func_save_t *d = NULL, *s, *last = NULL;
894 if (!(dst && src))
895 return;
896 s = VAL(src);
898 if (VAL(dst))
899 free_func_pf(dst);
901 while (s) {
902 d = calloc(1, sizeof(m_func_save_t));
903 d->name = strdup(s->name);
904 d->param = s->param ? strdup(s->param) : NULL;
905 if (last)
906 last->next = d;
907 else
908 VAL(dst) = d;
909 last = d;
910 s = s->next;
916 /////////////////// Func_param
918 static void set_func_param(const m_option_t *opt, void *dst, const void *src)
920 m_func_save_t *s;
922 if (!src)
923 return;
924 s = VAL(src);
926 if (!s)
927 return;
929 for (; s != NULL; s = s->next)
930 ((m_opt_func_param_t) opt->p)(opt, s->param);
933 const m_option_type_t m_option_type_func_param = {
934 "Func param",
936 sizeof(m_func_save_t *),
937 M_OPT_TYPE_INDIRECT,
938 parse_func_pf,
939 NULL,
940 NULL, // Nothing to do on save
941 set_func_param,
942 copy_func_pf,
943 free_func_pf
946 /////////////// Func
948 #undef VAL
950 static int parse_func(const m_option_t *opt, const char *name,
951 const char *param, void *dst, int src)
953 return 0;
956 static void set_func(const m_option_t *opt, void *dst, const void *src)
958 ((m_opt_func_t) opt->p)(opt);
961 const m_option_type_t m_option_type_func = {
962 "Func",
964 sizeof(int),
965 M_OPT_TYPE_INDIRECT,
966 parse_func,
967 NULL,
968 NULL, // Nothing to do on save
969 set_func,
970 NULL,
971 NULL
974 /////////////////// Print
976 static int parse_print(const m_option_t *opt, const char *name,
977 const char *param, void *dst, int src)
979 if (opt->type == CONF_TYPE_PRINT_INDIRECT)
980 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", *(char **) opt->p);
981 else if (opt->type == CONF_TYPE_PRINT_FUNC)
982 return ((m_opt_func_full_t) opt->p)(opt, name, param);
983 else
984 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", mp_gtext(opt->p));
986 if (opt->priv == NULL)
987 return M_OPT_EXIT;
988 return 0;
991 const m_option_type_t m_option_type_print = {
992 "Print",
996 parse_print,
997 NULL,
998 NULL,
999 NULL,
1000 NULL,
1001 NULL
1004 const m_option_type_t m_option_type_print_indirect = {
1005 "Print",
1009 parse_print,
1010 NULL,
1011 NULL,
1012 NULL,
1013 NULL,
1014 NULL
1017 const m_option_type_t m_option_type_print_func = {
1018 "Print",
1021 M_OPT_TYPE_ALLOW_WILDCARD,
1022 parse_print,
1023 NULL,
1024 NULL,
1025 NULL,
1026 NULL,
1027 NULL
1031 /////////////////////// Subconfig
1032 #undef VAL
1033 #define VAL(x) (*(char ***)(x))
1035 static int parse_subconf(const m_option_t *opt, const char *name,
1036 const char *param, void *dst, int src)
1038 char *subparam;
1039 char *subopt;
1040 int nr = 0, i, r;
1041 const m_option_t *subopts;
1042 const char *p;
1043 char **lst = NULL;
1045 if (param == NULL || strlen(param) == 0)
1046 return M_OPT_MISSING_PARAM;
1048 subparam = malloc(strlen(param) + 1);
1049 subopt = malloc(strlen(param) + 1);
1050 p = param;
1052 subopts = opt->p;
1054 while (p[0]) {
1055 int sscanf_ret = 1;
1056 int optlen = strcspn(p, ":=");
1057 /* clear out */
1058 subopt[0] = subparam[0] = 0;
1059 av_strlcpy(subopt, p, optlen + 1);
1060 p = &p[optlen];
1061 if (p[0] == '=') {
1062 sscanf_ret = 2;
1063 p = &p[1];
1064 if (p[0] == '"') {
1065 p = &p[1];
1066 optlen = strcspn(p, "\"");
1067 av_strlcpy(subparam, p, optlen + 1);
1068 p = &p[optlen];
1069 if (p[0] != '"') {
1070 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1071 "Terminating '\"' missing for '%s'\n", subopt);
1072 return M_OPT_INVALID;
1074 p = &p[1];
1075 } else if (p[0] == '%') {
1076 p = &p[1];
1077 optlen = (int)strtol(p, (char **)&p, 0);
1078 if (!p || p[0] != '%' || (optlen > strlen(p) - 1)) {
1079 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1080 "Invalid length %i for '%s'\n", optlen, subopt);
1081 return M_OPT_INVALID;
1083 p = &p[1];
1084 av_strlcpy(subparam, p, optlen + 1);
1085 p = &p[optlen];
1086 } else {
1087 optlen = strcspn(p, ":");
1088 av_strlcpy(subparam, p, optlen + 1);
1089 p = &p[optlen];
1092 if (p[0] == ':')
1093 p = &p[1];
1094 else if (p[0]) {
1095 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1096 "Incorrect termination for '%s'\n", subopt);
1097 return M_OPT_INVALID;
1100 switch (sscanf_ret) {
1101 case 1:
1102 subparam[0] = 0;
1103 case 2:
1104 for (i = 0; subopts[i].name; i++)
1105 if (!strcmp(subopts[i].name, subopt))
1106 break;
1107 if (!subopts[i].name) {
1108 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1109 "Option %s: Unknown suboption %s\n", name, subopt);
1110 return M_OPT_UNKNOWN;
1112 r = m_option_parse(&subopts[i], subopt,
1113 subparam[0] == 0 ? NULL : subparam, NULL, src);
1114 if (r < 0)
1115 return r;
1116 if (dst) {
1117 lst = realloc(lst, 2 * (nr + 2) * sizeof(char *));
1118 lst[2 * nr] = strdup(subopt);
1119 lst[2 * nr + 1] = subparam[0] == 0 ? NULL : strdup(subparam);
1120 memset(&lst[2 * (nr + 1)], 0, 2 * sizeof(char *));
1121 nr++;
1123 break;
1127 free(subparam);
1128 free(subopt);
1129 if (dst)
1130 VAL(dst) = lst;
1132 return 1;
1135 const m_option_type_t m_option_type_subconfig = {
1136 "Subconfig",
1137 "The syntax is -option opt1=foo:flag:opt2=blah",
1138 sizeof(int),
1139 M_OPT_TYPE_HAS_CHILD,
1140 parse_subconf,
1141 NULL,
1142 NULL,
1143 NULL,
1144 NULL,
1145 NULL
1148 #include "libmpcodecs/img_format.h"
1150 /* FIXME: snyc with img_format.h */
1151 static struct {
1152 const char *name;
1153 unsigned int fmt;
1154 } mp_imgfmt_list[] = {
1155 {"444p16le", IMGFMT_444P16_LE},
1156 {"444p16be", IMGFMT_444P16_BE},
1157 {"444p10le", IMGFMT_444P10_LE},
1158 {"444p10be", IMGFMT_444P10_BE},
1159 {"444p9le", IMGFMT_444P9_LE},
1160 {"444p9be", IMGFMT_444P9_BE},
1161 {"422p16le", IMGFMT_422P16_LE},
1162 {"422p16be", IMGFMT_422P16_BE},
1163 {"422p10le", IMGFMT_422P10_LE},
1164 {"422p10be", IMGFMT_422P10_BE},
1165 {"420p16le", IMGFMT_420P16_LE},
1166 {"420p16be", IMGFMT_420P16_BE},
1167 {"420p10le", IMGFMT_420P10_LE},
1168 {"420p10be", IMGFMT_420P10_BE},
1169 {"420p9le", IMGFMT_420P9_LE},
1170 {"420p9be", IMGFMT_420P9_BE},
1171 {"444p16", IMGFMT_444P16},
1172 {"444p10", IMGFMT_444P10},
1173 {"444p9", IMGFMT_444P9},
1174 {"422p16", IMGFMT_422P16},
1175 {"422p10", IMGFMT_422P10},
1176 {"420p10", IMGFMT_420P10},
1177 {"420p9", IMGFMT_420P9},
1178 {"420p16", IMGFMT_420P16},
1179 {"420a", IMGFMT_420A},
1180 {"444p", IMGFMT_444P},
1181 {"422p", IMGFMT_422P},
1182 {"411p", IMGFMT_411P},
1183 {"440p", IMGFMT_440P},
1184 {"yuy2", IMGFMT_YUY2},
1185 {"uyvy", IMGFMT_UYVY},
1186 {"yvu9", IMGFMT_YVU9},
1187 {"if09", IMGFMT_IF09},
1188 {"yv12", IMGFMT_YV12},
1189 {"i420", IMGFMT_I420},
1190 {"iyuv", IMGFMT_IYUV},
1191 {"clpl", IMGFMT_CLPL},
1192 {"hm12", IMGFMT_HM12},
1193 {"y800", IMGFMT_Y800},
1194 {"y8", IMGFMT_Y8},
1195 {"nv12", IMGFMT_NV12},
1196 {"nv21", IMGFMT_NV21},
1197 {"bgr24", IMGFMT_BGR24},
1198 {"bgr32", IMGFMT_BGR32},
1199 {"bgr16", IMGFMT_BGR16},
1200 {"bgr15", IMGFMT_BGR15},
1201 {"bgr12", IMGFMT_BGR12},
1202 {"bgr8", IMGFMT_BGR8},
1203 {"bgr4", IMGFMT_BGR4},
1204 {"bg4b", IMGFMT_BG4B},
1205 {"bgr1", IMGFMT_BGR1},
1206 {"rgb48be", IMGFMT_RGB48BE},
1207 {"rgb48le", IMGFMT_RGB48LE},
1208 {"rgb48ne", IMGFMT_RGB48NE},
1209 {"rgb24", IMGFMT_RGB24},
1210 {"rgb32", IMGFMT_RGB32},
1211 {"rgb16", IMGFMT_RGB16},
1212 {"rgb15", IMGFMT_RGB15},
1213 {"rgb12", IMGFMT_RGB12},
1214 {"rgb8", IMGFMT_RGB8},
1215 {"rgb4", IMGFMT_RGB4},
1216 {"rg4b", IMGFMT_RG4B},
1217 {"rgb1", IMGFMT_RGB1},
1218 {"rgba", IMGFMT_RGBA},
1219 {"argb", IMGFMT_ARGB},
1220 {"bgra", IMGFMT_BGRA},
1221 {"abgr", IMGFMT_ABGR},
1222 {"mjpeg", IMGFMT_MJPEG},
1223 {"mjpg", IMGFMT_MJPEG},
1224 { NULL, 0 }
1227 static int parse_imgfmt(const m_option_t *opt, const char *name,
1228 const char *param, void *dst, int src)
1230 uint32_t fmt = 0;
1231 int i;
1233 if (param == NULL || strlen(param) == 0)
1234 return M_OPT_MISSING_PARAM;
1236 if (!strcmp(param, "help")) {
1237 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available formats:");
1238 for (i = 0; mp_imgfmt_list[i].name; i++)
1239 mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %s", mp_imgfmt_list[i].name);
1240 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n");
1241 return M_OPT_EXIT - 1;
1244 if (sscanf(param, "0x%x", &fmt) != 1) {
1245 for (i = 0; mp_imgfmt_list[i].name; i++) {
1246 if (!strcasecmp(param, mp_imgfmt_list[i].name)) {
1247 fmt = mp_imgfmt_list[i].fmt;
1248 break;
1251 if (!mp_imgfmt_list[i].name) {
1252 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1253 "Option %s: unknown format name: '%s'\n", name, param);
1254 return M_OPT_INVALID;
1258 if (dst)
1259 *((uint32_t *)dst) = fmt;
1261 return 1;
1264 const m_option_type_t m_option_type_imgfmt = {
1265 "Image format",
1266 "Please report any missing colorspaces.",
1267 sizeof(uint32_t),
1269 parse_imgfmt,
1270 NULL,
1271 copy_opt,
1272 copy_opt,
1273 NULL,
1274 NULL
1277 #include "libaf/af_format.h"
1279 /* FIXME: snyc with af_format.h */
1280 static struct {
1281 const char *name;
1282 unsigned int fmt;
1283 } mp_afmt_list[] = {
1284 // SPECIAL
1285 {"mulaw", AF_FORMAT_MU_LAW},
1286 {"alaw", AF_FORMAT_A_LAW},
1287 {"mpeg2", AF_FORMAT_MPEG2},
1288 {"ac3le", AF_FORMAT_AC3_LE},
1289 {"ac3be", AF_FORMAT_AC3_BE},
1290 {"ac3ne", AF_FORMAT_AC3_NE},
1291 {"imaadpcm", AF_FORMAT_IMA_ADPCM},
1292 // ORDINARY
1293 {"u8", AF_FORMAT_U8},
1294 {"s8", AF_FORMAT_S8},
1295 {"u16le", AF_FORMAT_U16_LE},
1296 {"u16be", AF_FORMAT_U16_BE},
1297 {"u16ne", AF_FORMAT_U16_NE},
1298 {"s16le", AF_FORMAT_S16_LE},
1299 {"s16be", AF_FORMAT_S16_BE},
1300 {"s16ne", AF_FORMAT_S16_NE},
1301 {"u24le", AF_FORMAT_U24_LE},
1302 {"u24be", AF_FORMAT_U24_BE},
1303 {"u24ne", AF_FORMAT_U24_NE},
1304 {"s24le", AF_FORMAT_S24_LE},
1305 {"s24be", AF_FORMAT_S24_BE},
1306 {"s24ne", AF_FORMAT_S24_NE},
1307 {"u32le", AF_FORMAT_U32_LE},
1308 {"u32be", AF_FORMAT_U32_BE},
1309 {"u32ne", AF_FORMAT_U32_NE},
1310 {"s32le", AF_FORMAT_S32_LE},
1311 {"s32be", AF_FORMAT_S32_BE},
1312 {"s32ne", AF_FORMAT_S32_NE},
1313 {"floatle", AF_FORMAT_FLOAT_LE},
1314 {"floatbe", AF_FORMAT_FLOAT_BE},
1315 {"floatne", AF_FORMAT_FLOAT_NE},
1316 { NULL, 0 }
1319 static int parse_afmt(const m_option_t *opt, const char *name,
1320 const char *param, void *dst, int src)
1322 uint32_t fmt = 0;
1323 int i;
1325 if (param == NULL || strlen(param) == 0)
1326 return M_OPT_MISSING_PARAM;
1328 if (!strcmp(param, "help")) {
1329 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available formats:");
1330 for (i = 0; mp_afmt_list[i].name; i++)
1331 mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %s", mp_afmt_list[i].name);
1332 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n");
1333 return M_OPT_EXIT - 1;
1336 if (sscanf(param, "0x%x", &fmt) != 1) {
1337 for (i = 0; mp_afmt_list[i].name; i++) {
1338 if (!strcasecmp(param, mp_afmt_list[i].name)) {
1339 fmt = mp_afmt_list[i].fmt;
1340 break;
1343 if (!mp_afmt_list[i].name) {
1344 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1345 "Option %s: unknown format name: '%s'\n", name, param);
1346 return M_OPT_INVALID;
1350 if (dst)
1351 *((uint32_t *)dst) = fmt;
1353 return 1;
1356 const m_option_type_t m_option_type_afmt = {
1357 "Audio format",
1358 "Please report any missing formats.",
1359 sizeof(uint32_t),
1361 parse_afmt,
1362 NULL,
1363 copy_opt,
1364 copy_opt,
1365 NULL,
1366 NULL
1370 int parse_timestring(const char *str, double *time, char endchar)
1372 int a, b, len;
1373 double d;
1374 *time = 0; /* ensure initialization for error cases */
1375 if (sscanf(str, "%d:%d:%lf%n", &a, &b, &d, &len) >= 3)
1376 *time = 3600 * a + 60 * b + d;
1377 else if (sscanf(str, "%d:%lf%n", &a, &d, &len) >= 2)
1378 *time = 60 * a + d;
1379 else if (sscanf(str, "%lf%n", &d, &len) >= 1)
1380 *time = d;
1381 else
1382 return 0; /* unsupported time format */
1383 if (str[len] && str[len] != endchar)
1384 return 0; /* invalid extra characters at the end */
1385 return len;
1389 static int parse_time(const m_option_t *opt, const char *name,
1390 const char *param, void *dst, int src)
1392 double time;
1394 if (param == NULL || strlen(param) == 0)
1395 return M_OPT_MISSING_PARAM;
1397 if (!parse_timestring(param, &time, 0)) {
1398 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: invalid time: '%s'\n",
1399 name, param);
1400 return M_OPT_INVALID;
1403 if (dst)
1404 *(double *)dst = time;
1405 return 1;
1408 const m_option_type_t m_option_type_time = {
1409 "Time",
1411 sizeof(double),
1413 parse_time,
1414 print_double,
1415 copy_opt,
1416 copy_opt,
1417 NULL,
1418 NULL
1422 // Time or size (-endpos)
1424 static int parse_time_size(const m_option_t *opt, const char *name,
1425 const char *param, void *dst, int src)
1427 m_time_size_t ts;
1428 char unit[4];
1429 double end_at;
1431 if (param == NULL || strlen(param) == 0)
1432 return M_OPT_MISSING_PARAM;
1434 ts.pos = 0;
1435 /* End at size parsing */
1436 if (sscanf(param, "%lf%3s", &end_at, unit) == 2) {
1437 ts.type = END_AT_SIZE;
1438 if (!strcasecmp(unit, "b"))
1440 else if (!strcasecmp(unit, "kb"))
1441 end_at *= 1024;
1442 else if (!strcasecmp(unit, "mb"))
1443 end_at *= 1024 * 1024;
1444 else if (!strcasecmp(unit, "gb"))
1445 end_at *= 1024 * 1024 * 1024;
1446 else
1447 ts.type = END_AT_NONE;
1449 if (ts.type == END_AT_SIZE) {
1450 ts.pos = end_at;
1451 goto out;
1455 /* End at time parsing. This has to be last because the parsing accepts
1456 * even a number followed by garbage */
1457 if (!parse_timestring(param, &end_at, 0)) {
1458 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1459 "Option %s: invalid time or size: '%s'\n",
1460 name, param);
1461 return M_OPT_INVALID;
1464 ts.type = END_AT_TIME;
1465 ts.pos = end_at;
1466 out:
1467 if (dst)
1468 *(m_time_size_t *)dst = ts;
1469 return 1;
1472 const m_option_type_t m_option_type_time_size = {
1473 "Time or size",
1475 sizeof(m_time_size_t),
1477 parse_time_size,
1478 NULL,
1479 copy_opt,
1480 copy_opt,
1481 NULL,
1482 NULL
1486 //// Objects (i.e. filters, etc) settings
1488 #include "m_struct.h"
1490 #undef VAL
1491 #define VAL(x) (*(m_obj_settings_t **)(x))
1493 static int find_obj_desc(const char *name, const m_obj_list_t *l,
1494 const m_struct_t **ret)
1496 int i;
1497 char *n;
1499 for (i = 0; l->list[i]; i++) {
1500 n = M_ST_MB(char *, l->list[i], l->name_off);
1501 if (!strcmp(n, name)) {
1502 *ret = M_ST_MB(m_struct_t *, l->list[i], l->desc_off);
1503 return 1;
1506 return 0;
1509 static int get_obj_param(const char *opt_name, const char *obj_name,
1510 const m_struct_t *desc, char *str, int *nold,
1511 int oldmax, char **dst)
1513 char *eq;
1514 const m_option_t *opt;
1515 int r;
1517 eq = strchr(str, '=');
1518 if (eq && eq == str)
1519 eq = NULL;
1521 if (eq) {
1522 char *p = eq + 1;
1523 if (p[0] == '\0')
1524 p = NULL;
1525 eq[0] = '\0';
1526 opt = m_option_list_find(desc->fields, str);
1527 if (!opt) {
1528 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1529 "Option %s: %s doesn't have a %s parameter.\n",
1530 opt_name, obj_name, str);
1531 return M_OPT_UNKNOWN;
1533 r = m_option_parse(opt, str, p, NULL, M_CONFIG_FILE);
1534 if (r < 0) {
1535 if (r > M_OPT_EXIT)
1536 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1537 "Option %s: Error while parsing %s parameter %s (%s)\n",
1538 opt_name, obj_name, str, p);
1539 eq[0] = '=';
1540 return r;
1542 if (dst) {
1543 dst[0] = strdup(str);
1544 dst[1] = p ? strdup(p) : NULL;
1546 eq[0] = '=';
1547 } else {
1548 if ((*nold) >= oldmax) {
1549 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: %s has only %d params, so you can't give more than %d unnamed params.\n",
1550 opt_name, obj_name, oldmax, oldmax);
1551 return M_OPT_OUT_OF_RANGE;
1553 opt = &desc->fields[(*nold)];
1554 r = m_option_parse(opt, opt->name, str, NULL, M_CONFIG_FILE);
1555 if (r < 0) {
1556 if (r > M_OPT_EXIT)
1557 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
1558 "Option %s: Error while parsing %s parameter %s (%s)\n",
1559 opt_name, obj_name, opt->name, str);
1560 return r;
1562 if (dst) {
1563 dst[0] = strdup(opt->name);
1564 dst[1] = strdup(str);
1566 (*nold)++;
1568 return 1;
1571 static int get_obj_params(const char *opt_name, const char *name, char *params,
1572 const m_struct_t *desc, char separator, char ***_ret)
1574 int n = 0, nold = 0, nopts, r;
1575 char *ptr, *last_ptr = params;
1576 char **ret;
1578 if (!strcmp(params, "help")) { // Help
1579 char min[50], max[50];
1580 if (!desc->fields) {
1581 printf("%s doesn't have any options.\n\n", name);
1582 return M_OPT_EXIT - 1;
1584 printf("\n Name Type Min Max\n\n");
1585 for (n = 0; desc->fields[n].name; n++) {
1586 const m_option_t *opt = &desc->fields[n];
1587 if (opt->type->flags & M_OPT_TYPE_HAS_CHILD)
1588 continue;
1589 if (opt->flags & M_OPT_MIN)
1590 sprintf(min, "%-8.0f", opt->min);
1591 else
1592 strcpy(min, "No");
1593 if (opt->flags & M_OPT_MAX)
1594 sprintf(max, "%-8.0f", opt->max);
1595 else
1596 strcpy(max, "No");
1597 printf(" %-20.20s %-15.15s %-10.10s %-10.10s\n",
1598 opt->name,
1599 opt->type->name,
1600 min,
1601 max);
1603 printf("\n");
1604 return M_OPT_EXIT - 1;
1607 for (nopts = 0; desc->fields[nopts].name; nopts++)
1608 /* NOP */;
1610 // TODO : Check that each opt can be parsed
1611 r = 1;
1612 while (last_ptr && last_ptr[0] != '\0') {
1613 ptr = strchr(last_ptr, separator);
1614 if (!ptr) {
1615 r = get_obj_param(opt_name, name, desc, last_ptr, &nold, nopts,
1616 NULL);
1617 n++;
1618 break;
1620 if (ptr == last_ptr) { // Empty field, count it and go on
1621 nold++;
1622 last_ptr = ptr + 1;
1623 continue;
1625 ptr[0] = '\0';
1626 r = get_obj_param(opt_name, name, desc, last_ptr, &nold, nopts, NULL);
1627 ptr[0] = separator;
1628 if (r < 0)
1629 break;
1630 n++;
1631 last_ptr = ptr + 1;
1633 if (r < 0)
1634 return r;
1635 if (!last_ptr[0]) // count an empty field at the end, too
1636 nold++;
1637 if (nold > nopts) {
1638 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Too many options for %s\n", name);
1639 return M_OPT_OUT_OF_RANGE;
1641 if (!_ret) // Just test
1642 return 1;
1643 if (n == 0) // No options or only empty options
1644 return 1;
1646 ret = malloc((n + 2) * 2 * sizeof(char *));
1647 n = nold = 0;
1648 last_ptr = params;
1650 while (last_ptr && last_ptr[0] != '\0') {
1651 ptr = strchr(last_ptr, separator);
1652 if (!ptr) {
1653 get_obj_param(opt_name, name, desc, last_ptr, &nold, nopts,
1654 &ret[n * 2]);
1655 n++;
1656 break;
1658 if (ptr == last_ptr) { // Empty field, count it and go on
1659 last_ptr = ptr + 1;
1660 nold++;
1661 continue;
1663 ptr[0] = '\0';
1664 get_obj_param(opt_name, name, desc, last_ptr, &nold, nopts,
1665 &ret[n * 2]);
1666 n++;
1667 last_ptr = ptr + 1;
1669 ret[n * 2] = ret[n * 2 + 1] = NULL;
1670 *_ret = ret;
1672 return 1;
1675 static int parse_obj_params(const m_option_t *opt, const char *name,
1676 const char *param, void *dst, int src)
1678 char **opts;
1679 int r;
1680 m_obj_params_t *p = opt->priv;
1681 const m_struct_t *desc;
1682 char *cpy;
1684 // We need the object desc
1685 if (!p)
1686 return M_OPT_INVALID;
1688 desc = p->desc;
1689 cpy = strdup(param);
1690 r = get_obj_params(name, desc->name, cpy, desc, p->separator,
1691 dst ? &opts : NULL);
1692 free(cpy);
1693 if (r < 0)
1694 return r;
1695 if (!dst)
1696 return 1;
1697 if (!opts) // no arguments given
1698 return 1;
1700 for (r = 0; opts[r]; r += 2)
1701 m_struct_set(desc, dst, opts[r], opts[r + 1]);
1703 return 1;
1707 const m_option_type_t m_option_type_obj_params = {
1708 "Object params",
1712 parse_obj_params,
1713 NULL,
1714 NULL,
1715 NULL,
1716 NULL,
1717 NULL
1720 /// Some predefined types as a definition would be quite lengthy
1722 /// Span arguments
1723 static const m_span_t m_span_params_dflts = {
1724 -1, -1
1726 static const m_option_t m_span_params_fields[] = {
1727 {"start", M_ST_OFF(m_span_t, start), CONF_TYPE_INT, M_OPT_MIN, 1, 0, NULL},
1728 {"end", M_ST_OFF(m_span_t, end), CONF_TYPE_INT, M_OPT_MIN, 1, 0, NULL},
1729 { NULL, NULL, 0, 0, 0, 0, NULL }
1731 static const struct m_struct_st m_span_opts = {
1732 "m_span",
1733 sizeof(m_span_t),
1734 &m_span_params_dflts,
1735 m_span_params_fields
1737 const m_obj_params_t m_span_params_def = {
1738 &m_span_opts,
1742 static int parse_obj_settings(const char *opt, char *str,
1743 const m_obj_list_t *list,
1744 m_obj_settings_t **_ret, int ret_n)
1746 int r;
1747 char *param, **plist = NULL;
1748 const m_struct_t *desc;
1749 m_obj_settings_t *ret = _ret ? *_ret : NULL;
1752 // Now check that the object exists
1753 param = strchr(str, '=');
1754 if (param) {
1755 param[0] = '\0';
1756 param++;
1757 if (strlen(param) <= 0)
1758 param = NULL;
1762 if (!find_obj_desc(str, list, &desc)) {
1763 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: %s doesn't exist.\n",
1764 opt, str);
1765 return M_OPT_INVALID;
1768 if (param) {
1769 if (!desc && _ret) {
1770 if (!strcmp(param, "help")) {
1771 mp_msg(MSGT_CFGPARSER, MSGL_INFO,
1772 "Option %s: %s have no option description.\n", opt, str);
1773 return M_OPT_EXIT - 1;
1775 plist = calloc(4, sizeof(char *));
1776 plist[0] = strdup("_oldargs_");
1777 plist[1] = strdup(param);
1778 } else if (desc) {
1779 r = get_obj_params(opt, str, param, desc, ':',
1780 _ret ? &plist : NULL);
1781 if (r < 0)
1782 return r;
1785 if (!_ret)
1786 return 1;
1788 ret = realloc(ret, (ret_n + 2) * sizeof(m_obj_settings_t));
1789 memset(&ret[ret_n], 0, 2 * sizeof(m_obj_settings_t));
1790 ret[ret_n].name = strdup(str);
1791 ret[ret_n].attribs = plist;
1793 *_ret = ret;
1794 return 1;
1797 static int obj_settings_list_del(const char *opt_name, const char *param,
1798 void *dst, int src)
1800 char **str_list = NULL;
1801 int r, i, idx_max = 0;
1802 char *rem_id = "_removed_marker_";
1803 const m_option_t list_opt = {
1804 opt_name, NULL, CONF_TYPE_STRING_LIST,
1805 0, 0, 0, NULL
1807 m_obj_settings_t *obj_list = dst ? VAL(dst) : NULL;
1809 if (dst && !obj_list) {
1810 mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: the list is empty.\n",
1811 opt_name);
1812 return 1;
1813 } else if (obj_list) {
1814 for (idx_max = 0; obj_list[idx_max].name != NULL; idx_max++)
1815 /* NOP */;
1818 r = m_option_parse(&list_opt, opt_name, param, &str_list, src);
1819 if (r < 0 || !str_list)
1820 return r;
1822 for (r = 0; str_list[r]; r++) {
1823 int id;
1824 char *endptr;
1825 id = strtol(str_list[r], &endptr, 0);
1826 if (endptr == str_list[r]) {
1827 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);
1828 m_option_free(&list_opt, &str_list);
1829 return M_OPT_INVALID;
1831 if (!obj_list)
1832 continue;
1833 if (id >= idx_max || id < -idx_max) {
1834 mp_msg(MSGT_CFGPARSER, MSGL_WARN,
1835 "Option %s: Index %d is out of range.\n", opt_name, id);
1836 continue;
1838 if (id < 0)
1839 id = idx_max + id;
1840 free(obj_list[id].name);
1841 free_str_list(&(obj_list[id].attribs));
1842 obj_list[id].name = rem_id;
1845 if (!dst) {
1846 m_option_free(&list_opt, &str_list);
1847 return 1;
1850 for (i = 0; obj_list[i].name; i++) {
1851 while (obj_list[i].name == rem_id) {
1852 memmove(&obj_list[i], &obj_list[i + 1],
1853 sizeof(m_obj_settings_t) * (idx_max - i));
1854 idx_max--;
1857 obj_list = realloc(obj_list, sizeof(m_obj_settings_t) * (idx_max + 1));
1858 VAL(dst) = obj_list;
1860 return 1;
1863 static void free_obj_settings_list(void *dst)
1865 int n;
1866 m_obj_settings_t *d;
1868 if (!dst || !VAL(dst))
1869 return;
1871 d = VAL(dst);
1872 #ifndef NO_FREE
1873 for (n = 0; d[n].name; n++) {
1874 free(d[n].name);
1875 free_str_list(&(d[n].attribs));
1877 free(d);
1878 #endif
1879 VAL(dst) = NULL;
1882 static int parse_obj_settings_list(const m_option_t *opt, const char *name,
1883 const char *param, void *dst, int src)
1885 int n = 0, r, len = strlen(opt->name);
1886 char *str;
1887 char *ptr, *last_ptr;
1888 m_obj_settings_t *res = NULL, *queue = NULL, *head = NULL;
1889 int op = OP_NONE;
1891 // We need the objects list
1892 if (!opt->priv)
1893 return M_OPT_INVALID;
1895 if (opt->name[len - 1] == '*' && ((int)strlen(name) > len - 1)) {
1896 const char *n = &name[len - 1];
1897 if (strcasecmp(n, "-add") == 0)
1898 op = OP_ADD;
1899 else if (strcasecmp(n, "-pre") == 0)
1900 op = OP_PRE;
1901 else if (strcasecmp(n, "-del") == 0)
1902 op = OP_DEL;
1903 else if (strcasecmp(n, "-clr") == 0)
1904 op = OP_CLR;
1905 else {
1906 char prefix[len];
1907 strncpy(prefix, opt->name, len - 1);
1908 prefix[len - 1] = '\0';
1909 mp_msg(MSGT_VFILTER, MSGL_ERR, "Option %s: unknown postfix %s\n"
1910 "Supported postfixes are:\n"
1911 " %s-add\n"
1912 " Append the given list to the current list\n\n"
1913 " %s-pre\n"
1914 " Prepend the given list to the current list\n\n"
1915 " %s-del x,y,...\n"
1916 " Remove the given elements. Take the list element index (starting from 0).\n"
1917 " Negative index can be used (i.e. -1 is the last element)\n\n"
1918 " %s-clr\n"
1919 " Clear the current list.\n",
1920 name, n, prefix, prefix, prefix, prefix);
1922 return M_OPT_UNKNOWN;
1926 // Clear the list ??
1927 if (op == OP_CLR) {
1928 if (dst)
1929 free_obj_settings_list(dst);
1930 return 0;
1933 if (param == NULL || strlen(param) == 0)
1934 return M_OPT_MISSING_PARAM;
1936 switch (op) {
1937 case OP_ADD:
1938 if (dst)
1939 head = VAL(dst);
1940 break;
1941 case OP_PRE:
1942 if (dst)
1943 queue = VAL(dst);
1944 break;
1945 case OP_DEL:
1946 return obj_settings_list_del(name, param, dst, src);
1947 case OP_NONE:
1948 if (dst && VAL(dst))
1949 free_obj_settings_list(dst);
1950 break;
1951 default:
1952 mp_msg(MSGT_VFILTER, MSGL_ERR, "Option %s: FIXME\n", name);
1953 return M_OPT_UNKNOWN;
1956 if (!strcmp(param, "help")) {
1957 m_obj_list_t *ol = opt->priv;
1958 mp_msg(MSGT_VFILTER, MSGL_INFO, "Available video filters:\n");
1959 mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_FILTERS\n");
1960 for (n = 0; ol->list[n]; n++)
1961 mp_msg(MSGT_VFILTER, MSGL_INFO, " %-15s: %s\n",
1962 M_ST_MB(char *, ol->list[n], ol->name_off),
1963 M_ST_MB(char *, ol->list[n], ol->info_off));
1964 mp_msg(MSGT_VFILTER, MSGL_INFO, "\n");
1965 return M_OPT_EXIT - 1;
1967 ptr = str = strdup(param);
1969 while (ptr[0] != '\0') {
1970 last_ptr = ptr;
1971 ptr = get_nextsep(ptr, OPTION_LIST_SEPARATOR, 1);
1973 if (!ptr) {
1974 r = parse_obj_settings(name, last_ptr, opt->priv,
1975 dst ? &res : NULL, n);
1976 if (r < 0) {
1977 free(str);
1978 return r;
1980 n++;
1981 break;
1983 ptr[0] = '\0';
1984 r = parse_obj_settings(name, last_ptr, opt->priv, dst ? &res : NULL, n);
1985 if (r < 0) {
1986 free(str);
1987 return r;
1989 ptr++;
1990 n++;
1992 free(str);
1993 if (n == 0)
1994 return M_OPT_INVALID;
1996 if (((opt->flags & M_OPT_MIN) && (n < opt->min)) ||
1997 ((opt->flags & M_OPT_MAX) && (n > opt->max)))
1998 return M_OPT_OUT_OF_RANGE;
2000 if (dst) {
2001 if (queue) {
2002 int qsize;
2003 for (qsize = 0; queue[qsize].name; qsize++)
2004 /* NOP */;
2005 res = realloc(res, (qsize + n + 1) * sizeof(m_obj_settings_t));
2006 memcpy(&res[n], queue, (qsize + 1) * sizeof(m_obj_settings_t));
2007 n += qsize;
2008 free(queue);
2010 if (head) {
2011 int hsize;
2012 for (hsize = 0; head[hsize].name; hsize++)
2013 /* NOP */;
2014 head = realloc(head, (hsize + n + 1) * sizeof(m_obj_settings_t));
2015 memcpy(&head[hsize], res, (n + 1) * sizeof(m_obj_settings_t));
2016 free(res);
2017 res = head;
2019 VAL(dst) = res;
2021 return 1;
2024 static void copy_obj_settings_list(const m_option_t *opt, void *dst,
2025 const void *src)
2027 m_obj_settings_t *d, *s;
2028 int n;
2030 if (!(dst && src))
2031 return;
2033 s = VAL(src);
2035 if (VAL(dst))
2036 free_obj_settings_list(dst);
2037 if (!s)
2038 return;
2042 for (n = 0; s[n].name; n++)
2043 /* NOP */;
2044 d = malloc((n + 1) * sizeof(m_obj_settings_t));
2045 for (n = 0; s[n].name; n++) {
2046 d[n].name = strdup(s[n].name);
2047 d[n].attribs = NULL;
2048 copy_str_list(NULL, &(d[n].attribs), &(s[n].attribs));
2050 d[n].name = NULL;
2051 d[n].attribs = NULL;
2052 VAL(dst) = d;
2055 const m_option_type_t m_option_type_obj_settings_list = {
2056 "Object settings list",
2058 sizeof(m_obj_settings_t *),
2059 M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD,
2060 parse_obj_settings_list,
2061 NULL,
2062 copy_obj_settings_list,
2063 copy_obj_settings_list,
2064 copy_obj_settings_list,
2065 free_obj_settings_list,
2070 static int parse_obj_presets(const m_option_t *opt, const char *name,
2071 const char *param, void *dst, int src)
2073 m_obj_presets_t *obj_p = (m_obj_presets_t *)opt->priv;
2074 const m_struct_t *in_desc;
2075 const m_struct_t *out_desc;
2076 int s, i;
2077 const unsigned char *pre;
2078 char *pre_name = NULL;
2080 if (!obj_p) {
2081 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Presets need a "
2082 "pointer to a m_obj_presets_t in the priv field.\n", name);
2083 return M_OPT_PARSER_ERR;
2086 if (!param)
2087 return M_OPT_MISSING_PARAM;
2089 pre = obj_p->presets;
2090 in_desc = obj_p->in_desc;
2091 out_desc = obj_p->out_desc ? obj_p->out_desc : obj_p->in_desc;
2092 s = in_desc->size;
2094 if (!strcmp(param, "help")) {
2095 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available presets for %s->%s:",
2096 out_desc->name, name);
2097 for (pre = obj_p->presets;
2098 (pre_name = M_ST_MB(char *, pre, obj_p->name_off)); pre += s)
2099 mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %s", pre_name);
2100 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "\n");
2101 return M_OPT_EXIT - 1;
2104 for (pre_name = M_ST_MB(char *, pre, obj_p->name_off); pre_name;
2105 pre += s, pre_name = M_ST_MB(char *, pre, obj_p->name_off))
2106 if (!strcmp(pre_name, param))
2107 break;
2108 if (!pre_name) {
2109 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2110 "Option %s: There is no preset named %s\n"
2111 "Available presets are:", name, param);
2112 for (pre = obj_p->presets;
2113 (pre_name = M_ST_MB(char *, pre, obj_p->name_off)); pre += s)
2114 mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %s", pre_name);
2115 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "\n");
2116 return M_OPT_INVALID;
2119 if (!dst)
2120 return 1;
2122 for (i = 0; in_desc->fields[i].name; i++) {
2123 const m_option_t *out_opt = m_option_list_find(out_desc->fields,
2124 in_desc->fields[i].name);
2125 if (!out_opt) {
2126 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2127 "Option %s: Unable to find the target option for field %s.\n"
2128 "Please report this to the developers.\n",
2129 name, in_desc->fields[i].name);
2130 return M_OPT_PARSER_ERR;
2132 m_option_copy(out_opt, M_ST_MB_P(dst, out_opt->p),
2133 M_ST_MB_P(pre, in_desc->fields[i].p));
2135 return 1;
2139 const m_option_type_t m_option_type_obj_presets = {
2140 "Object presets",
2144 parse_obj_presets,
2145 NULL,
2146 NULL,
2147 NULL,
2148 NULL,
2149 NULL
2152 static int parse_custom_url(const m_option_t *opt, const char *name,
2153 const char *url, void *dst, int src)
2155 int pos1, pos2, r, v6addr = 0;
2156 char *ptr1 = NULL, *ptr2 = NULL, *ptr3 = NULL, *ptr4 = NULL;
2157 m_struct_t *desc = opt->priv;
2159 if (!desc) {
2160 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Custom URL needs "
2161 "a pointer to a m_struct_t in the priv field.\n", name);
2162 return M_OPT_PARSER_ERR;
2165 // extract the protocol
2166 ptr1 = strstr(url, "://");
2167 if (ptr1 == NULL) {
2168 // Filename only
2169 if (m_option_list_find(desc->fields, "filename")) {
2170 m_struct_set(desc, dst, "filename", url);
2171 return 1;
2173 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2174 "Option %s: URL doesn't have a valid protocol!\n", name);
2175 return M_OPT_INVALID;
2177 if (m_option_list_find(desc->fields, "string")) {
2178 if (strlen(ptr1) > 3) {
2179 m_struct_set(desc, dst, "string", ptr1 + 3);
2180 return 1;
2183 pos1 = ptr1 - url;
2184 if (dst && m_option_list_find(desc->fields, "protocol")) {
2185 ptr1[0] = '\0';
2186 r = m_struct_set(desc, dst, "protocol", url);
2187 ptr1[0] = ':';
2188 if (r < 0) {
2189 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2190 "Option %s: Error while setting protocol.\n", name);
2191 return r;
2195 // jump the "://"
2196 ptr1 += 3;
2197 pos1 += 3;
2199 // check if a username:password is given
2200 ptr2 = strstr(ptr1, "@");
2201 ptr3 = strstr(ptr1, "/");
2202 if (ptr3 != NULL && ptr3 < ptr2) {
2203 // it isn't really a username but rather a part of the path
2204 ptr2 = NULL;
2206 if (ptr2 != NULL) {
2208 // We got something, at least a username...
2209 if (!m_option_list_find(desc->fields, "username")) {
2210 mp_msg(MSGT_CFGPARSER, MSGL_WARN,
2211 "Option %s: This URL doesn't have a username part.\n", name);
2212 // skip
2213 } else {
2214 ptr3 = strstr(ptr1, ":");
2215 if (ptr3 != NULL && ptr3 < ptr2) {
2216 // We also have a password
2217 if (!m_option_list_find(desc->fields, "password")) {
2218 mp_msg(MSGT_CFGPARSER, MSGL_WARN,
2219 "Option %s: This URL doesn't have a password part.\n",
2220 name);
2221 // skip
2222 } else { // Username and password
2223 if (dst) {
2224 ptr3[0] = '\0';
2225 r = m_struct_set(desc, dst, "username", ptr1);
2226 ptr3[0] = ':';
2227 if (r < 0) {
2228 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2229 "Option %s: Error while setting username.\n",
2230 name);
2231 return r;
2233 ptr2[0] = '\0';
2234 r = m_struct_set(desc, dst, "password", ptr3 + 1);
2235 ptr2[0] = '@';
2236 if (r < 0) {
2237 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2238 "Option %s: Error while setting password.\n",
2239 name);
2240 return r;
2244 } else { // User name only
2245 ptr2[0] = '\0';
2246 r = m_struct_set(desc, dst, "username", ptr1);
2247 ptr2[0] = '@';
2248 if (r < 0) {
2249 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2250 "Option %s: Error while setting username.\n", name);
2251 return r;
2255 ptr1 = ptr2 + 1;
2256 pos1 = ptr1 - url;
2259 // Before looking for a port number check if we have an IPv6 type
2260 // numeric address.
2261 // In an IPv6 URL the numeric address should be inside square braces.
2262 ptr2 = strstr(ptr1, "[");
2263 ptr3 = strstr(ptr1, "]");
2264 // If the [] is after the first it isn't the hostname
2265 ptr4 = strstr(ptr1, "/");
2266 if (ptr2 != NULL && ptr3 != NULL && (ptr2 < ptr3)
2267 && (!ptr4 || ptr4 > ptr3)) {
2268 // we have an IPv6 numeric address
2269 ptr1++;
2270 pos1++;
2271 ptr2 = ptr3;
2272 v6addr = 1;
2273 } else
2274 ptr2 = ptr1;
2276 // look if the port is given
2277 ptr2 = strstr(ptr2, ":");
2278 // If the : is after the first / it isn't the port
2279 ptr3 = strstr(ptr1, "/");
2280 if (ptr3 && ptr3 - ptr2 < 0)
2281 ptr2 = NULL;
2282 if (ptr2 == NULL) {
2283 // No port is given
2284 // Look if a path is given
2285 if (ptr3 == NULL) {
2286 // No path/filename
2287 // So we have an URL like http://www.hostname.com
2288 pos2 = strlen(url);
2289 } else {
2290 // We have an URL like http://www.hostname.com/file.txt
2291 pos2 = ptr3 - url;
2293 } else {
2294 // We have an URL beginning like http://www.hostname.com:1212
2295 // Get the port number
2296 if (!m_option_list_find(desc->fields, "port")) {
2297 mp_msg(MSGT_CFGPARSER, MSGL_WARN,
2298 "Option %s: This URL doesn't have a port part.\n", name);
2299 // skip
2300 } else {
2301 if (dst) {
2302 int p = atoi(ptr2 + 1);
2303 char tmp[100];
2304 snprintf(tmp, 99, "%d", p);
2305 r = m_struct_set(desc, dst, "port", tmp);
2306 if (r < 0) {
2307 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2308 "Option %s: Error while setting port.\n", name);
2309 return r;
2313 pos2 = ptr2 - url;
2315 if (v6addr)
2316 pos2--;
2317 // Get the hostname
2318 if (pos2 - pos1 > 0) {
2319 if (!m_option_list_find(desc->fields, "hostname")) {
2320 mp_msg(MSGT_CFGPARSER, MSGL_WARN,
2321 "Option %s: This URL doesn't have a hostname part.\n", name);
2322 // skip
2323 } else {
2324 char tmp[pos2 - pos1 + 1];
2325 strncpy(tmp, ptr1, pos2 - pos1);
2326 tmp[pos2 - pos1] = '\0';
2327 r = m_struct_set(desc, dst, "hostname", tmp);
2328 if (r < 0) {
2329 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2330 "Option %s: Error while setting hostname.\n", name);
2331 return r;
2335 // Look if a path is given
2336 ptr2 = strstr(ptr1, "/");
2337 if (ptr2 != NULL) {
2338 // A path/filename is given
2339 // check if it's not a trailing '/'
2340 if (strlen(ptr2) > 1) {
2341 // copy the path/filename in the URL container
2342 if (!m_option_list_find(desc->fields, "filename")) {
2343 mp_msg(MSGT_CFGPARSER, MSGL_WARN,
2344 "Option %s: This URL doesn't have a hostname part.\n",
2345 name);
2346 // skip
2347 } else {
2348 if (dst) {
2349 int l = strlen(ptr2 + 1) + 1;
2350 char *fname = ptr2 + 1;
2351 if (l > 1) {
2352 fname = malloc(l);
2353 url_unescape_string(fname, ptr2 + 1);
2355 r = m_struct_set(desc, dst, "filename", fname);
2356 if (fname != ptr2 + 1)
2357 free(fname);
2358 if (r < 0) {
2359 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
2360 "Option %s: Error while setting filename.\n",
2361 name);
2362 return r;
2368 return 1;
2371 /// TODO : Write the other needed funcs for 'normal' options
2372 const m_option_type_t m_option_type_custom_url = {
2373 "Custom URL",
2377 parse_custom_url,
2378 NULL,
2379 NULL,
2380 NULL,
2381 NULL,
2382 NULL