1 /*****************************************************************************
2 * variables.c: routines for object variables handling
3 *****************************************************************************
4 * Copyright (C) 2002-2009 VLC authors and VideoLAN
7 * Authors: Samuel Hocevar <sam@zoy.org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
39 #include <vlc_common.h>
40 #include <vlc_arrays.h>
41 #include <vlc_charset.h>
43 #include "variables.h"
44 #include "config/configuration.h"
46 typedef struct callback_entry_t
50 vlc_callback_t pf_value_callback
;
51 vlc_list_callback_t pf_list_callback
;
57 typedef struct variable_ops_t
59 int (*pf_cmp
) ( vlc_value_t
, vlc_value_t
);
60 void (*pf_dup
) ( vlc_value_t
* );
61 void (*pf_free
) ( vlc_value_t
* );
64 typedef struct callback_table_t
67 callback_entry_t
* p_entries
;
71 * The structure describing a variable.
72 * \note vlc_value_t is the common union for variable values
76 char * psz_name
; /**< The variable unique name (must be first) */
78 /** The variable's exported value */
81 /** The variable display name, mainly for use by the interfaces */
84 const variable_ops_t
*ops
;
86 int i_type
; /**< The type of the variable */
87 unsigned i_usage
; /**< Reference count */
89 /** If the variable has min/max/step values */
90 vlc_value_t min
, max
, step
;
92 /** List of choices */
94 /** List of friendly names for the choices */
95 vlc_list_t choices_text
;
97 /** Set to TRUE if the variable is in a callback */
100 /** Registered value callbacks */
101 callback_table_t value_callbacks
;
102 /** Registered list callbacks */
103 callback_table_t list_callbacks
;
106 static int CmpBool( vlc_value_t v
, vlc_value_t w
)
108 return v
.b_bool
? w
.b_bool
? 0 : 1 : w
.b_bool
? -1 : 0;
111 static int CmpInt( vlc_value_t v
, vlc_value_t w
)
113 return v
.i_int
== w
.i_int
? 0 : v
.i_int
> w
.i_int
? 1 : -1;
116 static int CmpString( vlc_value_t v
, vlc_value_t w
)
119 return !w
.psz_string
? 0 : -1;
121 return !w
.psz_string
? 1 : strcmp( v
.psz_string
, w
.psz_string
);
123 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; }
124 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; }
126 static void DupDummy( vlc_value_t
*p_val
) { (void)p_val
; /* unused */ }
127 static void DupString( vlc_value_t
*p_val
)
129 p_val
->psz_string
= strdup( p_val
->psz_string
? p_val
->psz_string
: "" );
132 static void FreeDummy( vlc_value_t
*p_val
) { (void)p_val
; /* unused */ }
133 static void FreeString( vlc_value_t
*p_val
) { free( p_val
->psz_string
); }
135 static const struct variable_ops_t
136 void_ops
= { NULL
, DupDummy
, FreeDummy
, },
137 addr_ops
= { CmpAddress
, DupDummy
, FreeDummy
, },
138 bool_ops
= { CmpBool
, DupDummy
, FreeDummy
, },
139 float_ops
= { CmpFloat
, DupDummy
, FreeDummy
, },
140 int_ops
= { CmpInt
, DupDummy
, FreeDummy
, },
141 string_ops
= { CmpString
, DupString
, FreeString
, },
142 coords_ops
= { NULL
, DupDummy
, FreeDummy
, };
144 static int varcmp( const void *a
, const void *b
)
146 const variable_t
*va
= a
, *vb
= b
;
148 /* psz_name must be first */
149 assert( va
== (const void *)&va
->psz_name
);
150 return strcmp( va
->psz_name
, vb
->psz_name
);
153 static variable_t
*Lookup( vlc_object_t
*obj
, const char *psz_name
)
155 vlc_object_internals_t
*priv
= vlc_internals( obj
);
158 vlc_mutex_lock(&priv
->var_lock
);
159 pp_var
= tfind( &psz_name
, &priv
->var_root
, varcmp
);
160 return (pp_var
!= NULL
) ? *pp_var
: NULL
;
163 static void Destroy( variable_t
*p_var
)
165 p_var
->ops
->pf_free( &p_var
->val
);
166 if( p_var
->choices
.i_count
)
168 for( int i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
170 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
171 free( p_var
->choices_text
.p_values
[i
].psz_string
);
173 free( p_var
->choices
.p_values
);
174 free( p_var
->choices_text
.p_values
);
177 free( p_var
->psz_name
);
178 free( p_var
->psz_text
);
179 free( p_var
->value_callbacks
.p_entries
);
184 * Adjusts a value to fit the constraints for a certain variable:
185 * - If the value is lower than the minimum, use the minimum.
186 * - If the value is higher than the maximum, use the maximum.
187 * - If the variable has steps, round the value to the nearest step.
189 static void CheckValue(variable_t
*var
, vlc_value_t
*val
)
191 /* Check that our variable is within the bounds */
192 switch (var
->i_type
& VLC_VAR_TYPE
)
194 case VLC_VAR_INTEGER
:
195 if (val
->i_int
< var
->min
.i_int
)
196 val
->i_int
= var
->min
.i_int
;
197 if (val
->i_int
> var
->max
.i_int
)
198 val
->i_int
= var
->max
.i_int
;
199 if (var
->step
.i_int
!= 0 && (val
->i_int
% var
->step
.i_int
))
202 val
->i_int
= (val
->i_int
+ (var
->step
.i_int
/ 2))
203 / var
->step
.i_int
* var
->step
.i_int
;
205 val
->i_int
= (val
->i_int
- (var
->step
.i_int
/ 2))
206 / var
->step
.i_int
* var
->step
.i_int
;
211 if (isless(val
->f_float
, var
->min
.f_float
))
212 val
->f_float
= var
->min
.f_float
;
213 if (isgreater(val
->f_float
, var
->max
.f_float
))
214 val
->f_float
= var
->max
.f_float
;
215 if (var
->step
.f_float
!= 0.f
)
216 val
->f_float
= var
->step
.f_float
217 * roundf(val
->f_float
/ var
->step
.f_float
);
223 * Waits until the variable is inactive (i.e. not executing a callback)
225 static void WaitUnused(vlc_object_t
*obj
, variable_t
*var
)
227 vlc_object_internals_t
*priv
= vlc_internals(obj
);
229 mutex_cleanup_push(&priv
->var_lock
);
230 while (var
->b_incallback
)
231 vlc_cond_wait(&priv
->var_wait
, &priv
->var_lock
);
235 static void TriggerCallback(vlc_object_t
*obj
, variable_t
*var
,
236 const char *name
, vlc_value_t prev
)
240 size_t count
= var
->value_callbacks
.i_entries
;
244 callback_entry_t
*entries
= var
->value_callbacks
.p_entries
;
245 vlc_object_internals_t
*priv
= vlc_internals(obj
);
247 assert(!var
->b_incallback
);
248 var
->b_incallback
= true;
249 vlc_mutex_unlock(&priv
->var_lock
);
251 for (size_t i
= 0; i
< count
; i
++)
252 entries
[i
].pf_value_callback(obj
, name
, prev
, var
->val
,
255 vlc_mutex_lock(&priv
->var_lock
);
256 var
->b_incallback
= false;
257 vlc_cond_broadcast(&priv
->var_wait
);
260 static void TriggerListCallback(vlc_object_t
*obj
, variable_t
*var
,
261 const char *name
, int action
, vlc_value_t
*val
)
265 size_t count
= var
->list_callbacks
.i_entries
;
269 callback_entry_t
*entries
= var
->list_callbacks
.p_entries
;
270 vlc_object_internals_t
*priv
= vlc_internals(obj
);
272 assert(!var
->b_incallback
);
273 var
->b_incallback
= true;
274 vlc_mutex_unlock(&priv
->var_lock
);
276 for (size_t i
= 0; i
< count
; i
++)
277 entries
[i
].pf_list_callback(obj
, name
, action
, val
,
280 vlc_mutex_lock(&priv
->var_lock
);
281 var
->b_incallback
= false;
282 vlc_cond_broadcast(&priv
->var_wait
);
287 * Initialize a vlc variable
289 * We hash the given string and insert it into the sorted list. The insertion
290 * may require slow memory copies, but think about what we gain in the log(n)
291 * lookup phase when setting/getting the variable value!
293 * \param p_this The object in which to create the variable
294 * \param psz_name The name of the variable
295 * \param i_type The variables type. Must be one of \ref var_type combined with
296 * zero or more \ref var_flags
298 int var_Create( vlc_object_t
*p_this
, const char *psz_name
, int i_type
)
302 variable_t
*p_var
= calloc( 1, sizeof( *p_var
) );
306 p_var
->psz_name
= strdup( psz_name
);
307 p_var
->psz_text
= NULL
;
309 p_var
->i_type
= i_type
& ~VLC_VAR_DOINHERIT
;
313 p_var
->choices
.i_count
= 0;
314 p_var
->choices
.p_values
= NULL
;
315 p_var
->choices_text
.i_count
= 0;
316 p_var
->choices_text
.p_values
= NULL
;
318 p_var
->b_incallback
= false;
319 p_var
->value_callbacks
= (callback_table_t
){ 0 };
321 /* Always initialize the variable, even if it is a list variable; this
322 * will lead to errors if the variable is not initialized, but it will
323 * not cause crashes in the variable handling. */
324 switch( i_type
& VLC_VAR_CLASS
)
327 p_var
->ops
= &bool_ops
;
328 p_var
->val
.b_bool
= false;
330 case VLC_VAR_INTEGER
:
331 p_var
->ops
= &int_ops
;
332 p_var
->val
.i_int
= 0;
333 p_var
->min
.i_int
= INT64_MIN
;
334 p_var
->max
.i_int
= INT64_MAX
;
337 p_var
->ops
= &string_ops
;
338 p_var
->val
.psz_string
= NULL
;
341 p_var
->ops
= &float_ops
;
342 p_var
->val
.f_float
= 0.f
;
343 p_var
->min
.f_float
= -FLT_MAX
;
344 p_var
->max
.f_float
= FLT_MAX
;
347 p_var
->ops
= &coords_ops
;
348 p_var
->val
.coords
.x
= p_var
->val
.coords
.y
= 0;
350 case VLC_VAR_ADDRESS
:
351 p_var
->ops
= &addr_ops
;
352 p_var
->val
.p_address
= NULL
;
355 p_var
->ops
= &void_ops
;
358 vlc_assert_unreachable ();
361 if (i_type
& VLC_VAR_DOINHERIT
)
362 var_Inherit(p_this
, psz_name
, i_type
, &p_var
->val
);
364 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
365 variable_t
**pp_var
, *p_oldvar
;
366 int ret
= VLC_SUCCESS
;
368 vlc_mutex_lock( &p_priv
->var_lock
);
370 pp_var
= tsearch( p_var
, &p_priv
->var_root
, varcmp
);
371 if( unlikely(pp_var
== NULL
) )
373 else if( (p_oldvar
= *pp_var
) == p_var
) /* Variable create */
374 p_var
= NULL
; /* Variable created */
375 else /* Variable already exists */
377 assert (((i_type
^ p_oldvar
->i_type
) & VLC_VAR_CLASS
) == 0);
379 p_oldvar
->i_type
|= i_type
& VLC_VAR_ISCOMMAND
;
381 vlc_mutex_unlock( &p_priv
->var_lock
);
383 /* If we did not need to create a new variable, free everything... */
390 * Destroy a vlc variable
392 * Look for the variable and destroy it if it is found. As in var_Create we
393 * do a call to memmove() but we have performance counterparts elsewhere.
395 * \param p_this The object that holds the variable
396 * \param psz_name The name of the variable
398 void (var_Destroy
)(vlc_object_t
*p_this
, const char *psz_name
)
404 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
406 p_var
= Lookup( p_this
, psz_name
);
408 msg_Dbg( p_this
, "attempt to destroy nonexistent variable \"%s\"",
410 else if( --p_var
->i_usage
== 0 )
412 assert(!p_var
->b_incallback
);
413 tdelete( p_var
, &p_priv
->var_root
, varcmp
);
417 assert(p_var
->i_usage
!= -1u);
420 vlc_mutex_unlock( &p_priv
->var_lock
);
426 static void CleanupVar( void *var
)
431 void var_DestroyAll( vlc_object_t
*obj
)
433 vlc_object_internals_t
*priv
= vlc_internals( obj
);
435 tdestroy( priv
->var_root
, CleanupVar
);
436 priv
->var_root
= NULL
;
441 * Perform an action on a variable
443 * \param p_this The object that holds the variable
444 * \param psz_name The name of the variable
445 * \param i_action The action to perform. Must be one of \ref var_action
446 * \param p_val First action parameter
447 * \param p_val2 Second action parameter
449 int var_Change( vlc_object_t
*p_this
, const char *psz_name
,
450 int i_action
, vlc_value_t
*p_val
, vlc_value_t
*p_val2
)
452 int ret
= VLC_SUCCESS
;
459 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
461 p_var
= Lookup( p_this
, psz_name
);
464 vlc_mutex_unlock( &p_priv
->var_lock
);
476 case VLC_VAR_SETMINMAX
:
477 assert(p_var
->ops
->pf_free
== FreeDummy
);
479 p_var
->max
= *p_val2
;
481 case VLC_VAR_SETSTEP
:
482 assert(p_var
->ops
->pf_free
== FreeDummy
);
483 p_var
->step
= *p_val
;
484 CheckValue( p_var
, &p_var
->val
);
486 case VLC_VAR_GETSTEP
:
487 switch (p_var
->i_type
& VLC_VAR_TYPE
)
489 case VLC_VAR_INTEGER
:
490 if (p_var
->step
.i_int
== 0)
494 if (p_var
->step
.f_float
== 0.f
)
500 if (ret
== VLC_SUCCESS
)
501 *p_val
= p_var
->step
;
503 case VLC_VAR_ADDCHOICE
:
505 int i
= p_var
->choices
.i_count
;
507 TAB_APPEND(p_var
->choices
.i_count
,
508 p_var
->choices
.p_values
, *p_val
);
509 assert(i
== p_var
->choices_text
.i_count
);
510 TAB_APPEND(p_var
->choices_text
.i_count
,
511 p_var
->choices_text
.p_values
, *p_val
);
512 p_var
->ops
->pf_dup( &p_var
->choices
.p_values
[i
] );
513 p_var
->choices_text
.p_values
[i
].psz_string
=
514 ( p_val2
&& p_val2
->psz_string
) ?
515 strdup( p_val2
->psz_string
) : NULL
;
517 TriggerListCallback(p_this
, p_var
, psz_name
, VLC_VAR_ADDCHOICE
, p_val
);
520 case VLC_VAR_DELCHOICE
:
524 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
525 if( p_var
->ops
->pf_cmp( p_var
->choices
.p_values
[i
], *p_val
) == 0 )
528 if( i
== p_var
->choices
.i_count
)
531 vlc_mutex_unlock( &p_priv
->var_lock
);
535 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
536 free( p_var
->choices_text
.p_values
[i
].psz_string
);
537 TAB_ERASE(p_var
->choices
.i_count
, p_var
->choices
.p_values
, i
);
538 TAB_ERASE(p_var
->choices_text
.i_count
,
539 p_var
->choices_text
.p_values
, i
);
541 TriggerListCallback(p_this
, p_var
, psz_name
, VLC_VAR_DELCHOICE
, p_val
);
544 case VLC_VAR_CHOICESCOUNT
:
545 p_val
->i_int
= p_var
->choices
.i_count
;
547 case VLC_VAR_CLEARCHOICES
:
548 for( int i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
549 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
550 for( int i
= 0 ; i
< p_var
->choices_text
.i_count
; i
++ )
551 free( p_var
->choices_text
.p_values
[i
].psz_string
);
553 if( p_var
->choices
.i_count
) free( p_var
->choices
.p_values
);
554 if( p_var
->choices_text
.i_count
) free( p_var
->choices_text
.p_values
);
556 p_var
->choices
.i_count
= 0;
557 p_var
->choices
.p_values
= NULL
;
558 p_var
->choices_text
.i_count
= 0;
559 p_var
->choices_text
.p_values
= NULL
;
560 TriggerListCallback(p_this
, p_var
, psz_name
, VLC_VAR_CLEARCHOICES
, NULL
);
562 case VLC_VAR_SETVALUE
:
563 /* Duplicate data if needed */
565 p_var
->ops
->pf_dup( &newval
);
566 /* Backup needed stuff */
568 /* Check boundaries and list */
569 CheckValue( p_var
, &newval
);
570 /* Set the variable */
572 /* Free data if needed */
573 p_var
->ops
->pf_free( &oldval
);
575 case VLC_VAR_GETCHOICES
:
576 p_val
->p_list
= xmalloc( sizeof(vlc_list_t
) );
577 p_val
->p_list
->p_values
=
578 xmalloc( p_var
->choices
.i_count
* sizeof(vlc_value_t
) );
579 p_val
->p_list
->i_type
= p_var
->i_type
;
580 p_val
->p_list
->i_count
= p_var
->choices
.i_count
;
583 p_val2
->p_list
= xmalloc( sizeof(vlc_list_t
) );
584 p_val2
->p_list
->p_values
=
585 xmalloc( p_var
->choices
.i_count
* sizeof(vlc_value_t
) );
586 p_val2
->p_list
->i_type
= VLC_VAR_STRING
;
587 p_val2
->p_list
->i_count
= p_var
->choices
.i_count
;
589 for( int i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
591 p_val
->p_list
->p_values
[i
] = p_var
->choices
.p_values
[i
];
592 p_var
->ops
->pf_dup( &p_val
->p_list
->p_values
[i
] );
595 p_val2
->p_list
->p_values
[i
].psz_string
=
596 p_var
->choices_text
.p_values
[i
].psz_string
?
597 strdup(p_var
->choices_text
.p_values
[i
].psz_string
) : NULL
;
601 case VLC_VAR_SETTEXT
:
602 free( p_var
->psz_text
);
603 if( p_val
&& p_val
->psz_string
)
604 p_var
->psz_text
= strdup( p_val
->psz_string
);
606 p_var
->psz_text
= NULL
;
608 case VLC_VAR_GETTEXT
:
609 p_val
->psz_string
= p_var
->psz_text
? strdup( p_var
->psz_text
)
616 vlc_mutex_unlock( &p_priv
->var_lock
);
623 * Perform a Get and Set on a variable
625 * \param p_this: The object that hold the variable
626 * \param psz_name: the name of the variable
627 * \param i_action: the action to perform
628 * \param p_val: The action parameter
629 * \return vlc error codes
631 int var_GetAndSet( vlc_object_t
*p_this
, const char *psz_name
, int i_action
,
640 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
642 p_var
= Lookup( p_this
, psz_name
);
645 vlc_mutex_unlock( &p_priv
->var_lock
);
649 WaitUnused( p_this
, p_var
);
651 /* Duplicated data if needed */
652 //p_var->ops->pf_dup( &val );
654 /* Backup needed stuff */
657 /* depending of the action requiered */
660 case VLC_VAR_BOOL_TOGGLE
:
661 assert( ( p_var
->i_type
& VLC_VAR_BOOL
) == VLC_VAR_BOOL
);
662 p_var
->val
.b_bool
= !p_var
->val
.b_bool
;
664 case VLC_VAR_INTEGER_ADD
:
665 assert( ( p_var
->i_type
& VLC_VAR_INTEGER
) == VLC_VAR_INTEGER
);
666 p_var
->val
.i_int
+= p_val
->i_int
;
668 case VLC_VAR_INTEGER_OR
:
669 assert( ( p_var
->i_type
& VLC_VAR_INTEGER
) == VLC_VAR_INTEGER
);
670 p_var
->val
.i_int
|= p_val
->i_int
;
672 case VLC_VAR_INTEGER_NAND
:
673 assert( ( p_var
->i_type
& VLC_VAR_INTEGER
) == VLC_VAR_INTEGER
);
674 p_var
->val
.i_int
&= ~p_val
->i_int
;
677 vlc_mutex_unlock( &p_priv
->var_lock
);
681 /* Check boundaries */
682 CheckValue( p_var
, &p_var
->val
);
685 /* Deal with callbacks.*/
686 TriggerCallback( p_this
, p_var
, psz_name
, oldval
);
688 vlc_mutex_unlock( &p_priv
->var_lock
);
694 * Request a variable's type
696 * \return The variable type if it exists, or 0 if the
697 * variable could not be found.
700 int var_Type( vlc_object_t
*p_this
, const char *psz_name
)
707 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
709 p_var
= Lookup( p_this
, psz_name
);
712 i_type
= p_var
->i_type
;
713 if( p_var
->choices
.i_count
> 0 )
714 i_type
|= VLC_VAR_HASCHOICE
;
716 vlc_mutex_unlock( &p_priv
->var_lock
);
721 #undef var_SetChecked
722 int var_SetChecked( vlc_object_t
*p_this
, const char *psz_name
,
723 int expected_type
, vlc_value_t val
)
730 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
732 p_var
= Lookup( p_this
, psz_name
);
735 vlc_mutex_unlock( &p_priv
->var_lock
);
739 assert( expected_type
== 0 ||
740 (p_var
->i_type
& VLC_VAR_CLASS
) == expected_type
);
741 assert ((p_var
->i_type
& VLC_VAR_CLASS
) != VLC_VAR_VOID
);
743 WaitUnused( p_this
, p_var
);
745 /* Duplicate data if needed */
746 p_var
->ops
->pf_dup( &val
);
748 /* Backup needed stuff */
751 /* Check boundaries and list */
752 CheckValue( p_var
, &val
);
754 /* Set the variable */
757 /* Deal with callbacks */
758 TriggerCallback( p_this
, p_var
, psz_name
, oldval
);
760 /* Free data if needed */
761 p_var
->ops
->pf_free( &oldval
);
763 vlc_mutex_unlock( &p_priv
->var_lock
);
769 * Set a variable's value
771 * \param p_this The object that hold the variable
772 * \param psz_name The name of the variable
773 * \param val the value to set
775 int var_Set( vlc_object_t
*p_this
, const char *psz_name
, vlc_value_t val
)
777 return var_SetChecked( p_this
, psz_name
, 0, val
);
780 #undef var_GetChecked
781 int var_GetChecked( vlc_object_t
*p_this
, const char *psz_name
,
782 int expected_type
, vlc_value_t
*p_val
)
786 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
788 int err
= VLC_SUCCESS
;
790 p_var
= Lookup( p_this
, psz_name
);
793 assert( expected_type
== 0 ||
794 (p_var
->i_type
& VLC_VAR_CLASS
) == expected_type
);
795 assert ((p_var
->i_type
& VLC_VAR_CLASS
) != VLC_VAR_VOID
);
797 /* Really get the variable */
800 /* Duplicate value if needed */
801 p_var
->ops
->pf_dup( p_val
);
806 vlc_mutex_unlock( &p_priv
->var_lock
);
812 * Get a variable's value
814 * \param p_this The object that holds the variable
815 * \param psz_name The name of the variable
816 * \param p_val Pointer to a vlc_value_t that will hold the variable's value
817 * after the function is finished
819 int var_Get( vlc_object_t
*p_this
, const char *psz_name
, vlc_value_t
*p_val
)
821 return var_GetChecked( p_this
, psz_name
, 0, p_val
);
828 } vlc_callback_type_t
;
830 static void AddCallback( vlc_object_t
*p_this
, const char *psz_name
,
831 callback_entry_t entry
, vlc_callback_type_t i_type
)
837 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
839 p_var
= Lookup( p_this
, psz_name
);
842 vlc_mutex_unlock( &p_priv
->var_lock
);
843 msg_Err( p_this
, "cannot add callback %p to nonexistent variable '%s'",
844 entry
.p_callback
, psz_name
);
848 WaitUnused( p_this
, p_var
);
850 callback_table_t
*p_table
;
851 if (i_type
== vlc_value_callback
)
852 p_table
= &p_var
->value_callbacks
;
854 p_table
= &p_var
->list_callbacks
;
855 TAB_APPEND(p_table
->i_entries
, p_table
->p_entries
, entry
);
857 vlc_mutex_unlock( &p_priv
->var_lock
);
860 #undef var_AddCallback
862 * Register a callback in a variable
864 * We store a function pointer that will be called upon variable
867 * \param p_this The object that holds the variable
868 * \param psz_name The name of the variable
869 * \param pf_callback The function pointer
870 * \param p_data A generic pointer that will be passed as the last
871 * argument to the callback function.
873 * \warning The callback function is run in the thread that calls var_Set on
874 * the variable. Use proper locking. This thread may not have much
875 * time to spare, so keep callback functions short.
877 void var_AddCallback( vlc_object_t
*p_this
, const char *psz_name
,
878 vlc_callback_t pf_callback
, void *p_data
)
880 callback_entry_t entry
;
881 entry
.pf_value_callback
= pf_callback
;
882 entry
.p_data
= p_data
;
884 AddCallback(p_this
, psz_name
, entry
, vlc_value_callback
);
887 static void DelCallback( vlc_object_t
*p_this
, const char *psz_name
,
888 callback_entry_t entry
, vlc_callback_type_t i_type
)
893 bool b_found_similar
= false;
898 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
900 p_var
= Lookup( p_this
, psz_name
);
903 vlc_mutex_unlock( &p_priv
->var_lock
);
904 msg_Err( p_this
, "cannot delete callback %p from nonexistent "
905 "variable '%s'", entry
.p_callback
, psz_name
);
909 WaitUnused( p_this
, p_var
);
911 callback_table_t
*p_table
;
912 if (i_type
== vlc_value_callback
)
913 p_table
= &p_var
->value_callbacks
;
915 p_table
= &p_var
->list_callbacks
;
917 for( i_entry
= p_table
->i_entries
; i_entry
-- ; )
919 if( p_table
->p_entries
[i_entry
].p_callback
== entry
.p_callback
920 && p_table
->p_entries
[i_entry
].p_data
== entry
.p_data
)
925 else if( p_table
->p_entries
[i_entry
].p_callback
== entry
.p_callback
)
926 b_found_similar
= true;
933 if( b_found_similar
)
934 fprintf( stderr
, "Calling var_DelCallback for '%s' with the same "
935 "function but not the same data.", psz_name
);
936 vlc_assert_unreachable();
938 vlc_mutex_unlock( &p_priv
->var_lock
);
942 TAB_ERASE(p_table
->i_entries
, p_table
->p_entries
, i_entry
);
944 vlc_mutex_unlock( &p_priv
->var_lock
);
947 #undef var_DelCallback
949 * Remove a callback from a variable
951 * pf_callback and p_data have to be given again, because different objects
952 * might have registered the same callback function.
954 void var_DelCallback( vlc_object_t
*p_this
, const char *psz_name
,
955 vlc_callback_t pf_callback
, void *p_data
)
957 callback_entry_t entry
;
958 entry
.pf_value_callback
= pf_callback
;
959 entry
.p_data
= p_data
;
961 DelCallback(p_this
, psz_name
, entry
, vlc_value_callback
);
964 #undef var_TriggerCallback
966 * Trigger callback on a variable
968 * \param p_this The object that hold the variable
969 * \param psz_name The name of the variable
971 void var_TriggerCallback( vlc_object_t
*p_this
, const char *psz_name
)
973 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
974 variable_t
*p_var
= Lookup( p_this
, psz_name
);
977 WaitUnused( p_this
, p_var
);
979 /* Deal with callbacks. Tell we're in a callback, release the lock,
980 * call stored functions, retake the lock. */
981 TriggerCallback( p_this
, p_var
, psz_name
, p_var
->val
);
983 vlc_mutex_unlock( &p_priv
->var_lock
);
986 #undef var_AddListCallback
988 * Register a callback for a list variable
990 * The callback is triggered when an element is added/removed from the
991 * list or when the list is cleared.
993 * See var_AddCallback().
995 void var_AddListCallback( vlc_object_t
*p_this
, const char *psz_name
,
996 vlc_list_callback_t pf_callback
, void *p_data
)
998 callback_entry_t entry
;
999 entry
.pf_list_callback
= pf_callback
;
1000 entry
.p_data
= p_data
;
1002 AddCallback(p_this
, psz_name
, entry
, vlc_list_callback
);
1005 #undef var_DelListCallback
1007 * Remove a callback from a list variable
1009 * See var_DelCallback().
1011 void var_DelListCallback( vlc_object_t
*p_this
, const char *psz_name
,
1012 vlc_list_callback_t pf_callback
, void *p_data
)
1014 callback_entry_t entry
;
1015 entry
.pf_list_callback
= pf_callback
;
1016 entry
.p_data
= p_data
;
1018 DelCallback(p_this
, psz_name
, entry
, vlc_list_callback
);
1021 /** Parse a stringified option
1022 * This function parse a string option and create the associated object
1024 * The option must be of the form "[no[-]]foo[=bar]" where foo is the
1025 * option name and bar is the value of the option.
1026 * \param p_obj the object in which the variable must be created
1027 * \param psz_option the option to parse
1028 * \param trusted whether the option is set by a trusted input or not
1031 void var_OptionParse( vlc_object_t
*p_obj
, const char *psz_option
,
1034 char *psz_name
, *psz_value
;
1036 bool b_isno
= false;
1039 val
.psz_string
= NULL
;
1041 /* It's too much of a hassle to remove the ':' when we parse
1042 * the cmd line :) */
1043 if( psz_option
[0] == ':' )
1046 if( !psz_option
[0] )
1049 psz_name
= strdup( psz_option
);
1050 if( psz_name
== NULL
)
1053 psz_value
= strchr( psz_name
, '=' );
1054 if( psz_value
!= NULL
)
1055 *psz_value
++ = '\0';
1057 i_type
= config_GetType( p_obj
, psz_name
);
1058 if( !i_type
&& !psz_value
)
1060 /* check for "no-foo" or "nofoo" */
1061 if( !strncmp( psz_name
, "no-", 3 ) )
1063 memmove( psz_name
, psz_name
+ 3, strlen(psz_name
) + 1 - 3 );
1065 else if( !strncmp( psz_name
, "no", 2 ) )
1067 memmove( psz_name
, psz_name
+ 2, strlen(psz_name
) + 1 - 2 );
1069 else goto cleanup
; /* Option doesn't exist */
1072 i_type
= config_GetType( p_obj
, psz_name
);
1074 if( !i_type
) goto cleanup
; /* Option doesn't exist */
1076 if( ( i_type
!= VLC_VAR_BOOL
) &&
1077 ( !psz_value
|| !*psz_value
) ) goto cleanup
; /* Invalid value */
1079 /* check if option is unsafe */
1080 if( !trusted
&& !config_IsSafe( psz_name
) )
1082 msg_Err( p_obj
, "unsafe option \"%s\" has been ignored for "
1083 "security reasons", psz_name
);
1088 /* Create the variable in the input object.
1089 * Children of the input object will be able to retrieve this value
1090 * thanks to the inheritance property of the object variables. */
1091 var_Create( p_obj
, psz_name
, i_type
);
1096 val
.b_bool
= !b_isno
;
1099 case VLC_VAR_INTEGER
:
1100 val
.i_int
= strtoll( psz_value
, NULL
, 0 );
1104 val
.f_float
= us_atof( psz_value
);
1107 case VLC_VAR_STRING
:
1108 val
.psz_string
= psz_value
;
1115 var_Set( p_obj
, psz_name
, val
);
1121 #undef var_LocationParse
1123 * Parses a set of colon-separated or semicolon-separated
1124 * <code>name=value</code> pairs.
1125 * Some access (or access_demux) plugins uses this scheme
1126 * in media resource location.
1127 * @note Only trusted/safe variables are allowed. This is intended.
1129 * @warning Only use this for plugins implementing VLC-specific resource
1130 * location schemes. This would not make any sense for standardized ones.
1132 * @param obj VLC object on which to set variables (and emit error messages)
1133 * @param mrl string to parse
1134 * @param pref prefix to prepend to option names in the string
1136 * @return VLC_ENOMEM on error, VLC_SUCCESS on success.
1138 int var_LocationParse (vlc_object_t
*obj
, const char *mrl
, const char *pref
)
1140 int ret
= VLC_SUCCESS
;
1141 size_t preflen
= strlen (pref
) + 1;
1143 assert(mrl
!= NULL
);
1144 while (*mrl
!= '\0')
1146 mrl
+= strspn (mrl
, ":;"); /* skip leading colon(s) */
1148 size_t len
= strcspn (mrl
, ":;");
1149 char *buf
= malloc (preflen
+ len
);
1151 if (likely(buf
!= NULL
))
1153 /* NOTE: this does not support the "no-<varname>" bool syntax. */
1154 /* DO NOT use asprintf() here; it won't work! Think again. */
1155 snprintf (buf
, preflen
+ len
, "%s%s", pref
, mrl
);
1156 var_OptionParse (obj
, buf
, false);
1168 * Finds the value of a variable. If the specified object does not hold a
1169 * variable with the specified name, try the parent object, and iterate until
1170 * the top of the tree. If no match is found, the value is read from the
1173 int var_Inherit( vlc_object_t
*p_this
, const char *psz_name
, int i_type
,
1174 vlc_value_t
*p_val
)
1176 i_type
&= VLC_VAR_CLASS
;
1177 for( vlc_object_t
*obj
= p_this
; obj
!= NULL
; obj
= obj
->obj
.parent
)
1179 if( var_GetChecked( obj
, psz_name
, i_type
, p_val
) == VLC_SUCCESS
)
1183 /* else take value from config */
1184 switch( i_type
& VLC_VAR_CLASS
)
1186 case VLC_VAR_STRING
:
1187 p_val
->psz_string
= config_GetPsz( p_this
, psz_name
);
1188 if( !p_val
->psz_string
) p_val
->psz_string
= strdup("");
1191 p_val
->f_float
= config_GetFloat( p_this
, psz_name
);
1193 case VLC_VAR_INTEGER
:
1194 p_val
->i_int
= config_GetInt( p_this
, psz_name
);
1197 p_val
->b_bool
= config_GetInt( p_this
, psz_name
);
1200 vlc_assert_unreachable();
1201 case VLC_VAR_ADDRESS
:
1209 * It inherits a string as an unsigned rational number (it also accepts basic
1212 * It returns an error if the rational number cannot be parsed (0/0 is valid).
1213 * The rational is already reduced.
1215 int (var_InheritURational
)(vlc_object_t
*object
,
1216 unsigned *num
, unsigned *den
,
1219 char *str
= var_InheritString(object
, var
);
1224 unsigned n
= strtoul(str
, &sep
, 10);
1229 /* Decimal integer */
1235 /* Decimal fraction */
1236 d
= strtoul(sep
+ 1, &sep
, 10);
1242 /* Decimal number */
1246 while ((c
= *(++sep
)) != '\0') {
1267 } else if (d
== 0) {
1271 vlc_ureduce(num
, den
, n
, d
, 0);
1279 return VLC_EGENERIC
;
1283 * Free a list and the associated strings
1284 * @param p_val: the list variable
1285 * @param p_val2: the variable associated or NULL
1287 void var_FreeList( vlc_value_t
*p_val
, vlc_value_t
*p_val2
)
1289 switch( p_val
->p_list
->i_type
& VLC_VAR_CLASS
)
1291 case VLC_VAR_STRING
:
1292 for( int i
= 0; i
< p_val
->p_list
->i_count
; i
++ )
1293 free( p_val
->p_list
->p_values
[i
].psz_string
);
1297 free( p_val
->p_list
->p_values
);
1298 free( p_val
->p_list
);
1300 if( p_val2
!= NULL
)
1302 assert( p_val2
->p_list
!= NULL
);
1303 assert( p_val2
->p_list
->i_type
== VLC_VAR_STRING
);
1305 for( int i
= 0; i
< p_val2
->p_list
->i_count
; i
++ )
1306 free( p_val2
->p_list
->p_values
[i
].psz_string
);
1307 free( p_val2
->p_list
->p_values
);
1308 free( p_val2
->p_list
);
1312 static void DumpVariable(const void *data
, const VISIT which
, const int depth
)
1314 if (which
!= postorder
&& which
!= leaf
)
1318 const variable_t
*var
= *(const variable_t
**)data
;
1319 const char *typename
= "unknown";
1321 switch (var
->i_type
& VLC_VAR_TYPE
)
1323 case VLC_VAR_VOID
: typename
= "void"; break;
1324 case VLC_VAR_BOOL
: typename
= "bool"; break;
1325 case VLC_VAR_INTEGER
: typename
= "integer"; break;
1326 case VLC_VAR_STRING
: typename
= "string"; break;
1327 case VLC_VAR_FLOAT
: typename
= "float"; break;
1328 case VLC_VAR_COORDS
: typename
= "coordinates"; break;
1329 case VLC_VAR_ADDRESS
: typename
= "address"; break;
1330 default: typename
= "unknown"; break;
1333 printf(" *-o \"%s\" (%s", var
->psz_name
, typename
);
1334 if (var
->psz_text
!= NULL
)
1335 printf(", %s", var
->psz_text
);
1337 if (var
->i_type
& VLC_VAR_HASCHOICE
)
1338 fputs(", has choices", stdout
);
1339 if (var
->i_type
& VLC_VAR_ISCOMMAND
)
1340 fputs(", command", stdout
);
1341 if (var
->value_callbacks
.i_entries
)
1342 printf(", %d callbacks", var
->value_callbacks
.i_entries
);
1344 switch (var
->i_type
& VLC_VAR_CLASS
)
1349 printf(": %s", var
->val
.b_bool
? "true" : "false");
1351 case VLC_VAR_INTEGER
:
1352 printf(": %"PRId64
, var
->val
.i_int
);
1354 case VLC_VAR_STRING
:
1355 printf(": \"%s\"", var
->val
.psz_string
);
1358 printf(": %f", var
->val
.f_float
);
1360 case VLC_VAR_COORDS
:
1361 printf(": %"PRId32
"x%"PRId32
,
1362 var
->val
.coords
.x
, var
->val
.coords
.y
);
1364 case VLC_VAR_ADDRESS
:
1365 printf(": %p", var
->val
.p_address
);
1371 void DumpVariables(vlc_object_t
*obj
)
1373 vlc_mutex_lock(&vlc_internals(obj
)->var_lock
);
1374 if (vlc_internals(obj
)->var_root
== NULL
)
1375 puts(" `-o No variables");
1377 twalk(vlc_internals(obj
)->var_root
, DumpVariable
);
1378 vlc_mutex_unlock(&vlc_internals(obj
)->var_lock
);
1381 static thread_local
void *twalk_ctx
;
1383 static void TwalkGetNames(const void *data
, const VISIT which
, const int depth
)
1385 if (which
!= postorder
&& which
!= leaf
)
1389 const variable_t
*var
= *(const variable_t
**)data
;
1390 DECL_ARRAY(char *) *names
= twalk_ctx
;
1391 char *dup
= strdup(var
->psz_name
);
1393 ARRAY_APPEND(*names
, dup
);
1396 char **var_GetAllNames(vlc_object_t
*obj
)
1398 vlc_object_internals_t
*priv
= vlc_internals(obj
);
1400 DECL_ARRAY(char *) names
;
1404 vlc_mutex_lock(&priv
->var_lock
);
1405 twalk(priv
->var_root
, TwalkGetNames
);
1406 vlc_mutex_unlock(&priv
->var_lock
);
1408 if (names
.i_size
== 0)
1410 ARRAY_APPEND(names
, NULL
);
1411 return names
.p_elems
;