+/*****************************************************************************
+ * CheckValue: check that a value is valid wrt. a variable
+ *****************************************************************************
+ * This function checks p_val's value against p_var's limitations such as
+ * minimal and maximal value, step, in-list position, and modifies p_val if
+ * necessary.
+ ****************************************************************************/
+static void CheckValue ( variable_t *p_var, vlc_value_t *p_val )
+{
+ /* Check that our variable is in the list */
+ if( p_var->i_type & VLC_VAR_HASCHOICE && p_var->choices.i_count )
+ {
+ int i;
+
+ /* FIXME: the list is sorted, dude. Use something cleverer. */
+ for( i = p_var->choices.i_count ; i-- ; )
+ {
+ if( p_var->pf_cmp( *p_val, p_var->choices.p_values[i] ) == 0 )
+ {
+ break;
+ }
+ }
+
+ /* If not found, change it to anything vaguely valid */
+ if( i < 0 )
+ {
+ /* Free the old variable, get the new one, dup it */
+ p_var->pf_free( p_val );
+ *p_val = p_var->choices.p_values[p_var->i_default >= 0
+ ? p_var->i_default : 0 ];
+ p_var->pf_dup( p_val );
+ }
+ }
+
+ /* Check that our variable is within the bounds */
+ switch( p_var->i_type & VLC_VAR_TYPE )
+ {
+ case VLC_VAR_INTEGER:
+ if( p_var->i_type & VLC_VAR_HASSTEP && p_var->step.i_int
+ && (p_val->i_int % p_var->step.i_int) )
+ {
+ p_val->i_int = (p_val->i_int + (p_var->step.i_int / 2))
+ / p_var->step.i_int * p_var->step.i_int;
+ }
+ if( p_var->i_type & VLC_VAR_HASMIN
+ && p_val->i_int < p_var->min.i_int )
+ {
+ p_val->i_int = p_var->min.i_int;
+ }
+ if( p_var->i_type & VLC_VAR_HASMAX
+ && p_val->i_int > p_var->max.i_int )
+ {
+ p_val->i_int = p_var->max.i_int;
+ }
+ break;
+ case VLC_VAR_FLOAT:
+ if( p_var->i_type & VLC_VAR_HASSTEP && p_var->step.f_float )
+ {
+ float f_round = p_var->step.f_float * (float)(int)( 0.5 +
+ p_val->f_float / p_var->step.f_float );
+ if( p_val->f_float != f_round )
+ {
+ p_val->f_float = f_round;
+ }
+ }
+ if( p_var->i_type & VLC_VAR_HASMIN
+ && p_val->f_float < p_var->min.f_float )
+ {
+ p_val->f_float = p_var->min.f_float;
+ }
+ if( p_var->i_type & VLC_VAR_HASMAX
+ && p_val->f_float > p_var->max.f_float )
+ {
+ p_val->f_float = p_var->max.f_float;
+ }
+ break;
+ case VLC_VAR_TIME:
+ /* FIXME: TODO */
+ break;
+ }
+}
+
+/*****************************************************************************
+ * InheritValue: try to inherit the value of this variable from the same one
+ * in our closest parent.
+ *****************************************************************************/
+static int InheritValue( vlc_object_t *p_this, const char *psz_name,
+ vlc_value_t *p_val, int i_type )
+{
+ int i_var;
+ variable_t *p_var;
+
+ /* No need to take the structure lock,
+ * we are only looking for our parents */
+
+ if( !p_this->p_parent )
+ {
+ switch( i_type & VLC_VAR_TYPE )
+ {
+ case VLC_VAR_FILE:
+ case VLC_VAR_DIRECTORY:
+ case VLC_VAR_STRING:
+ case VLC_VAR_MODULE:
+ p_val->psz_string = config_GetPsz( p_this, psz_name );
+ if( !p_val->psz_string ) p_val->psz_string = strdup("");
+ break;
+ case VLC_VAR_FLOAT:
+ p_val->f_float = config_GetFloat( p_this, psz_name );
+ break;
+ case VLC_VAR_INTEGER:
+ case VLC_VAR_HOTKEY:
+ p_val->i_int = config_GetInt( p_this, psz_name );
+ break;
+ case VLC_VAR_BOOL:
+ p_val->b_bool = config_GetInt( p_this, psz_name );
+ break;
+ case VLC_VAR_LIST:
+ {
+ char *psz_orig, *psz_var;
+ vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
+ p_val->p_list = p_list;
+ p_list->i_count = 0;
+
+ psz_var = psz_orig = config_GetPsz( p_this, psz_name );
+ while( psz_var && *psz_var )
+ {
+ char *psz_item = psz_var;
+ vlc_value_t val;
+ while( *psz_var && *psz_var != ',' ) psz_var++;
+ if( *psz_var == ',' )
+ {
+ *psz_var = '\0';
+ psz_var++;
+ }
+ val.i_int = strtol( psz_item, NULL, 0 );
+ INSERT_ELEM( p_list->p_values, p_list->i_count,
+ p_list->i_count, val );
+ /* p_list->i_count is incremented twice by INSERT_ELEM */
+ p_list->i_count--;
+ INSERT_ELEM( p_list->pi_types, p_list->i_count,
+ p_list->i_count, VLC_VAR_INTEGER );
+ }
+ free( psz_orig );
+ break;
+ }
+ default:
+ return VLC_ENOOBJ;
+ break;
+ }
+
+ return VLC_SUCCESS;
+ }
+
+ vlc_object_internals_t *p_priv = vlc_internals( p_this->p_parent );
+
+ /* Look for the variable */
+ vlc_mutex_lock( &p_priv->var_lock );
+
+ i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
+
+ if( i_var >= 0 )
+ {
+ /* We found it! */
+ p_var = &p_priv->p_vars[i_var];
+
+ /* Really get the variable */
+ *p_val = p_var->val;
+
+ /* Duplicate value if needed */
+ p_var->pf_dup( p_val );
+
+ vlc_mutex_unlock( &p_priv->var_lock );
+ return VLC_SUCCESS;
+ }
+
+ vlc_mutex_unlock( &p_priv->var_lock );
+
+ /* We're still not there */
+
+ return InheritValue( p_this->p_parent, psz_name, p_val, i_type );
+}
+
+/**********************************************************************
+ * Execute a var command on an object identified by its name
+ **********************************************************************/
+int __var_Command( vlc_object_t *p_this, const char *psz_name,
+ const char *psz_cmd, const char *psz_arg, char **psz_msg )
+{
+ vlc_object_t *p_obj = vlc_object_find_name( p_this->p_libvlc,
+ psz_name, FIND_CHILD );
+ int i_type, i_ret;
+
+ if( !p_obj )
+ {
+ if( psz_msg )
+ *psz_msg = strdup( "Unknown destination object." );
+ return VLC_ENOOBJ;
+ }
+
+ vlc_refcheck( p_this );
+ i_type = var_Type( p_obj, psz_cmd );
+ if( !( i_type&VLC_VAR_ISCOMMAND ) )
+ {
+ vlc_object_release( p_obj );
+ if( psz_msg )
+ *psz_msg = strdup( "Variable doesn't exist or isn't a command." );
+ return VLC_EGENERIC;
+ }
+
+ i_type &= 0xf0;
+ switch( i_type )
+ {
+ case VLC_VAR_INTEGER:
+ i_ret = var_SetInteger( p_obj, psz_cmd, atoi( psz_arg ) );
+ break;
+ case VLC_VAR_FLOAT:
+ i_ret = var_SetFloat( p_obj, psz_cmd, atof( psz_arg ) );
+ break;
+ case VLC_VAR_STRING:
+ i_ret = var_SetString( p_obj, psz_cmd, psz_arg );
+ break;
+ case VLC_VAR_BOOL:
+ i_ret = var_SetBool( p_obj, psz_cmd, atoi( psz_arg ) );
+ break;
+ default:
+ i_ret = VLC_EGENERIC;
+ break;
+ }
+
+ vlc_object_release( p_obj );
+
+ if( psz_msg )
+ {
+ *psz_msg = (char*)malloc( 80 );
+ sprintf( *psz_msg, "%s on object %s returned %i (%s)",
+ psz_cmd, psz_name, i_ret, vlc_error( i_ret ) );
+ }
+
+ return i_ret;
+}