1 /*****************************************************************************
2 * variables.c: routines for object variables handling
3 *****************************************************************************
4 * Copyright (C) 2002-2006 the VideoLAN team
7 * Authors: Samuel Hocevar <sam@zoy.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
31 #include <vlc_common.h>
32 #include "variables.h"
36 #include "vlc_interface.h"
38 /*****************************************************************************
40 *****************************************************************************/
41 struct callback_entry_t
43 vlc_callback_t pf_callback;
47 /*****************************************************************************
48 * Local comparison functions, returns 0 if v == w, < 0 if v < w, > 0 if v > w
49 *****************************************************************************/
50 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; }
51 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; }
52 static int CmpTime( vlc_value_t v, vlc_value_t w )
54 return v.i_time == w.i_time ? 0 : v.i_time > w.i_time ? 1 : -1;
56 static int CmpString( vlc_value_t v, vlc_value_t w )
59 return !w.psz_string ? 0 : -1;
61 return !w.psz_string ? 1 : strcmp( v.psz_string, w.psz_string );
63 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; }
64 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; }
66 /*****************************************************************************
67 * Local duplication functions, and local deallocation functions
68 *****************************************************************************/
69 static void DupDummy( vlc_value_t *p_val ) { (void)p_val; /* unused */ }
70 static void DupString( vlc_value_t *p_val ) { if( p_val->psz_string ) p_val->psz_string = strdup( p_val->psz_string ); }
72 static void DupList( vlc_value_t *p_val )
75 vlc_list_t *p_list = malloc( sizeof(vlc_list_t) );
77 p_list->i_count = p_val->p_list->i_count;
78 if( p_val->p_list->i_count )
80 p_list->p_values = malloc( p_list->i_count * sizeof(vlc_value_t) );
81 p_list->pi_types = malloc( p_list->i_count * sizeof(int) );
85 p_list->p_values = NULL;
86 p_list->pi_types = NULL;
89 for( i = 0; i < p_list->i_count; i++ )
91 p_list->p_values[i] = p_val->p_list->p_values[i];
92 p_list->pi_types[i] = p_val->p_list->pi_types[i];
93 switch( p_val->p_list->pi_types[i] & VLC_VAR_CLASS )
97 DupString( &p_list->p_values[i] );
104 p_val->p_list = p_list;
107 static void FreeDummy( vlc_value_t *p_val ) { (void)p_val; /* unused */ }
108 static void FreeString( vlc_value_t *p_val ) { free( p_val->psz_string ); }
109 static void FreeMutex( vlc_value_t *p_val ) { vlc_mutex_destroy( (vlc_mutex_t*)p_val->p_address ); free( p_val->p_address ); }
111 static void FreeList( vlc_value_t *p_val )
114 for( i = 0; i < p_val->p_list->i_count; i++ )
116 switch( p_val->p_list->pi_types[i] & VLC_VAR_CLASS )
119 FreeString( &p_val->p_list->p_values[i] );
122 FreeMutex( &p_val->p_list->p_values[i] );
129 if( p_val->p_list->i_count )
131 free( p_val->p_list->p_values );
132 free( p_val->p_list->pi_types );
134 free( p_val->p_list );
137 /*****************************************************************************
139 *****************************************************************************/
140 static int GetUnused ( vlc_object_t *, const char * );
141 static uint32_t HashString ( const char * );
142 static int Insert ( variable_t *, int, const char * );
143 static int InsertInner ( variable_t *, int, uint32_t );
144 static int Lookup ( variable_t *, int, const char * );
145 static int LookupInner ( variable_t *, int, uint32_t );
147 static void CheckValue ( variable_t *, vlc_value_t * );
149 static int InheritValue( vlc_object_t *, const char *, vlc_value_t *,
153 * Initialize a vlc variable
155 * We hash the given string and insert it into the sorted list. The insertion
156 * may require slow memory copies, but think about what we gain in the log(n)
157 * lookup phase when setting/getting the variable value!
159 * \param p_this The object in which to create the variable
160 * \param psz_name The name of the variable
161 * \param i_type The variables type. Must be one of \ref var_type combined with
162 * zero or more \ref var_flags
164 int __var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
168 static vlc_list_t dummy_null_list = {0, NULL, NULL};
169 vlc_object_internals_t *p_priv = vlc_internals( p_this );
171 vlc_mutex_lock( &p_priv->var_lock );
173 /* FIXME: if the variable already exists, we don't duplicate it. But we
174 * duplicate the lookups. It's not that serious, but if anyone finds some
175 * time to rework Insert() so that only one lookup has to be done, feel
177 i_new = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
181 /* If the types differ, variable creation failed. */
182 if( (i_type & ~(VLC_VAR_DOINHERIT|VLC_VAR_ISCOMMAND)) != p_priv->p_vars[i_new].i_type )
184 vlc_mutex_unlock( &p_priv->var_lock );
188 p_priv->p_vars[i_new].i_usage++;
189 if( i_type & VLC_VAR_ISCOMMAND )
190 p_priv->p_vars[i_new].i_type |= VLC_VAR_ISCOMMAND;
191 vlc_mutex_unlock( &p_priv->var_lock );
195 i_new = Insert( p_priv->p_vars, p_priv->i_vars, psz_name );
197 if( (p_priv->i_vars & 15) == 15 )
199 p_priv->p_vars = realloc( p_priv->p_vars,
200 (p_priv->i_vars+17) * sizeof(variable_t) );
203 memmove( p_priv->p_vars + i_new + 1,
204 p_priv->p_vars + i_new,
205 (p_priv->i_vars - i_new) * sizeof(variable_t) );
209 p_var = &p_priv->p_vars[i_new];
210 memset( p_var, 0, sizeof(*p_var) );
212 p_var->i_hash = HashString( psz_name );
213 p_var->psz_name = strdup( psz_name );
214 p_var->psz_text = NULL;
216 p_var->i_type = i_type & ~VLC_VAR_DOINHERIT;
217 memset( &p_var->val, 0, sizeof(vlc_value_t) );
219 p_var->pf_dup = DupDummy;
220 p_var->pf_free = FreeDummy;
224 p_var->i_default = -1;
225 p_var->choices.i_count = 0;
226 p_var->choices.p_values = NULL;
227 p_var->choices_text.i_count = 0;
228 p_var->choices_text.p_values = NULL;
230 p_var->b_incallback = false;
231 p_var->i_entries = 0;
232 p_var->p_entries = NULL;
234 /* Always initialize the variable, even if it is a list variable; this
235 * will lead to errors if the variable is not initialized, but it will
236 * not cause crashes in the variable handling. */
237 switch( i_type & VLC_VAR_CLASS )
240 p_var->pf_cmp = CmpBool;
241 p_var->val.b_bool = false;
243 case VLC_VAR_INTEGER:
244 p_var->pf_cmp = CmpInt;
245 p_var->val.i_int = 0;
248 p_var->pf_cmp = CmpString;
249 p_var->pf_dup = DupString;
250 p_var->pf_free = FreeString;
251 p_var->val.psz_string = NULL;
254 p_var->pf_cmp = CmpFloat;
255 p_var->val.f_float = 0.0;
258 p_var->pf_cmp = CmpTime;
259 p_var->val.i_time = 0;
261 case VLC_VAR_ADDRESS:
262 p_var->pf_cmp = CmpAddress;
263 p_var->val.p_address = NULL;
266 p_var->pf_cmp = CmpAddress;
267 p_var->pf_free = FreeMutex;
268 p_var->val.p_address = malloc( sizeof(vlc_mutex_t) );
269 vlc_mutex_init( (vlc_mutex_t*)p_var->val.p_address );
272 p_var->pf_cmp = CmpAddress;
273 p_var->pf_dup = DupList;
274 p_var->pf_free = FreeList;
275 p_var->val.p_list = &dummy_null_list;
279 /* Duplicate the default data we stored. */
280 p_var->pf_dup( &p_var->val );
282 if( i_type & VLC_VAR_DOINHERIT )
286 if( InheritValue( p_this, psz_name, &val, p_var->i_type )
289 /* Free data if needed */
290 p_var->pf_free( &p_var->val );
291 /* Set the variable */
294 if( i_type & VLC_VAR_HASCHOICE )
296 /* We must add the inherited value to our choice list */
297 p_var->i_default = 0;
299 INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count,
301 INSERT_ELEM( p_var->choices_text.p_values,
302 p_var->choices_text.i_count, 0, val );
303 p_var->pf_dup( &p_var->choices.p_values[0] );
304 p_var->choices_text.p_values[0].psz_string = NULL;
309 vlc_mutex_unlock( &p_priv->var_lock );
315 * Destroy a vlc variable
317 * Look for the variable and destroy it if it is found. As in var_Create we
318 * do a call to memmove() but we have performance counterparts elsewhere.
320 * \param p_this The object that holds the variable
321 * \param psz_name The name of the variable
323 int __var_Destroy( vlc_object_t *p_this, const char *psz_name )
327 vlc_object_internals_t *p_priv = vlc_internals( p_this );
329 vlc_mutex_lock( &p_priv->var_lock );
331 i_var = GetUnused( p_this, psz_name );
334 vlc_mutex_unlock( &p_priv->var_lock );
338 p_var = &p_priv->p_vars[i_var];
340 if( p_var->i_usage > 1 )
343 vlc_mutex_unlock( &p_priv->var_lock );
347 /* Free value if needed */
348 p_var->pf_free( &p_var->val );
350 /* Free choice list if needed */
351 if( p_var->choices.i_count )
353 for( i = 0 ; i < p_var->choices.i_count ; i++ )
355 p_var->pf_free( &p_var->choices.p_values[i] );
356 free( p_var->choices_text.p_values[i].psz_string );
358 free( p_var->choices.p_values );
359 free( p_var->choices_text.p_values );
362 /* Free callbacks if needed */
363 if( p_var->p_entries )
365 free( p_var->p_entries );
368 free( p_var->psz_name );
369 free( p_var->psz_text );
371 memmove( p_priv->p_vars + i_var,
372 p_priv->p_vars + i_var + 1,
373 (p_priv->i_vars - i_var - 1) * sizeof(variable_t) );
375 if( (p_priv->i_vars & 15) == 0 )
377 p_priv->p_vars = realloc( p_priv->p_vars,
378 (p_priv->i_vars) * sizeof( variable_t ) );
383 vlc_mutex_unlock( &p_priv->var_lock );
389 * Perform an action on a variable
391 * \param p_this The object that holds the variable
392 * \param psz_name The name of the variable
393 * \param i_action The action to perform. Must be one of \ref var_action
394 * \param p_val First action parameter
395 * \param p_val2 Second action parameter
397 int __var_Change( vlc_object_t *p_this, const char *psz_name,
398 int i_action, vlc_value_t *p_val, vlc_value_t *p_val2 )
403 vlc_object_internals_t *p_priv = vlc_internals( p_this );
405 vlc_mutex_lock( &p_priv->var_lock );
407 i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
411 vlc_mutex_unlock( &p_priv->var_lock );
415 p_var = &p_priv->p_vars[i_var];
420 if( p_var->i_type & VLC_VAR_HASMIN )
422 p_var->pf_free( &p_var->min );
424 p_var->i_type |= VLC_VAR_HASMIN;
426 p_var->pf_dup( &p_var->min );
427 CheckValue( p_var, &p_var->val );
430 if( p_var->i_type & VLC_VAR_HASMIN )
436 if( p_var->i_type & VLC_VAR_HASMAX )
438 p_var->pf_free( &p_var->max );
440 p_var->i_type |= VLC_VAR_HASMAX;
442 p_var->pf_dup( &p_var->max );
443 CheckValue( p_var, &p_var->val );
446 if( p_var->i_type & VLC_VAR_HASMAX )
451 case VLC_VAR_SETSTEP:
452 if( p_var->i_type & VLC_VAR_HASSTEP )
454 p_var->pf_free( &p_var->step );
456 p_var->i_type |= VLC_VAR_HASSTEP;
457 p_var->step = *p_val;
458 p_var->pf_dup( &p_var->step );
459 CheckValue( p_var, &p_var->val );
461 case VLC_VAR_GETSTEP:
462 if( p_var->i_type & VLC_VAR_HASSTEP )
464 *p_val = p_var->step;
467 case VLC_VAR_ADDCHOICE:
468 i = p_var->choices.i_count;
470 INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count,
472 INSERT_ELEM( p_var->choices_text.p_values,
473 p_var->choices_text.i_count, i, *p_val );
474 p_var->pf_dup( &p_var->choices.p_values[i] );
475 p_var->choices_text.p_values[i].psz_string =
476 ( p_val2 && p_val2->psz_string ) ?
477 strdup( p_val2->psz_string ) : NULL;
479 CheckValue( p_var, &p_var->val );
481 case VLC_VAR_DELCHOICE:
482 for( i = 0 ; i < p_var->choices.i_count ; i++ )
484 if( p_var->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 )
490 if( i == p_var->choices.i_count )
493 vlc_mutex_unlock( &p_priv->var_lock );
497 if( p_var->i_default > i )
501 else if( p_var->i_default == i )
503 p_var->i_default = -1;
506 p_var->pf_free( &p_var->choices.p_values[i] );
507 free( p_var->choices_text.p_values[i].psz_string );
508 REMOVE_ELEM( p_var->choices.p_values, p_var->choices.i_count, i );
509 REMOVE_ELEM( p_var->choices_text.p_values,
510 p_var->choices_text.i_count, i );
512 CheckValue( p_var, &p_var->val );
514 case VLC_VAR_CHOICESCOUNT:
515 p_val->i_int = p_var->choices.i_count;
517 case VLC_VAR_CLEARCHOICES:
518 for( i = 0 ; i < p_var->choices.i_count ; i++ )
520 p_var->pf_free( &p_var->choices.p_values[i] );
522 for( i = 0 ; i < p_var->choices_text.i_count ; i++ )
523 free( p_var->choices_text.p_values[i].psz_string );
525 if( p_var->choices.i_count ) free( p_var->choices.p_values );
526 if( p_var->choices_text.i_count ) free( p_var->choices_text.p_values );
528 p_var->choices.i_count = 0;
529 p_var->choices.p_values = NULL;
530 p_var->choices_text.i_count = 0;
531 p_var->choices_text.p_values = NULL;
532 p_var->i_default = -1;
534 case VLC_VAR_SETDEFAULT:
535 /* FIXME: the list is sorted, dude. Use something cleverer. */
536 for( i = 0 ; i < p_var->choices.i_count ; i++ )
538 if( p_var->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 )
544 if( i == p_var->choices.i_count )
550 p_var->i_default = i;
551 CheckValue( p_var, &p_var->val );
553 case VLC_VAR_SETVALUE:
554 /* Duplicate data if needed */
555 p_var->pf_dup( p_val );
556 /* Backup needed stuff */
558 /* Check boundaries and list */
559 CheckValue( p_var, p_val );
560 /* Set the variable */
562 /* Free data if needed */
563 p_var->pf_free( &oldval );
565 case VLC_VAR_GETCHOICES:
566 case VLC_VAR_GETLIST:
567 p_val->p_list = malloc( sizeof(vlc_list_t) );
568 if( p_val2 ) p_val2->p_list = malloc( sizeof(vlc_list_t) );
569 if( p_var->choices.i_count )
571 p_val->p_list->p_values = malloc( p_var->choices.i_count
572 * sizeof(vlc_value_t) );
573 p_val->p_list->pi_types = malloc( p_var->choices.i_count
577 p_val2->p_list->p_values =
578 malloc( p_var->choices.i_count * sizeof(vlc_value_t) );
579 p_val2->p_list->pi_types =
580 malloc( p_var->choices.i_count * sizeof(int) );
583 p_val->p_list->i_count = p_var->choices.i_count;
584 if( p_val2 ) p_val2->p_list->i_count = p_var->choices.i_count;
585 for( i = 0 ; i < p_var->choices.i_count ; i++ )
587 p_val->p_list->p_values[i] = p_var->choices.p_values[i];
588 p_val->p_list->pi_types[i] = p_var->i_type;
589 p_var->pf_dup( &p_val->p_list->p_values[i] );
592 p_val2->p_list->p_values[i].psz_string =
593 p_var->choices_text.p_values[i].psz_string ?
594 strdup(p_var->choices_text.p_values[i].psz_string) : NULL;
595 p_val2->p_list->pi_types[i] = VLC_VAR_STRING;
599 case VLC_VAR_FREELIST:
601 if( p_val2 && p_val2->p_list )
603 for( i = 0; i < p_val2->p_list->i_count; i++ )
604 free( p_val2->p_list->p_values[i].psz_string );
605 if( p_val2->p_list->i_count )
607 free( p_val2->p_list->p_values );
608 free( p_val2->p_list->pi_types );
610 free( p_val2->p_list );
613 case VLC_VAR_SETTEXT:
614 free( p_var->psz_text );
615 if( p_val && p_val->psz_string )
616 p_var->psz_text = strdup( p_val->psz_string );
618 case VLC_VAR_GETTEXT:
619 p_val->psz_string = NULL;
620 if( p_var->psz_text )
622 p_val->psz_string = strdup( p_var->psz_text );
625 case VLC_VAR_INHERITVALUE:
629 if( InheritValue( p_this,
630 p_val2 ? p_val2->psz_string : psz_name,
631 &val, p_var->i_type )
634 /* Duplicate already done */
636 /* Backup needed stuff */
638 /* Check boundaries and list */
639 CheckValue( p_var, &val );
640 /* Set the variable */
642 /* Free data if needed */
643 p_var->pf_free( &oldval );
649 p_var->pf_dup( p_val );
653 case VLC_VAR_TRIGGER_CALLBACKS:
655 /* Deal with callbacks. Tell we're in a callback, release the lock,
656 * call stored functions, retake the lock. */
657 if( p_var->i_entries )
660 int i_entries = p_var->i_entries;
661 callback_entry_t *p_entries = p_var->p_entries;
663 p_var->b_incallback = true;
664 vlc_mutex_unlock( &p_priv->var_lock );
667 for( ; i_entries-- ; )
669 p_entries[i_entries].pf_callback( p_this, psz_name, p_var->val, p_var->val,
670 p_entries[i_entries].p_data );
673 vlc_mutex_lock( &p_priv->var_lock );
675 i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
678 msg_Err( p_this, "variable %s has disappeared", psz_name );
679 vlc_mutex_unlock( &p_priv->var_lock );
683 p_var = &p_priv->p_vars[i_var];
684 p_var->b_incallback = false;
689 case VLC_VAR_SETISCOMMAND:
690 p_var->i_type |= VLC_VAR_ISCOMMAND;
697 vlc_mutex_unlock( &p_priv->var_lock );
703 * Request a variable's type
705 * \return The variable type if it exists, or 0 if the
706 * variable could not be found.
709 int __var_Type( vlc_object_t *p_this, const char *psz_name )
712 vlc_object_internals_t *p_priv = vlc_internals( p_this );
714 vlc_mutex_lock( &p_priv->var_lock );
716 i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
720 vlc_mutex_unlock( &p_priv->var_lock );
724 i_type = p_priv->p_vars[i_var].i_type;
726 vlc_mutex_unlock( &p_priv->var_lock );
732 * Set a variable's value
734 * \param p_this The object that hold the variable
735 * \param psz_name The name of the variable
736 * \param val the value to set
738 int __var_Set( vlc_object_t *p_this, const char *psz_name, vlc_value_t val )
743 vlc_object_internals_t *p_priv = vlc_internals( p_this );
745 vlc_mutex_lock( &p_priv->var_lock );
747 i_var = GetUnused( p_this, psz_name );
750 vlc_mutex_unlock( &p_priv->var_lock );
754 p_var = &p_priv->p_vars[i_var];
756 /* Duplicate data if needed */
757 p_var->pf_dup( &val );
759 /* Backup needed stuff */
762 /* Check boundaries and list */
763 CheckValue( p_var, &val );
765 /* Set the variable */
768 /* Deal with callbacks. Tell we're in a callback, release the lock,
769 * call stored functions, retake the lock. */
770 if( p_var->i_entries )
773 int i_entries = p_var->i_entries;
774 callback_entry_t *p_entries = p_var->p_entries;
776 p_var->b_incallback = true;
777 vlc_mutex_unlock( &p_priv->var_lock );
780 for( ; i_entries-- ; )
782 p_entries[i_entries].pf_callback( p_this, psz_name, oldval, val,
783 p_entries[i_entries].p_data );
786 vlc_mutex_lock( &p_priv->var_lock );
788 i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
791 msg_Err( p_this, "variable %s has disappeared", psz_name );
792 vlc_mutex_unlock( &p_priv->var_lock );
796 p_var = &p_priv->p_vars[i_var];
797 p_var->b_incallback = false;
800 /* Free data if needed */
801 p_var->pf_free( &oldval );
803 vlc_mutex_unlock( &p_priv->var_lock );
809 * Get a variable's value
811 * \param p_this The object that holds the variable
812 * \param psz_name The name of the variable
813 * \param p_val Pointer to a vlc_value_t that will hold the variable's value
814 * after the function is finished
816 int __var_Get( vlc_object_t *p_this, const char *psz_name, vlc_value_t *p_val )
820 vlc_object_internals_t *p_priv = vlc_internals( p_this );
822 vlc_mutex_lock( &p_priv->var_lock );
824 i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
828 vlc_mutex_unlock( &p_priv->var_lock );
832 p_var = &p_priv->p_vars[i_var];
834 /* Really get the variable */
837 /* Duplicate value if needed */
838 p_var->pf_dup( p_val );
840 vlc_mutex_unlock( &p_priv->var_lock );
846 #undef var_AcquireMutex
848 * Finds a process-wide mutex, creates it if needed, and locks it.
849 * Unlock with vlc_mutex_unlock().
851 vlc_mutex_t *var_AcquireMutex( const char *name )
853 libvlc_global_data_t *p_global = vlc_global();
856 if( var_Create( p_global, name, VLC_VAR_MUTEX ) )
859 var_Get( p_global, name, &val );
860 vlc_mutex_lock( val.p_address );
861 return val.p_address;
866 * Register a callback in a variable
868 * We store a function pointer that will be called upon variable
871 * \param p_this The object that holds the variable
872 * \param psz_name The name of the variable
873 * \param pf_callback The function pointer
874 * \param p_data A generic pointer that will be passed as the last
875 * argument to the callback function.
877 * \warning The callback function is run in the thread that calls var_Set on
878 * the variable. Use proper locking. This thread may not have much
879 * time to spare, so keep callback functions short.
881 int __var_AddCallback( vlc_object_t *p_this, const char *psz_name,
882 vlc_callback_t pf_callback, void *p_data )
886 callback_entry_t entry;
887 vlc_object_internals_t *p_priv = vlc_internals( p_this );
889 entry.pf_callback = pf_callback;
890 entry.p_data = p_data;
892 vlc_mutex_lock( &p_priv->var_lock );
894 i_var = GetUnused( p_this, psz_name );
897 vlc_mutex_unlock( &p_priv->var_lock );
901 p_var = &p_priv->p_vars[i_var];
903 INSERT_ELEM( p_var->p_entries,
908 vlc_mutex_unlock( &p_priv->var_lock );
914 * Remove a callback from a variable
916 * pf_callback and p_data have to be given again, because different objects
917 * might have registered the same callback function.
919 int __var_DelCallback( vlc_object_t *p_this, const char *psz_name,
920 vlc_callback_t pf_callback, void *p_data )
924 vlc_object_internals_t *p_priv = vlc_internals( p_this );
926 vlc_mutex_lock( &p_priv->var_lock );
928 i_var = GetUnused( p_this, psz_name );
931 vlc_mutex_unlock( &p_priv->var_lock );
935 p_var = &p_priv->p_vars[i_var];
937 for( i_entry = p_var->i_entries ; i_entry-- ; )
939 if( p_var->p_entries[i_entry].pf_callback == pf_callback
940 && p_var->p_entries[i_entry].p_data == p_data )
948 vlc_mutex_unlock( &p_priv->var_lock );
952 REMOVE_ELEM( p_var->p_entries, p_var->i_entries, i_entry );
954 vlc_mutex_unlock( &p_priv->var_lock );
960 * Trigger callback on a variable
962 * \param p_this The object that hold the variable
963 * \param psz_name The name of the variable
965 int __var_TriggerCallback( vlc_object_t *p_this, const char *psz_name )
970 vlc_object_internals_t *p_priv = vlc_internals( p_this );
972 vlc_mutex_lock( &p_priv->var_lock );
974 i_var = GetUnused( p_this, psz_name );
977 vlc_mutex_unlock( &p_priv->var_lock );
981 p_var = &p_priv->p_vars[i_var];
983 /* Backup needed stuff */
986 /* Deal with callbacks. Tell we're in a callback, release the lock,
987 * call stored functions, retake the lock. */
988 if( p_var->i_entries )
991 int i_entries = p_var->i_entries;
992 callback_entry_t *p_entries = p_var->p_entries;
994 p_var->b_incallback = true;
995 vlc_mutex_unlock( &p_priv->var_lock );
998 for( ; i_entries-- ; )
1000 p_entries[i_entries].pf_callback( p_this, psz_name, oldval, oldval,
1001 p_entries[i_entries].p_data );
1004 vlc_mutex_lock( &p_priv->var_lock );
1006 i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
1009 msg_Err( p_this, "variable %s has disappeared", psz_name );
1010 vlc_mutex_unlock( &p_priv->var_lock );
1014 p_var = &p_priv->p_vars[i_var];
1015 p_var->b_incallback = false;
1018 vlc_mutex_unlock( &p_priv->var_lock );
1022 /** Parse a stringified option
1023 * This function parse a string option and create the associated object
1025 * The option must be of the form "[no[-]]foo[=bar]" where foo is the
1026 * option name and bar is the value of the option.
1027 * \param p_obj the object in which the variable must be created
1028 * \param psz_option the option to parse
1029 * \param trusted whether the option is set by a trusted input or not
1032 void var_OptionParse( vlc_object_t *p_obj, const char *psz_option,
1035 char *psz_name, *psz_value;
1037 bool b_isno = false;
1040 val.psz_string = NULL;
1042 /* It's too much of a hassle to remove the ':' when we parse
1043 * the cmd line :) */
1044 if( psz_option[0] == ':' )
1047 if( !psz_option[0] )
1050 psz_name = strdup( psz_option );
1051 if( psz_name == NULL )
1054 psz_value = strchr( psz_name, '=' );
1055 if( psz_value != NULL )
1056 *psz_value++ = '\0';
1058 /* FIXME: :programs should be handled generically */
1059 if( !strcmp( psz_name, "programs" ) )
1060 i_type = VLC_VAR_LIST;
1062 i_type = config_GetType( p_obj, psz_name );
1064 if( !i_type && !psz_value )
1066 /* check for "no-foo" or "nofoo" */
1067 if( !strncmp( psz_name, "no-", 3 ) )
1069 memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
1071 else if( !strncmp( psz_name, "no", 2 ) )
1073 memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
1075 else goto cleanup; /* Option doesn't exist */
1078 i_type = config_GetType( p_obj, psz_name );
1080 if( !i_type ) goto cleanup; /* Option doesn't exist */
1082 if( ( i_type != VLC_VAR_BOOL ) &&
1083 ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */
1085 /* check if option is unsafe */
1088 module_config_t *p_config = config_FindConfig( p_obj, psz_name );
1089 if( !p_config->b_safe )
1091 msg_Err( p_obj, "unsafe option \"%s\" has been ignored for "
1092 "security reasons", psz_name );
1097 /* Create the variable in the input object.
1098 * Children of the input object will be able to retreive this value
1099 * thanks to the inheritance property of the object variables. */
1100 var_Create( p_obj, psz_name, i_type );
1105 val.b_bool = !b_isno;
1108 case VLC_VAR_INTEGER:
1109 val.i_int = strtol( psz_value, NULL, 0 );
1113 val.f_float = atof( psz_value );
1116 case VLC_VAR_STRING:
1117 case VLC_VAR_MODULE:
1119 case VLC_VAR_DIRECTORY:
1120 val.psz_string = psz_value;
1125 char *psz_orig, *psz_var;
1126 vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
1127 val.p_list = p_list;
1128 p_list->i_count = 0;
1130 psz_var = psz_orig = strdup(psz_value);
1131 while( psz_var && *psz_var )
1133 char *psz_item = psz_var;
1135 while( *psz_var && *psz_var != ',' ) psz_var++;
1136 if( *psz_var == ',' )
1141 val2.i_int = strtol( psz_item, NULL, 0 );
1142 INSERT_ELEM( p_list->p_values, p_list->i_count,
1143 p_list->i_count, val2 );
1144 /* p_list->i_count is incremented twice by INSERT_ELEM */
1146 INSERT_ELEM( p_list->pi_types, p_list->i_count,
1147 p_list->i_count, VLC_VAR_INTEGER );
1157 var_Set( p_obj, psz_name, val );
1164 /* Following functions are local */
1166 /*****************************************************************************
1167 * GetUnused: find an unused variable from its name
1168 *****************************************************************************
1169 * We do i_tries tries before giving up, just in case the variable is being
1170 * modified and called from a callback.
1171 *****************************************************************************/
1172 static int GetUnused( vlc_object_t *p_this, const char *psz_name )
1174 int i_var, i_tries = 0;
1175 vlc_object_internals_t *p_priv = vlc_internals( p_this );
1179 i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
1185 if( ! p_priv->p_vars[i_var].b_incallback )
1190 if( i_tries++ > 100 )
1192 msg_Err( p_this, "caught in a callback deadlock? ('%s')", psz_name );
1193 return VLC_ETIMEOUT;
1196 vlc_mutex_unlock( &p_priv->var_lock );
1197 msleep( THREAD_SLEEP );
1198 vlc_mutex_lock( &p_priv->var_lock );
1202 /*****************************************************************************
1203 * HashString: our cool hash function
1204 *****************************************************************************
1205 * This function is not intended to be crypto-secure, we only want it to be
1206 * fast and not suck too much. This one is pretty fast and did 0 collisions
1207 * in wenglish's dictionary.
1208 *****************************************************************************/
1209 static uint32_t HashString( const char *psz_string )
1211 uint32_t i_hash = 0;
1213 while( *psz_string )
1215 i_hash += *psz_string++;
1216 i_hash += i_hash << 10;
1217 i_hash ^= i_hash >> 8;
1223 /*****************************************************************************
1224 * Insert: find an empty slot to insert a new variable
1225 *****************************************************************************
1226 * We use a recursive inner function indexed on the hash. This function does
1227 * nothing in the rare cases where a collision may occur, see Lookup()
1228 * to see how we handle them.
1229 * XXX: does this really need to be written recursively?
1230 *****************************************************************************/
1231 static int Insert( variable_t *p_vars, int i_count, const char *psz_name )
1238 return InsertInner( p_vars, i_count, HashString( psz_name ) );
1241 static int InsertInner( variable_t *p_vars, int i_count, uint32_t i_hash )
1245 if( i_hash <= p_vars[0].i_hash )
1250 if( i_hash >= p_vars[i_count - 1].i_hash )
1255 i_middle = i_count / 2;
1257 /* We know that 0 < i_middle */
1258 if( i_hash < p_vars[i_middle].i_hash )
1260 return InsertInner( p_vars, i_middle, i_hash );
1263 /* We know that i_middle + 1 < i_count */
1264 if( i_hash > p_vars[i_middle + 1].i_hash )
1266 return i_middle + 1 + InsertInner( p_vars + i_middle + 1,
1267 i_count - i_middle - 1,
1271 return i_middle + 1;
1274 /*****************************************************************************
1275 * Lookup: find an existing variable given its name
1276 *****************************************************************************
1277 * We use a recursive inner function indexed on the hash. Care is taken of
1278 * possible hash collisions.
1279 * XXX: does this really need to be written recursively?
1280 *****************************************************************************/
1281 static int Lookup( variable_t *p_vars, int i_count, const char *psz_name )
1291 i_hash = HashString( psz_name );
1293 i_pos = LookupInner( p_vars, i_count, i_hash );
1295 /* Hash not found */
1296 if( i_hash != p_vars[i_pos].i_hash )
1301 /* Hash found, entry found */
1302 if( !strcmp( psz_name, p_vars[i_pos].psz_name ) )
1307 /* Hash collision! This should be very rare, but we cannot guarantee
1308 * it will never happen. Just do an exhaustive search amongst all
1309 * entries with the same hash. */
1310 for( i = i_pos - 1 ; i > 0 && i_hash == p_vars[i].i_hash ; i-- )
1312 if( !strcmp( psz_name, p_vars[i].psz_name ) )
1318 for( i = i_pos + 1 ; i < i_count && i_hash == p_vars[i].i_hash ; i++ )
1320 if( !strcmp( psz_name, p_vars[i].psz_name ) )
1326 /* Hash found, but entry not found */
1330 static int LookupInner( variable_t *p_vars, int i_count, uint32_t i_hash )
1334 if( i_hash <= p_vars[0].i_hash )
1339 if( i_hash >= p_vars[i_count-1].i_hash )
1344 i_middle = i_count / 2;
1346 /* We know that 0 < i_middle */
1347 if( i_hash < p_vars[i_middle].i_hash )
1349 return LookupInner( p_vars, i_middle, i_hash );
1352 /* We know that i_middle + 1 < i_count */
1353 if( i_hash > p_vars[i_middle].i_hash )
1355 return i_middle + LookupInner( p_vars + i_middle,
1363 /*****************************************************************************
1364 * CheckValue: check that a value is valid wrt. a variable
1365 *****************************************************************************
1366 * This function checks p_val's value against p_var's limitations such as
1367 * minimal and maximal value, step, in-list position, and modifies p_val if
1369 ****************************************************************************/
1370 static void CheckValue ( variable_t *p_var, vlc_value_t *p_val )
1372 /* Check that our variable is in the list */
1373 if( p_var->i_type & VLC_VAR_HASCHOICE && p_var->choices.i_count )
1377 /* FIXME: the list is sorted, dude. Use something cleverer. */
1378 for( i = p_var->choices.i_count ; i-- ; )
1380 if( p_var->pf_cmp( *p_val, p_var->choices.p_values[i] ) == 0 )
1386 /* If not found, change it to anything vaguely valid */
1389 /* Free the old variable, get the new one, dup it */
1390 p_var->pf_free( p_val );
1391 *p_val = p_var->choices.p_values[p_var->i_default >= 0
1392 ? p_var->i_default : 0 ];
1393 p_var->pf_dup( p_val );
1397 /* Check that our variable is within the bounds */
1398 switch( p_var->i_type & VLC_VAR_TYPE )
1400 case VLC_VAR_INTEGER:
1401 if( p_var->i_type & VLC_VAR_HASSTEP && p_var->step.i_int
1402 && (p_val->i_int % p_var->step.i_int) )
1404 p_val->i_int = (p_val->i_int + (p_var->step.i_int / 2))
1405 / p_var->step.i_int * p_var->step.i_int;
1407 if( p_var->i_type & VLC_VAR_HASMIN
1408 && p_val->i_int < p_var->min.i_int )
1410 p_val->i_int = p_var->min.i_int;
1412 if( p_var->i_type & VLC_VAR_HASMAX
1413 && p_val->i_int > p_var->max.i_int )
1415 p_val->i_int = p_var->max.i_int;
1419 if( p_var->i_type & VLC_VAR_HASSTEP && p_var->step.f_float )
1421 float f_round = p_var->step.f_float * (float)(int)( 0.5 +
1422 p_val->f_float / p_var->step.f_float );
1423 if( p_val->f_float != f_round )
1425 p_val->f_float = f_round;
1428 if( p_var->i_type & VLC_VAR_HASMIN
1429 && p_val->f_float < p_var->min.f_float )
1431 p_val->f_float = p_var->min.f_float;
1433 if( p_var->i_type & VLC_VAR_HASMAX
1434 && p_val->f_float > p_var->max.f_float )
1436 p_val->f_float = p_var->max.f_float;
1445 /*****************************************************************************
1446 * InheritValue: try to inherit the value of this variable from the same one
1447 * in our closest parent.
1448 *****************************************************************************/
1449 static int InheritValue( vlc_object_t *p_this, const char *psz_name,
1450 vlc_value_t *p_val, int i_type )
1454 vlc_object_internals_t *p_priv;
1456 /* No need to take the structure lock,
1457 * we are only looking for our parents */
1459 if( !p_this->p_parent && !p_this->p_libvlc )
1461 switch( i_type & VLC_VAR_CLASS )
1463 case VLC_VAR_STRING:
1464 p_val->psz_string = config_GetPsz( p_this, psz_name );
1465 if( !p_val->psz_string ) p_val->psz_string = strdup("");
1468 p_val->f_float = config_GetFloat( p_this, psz_name );
1470 case VLC_VAR_INTEGER:
1471 p_val->i_int = config_GetInt( p_this, psz_name );
1474 p_val->b_bool = config_GetInt( p_this, psz_name );
1478 char *psz_orig, *psz_var;
1479 vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
1480 p_val->p_list = p_list;
1481 p_list->i_count = 0;
1483 psz_var = psz_orig = config_GetPsz( p_this, psz_name );
1484 while( psz_var && *psz_var )
1486 char *psz_item = psz_var;
1488 while( *psz_var && *psz_var != ',' ) psz_var++;
1489 if( *psz_var == ',' )
1494 val.i_int = strtol( psz_item, NULL, 0 );
1495 INSERT_ELEM( p_list->p_values, p_list->i_count,
1496 p_list->i_count, val );
1497 /* p_list->i_count is incremented twice by INSERT_ELEM */
1499 INSERT_ELEM( p_list->pi_types, p_list->i_count,
1500 p_list->i_count, VLC_VAR_INTEGER );
1513 if( !p_this->p_parent )
1514 p_priv = vlc_internals( p_this->p_libvlc );
1516 p_priv = vlc_internals( p_this->p_parent );
1518 /* Look for the variable */
1519 vlc_mutex_lock( &p_priv->var_lock );
1521 i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
1526 p_var = &p_priv->p_vars[i_var];
1528 /* Really get the variable */
1529 *p_val = p_var->val;
1531 /* Duplicate value if needed */
1532 p_var->pf_dup( p_val );
1534 vlc_mutex_unlock( &p_priv->var_lock );
1538 vlc_mutex_unlock( &p_priv->var_lock );
1540 /* We're still not there */
1542 return InheritValue( p_this->p_parent, psz_name, p_val, i_type );
1545 /**********************************************************************
1546 * Execute a var command on an object identified by its name
1547 **********************************************************************/
1548 int __var_Command( vlc_object_t *p_this, const char *psz_name,
1549 const char *psz_cmd, const char *psz_arg, char **psz_msg )
1551 vlc_object_t *p_obj = vlc_object_find_name( p_this->p_libvlc,
1552 psz_name, FIND_CHILD );
1558 *psz_msg = strdup( "Unknown destination object." );
1562 i_type = var_Type( p_obj, psz_cmd );
1563 if( !( i_type&VLC_VAR_ISCOMMAND ) )
1565 vlc_object_release( p_obj );
1567 *psz_msg = strdup( "Variable doesn't exist or isn't a command." );
1568 return VLC_EGENERIC;
1571 i_type &= VLC_VAR_CLASS;
1574 case VLC_VAR_INTEGER:
1575 i_ret = var_SetInteger( p_obj, psz_cmd, atoi( psz_arg ) );
1578 i_ret = var_SetFloat( p_obj, psz_cmd, atof( psz_arg ) );
1580 case VLC_VAR_STRING:
1581 i_ret = var_SetString( p_obj, psz_cmd, psz_arg );
1584 i_ret = var_SetBool( p_obj, psz_cmd, atoi( psz_arg ) );
1587 i_ret = VLC_EGENERIC;
1591 vlc_object_release( p_obj );
1595 *psz_msg = (char*)malloc( 80 );
1596 sprintf( *psz_msg, "%s on object %s returned %i (%s)",
1597 psz_cmd, psz_name, i_ret, vlc_error( i_ret ) );