X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fvariables.c;h=72a59ca0946e5e3cebff3ab8c9e214986d5acd13;hb=1171979d73a6ddd4da292e772aa8d29d0e581996;hp=3c73184ffbeeefa009ca115a7f35af41efbbb1a8;hpb=7ee2435d3083ccd4c3db1c586d5388e489f502fe;p=vlc diff --git a/src/misc/variables.c b/src/misc/variables.c index 3c73184ffb..72a59ca094 100644 --- a/src/misc/variables.c +++ b/src/misc/variables.c @@ -2,7 +2,7 @@ * variables.c: routines for object variables handling ***************************************************************************** * Copyright (C) 2002 VideoLAN - * $Id: variables.c,v 1.7 2002/10/16 19:39:42 sam Exp $ + * $Id: variables.c,v 1.21 2003/03/11 23:56:54 gbazin Exp $ * * Authors: Samuel Hocevar * @@ -10,7 +10,7 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -39,14 +39,36 @@ struct callback_entry_t void * p_data; }; +/***************************************************************************** + * Local comparison functions, returns 0 if v == w, < 0 if v < w, > 0 if v > w + *****************************************************************************/ +static int CmpBool( vlc_value_t v, vlc_value_t w ) { return v.b_bool ? w.b_bool ? 0 : 1 : w.b_bool ? -1 : 0; } +static int CmpInt( vlc_value_t v, vlc_value_t w ) { return v.i_int == w.i_int ? 0 : v.i_int > w.i_int ? 1 : -1; } +static int CmpString( vlc_value_t v, vlc_value_t w ) { return strcmp( v.psz_string, w.psz_string ); } +static int CmpFloat( vlc_value_t v, vlc_value_t w ) { return v.f_float == w.f_float ? 0 : v.f_float > w.f_float ? 1 : -1; } +static int CmpAddress( vlc_value_t v, vlc_value_t w ) { return v.p_address == w.p_address ? 0 : v.p_address > w.p_address ? 1 : -1; } + +/***************************************************************************** + * Local duplication functions, and local deallocation functions + *****************************************************************************/ +static void DupDummy( vlc_value_t *p_val ) { (void)p_val; /* unused */ } +static void DupString( vlc_value_t *p_val ) { p_val->psz_string = strdup( p_val->psz_string ); } + +static void FreeDummy( vlc_value_t *p_val ) { (void)p_val; /* unused */ } +static void FreeString( vlc_value_t *p_val ) { free( p_val->psz_string ); } +static void FreeMutex( vlc_value_t *p_val ) { vlc_mutex_destroy( (vlc_mutex_t*)p_val->p_address ); free( p_val->p_address ); } + /***************************************************************************** * Local prototypes *****************************************************************************/ -static u32 HashString ( const char * ); -static int Insert ( variable_t *, int, const char * ); -static int InsertInner ( variable_t *, int, u32 ); -static int Lookup ( variable_t *, int, const char * ); -static int LookupInner ( variable_t *, int, u32 ); +static int GetUnused ( vlc_object_t *, const char * ); +static uint32_t HashString ( const char * ); +static int Insert ( variable_t *, int, const char * ); +static int InsertInner ( variable_t *, int, uint32_t ); +static int Lookup ( variable_t *, int, const char * ); +static int LookupInner ( variable_t *, int, uint32_t ); + +static void CheckValue ( variable_t *, vlc_value_t * ); /***************************************************************************** * var_Create: initialize a vlc variable @@ -104,41 +126,64 @@ int __var_Create( vlc_object_t *p_this, const char *psz_name, int i_type ) p_var->i_type = i_type; memset( &p_var->val, 0, sizeof(vlc_value_t) ); + p_var->pf_dup = DupDummy; + p_var->pf_free = FreeDummy; + p_var->i_usage = 1; + p_var->i_default = -1; + p_var->choices.i_count = 0; + p_var->choices.p_values = NULL; + + p_var->b_incallback = VLC_FALSE; p_var->i_entries = 0; p_var->p_entries = NULL; - /* Always initialize the variable */ - switch( i_type ) + /* Always initialize the variable, even if it is a list variable; this + * will lead to errors if the variable is not initialized, but it will + * not cause crashes in the variable handling. */ + switch( i_type & VLC_VAR_TYPE ) { case VLC_VAR_BOOL: + p_var->pf_cmp = CmpBool; p_var->val.b_bool = VLC_FALSE; break; case VLC_VAR_INTEGER: + p_var->pf_cmp = CmpInt; p_var->val.i_int = 0; break; case VLC_VAR_STRING: case VLC_VAR_MODULE: case VLC_VAR_FILE: - p_var->val.psz_string = strdup( "" ); + case VLC_VAR_DIRECTORY: + case VLC_VAR_VARIABLE: + p_var->pf_cmp = CmpString; + p_var->pf_dup = DupString; + p_var->pf_free = FreeString; + p_var->val.psz_string = ""; break; case VLC_VAR_FLOAT: + p_var->pf_cmp = CmpFloat; p_var->val.f_float = 0.0; break; case VLC_VAR_TIME: - /* TODO */ + /* FIXME: TODO */ break; case VLC_VAR_ADDRESS: - case VLC_VAR_COMMAND: + p_var->pf_cmp = CmpAddress; p_var->val.p_address = NULL; break; case VLC_VAR_MUTEX: + p_var->pf_cmp = CmpAddress; + p_var->pf_free = FreeMutex; p_var->val.p_address = malloc( sizeof(vlc_mutex_t) ); vlc_mutex_init( p_this, (vlc_mutex_t*)p_var->val.p_address ); break; } + /* Duplicate the default data we stored. */ + p_var->pf_dup( &p_var->val ); + vlc_mutex_unlock( &p_this->var_lock ); return VLC_SUCCESS; @@ -152,20 +197,19 @@ int __var_Create( vlc_object_t *p_this, const char *psz_name, int i_type ) *****************************************************************************/ int __var_Destroy( vlc_object_t *p_this, const char *psz_name ) { - int i_del; + int i_var, i; variable_t *p_var; vlc_mutex_lock( &p_this->var_lock ); - i_del = Lookup( p_this->p_vars, p_this->i_vars, psz_name ); - - if( i_del < 0 ) + i_var = GetUnused( p_this, psz_name ); + if( i_var < 0 ) { vlc_mutex_unlock( &p_this->var_lock ); - return VLC_ENOVAR; + return i_var; } - p_var = &p_this->p_vars[i_del]; + p_var = &p_this->p_vars[i_var]; if( p_var->i_usage > 1 ) { @@ -175,18 +219,16 @@ int __var_Destroy( vlc_object_t *p_this, const char *psz_name ) } /* Free value if needed */ - switch( p_var->i_type ) - { - case VLC_VAR_STRING: - case VLC_VAR_MODULE: - case VLC_VAR_FILE: - free( p_var->val.psz_string ); - break; + p_var->pf_free( &p_var->val ); - case VLC_VAR_MUTEX: - vlc_mutex_destroy( (vlc_mutex_t*)p_var->val.p_address ); - free( p_var->val.p_address ); - break; + /* Free choice list if needed */ + if( p_var->choices.i_count ) + { + for( i = 0 ; i < p_var->choices.i_count ; i++ ) + { + p_var->pf_free( &p_var->choices.p_values[i] ); + } + free( p_var->choices.p_values ); } /* Free callbacks if needed */ @@ -197,9 +239,9 @@ int __var_Destroy( vlc_object_t *p_this, const char *psz_name ) free( p_var->psz_name ); - memmove( p_this->p_vars + i_del, - p_this->p_vars + i_del + 1, - (p_this->i_vars - i_del - 1) * sizeof(variable_t) ); + memmove( p_this->p_vars + i_var, + p_this->p_vars + i_var + 1, + (p_this->i_vars - i_var - 1) * sizeof(variable_t) ); if( (p_this->i_vars & 15) == 0 ) { @@ -215,9 +257,195 @@ int __var_Destroy( vlc_object_t *p_this, const char *psz_name ) } /***************************************************************************** - * var_Type: request a variable's type, 0 if not found + * var_Change: perform an action on a variable + ***************************************************************************** + * + *****************************************************************************/ +int __var_Change( vlc_object_t *p_this, const char *psz_name, + int i_action, vlc_value_t *p_val ) +{ + int i_var, i; + variable_t *p_var; + vlc_value_t oldval; + + vlc_mutex_lock( &p_this->var_lock ); + + i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name ); + + if( i_var < 0 ) + { + vlc_mutex_unlock( &p_this->var_lock ); + return VLC_ENOVAR; + } + + p_var = &p_this->p_vars[i_var]; + + switch( i_action ) + { + case VLC_VAR_SETMIN: + if( p_var->i_type & VLC_VAR_HASMIN ) + { + p_var->pf_free( &p_var->min ); + } + p_var->i_type |= VLC_VAR_HASMIN; + p_var->min = *p_val; + p_var->pf_dup( &p_var->min ); + CheckValue( p_var, &p_var->val ); + break; + case VLC_VAR_SETMAX: + if( p_var->i_type & VLC_VAR_HASMAX ) + { + p_var->pf_free( &p_var->max ); + } + p_var->i_type |= VLC_VAR_HASMAX; + p_var->max = *p_val; + p_var->pf_dup( &p_var->max ); + CheckValue( p_var, &p_var->val ); + break; + case VLC_VAR_SETSTEP: + if( p_var->i_type & VLC_VAR_HASSTEP ) + { + p_var->pf_free( &p_var->step ); + } + p_var->i_type |= VLC_VAR_HASSTEP; + p_var->step = *p_val; + p_var->pf_dup( &p_var->step ); + CheckValue( p_var, &p_var->val ); + break; + case VLC_VAR_ADDCHOICE: + /* FIXME: the list is sorted, dude. Use something cleverer. */ + for( i = p_var->choices.i_count ; i-- ; ) + { + if( p_var->pf_cmp( p_var->choices.p_values[i], *p_val ) < 0 ) + { + break; + } + } + + /* The new place is i+1 */ + i++; + + if( p_var->i_default >= i ) + { + p_var->i_default++; + } + + INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count, + i, *p_val ); + p_var->pf_dup( &p_var->choices.p_values[i] ); + + CheckValue( p_var, &p_var->val ); + break; + case VLC_VAR_DELCHOICE: + /* FIXME: the list is sorted, dude. Use something cleverer. */ + for( i = 0 ; i < p_var->choices.i_count ; i++ ) + { + if( p_var->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 ) + { + break; + } + } + + if( i == p_var->choices.i_count ) + { + /* Not found */ + vlc_mutex_unlock( &p_this->var_lock ); + return VLC_EGENERIC; + } + + if( p_var->i_default > i ) + { + p_var->i_default--; + } + else if( p_var->i_default == i ) + { + p_var->i_default = -1; + } + + p_var->pf_free( &p_var->choices.p_values[i] ); + REMOVE_ELEM( p_var->choices.p_values, p_var->choices.i_count, i ); + + CheckValue( p_var, &p_var->val ); + break; + case VLC_VAR_CLEARCHOICES: + for( i = 0 ; i < p_var->choices.i_count ; i++ ) + { + p_var->pf_free( &p_var->choices.p_values[i] ); + } + if( p_var->choices.i_count ) + free( p_var->choices.p_values ); + + p_var->choices.i_count = 0; + p_var->choices.p_values = NULL; + p_var->i_default = -1; + break; + case VLC_VAR_SETDEFAULT: + /* FIXME: the list is sorted, dude. Use something cleverer. */ + for( i = 0 ; i < p_var->choices.i_count ; i++ ) + { + if( p_var->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 ) + { + break; + } + } + + if( i == p_var->choices.i_count ) + { + /* Not found */ + break; + } + + p_var->i_default = i; + CheckValue( p_var, &p_var->val ); + break; + case VLC_VAR_SETVALUE: + /* Duplicate data if needed */ + p_var->pf_dup( p_val ); + /* Backup needed stuff */ + oldval = p_var->val; + /* Check boundaries and list */ + CheckValue( p_var, p_val ); + /* Set the variable */ + p_var->val = *p_val; + /* Free data if needed */ + p_var->pf_free( &oldval ); + break; + case VLC_VAR_GETLIST: + p_val->p_list = malloc( sizeof(vlc_list_t) ); + if( p_var->choices.i_count ) + p_val->p_list->p_values = malloc( p_var->choices.i_count + * sizeof(vlc_value_t) ); + p_val->p_list->i_count = p_var->choices.i_count; + for( i = 0 ; i < p_var->choices.i_count ; i++ ) + { + p_val->p_list->p_values[i] = p_var->choices.p_values[i]; + p_var->pf_dup( &p_val->p_list->p_values[i] ); + } + break; + case VLC_VAR_FREELIST: + for( i = p_val->p_list->i_count ; i-- ; ) + { + p_var->pf_free( &p_val->p_list->p_values[i] ); + } + if( p_val->p_list->i_count ) + free( p_val->p_list->p_values ); + free( p_val->p_list ); + break; + + default: + break; + } + + vlc_mutex_unlock( &p_this->var_lock ); + + return VLC_SUCCESS; +} + +/***************************************************************************** + * var_Type: request a variable's type ***************************************************************************** - * + * This function returns the variable type if it exists, or 0 if the + * variable could not be found. *****************************************************************************/ int __var_Type( vlc_object_t *p_this, const char *psz_name ) { @@ -253,55 +481,61 @@ int __var_Set( vlc_object_t *p_this, const char *psz_name, vlc_value_t val ) vlc_mutex_lock( &p_this->var_lock ); - i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name ); - + i_var = GetUnused( p_this, psz_name ); if( i_var < 0 ) { vlc_mutex_unlock( &p_this->var_lock ); - return VLC_ENOVAR; + return i_var; } p_var = &p_this->p_vars[i_var]; /* Duplicate data if needed */ - switch( p_var->i_type ) - { - case VLC_VAR_STRING: - case VLC_VAR_MODULE: - case VLC_VAR_FILE: - val.psz_string = strdup( val.psz_string ); - break; - } + p_var->pf_dup( &val ); /* Backup needed stuff */ oldval = p_var->val; + /* Check boundaries and list */ + CheckValue( p_var, &val ); + /* Set the variable */ p_var->val = val; - /* Deal with callbacks */ + /* Deal with callbacks. Tell we're in a callback, release the lock, + * call stored functions, retake the lock. */ if( p_var->i_entries ) { - int i; + int i_var; + int i_entries = p_var->i_entries; + callback_entry_t *p_entries = p_var->p_entries; + + p_var->b_incallback = VLC_TRUE; + vlc_mutex_unlock( &p_this->var_lock ); - for( i = p_var->i_entries ; i-- ; ) + /* The real calls */ + for( ; i_entries-- ; ) { - /* FIXME: oooh, see the deadlocks! see the race conditions! */ - p_var->p_entries[i].pf_callback( p_this, p_var->psz_name, - oldval, val, - p_var->p_entries[i].p_data ); + p_entries[i_entries].pf_callback( p_this, psz_name, oldval, val, + p_entries[i_entries].p_data ); } + + vlc_mutex_lock( &p_this->var_lock ); + + i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name ); + if( i_var < 0 ) + { + msg_Err( p_this, "variable %s has disappeared", psz_name ); + vlc_mutex_unlock( &p_this->var_lock ); + return VLC_ENOVAR; + } + + p_var = &p_this->p_vars[i_var]; + p_var->b_incallback = VLC_FALSE; } /* Free data if needed */ - switch( p_var->i_type ) - { - case VLC_VAR_STRING: - case VLC_VAR_MODULE: - case VLC_VAR_FILE: - free( oldval.psz_string ); - break; - } + p_var->pf_free( &oldval ); vlc_mutex_unlock( &p_this->var_lock ); @@ -330,45 +564,11 @@ int __var_Get( vlc_object_t *p_this, const char *psz_name, vlc_value_t *p_val ) p_var = &p_this->p_vars[i_var]; - /* Some variables trigger special behaviour. */ - switch( p_var->i_type ) - { - case VLC_VAR_COMMAND: - if( p_var->val.p_address ) - { - /* We need to save data before releasing the lock */ - int i_ret; - int (*pf_command) (vlc_object_t *, char *, char *) = - p_var->val.p_address; - char *psz_cmd = strdup( p_var->psz_name ); - char *psz_arg = strdup( p_val->psz_string ); - - vlc_mutex_unlock( &p_this->var_lock ); - - i_ret = pf_command( p_this, psz_cmd, psz_arg ); - free( psz_cmd ); - free( psz_arg ); - - return i_ret; - } - break; - } - - /* Really set the variable */ + /* Really get the variable */ *p_val = p_var->val; /* Duplicate value if needed */ - switch( p_var->i_type ) - { - case VLC_VAR_STRING: - case VLC_VAR_MODULE: - case VLC_VAR_FILE: - if( p_val->psz_string ) - { - p_val->psz_string = strdup( p_val->psz_string ); - } - break; - } + p_var->pf_dup( p_val ); vlc_mutex_unlock( &p_this->var_lock ); @@ -385,35 +585,29 @@ int __var_Get( vlc_object_t *p_this, const char *psz_name, vlc_value_t *p_val ) int __var_AddCallback( vlc_object_t *p_this, const char *psz_name, vlc_callback_t pf_callback, void *p_data ) { - int i_var, i_entry; + int i_var; variable_t *p_var; + callback_entry_t entry; + + entry.pf_callback = pf_callback; + entry.p_data = p_data; vlc_mutex_lock( &p_this->var_lock ); - i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name ); + i_var = GetUnused( p_this, psz_name ); if( i_var < 0 ) { vlc_mutex_unlock( &p_this->var_lock ); - return VLC_ENOVAR; + return i_var; } p_var = &p_this->p_vars[i_var]; - i_entry = p_var->i_entries++; - - if( i_entry ) - { - p_var->p_entries = realloc( p_var->p_entries, - sizeof( callback_entry_t ) * p_var->i_entries ); - } - else - { - p_var->p_entries = malloc( sizeof( callback_entry_t ) ); - } + INSERT_ELEM( p_var->p_entries, + p_var->i_entries, + p_var->i_entries, + entry ); - p_var->p_entries[ i_entry ].pf_callback = pf_callback; - p_var->p_entries[ i_entry ].p_data = p_data; - vlc_mutex_unlock( &p_this->var_lock ); return VLC_SUCCESS; @@ -428,16 +622,16 @@ int __var_AddCallback( vlc_object_t *p_this, const char *psz_name, int __var_DelCallback( vlc_object_t *p_this, const char *psz_name, vlc_callback_t pf_callback, void *p_data ) { - int i_var, i_entry; + int i_entry, i_var; variable_t *p_var; vlc_mutex_lock( &p_this->var_lock ); - i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name ); + i_var = GetUnused( p_this, psz_name ); if( i_var < 0 ) { vlc_mutex_unlock( &p_this->var_lock ); - return VLC_ENOVAR; + return i_var; } p_var = &p_this->p_vars[i_var]; @@ -445,7 +639,7 @@ int __var_DelCallback( vlc_object_t *p_this, const char *psz_name, for( i_entry = p_var->i_entries ; i_entry-- ; ) { if( p_var->p_entries[i_entry].pf_callback == pf_callback - || p_var->p_entries[i_entry].p_data == p_data ) + && p_var->p_entries[i_entry].p_data == p_data ) { break; } @@ -457,22 +651,7 @@ int __var_DelCallback( vlc_object_t *p_this, const char *psz_name, return VLC_EGENERIC; } - p_var->i_entries--; - - memmove( p_var->p_entries + i_entry, - p_var->p_entries + i_entry + 1, - sizeof( callback_entry_t ) * ( p_var->i_entries - i_entry ) ); - - if( p_var->i_entries ) - { - p_var->p_entries = realloc( p_var->p_entries, - sizeof( callback_entry_t ) * ( p_var->i_entries ) ); - } - else - { - free( p_var->p_entries ); - p_var->p_entries = NULL; - } + REMOVE_ELEM( p_var->p_entries, p_var->i_entries, i_entry ); vlc_mutex_unlock( &p_this->var_lock ); @@ -481,6 +660,41 @@ int __var_DelCallback( vlc_object_t *p_this, const char *psz_name, /* Following functions are local */ +/***************************************************************************** + * GetUnused: find an unused variable from its name + ***************************************************************************** + * We do i_tries tries before giving up, just in case the variable is being + * modified and called from a callback. + *****************************************************************************/ +static int GetUnused( vlc_object_t *p_this, const char *psz_name ) +{ + int i_var, i_tries = 0; + + while( VLC_TRUE ) + { + i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name ); + if( i_var < 0 ) + { + return VLC_ENOVAR; + } + + if( ! p_this->p_vars[i_var].b_incallback ) + { + return i_var; + } + + if( i_tries++ > 100 ) + { + msg_Err( p_this, "caught in a callback deadlock?" ); + return VLC_ETIMEOUT; + } + + vlc_mutex_unlock( &p_this->var_lock ); + msleep( THREAD_SLEEP ); + vlc_mutex_lock( &p_this->var_lock ); + } +} + /***************************************************************************** * HashString: our cool hash function ***************************************************************************** @@ -488,9 +702,9 @@ int __var_DelCallback( vlc_object_t *p_this, const char *psz_name, * fast and not suck too much. This one is pretty fast and did 0 collisions * in wenglish's dictionary. *****************************************************************************/ -static u32 HashString( const char *psz_string ) +static uint32_t HashString( const char *psz_string ) { - u32 i_hash = 0; + uint32_t i_hash = 0; while( *psz_string ) { @@ -520,7 +734,7 @@ static int Insert( variable_t *p_vars, int i_count, const char *psz_name ) return InsertInner( p_vars, i_count, HashString( psz_name ) ); } -static int InsertInner( variable_t *p_vars, int i_count, u32 i_hash ) +static int InsertInner( variable_t *p_vars, int i_count, uint32_t i_hash ) { int i_middle; @@ -562,7 +776,7 @@ static int InsertInner( variable_t *p_vars, int i_count, u32 i_hash ) *****************************************************************************/ static int Lookup( variable_t *p_vars, int i_count, const char *psz_name ) { - u32 i_hash; + uint32_t i_hash; int i, i_pos; if( i_count == 0 ) @@ -609,7 +823,7 @@ static int Lookup( variable_t *p_vars, int i_count, const char *psz_name ) return -1; } -static int LookupInner( variable_t *p_vars, int i_count, u32 i_hash ) +static int LookupInner( variable_t *p_vars, int i_count, uint32_t i_hash ) { int i_middle; @@ -642,3 +856,84 @@ static int LookupInner( variable_t *p_vars, int i_count, u32 i_hash ) return i_middle; } +/***************************************************************************** + * 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; + } +}