📄 m_option.c
字号:
} ret[n*2] = ret[n*2+1] = NULL; *_ret = ret; return 1;}static int parse_obj_params(m_option_t* opt,char *name, char *param, void* dst, int src) { char** opts; int r; m_obj_params_t* p = opt->priv; m_struct_t* desc = p->desc; char* cpy = strdup(param); // We need the object desc if(!p) return M_OPT_INVALID; r = get_obj_params(name,desc->name,cpy,desc,p->separator,&opts); free(cpy); if(r < 0) return r; if(!dst) return 1; for(r = 0 ; opts[r] ; r += 2) m_struct_set(desc,dst,opts[r],opts[r+1]); return 1; }m_option_type_t m_option_type_obj_params = { "Object params", "", 0, 0, parse_obj_params, NULL, NULL, NULL, NULL, NULL};/// Some predefined types as a definition would be quite lengthy/// Span argumentsstatic m_span_t m_span_params_dflts = { -1, -1 };static m_option_t m_span_params_fields[] = { {"start", M_ST_OFF(m_span_t,start), CONF_TYPE_INT, M_OPT_MIN, 1 ,0, NULL}, {"end", M_ST_OFF(m_span_t,end), CONF_TYPE_INT, M_OPT_MIN , 1 ,0, NULL}, { NULL, NULL, 0, 0, 0, 0, NULL }};static struct m_struct_st m_span_opts = { "m_span", sizeof(m_span_t), &m_span_params_dflts, m_span_params_fields};m_obj_params_t m_span_params_def = { &m_span_opts, '-'};static int parse_obj_settings(char* opt,char* str,m_obj_list_t* list, m_obj_settings_t **_ret, int ret_n) { int r; char *param,**plist = NULL; m_struct_t* desc; m_obj_settings_t *ret = _ret ? *_ret : NULL; // Now check that the object exists param = strchr(str,'='); if(param) { param[0] = '\0'; param++; if(strlen(param) <= 0) param = NULL; } if(!find_obj_desc(str,list,&desc)) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: %s doesn't exist.\n",opt,str); return M_OPT_INVALID; } if(param) { if(!desc && _ret) { plist = calloc(4,sizeof(char*)); plist[0] = strdup("_oldargs_"); plist[1] = strdup(param); } else if(desc) { r = get_obj_params(opt,str,param,desc,':',_ret ? &plist : NULL); if(r < 0) return r; } } if(!_ret) return 1; ret = realloc(ret,(ret_n+2)*sizeof(m_obj_settings_t)); memset(&ret[ret_n],0,2*sizeof(m_obj_settings_t)); ret[ret_n].name = strdup(str); ret[ret_n].attribs = plist; *_ret = ret; return 1;}static void free_obj_settings_list(void* dst);static int obj_settings_list_del(char *opt_name,char *param,void* dst, int src) { char** str_list = NULL; int r,i,idx_max = 0; char* rem_id = "_removed_marker_"; m_option_t list_opt = {opt_name , NULL, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL }; m_obj_settings_t* obj_list = dst ? VAL(dst) : NULL; if(dst && !obj_list) { mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: the list is empty.\n",opt_name); return 1; } else if(obj_list) { for(idx_max = 0 ; obj_list[idx_max].name != NULL ; idx_max++) /* NOP */; } r = m_option_parse(&list_opt,opt_name,param,&str_list,src); if(r < 0 || !str_list) return r; for(r = 0 ; str_list[r] ; r++) { int id; char* endptr; id = strtol(str_list[r],&endptr,0); if(endptr == str_list[r]) { 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); m_option_free(&list_opt,&str_list); return M_OPT_INVALID; } if(!obj_list) continue; if(id >= idx_max || id < -idx_max) { mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: Index %d is out of range.\n",opt_name,id); continue; } if(id < 0) id = idx_max + id; free(obj_list[id].name); free_str_list(&(obj_list[id].attribs)); obj_list[id].name = rem_id; } if(!dst) { m_option_free(&list_opt,&str_list); return 1; } for(i = 0 ; obj_list[i].name ; i++) { while(obj_list[i].name == rem_id) { memmove(&obj_list[i],&obj_list[i+1],sizeof(m_obj_settings_t)*(idx_max - i)); idx_max--; } } obj_list = realloc(obj_list,sizeof(m_obj_settings_t)*(idx_max+1)); VAL(dst) = obj_list; return 1;}static int parse_obj_settings_list(m_option_t* opt,char *name, char *param, void* dst, int src) { int n = 0,r,len = strlen(opt->name); char *str; char *ptr, *last_ptr; m_obj_settings_t *res = NULL,*queue = NULL,*head = NULL; int op = OP_NONE; // We need the objects list if(!opt->priv) return M_OPT_INVALID; 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 { char prefix[len]; strncpy(prefix,opt->name,len-1); prefix[len-1] = '\0'; mp_msg(MSGT_VFILTER,MSGL_ERR, "Option %s: unknown postfix %s\n" "Supported postfixes are:\n" " %s-add\n" " Append the given list to the current list\n\n" " %s-pre\n" " Prepend the given list to the current list\n\n" " %s-del x,y,...\n" " Remove the given elements. Take the list element index (starting from 0).\n" " Negative index can be used (i.e. -1 is the last element)\n\n" " %s-clr\n" " Clear the current list.\n",name,n,prefix,prefix,prefix,prefix); return M_OPT_UNKNOWN; } } // Clear the list ?? if(op == OP_CLR) { if(dst) free_obj_settings_list(dst); return 0; } if (param == NULL || strlen(param) == 0) return M_OPT_MISSING_PARAM; switch(op) { case OP_ADD: if(dst) head = VAL(dst); break; case OP_PRE: if(dst) queue = VAL(dst); break; case OP_DEL: return obj_settings_list_del(name,param,dst,src); case OP_NONE: if(dst && VAL(dst)) free_obj_settings_list(dst); break; default: mp_msg(MSGT_VFILTER,MSGL_ERR, "Option %s: FIXME\n",name); return M_OPT_UNKNOWN; } if(!strcmp(param,"help")) { m_obj_list_t* ol = opt->priv; mp_msg(MSGT_VFILTER,MSGL_INFO,"Available video filters:\n"); for(n = 0 ; ol->list[n] ; n++) mp_msg(MSGT_VFILTER,MSGL_INFO," %-15s: %s\n", M_ST_MB(char*,ol->list[n],ol->name_off), M_ST_MB(char*,ol->list[n],ol->info_off)); return M_OPT_EXIT; } ptr = str = strdup(param); while(ptr[0] != '\0') { last_ptr = ptr; ptr = strchr(ptr,LIST_SEPARATOR); if(!ptr) { r = parse_obj_settings(name,last_ptr,opt->priv,dst ? &res : NULL,n); if(r < 0) { free(str); return r; } n++; break; } ptr[0] = '\0'; r = parse_obj_settings(name,last_ptr,opt->priv,dst ? &res : NULL,n); if(r < 0) { free(str); return r; } ptr++; n++; } free(str); 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) { if(queue) { int qsize; for(qsize = 0 ; queue[qsize].name ; qsize++) /* NOP */; res = realloc(res,(qsize+n+1)*sizeof(m_obj_settings_t)); memcpy(&res[n],queue,(qsize+1)*sizeof(m_obj_settings_t)); n += qsize; free(queue); } if(head) { int hsize; for(hsize = 0 ; head[hsize].name ; hsize++) /* NOP */; head = realloc(head,(hsize+n+1)*sizeof(m_obj_settings_t)); memcpy(&head[hsize],res,(n+1)*sizeof(m_obj_settings_t)); free(res); res = head; } VAL(dst) = res; } return 1;}static void free_obj_settings_list(void* dst) { int n; m_obj_settings_t *d; if(!dst || !VAL(dst)) return; d = VAL(dst);#ifndef NO_FREE for(n = 0 ; d[n].name ; n++) { free(d[n].name); free_str_list(&(d[n].attribs)); } free(d);#endif VAL(dst) = NULL;}static void copy_obj_settings_list(m_option_t* opt,void* dst, void* src) { m_obj_settings_t *d,*s; int n; if(!(dst && src)) return; s = VAL(src); if(VAL(dst)) free_obj_settings_list(dst); if(!s) return; for(n = 0 ; s[n].name ; n++) /* NOP */; d = malloc((n+1)*sizeof(m_obj_settings_t)); for(n = 0 ; s[n].name ; n++) { d[n].name = strdup(s[n].name); d[n].attribs = NULL; copy_str_list(NULL,&(d[n].attribs),&(s[n].attribs)); } d[n].name = NULL; d[n].attribs = NULL; VAL(dst) = d;}m_option_type_t m_option_type_obj_settings_list = { "Object settings list", "", sizeof(m_obj_settings_t*), M_OPT_TYPE_DYNAMIC|M_OPT_TYPE_ALLOW_WILDCARD, parse_obj_settings_list, NULL, copy_obj_settings_list, copy_obj_settings_list, copy_obj_settings_list, free_obj_settings_list,};static int parse_obj_presets(m_option_t* opt,char *name, char *param, void* dst, int src) { m_obj_presets_t* obj_p = (m_obj_presets_t*)opt->priv; m_struct_t *in_desc,*out_desc; int s,i; unsigned char* pre = obj_p->presets; char* pre_name = NULL; if(!obj_p) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Presets need a pointer to a m_obj_presets_t in the priv field.\n",name); return M_OPT_PARSER_ERR; } if(!param) return M_OPT_MISSING_PARAM; in_desc = obj_p->in_desc; out_desc = obj_p->out_desc ? obj_p->out_desc : obj_p->in_desc; s = in_desc->size; if(!strcmp(param,"help")) { mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available presets for %s->%s:",out_desc->name,name); for(pre = obj_p->presets;(pre_name = M_ST_MB(char*,pre,obj_p->name_off)) ; pre += s) mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %s",pre_name); mp_msg(MSGT_CFGPARSER, MSGL_ERR, "\n"); return M_OPT_EXIT; } for(pre_name = M_ST_MB(char*,pre,obj_p->name_off) ; pre_name ; pre += s, pre_name = M_ST_MB(char*,pre,obj_p->name_off)) { if(!strcmp(pre_name,param)) break; } if(!pre_name) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: There is no preset named %s\n" "Available presets are:",name,param); for(pre = obj_p->presets;(pre_name = M_ST_MB(char*,pre,obj_p->name_off)) ; pre += s) mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %s",pre_name); mp_msg(MSGT_CFGPARSER, MSGL_ERR, "\n"); return M_OPT_INVALID; } if(!dst) return 1; for(i = 0 ; in_desc->fields[i].name ; i++) { m_option_t* out_opt = m_option_list_find(out_desc->fields, in_desc->fields[i].name); if(!out_opt) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Unable to find the target option for field %s.\nPlease report this to the developers.\n",name,in_desc->fields[i].name); return M_OPT_PARSER_ERR; } m_option_copy(out_opt,M_ST_MB_P(dst,out_opt->p),M_ST_MB_P(pre,in_desc->fields[i].p)); } return 1;}m_option_type_t m_option_type_obj_presets = { "Object presets", "", 0, 0, parse_obj_presets, NULL, NULL, NULL, NULL, NULL};static int parse_custom_url(m_option_t* opt,char *name, char *url, void* dst, int src) { int pos1, pos2, r, v6addr = 0; char *ptr1=NULL, *ptr2=NULL, *ptr3=NULL, *ptr4=NULL; m_struct_t* desc = opt->priv; if(!desc) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Custom URL needs a pointer to a m_struct_t in the priv field.\n",name); return M_OPT_PARSER_ERR; } // extract the protocol ptr1 = strstr(url, "://"); if( ptr1==NULL ) { // Filename only if(m_option_list_find(desc->fields,"filename")) { m_struct_set(desc,dst,"filename",url); return 1; } mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Option %s: URL doesn't have a valid protocol!\n",name); return M_OPT_INVALID; } pos1 = ptr1-url; if(dst && m_option_list_find(desc->fields,"protocol")) { ptr1[0] = '\0'; r = m_struct_set(desc,dst,"protocol",url); ptr1[0] = ':'; if(r < 0) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting protocol.\n",name); return r; } } // jump the "://" ptr1 += 3; pos1 += 3; // check if a username:password is given ptr2 = strstr(ptr1, "@"); ptr3 = strstr(ptr1, "/"); if( ptr3!=NULL && ptr3<ptr2 ) { // it isn't really a username but rather a part of the path ptr2 = NULL; } if( ptr2!=NULL ) { // We got something, at least a username... int len = ptr2-ptr1; if(!m_option_list_find(desc->fields,"username")) { mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: This URL doesn't have a username part.\n",name); // skip } else { ptr3 = strstr(ptr1, ":"); if( ptr3!=NULL && ptr3<ptr2 ) { // We also have a password int len2 = ptr2-ptr3-1; if(!m_option_list_find(desc->fields,"password")) { mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: This URL doesn't have a password part.\n",name); // skip } else { // Username and password if(dst) { ptr3[0] = '\0'; r = m_struct_set(desc,dst,"username",ptr1); ptr3[0] = ':'; if(r < 0) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting username.\n",name); return r; } ptr2[0] = '\0'; r = m_struct_set(desc,dst,"password",ptr3+1); ptr2[0] = '@'; if(r < 0) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting password.\n",name); return r; } } } } else { // User name only ptr2[0] = '\0'; r = m_struct_set(desc,dst,"username",ptr1); ptr2[0] = '@'; if(r < 0) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting username.\n",name); return r; } } } ptr1 = ptr2+1; pos1 = ptr1-url; } // before looking for a port number check if we have an IPv6 type numeric address // in an IPv6 URL the numeric address should be inside square braces. ptr2 = strstr(ptr1, "["); ptr3 = strstr(ptr1, "]"); // If the [] is after the first it isn't the hostname ptr4 = strstr(ptr1, "/"); if( ptr2!=NULL && ptr3!=NULL && (ptr2 < ptr3) && (!ptr4 || ptr4 > ptr3)) { // we have an IPv6 numeric address ptr1++; pos1++; ptr2 = ptr3; v6addr = 1; } else { ptr2 = ptr1; } // look if the port is given ptr2 = strstr(ptr2, ":"); // If the : is after the first / it isn't the port ptr3 = strstr(ptr1, "/"); if(ptr3 && ptr3 - ptr2 < 0) ptr2 = NULL; if( ptr2==NULL ) { // No port is given // Look if a path is given if( ptr3==NULL ) { // No path/filename // So we have an URL like http://www.hostname.com pos2 = strlen(url); } else { // We have an URL like http://www.hostname.com/file.txt pos2 = ptr3-url; } } else { // We have an URL beginning like http://www.hostname.com:1212 // Get the port number if(!m_option_list_find(desc->fields,"port")) { mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: This URL doesn't have a port part.\n",name); // skip } else { if(dst) { int p = atoi(ptr2+1); char tmp[100]; snprintf(tmp,99,"%d",p); r = m_struct_set(desc,dst,"port",tmp); if(r < 0) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting port.\n",name); return r; } } } pos2 = ptr2-url; } if( v6addr ) pos2--; // Get the hostname if(pos2-pos1 > 0) { if(!m_option_list_find(desc->fields,"hostname")) { mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: This URL doesn't have a hostname part.\n",name); // skip } else { char tmp[pos2-pos1+1]; strncpy(tmp,ptr1, pos2-pos1); tmp[pos2-pos1] = '\0'; r = m_struct_set(desc,dst,"hostname",tmp); if(r < 0) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting hostname.\n",name); return r; } } } // Look if a path is given ptr2 = strstr(ptr1, "/"); if( ptr2!=NULL ) { // A path/filename is given // check if it's not a trailing '/' if( strlen(ptr2)>1 ) { // copy the path/filename in the URL container if(!m_option_list_find(desc->fields,"filename")) { mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: This URL doesn't have a hostname part.\n",name); // skip } else { if(dst) { int l = strlen(ptr2+1) + 1; char* fname = ptr2+1; if(l > 1) { fname = malloc(l); url_unescape_string(fname,ptr2+1); } r = m_struct_set(desc,dst,"filename",fname); if(fname != ptr2+1) free(fname); if(r < 0) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting filename.\n",name); return r; } } } } } return 1;}/// TODO : Write the other needed funcs for 'normal' optionsm_option_type_t m_option_type_custom_url = { "Custom URL", "", 0, 0, parse_custom_url, NULL, NULL, NULL, NULL, NULL};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -