]> git.sesse.net Git - vlc/blob - src/misc/variables.c
b930544a5e4fa1fca50bb24b8997bc04f54362e7
[vlc] / src / misc / variables.c
1 /*****************************************************************************
2  * variables.c: routines for object variables handling
3  *****************************************************************************
4  * Copyright (C) 2002-2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_charset.h>
33 #include "variables.h"
34
35 #include "libvlc.h"
36
37 #include <assert.h>
38
39 /*****************************************************************************
40  * Private types
41  *****************************************************************************/
42 struct callback_entry_t
43 {
44     vlc_callback_t pf_callback;
45     void *         p_data;
46 };
47
48 /*****************************************************************************
49  * Local comparison functions, returns 0 if v == w, < 0 if v < w, > 0 if v > w
50  *****************************************************************************/
51 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; }
52 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; }
53 static int CmpTime( vlc_value_t v, vlc_value_t w )
54 {
55     return v.i_time == w.i_time ? 0 : v.i_time > w.i_time ? 1 : -1;
56 }
57 static int CmpString( vlc_value_t v, vlc_value_t w )
58 {
59     if( !v.psz_string )
60         return !w.psz_string ? 0 : -1;
61     else
62         return !w.psz_string ? 1 : strcmp( v.psz_string, w.psz_string );
63 }
64 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; }
65 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 /*****************************************************************************
68  * Local duplication functions, and local deallocation functions
69  *****************************************************************************/
70 static void DupDummy( vlc_value_t *p_val ) { (void)p_val; /* unused */ }
71 static void DupString( vlc_value_t *p_val )
72 {
73     p_val->psz_string = strdup( p_val->psz_string ? p_val->psz_string :  "" );
74 }
75
76 static void DupList( vlc_value_t *p_val )
77 {
78     int i;
79     vlc_list_t *p_list = malloc( sizeof(vlc_list_t) );
80
81     p_list->i_count = p_val->p_list->i_count;
82     if( p_val->p_list->i_count )
83     {
84         p_list->p_values = malloc( p_list->i_count * sizeof(vlc_value_t) );
85         p_list->pi_types = malloc( p_list->i_count * sizeof(int) );
86     }
87     else
88     {
89         p_list->p_values = NULL;
90         p_list->pi_types = NULL;
91     }
92
93     for( i = 0; i < p_list->i_count; i++ )
94     {
95         p_list->p_values[i] = p_val->p_list->p_values[i];
96         p_list->pi_types[i] = p_val->p_list->pi_types[i];
97         switch( p_val->p_list->pi_types[i] & VLC_VAR_CLASS )
98         {
99         case VLC_VAR_STRING:
100
101             DupString( &p_list->p_values[i] );
102             break;
103         default:
104             break;
105         }
106     }
107
108     p_val->p_list = p_list;
109 }
110
111 static void FreeDummy( vlc_value_t *p_val ) { (void)p_val; /* unused */ }
112 static void FreeString( vlc_value_t *p_val ) { free( p_val->psz_string ); }
113 static void FreeMutex( vlc_value_t *p_val ) { vlc_mutex_destroy( (vlc_mutex_t*)p_val->p_address ); free( p_val->p_address ); }
114
115 static void FreeList( vlc_value_t *p_val )
116 {
117     int i;
118     for( i = 0; i < p_val->p_list->i_count; i++ )
119     {
120         switch( p_val->p_list->pi_types[i] & VLC_VAR_CLASS )
121         {
122         case VLC_VAR_STRING:
123             FreeString( &p_val->p_list->p_values[i] );
124             break;
125         case VLC_VAR_MUTEX:
126             FreeMutex( &p_val->p_list->p_values[i] );
127             break;
128         default:
129             break;
130         }
131     }
132
133     if( p_val->p_list->i_count )
134     {
135         free( p_val->p_list->p_values );
136         free( p_val->p_list->pi_types );
137     }
138     free( p_val->p_list );
139 }
140
141 static const struct variable_ops_t
142 void_ops   = { NULL,       DupDummy,  FreeDummy,  },
143 addr_ops   = { CmpAddress, DupDummy,  FreeDummy,  },
144 bool_ops   = { CmpBool,    DupDummy,  FreeDummy,  },
145 float_ops  = { CmpFloat,   DupDummy,  FreeDummy,  },
146 int_ops    = { CmpInt,     DupDummy,  FreeDummy,  },
147 list_ops   = { CmpAddress, DupList,   FreeList,   },
148 mutex_ops  = { CmpAddress, DupDummy,  FreeMutex,  },
149 string_ops = { CmpString,  DupString, FreeString, },
150 time_ops   = { CmpTime,    DupDummy,  FreeDummy,  };
151
152 /*****************************************************************************
153  * Local prototypes
154  *****************************************************************************/
155 static int      GetUnused   ( vlc_object_t *, const char * );
156 static uint32_t HashString  ( const char * );
157 static int      Insert      ( variable_t *, int, const char * );
158 static int      InsertInner ( variable_t *, int, uint32_t );
159 static int      Lookup      ( variable_t *, size_t, const char * );
160
161 static void     CheckValue  ( variable_t *, vlc_value_t * );
162
163 static int      InheritValue( vlc_object_t *, const char *, vlc_value_t *,
164                               int );
165 static int      TriggerCallback( vlc_object_t *, variable_t **, const char *,
166                                  vlc_value_t );
167
168 /**
169  * Initialize a vlc variable
170  *
171  * We hash the given string and insert it into the sorted list. The insertion
172  * may require slow memory copies, but think about what we gain in the log(n)
173  * lookup phase when setting/getting the variable value!
174  *
175  * \param p_this The object in which to create the variable
176  * \param psz_name The name of the variable
177  * \param i_type The variables type. Must be one of \ref var_type combined with
178  *               zero or more \ref var_flags
179  */
180 int __var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
181 {
182     variable_t var, *p_var = &var;
183     static vlc_list_t dummy_null_list = {0, NULL, NULL};
184
185     assert( p_this );
186
187     memset( p_var, 0, sizeof(*p_var) );
188
189     p_var->i_hash = HashString( psz_name );
190     p_var->psz_name = strdup( psz_name );
191     p_var->psz_text = NULL;
192
193     p_var->i_type = i_type & ~VLC_VAR_DOINHERIT;
194
195     p_var->i_usage = 1;
196
197     p_var->i_default = -1;
198     p_var->choices.i_count = 0;
199     p_var->choices.p_values = NULL;
200     p_var->choices_text.i_count = 0;
201     p_var->choices_text.p_values = NULL;
202
203     p_var->b_incallback = false;
204     p_var->i_entries = 0;
205     p_var->p_entries = NULL;
206
207     /* Always initialize the variable, even if it is a list variable; this
208      * will lead to errors if the variable is not initialized, but it will
209      * not cause crashes in the variable handling. */
210     switch( i_type & VLC_VAR_CLASS )
211     {
212         case VLC_VAR_BOOL:
213             p_var->ops = &bool_ops;
214             p_var->val.b_bool = false;
215             break;
216         case VLC_VAR_INTEGER:
217             p_var->ops = &int_ops;
218             p_var->val.i_int = 0;
219             break;
220         case VLC_VAR_STRING:
221             p_var->ops = &string_ops;
222             p_var->val.psz_string = NULL;
223             break;
224         case VLC_VAR_FLOAT:
225             p_var->ops = &float_ops;
226             p_var->val.f_float = 0.0;
227             break;
228         case VLC_VAR_TIME:
229             p_var->ops = &time_ops;
230             p_var->val.i_time = 0;
231             break;
232         case VLC_VAR_ADDRESS:
233             p_var->ops = &addr_ops;
234             p_var->val.p_address = NULL;
235             break;
236         case VLC_VAR_MUTEX:
237             p_var->ops = &mutex_ops;
238             p_var->val.p_address = malloc( sizeof(vlc_mutex_t) );
239             vlc_mutex_init( (vlc_mutex_t*)p_var->val.p_address );
240             break;
241         case VLC_VAR_LIST:
242             p_var->ops = &list_ops;
243             p_var->val.p_list = &dummy_null_list;
244             break;
245         default:
246             p_var->ops = &void_ops;
247             break;
248     }
249
250     if( i_type & VLC_VAR_DOINHERIT )
251     {
252         if( InheritValue( p_this, psz_name, &p_var->val, p_var->i_type ) )
253             msg_Err( p_this, "cannot inherit value for %s", psz_name );
254         else if( i_type & VLC_VAR_HASCHOICE )
255         {
256             /* We must add the inherited value to our choice list */
257             p_var->i_default = 0;
258
259             INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count,
260                          0, p_var->val );
261             INSERT_ELEM( p_var->choices_text.p_values,
262                          p_var->choices_text.i_count, 0, p_var->val );
263             p_var->ops->pf_dup( &p_var->choices.p_values[0] );
264             p_var->choices_text.p_values[0].psz_string = NULL;
265         }
266     }
267
268     vlc_object_internals_t *p_priv = vlc_internals( p_this );
269     int i_new;
270
271     vlc_mutex_lock( &p_priv->var_lock );
272
273     /* FIXME: if the variable already exists, we don't duplicate it. But we
274      * duplicate the lookups. It's not that serious, but if anyone finds some
275      * time to rework Insert() so that only one lookup has to be done, feel
276      * free to do so. */
277     i_new = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
278
279     if( i_new >= 0 )
280     {
281         /* If the types differ, variable creation failed. */
282         if( (i_type & VLC_VAR_CLASS) != (p_priv->p_vars[i_new].i_type & VLC_VAR_CLASS) )
283         {
284             msg_Err( p_this, "Variable '%s' (0x%04x) already exist but with a different type (0x%04x)",
285                      psz_name, p_priv->p_vars[i_new].i_type, i_type );
286             vlc_mutex_unlock( &p_priv->var_lock );
287             return VLC_EBADVAR;
288         }
289
290         p_priv->p_vars[i_new].i_usage++;
291         p_priv->p_vars[i_new].i_type |= ( i_type & VLC_VAR_ISCOMMAND );
292         p_priv->p_vars[i_new].i_type |= ( i_type & VLC_VAR_HASCHOICE );
293         vlc_mutex_unlock( &p_priv->var_lock );
294
295         /* We did not need to create a new variable, free everything... */
296         p_var->ops->pf_free( &p_var->val );
297         free( p_var->psz_name );
298         if( p_var->choices.i_count )
299         {
300             for( int i = 0 ; i < p_var->choices.i_count ; i++ )
301             {
302                 p_var->ops->pf_free( &p_var->choices.p_values[i] );
303                 free( p_var->choices_text.p_values[i].psz_string );
304             }
305             free( p_var->choices.p_values );
306             free( p_var->choices_text.p_values );
307         }
308         return VLC_SUCCESS;
309     }
310
311     i_new = Insert( p_priv->p_vars, p_priv->i_vars, psz_name );
312
313     if( (p_priv->i_vars & 15) == 15 )
314     {
315         p_priv->p_vars = xrealloc( p_priv->p_vars,
316                                   (p_priv->i_vars+17) * sizeof(variable_t) );
317     }
318
319     memmove( p_priv->p_vars + i_new + 1,
320              p_priv->p_vars + i_new,
321              (p_priv->i_vars - i_new) * sizeof(variable_t) );
322
323     p_priv->i_vars++;
324
325     p_priv->p_vars[i_new] = var;
326     vlc_mutex_unlock( &p_priv->var_lock );
327
328     return VLC_SUCCESS;
329 }
330
331 /**
332  * Destroy a vlc variable
333  *
334  * Look for the variable and destroy it if it is found. As in var_Create we
335  * do a call to memmove() but we have performance counterparts elsewhere.
336  *
337  * \param p_this The object that holds the variable
338  * \param psz_name The name of the variable
339  */
340 int __var_Destroy( vlc_object_t *p_this, const char *psz_name )
341 {
342     int i_var, i;
343     variable_t *p_var;
344
345     assert( p_this );
346
347     vlc_object_internals_t *p_priv = vlc_internals( p_this );
348
349     vlc_mutex_lock( &p_priv->var_lock );
350
351     i_var = GetUnused( p_this, psz_name );
352     if( i_var < 0 )
353     {
354         vlc_mutex_unlock( &p_priv->var_lock );
355         return i_var;
356     }
357
358     p_var = &p_priv->p_vars[i_var];
359
360     if( p_var->i_usage > 1 )
361     {
362         p_var->i_usage--;
363         vlc_mutex_unlock( &p_priv->var_lock );
364         return VLC_SUCCESS;
365     }
366
367     /* Free value if needed */
368     p_var->ops->pf_free( &p_var->val );
369
370     /* Free choice list if needed */
371     if( p_var->choices.i_count )
372     {
373         for( i = 0 ; i < p_var->choices.i_count ; i++ )
374         {
375             p_var->ops->pf_free( &p_var->choices.p_values[i] );
376             free( p_var->choices_text.p_values[i].psz_string );
377         }
378         free( p_var->choices.p_values );
379         free( p_var->choices_text.p_values );
380     }
381
382     /* Free callbacks if needed */
383     free( p_var->p_entries );
384
385     free( p_var->psz_name );
386     free( p_var->psz_text );
387
388     memmove( p_priv->p_vars + i_var,
389              p_priv->p_vars + i_var + 1,
390              (p_priv->i_vars - i_var - 1) * sizeof(variable_t) );
391
392     if( (p_priv->i_vars & 15) == 0 )
393     {
394         variable_t *p_vars = realloc( p_priv->p_vars,
395                                     (p_priv->i_vars) * sizeof( variable_t ) );
396         if( p_vars )
397             p_priv->p_vars = p_vars;
398     }
399
400     p_priv->i_vars--;
401
402     vlc_mutex_unlock( &p_priv->var_lock );
403
404     return VLC_SUCCESS;
405 }
406
407 /**
408  * Perform an action on a variable
409  *
410  * \param p_this The object that holds the variable
411  * \param psz_name The name of the variable
412  * \param i_action The action to perform. Must be one of \ref var_action
413  * \param p_val First action parameter
414  * \param p_val2 Second action parameter
415  */
416 int __var_Change( vlc_object_t *p_this, const char *psz_name,
417                   int i_action, vlc_value_t *p_val, vlc_value_t *p_val2 )
418 {
419     int i_var, i;
420     variable_t *p_var;
421     vlc_value_t oldval;
422
423     assert( p_this );
424
425     vlc_object_internals_t *p_priv = vlc_internals( p_this );
426
427     vlc_mutex_lock( &p_priv->var_lock );
428
429     i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
430
431     if( i_var < 0 )
432     {
433         vlc_mutex_unlock( &p_priv->var_lock );
434         return VLC_ENOVAR;
435     }
436
437     p_var = &p_priv->p_vars[i_var];
438
439     switch( i_action )
440     {
441         case VLC_VAR_SETMIN:
442             if( p_var->i_type & VLC_VAR_HASMIN )
443             {
444                 p_var->ops->pf_free( &p_var->min );
445             }
446             p_var->i_type |= VLC_VAR_HASMIN;
447             p_var->min = *p_val;
448             p_var->ops->pf_dup( &p_var->min );
449             CheckValue( p_var, &p_var->val );
450             break;
451         case VLC_VAR_GETMIN:
452             if( p_var->i_type & VLC_VAR_HASMIN )
453             {
454                 *p_val = p_var->min;
455             }
456             break;
457         case VLC_VAR_SETMAX:
458             if( p_var->i_type & VLC_VAR_HASMAX )
459             {
460                 p_var->ops->pf_free( &p_var->max );
461             }
462             p_var->i_type |= VLC_VAR_HASMAX;
463             p_var->max = *p_val;
464             p_var->ops->pf_dup( &p_var->max );
465             CheckValue( p_var, &p_var->val );
466             break;
467         case VLC_VAR_GETMAX:
468             if( p_var->i_type & VLC_VAR_HASMAX )
469             {
470                 *p_val = p_var->max;
471             }
472             break;
473         case VLC_VAR_SETSTEP:
474             if( p_var->i_type & VLC_VAR_HASSTEP )
475             {
476                 p_var->ops->pf_free( &p_var->step );
477             }
478             p_var->i_type |= VLC_VAR_HASSTEP;
479             p_var->step = *p_val;
480             p_var->ops->pf_dup( &p_var->step );
481             CheckValue( p_var, &p_var->val );
482             break;
483         case VLC_VAR_GETSTEP:
484             if( p_var->i_type & VLC_VAR_HASSTEP )
485             {
486                 *p_val = p_var->step;
487             }
488             break;
489         case VLC_VAR_ADDCHOICE:
490             i = p_var->choices.i_count;
491
492             INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count,
493                          i, *p_val );
494             INSERT_ELEM( p_var->choices_text.p_values,
495                          p_var->choices_text.i_count, i, *p_val );
496             p_var->ops->pf_dup( &p_var->choices.p_values[i] );
497             p_var->choices_text.p_values[i].psz_string =
498                 ( p_val2 && p_val2->psz_string ) ?
499                 strdup( p_val2->psz_string ) : NULL;
500
501             CheckValue( p_var, &p_var->val );
502             break;
503         case VLC_VAR_DELCHOICE:
504             for( i = 0 ; i < p_var->choices.i_count ; i++ )
505             {
506                 if( p_var->ops->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 )
507                 {
508                     break;
509                 }
510             }
511
512             if( i == p_var->choices.i_count )
513             {
514                 /* Not found */
515                 vlc_mutex_unlock( &p_priv->var_lock );
516                 return VLC_EGENERIC;
517             }
518
519             if( p_var->i_default > i )
520             {
521                 p_var->i_default--;
522             }
523             else if( p_var->i_default == i )
524             {
525                 p_var->i_default = -1;
526             }
527
528             p_var->ops->pf_free( &p_var->choices.p_values[i] );
529             free( p_var->choices_text.p_values[i].psz_string );
530             REMOVE_ELEM( p_var->choices.p_values, p_var->choices.i_count, i );
531             REMOVE_ELEM( p_var->choices_text.p_values,
532                          p_var->choices_text.i_count, i );
533
534             CheckValue( p_var, &p_var->val );
535             break;
536         case VLC_VAR_CHOICESCOUNT:
537             p_val->i_int = p_var->choices.i_count;
538             break;
539         case VLC_VAR_CLEARCHOICES:
540             for( i = 0 ; i < p_var->choices.i_count ; i++ )
541             {
542                 p_var->ops->pf_free( &p_var->choices.p_values[i] );
543             }
544             for( i = 0 ; i < p_var->choices_text.i_count ; i++ )
545                 free( p_var->choices_text.p_values[i].psz_string );
546
547             if( p_var->choices.i_count ) free( p_var->choices.p_values );
548             if( p_var->choices_text.i_count ) free( p_var->choices_text.p_values );
549
550             p_var->choices.i_count = 0;
551             p_var->choices.p_values = NULL;
552             p_var->choices_text.i_count = 0;
553             p_var->choices_text.p_values = NULL;
554             p_var->i_default = -1;
555             break;
556         case VLC_VAR_SETDEFAULT:
557             /* FIXME: the list is sorted, dude. Use something cleverer. */
558             for( i = 0 ; i < p_var->choices.i_count ; i++ )
559             {
560                 if( p_var->ops->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 )
561                 {
562                     break;
563                 }
564             }
565
566             if( i == p_var->choices.i_count )
567             {
568                 /* Not found */
569                 break;
570             }
571
572             p_var->i_default = i;
573             CheckValue( p_var, &p_var->val );
574             break;
575         case VLC_VAR_SETVALUE:
576             /* Duplicate data if needed */
577             p_var->ops->pf_dup( p_val );
578             /* Backup needed stuff */
579             oldval = p_var->val;
580             /* Check boundaries and list */
581             CheckValue( p_var, p_val );
582             /* Set the variable */
583             p_var->val = *p_val;
584             /* Free data if needed */
585             p_var->ops->pf_free( &oldval );
586             break;
587         case VLC_VAR_GETCHOICES:
588         case VLC_VAR_GETLIST:
589             p_val->p_list = malloc( sizeof(vlc_list_t) );
590             if( p_val2 ) p_val2->p_list = malloc( sizeof(vlc_list_t) );
591             if( p_var->choices.i_count )
592             {
593                 p_val->p_list->p_values = malloc( p_var->choices.i_count
594                                                   * sizeof(vlc_value_t) );
595                 p_val->p_list->pi_types = malloc( p_var->choices.i_count
596                                                   * sizeof(int) );
597                 if( p_val2 )
598                 {
599                     p_val2->p_list->p_values =
600                         malloc( p_var->choices.i_count * sizeof(vlc_value_t) );
601                     p_val2->p_list->pi_types =
602                         malloc( p_var->choices.i_count * sizeof(int) );
603                 }
604             }
605             p_val->p_list->i_count = p_var->choices.i_count;
606             if( p_val2 ) p_val2->p_list->i_count = p_var->choices.i_count;
607             for( i = 0 ; i < p_var->choices.i_count ; i++ )
608             {
609                 p_val->p_list->p_values[i] = p_var->choices.p_values[i];
610                 p_val->p_list->pi_types[i] = p_var->i_type;
611                 p_var->ops->pf_dup( &p_val->p_list->p_values[i] );
612                 if( p_val2 )
613                 {
614                     p_val2->p_list->p_values[i].psz_string =
615                         p_var->choices_text.p_values[i].psz_string ?
616                     strdup(p_var->choices_text.p_values[i].psz_string) : NULL;
617                     p_val2->p_list->pi_types[i] = VLC_VAR_STRING;
618                 }
619             }
620             break;
621         case VLC_VAR_SETTEXT:
622             free( p_var->psz_text );
623             if( p_val && p_val->psz_string )
624                 p_var->psz_text = strdup( p_val->psz_string );
625             else
626                 p_var->psz_text = NULL;
627             break;
628         case VLC_VAR_GETTEXT:
629             p_val->psz_string = p_var->psz_text ? strdup( p_var->psz_text )
630                                                 : NULL;
631             break;
632         case VLC_VAR_SETISCOMMAND:
633             p_var->i_type |= VLC_VAR_ISCOMMAND;
634             break;
635
636         default:
637             break;
638     }
639
640     vlc_mutex_unlock( &p_priv->var_lock );
641
642     return VLC_SUCCESS;
643 }
644
645
646 /**
647  * Perform a Get and Set on a variable
648  *
649  * \param p_this: The object that hold the variable
650  * \param psz_name: the name of the variable
651  * \param i_action: the action to perform
652  * \param p_val: The action parameter
653  * \return vlc error codes
654  */
655 int __var_GetAndSet( vlc_object_t *p_this, const char *psz_name, int i_action,
656                      vlc_value_t val )
657 {
658     int i_var;
659     int i_ret = VLC_SUCCESS;
660     variable_t *p_var;
661     vlc_value_t oldval;
662
663     assert( p_this );
664
665     vlc_object_internals_t *p_priv = vlc_internals( p_this );
666
667     vlc_mutex_lock( &p_priv->var_lock );
668     i_var = GetUnused( p_this, psz_name );
669     if( i_var < 0 )
670     {
671         vlc_mutex_unlock( &p_priv->var_lock );
672         return i_var;
673     }
674
675     p_var = &p_priv->p_vars[i_var];
676
677     /* Duplicated data if needed */
678     //p_var->ops->pf_dup( &val );
679
680     /* Backup needed stuff */
681     oldval = p_var->val;
682
683     /* depending of the action requiered */
684     switch( i_action )
685     {
686     case VLC_VAR_TOGGLE_BOOL:
687         assert( ( p_var->i_type & VLC_VAR_BOOL ) == VLC_VAR_BOOL );
688         p_var->val.b_bool = !p_var->val.b_bool;
689         break;
690     case VLC_VAR_INTEGER_INCDEC:
691         assert( ( p_var->i_type & VLC_VAR_INTEGER ) == VLC_VAR_INTEGER );
692         p_var->val.i_int += val.i_int;
693         break;
694     default:
695         vlc_mutex_unlock( &p_priv->var_lock );
696         return VLC_EGENERIC;
697     }
698
699     /*  Check boundaries */
700     CheckValue( p_var, &p_var->val );
701
702     /* Deal with callbacks.*/
703     if( p_var->i_entries )
704         i_ret = TriggerCallback( p_this, &p_var, psz_name, oldval );
705
706     vlc_mutex_unlock( &p_priv->var_lock );
707
708     return i_ret;
709 }
710
711
712 /**
713  * Request a variable's type
714  *
715  * \return The variable type if it exists, or 0 if the
716  * variable could not be found.
717  * \see \ref var_type
718  */
719 int __var_Type( vlc_object_t *p_this, const char *psz_name )
720 {
721     int i_var, i_type;
722
723     assert( p_this );
724
725     vlc_object_internals_t *p_priv = vlc_internals( p_this );
726
727     vlc_mutex_lock( &p_priv->var_lock );
728
729     i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
730
731     if( i_var < 0 )
732     {
733         vlc_mutex_unlock( &p_priv->var_lock );
734         return 0;
735     }
736
737     i_type = p_priv->p_vars[i_var].i_type;
738
739     vlc_mutex_unlock( &p_priv->var_lock );
740
741     return i_type;
742 }
743
744 int var_SetChecked( vlc_object_t *p_this, const char *psz_name,
745                     int expected_type, vlc_value_t val )
746 {
747     int i_var;
748     int i_ret = VLC_SUCCESS;
749     variable_t *p_var;
750     vlc_value_t oldval;
751
752     assert( p_this );
753
754     vlc_object_internals_t *p_priv = vlc_internals( p_this );
755
756     vlc_mutex_lock( &p_priv->var_lock );
757
758     i_var = GetUnused( p_this, psz_name );
759     if( i_var < 0 )
760     {
761         vlc_mutex_unlock( &p_priv->var_lock );
762         return i_var;
763     }
764
765     p_var = &p_priv->p_vars[i_var];
766     assert( expected_type == 0 ||
767             (p_var->i_type & VLC_VAR_CLASS) == expected_type );
768
769     /* Duplicate data if needed */
770     p_var->ops->pf_dup( &val );
771
772     /* Backup needed stuff */
773     oldval = p_var->val;
774
775     /* Check boundaries and list */
776     CheckValue( p_var, &val );
777
778     /* Set the variable */
779     p_var->val = val;
780
781     /* Deal with callbacks */
782     if( p_var->i_entries )
783         i_ret = TriggerCallback( p_this, &p_var, psz_name, oldval );
784
785     /* Free data if needed */
786     p_var->ops->pf_free( &oldval );
787
788     vlc_mutex_unlock( &p_priv->var_lock );
789
790     return i_ret;
791 }
792
793
794 /**
795  * Set a variable's value
796  *
797  * \param p_this The object that hold the variable
798  * \param psz_name The name of the variable
799  * \param val the value to set
800  */
801 int __var_Set( vlc_object_t *p_this, const char *psz_name, vlc_value_t val )
802 {
803     return var_SetChecked( p_this, psz_name, 0, val );
804 }
805
806 int var_GetChecked( vlc_object_t *p_this, const char *psz_name,
807                     int expected_type, vlc_value_t *p_val )
808 {
809     assert( p_this );
810
811     vlc_object_internals_t *p_priv = vlc_internals( p_this );
812     int i_var, err = VLC_SUCCESS;
813
814     vlc_mutex_lock( &p_priv->var_lock );
815
816     i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
817     if( i_var >= 0 )
818     {
819         variable_t *p_var = &p_priv->p_vars[i_var];
820
821         assert( expected_type == 0 ||
822                 (p_var->i_type & VLC_VAR_CLASS) == expected_type );
823
824         /* Really get the variable */
825         *p_val = p_var->val;
826
827 #ifndef NDEBUG
828         /* Alert if the type is VLC_VAR_VOID */
829         if( ( p_var->i_type & VLC_VAR_TYPE ) == VLC_VAR_VOID )
830             msg_Warn( p_this, "Calling var_GetVoid on the void variable '%s' (0x%04x)", psz_name, p_var->i_type );
831 #endif
832
833         /* Duplicate value if needed */
834         p_var->ops->pf_dup( p_val );
835     }
836     else
837         err = VLC_ENOVAR;
838
839     vlc_mutex_unlock( &p_priv->var_lock );
840     return err;
841 }
842
843 /**
844  * Get a variable's value
845  *
846  * \param p_this The object that holds the variable
847  * \param psz_name The name of the variable
848  * \param p_val Pointer to a vlc_value_t that will hold the variable's value
849  *              after the function is finished
850  */
851 int __var_Get( vlc_object_t *p_this, const char *psz_name, vlc_value_t *p_val )
852 {
853     return var_GetChecked( p_this, psz_name, 0, p_val );
854 }
855
856 /**
857  * Register a callback in a variable
858  *
859  * We store a function pointer that will be called upon variable
860  * modification.
861  *
862  * \param p_this The object that holds the variable
863  * \param psz_name The name of the variable
864  * \param pf_callback The function pointer
865  * \param p_data A generic pointer that will be passed as the last
866  *               argument to the callback function.
867  *
868  * \warning The callback function is run in the thread that calls var_Set on
869  *          the variable. Use proper locking. This thread may not have much
870  *          time to spare, so keep callback functions short.
871  */
872 int __var_AddCallback( vlc_object_t *p_this, const char *psz_name,
873                        vlc_callback_t pf_callback, void *p_data )
874 {
875     int i_var;
876     variable_t *p_var;
877     callback_entry_t entry;
878
879     assert( p_this );
880
881     vlc_object_internals_t *p_priv = vlc_internals( p_this );
882
883     entry.pf_callback = pf_callback;
884     entry.p_data = p_data;
885
886     vlc_mutex_lock( &p_priv->var_lock );
887
888     i_var = GetUnused( p_this, psz_name );
889     if( i_var < 0 )
890     {
891 #ifndef NDEBUG
892         msg_Warn( p_this, "Failed to add a callback to the non-existing "
893                           "variable '%s'", psz_name );
894 #endif
895         vlc_mutex_unlock( &p_priv->var_lock );
896         return i_var;
897     }
898
899     p_var = &p_priv->p_vars[i_var];
900
901     INSERT_ELEM( p_var->p_entries,
902                  p_var->i_entries,
903                  p_var->i_entries,
904                  entry );
905
906     vlc_mutex_unlock( &p_priv->var_lock );
907
908     return VLC_SUCCESS;
909 }
910
911 /**
912  * Remove a callback from a variable
913  *
914  * pf_callback and p_data have to be given again, because different objects
915  * might have registered the same callback function.
916  */
917 int __var_DelCallback( vlc_object_t *p_this, const char *psz_name,
918                        vlc_callback_t pf_callback, void *p_data )
919 {
920     int i_entry, i_var;
921     variable_t *p_var;
922 #ifndef NDEBUG
923     bool b_found_similar = false;
924 #endif
925
926     assert( p_this );
927
928     vlc_object_internals_t *p_priv = vlc_internals( p_this );
929
930     vlc_mutex_lock( &p_priv->var_lock );
931
932     i_var = GetUnused( p_this, psz_name );
933     if( i_var < 0 )
934     {
935         vlc_mutex_unlock( &p_priv->var_lock );
936         return i_var;
937     }
938
939     p_var = &p_priv->p_vars[i_var];
940
941     for( i_entry = p_var->i_entries ; i_entry-- ; )
942     {
943         if( p_var->p_entries[i_entry].pf_callback == pf_callback
944             && p_var->p_entries[i_entry].p_data == p_data )
945         {
946             break;
947         }
948 #ifndef NDEBUG
949         else if( p_var->p_entries[i_entry].pf_callback == pf_callback )
950             b_found_similar = true;
951 #endif
952     }
953
954     if( i_entry < 0 )
955     {
956 #ifndef NDEBUG
957         if( b_found_similar )
958             fprintf( stderr, "Calling var_DelCallback for '%s' with the same "
959                              "function but not the same data.", psz_name );
960         assert( 0 );
961 #endif
962         vlc_mutex_unlock( &p_priv->var_lock );
963         return VLC_EGENERIC;
964     }
965
966     REMOVE_ELEM( p_var->p_entries, p_var->i_entries, i_entry );
967
968     vlc_mutex_unlock( &p_priv->var_lock );
969
970     return VLC_SUCCESS;
971 }
972
973 /**
974  * Trigger callback on a variable
975  *
976  * \param p_this The object that hold the variable
977  * \param psz_name The name of the variable
978  */
979 int __var_TriggerCallback( vlc_object_t *p_this, const char *psz_name )
980 {
981     int i_var;
982     int i_ret = VLC_SUCCESS;
983     variable_t *p_var;
984
985     assert( p_this );
986
987     vlc_object_internals_t *p_priv = vlc_internals( p_this );
988
989     vlc_mutex_lock( &p_priv->var_lock );
990
991     i_var = GetUnused( p_this, psz_name );
992     if( i_var < 0 )
993     {
994         vlc_mutex_unlock( &p_priv->var_lock );
995         return i_var;
996     }
997
998     p_var = &p_priv->p_vars[i_var];
999
1000     /* Deal with callbacks. Tell we're in a callback, release the lock,
1001      * call stored functions, retake the lock. */
1002     if( p_var->i_entries )
1003         i_ret = TriggerCallback( p_this, &p_var, psz_name, p_var->val );
1004
1005     vlc_mutex_unlock( &p_priv->var_lock );
1006     return i_ret;
1007 }
1008
1009 /** Parse a stringified option
1010  * This function parse a string option and create the associated object
1011  * variable
1012  * The option must be of the form "[no[-]]foo[=bar]" where foo is the
1013  * option name and bar is the value of the option.
1014  * \param p_obj the object in which the variable must be created
1015  * \param psz_option the option to parse
1016  * \param trusted whether the option is set by a trusted input or not
1017  * \return nothing
1018  */
1019 void var_OptionParse( vlc_object_t *p_obj, const char *psz_option,
1020                       bool trusted )
1021 {
1022     char *psz_name, *psz_value;
1023     int  i_type;
1024     bool b_isno = false;
1025     vlc_value_t val;
1026
1027     val.psz_string = NULL;
1028
1029     /* It's too much of a hassle to remove the ':' when we parse
1030      * the cmd line :) */
1031     if( psz_option[0] == ':' )
1032         psz_option++;
1033
1034     if( !psz_option[0] )
1035         return;
1036
1037     psz_name = strdup( psz_option );
1038     if( psz_name == NULL )
1039         return;
1040
1041     psz_value = strchr( psz_name, '=' );
1042     if( psz_value != NULL )
1043         *psz_value++ = '\0';
1044
1045     /* FIXME: :programs should be handled generically */
1046     if( !strcmp( psz_name, "programs" ) )
1047         i_type = VLC_VAR_LIST;
1048     else
1049         i_type = config_GetType( p_obj, psz_name );
1050
1051     if( !i_type && !psz_value )
1052     {
1053         /* check for "no-foo" or "nofoo" */
1054         if( !strncmp( psz_name, "no-", 3 ) )
1055         {
1056             memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
1057         }
1058         else if( !strncmp( psz_name, "no", 2 ) )
1059         {
1060             memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
1061         }
1062         else goto cleanup;           /* Option doesn't exist */
1063
1064         b_isno = true;
1065         i_type = config_GetType( p_obj, psz_name );
1066     }
1067     if( !i_type ) goto cleanup; /* Option doesn't exist */
1068
1069     if( ( i_type != VLC_VAR_BOOL ) &&
1070         ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */
1071
1072     /* check if option is unsafe */
1073     if( !trusted )
1074     {
1075         module_config_t *p_config = config_FindConfig( p_obj, psz_name );
1076         if( !p_config || !p_config->b_safe )
1077         {
1078             msg_Err( p_obj, "unsafe option \"%s\" has been ignored for "
1079                             "security reasons", psz_name );
1080             free( psz_name );
1081             return;
1082         }
1083     }
1084
1085     /* Create the variable in the input object.
1086      * Children of the input object will be able to retreive this value
1087      * thanks to the inheritance property of the object variables. */
1088     __var_Create( p_obj, psz_name, i_type );
1089
1090     switch( i_type )
1091     {
1092     case VLC_VAR_BOOL:
1093         val.b_bool = !b_isno;
1094         break;
1095
1096     case VLC_VAR_INTEGER:
1097         val.i_int = strtol( psz_value, NULL, 0 );
1098         break;
1099
1100     case VLC_VAR_FLOAT:
1101         val.f_float = us_atof( psz_value );
1102         break;
1103
1104     case VLC_VAR_STRING:
1105     case VLC_VAR_MODULE:
1106     case VLC_VAR_FILE:
1107     case VLC_VAR_DIRECTORY:
1108         val.psz_string = psz_value;
1109         break;
1110
1111     case VLC_VAR_LIST:
1112     {
1113         char *psz_orig, *psz_var;
1114         vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
1115         val.p_list = p_list;
1116         p_list->i_count = 0;
1117
1118         psz_var = psz_orig = strdup(psz_value);
1119         while( psz_var && *psz_var )
1120         {
1121             char *psz_item = psz_var;
1122             vlc_value_t val2;
1123             while( *psz_var && *psz_var != ',' ) psz_var++;
1124             if( *psz_var == ',' )
1125             {
1126                 *psz_var = '\0';
1127                 psz_var++;
1128             }
1129             val2.i_int = strtol( psz_item, NULL, 0 );
1130             INSERT_ELEM( p_list->p_values, p_list->i_count,
1131                          p_list->i_count, val2 );
1132             /* p_list->i_count is incremented twice by INSERT_ELEM */
1133             p_list->i_count--;
1134             INSERT_ELEM( p_list->pi_types, p_list->i_count,
1135                          p_list->i_count, VLC_VAR_INTEGER );
1136         }
1137         free( psz_orig );
1138         break;
1139     }
1140
1141     default:
1142         goto cleanup;
1143     }
1144
1145     __var_Set( p_obj, psz_name, val );
1146
1147     /* If that's a list, remove all elements allocated */
1148     if( i_type == VLC_VAR_LIST )
1149         FreeList( &val );
1150
1151 cleanup:
1152     free( psz_name );
1153 }
1154
1155
1156 /* Following functions are local */
1157
1158 /*****************************************************************************
1159  * GetUnused: find an unused (not in callback) variable from its name
1160  *****************************************************************************
1161  * We do i_tries tries before giving up, just in case the variable is being
1162  * modified and called from a callback.
1163  *****************************************************************************/
1164 static int GetUnused( vlc_object_t *p_this, const char *psz_name )
1165 {
1166     assert( p_this );
1167
1168     vlc_object_internals_t *p_priv = vlc_internals( p_this );
1169
1170     while( true )
1171     {
1172         int i_var;
1173
1174         i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
1175         if( i_var < 0 )
1176         {
1177             return VLC_ENOVAR;
1178         }
1179
1180         if( ! p_priv->p_vars[i_var].b_incallback )
1181         {
1182             return i_var;
1183         }
1184
1185         mutex_cleanup_push( &p_priv->var_lock );
1186         vlc_cond_wait( &p_priv->var_wait, &p_priv->var_lock );
1187         vlc_cleanup_pop( );
1188     }
1189 }
1190
1191 /*****************************************************************************
1192  * HashString: our cool hash function
1193  *****************************************************************************
1194  * This function is not intended to be crypto-secure, we only want it to be
1195  * fast and not suck too much. This one is pretty fast and did 0 collisions
1196  * in wenglish's dictionary.
1197  *****************************************************************************/
1198 static uint32_t HashString( const char *psz_string )
1199 {
1200     uint32_t i_hash = 0;
1201
1202     while( *psz_string )
1203     {
1204         i_hash += *psz_string++;
1205         i_hash += i_hash << 10;
1206         i_hash ^= i_hash >> 8;
1207     }
1208
1209     return i_hash;
1210 }
1211
1212 /*****************************************************************************
1213  * Insert: find an empty slot to insert a new variable
1214  *****************************************************************************
1215  * We use a recursive inner function indexed on the hash. This function does
1216  * nothing in the rare cases where a collision may occur, see Lookup()
1217  * to see how we handle them.
1218  * XXX: does this really need to be written recursively?
1219  *****************************************************************************/
1220 static int Insert( variable_t *p_vars, int i_count, const char *psz_name )
1221 {
1222     if( i_count == 0 )
1223     {
1224         return 0;
1225     }
1226
1227     return InsertInner( p_vars, i_count, HashString( psz_name ) );
1228 }
1229
1230 static int InsertInner( variable_t *p_vars, int i_count, uint32_t i_hash )
1231 {
1232     int i_middle;
1233
1234     if( i_hash <= p_vars[0].i_hash )
1235     {
1236         return 0;
1237     }
1238
1239     if( i_hash >= p_vars[i_count - 1].i_hash )
1240     {
1241         return i_count;
1242     }
1243
1244     i_middle = i_count / 2;
1245
1246     /* We know that 0 < i_middle */
1247     if( i_hash < p_vars[i_middle].i_hash )
1248     {
1249         return InsertInner( p_vars, i_middle, i_hash );
1250     }
1251
1252     /* We know that i_middle + 1 < i_count */
1253     if( i_hash > p_vars[i_middle + 1].i_hash )
1254     {
1255         return i_middle + 1 + InsertInner( p_vars + i_middle + 1,
1256                                            i_count - i_middle - 1,
1257                                            i_hash );
1258     }
1259
1260     return i_middle + 1;
1261 }
1262
1263 static int u32cmp( const void *key, const void *data )
1264 {
1265     const variable_t *p_var = data;
1266     uint32_t hash = *(const uint32_t *)key ;
1267
1268     if( hash > p_var->i_hash )
1269         return 1;
1270     if( hash < p_var->i_hash )
1271         return -1;
1272     return 0;
1273 }
1274
1275 /*****************************************************************************
1276  * Lookup: find an existing variable given its name
1277  *****************************************************************************
1278  * We use a recursive inner function indexed on the hash. Care is taken of
1279  * possible hash collisions.
1280  *****************************************************************************/
1281 static int Lookup( variable_t *p_vars, size_t i_count, const char *psz_name )
1282 {
1283     variable_t *p_var;
1284     uint32_t i_hash;
1285
1286     i_hash = HashString( psz_name );
1287     p_var = bsearch( &i_hash, p_vars, i_count, sizeof( *p_var ), u32cmp );
1288
1289     /* Hash not found */
1290     if( p_var == NULL )
1291         return -1;
1292
1293     assert( i_count > 0 );
1294
1295     /* Find the first entry with the right hash */
1296     while( (p_var > p_vars) && (i_hash == p_var[-1].i_hash) )
1297         p_var--;
1298
1299     assert( p_var->i_hash == i_hash );
1300
1301     /* Hash collision should be very unlikely, but we cannot guarantee
1302      * it will never happen. So we do an exhaustive search amongst all
1303      * entries with the same hash. Typically, there is only one anyway. */
1304     for( variable_t *p_end = p_vars + i_count;
1305          (p_var < p_end) && (i_hash == p_var->i_hash);
1306          p_var++ )
1307     {
1308         if( !strcmp( psz_name, p_var->psz_name ) )
1309             return p_var - p_vars;
1310     }
1311
1312     /* Hash found, but entry not found */
1313     return -1;
1314 }
1315
1316 /*****************************************************************************
1317  * CheckValue: check that a value is valid wrt. a variable
1318  *****************************************************************************
1319  * This function checks p_val's value against p_var's limitations such as
1320  * minimal and maximal value, step, in-list position, and modifies p_val if
1321  * necessary.
1322  ****************************************************************************/
1323 static void CheckValue ( variable_t *p_var, vlc_value_t *p_val )
1324 {
1325     /* Check that our variable is in the list */
1326     if( p_var->i_type & VLC_VAR_HASCHOICE && p_var->choices.i_count )
1327     {
1328         int i;
1329
1330         /* This list is not sorted so go throug it (this is a small list) */
1331         for( i = p_var->choices.i_count ; i-- ; )
1332         {
1333             if( p_var->ops->pf_cmp( *p_val, p_var->choices.p_values[i] ) == 0 )
1334             {
1335                 break;
1336             }
1337         }
1338
1339         /* If not found, change it to anything vaguely valid */
1340         if( i < 0 )
1341         {
1342             /* Free the old variable, get the new one, dup it */
1343             p_var->ops->pf_free( p_val );
1344             *p_val = p_var->choices.p_values[p_var->i_default >= 0
1345                                           ? p_var->i_default : 0 ];
1346             p_var->ops->pf_dup( p_val );
1347         }
1348     }
1349
1350     /* Check that our variable is within the bounds */
1351     switch( p_var->i_type & VLC_VAR_TYPE )
1352     {
1353         case VLC_VAR_INTEGER:
1354             if( p_var->i_type & VLC_VAR_HASSTEP && p_var->step.i_int
1355                  && (p_val->i_int % p_var->step.i_int) )
1356             {
1357                 p_val->i_int = (p_val->i_int + (p_var->step.i_int / 2))
1358                                / p_var->step.i_int * p_var->step.i_int;
1359             }
1360             if( p_var->i_type & VLC_VAR_HASMIN
1361                  && p_val->i_int < p_var->min.i_int )
1362             {
1363                 p_val->i_int = p_var->min.i_int;
1364             }
1365             if( p_var->i_type & VLC_VAR_HASMAX
1366                  && p_val->i_int > p_var->max.i_int )
1367             {
1368                 p_val->i_int = p_var->max.i_int;
1369             }
1370             break;
1371         case VLC_VAR_FLOAT:
1372             if( p_var->i_type & VLC_VAR_HASSTEP && p_var->step.f_float )
1373             {
1374                 float f_round = p_var->step.f_float * (float)(int)( 0.5 +
1375                                         p_val->f_float / p_var->step.f_float );
1376                 if( p_val->f_float != f_round )
1377                 {
1378                     p_val->f_float = f_round;
1379                 }
1380             }
1381             if( p_var->i_type & VLC_VAR_HASMIN
1382                  && p_val->f_float < p_var->min.f_float )
1383             {
1384                 p_val->f_float = p_var->min.f_float;
1385             }
1386             if( p_var->i_type & VLC_VAR_HASMAX
1387                  && p_val->f_float > p_var->max.f_float )
1388             {
1389                 p_val->f_float = p_var->max.f_float;
1390             }
1391             break;
1392         case VLC_VAR_TIME:
1393             /* FIXME: TODO */
1394             break;
1395     }
1396 }
1397
1398 /*****************************************************************************
1399  * InheritValue: try to inherit the value of this variable from the closest
1400  * ancestor objects or ultimately from the configuration.
1401  * The function should always be entered with the object var_lock locked.
1402  *****************************************************************************/
1403 static int InheritValue( vlc_object_t *p_this, const char *psz_name,
1404                          vlc_value_t *p_val, int i_type )
1405 {
1406     i_type &= VLC_VAR_CLASS;
1407     for( vlc_object_t *obj = p_this->p_parent; obj != NULL; obj = obj->p_parent )
1408         if( var_GetChecked( obj, psz_name, i_type, p_val ) == VLC_SUCCESS )
1409             return VLC_SUCCESS;
1410
1411     /* else take value from config */
1412     switch( i_type & VLC_VAR_CLASS )
1413     {
1414         case VLC_VAR_STRING:
1415             p_val->psz_string = config_GetPsz( p_this, psz_name );
1416             if( !p_val->psz_string ) p_val->psz_string = strdup("");
1417             break;
1418         case VLC_VAR_FLOAT:
1419             p_val->f_float = config_GetFloat( p_this, psz_name );
1420             break;
1421         case VLC_VAR_INTEGER:
1422             p_val->i_int = config_GetInt( p_this, psz_name );
1423             break;
1424         case VLC_VAR_BOOL:
1425             p_val->b_bool = config_GetInt( p_this, psz_name );
1426             break;
1427         case VLC_VAR_LIST:
1428         {
1429             char *psz_orig, *psz_var;
1430             vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
1431             p_val->p_list = p_list;
1432             p_list->i_count = 0;
1433
1434             psz_var = psz_orig = config_GetPsz( p_this, psz_name );
1435             while( psz_var && *psz_var )
1436             {
1437                 char *psz_item = psz_var;
1438                 vlc_value_t val;
1439                 while( *psz_var && *psz_var != ',' ) psz_var++;
1440                 if( *psz_var == ',' )
1441                 {
1442                     *psz_var = '\0';
1443                     psz_var++;
1444                 }
1445                 val.i_int = strtol( psz_item, NULL, 0 );
1446                 INSERT_ELEM( p_list->p_values, p_list->i_count,
1447                              p_list->i_count, val );
1448                 /* p_list->i_count is incremented twice by INSERT_ELEM */
1449                 p_list->i_count--;
1450                 INSERT_ELEM( p_list->pi_types, p_list->i_count,
1451                              p_list->i_count, VLC_VAR_INTEGER );
1452             }
1453             free( psz_orig );
1454             break;
1455         }
1456         default:
1457             msg_Warn( p_this, "Could not inherit value for var %s "
1458                               "from config. Invalid Type", psz_name );
1459             return VLC_ENOOBJ;
1460             break;
1461     }
1462     /*msg_Dbg( p_this, "Inherited value for var %s from config", psz_name );*/
1463     return VLC_SUCCESS;
1464 }
1465
1466
1467 /**********************************************************************
1468  * Trigger the callbacks.
1469  * Tell we're in a callback, release the lock, call stored functions,
1470  * retake the lock.
1471  **********************************************************************/
1472 static int TriggerCallback( vlc_object_t *p_this, variable_t **pp_var,
1473                             const char *psz_name, vlc_value_t oldval )
1474 {
1475     int i_var;
1476     int i_entries = (*pp_var)->i_entries;
1477     callback_entry_t *p_entries = (*pp_var)->p_entries;
1478
1479     assert( p_this );
1480
1481     vlc_object_internals_t *p_priv = vlc_internals( p_this );
1482
1483     (*pp_var)->b_incallback = true;
1484     vlc_mutex_unlock( &p_priv->var_lock );
1485
1486     /* The real calls */
1487     for( ; i_entries-- ; )
1488     {
1489         p_entries[i_entries].pf_callback( p_this, psz_name, oldval, (*pp_var)->val,
1490                                           p_entries[i_entries].p_data );
1491     }
1492
1493     vlc_mutex_lock( &p_priv->var_lock );
1494
1495     i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
1496     if( i_var < 0 )
1497     {
1498         msg_Err( p_this, "variable %s has disappeared", psz_name );
1499         return VLC_ENOVAR;
1500      }
1501
1502      *pp_var = &p_priv->p_vars[i_var];
1503      (*pp_var)->b_incallback = false;
1504      vlc_cond_broadcast( &p_priv->var_wait );
1505
1506      return VLC_SUCCESS;
1507 }
1508
1509
1510 /**********************************************************************
1511  * Execute a var command on an object identified by its name
1512  **********************************************************************/
1513 int __var_Command( vlc_object_t *p_this, const char *psz_name,
1514                    const char *psz_cmd, const char *psz_arg, char **psz_msg )
1515 {
1516     vlc_object_t *p_obj = vlc_object_find_name( p_this->p_libvlc,
1517                                                 psz_name, FIND_CHILD );
1518     int i_type, i_ret;
1519
1520     if( !p_obj )
1521     {
1522         if( psz_msg )
1523             *psz_msg = strdup( "Unknown destination object." );
1524         return VLC_ENOOBJ;
1525     }
1526
1527     i_type = var_Type( p_obj, psz_cmd );
1528     if( !( i_type&VLC_VAR_ISCOMMAND ) )
1529     {
1530         vlc_object_release( p_obj );
1531         if( psz_msg )
1532             *psz_msg = strdup( "Variable doesn't exist or isn't a command." );
1533         return VLC_EGENERIC;
1534     }
1535
1536     i_type &= VLC_VAR_CLASS;
1537     switch( i_type )
1538     {
1539         case VLC_VAR_INTEGER:
1540             i_ret = var_SetInteger( p_obj, psz_cmd, atoi( psz_arg ) );
1541             break;
1542         case VLC_VAR_FLOAT:
1543             i_ret = var_SetFloat( p_obj, psz_cmd, us_atof( psz_arg ) );
1544             break;
1545         case VLC_VAR_STRING:
1546             i_ret = var_SetString( p_obj, psz_cmd, psz_arg );
1547             break;
1548         case VLC_VAR_BOOL:
1549             i_ret = var_SetBool( p_obj, psz_cmd, atoi( psz_arg ) );
1550             break;
1551         default:
1552             i_ret = VLC_EGENERIC;
1553             break;
1554     }
1555
1556     vlc_object_release( p_obj );
1557
1558     if( psz_msg )
1559     {
1560         if( asprintf( psz_msg, "%s on object %s returned %i (%s)",
1561                   psz_cmd, psz_name, i_ret, vlc_error( i_ret ) ) == -1)
1562             *psz_msg = NULL;
1563     }
1564
1565     return i_ret;
1566 }
1567
1568
1569 /**
1570  * Free a list and the associated strings
1571  * @param p_val: the list variable
1572  * @param p_val2: the variable associated or NULL
1573  */
1574 void var_FreeList( vlc_value_t *p_val, vlc_value_t *p_val2 )
1575 {
1576     FreeList( p_val );
1577     if( p_val2 && p_val2->p_list )
1578     {
1579         for( int i = 0; i < p_val2->p_list->i_count; i++ )
1580             free( p_val2->p_list->p_values[i].psz_string );
1581         if( p_val2->p_list->i_count )
1582         {
1583             free( p_val2->p_list->p_values );
1584             free( p_val2->p_list->pi_types );
1585         }
1586         free( p_val2->p_list );
1587     }
1588 }