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