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