00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <vlc/vlc.h>
00028
00029 #ifdef HAVE_STDLIB_H
00030 # include <stdlib.h>
00031 #endif
00032
00033
00034
00035
00036 struct callback_entry_t
00037 {
00038 vlc_callback_t pf_callback;
00039 void * p_data;
00040 };
00041
00042
00043
00044
00045 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; }
00046 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; }
00047 static int CmpTime( vlc_value_t v, vlc_value_t w )
00048 {
00049 return v.i_time == w.i_time ? 0 : v.i_time > w.i_time ? 1 : -1;
00050 }
00051 static int CmpString( vlc_value_t v, vlc_value_t w ) { return strcmp( v.psz_string, w.psz_string ); }
00052 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; }
00053 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; }
00054
00055
00056
00057
00058 static void DupDummy( vlc_value_t *p_val ) { (void)p_val; }
00059 static void DupString( vlc_value_t *p_val ) { p_val->psz_string = strdup( p_val->psz_string ); }
00060
00061 static void DupList( vlc_value_t *p_val )
00062 {
00063 int i;
00064 vlc_list_t *p_list = malloc( sizeof(vlc_list_t) );
00065
00066 p_list->i_count = p_val->p_list->i_count;
00067 if( p_val->p_list->i_count )
00068 {
00069 p_list->p_values = malloc( p_list->i_count * sizeof(vlc_value_t) );
00070 p_list->pi_types = malloc( p_list->i_count * sizeof(int) );
00071 }
00072 else
00073 {
00074 p_list->p_values = NULL;
00075 p_list->pi_types = NULL;
00076 }
00077
00078 for( i = 0; i < p_list->i_count; i++ )
00079 {
00080 p_list->p_values[i] = p_val->p_list->p_values[i];
00081 p_list->pi_types[i] = p_val->p_list->pi_types[i];
00082 switch( p_val->p_list->pi_types[i] & VLC_VAR_TYPE )
00083 {
00084 case VLC_VAR_STRING:
00085
00086 DupString( &p_list->p_values[i] );
00087 break;
00088 default:
00089 break;
00090 }
00091 }
00092
00093 p_val->p_list = p_list;
00094 }
00095
00096 static void FreeDummy( vlc_value_t *p_val ) { (void)p_val; }
00097 static void FreeString( vlc_value_t *p_val ) { free( p_val->psz_string ); }
00098 static void FreeMutex( vlc_value_t *p_val ) { vlc_mutex_destroy( (vlc_mutex_t*)p_val->p_address ); free( p_val->p_address ); }
00099
00100 static void FreeList( vlc_value_t *p_val )
00101 {
00102 int i;
00103 for( i = 0; i < p_val->p_list->i_count; i++ )
00104 {
00105 switch( p_val->p_list->pi_types[i] & VLC_VAR_TYPE )
00106 {
00107 case VLC_VAR_STRING:
00108 FreeString( &p_val->p_list->p_values[i] );
00109 break;
00110 case VLC_VAR_MUTEX:
00111 FreeMutex( &p_val->p_list->p_values[i] );
00112 break;
00113 default:
00114 break;
00115 }
00116 }
00117
00118 if( p_val->p_list->i_count )
00119 {
00120 free( p_val->p_list->p_values );
00121 free( p_val->p_list->pi_types );
00122 }
00123 free( p_val->p_list );
00124 }
00125
00126
00127
00128
00129 static int GetUnused ( vlc_object_t *, const char * );
00130 static uint32_t HashString ( const char * );
00131 static int Insert ( variable_t *, int, const char * );
00132 static int InsertInner ( variable_t *, int, uint32_t );
00133 static int Lookup ( variable_t *, int, const char * );
00134 static int LookupInner ( variable_t *, int, uint32_t );
00135
00136 static void CheckValue ( variable_t *, vlc_value_t * );
00137
00138 static int InheritValue( vlc_object_t *, const char *, vlc_value_t *,
00139 int );
00140
00153 int __var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
00154 {
00155 int i_new;
00156 variable_t *p_var;
00157 static vlc_list_t dummy_null_list = {0, NULL, NULL};
00158
00159 vlc_mutex_lock( &p_this->var_lock );
00160
00161
00162
00163
00164
00165 i_new = Lookup( p_this->p_vars, p_this->i_vars, psz_name );
00166
00167 if( i_new >= 0 )
00168 {
00169
00170 if( (i_type & ~VLC_VAR_DOINHERIT) != p_this->p_vars[i_new].i_type )
00171 {
00172 vlc_mutex_unlock( &p_this->var_lock );
00173 return VLC_EBADVAR;
00174 }
00175
00176 p_this->p_vars[i_new].i_usage++;
00177 vlc_mutex_unlock( &p_this->var_lock );
00178 return VLC_SUCCESS;
00179 }
00180
00181 i_new = Insert( p_this->p_vars, p_this->i_vars, psz_name );
00182
00183 if( (p_this->i_vars & 15) == 15 )
00184 {
00185 p_this->p_vars = realloc( p_this->p_vars,
00186 (p_this->i_vars+17) * sizeof(variable_t) );
00187 }
00188
00189 memmove( p_this->p_vars + i_new + 1,
00190 p_this->p_vars + i_new,
00191 (p_this->i_vars - i_new) * sizeof(variable_t) );
00192
00193 p_this->i_vars++;
00194
00195 p_var = &p_this->p_vars[i_new];
00196 memset( p_var, 0, sizeof(*p_var) );
00197
00198 p_var->i_hash = HashString( psz_name );
00199 p_var->psz_name = strdup( psz_name );
00200 p_var->psz_text = NULL;
00201
00202 p_var->i_type = i_type & ~VLC_VAR_DOINHERIT;
00203 memset( &p_var->val, 0, sizeof(vlc_value_t) );
00204
00205 p_var->pf_dup = DupDummy;
00206 p_var->pf_free = FreeDummy;
00207
00208 p_var->i_usage = 1;
00209
00210 p_var->i_default = -1;
00211 p_var->choices.i_count = 0;
00212 p_var->choices.p_values = NULL;
00213 p_var->choices_text.i_count = 0;
00214 p_var->choices_text.p_values = NULL;
00215
00216 p_var->b_incallback = VLC_FALSE;
00217 p_var->i_entries = 0;
00218 p_var->p_entries = NULL;
00219
00220
00221
00222
00223 switch( i_type & VLC_VAR_TYPE )
00224 {
00225 case VLC_VAR_BOOL:
00226 p_var->pf_cmp = CmpBool;
00227 p_var->val.b_bool = VLC_FALSE;
00228 break;
00229 case VLC_VAR_INTEGER:
00230 case VLC_VAR_HOTKEY:
00231 p_var->pf_cmp = CmpInt;
00232 p_var->val.i_int = 0;
00233 break;
00234 case VLC_VAR_STRING:
00235 case VLC_VAR_MODULE:
00236 case VLC_VAR_FILE:
00237 case VLC_VAR_DIRECTORY:
00238 case VLC_VAR_VARIABLE:
00239 p_var->pf_cmp = CmpString;
00240 p_var->pf_dup = DupString;
00241 p_var->pf_free = FreeString;
00242 p_var->val.psz_string = "";
00243 break;
00244 case VLC_VAR_FLOAT:
00245 p_var->pf_cmp = CmpFloat;
00246 p_var->val.f_float = 0.0;
00247 break;
00248 case VLC_VAR_TIME:
00249 p_var->pf_cmp = CmpTime;
00250 p_var->val.i_time = 0;
00251 break;
00252 case VLC_VAR_ADDRESS:
00253 p_var->pf_cmp = CmpAddress;
00254 p_var->val.p_address = NULL;
00255 break;
00256 case VLC_VAR_MUTEX:
00257 p_var->pf_cmp = CmpAddress;
00258 p_var->pf_free = FreeMutex;
00259 p_var->val.p_address = malloc( sizeof(vlc_mutex_t) );
00260 vlc_mutex_init( p_this, (vlc_mutex_t*)p_var->val.p_address );
00261 break;
00262 case VLC_VAR_LIST:
00263 p_var->pf_cmp = CmpAddress;
00264 p_var->pf_dup = DupList;
00265 p_var->pf_free = FreeList;
00266 p_var->val.p_list = &dummy_null_list;
00267 break;
00268 }
00269
00270
00271 p_var->pf_dup( &p_var->val );
00272
00273 if( i_type & VLC_VAR_DOINHERIT )
00274 {
00275 vlc_value_t val;
00276
00277 if( InheritValue( p_this, psz_name, &val, p_var->i_type )
00278 == VLC_SUCCESS );
00279 {
00280
00281 p_var->pf_free( &p_var->val );
00282
00283 p_var->val = val;
00284
00285 if( i_type & VLC_VAR_HASCHOICE )
00286 {
00287
00288 p_var->i_default = 0;
00289
00290 INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count,
00291 0, val );
00292 INSERT_ELEM( p_var->choices_text.p_values,
00293 p_var->choices_text.i_count, 0, val );
00294 p_var->pf_dup( &p_var->choices.p_values[0] );
00295 p_var->choices_text.p_values[0].psz_string = NULL;
00296 }
00297 }
00298 }
00299
00300 vlc_mutex_unlock( &p_this->var_lock );
00301
00302 return VLC_SUCCESS;
00303 }
00304
00314 int __var_Destroy( vlc_object_t *p_this, const char *psz_name )
00315 {
00316 int i_var, i;
00317 variable_t *p_var;
00318
00319 vlc_mutex_lock( &p_this->var_lock );
00320
00321 i_var = GetUnused( p_this, psz_name );
00322 if( i_var < 0 )
00323 {
00324 vlc_mutex_unlock( &p_this->var_lock );
00325 return i_var;
00326 }
00327
00328 p_var = &p_this->p_vars[i_var];
00329
00330 if( p_var->i_usage > 1 )
00331 {
00332 p_var->i_usage--;
00333 vlc_mutex_unlock( &p_this->var_lock );
00334 return VLC_SUCCESS;
00335 }
00336
00337
00338 p_var->pf_free( &p_var->val );
00339
00340
00341 if( p_var->choices.i_count )
00342 {
00343 for( i = 0 ; i < p_var->choices.i_count ; i++ )
00344 {
00345 p_var->pf_free( &p_var->choices.p_values[i] );
00346 if( p_var->choices_text.p_values[i].psz_string )
00347 free( p_var->choices_text.p_values[i].psz_string );
00348 }
00349 free( p_var->choices.p_values );
00350 free( p_var->choices_text.p_values );
00351 }
00352
00353
00354 if( p_var->p_entries )
00355 {
00356 free( p_var->p_entries );
00357 }
00358
00359 free( p_var->psz_name );
00360 if( p_var->psz_text ) free( p_var->psz_text );
00361
00362 memmove( p_this->p_vars + i_var,
00363 p_this->p_vars + i_var + 1,
00364 (p_this->i_vars - i_var - 1) * sizeof(variable_t) );
00365
00366 if( (p_this->i_vars & 15) == 0 )
00367 {
00368 p_this->p_vars = realloc( p_this->p_vars,
00369 (p_this->i_vars) * sizeof( variable_t ) );
00370 }
00371
00372 p_this->i_vars--;
00373
00374 vlc_mutex_unlock( &p_this->var_lock );
00375
00376 return VLC_SUCCESS;
00377 }
00378
00388 int __var_Change( vlc_object_t *p_this, const char *psz_name,
00389 int i_action, vlc_value_t *p_val, vlc_value_t *p_val2 )
00390 {
00391 int i_var, i;
00392 variable_t *p_var;
00393 vlc_value_t oldval;
00394
00395 vlc_mutex_lock( &p_this->var_lock );
00396
00397 i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name );
00398
00399 if( i_var < 0 )
00400 {
00401 vlc_mutex_unlock( &p_this->var_lock );
00402 return VLC_ENOVAR;
00403 }
00404
00405 p_var = &p_this->p_vars[i_var];
00406
00407 switch( i_action )
00408 {
00409 case VLC_VAR_SETMIN:
00410 if( p_var->i_type & VLC_VAR_HASMIN )
00411 {
00412 p_var->pf_free( &p_var->min );
00413 }
00414 p_var->i_type |= VLC_VAR_HASMIN;
00415 p_var->min = *p_val;
00416 p_var->pf_dup( &p_var->min );
00417 CheckValue( p_var, &p_var->val );
00418 break;
00419 case VLC_VAR_SETMAX:
00420 if( p_var->i_type & VLC_VAR_HASMAX )
00421 {
00422 p_var->pf_free( &p_var->max );
00423 }
00424 p_var->i_type |= VLC_VAR_HASMAX;
00425 p_var->max = *p_val;
00426 p_var->pf_dup( &p_var->max );
00427 CheckValue( p_var, &p_var->val );
00428 break;
00429 case VLC_VAR_SETSTEP:
00430 if( p_var->i_type & VLC_VAR_HASSTEP )
00431 {
00432 p_var->pf_free( &p_var->step );
00433 }
00434 p_var->i_type |= VLC_VAR_HASSTEP;
00435 p_var->step = *p_val;
00436 p_var->pf_dup( &p_var->step );
00437 CheckValue( p_var, &p_var->val );
00438 break;
00439 case VLC_VAR_ADDCHOICE:
00440
00441 for( i = p_var->choices.i_count ; i-- ; )
00442 {
00443 if( p_var->pf_cmp( p_var->choices.p_values[i], *p_val ) < 0 )
00444 {
00445 break;
00446 }
00447 }
00448
00449
00450 i++;
00451
00452 if( p_var->i_default >= i )
00453 {
00454 p_var->i_default++;
00455 }
00456
00457 INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count,
00458 i, *p_val );
00459 INSERT_ELEM( p_var->choices_text.p_values,
00460 p_var->choices_text.i_count, i, *p_val );
00461 p_var->pf_dup( &p_var->choices.p_values[i] );
00462 p_var->choices_text.p_values[i].psz_string =
00463 ( p_val2 && p_val2->psz_string ) ?
00464 strdup( p_val2->psz_string ) : NULL;
00465
00466 CheckValue( p_var, &p_var->val );
00467 break;
00468 case VLC_VAR_DELCHOICE:
00469
00470 for( i = 0 ; i < p_var->choices.i_count ; i++ )
00471 {
00472 if( p_var->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 )
00473 {
00474 break;
00475 }
00476 }
00477
00478 if( i == p_var->choices.i_count )
00479 {
00480
00481 vlc_mutex_unlock( &p_this->var_lock );
00482 return VLC_EGENERIC;
00483 }
00484
00485 if( p_var->i_default > i )
00486 {
00487 p_var->i_default--;
00488 }
00489 else if( p_var->i_default == i )
00490 {
00491 p_var->i_default = -1;
00492 }
00493
00494 p_var->pf_free( &p_var->choices.p_values[i] );
00495 if( p_var->choices_text.p_values[i].psz_string )
00496 free( p_var->choices_text.p_values[i].psz_string );
00497 REMOVE_ELEM( p_var->choices.p_values, p_var->choices.i_count, i );
00498 REMOVE_ELEM( p_var->choices_text.p_values,
00499 p_var->choices_text.i_count, i );
00500
00501 CheckValue( p_var, &p_var->val );
00502 break;
00503 case VLC_VAR_CHOICESCOUNT:
00504 p_val->i_int = p_var->choices.i_count;
00505 break;
00506 case VLC_VAR_CLEARCHOICES:
00507 for( i = 0 ; i < p_var->choices.i_count ; i++ )
00508 {
00509 p_var->pf_free( &p_var->choices.p_values[i] );
00510 }
00511 for( i = 0 ; i < p_var->choices_text.i_count ; i++ )
00512 {
00513 if( p_var->choices_text.p_values[i].psz_string )
00514 free( p_var->choices_text.p_values[i].psz_string );
00515 }
00516 if( p_var->choices.i_count ) free( p_var->choices.p_values );
00517 if( p_var->choices_text.i_count ) free( p_var->choices_text.p_values );
00518
00519 p_var->choices.i_count = 0;
00520 p_var->choices.p_values = NULL;
00521 p_var->choices_text.i_count = 0;
00522 p_var->choices_text.p_values = NULL;
00523 p_var->i_default = -1;
00524 break;
00525 case VLC_VAR_SETDEFAULT:
00526
00527 for( i = 0 ; i < p_var->choices.i_count ; i++ )
00528 {
00529 if( p_var->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 )
00530 {
00531 break;
00532 }
00533 }
00534
00535 if( i == p_var->choices.i_count )
00536 {
00537
00538 break;
00539 }
00540
00541 p_var->i_default = i;
00542 CheckValue( p_var, &p_var->val );
00543 break;
00544 case VLC_VAR_SETVALUE:
00545
00546 p_var->pf_dup( p_val );
00547
00548 oldval = p_var->val;
00549
00550 CheckValue( p_var, p_val );
00551
00552 p_var->val = *p_val;
00553
00554 p_var->pf_free( &oldval );
00555 break;
00556 case VLC_VAR_GETCHOICES:
00557 case VLC_VAR_GETLIST:
00558 p_val->p_list = malloc( sizeof(vlc_list_t) );
00559 if( p_val2 ) p_val2->p_list = malloc( sizeof(vlc_list_t) );
00560 if( p_var->choices.i_count )
00561 {
00562 p_val->p_list->p_values = malloc( p_var->choices.i_count
00563 * sizeof(vlc_value_t) );
00564 p_val->p_list->pi_types = malloc( p_var->choices.i_count
00565 * sizeof(int) );
00566 if( p_val2 )
00567 {
00568 p_val2->p_list->p_values =
00569 malloc( p_var->choices.i_count * sizeof(vlc_value_t) );
00570 p_val2->p_list->pi_types =
00571 malloc( p_var->choices.i_count * sizeof(int) );
00572 }
00573 }
00574 p_val->p_list->i_count = p_var->choices.i_count;
00575 if( p_val2 ) p_val2->p_list->i_count = p_var->choices.i_count;
00576 for( i = 0 ; i < p_var->choices.i_count ; i++ )
00577 {
00578 p_val->p_list->p_values[i] = p_var->choices.p_values[i];
00579 p_val->p_list->pi_types[i] = p_var->i_type;
00580 p_var->pf_dup( &p_val->p_list->p_values[i] );
00581 if( p_val2 )
00582 {
00583 p_val2->p_list->p_values[i].psz_string =
00584 p_var->choices_text.p_values[i].psz_string ?
00585 strdup(p_var->choices_text.p_values[i].psz_string) : NULL;
00586 p_val2->p_list->pi_types[i] = VLC_VAR_STRING;
00587 }
00588 }
00589 break;
00590 case VLC_VAR_FREELIST:
00591 FreeList( p_val );
00592 if( p_val2 && p_val2->p_list )
00593 {
00594 for( i = 0; i < p_val2->p_list->i_count; i++ )
00595 if( p_val2->p_list->p_values[i].psz_string )
00596 free( p_val2->p_list->p_values[i].psz_string );
00597 if( p_val2->p_list->i_count )
00598 {
00599 free( p_val2->p_list->p_values );
00600 free( p_val2->p_list->pi_types );
00601 }
00602 free( p_val2->p_list );
00603 }
00604 break;
00605 case VLC_VAR_SETTEXT:
00606 if( p_var->psz_text ) free( p_var->psz_text );
00607 if( p_val && p_val->psz_string )
00608 p_var->psz_text = strdup( p_val->psz_string );
00609 break;
00610 case VLC_VAR_GETTEXT:
00611 p_val->psz_string = NULL;
00612 if( p_var->psz_text )
00613 {
00614 p_val->psz_string = strdup( p_var->psz_text );
00615 }
00616 break;
00617 case VLC_VAR_INHERITVALUE:
00618 {
00619 vlc_value_t val;
00620
00621 if( InheritValue( p_this, psz_name, &val, p_var->i_type )
00622 == VLC_SUCCESS );
00623 {
00624
00625
00626
00627 oldval = p_var->val;
00628
00629 CheckValue( p_var, &val );
00630
00631 p_var->val = val;
00632
00633 p_var->pf_free( &oldval );
00634 }
00635
00636 if( p_val )
00637 {
00638 *p_val = p_var->val;
00639 p_var->pf_dup( p_val );
00640 }
00641 }
00642 break;
00643 case VLC_VAR_TRIGGER_CALLBACKS:
00644 {
00645
00646
00647 if( p_var->i_entries )
00648 {
00649 int i_var;
00650 int i_entries = p_var->i_entries;
00651 callback_entry_t *p_entries = p_var->p_entries;
00652
00653 p_var->b_incallback = VLC_TRUE;
00654 vlc_mutex_unlock( &p_this->var_lock );
00655
00656
00657 for( ; i_entries-- ; )
00658 {
00659 p_entries[i_entries].pf_callback( p_this, psz_name, p_var->val, p_var->val,
00660 p_entries[i_entries].p_data );
00661 }
00662
00663 vlc_mutex_lock( &p_this->var_lock );
00664
00665 i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name );
00666 if( i_var < 0 )
00667 {
00668 msg_Err( p_this, "variable %s has disappeared", psz_name );
00669 vlc_mutex_unlock( &p_this->var_lock );
00670 return VLC_ENOVAR;
00671 }
00672
00673 p_var = &p_this->p_vars[i_var];
00674 p_var->b_incallback = VLC_FALSE;
00675 }
00676 }
00677 break;
00678
00679 default:
00680 break;
00681 }
00682
00683 vlc_mutex_unlock( &p_this->var_lock );
00684
00685 return VLC_SUCCESS;
00686 }
00687
00695 int __var_Type( vlc_object_t *p_this, const char *psz_name )
00696 {
00697 int i_var, i_type;
00698
00699 vlc_mutex_lock( &p_this->var_lock );
00700
00701 i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name );
00702
00703 if( i_var < 0 )
00704 {
00705 vlc_mutex_unlock( &p_this->var_lock );
00706 return 0;
00707 }
00708
00709 i_type = p_this->p_vars[i_var].i_type;
00710
00711 vlc_mutex_unlock( &p_this->var_lock );
00712
00713 return i_type;
00714 }
00715
00723 int __var_Set( vlc_object_t *p_this, const char *psz_name, vlc_value_t val )
00724 {
00725 int i_var;
00726 variable_t *p_var;
00727 vlc_value_t oldval;
00728
00729 vlc_mutex_lock( &p_this->var_lock );
00730
00731 i_var = GetUnused( p_this, psz_name );
00732 if( i_var < 0 )
00733 {
00734 vlc_mutex_unlock( &p_this->var_lock );
00735 return i_var;
00736 }
00737
00738 p_var = &p_this->p_vars[i_var];
00739
00740
00741 p_var->pf_dup( &val );
00742
00743
00744 oldval = p_var->val;
00745
00746
00747 CheckValue( p_var, &val );
00748
00749
00750 p_var->val = val;
00751
00752
00753
00754 if( p_var->i_entries )
00755 {
00756 int i_var;
00757 int i_entries = p_var->i_entries;
00758 callback_entry_t *p_entries = p_var->p_entries;
00759
00760 p_var->b_incallback = VLC_TRUE;
00761 vlc_mutex_unlock( &p_this->var_lock );
00762
00763
00764 for( ; i_entries-- ; )
00765 {
00766 p_entries[i_entries].pf_callback( p_this, psz_name, oldval, val,
00767 p_entries[i_entries].p_data );
00768 }
00769
00770 vlc_mutex_lock( &p_this->var_lock );
00771
00772 i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name );
00773 if( i_var < 0 )
00774 {
00775 msg_Err( p_this, "variable %s has disappeared", psz_name );
00776 vlc_mutex_unlock( &p_this->var_lock );
00777 return VLC_ENOVAR;
00778 }
00779
00780 p_var = &p_this->p_vars[i_var];
00781 p_var->b_incallback = VLC_FALSE;
00782 }
00783
00784
00785 p_var->pf_free( &oldval );
00786
00787 vlc_mutex_unlock( &p_this->var_lock );
00788
00789 return VLC_SUCCESS;
00790 }
00791
00800 int __var_Get( vlc_object_t *p_this, const char *psz_name, vlc_value_t *p_val )
00801 {
00802 int i_var;
00803 variable_t *p_var;
00804
00805 vlc_mutex_lock( &p_this->var_lock );
00806
00807 i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name );
00808
00809 if( i_var < 0 )
00810 {
00811 vlc_mutex_unlock( &p_this->var_lock );
00812 return VLC_ENOVAR;
00813 }
00814
00815 p_var = &p_this->p_vars[i_var];
00816
00817
00818 *p_val = p_var->val;
00819
00820
00821 p_var->pf_dup( p_val );
00822
00823 vlc_mutex_unlock( &p_this->var_lock );
00824
00825 return VLC_SUCCESS;
00826 }
00827
00844 int __var_AddCallback( vlc_object_t *p_this, const char *psz_name,
00845 vlc_callback_t pf_callback, void *p_data )
00846 {
00847 int i_var;
00848 variable_t *p_var;
00849 callback_entry_t entry;
00850
00851 entry.pf_callback = pf_callback;
00852 entry.p_data = p_data;
00853
00854 vlc_mutex_lock( &p_this->var_lock );
00855
00856 i_var = GetUnused( p_this, psz_name );
00857 if( i_var < 0 )
00858 {
00859 vlc_mutex_unlock( &p_this->var_lock );
00860 return i_var;
00861 }
00862
00863 p_var = &p_this->p_vars[i_var];
00864
00865 INSERT_ELEM( p_var->p_entries,
00866 p_var->i_entries,
00867 p_var->i_entries,
00868 entry );
00869
00870 vlc_mutex_unlock( &p_this->var_lock );
00871
00872 return VLC_SUCCESS;
00873 }
00874
00881 int __var_DelCallback( vlc_object_t *p_this, const char *psz_name,
00882 vlc_callback_t pf_callback, void *p_data )
00883 {
00884 int i_entry, i_var;
00885 variable_t *p_var;
00886
00887 vlc_mutex_lock( &p_this->var_lock );
00888
00889 i_var = GetUnused( p_this, psz_name );
00890 if( i_var < 0 )
00891 {
00892 vlc_mutex_unlock( &p_this->var_lock );
00893 return i_var;
00894 }
00895
00896 p_var = &p_this->p_vars[i_var];
00897
00898 for( i_entry = p_var->i_entries ; i_entry-- ; )
00899 {
00900 if( p_var->p_entries[i_entry].pf_callback == pf_callback
00901 && p_var->p_entries[i_entry].p_data == p_data )
00902 {
00903 break;
00904 }
00905 }
00906
00907 if( i_entry < 0 )
00908 {
00909 vlc_mutex_unlock( &p_this->var_lock );
00910 return VLC_EGENERIC;
00911 }
00912
00913 REMOVE_ELEM( p_var->p_entries, p_var->i_entries, i_entry );
00914
00915 vlc_mutex_unlock( &p_this->var_lock );
00916
00917 return VLC_SUCCESS;
00918 }
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928 static int GetUnused( vlc_object_t *p_this, const char *psz_name )
00929 {
00930 int i_var, i_tries = 0;
00931
00932 while( VLC_TRUE )
00933 {
00934 i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name );
00935 if( i_var < 0 )
00936 {
00937 return VLC_ENOVAR;
00938 }
00939
00940 if( ! p_this->p_vars[i_var].b_incallback )
00941 {
00942 return i_var;
00943 }
00944
00945 if( i_tries++ > 100 )
00946 {
00947 msg_Err( p_this, "caught in a callback deadlock?" );
00948 return VLC_ETIMEOUT;
00949 }
00950
00951 vlc_mutex_unlock( &p_this->var_lock );
00952 msleep( THREAD_SLEEP );
00953 vlc_mutex_lock( &p_this->var_lock );
00954 }
00955 }
00956
00957
00958
00959
00960
00961
00962
00963
00964 static uint32_t HashString( const char *psz_string )
00965 {
00966 uint32_t i_hash = 0;
00967
00968 while( *psz_string )
00969 {
00970 i_hash += *psz_string++;
00971 i_hash += i_hash << 10;
00972 i_hash ^= i_hash >> 8;
00973 }
00974
00975 return i_hash;
00976 }
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986 static int Insert( variable_t *p_vars, int i_count, const char *psz_name )
00987 {
00988 if( i_count == 0 )
00989 {
00990 return 0;
00991 }
00992
00993 return InsertInner( p_vars, i_count, HashString( psz_name ) );
00994 }
00995
00996 static int InsertInner( variable_t *p_vars, int i_count, uint32_t i_hash )
00997 {
00998 int i_middle;
00999
01000 if( i_hash <= p_vars[0].i_hash )
01001 {
01002 return 0;
01003 }
01004
01005 if( i_hash >= p_vars[i_count - 1].i_hash )
01006 {
01007 return i_count;
01008 }
01009
01010 i_middle = i_count / 2;
01011
01012
01013 if( i_hash < p_vars[i_middle].i_hash )
01014 {
01015 return InsertInner( p_vars, i_middle, i_hash );
01016 }
01017
01018
01019 if( i_hash > p_vars[i_middle + 1].i_hash )
01020 {
01021 return i_middle + 1 + InsertInner( p_vars + i_middle + 1,
01022 i_count - i_middle - 1,
01023 i_hash );
01024 }
01025
01026 return i_middle + 1;
01027 }
01028
01029
01030
01031
01032
01033
01034
01035
01036 static int Lookup( variable_t *p_vars, int i_count, const char *psz_name )
01037 {
01038 uint32_t i_hash;
01039 int i, i_pos;
01040
01041 if( i_count == 0 )
01042 {
01043 return -1;
01044 }
01045
01046 i_hash = HashString( psz_name );
01047
01048 i_pos = LookupInner( p_vars, i_count, i_hash );
01049
01050
01051 if( i_hash != p_vars[i_pos].i_hash )
01052 {
01053 return -1;
01054 }
01055
01056
01057 if( !strcmp( psz_name, p_vars[i_pos].psz_name ) )
01058 {
01059 return i_pos;
01060 }
01061
01062
01063
01064
01065 for( i = i_pos - 1 ; i > 0 && i_hash == p_vars[i].i_hash ; i-- )
01066 {
01067 if( !strcmp( psz_name, p_vars[i].psz_name ) )
01068 {
01069 return i;
01070 }
01071 }
01072
01073 for( i = i_pos + 1 ; i < i_count && i_hash == p_vars[i].i_hash ; i++ )
01074 {
01075 if( !strcmp( psz_name, p_vars[i].psz_name ) )
01076 {
01077 return i;
01078 }
01079 }
01080
01081
01082 return -1;
01083 }
01084
01085 static int LookupInner( variable_t *p_vars, int i_count, uint32_t i_hash )
01086 {
01087 int i_middle;
01088
01089 if( i_hash <= p_vars[0].i_hash )
01090 {
01091 return 0;
01092 }
01093
01094 if( i_hash >= p_vars[i_count-1].i_hash )
01095 {
01096 return i_count - 1;
01097 }
01098
01099 i_middle = i_count / 2;
01100
01101
01102 if( i_hash < p_vars[i_middle].i_hash )
01103 {
01104 return LookupInner( p_vars, i_middle, i_hash );
01105 }
01106
01107
01108 if( i_hash > p_vars[i_middle].i_hash )
01109 {
01110 return i_middle + LookupInner( p_vars + i_middle,
01111 i_count - i_middle,
01112 i_hash );
01113 }
01114
01115 return i_middle;
01116 }
01117
01118
01119
01120
01121
01122
01123
01124
01125 static void CheckValue ( variable_t *p_var, vlc_value_t *p_val )
01126 {
01127
01128 if( p_var->i_type & VLC_VAR_HASCHOICE && p_var->choices.i_count )
01129 {
01130 int i;
01131
01132
01133 for( i = p_var->choices.i_count ; i-- ; )
01134 {
01135 if( p_var->pf_cmp( *p_val, p_var->choices.p_values[i] ) == 0 )
01136 {
01137 break;
01138 }
01139 }
01140
01141
01142 if( i < 0 )
01143 {
01144
01145 p_var->pf_free( p_val );
01146 *p_val = p_var->choices.p_values[p_var->i_default >= 0
01147 ? p_var->i_default : 0 ];
01148 p_var->pf_dup( p_val );
01149 }
01150 }
01151
01152
01153 switch( p_var->i_type & VLC_VAR_TYPE )
01154 {
01155 case VLC_VAR_INTEGER:
01156 if( p_var->i_type & VLC_VAR_HASSTEP && p_var->step.i_int
01157 && (p_val->i_int % p_var->step.i_int) )
01158 {
01159 p_val->i_int = (p_val->i_int + (p_var->step.i_int / 2))
01160 / p_var->step.i_int * p_var->step.i_int;
01161 }
01162 if( p_var->i_type & VLC_VAR_HASMIN
01163 && p_val->i_int < p_var->min.i_int )
01164 {
01165 p_val->i_int = p_var->min.i_int;
01166 }
01167 if( p_var->i_type & VLC_VAR_HASMAX
01168 && p_val->i_int > p_var->max.i_int )
01169 {
01170 p_val->i_int = p_var->max.i_int;
01171 }
01172 break;
01173 case VLC_VAR_FLOAT:
01174 if( p_var->i_type & VLC_VAR_HASSTEP && p_var->step.f_float )
01175 {
01176 float f_round = p_var->step.f_float * (float)(int)( 0.5 +
01177 p_val->f_float / p_var->step.f_float );
01178 if( p_val->f_float != f_round )
01179 {
01180 p_val->f_float = f_round;
01181 }
01182 }
01183 if( p_var->i_type & VLC_VAR_HASMIN
01184 && p_val->f_float < p_var->min.f_float )
01185 {
01186 p_val->f_float = p_var->min.f_float;
01187 }
01188 if( p_var->i_type & VLC_VAR_HASMAX
01189 && p_val->f_float > p_var->max.f_float )
01190 {
01191 p_val->f_float = p_var->max.f_float;
01192 }
01193 break;
01194 case VLC_VAR_TIME:
01195
01196 break;
01197 }
01198 }
01199
01200
01201
01202
01203
01204 static int InheritValue( vlc_object_t *p_this, const char *psz_name,
01205 vlc_value_t *p_val, int i_type )
01206 {
01207 int i_var;
01208 variable_t *p_var;
01209
01210
01211
01212
01213 if( !p_this->p_parent )
01214 {
01215 switch( i_type & VLC_VAR_TYPE )
01216 {
01217 case VLC_VAR_FILE:
01218 case VLC_VAR_DIRECTORY:
01219 case VLC_VAR_STRING:
01220 case VLC_VAR_MODULE:
01221 p_val->psz_string = config_GetPsz( p_this, psz_name );
01222 if( !p_val->psz_string ) p_val->psz_string = strdup("");
01223 break;
01224 case VLC_VAR_FLOAT:
01225 p_val->f_float = config_GetFloat( p_this, psz_name );
01226 break;
01227 case VLC_VAR_INTEGER:
01228 case VLC_VAR_HOTKEY:
01229 p_val->i_int = config_GetInt( p_this, psz_name );
01230 break;
01231 case VLC_VAR_BOOL:
01232 p_val->b_bool = config_GetInt( p_this, psz_name );
01233 break;
01234 case VLC_VAR_LIST:
01235 {
01236 char *psz_orig, *psz_var;
01237 vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
01238 p_val->p_list = p_list;
01239 p_list->i_count = 0;
01240
01241 psz_var = psz_orig = config_GetPsz( p_this, psz_name );
01242 while( psz_var && *psz_var )
01243 {
01244 char *psz_item = psz_var;
01245 vlc_value_t val;
01246 while( *psz_var && *psz_var != ',' ) psz_var++;
01247 if( *psz_var == ',' )
01248 {
01249 *psz_var = '\0';
01250 psz_var++;
01251 }
01252 val.i_int = strtol( psz_item, NULL, 0 );
01253 INSERT_ELEM( p_list->p_values, p_list->i_count,
01254 p_list->i_count, val );
01255
01256 p_list->i_count--;
01257 INSERT_ELEM( p_list->pi_types, p_list->i_count,
01258 p_list->i_count, VLC_VAR_INTEGER );
01259 }
01260 if( psz_orig ) free( psz_orig );
01261 break;
01262 }
01263 default:
01264 return VLC_ENOOBJ;
01265 break;
01266 }
01267
01268 return VLC_SUCCESS;
01269 }
01270
01271
01272 vlc_mutex_lock( &p_this->p_parent->var_lock );
01273
01274 i_var = Lookup( p_this->p_parent->p_vars, p_this->p_parent->i_vars,
01275 psz_name );
01276
01277 if( i_var >= 0 )
01278 {
01279
01280 p_var = &p_this->p_parent->p_vars[i_var];
01281
01282
01283 *p_val = p_var->val;
01284
01285
01286 p_var->pf_dup( p_val );
01287
01288 vlc_mutex_unlock( &p_this->p_parent->var_lock );
01289 return VLC_SUCCESS;
01290 }
01291
01292 vlc_mutex_unlock( &p_this->p_parent->var_lock );
01293
01294
01295
01296 return InheritValue( p_this->p_parent, psz_name, p_val, i_type );
01297 }