From 1654c2bd80110fea2c2665b1a8499c7ee8eefd2a Mon Sep 17 00:00:00 2001 From: albeu Date: Tue, 29 May 2007 21:49:39 +0000 Subject: Rework the property API to allow sub properties such as metadata/title, etc. git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@23411 b3059339-0415-0410-9bf9-f77b7e298cf2 --- command.c | 76 +++++++++++++-------------------- libmenu/menu_param.c | 20 ++++----- m_property.c | 116 +++++++++++++++++++++++++++++++-------------------- m_property.h | 51 ++++++++++++++-------- 4 files changed, 144 insertions(+), 119 deletions(-) diff --git a/command.c b/command.c index 18f11cced9..fd9e8b0811 100644 --- a/command.c +++ b/command.c @@ -1410,17 +1410,17 @@ static m_option_t mp_properties[] = { }; -m_option_t *mp_property_find(const char *name) +int mp_property_do(const char *name, int action, void *val, void *ctx) { - return m_option_list_find(mp_properties, name); + return m_property_do(mp_properties, name, action, val, ctx); } -int mp_property_do(const char *name, int action, void *val, void *ctx) +char* mp_property_print(const char *name, void* ctx) { - m_option_t *p = mp_property_find(name); - if (!p) - return M_PROPERTY_UNAVAILABLE; - return m_property_do(p, action, val, ctx); + char* ret = NULL; + if(mp_property_do(name,M_PROPERTY_PRINT,&ret,ctx) <= 0) + return NULL; + return ret; } char *property_expand_string(MPContext * mpctx, char *str) @@ -1511,43 +1511,42 @@ static struct { static int set_property_command(MPContext * mpctx, mp_cmd_t * cmd) { int i, r; - m_option_t *prop; + m_option_t* prop; + const char *pname; // look for the command for (i = 0; set_prop_cmd[i].name; i++) if (set_prop_cmd[i].cmd == cmd->id) break; - if (!set_prop_cmd[i].name) + if (!(pname = set_prop_cmd[i].name)) return 0; - // get the property - prop = mp_property_find(set_prop_cmd[i].name); - if (!prop) - return 0; + if (mp_property_do(pname,M_PROPERTY_GET_TYPE,&prop,mpctx) <= 0 || !prop) + return 0; // toggle command if (set_prop_cmd[i].toggle) { // set to value if (cmd->nargs > 0 && cmd->args[0].v.i >= prop->min) - r = m_property_do(prop, M_PROPERTY_SET, &cmd->args[0].v.i, mpctx); + r = mp_property_do(pname, M_PROPERTY_SET, &cmd->args[0].v.i, mpctx); else - r = m_property_do(prop, M_PROPERTY_STEP_UP, NULL, mpctx); + r = mp_property_do(pname, M_PROPERTY_STEP_UP, NULL, mpctx); } else if (cmd->args[1].v.i) //set - r = m_property_do(prop, M_PROPERTY_SET, &cmd->args[0].v, mpctx); + r = mp_property_do(pname, M_PROPERTY_SET, &cmd->args[0].v, mpctx); else // adjust - r = m_property_do(prop, M_PROPERTY_STEP_UP, &cmd->args[0].v, mpctx); + r = mp_property_do(pname, M_PROPERTY_STEP_UP, &cmd->args[0].v, mpctx); if (r <= 0) return 1; if (set_prop_cmd[i].osd_progbar) { if (prop->type == CONF_TYPE_INT) { - if (m_property_do(prop, M_PROPERTY_GET, &r, mpctx) > 0) + if (mp_property_do(pname, M_PROPERTY_GET, &r, mpctx) > 0) set_osd_bar(set_prop_cmd[i].osd_progbar, set_prop_cmd[i].osd_msg, prop->min, prop->max, r); } else if (prop->type == CONF_TYPE_FLOAT) { float f; - if (m_property_do(prop, M_PROPERTY_GET, &f, mpctx) > 0) + if (mp_property_do(pname, M_PROPERTY_GET, &f, mpctx) > 0) set_osd_bar(set_prop_cmd[i].osd_progbar, set_prop_cmd[i].osd_msg, prop->min, prop->max, f); } else @@ -1557,7 +1556,7 @@ static int set_property_command(MPContext * mpctx, mp_cmd_t * cmd) } if (set_prop_cmd[i].osd_msg) { - char *val = m_property_print(prop, mpctx); + char *val = mp_property_print(pname, mpctx); if (val) { set_osd_msg(set_prop_cmd[i].osd_id >= 0 ? set_prop_cmd[i].osd_id : OSD_MSG_PROPERTY + i, @@ -1603,11 +1602,12 @@ int run_command(MPContext * mpctx, mp_cmd_t * cmd) break; case MP_CMD_SET_PROPERTY:{ - m_option_t *prop = mp_property_find(cmd->args[0].v.s); - if (!prop) + int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_PARSE, + cmd->args[1].v.s, mpctx); + if (r == M_PROPERTY_UNKNOWN) mp_msg(MSGT_CPLAYER, MSGL_WARN, "Unknown property: '%s'\n", cmd->args[0].v.s); - else if (m_property_parse(prop, cmd->args[1].v.s, mpctx) <= 0) + else if (r <= 0) mp_msg(MSGT_CPLAYER, MSGL_WARN, "Failed to set property '%s' to '%s'.\n", cmd->args[0].v.s, cmd->args[1].v.s); @@ -1615,14 +1615,14 @@ int run_command(MPContext * mpctx, mp_cmd_t * cmd) break; case MP_CMD_STEP_PROPERTY:{ - m_option_t *prop = mp_property_find(cmd->args[0].v.s); float arg = cmd->args[1].v.f; - if (!prop) + int r = mp_property_do + (cmd->args[0].v.s, M_PROPERTY_STEP_UP, + arg ? &arg : NULL, mpctx); + if (r == M_PROPERTY_UNKNOWN) mp_msg(MSGT_CPLAYER, MSGL_WARN, "Unknown property: '%s'\n", cmd->args[0].v.s); - else if (m_property_do - (prop, M_PROPERTY_STEP_UP, - arg ? &arg : NULL, mpctx) <= 0) + else if (r <= 0) mp_msg(MSGT_CPLAYER, MSGL_WARN, "Failed to increment property '%s' by %f.\n", cmd->args[0].v.s, arg); @@ -1630,30 +1630,14 @@ int run_command(MPContext * mpctx, mp_cmd_t * cmd) break; case MP_CMD_GET_PROPERTY:{ - m_option_t *prop; - void *val; char *tmp; - prop = mp_property_find(cmd->args[0].v.s); - if (!prop) { - mp_msg(MSGT_CPLAYER, MSGL_WARN, - "Unknown property: '%s'\n", cmd->args[0].v.s); - break; - } - /* Use m_option_print directly to get easily parseable values. */ - val = calloc(1, prop->type->size); - if (m_property_do(prop, M_PROPERTY_GET, val, mpctx) <= 0) { + if (mp_property_do(cmd->args[0].v.s, M_PROPERTY_TO_STRING, + &tmp, mpctx) <= 0) { mp_msg(MSGT_CPLAYER, MSGL_WARN, "Failed to get value of property '%s'.\n", cmd->args[0].v.s); break; } - tmp = m_option_print(prop, val); - if (!tmp || tmp == (char *) -1) { - mp_msg(MSGT_CPLAYER, MSGL_WARN, - "Failed to print value of property '%s'.\n", - cmd->args[0].v.s); - break; - } mp_msg(MSGT_GLOBAL, MSGL_INFO, "ANS_%s=%s\n", cmd->args[0].v.s, tmp); free(tmp); diff --git a/libmenu/menu_param.c b/libmenu/menu_param.c index 1be3c2e547..20cc120bd9 100644 --- a/libmenu/menu_param.c +++ b/libmenu/menu_param.c @@ -30,6 +30,7 @@ struct list_entry_s { struct list_entry p; char* name; + char* prop; m_option_t* opt; char* menu; }; @@ -76,10 +77,8 @@ static m_option_t cfg_fields[] = { #define OPT_INFO_TRACK "track" #define OPT_INFO_GENRE "genre" -m_option_t* mp_property_find(const char* name); - static void entry_set_text(menu_t* menu, list_entry_t* e) { - char* val = m_property_print(e->opt, menu->ctx); + char* val = mp_property_print(e->prop, menu->ctx); int l,edit = (mpriv->edit && e == mpriv->p.current); if(!val) { if(mpriv->hide_na) { @@ -99,7 +98,7 @@ static void entry_set_text(menu_t* menu, list_entry_t* e) { static void update_entries(menu_t* menu) { list_entry_t* e; for(e = mpriv->p.menu ; e ; e = e->p.next) - if(e->opt) entry_set_text(menu,e); + if(e->prop) entry_set_text(menu,e); } static int parse_args(menu_t* menu,char* args) { @@ -195,13 +194,13 @@ static int parse_args(menu_t* menu,char* args) { } name = asx_get_attrib("property",attribs); - opt = name ? mp_property_find(name) : NULL; - if(!opt) { + if(!name || mp_property_do(name,M_PROPERTY_GET_TYPE,&opt,menu->ctx) <= 0) { mp_msg(MSGT_OSD_MENU,MSGL_WARN,MSGTR_LIBMENU_PrefMenuEntryDefinitionsNeed,parser->line); goto next_element; } m = calloc(1,sizeof(struct list_entry_s)); m->opt = opt; + m->prop = strdup(name); m->name = asx_get_attrib("name",attribs); if(!m->name) m->name = strdup(opt->name); entry_set_text(menu,m); @@ -227,22 +226,22 @@ static void read_cmd(menu_t* menu,int cmd) { case MENU_CMD_UP: if(!mpriv->edit) break; case MENU_CMD_RIGHT: - if(m_property_do(e->opt,M_PROPERTY_STEP_UP,NULL,menu->ctx) > 0) + if(mp_property_do(e->prop,M_PROPERTY_STEP_UP,NULL,menu->ctx) > 0) update_entries(menu); return; case MENU_CMD_DOWN: if(!mpriv->edit) break; case MENU_CMD_LEFT: - if(m_property_do(e->opt,M_PROPERTY_STEP_DOWN,NULL,menu->ctx) > 0) + if(mp_property_do(e->prop,M_PROPERTY_STEP_DOWN,NULL,menu->ctx) > 0) update_entries(menu); return; case MENU_CMD_OK: // check that the property is writable - if(m_property_do(e->opt,M_PROPERTY_SET,NULL,menu->ctx) < 0) return; + if(mp_property_do(e->prop,M_PROPERTY_SET,NULL,menu->ctx) < 0) return; // shortcut for flags if(e->opt->type == CONF_TYPE_FLAG) { - if(m_property_do(e->opt,M_PROPERTY_STEP_UP,NULL,menu->ctx) > 0) + if(mp_property_do(e->prop,M_PROPERTY_STEP_UP,NULL,menu->ctx) > 0) update_entries(menu); return; } @@ -291,6 +290,7 @@ static void read_cmd(menu_t* menu,int cmd) { static void free_entry(list_entry_t* entry) { free(entry->p.txt); if(entry->name) free(entry->name); + if(entry->prop) free(entry->prop); if(entry->menu) free(entry->menu); free(entry); } diff --git a/m_property.c b/m_property.c index fe28f145b5..61d2ac33df 100644 --- a/m_property.c +++ b/m_property.c @@ -17,55 +17,84 @@ #define ROUND(x) ((int)((x)<0 ? (x)-0.5 : (x)+0.5)) -int m_property_do(m_option_t* prop, int action, void* arg, void *ctx) { +static int do_action(m_option_t* prop_list, const char* name, + int action, void* arg, void *ctx) { + const char* sep; + m_option_t* prop; + m_property_action_t ka; + int r; + if((sep = strchr(name,'/')) && sep[1]) { + int len = sep-name; + char base[len+1]; + memcpy(base,name,len); + base[len] = 0; + prop = m_option_list_find(prop_list, base); + ka.key = sep+1; + ka.action = action; + ka.arg = arg; + action = M_PROPERTY_KEY_ACTION; + arg = &ka; + } else + prop = m_option_list_find(prop_list, name); if(!prop) return M_PROPERTY_UNKNOWN; - return ((m_property_ctrl_f)prop->p)(prop,action,arg,ctx); -} - - -char* m_property_print(m_option_t* prop, void *ctx) { - m_property_ctrl_f ctrl; - void* val; - char* ret; - - if(!prop) return NULL; - - ctrl = prop->p; - // look if the property have it's own print func - if(ctrl(prop,M_PROPERTY_PRINT,&ret, ctx) >= 0) - return ret; - // fallback on the default print for this type - val = calloc(1,prop->type->size); - if(ctrl(prop,M_PROPERTY_GET,val,ctx) <= 0) { - free(val); - return NULL; + r = ((m_property_ctrl_f)prop->p)(prop,action,arg,ctx); + if(action == M_PROPERTY_GET_TYPE && r == M_PROPERTY_NOT_IMPLEMENTED) { + if(!arg) return M_PROPERTY_ERROR; + *(m_option_t**)arg = prop; + return M_PROPERTY_OK; } - ret = m_option_print(prop,val); - free(val); - return ret == (char*)-1 ? NULL : ret; + return r; } -int m_property_parse(m_option_t* prop, char* txt, void *ctx) { - m_property_ctrl_f ctrl; +int m_property_do(m_option_t* prop_list, const char* name, + int action, void* arg, void *ctx) { + m_option_t* opt; void* val; + char* str; int r; - - if(!prop) return M_PROPERTY_UNKNOWN; - ctrl = prop->p; - // try the property own parsing func - if((r = ctrl(prop,M_PROPERTY_PARSE,txt,ctx)) != M_PROPERTY_NOT_IMPLEMENTED) - return r; - // fallback on the default - val = calloc(1,prop->type->size); - if((r = m_option_parse(prop,prop->name,txt,val,M_CONFIG_FILE)) <= 0) { + switch(action) { + case M_PROPERTY_PRINT: + if((r = do_action(prop_list,name,M_PROPERTY_PRINT,arg,ctx)) >= 0) + return r; + // fallback on the default print for this type + case M_PROPERTY_TO_STRING: + if((r = do_action(prop_list,name,M_PROPERTY_TO_STRING,arg,ctx)) != + M_PROPERTY_NOT_IMPLEMENTED) + return r; + // fallback on the options API. Get the type, value and print. + if((r = do_action(prop_list,name,M_PROPERTY_GET_TYPE,&opt,ctx)) <= 0) + return r; + val = calloc(1,opt->type->size); + if((r = do_action(prop_list,name,M_PROPERTY_GET,val,ctx)) <= 0) { + free(val); + return r; + } + if(!arg) return M_PROPERTY_ERROR; + str = m_option_print(opt,val); + free(val); + *(char**)arg = str == (char*)-1 ? NULL : str; + return str != (char*)-1; + case M_PROPERTY_PARSE: + // try the property own parsing func + if((r = do_action(prop_list,name,M_PROPERTY_PARSE,arg,ctx)) != + M_PROPERTY_NOT_IMPLEMENTED) + return r; + // fallback on the options API, get the type and parse. + if((r = do_action(prop_list,name,M_PROPERTY_GET_TYPE,&opt,ctx)) <= 0) + return r; + if(!arg) return M_PROPERTY_ERROR; + val = calloc(1,opt->type->size); + if((r = m_option_parse(opt,opt->name,arg,val,M_CONFIG_FILE)) <= 0) { + free(val); + return r; + } + r = do_action(prop_list,name,M_PROPERTY_SET,val,ctx); + m_option_free(opt,val); free(val); return r; } - r = ctrl(prop,M_PROPERTY_SET,val,ctx); - m_option_free(prop,val); - free(val); - return r; + return do_action(prop_list,name,action,arg,ctx); } char* m_properties_expand_string(m_option_t* prop_list,char* str, void *ctx) { @@ -106,11 +135,10 @@ char* m_properties_expand_string(m_option_t* prop_list,char* str, void *ctx) { } else if(str[0] == '$' && str[1] == '{' && (e = strchr(str+2,'}'))) { int pl = e-str-2; char pname[pl+1]; - m_option_t* prop; memcpy(pname,str+2,pl); pname[pl] = 0; - if((prop = m_option_list_find(prop_list,pname)) && - (p = m_property_print(prop, ctx))) + if(m_property_do(prop_list, pname, + M_PROPERTY_PRINT, &p, ctx) >= 0 && p) l = strlen(p), fr = 1; else l = 0; @@ -118,13 +146,11 @@ char* m_properties_expand_string(m_option_t* prop_list,char* str, void *ctx) { } else if(str[0] == '?' && str[1] == '(' && (e = strchr(str+2,':'))) { int pl = e-str-2; char pname[pl+1]; - m_option_t* prop; lvl++; if(!skip) { memcpy(pname,str+2,pl); pname[pl] = 0; - if(!(prop = m_option_list_find(prop_list,pname)) || - m_property_do(prop,M_PROPERTY_GET,NULL, ctx) < 0) + if(m_property_do(prop_list,pname,M_PROPERTY_GET,NULL,ctx) < 0) skip = 1, skip_lvl = lvl; } str = e+1, l = 0; diff --git a/m_property.h b/m_property.h index f022fdd1bf..2d29507f68 100644 --- a/m_property.h +++ b/m_property.h @@ -48,6 +48,32 @@ */ #define M_PROPERTY_STEP_DOWN 5 +/// Get a string containg a parsable representation. +/** Set the variable to a newly allocated string or NULL. + * \param arg Pointer to a char* variable. + */ +#define M_PROPERTY_TO_STRING 6 + +/// Pass down an action to a sub-property. +#define M_PROPERTY_KEY_ACTION 7 + +/// Get a m_option describing the property. +#define M_PROPERTY_GET_TYPE 8 + +///@} + +/// \defgroup PropertyActionsArg Property actions argument type +/// \ingroup Properties +/// \brief Types used as action argument. +///@{ + +/// Argument for \ref M_PROPERTY_KEY_ACTION +typedef struct { + const char* key; + int action; + void* arg; +} m_property_action_t; + ///@} /// \defgroup PropertyActionsReturn Property actions return code @@ -81,25 +107,14 @@ typedef int(*m_property_ctrl_f)(m_option_t* prop,int action,void* arg,void *ctx); /// Do an action on a property. -/** \param prop The property. +/** \param prop_list The list of properties. + * \param prop The path of the property. * \param action See \ref PropertyActions. * \param arg Argument, usually a pointer to the data type used by the property. * \return See \ref PropertyActionsReturn. */ -int m_property_do(m_option_t* prop, int action, void* arg, void *ctx); - -/// Print the current value of a property. -/** \param prop The property. - * \return A newly allocated string with the current value or NULL on error. - */ -char* m_property_print(m_option_t* prop, void *ctx); - -/// Set a property. -/** \param prop The property. - * \param txt The value to set. - * \return 1 on success, 0 on error. - */ -int m_property_parse(m_option_t* prop, char* txt, void *ctx); +int m_property_do(m_option_t* prop_list, const char* prop, + int action, void* arg, void *ctx); /// Print a list of properties. void m_properties_print_help_list(m_option_t* list); @@ -119,12 +134,12 @@ char* m_properties_expand_string(m_option_t* prop_list,char* str, void *ctx); // Helpers to use MPlayer's properties -/// Get an MPlayer property. -m_option_t* mp_property_find(const char* name); - /// Do an action with an MPlayer property. int mp_property_do(const char* name,int action, void* val, void *ctx); +/// Get the value of a property as a string suitable for display in an UI. +char* mp_property_print(const char *name, void* ctx); + /// \defgroup PropertyImplHelper Property implementation helpers /// \ingroup Properties /// \brief Helper functions for common property types. -- cgit v1.2.3