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