]> git.sesse.net Git - vlc/blob - src/misc/variables.c
programs is a string, which is a string, which is not a list
[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     i_type = config_GetType( p_obj, psz_name );
1052     if( !i_type && !psz_value )
1053     {
1054         /* check for "no-foo" or "nofoo" */
1055         if( !strncmp( psz_name, "no-", 3 ) )
1056         {
1057             memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
1058         }
1059         else if( !strncmp( psz_name, "no", 2 ) )
1060         {
1061             memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
1062         }
1063         else goto cleanup;           /* Option doesn't exist */
1064
1065         b_isno = true;
1066         i_type = config_GetType( p_obj, psz_name );
1067     }
1068     if( !i_type ) goto cleanup; /* Option doesn't exist */
1069
1070     if( ( i_type != VLC_VAR_BOOL ) &&
1071         ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */
1072
1073     /* check if option is unsafe */
1074     if( !trusted )
1075     {
1076         module_config_t *p_config = config_FindConfig( p_obj, psz_name );
1077         if( !p_config || !p_config->b_safe )
1078         {
1079             msg_Err( p_obj, "unsafe option \"%s\" has been ignored for "
1080                             "security reasons", psz_name );
1081             free( psz_name );
1082             return;
1083         }
1084     }
1085
1086     /* Create the variable in the input object.
1087      * Children of the input object will be able to retreive this value
1088      * thanks to the inheritance property of the object variables. */
1089     var_Create( p_obj, psz_name, i_type );
1090
1091     switch( i_type )
1092     {
1093     case VLC_VAR_BOOL:
1094         val.b_bool = !b_isno;
1095         break;
1096
1097     case VLC_VAR_INTEGER:
1098         val.i_int = strtol( psz_value, NULL, 0 );
1099         break;
1100
1101     case VLC_VAR_FLOAT:
1102         val.f_float = us_atof( psz_value );
1103         break;
1104
1105     case VLC_VAR_STRING:
1106     case VLC_VAR_MODULE:
1107     case VLC_VAR_FILE:
1108     case VLC_VAR_DIRECTORY:
1109         val.psz_string = psz_value;
1110         break;
1111
1112     case VLC_VAR_LIST:
1113     {
1114         char *psz_orig, *psz_var;
1115         vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
1116         val.p_list = p_list;
1117         p_list->i_count = 0;
1118
1119         psz_var = psz_orig = strdup(psz_value);
1120         while( psz_var && *psz_var )
1121         {
1122             char *psz_item = psz_var;
1123             vlc_value_t val2;
1124             while( *psz_var && *psz_var != ',' ) psz_var++;
1125             if( *psz_var == ',' )
1126             {
1127                 *psz_var = '\0';
1128                 psz_var++;
1129             }
1130             val2.i_int = strtol( psz_item, NULL, 0 );
1131             INSERT_ELEM( p_list->p_values, p_list->i_count,
1132                          p_list->i_count, val2 );
1133             /* p_list->i_count is incremented twice by INSERT_ELEM */
1134             p_list->i_count--;
1135             INSERT_ELEM( p_list->pi_types, p_list->i_count,
1136                          p_list->i_count, VLC_VAR_INTEGER );
1137         }
1138         free( psz_orig );
1139         break;
1140     }
1141
1142     default:
1143         goto cleanup;
1144     }
1145
1146     var_Set( p_obj, psz_name, val );
1147
1148     /* If that's a list, remove all elements allocated */
1149     if( i_type == VLC_VAR_LIST )
1150         FreeList( &val );
1151
1152 cleanup:
1153     free( psz_name );
1154 }
1155
1156
1157 /* Following functions are local */
1158
1159 /**
1160  * Waits until the variable is inactive (i.e. not executing a callback)
1161  */
1162 static void WaitUnused( vlc_object_t *p_this, variable_t *p_var )
1163 {
1164     vlc_object_internals_t *p_priv = vlc_internals( p_this );
1165
1166     mutex_cleanup_push( &p_priv->var_lock );
1167     while( p_var->b_incallback )
1168         vlc_cond_wait( &p_priv->var_wait, &p_priv->var_lock );
1169     vlc_cleanup_pop( );
1170 }
1171
1172 /*****************************************************************************
1173  * CheckValue: check that a value is valid wrt. a variable
1174  *****************************************************************************
1175  * This function checks p_val's value against p_var's limitations such as
1176  * minimal and maximal value, step, in-list position, and modifies p_val if
1177  * necessary.
1178  ****************************************************************************/
1179 static void CheckValue ( variable_t *p_var, vlc_value_t *p_val )
1180 {
1181     /* Check that our variable is in the list */
1182     if( p_var->i_type & VLC_VAR_HASCHOICE && p_var->choices.i_count )
1183     {
1184         int i;
1185
1186         /* This list is not sorted so go throug it (this is a small list) */
1187         for( i = p_var->choices.i_count ; i-- ; )
1188         {
1189             if( p_var->ops->pf_cmp( *p_val, p_var->choices.p_values[i] ) == 0 )
1190             {
1191                 break;
1192             }
1193         }
1194
1195         /* If not found, change it to anything vaguely valid */
1196         if( i < 0 )
1197         {
1198             /* Free the old variable, get the new one, dup it */
1199             p_var->ops->pf_free( p_val );
1200             *p_val = p_var->choices.p_values[p_var->i_default >= 0
1201                                           ? p_var->i_default : 0 ];
1202             p_var->ops->pf_dup( p_val );
1203         }
1204     }
1205
1206     /* Check that our variable is within the bounds */
1207     switch( p_var->i_type & VLC_VAR_TYPE )
1208     {
1209         case VLC_VAR_INTEGER:
1210             if( p_var->i_type & VLC_VAR_HASSTEP && p_var->step.i_int
1211                  && (p_val->i_int % p_var->step.i_int) )
1212             {
1213                 p_val->i_int = (p_val->i_int + (p_var->step.i_int / 2))
1214                                / p_var->step.i_int * p_var->step.i_int;
1215             }
1216             if( p_var->i_type & VLC_VAR_HASMIN
1217                  && p_val->i_int < p_var->min.i_int )
1218             {
1219                 p_val->i_int = p_var->min.i_int;
1220             }
1221             if( p_var->i_type & VLC_VAR_HASMAX
1222                  && p_val->i_int > p_var->max.i_int )
1223             {
1224                 p_val->i_int = p_var->max.i_int;
1225             }
1226             break;
1227         case VLC_VAR_FLOAT:
1228             if( p_var->i_type & VLC_VAR_HASSTEP && p_var->step.f_float )
1229             {
1230                 float f_round = p_var->step.f_float * (float)(int)( 0.5 +
1231                                         p_val->f_float / p_var->step.f_float );
1232                 if( p_val->f_float != f_round )
1233                 {
1234                     p_val->f_float = f_round;
1235                 }
1236             }
1237             if( p_var->i_type & VLC_VAR_HASMIN
1238                  && p_val->f_float < p_var->min.f_float )
1239             {
1240                 p_val->f_float = p_var->min.f_float;
1241             }
1242             if( p_var->i_type & VLC_VAR_HASMAX
1243                  && p_val->f_float > p_var->max.f_float )
1244             {
1245                 p_val->f_float = p_var->max.f_float;
1246             }
1247             break;
1248         case VLC_VAR_TIME:
1249             /* FIXME: TODO */
1250             break;
1251     }
1252 }
1253
1254 /**
1255  * Finds the value of a variable. If the specified object does not hold a
1256  * variable with the specified name, try the parent object, and iterate until
1257  * the top of the tree. If no match is found, the value is read from the
1258  * configuration.
1259  */
1260 int var_Inherit( vlc_object_t *p_this, const char *psz_name, int i_type,
1261                  vlc_value_t *p_val )
1262 {
1263 #ifndef NDEBUG
1264     if (p_this != VLC_OBJECT(p_this->p_libvlc)
1265      && unlikely(p_this->p_parent == NULL))
1266     {
1267         msg_Info (p_this, "%s(%s) on detached object", __func__, psz_name);
1268         //vlc_backtrace ();
1269     }
1270 #endif
1271     i_type &= VLC_VAR_CLASS;
1272     for( vlc_object_t *obj = p_this; obj != NULL; obj = obj->p_parent )
1273     {
1274         if( var_GetChecked( obj, psz_name, i_type, p_val ) == VLC_SUCCESS )
1275             return VLC_SUCCESS;
1276 #ifndef NDEBUG
1277         if (obj != p_this && obj != VLC_OBJECT(p_this->p_libvlc)
1278          && unlikely(obj->p_parent == NULL))
1279         {
1280             msg_Info (p_this, "%s(%s) on detached tree [%p] %s", __func__,
1281                       psz_name, obj, obj->psz_object_type);
1282             //vlc_backtrace ();
1283         }
1284 #endif
1285     }
1286
1287     /* else take value from config */
1288     switch( i_type & VLC_VAR_CLASS )
1289     {
1290         case VLC_VAR_STRING:
1291             p_val->psz_string = config_GetPsz( p_this, psz_name );
1292             if( !p_val->psz_string ) p_val->psz_string = strdup("");
1293             break;
1294         case VLC_VAR_FLOAT:
1295             p_val->f_float = config_GetFloat( p_this, psz_name );
1296             break;
1297         case VLC_VAR_INTEGER:
1298             p_val->i_int = config_GetInt( p_this, psz_name );
1299             break;
1300         case VLC_VAR_BOOL:
1301             p_val->b_bool = config_GetInt( p_this, psz_name );
1302             break;
1303         case VLC_VAR_LIST:
1304         {
1305             char *psz_orig, *psz_var;
1306             vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
1307             p_val->p_list = p_list;
1308             p_list->i_count = 0;
1309
1310             psz_var = psz_orig = config_GetPsz( p_this, psz_name );
1311             while( psz_var && *psz_var )
1312             {
1313                 char *psz_item = psz_var;
1314                 vlc_value_t val;
1315                 while( *psz_var && *psz_var != ',' ) psz_var++;
1316                 if( *psz_var == ',' )
1317                 {
1318                     *psz_var = '\0';
1319                     psz_var++;
1320                 }
1321                 val.i_int = strtol( psz_item, NULL, 0 );
1322                 INSERT_ELEM( p_list->p_values, p_list->i_count,
1323                              p_list->i_count, val );
1324                 /* p_list->i_count is incremented twice by INSERT_ELEM */
1325                 p_list->i_count--;
1326                 INSERT_ELEM( p_list->pi_types, p_list->i_count,
1327                              p_list->i_count, VLC_VAR_INTEGER );
1328             }
1329             free( psz_orig );
1330             break;
1331         }
1332         default:
1333             msg_Warn( p_this, "Could not inherit value for var %s "
1334                               "from config. Invalid Type", psz_name );
1335             return VLC_ENOOBJ;
1336     }
1337     /*msg_Dbg( p_this, "Inherited value for var %s from config", psz_name );*/
1338     return VLC_SUCCESS;
1339 }
1340
1341
1342 /**
1343  * It inherits a string as an unsigned rational number (it also accepts basic
1344  * float number).
1345  *
1346  * It returns an error if the rational number cannot be parsed (0/0 is valid).
1347  * The rational is already reduced.
1348  */
1349 int (var_InheritURational)(vlc_object_t *object,
1350                            unsigned *num, unsigned *den,
1351                            const char *var)
1352 {
1353     /* */
1354     *num = 0;
1355     *den = 0;
1356
1357     /* */
1358     char *tmp = var_InheritString(object, var);
1359     if (!tmp)
1360         goto error;
1361
1362     char *next;
1363     unsigned n = strtol(tmp,  &next, 0);
1364     unsigned d = strtol(*next ? &next[1] : "0", NULL, 0);
1365
1366     if (*next == '.') {
1367         /* Interpret as a float number */
1368         double r = us_atof(tmp);
1369         double c = ceil(r);
1370         if (c >= UINT_MAX)
1371             goto error;
1372         unsigned m = c;
1373         if (m > 0) {
1374             d = UINT_MAX / m;
1375             n = r * d;
1376         } else {
1377             n = 0;
1378             d = 0;
1379         }
1380     }
1381
1382     if (n > 0 && d > 0)
1383         vlc_ureduce(num, den, n, d, 0);
1384
1385     free(tmp);
1386     return VLC_SUCCESS;
1387
1388 error:
1389     free(tmp);
1390     return VLC_EGENERIC;
1391 }
1392
1393 /**********************************************************************
1394  * Trigger the callbacks.
1395  * Tell we're in a callback, release the lock, call stored functions,
1396  * retake the lock.
1397  **********************************************************************/
1398 static int TriggerCallback( vlc_object_t *p_this, variable_t *p_var,
1399                             const char *psz_name, vlc_value_t oldval )
1400 {
1401     assert( p_this );
1402
1403     int i_entries = p_var->i_entries;
1404     if( i_entries == 0 )
1405         return VLC_SUCCESS;
1406
1407     callback_entry_t *p_entries = p_var->p_entries;
1408     vlc_object_internals_t *p_priv = vlc_internals( p_this );
1409
1410     assert( !p_var->b_incallback );
1411     p_var->b_incallback = true;
1412     vlc_mutex_unlock( &p_priv->var_lock );
1413
1414     /* The real calls */
1415     for( ; i_entries-- ; )
1416     {
1417         p_entries[i_entries].pf_callback( p_this, psz_name, oldval, p_var->val,
1418                                           p_entries[i_entries].p_data );
1419     }
1420
1421     vlc_mutex_lock( &p_priv->var_lock );
1422     p_var->b_incallback = false;
1423     vlc_cond_broadcast( &p_priv->var_wait );
1424
1425     return VLC_SUCCESS;
1426 }
1427
1428 #undef var_Command
1429 /**********************************************************************
1430  * Execute a var command on an object identified by its name
1431  **********************************************************************/
1432 int var_Command( vlc_object_t *p_this, const char *psz_name,
1433                  const char *psz_cmd, const char *psz_arg, char **psz_msg )
1434 {
1435     vlc_object_t *p_obj = vlc_object_find_name( p_this->p_libvlc,
1436                                                 psz_name, FIND_CHILD );
1437     int i_type, i_ret;
1438
1439     if( !p_obj )
1440     {
1441         if( psz_msg )
1442             *psz_msg = strdup( "Unknown destination object." );
1443         return VLC_ENOOBJ;
1444     }
1445
1446     i_type = var_Type( p_obj, psz_cmd );
1447     if( !( i_type&VLC_VAR_ISCOMMAND ) )
1448     {
1449         vlc_object_release( p_obj );
1450         if( psz_msg )
1451             *psz_msg = strdup( "Variable doesn't exist or isn't a command." );
1452         return VLC_EGENERIC;
1453     }
1454
1455     i_type &= VLC_VAR_CLASS;
1456     switch( i_type )
1457     {
1458         case VLC_VAR_INTEGER:
1459             i_ret = var_SetInteger( p_obj, psz_cmd, atoi( psz_arg ) );
1460             break;
1461         case VLC_VAR_FLOAT:
1462             i_ret = var_SetFloat( p_obj, psz_cmd, us_atof( psz_arg ) );
1463             break;
1464         case VLC_VAR_STRING:
1465             i_ret = var_SetString( p_obj, psz_cmd, psz_arg );
1466             break;
1467         case VLC_VAR_BOOL:
1468             i_ret = var_SetBool( p_obj, psz_cmd, atoi( psz_arg ) );
1469             break;
1470         default:
1471             i_ret = VLC_EGENERIC;
1472             break;
1473     }
1474
1475     vlc_object_release( p_obj );
1476
1477     if( psz_msg )
1478     {
1479         if( asprintf( psz_msg, "%s on object %s returned %i (%s)",
1480                   psz_cmd, psz_name, i_ret, vlc_error( i_ret ) ) == -1)
1481             *psz_msg = NULL;
1482     }
1483
1484     return i_ret;
1485 }
1486
1487
1488 /**
1489  * Free a list and the associated strings
1490  * @param p_val: the list variable
1491  * @param p_val2: the variable associated or NULL
1492  */
1493 void var_FreeList( vlc_value_t *p_val, vlc_value_t *p_val2 )
1494 {
1495     FreeList( p_val );
1496     if( p_val2 && p_val2->p_list )
1497     {
1498         for( int i = 0; i < p_val2->p_list->i_count; i++ )
1499             free( p_val2->p_list->p_values[i].psz_string );
1500         if( p_val2->p_list->i_count )
1501         {
1502             free( p_val2->p_list->p_values );
1503             free( p_val2->p_list->pi_types );
1504         }
1505         free( p_val2->p_list );
1506     }
1507 }