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