mirror of
https://github.com/mpv-player/mpv
synced 2024-09-09 01:16:56 +02:00
![arpi](/assets/img/avatar_default.png)
(and a little memleak), but i can explain :) [note it's just a few kB memleak, but it's the price of stability without full code review/audit - there are hunderds of possible double free()] the old config parser didn't free() strings/stringlists, but didn't even allocate them by default. the new one always free(), and it causes memcorruption/sig11 at cases like this: char* dvd_device="/dev/dvd"; {"dvd-device", &dvd_device, CONF_TYPE_STRING, 0, 0, 0, NULL}, since string constansts (allocated in .TEXT segment) cannot be free()'d git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@9178 b3059339-0415-0410-9bf9-f77b7e298cf2
1044 lines
22 KiB
C
1044 lines
22 KiB
C
|
|
#include "config.h"
|
|
|
|
#ifdef NEW_CONFIG
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <inttypes.h>
|
|
#include <unistd.h>
|
|
|
|
#include "m_option.h"
|
|
//#include "m_config.h"
|
|
#include "mp_msg.h"
|
|
|
|
// Default function that just do a memcpy
|
|
|
|
static void copy_opt(m_option_t* opt,void* dst,void* src) {
|
|
if(dst && src)
|
|
memcpy(dst,src,opt->type->size);
|
|
}
|
|
|
|
// Helper for the print funcs (from man printf)
|
|
static char* dup_printf(const char *fmt, ...) {
|
|
/* Guess we need no more than 50 bytes. */
|
|
int n, size = 50;
|
|
char *p;
|
|
va_list ap;
|
|
if ((p = malloc (size)) == NULL)
|
|
return NULL;
|
|
while (1) {
|
|
/* Try to print in the allocated space. */
|
|
va_start(ap, fmt);
|
|
n = vsnprintf (p, size, fmt, ap);
|
|
va_end(ap);
|
|
/* If that worked, return the string. */
|
|
if (n > -1 && n < size)
|
|
return p;
|
|
/* Else try again with more space. */
|
|
if (n > -1) /* glibc 2.1 */
|
|
size = n+1; /* precisely what is needed */
|
|
else /* glibc 2.0 */
|
|
size *= 2; /* twice the old size */
|
|
if ((p = realloc (p, size)) == NULL)
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// Flag
|
|
|
|
#define VAL(x) (*(int*)(x))
|
|
|
|
static int parse_flag(m_option_t* opt,char *name, char *param, void* dst, int src) {
|
|
if (src == M_CONFIG_FILE) {
|
|
if (!strcasecmp(param, "yes") || /* any other language? */
|
|
!strcasecmp(param, "ja") ||
|
|
!strcasecmp(param, "si") ||
|
|
!strcasecmp(param, "igen") ||
|
|
!strcasecmp(param, "y") ||
|
|
!strcasecmp(param, "j") ||
|
|
!strcasecmp(param, "i") ||
|
|
!strcmp(param, "1")) {
|
|
if(dst) VAL(dst) = opt->max;
|
|
} else if (!strcasecmp(param, "no") ||
|
|
!strcasecmp(param, "nein") ||
|
|
!strcasecmp(param, "nicht") ||
|
|
!strcasecmp(param, "nem") ||
|
|
!strcasecmp(param, "n") ||
|
|
!strcmp(param, "0")) {
|
|
if(dst) VAL(dst) = opt->min;
|
|
} else {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "invalid parameter for %s flag: %s\n",name, param);
|
|
return M_OPT_INVALID;
|
|
}
|
|
return 1;
|
|
} else {
|
|
if(dst) VAL(dst) = opt->max;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static char* print_flag(m_option_t* opt, void* val) {
|
|
if(VAL(val) == opt->min)
|
|
return strdup("no");
|
|
else
|
|
return strdup("yes");
|
|
}
|
|
|
|
m_option_type_t m_option_type_flag = {
|
|
"Flag",
|
|
"need yes or no in config files",
|
|
sizeof(int),
|
|
0,
|
|
parse_flag,
|
|
print_flag,
|
|
copy_opt,
|
|
copy_opt,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
// Integer
|
|
|
|
static int parse_int(m_option_t* opt,char *name, char *param, void* dst, int src) {
|
|
long tmp_int;
|
|
char *endptr;
|
|
src = 0;
|
|
|
|
if (param == NULL)
|
|
return M_OPT_MISSING_PARAM;
|
|
|
|
tmp_int = strtol(param, &endptr, 0);
|
|
if (*endptr) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be an integer: %s\n",name, param);
|
|
return M_OPT_INVALID;
|
|
}
|
|
|
|
if ((opt->flags & M_OPT_MIN) && (tmp_int < opt->min)) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be >= %d: %s\n", name, (int) opt->min, param);
|
|
return M_OPT_OUT_OF_RANGE;
|
|
}
|
|
|
|
if ((opt->flags & M_OPT_MAX) && (tmp_int > opt->max)) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be <= %d: %s\n",name, (int) opt->max, param);
|
|
return M_OPT_OUT_OF_RANGE;
|
|
}
|
|
|
|
if(dst) VAL(dst) = tmp_int;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static char* print_int(m_option_t* opt, void* val) {
|
|
opt = NULL;
|
|
return dup_printf("%d",VAL(val));
|
|
}
|
|
|
|
m_option_type_t m_option_type_int = {
|
|
"Integer",
|
|
"",
|
|
sizeof(int),
|
|
0,
|
|
parse_int,
|
|
print_int,
|
|
copy_opt,
|
|
copy_opt,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
// Float
|
|
|
|
#undef VAL
|
|
#define VAL(x) (*(float*)(x))
|
|
|
|
static int parse_float(m_option_t* opt,char *name, char *param, void* dst, int src) {
|
|
float tmp_float;
|
|
char* endptr;
|
|
src = 0;
|
|
|
|
if (param == NULL)
|
|
return M_OPT_MISSING_PARAM;
|
|
|
|
tmp_float = strtod(param, &endptr);
|
|
|
|
switch(*endptr) {
|
|
case ':':
|
|
case '/':
|
|
tmp_float /= strtod(endptr+1, &endptr);
|
|
break;
|
|
case '.':
|
|
case ',':
|
|
/* we also handle floats specified with
|
|
* non-locale decimal point ::atmos
|
|
*/
|
|
if(tmp_float<0)
|
|
tmp_float -= 1.0/pow(10,strlen(endptr+1)) * strtod(endptr+1, &endptr);
|
|
else
|
|
tmp_float += 1.0/pow(10,strlen(endptr+1)) * strtod(endptr+1, &endptr);
|
|
break;
|
|
}
|
|
|
|
if (*endptr) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be a floating point "
|
|
"number or a ratio (numerator[:/]denominator): %s\n",name, param);
|
|
return M_OPT_INVALID;
|
|
}
|
|
|
|
if (opt->flags & M_OPT_MIN)
|
|
if (tmp_float < opt->min) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be >= %f: %s\n", name, opt->min, param);
|
|
return M_OPT_OUT_OF_RANGE;
|
|
}
|
|
|
|
if (opt->flags & M_OPT_MAX)
|
|
if (tmp_float > opt->max) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be <= %f: %s\n", name, opt->max, param);
|
|
return M_OPT_OUT_OF_RANGE;
|
|
}
|
|
|
|
if(dst) VAL(dst) = tmp_float;
|
|
return 1;
|
|
}
|
|
|
|
static char* print_float(m_option_t* opt, void* val) {
|
|
opt = NULL;
|
|
return dup_printf("%f",VAL(val));
|
|
}
|
|
|
|
m_option_type_t m_option_type_float = {
|
|
"Float",
|
|
"floating point number or ratio (numerator[:/]denominator)",
|
|
sizeof(float),
|
|
0,
|
|
parse_float,
|
|
print_float,
|
|
copy_opt,
|
|
copy_opt,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
///////////// Position
|
|
#undef VAL
|
|
#define VAL(x) (*(off_t*)(x))
|
|
|
|
static int parse_position(m_option_t* opt,char *name, char *param, void* dst, int src) {
|
|
off_t tmp_off;
|
|
char dummy;
|
|
|
|
if (param == NULL)
|
|
return M_OPT_MISSING_PARAM;
|
|
if (sscanf(param, sizeof(off_t) == sizeof(int) ?
|
|
"%d%c" : "%lld%c", &tmp_off, &dummy) != 1) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be an integer: %s\n",opt->name,param);
|
|
return M_OPT_INVALID;
|
|
}
|
|
|
|
if (opt->flags & M_OPT_MIN)
|
|
if (tmp_off < opt->min) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR,
|
|
(sizeof(off_t) == sizeof(int) ?
|
|
"The %s option must be >= %d: %s\n" :
|
|
"The %s option must be >= %lld: %s\n"),
|
|
(off_t) opt->min, param);
|
|
return M_OPT_OUT_OF_RANGE;
|
|
}
|
|
|
|
if (opt->flags & M_OPT_MAX)
|
|
if (tmp_off > opt->max) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR,
|
|
(sizeof(off_t) == sizeof(int) ?
|
|
"The %s option must be <= %d: %s\n" :
|
|
"The %s option must be <= %lld: %s\n"),
|
|
(off_t) opt->max, param);
|
|
return M_OPT_OUT_OF_RANGE;
|
|
}
|
|
|
|
if(dst)
|
|
VAL(dst) = tmp_off;
|
|
return 1;
|
|
}
|
|
|
|
static char* print_position(m_option_t* opt, void* val) {
|
|
return dup_printf(sizeof(off_t) == sizeof(int) ? "%d" : "%lld",VAL(val));
|
|
}
|
|
|
|
m_option_type_t m_option_type_position = {
|
|
"Position",
|
|
"Integer (off_t)",
|
|
sizeof(off_t),
|
|
0,
|
|
parse_position,
|
|
print_position,
|
|
copy_opt,
|
|
copy_opt,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
|
|
///////////// String
|
|
|
|
#undef VAL
|
|
#define VAL(x) (*(char**)(x))
|
|
|
|
static int parse_str(m_option_t* opt,char *name, char *param, void* dst, int src) {
|
|
|
|
|
|
if (param == NULL)
|
|
return M_OPT_MISSING_PARAM;
|
|
|
|
if ((opt->flags & M_OPT_MIN) && (strlen(param) < opt->min)) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be >= %d chars: %s\n",
|
|
(int) opt->min, param);
|
|
return M_OPT_OUT_OF_RANGE;
|
|
}
|
|
|
|
if ((opt->flags & M_OPT_MAX) && (strlen(param) > opt->max)) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be <= %d chars: %s\n",
|
|
(int) opt->max, param);
|
|
return M_OPT_OUT_OF_RANGE;
|
|
}
|
|
|
|
if(dst) {
|
|
if(VAL(dst))
|
|
free(VAL(dst));
|
|
VAL(dst) = strdup(param);
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
static char* print_str(m_option_t* opt, void* val) {
|
|
return (val && VAL(val) && strlen(VAL(val)) > 0) ? strdup(VAL(val)) : NULL;
|
|
}
|
|
|
|
static void copy_str(m_option_t* opt,void* dst, void* src) {
|
|
if(dst && src) {
|
|
// if(VAL(dst)) free(VAL(dst)); //FIXME!!!
|
|
VAL(dst) = VAL(src) ? strdup(VAL(src)) : NULL;
|
|
}
|
|
}
|
|
|
|
static void free_str(void* src) {
|
|
if(src && VAL(src)){
|
|
// free(VAL(src)); //FIXME!!!
|
|
VAL(src) = NULL;
|
|
}
|
|
}
|
|
|
|
m_option_type_t m_option_type_string = {
|
|
"String",
|
|
"",
|
|
sizeof(char*),
|
|
M_OPT_TYPE_DYNAMIC,
|
|
parse_str,
|
|
print_str,
|
|
copy_str,
|
|
copy_str,
|
|
copy_str,
|
|
free_str
|
|
};
|
|
|
|
//////////// String list
|
|
|
|
#define LIST_SEPARATOR ','
|
|
#undef VAL
|
|
#define VAL(x) (*(char***)(x))
|
|
|
|
#define OP_NONE 0
|
|
#define OP_ADD 1
|
|
#define OP_PRE 2
|
|
#define OP_DEL 3
|
|
#define OP_CLR 4
|
|
|
|
static void free_str_list(void* dst) {
|
|
char** d;
|
|
int i;
|
|
|
|
if(!dst || !VAL(dst)) return;
|
|
d = VAL(dst);
|
|
|
|
// FIXME!!!
|
|
// for(i = 0 ; d[i] != NULL ; i++)
|
|
// free(d[i]);
|
|
// free(d);
|
|
VAL(dst) = NULL;
|
|
}
|
|
|
|
static int str_list_add(char** add, int n,void* dst,int pre) {
|
|
char** lst = VAL(dst);
|
|
int ln;
|
|
|
|
if(!dst) return M_OPT_PARSER_ERR;
|
|
lst = VAL(dst);
|
|
|
|
for(ln = 0 ; lst && lst[ln] ; ln++)
|
|
/**/;
|
|
|
|
lst = realloc(lst,(n+ln+1)*sizeof(char*));
|
|
|
|
if(pre) {
|
|
memmove(&lst[n],lst,(ln+1)*sizeof(char*));
|
|
memcpy(lst,add,n*sizeof(char*));
|
|
} else
|
|
memcpy(&lst[ln],add,(n+1)*sizeof(char*));
|
|
|
|
free(add);
|
|
|
|
VAL(dst) = lst;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int str_list_del(char** del, int n,void* dst) {
|
|
char **lst,*ep,**d;
|
|
int i,ln,s;
|
|
long idx;
|
|
|
|
if(!dst) return M_OPT_PARSER_ERR;
|
|
lst = VAL(dst);
|
|
|
|
for(ln = 0 ; lst && lst[ln] ; ln++)
|
|
/**/;
|
|
s = ln;
|
|
|
|
for(i = 0 ; del[i] != NULL ; i++) {
|
|
idx = strtol(del[i], &ep, 0);
|
|
if(*ep) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid index: %s\n",del[i]);
|
|
free(del[i]);
|
|
continue;
|
|
}
|
|
free(del[i]);
|
|
if(idx < 0 || idx >= ln) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Index %d is out of range\n",idx);
|
|
continue;
|
|
} else if(!lst[idx])
|
|
continue;
|
|
free(lst[idx]);
|
|
lst[idx] = NULL;
|
|
s--;
|
|
}
|
|
free(del);
|
|
|
|
if(s == 0) {
|
|
if(lst) free(lst);
|
|
VAL(dst) = NULL;
|
|
return 1;
|
|
}
|
|
|
|
d = calloc(s+1,sizeof(char*));
|
|
for(i = 0, n = 0 ; i < ln ; i++) {
|
|
if(!lst[i]) continue;
|
|
d[n] = lst[i];
|
|
n++;
|
|
}
|
|
d[s] = NULL;
|
|
|
|
if(lst) free(lst);
|
|
VAL(dst) = d;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int parse_str_list(m_option_t* opt,char *name, char *param, void* dst, int src) {
|
|
int n = 0,len = strlen(opt->name);
|
|
char *ptr = param, *last_ptr, **res;
|
|
int op = OP_NONE;
|
|
|
|
if(opt->name[len-1] == '*' && ((int)strlen(name) > len - 1)) {
|
|
char* n = &name[len-1];
|
|
if(strcasecmp(n,"-add") == 0)
|
|
op = OP_ADD;
|
|
else if(strcasecmp(n,"-pre") == 0)
|
|
op = OP_PRE;
|
|
else if(strcasecmp(n,"-del") == 0)
|
|
op = OP_DEL;
|
|
else if(strcasecmp(n,"-clr") == 0)
|
|
op = OP_CLR;
|
|
else
|
|
return M_OPT_UNKNOW;
|
|
}
|
|
|
|
// Clear the list ??
|
|
if(op == OP_CLR) {
|
|
if(dst)
|
|
free_str_list(dst);
|
|
return 0;
|
|
}
|
|
|
|
// All other op need a param
|
|
if (param == NULL || strlen(param) == 0)
|
|
return M_OPT_MISSING_PARAM;
|
|
|
|
|
|
while(ptr[0] != '\0') {
|
|
last_ptr = ptr;
|
|
ptr = strchr(ptr,LIST_SEPARATOR);
|
|
if(!ptr) {
|
|
n++;
|
|
break;
|
|
}
|
|
ptr++;
|
|
n++;
|
|
}
|
|
if(n == 0)
|
|
return M_OPT_INVALID;
|
|
if( ((opt->flags & M_OPT_MIN) && (n < opt->min)) ||
|
|
((opt->flags & M_OPT_MAX) && (n > opt->max)) )
|
|
return M_OPT_OUT_OF_RANGE;
|
|
|
|
if(!dst) return 1;
|
|
|
|
res = malloc((n+2)*sizeof(char*));
|
|
ptr = param;
|
|
n = 0;
|
|
|
|
while(1) {
|
|
last_ptr = ptr;
|
|
ptr = strchr(ptr,LIST_SEPARATOR);
|
|
if(!ptr) {
|
|
res[n] = strdup(last_ptr);
|
|
n++;
|
|
break;
|
|
}
|
|
len = ptr - last_ptr;
|
|
res[n] = (char*)malloc(len + 1);
|
|
if(len) strncpy(res[n],last_ptr,len);
|
|
res[n][len] = '\0';
|
|
ptr++;
|
|
n++;
|
|
}
|
|
res[n] = NULL;
|
|
|
|
switch(op) {
|
|
case OP_ADD:
|
|
return str_list_add(res,n,dst,0);
|
|
case OP_PRE:
|
|
return str_list_add(res,n,dst,1);
|
|
case OP_DEL:
|
|
return str_list_del(res,n,dst);
|
|
}
|
|
|
|
if(VAL(dst))
|
|
free_str_list(dst);
|
|
VAL(dst) = res;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void copy_str_list(m_option_t* opt,void* dst, void* src) {
|
|
int n;
|
|
char **d,**s;
|
|
|
|
if(!(dst && src)) return;
|
|
s = VAL(src);
|
|
|
|
if(VAL(dst))
|
|
free_str_list(dst);
|
|
|
|
if(!s) {
|
|
VAL(dst) = NULL;
|
|
return;
|
|
}
|
|
|
|
for(n = 0 ; s[n] != NULL ; n++)
|
|
/* NOTHING */;
|
|
d = (char**)malloc((n+1)*sizeof(char*));
|
|
for( ; n >= 0 ; n--)
|
|
d[n] = s[n] ? strdup(s[n]) : NULL;
|
|
|
|
VAL(dst) = d;
|
|
}
|
|
|
|
static char* print_str_list(m_option_t* opt, void* src) {
|
|
char **lst = NULL;
|
|
char *ret = NULL,*last = NULL;
|
|
int i;
|
|
|
|
if(!(src && VAL(src))) return NULL;
|
|
lst = VAL(src);
|
|
|
|
for(i = 0 ; lst[i] ; i++) {
|
|
if(last) {
|
|
ret = dup_printf("%s,%s",last,lst[i]);
|
|
free(last);
|
|
} else
|
|
ret = strdup(lst[i]);
|
|
last = ret;
|
|
}
|
|
if(last && last != ret) free(last);
|
|
return ret;
|
|
}
|
|
|
|
m_option_type_t m_option_type_string_list = {
|
|
"String list",
|
|
"A list of string separated by ','\n"
|
|
"Option with name that finish by an * allow to use the following suffix : \n"
|
|
"\t-add : add the given parameters at the end of list\n"
|
|
"\t-pre : add the given parameters at the begining of list\n"
|
|
"\t-del : remove the entry at the given indexs\n"
|
|
"\t-clr : clear the list\n"
|
|
"e.g: -vop-add flip,mirror -vop-del 2,5\n",
|
|
sizeof(char**),
|
|
M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD,
|
|
parse_str_list,
|
|
print_str_list,
|
|
copy_str_list,
|
|
copy_str_list,
|
|
copy_str_list,
|
|
free_str_list
|
|
};
|
|
|
|
|
|
/////////////////// Func based options
|
|
|
|
// A chained list to save the various calls for func_param and func_full
|
|
typedef struct m_func_save m_func_save_t;
|
|
struct m_func_save {
|
|
m_func_save_t* next;
|
|
char* name;
|
|
char* param;
|
|
};
|
|
|
|
#undef VAL
|
|
#define VAL(x) (*(m_func_save_t**)(x))
|
|
|
|
static void free_func_pf(void* src) {
|
|
m_func_save_t *s,*n;
|
|
|
|
if(!src) return;
|
|
|
|
s = VAL(src);
|
|
|
|
while(s) {
|
|
n = s->next;
|
|
free(s->name);
|
|
if(s->param) free(s->param);
|
|
free(s);
|
|
s = n;
|
|
}
|
|
VAL(src) = NULL;
|
|
}
|
|
|
|
// Parser for func_param and func_full
|
|
static int parse_func_pf(m_option_t* opt,char *name, char *param, void* dst, int src) {
|
|
m_func_save_t *s,*p;
|
|
|
|
if(!dst)
|
|
return 1;
|
|
|
|
s = (m_func_save_t*)calloc(1,sizeof(m_func_save_t));
|
|
s->name = strdup(name);
|
|
s->param = param ? strdup(param) : NULL;
|
|
|
|
p = VAL(dst);
|
|
if(p) {
|
|
for( ; p->next != NULL ; p = p->next)
|
|
/**/;
|
|
p->next = s;
|
|
} else
|
|
VAL(dst) = s;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void copy_func_pf(m_option_t* opt,void* dst, void* src) {
|
|
m_func_save_t *d = NULL, *s,* last = NULL;
|
|
|
|
if(!(dst && src)) return;
|
|
s = VAL(src);
|
|
|
|
if(VAL(dst))
|
|
free_func_pf(dst);
|
|
|
|
while(s) {
|
|
d = (m_func_save_t*)malloc(sizeof(m_func_save_t));
|
|
d->name = strdup(s->name);
|
|
d->param = s->param ? strdup(s->param) : NULL;
|
|
if(last)
|
|
last->next = d;
|
|
else
|
|
VAL(dst) = d;
|
|
last = d;
|
|
s = s->next;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/////////////////// Func_param
|
|
|
|
static void set_func_param(m_option_t* opt, void* dst, void* src) {
|
|
m_func_save_t* s;
|
|
|
|
if(!src) return;
|
|
s = VAL(src);
|
|
|
|
if(!s) return;
|
|
|
|
// Revert if needed
|
|
if(opt->priv) ((m_opt_default_func_t)opt->priv)(opt,opt->name);
|
|
for( ; s != NULL ; s = s->next)
|
|
((m_opt_func_param_t) opt->p)(opt,s->param);
|
|
}
|
|
|
|
m_option_type_t m_option_type_func_param = {
|
|
"Func param",
|
|
"",
|
|
sizeof(m_func_save_t*),
|
|
M_OPT_TYPE_INDIRECT,
|
|
parse_func_pf,
|
|
NULL,
|
|
NULL, // Nothing to do on save
|
|
set_func_param,
|
|
copy_func_pf,
|
|
free_func_pf
|
|
};
|
|
|
|
/////////////////// Func_full
|
|
|
|
static void set_func_full(m_option_t* opt, void* dst, void* src) {
|
|
m_func_save_t* s;
|
|
|
|
if(!src) return;
|
|
|
|
for(s = VAL(src) ; s ; s = s->next) {
|
|
// Revert if needed
|
|
if(opt->priv) ((m_opt_default_func_t)opt->priv)(opt,s->name);
|
|
((m_opt_func_full_t) opt->p)(opt,s->name,s->param);
|
|
}
|
|
}
|
|
|
|
m_option_type_t m_option_type_func_full = {
|
|
"Func full",
|
|
"",
|
|
sizeof(m_func_save_t*),
|
|
M_OPT_TYPE_ALLOW_WILDCARD|M_OPT_TYPE_INDIRECT,
|
|
parse_func_pf,
|
|
NULL,
|
|
NULL, // Nothing to do on save
|
|
set_func_full,
|
|
copy_func_pf,
|
|
free_func_pf
|
|
};
|
|
|
|
/////////////// Func
|
|
|
|
#undef VAL
|
|
#define VAL(x) (*(int*)(x))
|
|
|
|
static int parse_func(m_option_t* opt,char *name, char *param, void* dst, int src) {
|
|
if(dst)
|
|
VAL(dst) += 1;
|
|
return 0;
|
|
}
|
|
|
|
static void set_func(m_option_t* opt,void* dst, void* src) {
|
|
int i;
|
|
if(opt->priv) ((m_opt_default_func_t)opt->priv)(opt,opt->name);
|
|
for(i = 0 ; i < VAL(src) ; i++)
|
|
((m_opt_func_t) opt->p)(opt);
|
|
}
|
|
|
|
m_option_type_t m_option_type_func = {
|
|
"Func",
|
|
"",
|
|
sizeof(int),
|
|
M_OPT_TYPE_INDIRECT,
|
|
parse_func,
|
|
NULL,
|
|
NULL, // Nothing to do on save
|
|
set_func,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
/////////////////// Print
|
|
|
|
static int parse_print(m_option_t* opt,char *name, char *param, void* dst, int src) {
|
|
if(opt->type->flags&M_OPT_TYPE_INDIRECT)
|
|
mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", *(char **) opt->p);
|
|
else
|
|
mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", (char *) opt->p);
|
|
|
|
if(opt->priv == NULL)
|
|
exit(1); // Call something else instead ??
|
|
return 1;
|
|
}
|
|
|
|
m_option_type_t m_option_type_print = {
|
|
"Print",
|
|
"",
|
|
0,
|
|
0,
|
|
parse_print,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
m_option_type_t m_option_type_print_indirect = {
|
|
"Print",
|
|
"",
|
|
0,
|
|
M_OPT_TYPE_INDIRECT,
|
|
parse_print,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
|
|
/////////////////////// Subconfig
|
|
#undef VAL
|
|
#define VAL(x) (*(char***)(x))
|
|
|
|
static int parse_subconf(m_option_t* opt,char *name, char *param, void* dst, int src) {
|
|
char *subparam;
|
|
char *subopt;
|
|
int nr = 0;
|
|
m_option_t *subopts;
|
|
char *token;
|
|
char *p;
|
|
char** lst = NULL;
|
|
|
|
if (param == NULL || strlen(param) == 0)
|
|
return M_OPT_MISSING_PARAM;
|
|
|
|
subparam = malloc(strlen(param)+1);
|
|
subopt = malloc(strlen(param)+1);
|
|
p = strdup(param); // In case that param is a static string (cf man strtok)
|
|
|
|
subopts = opt->p;
|
|
|
|
token = strtok(p, (char *)&(":"));
|
|
while(token)
|
|
{
|
|
int sscanf_ret;
|
|
/* clear out */
|
|
subopt[0] = subparam[0] = 0;
|
|
|
|
sscanf_ret = sscanf(token, "%[^=]=%[^:]", subopt, subparam);
|
|
|
|
mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "token: '%s', subopt='%s', subparam='%s' (ret: %d)\n", token, subopt, subparam, sscanf_ret);
|
|
switch(sscanf_ret)
|
|
{
|
|
case 1:
|
|
subparam[0] = 0;
|
|
case 2:
|
|
if(dst) {
|
|
lst = (char**)realloc(lst,2 * (nr+2) * sizeof(char*));
|
|
lst[2*nr] = strdup(subopt);
|
|
lst[2*nr+1] = subparam[0] == 0 ? NULL : strdup(subparam);
|
|
memset(&lst[2*(nr+1)],0,2*sizeof(char*));
|
|
nr++;
|
|
}
|
|
break;
|
|
default:
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid subconfig argument! ('%s')\n", token);
|
|
return M_OPT_INVALID;
|
|
}
|
|
token = strtok(NULL, (char *)&(":"));
|
|
}
|
|
|
|
free(subparam);
|
|
free(subopt);
|
|
free(p);
|
|
VAL(dst) = lst;
|
|
|
|
return 1;
|
|
}
|
|
|
|
m_option_type_t m_option_type_subconfig = {
|
|
"Subconfig",
|
|
"The syntax is -option opt1=foo:flag:opt2=blah",
|
|
sizeof(int),
|
|
M_OPT_TYPE_HAS_CHILD,
|
|
parse_subconf,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
#include "libmpcodecs/img_format.h"
|
|
// TODO : use an array so we parse/print easily
|
|
|
|
static int parse_imgfmt(m_option_t* opt,char *name, char *param, void* dst, int src) {
|
|
uint32_t fmt = 0;
|
|
|
|
if (param == NULL || strlen(param) == 0)
|
|
return M_OPT_MISSING_PARAM;
|
|
|
|
// From vf_format
|
|
if(!strcasecmp(param,"444p")) fmt=IMGFMT_444P; else
|
|
if(!strcasecmp(param,"422p")) fmt=IMGFMT_422P; else
|
|
if(!strcasecmp(param,"411p")) fmt=IMGFMT_411P; else
|
|
if(!strcasecmp(param,"yuy2")) fmt=IMGFMT_YUY2; else
|
|
if(!strcasecmp(param,"yv12")) fmt=IMGFMT_YV12; else
|
|
if(!strcasecmp(param,"i420")) fmt=IMGFMT_I420; else
|
|
if(!strcasecmp(param,"yvu9")) fmt=IMGFMT_YVU9; else
|
|
if(!strcasecmp(param,"if09")) fmt=IMGFMT_IF09; else
|
|
if(!strcasecmp(param,"iyuv")) fmt=IMGFMT_IYUV; else
|
|
if(!strcasecmp(param,"uyvy")) fmt=IMGFMT_UYVY; else
|
|
if(!strcasecmp(param,"bgr24")) fmt=IMGFMT_BGR24; else
|
|
if(!strcasecmp(param,"bgr32")) fmt=IMGFMT_BGR32; else
|
|
if(!strcasecmp(param,"bgr16")) fmt=IMGFMT_BGR16; else
|
|
if(!strcasecmp(param,"bgr15")) fmt=IMGFMT_BGR15; else
|
|
if(!strcasecmp(param,"bgr8")) fmt=IMGFMT_BGR8; else
|
|
if(!strcasecmp(param,"bgr4")) fmt=IMGFMT_BGR4; else
|
|
if(!strcasecmp(param,"bgr1")) fmt=IMGFMT_BGR1; else
|
|
if(!strcasecmp(param,"rgb24")) fmt=IMGFMT_RGB24; else
|
|
if(!strcasecmp(param,"rgb32")) fmt=IMGFMT_RGB32; else
|
|
if(!strcasecmp(param,"rgb16")) fmt=IMGFMT_RGB16; else
|
|
if(!strcasecmp(param,"rgb15")) fmt=IMGFMT_RGB15; else
|
|
if(!strcasecmp(param,"rgb8")) fmt=IMGFMT_RGB8; else
|
|
if(!strcasecmp(param,"rgb4")) fmt=IMGFMT_RGB4; else
|
|
if(!strcasecmp(param,"rgb1")) fmt=IMGFMT_RGB1; else {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: unknown format name: '%s'\n",param);
|
|
return M_OPT_INVALID;
|
|
}
|
|
|
|
if(dst)
|
|
*((uint32_t*)dst) = fmt;
|
|
|
|
return 1;
|
|
}
|
|
|
|
m_option_type_t m_option_type_imgfmt = {
|
|
"Image format (aka colorspace)",
|
|
"Pls report any missing colorspace",
|
|
sizeof(uint32_t),
|
|
0,
|
|
parse_imgfmt,
|
|
NULL,
|
|
copy_opt,
|
|
copy_opt,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
/// Span stuff : Not finished
|
|
static int parse_play_pos(m_play_pos_t* pos,char* opt, char *s) {
|
|
char *ep;
|
|
long tmp;
|
|
int i;
|
|
|
|
memset(pos,0,sizeof(m_play_pos_t));
|
|
|
|
if(!s || s[0] == '\0')
|
|
return M_OPT_MISSING_PARAM;
|
|
|
|
// Track index
|
|
tmp = strtol(s, &ep, 0);
|
|
if(ep != s) {
|
|
if(tmp < 1) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Track/Chapter index must be > 0\n", opt);
|
|
return M_OPT_OUT_OF_RANGE;
|
|
}
|
|
pos->idx = tmp;
|
|
if(ep[0] == '\0')
|
|
return 1;
|
|
s = ep;
|
|
}
|
|
|
|
// Span
|
|
tmp = strlen(s);
|
|
if(s[0] != '[' || s[tmp-1] != ']') {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: invalid argument ?\n", opt);
|
|
return M_OPT_INVALID;
|
|
}
|
|
s[tmp-1] = '\0';
|
|
s++;
|
|
|
|
// hh:mm:ss
|
|
for( i = 2 ; i >= 0 && s[0] != 0 ; i--) {
|
|
if(s[0] == ':') {
|
|
tmp = 0;
|
|
s++;
|
|
} else {
|
|
tmp = strtol(s, &ep, 0);
|
|
if(tmp < 0 || (ep[0] != '\0' && ep[0] != (i > 0 ? ':' : '.') )) {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: invalid argument ?\n", opt);
|
|
return M_OPT_INVALID;
|
|
}
|
|
pos->seconds += tmp * pow(60,i);
|
|
s = ep;
|
|
if(s[0] != '\0')
|
|
s++;
|
|
|
|
}
|
|
}
|
|
|
|
// sectors
|
|
if(s[0]) {
|
|
tmp = strtol(s, &ep, 0);
|
|
if(tmp < 0 || ep[0] != '\0') {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: invalid argument ?\n", opt);
|
|
return M_OPT_INVALID;
|
|
}
|
|
pos->sectors = tmp;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int parse_span(m_option_t* opt,char *name, char *param, void* dst, int src) {
|
|
m_span_t* span = dst;
|
|
char *s = param,*e = NULL;
|
|
int r = M_OPT_INVALID;
|
|
|
|
if(param == NULL)
|
|
return M_OPT_MISSING_PARAM;
|
|
|
|
e = strchr(param,'-');
|
|
if(e) {
|
|
e[0] = '\0';
|
|
e++;
|
|
}
|
|
|
|
if(s[0] == '\0' && e[0] == '\0') {
|
|
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: invalid argument\n");
|
|
return M_OPT_INVALID;
|
|
}
|
|
|
|
if(s[0]) {
|
|
r = parse_play_pos(&span->start,name,s);
|
|
if(r < 0) return r;
|
|
}
|
|
if(e && e[0] != '\0')
|
|
r = parse_play_pos(&span->end,name,s);
|
|
|
|
return r;
|
|
}
|
|
|
|
m_option_type_t m_option_type_span = {
|
|
"Span",
|
|
"The syntax is 1[hh:mm:ss.zz]-5[hh:mm:ss.zz]",
|
|
sizeof(m_span_t),
|
|
0,
|
|
parse_span,
|
|
NULL,
|
|
copy_opt,
|
|
copy_opt,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
#endif
|