1 /*****************************************************************************
2 * variables.c: routines for object variables handling
3 *****************************************************************************
4 * Copyright (C) 2002-2009 the VideoLAN team
7 * Authors: Samuel Hocevar <sam@zoy.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_charset.h>
33 #include "variables.h"
45 /*****************************************************************************
47 *****************************************************************************/
48 struct callback_entry_t
50 vlc_callback_t pf_callback
;
54 /*****************************************************************************
55 * Local comparison functions, returns 0 if v == w, < 0 if v < w, > 0 if v > w
56 *****************************************************************************/
57 static int CmpBool( vlc_value_t v
, vlc_value_t w
)
59 return v
.b_bool
? w
.b_bool
? 0 : 1 : w
.b_bool
? -1 : 0;
62 static int CmpInt( vlc_value_t v
, vlc_value_t w
)
64 return v
.i_int
== w
.i_int
? 0 : v
.i_int
> w
.i_int
? 1 : -1;
67 static int CmpTime( vlc_value_t v
, vlc_value_t w
)
69 return v
.i_time
== w
.i_time
? 0 : v
.i_time
> w
.i_time
? 1 : -1;
72 static int CmpString( vlc_value_t v
, vlc_value_t w
)
75 return !w
.psz_string
? 0 : -1;
77 return !w
.psz_string
? 1 : strcmp( v
.psz_string
, w
.psz_string
);
79 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; }
80 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; }
82 /*****************************************************************************
83 * Local duplication functions, and local deallocation functions
84 *****************************************************************************/
85 static void DupDummy( vlc_value_t
*p_val
) { (void)p_val
; /* unused */ }
86 static void DupString( vlc_value_t
*p_val
)
88 p_val
->psz_string
= strdup( p_val
->psz_string
? p_val
->psz_string
: "" );
91 static void FreeDummy( vlc_value_t
*p_val
) { (void)p_val
; /* unused */ }
92 static void FreeString( vlc_value_t
*p_val
) { free( p_val
->psz_string
); }
93 static void FreeMutex( vlc_value_t
*p_val
) { vlc_mutex_destroy( (vlc_mutex_t
*)p_val
->p_address
); free( p_val
->p_address
); }
95 static void FreeList( vlc_value_t
*p_val
)
98 for( i
= 0; i
< p_val
->p_list
->i_count
; i
++ )
100 switch( p_val
->p_list
->pi_types
[i
] & VLC_VAR_CLASS
)
103 FreeString( &p_val
->p_list
->p_values
[i
] );
106 FreeMutex( &p_val
->p_list
->p_values
[i
] );
113 if( p_val
->p_list
->i_count
)
115 free( p_val
->p_list
->p_values
);
116 free( p_val
->p_list
->pi_types
);
118 free( p_val
->p_list
);
121 static const struct variable_ops_t
122 void_ops
= { NULL
, DupDummy
, FreeDummy
, },
123 addr_ops
= { CmpAddress
, DupDummy
, FreeDummy
, },
124 bool_ops
= { CmpBool
, DupDummy
, FreeDummy
, },
125 float_ops
= { CmpFloat
, DupDummy
, FreeDummy
, },
126 int_ops
= { CmpInt
, DupDummy
, FreeDummy
, },
127 mutex_ops
= { CmpAddress
, DupDummy
, FreeMutex
, },
128 string_ops
= { CmpString
, DupString
, FreeString
, },
129 time_ops
= { CmpTime
, DupDummy
, FreeDummy
, },
130 coords_ops
= { NULL
, DupDummy
, FreeDummy
, };
132 /*****************************************************************************
134 *****************************************************************************/
135 static void WaitUnused ( vlc_object_t
*, variable_t
* );
137 static void CheckValue ( variable_t
*, vlc_value_t
* );
139 static int TriggerCallback( vlc_object_t
*, variable_t
*, const char *,
142 static int varcmp( const void *a
, const void *b
)
144 const variable_t
*va
= a
, *vb
= b
;
146 /* psz_name must be first */
147 assert( va
== (const void *)&va
->psz_name
);
148 return strcmp( va
->psz_name
, vb
->psz_name
);
151 static variable_t
*Lookup( vlc_object_t
*obj
, const char *psz_name
)
153 vlc_object_internals_t
*priv
= vlc_internals( obj
);
156 vlc_assert_locked( &priv
->var_lock
);
157 pp_var
= tfind( &psz_name
, &priv
->var_root
, varcmp
);
158 return (pp_var
!= NULL
) ? *pp_var
: NULL
;
161 static void Destroy( variable_t
*p_var
)
163 p_var
->ops
->pf_free( &p_var
->val
);
164 if( p_var
->choices
.i_count
)
166 for( int i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
168 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
169 free( p_var
->choices_text
.p_values
[i
].psz_string
);
171 free( p_var
->choices
.p_values
);
172 free( p_var
->choices_text
.p_values
);
174 free( p_var
->psz_name
);
175 free( p_var
->psz_text
);
176 free( p_var
->p_entries
);
182 * Initialize a vlc variable
184 * We hash the given string and insert it into the sorted list. The insertion
185 * may require slow memory copies, but think about what we gain in the log(n)
186 * lookup phase when setting/getting the variable value!
188 * \param p_this The object in which to create the variable
189 * \param psz_name The name of the variable
190 * \param i_type The variables type. Must be one of \ref var_type combined with
191 * zero or more \ref var_flags
193 int var_Create( vlc_object_t
*p_this
, const char *psz_name
, int i_type
)
197 variable_t
*p_var
= calloc( 1, sizeof( *p_var
) );
201 p_var
->psz_name
= strdup( psz_name
);
202 p_var
->psz_text
= NULL
;
204 p_var
->i_type
= i_type
& ~VLC_VAR_DOINHERIT
;
208 p_var
->i_default
= -1;
209 p_var
->choices
.i_count
= 0;
210 p_var
->choices
.p_values
= NULL
;
211 p_var
->choices_text
.i_count
= 0;
212 p_var
->choices_text
.p_values
= NULL
;
214 p_var
->b_incallback
= false;
215 p_var
->i_entries
= 0;
216 p_var
->p_entries
= NULL
;
218 /* Always initialize the variable, even if it is a list variable; this
219 * will lead to errors if the variable is not initialized, but it will
220 * not cause crashes in the variable handling. */
221 switch( i_type
& VLC_VAR_CLASS
)
224 p_var
->ops
= &bool_ops
;
225 p_var
->val
.b_bool
= false;
227 case VLC_VAR_INTEGER
:
228 p_var
->ops
= &int_ops
;
229 p_var
->val
.i_int
= 0;
232 p_var
->ops
= &string_ops
;
233 p_var
->val
.psz_string
= NULL
;
236 p_var
->ops
= &float_ops
;
237 p_var
->val
.f_float
= 0.0;
240 p_var
->ops
= &time_ops
;
241 p_var
->val
.i_time
= 0;
244 p_var
->ops
= &coords_ops
;
245 p_var
->val
.coords
.x
= p_var
->val
.coords
.y
= 0;
247 case VLC_VAR_ADDRESS
:
248 p_var
->ops
= &addr_ops
;
249 p_var
->val
.p_address
= NULL
;
252 p_var
->ops
= &mutex_ops
;
253 p_var
->val
.p_address
= malloc( sizeof(vlc_mutex_t
) );
254 vlc_mutex_init( (vlc_mutex_t
*)p_var
->val
.p_address
);
257 p_var
->ops
= &void_ops
;
259 if( (i_type
& VLC_VAR_CLASS
) != VLC_VAR_VOID
)
260 msg_Err( p_this
, "Creating the variable '%s' without a type",
265 if( i_type
& VLC_VAR_DOINHERIT
)
267 if( var_Inherit( p_this
, psz_name
, i_type
, &p_var
->val
) )
268 msg_Err( p_this
, "cannot inherit value for %s", psz_name
);
269 else if( i_type
& VLC_VAR_HASCHOICE
)
271 /* We must add the inherited value to our choice list */
272 p_var
->i_default
= 0;
274 INSERT_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
,
276 INSERT_ELEM( p_var
->choices_text
.p_values
,
277 p_var
->choices_text
.i_count
, 0, p_var
->val
);
278 p_var
->ops
->pf_dup( &p_var
->choices
.p_values
[0] );
279 p_var
->choices_text
.p_values
[0].psz_string
= NULL
;
283 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
284 variable_t
**pp_var
, *p_oldvar
;
285 int ret
= VLC_SUCCESS
;
287 vlc_mutex_lock( &p_priv
->var_lock
);
289 pp_var
= tsearch( p_var
, &p_priv
->var_root
, varcmp
);
290 if( unlikely(pp_var
== NULL
) )
292 else if( (p_oldvar
= *pp_var
) == p_var
)
294 else if( unlikely((i_type
^ p_oldvar
->i_type
) & VLC_VAR_CLASS
) )
295 { /* If the types differ, variable creation failed. */
296 msg_Err( p_this
, "Variable '%s' (0x%04x) already exist "
297 "but with a different type (0x%04x)",
298 psz_name
, p_oldvar
->i_type
, i_type
);
304 p_oldvar
->i_type
|= i_type
& (VLC_VAR_ISCOMMAND
|VLC_VAR_HASCHOICE
);
306 vlc_mutex_unlock( &p_priv
->var_lock
);
308 /* If we did not need to create a new variable, free everything... */
316 * Destroy a vlc variable
318 * Look for the variable and destroy it if it is found. As in var_Create we
319 * do a call to memmove() but we have performance counterparts elsewhere.
321 * \param p_this The object that holds the variable
322 * \param psz_name The name of the variable
324 int var_Destroy( vlc_object_t
*p_this
, const char *psz_name
)
330 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
332 vlc_mutex_lock( &p_priv
->var_lock
);
334 p_var
= Lookup( p_this
, psz_name
);
337 vlc_mutex_unlock( &p_priv
->var_lock
);
341 WaitUnused( p_this
, p_var
);
343 if( --p_var
->i_usage
== 0 )
344 tdelete( p_var
, &p_priv
->var_root
, varcmp
);
347 vlc_mutex_unlock( &p_priv
->var_lock
);
354 static void CleanupVar( void *var
)
359 void var_DestroyAll( vlc_object_t
*obj
)
361 vlc_object_internals_t
*priv
= vlc_internals( obj
);
363 tdestroy( priv
->var_root
, CleanupVar
);
364 priv
->var_root
= NULL
;
369 * Perform an action on a variable
371 * \param p_this The object that holds the variable
372 * \param psz_name The name of the variable
373 * \param i_action The action to perform. Must be one of \ref var_action
374 * \param p_val First action parameter
375 * \param p_val2 Second action parameter
377 int var_Change( vlc_object_t
*p_this
, const char *psz_name
,
378 int i_action
, vlc_value_t
*p_val
, vlc_value_t
*p_val2
)
387 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
389 vlc_mutex_lock( &p_priv
->var_lock
);
391 p_var
= Lookup( p_this
, psz_name
);
394 vlc_mutex_unlock( &p_priv
->var_lock
);
401 if( p_var
->i_type
& VLC_VAR_HASMIN
)
403 p_var
->ops
->pf_free( &p_var
->min
);
405 p_var
->i_type
|= VLC_VAR_HASMIN
;
407 p_var
->ops
->pf_dup( &p_var
->min
);
408 CheckValue( p_var
, &p_var
->val
);
411 if( p_var
->i_type
& VLC_VAR_HASMIN
)
417 if( p_var
->i_type
& VLC_VAR_HASMAX
)
419 p_var
->ops
->pf_free( &p_var
->max
);
421 p_var
->i_type
|= VLC_VAR_HASMAX
;
423 p_var
->ops
->pf_dup( &p_var
->max
);
424 CheckValue( p_var
, &p_var
->val
);
427 if( p_var
->i_type
& VLC_VAR_HASMAX
)
432 case VLC_VAR_SETSTEP
:
433 if( p_var
->i_type
& VLC_VAR_HASSTEP
)
435 p_var
->ops
->pf_free( &p_var
->step
);
437 p_var
->i_type
|= VLC_VAR_HASSTEP
;
438 p_var
->step
= *p_val
;
439 p_var
->ops
->pf_dup( &p_var
->step
);
440 CheckValue( p_var
, &p_var
->val
);
442 case VLC_VAR_GETSTEP
:
443 if( p_var
->i_type
& VLC_VAR_HASSTEP
)
445 *p_val
= p_var
->step
;
448 case VLC_VAR_ADDCHOICE
:
449 i
= p_var
->choices
.i_count
;
451 INSERT_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
,
453 INSERT_ELEM( p_var
->choices_text
.p_values
,
454 p_var
->choices_text
.i_count
, i
, *p_val
);
455 p_var
->ops
->pf_dup( &p_var
->choices
.p_values
[i
] );
456 p_var
->choices_text
.p_values
[i
].psz_string
=
457 ( p_val2
&& p_val2
->psz_string
) ?
458 strdup( p_val2
->psz_string
) : NULL
;
460 CheckValue( p_var
, &p_var
->val
);
462 case VLC_VAR_DELCHOICE
:
463 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
465 if( p_var
->ops
->pf_cmp( p_var
->choices
.p_values
[i
], *p_val
) == 0 )
471 if( i
== p_var
->choices
.i_count
)
474 vlc_mutex_unlock( &p_priv
->var_lock
);
478 if( p_var
->i_default
> i
)
482 else if( p_var
->i_default
== i
)
484 p_var
->i_default
= -1;
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
);
493 CheckValue( p_var
, &p_var
->val
);
495 case VLC_VAR_CHOICESCOUNT
:
496 p_val
->i_int
= p_var
->choices
.i_count
;
498 case VLC_VAR_CLEARCHOICES
:
499 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
501 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
503 for( i
= 0 ; i
< p_var
->choices_text
.i_count
; i
++ )
504 free( p_var
->choices_text
.p_values
[i
].psz_string
);
506 if( p_var
->choices
.i_count
) free( p_var
->choices
.p_values
);
507 if( p_var
->choices_text
.i_count
) free( p_var
->choices_text
.p_values
);
509 p_var
->choices
.i_count
= 0;
510 p_var
->choices
.p_values
= NULL
;
511 p_var
->choices_text
.i_count
= 0;
512 p_var
->choices_text
.p_values
= NULL
;
513 p_var
->i_default
= -1;
515 case VLC_VAR_SETDEFAULT
:
516 /* FIXME: the list is sorted, dude. Use something cleverer. */
517 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 )
525 if( i
== p_var
->choices
.i_count
)
531 p_var
->i_default
= i
;
532 CheckValue( p_var
, &p_var
->val
);
534 case VLC_VAR_SETVALUE
:
535 /* Duplicate data if needed */
537 p_var
->ops
->pf_dup( &newval
);
538 /* Backup needed stuff */
540 /* Check boundaries and list */
541 CheckValue( p_var
, &newval
);
542 /* Set the variable */
544 /* Free data if needed */
545 p_var
->ops
->pf_free( &oldval
);
547 case VLC_VAR_GETCHOICES
:
548 case VLC_VAR_GETLIST
:
549 p_val
->p_list
= malloc( sizeof(vlc_list_t
) );
550 if( p_val2
) p_val2
->p_list
= malloc( sizeof(vlc_list_t
) );
551 if( p_var
->choices
.i_count
)
553 p_val
->p_list
->p_values
= malloc( p_var
->choices
.i_count
554 * sizeof(vlc_value_t
) );
555 p_val
->p_list
->pi_types
= malloc( p_var
->choices
.i_count
559 p_val2
->p_list
->p_values
=
560 malloc( p_var
->choices
.i_count
* sizeof(vlc_value_t
) );
561 p_val2
->p_list
->pi_types
=
562 malloc( p_var
->choices
.i_count
* sizeof(int) );
565 p_val
->p_list
->i_count
= p_var
->choices
.i_count
;
566 if( p_val2
) p_val2
->p_list
->i_count
= p_var
->choices
.i_count
;
567 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
569 p_val
->p_list
->p_values
[i
] = p_var
->choices
.p_values
[i
];
570 p_val
->p_list
->pi_types
[i
] = p_var
->i_type
;
571 p_var
->ops
->pf_dup( &p_val
->p_list
->p_values
[i
] );
574 p_val2
->p_list
->p_values
[i
].psz_string
=
575 p_var
->choices_text
.p_values
[i
].psz_string
?
576 strdup(p_var
->choices_text
.p_values
[i
].psz_string
) : NULL
;
577 p_val2
->p_list
->pi_types
[i
] = VLC_VAR_STRING
;
581 case VLC_VAR_SETTEXT
:
582 free( p_var
->psz_text
);
583 if( p_val
&& p_val
->psz_string
)
584 p_var
->psz_text
= strdup( p_val
->psz_string
);
586 p_var
->psz_text
= NULL
;
588 case VLC_VAR_GETTEXT
:
589 p_val
->psz_string
= p_var
->psz_text
? strdup( p_var
->psz_text
)
592 case VLC_VAR_SETISCOMMAND
:
593 p_var
->i_type
|= VLC_VAR_ISCOMMAND
;
600 vlc_mutex_unlock( &p_priv
->var_lock
);
607 * Perform a Get and Set on a variable
609 * \param p_this: The object that hold the variable
610 * \param psz_name: the name of the variable
611 * \param i_action: the action to perform
612 * \param p_val: The action parameter
613 * \return vlc error codes
615 int var_GetAndSet( vlc_object_t
*p_this
, const char *psz_name
, int i_action
,
625 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
627 vlc_mutex_lock( &p_priv
->var_lock
);
628 p_var
= Lookup( p_this
, psz_name
);
631 vlc_mutex_unlock( &p_priv
->var_lock
);
635 WaitUnused( p_this
, p_var
);
637 /* Duplicated data if needed */
638 //p_var->ops->pf_dup( &val );
640 /* Backup needed stuff */
643 /* depending of the action requiered */
646 case VLC_VAR_BOOL_TOGGLE
:
647 assert( ( p_var
->i_type
& VLC_VAR_BOOL
) == VLC_VAR_BOOL
);
648 p_var
->val
.b_bool
= !p_var
->val
.b_bool
;
650 case VLC_VAR_INTEGER_ADD
:
651 assert( ( p_var
->i_type
& VLC_VAR_INTEGER
) == VLC_VAR_INTEGER
);
652 p_var
->val
.i_int
+= p_val
->i_int
;
654 case VLC_VAR_INTEGER_OR
:
655 assert( ( p_var
->i_type
& VLC_VAR_INTEGER
) == VLC_VAR_INTEGER
);
656 p_var
->val
.i_int
|= p_val
->i_int
;
658 case VLC_VAR_INTEGER_NAND
:
659 assert( ( p_var
->i_type
& VLC_VAR_INTEGER
) == VLC_VAR_INTEGER
);
660 p_var
->val
.i_int
&= ~p_val
->i_int
;
663 vlc_mutex_unlock( &p_priv
->var_lock
);
667 /* Check boundaries */
668 CheckValue( p_var
, &p_var
->val
);
671 /* Deal with callbacks.*/
672 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, oldval
);
674 vlc_mutex_unlock( &p_priv
->var_lock
);
681 * Request a variable's type
683 * \return The variable type if it exists, or 0 if the
684 * variable could not be found.
687 int var_Type( vlc_object_t
*p_this
, const char *psz_name
)
694 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
696 vlc_mutex_lock( &p_priv
->var_lock
);
698 p_var
= Lookup( p_this
, psz_name
);
700 i_type
= p_var
->i_type
;
702 vlc_mutex_unlock( &p_priv
->var_lock
);
707 #undef var_SetChecked
708 int var_SetChecked( vlc_object_t
*p_this
, const char *psz_name
,
709 int expected_type
, vlc_value_t val
)
711 int i_ret
= VLC_SUCCESS
;
717 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
719 vlc_mutex_lock( &p_priv
->var_lock
);
721 p_var
= Lookup( p_this
, psz_name
);
724 vlc_mutex_unlock( &p_priv
->var_lock
);
728 assert( expected_type
== 0 ||
729 (p_var
->i_type
& VLC_VAR_CLASS
) == expected_type
);
731 /* Alert if the type is VLC_VAR_VOID */
732 if( ( p_var
->i_type
& VLC_VAR_TYPE
) == VLC_VAR_VOID
)
733 msg_Warn( p_this
, "Calling var_Set on the void variable '%s' (0x%04x)", psz_name
, p_var
->i_type
);
737 WaitUnused( p_this
, p_var
);
739 /* Duplicate data if needed */
740 p_var
->ops
->pf_dup( &val
);
742 /* Backup needed stuff */
745 /* Check boundaries and list */
746 CheckValue( p_var
, &val
);
748 /* Set the variable */
751 /* Deal with callbacks */
752 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, oldval
);
754 /* Free data if needed */
755 p_var
->ops
->pf_free( &oldval
);
757 vlc_mutex_unlock( &p_priv
->var_lock
);
764 * Set a variable's value
766 * \param p_this The object that hold the variable
767 * \param psz_name The name of the variable
768 * \param val the value to set
770 int var_Set( vlc_object_t
*p_this
, const char *psz_name
, vlc_value_t val
)
772 return var_SetChecked( p_this
, psz_name
, 0, val
);
775 #undef var_GetChecked
776 int var_GetChecked( vlc_object_t
*p_this
, const char *psz_name
,
777 int expected_type
, vlc_value_t
*p_val
)
781 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
783 int err
= VLC_SUCCESS
;
785 vlc_mutex_lock( &p_priv
->var_lock
);
787 p_var
= Lookup( p_this
, psz_name
);
790 assert( expected_type
== 0 ||
791 (p_var
->i_type
& VLC_VAR_CLASS
) == expected_type
);
793 /* Really get the variable */
797 /* Alert if the type is VLC_VAR_VOID */
798 if( ( p_var
->i_type
& VLC_VAR_TYPE
) == VLC_VAR_VOID
)
799 msg_Warn( p_this
, "Calling var_Get on the void variable '%s' (0x%04x)", psz_name
, p_var
->i_type
);
802 /* Duplicate value if needed */
803 p_var
->ops
->pf_dup( p_val
);
808 vlc_mutex_unlock( &p_priv
->var_lock
);
814 * Get a variable's value
816 * \param p_this The object that holds the variable
817 * \param psz_name The name of the variable
818 * \param p_val Pointer to a vlc_value_t that will hold the variable's value
819 * after the function is finished
821 int var_Get( vlc_object_t
*p_this
, const char *psz_name
, vlc_value_t
*p_val
)
823 return var_GetChecked( p_this
, psz_name
, 0, p_val
);
826 #undef var_AddCallback
828 * Register a callback in a variable
830 * We store a function pointer that will be called upon variable
833 * \param p_this The object that holds the variable
834 * \param psz_name The name of the variable
835 * \param pf_callback The function pointer
836 * \param p_data A generic pointer that will be passed as the last
837 * argument to the callback function.
839 * \warning The callback function is run in the thread that calls var_Set on
840 * the variable. Use proper locking. This thread may not have much
841 * time to spare, so keep callback functions short.
843 int var_AddCallback( vlc_object_t
*p_this
, const char *psz_name
,
844 vlc_callback_t pf_callback
, void *p_data
)
847 callback_entry_t entry
;
851 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
853 entry
.pf_callback
= pf_callback
;
854 entry
.p_data
= p_data
;
856 vlc_mutex_lock( &p_priv
->var_lock
);
858 p_var
= Lookup( p_this
, psz_name
);
862 msg_Warn( p_this
, "Failed to add a callback to the non-existing "
863 "variable '%s'", psz_name
);
865 vlc_mutex_unlock( &p_priv
->var_lock
);
869 WaitUnused( p_this
, p_var
);
870 INSERT_ELEM( p_var
->p_entries
,
875 vlc_mutex_unlock( &p_priv
->var_lock
);
880 #undef var_DelCallback
882 * Remove a callback from a variable
884 * pf_callback and p_data have to be given again, because different objects
885 * might have registered the same callback function.
887 int var_DelCallback( vlc_object_t
*p_this
, const char *psz_name
,
888 vlc_callback_t pf_callback
, void *p_data
)
893 bool b_found_similar
= false;
898 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
900 vlc_mutex_lock( &p_priv
->var_lock
);
902 p_var
= Lookup( p_this
, psz_name
);
905 vlc_mutex_unlock( &p_priv
->var_lock
);
909 WaitUnused( p_this
, p_var
);
911 for( i_entry
= p_var
->i_entries
; i_entry
-- ; )
913 if( p_var
->p_entries
[i_entry
].pf_callback
== pf_callback
914 && p_var
->p_entries
[i_entry
].p_data
== p_data
)
919 else if( p_var
->p_entries
[i_entry
].pf_callback
== pf_callback
)
920 b_found_similar
= true;
927 if( b_found_similar
)
928 fprintf( stderr
, "Calling var_DelCallback for '%s' with the same "
929 "function but not the same data.", psz_name
);
932 vlc_mutex_unlock( &p_priv
->var_lock
);
936 REMOVE_ELEM( p_var
->p_entries
, p_var
->i_entries
, i_entry
);
938 vlc_mutex_unlock( &p_priv
->var_lock
);
943 #undef var_TriggerCallback
945 * Trigger callback on a variable
947 * \param p_this The object that hold the variable
948 * \param psz_name The name of the variable
950 int var_TriggerCallback( vlc_object_t
*p_this
, const char *psz_name
)
957 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
959 vlc_mutex_lock( &p_priv
->var_lock
);
961 p_var
= Lookup( p_this
, psz_name
);
964 vlc_mutex_unlock( &p_priv
->var_lock
);
968 WaitUnused( p_this
, p_var
);
970 /* Deal with callbacks. Tell we're in a callback, release the lock,
971 * call stored functions, retake the lock. */
972 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, p_var
->val
);
974 vlc_mutex_unlock( &p_priv
->var_lock
);
978 /** Parse a stringified option
979 * This function parse a string option and create the associated object
981 * The option must be of the form "[no[-]]foo[=bar]" where foo is the
982 * option name and bar is the value of the option.
983 * \param p_obj the object in which the variable must be created
984 * \param psz_option the option to parse
985 * \param trusted whether the option is set by a trusted input or not
988 void var_OptionParse( vlc_object_t
*p_obj
, const char *psz_option
,
991 char *psz_name
, *psz_value
;
996 val
.psz_string
= NULL
;
998 /* It's too much of a hassle to remove the ':' when we parse
1000 if( psz_option
[0] == ':' )
1003 if( !psz_option
[0] )
1006 psz_name
= strdup( psz_option
);
1007 if( psz_name
== NULL
)
1010 psz_value
= strchr( psz_name
, '=' );
1011 if( psz_value
!= NULL
)
1012 *psz_value
++ = '\0';
1014 i_type
= config_GetType( p_obj
, psz_name
);
1015 if( !i_type
&& !psz_value
)
1017 /* check for "no-foo" or "nofoo" */
1018 if( !strncmp( psz_name
, "no-", 3 ) )
1020 memmove( psz_name
, psz_name
+ 3, strlen(psz_name
) + 1 - 3 );
1022 else if( !strncmp( psz_name
, "no", 2 ) )
1024 memmove( psz_name
, psz_name
+ 2, strlen(psz_name
) + 1 - 2 );
1026 else goto cleanup
; /* Option doesn't exist */
1029 i_type
= config_GetType( p_obj
, psz_name
);
1031 if( !i_type
) goto cleanup
; /* Option doesn't exist */
1033 if( ( i_type
!= VLC_VAR_BOOL
) &&
1034 ( !psz_value
|| !*psz_value
) ) goto cleanup
; /* Invalid value */
1036 /* check if option is unsafe */
1039 module_config_t
*p_config
= config_FindConfig( p_obj
, psz_name
);
1040 if( !p_config
|| !p_config
->b_safe
)
1042 msg_Err( p_obj
, "unsafe option \"%s\" has been ignored for "
1043 "security reasons", psz_name
);
1049 /* Create the variable in the input object.
1050 * Children of the input object will be able to retreive this value
1051 * thanks to the inheritance property of the object variables. */
1052 var_Create( p_obj
, psz_name
, i_type
);
1057 val
.b_bool
= !b_isno
;
1060 case VLC_VAR_INTEGER
:
1061 val
.i_int
= strtoll( psz_value
, NULL
, 0 );
1065 val
.f_float
= us_atof( psz_value
);
1068 case VLC_VAR_STRING
:
1069 val
.psz_string
= psz_value
;
1076 var_Set( p_obj
, psz_name
, val
);
1083 /* Following functions are local */
1086 * Waits until the variable is inactive (i.e. not executing a callback)
1088 static void WaitUnused( vlc_object_t
*p_this
, variable_t
*p_var
)
1090 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
1092 mutex_cleanup_push( &p_priv
->var_lock
);
1093 while( p_var
->b_incallback
)
1094 vlc_cond_wait( &p_priv
->var_wait
, &p_priv
->var_lock
);
1098 /*****************************************************************************
1099 * CheckValue: check that a value is valid wrt. a variable
1100 *****************************************************************************
1101 * This function checks p_val's value against p_var's limitations such as
1102 * minimal and maximal value, step, in-list position, and modifies p_val if
1104 ****************************************************************************/
1105 static void CheckValue ( variable_t
*p_var
, vlc_value_t
*p_val
)
1107 /* Check that our variable is in the list */
1108 if( p_var
->i_type
& VLC_VAR_HASCHOICE
&& p_var
->choices
.i_count
)
1112 /* This list is not sorted so go throug it (this is a small list) */
1113 for( i
= p_var
->choices
.i_count
; i
-- ; )
1115 if( p_var
->ops
->pf_cmp( *p_val
, p_var
->choices
.p_values
[i
] ) == 0 )
1121 /* If not found, change it to anything vaguely valid */
1124 /* Free the old variable, get the new one, dup it */
1125 p_var
->ops
->pf_free( p_val
);
1126 *p_val
= p_var
->choices
.p_values
[p_var
->i_default
>= 0
1127 ? p_var
->i_default
: 0 ];
1128 p_var
->ops
->pf_dup( p_val
);
1132 /* Check that our variable is within the bounds */
1133 switch( p_var
->i_type
& VLC_VAR_TYPE
)
1135 case VLC_VAR_INTEGER
:
1136 if( p_var
->i_type
& VLC_VAR_HASSTEP
&& p_var
->step
.i_int
1137 && (p_val
->i_int
% p_var
->step
.i_int
) )
1139 p_val
->i_int
= (p_val
->i_int
+ (p_var
->step
.i_int
/ 2))
1140 / p_var
->step
.i_int
* p_var
->step
.i_int
;
1142 if( p_var
->i_type
& VLC_VAR_HASMIN
1143 && p_val
->i_int
< p_var
->min
.i_int
)
1145 p_val
->i_int
= p_var
->min
.i_int
;
1147 if( p_var
->i_type
& VLC_VAR_HASMAX
1148 && p_val
->i_int
> p_var
->max
.i_int
)
1150 p_val
->i_int
= p_var
->max
.i_int
;
1154 if( p_var
->i_type
& VLC_VAR_HASSTEP
&& p_var
->step
.f_float
)
1156 float f_round
= p_var
->step
.f_float
* (float)(int)( 0.5 +
1157 p_val
->f_float
/ p_var
->step
.f_float
);
1158 if( p_val
->f_float
!= f_round
)
1160 p_val
->f_float
= f_round
;
1163 if( p_var
->i_type
& VLC_VAR_HASMIN
1164 && p_val
->f_float
< p_var
->min
.f_float
)
1166 p_val
->f_float
= p_var
->min
.f_float
;
1168 if( p_var
->i_type
& VLC_VAR_HASMAX
1169 && p_val
->f_float
> p_var
->max
.f_float
)
1171 p_val
->f_float
= p_var
->max
.f_float
;
1181 * Finds the value of a variable. If the specified object does not hold a
1182 * variable with the specified name, try the parent object, and iterate until
1183 * the top of the tree. If no match is found, the value is read from the
1186 int var_Inherit( vlc_object_t
*p_this
, const char *psz_name
, int i_type
,
1187 vlc_value_t
*p_val
)
1190 if (p_this
!= VLC_OBJECT(p_this
->p_libvlc
)
1191 && unlikely(p_this
->p_parent
== NULL
))
1193 msg_Info (p_this
, "%s(%s) on detached object", __func__
, psz_name
);
1197 i_type
&= VLC_VAR_CLASS
;
1198 for( vlc_object_t
*obj
= p_this
; obj
!= NULL
; obj
= obj
->p_parent
)
1200 if( var_GetChecked( obj
, psz_name
, i_type
, p_val
) == VLC_SUCCESS
)
1203 if (obj
!= p_this
&& obj
!= VLC_OBJECT(p_this
->p_libvlc
)
1204 && unlikely(obj
->p_parent
== NULL
))
1206 msg_Info (p_this
, "%s(%s) on detached tree [%p] %s", __func__
,
1207 psz_name
, obj
, obj
->psz_object_type
);
1213 /* else take value from config */
1214 switch( i_type
& VLC_VAR_CLASS
)
1216 case VLC_VAR_STRING
:
1217 p_val
->psz_string
= config_GetPsz( p_this
, psz_name
);
1218 if( !p_val
->psz_string
) p_val
->psz_string
= strdup("");
1221 p_val
->f_float
= config_GetFloat( p_this
, psz_name
);
1223 case VLC_VAR_INTEGER
:
1224 p_val
->i_int
= config_GetInt( p_this
, psz_name
);
1227 p_val
->b_bool
= config_GetInt( p_this
, psz_name
);
1229 case VLC_VAR_ADDRESS
:
1232 msg_Warn( p_this
, "Could not inherit value for var %s "
1233 "from config. Invalid Type", psz_name
);
1236 /*msg_Dbg( p_this, "Inherited value for var %s from config", psz_name );*/
1242 * It inherits a string as an unsigned rational number (it also accepts basic
1245 * It returns an error if the rational number cannot be parsed (0/0 is valid).
1246 * The rational is already reduced.
1248 int (var_InheritURational
)(vlc_object_t
*object
,
1249 unsigned *num
, unsigned *den
,
1257 char *tmp
= var_InheritString(object
, var
);
1262 unsigned n
= strtol(tmp
, &next
, 0);
1263 unsigned d
= strtol(*next
? &next
[1] : "0", NULL
, 0);
1266 /* Interpret as a float number */
1267 double r
= us_atof(tmp
);
1282 vlc_ureduce(num
, den
, n
, d
, 0);
1289 return VLC_EGENERIC
;
1292 /**********************************************************************
1293 * Trigger the callbacks.
1294 * Tell we're in a callback, release the lock, call stored functions,
1296 **********************************************************************/
1297 static int TriggerCallback( vlc_object_t
*p_this
, variable_t
*p_var
,
1298 const char *psz_name
, vlc_value_t oldval
)
1302 int i_entries
= p_var
->i_entries
;
1303 if( i_entries
== 0 )
1306 callback_entry_t
*p_entries
= p_var
->p_entries
;
1307 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
1309 assert( !p_var
->b_incallback
);
1310 p_var
->b_incallback
= true;
1311 vlc_mutex_unlock( &p_priv
->var_lock
);
1313 /* The real calls */
1314 for( ; i_entries
-- ; )
1316 p_entries
[i_entries
].pf_callback( p_this
, psz_name
, oldval
, p_var
->val
,
1317 p_entries
[i_entries
].p_data
);
1320 vlc_mutex_lock( &p_priv
->var_lock
);
1321 p_var
->b_incallback
= false;
1322 vlc_cond_broadcast( &p_priv
->var_wait
);
1328 /**********************************************************************
1329 * Execute a var command on an object identified by its name
1330 **********************************************************************/
1331 int var_Command( vlc_object_t
*p_this
, const char *psz_name
,
1332 const char *psz_cmd
, const char *psz_arg
, char **psz_msg
)
1334 vlc_object_t
*p_obj
= vlc_object_find_name( p_this
->p_libvlc
,
1335 psz_name
, FIND_CHILD
);
1341 *psz_msg
= strdup( "Unknown destination object." );
1345 i_type
= var_Type( p_obj
, psz_cmd
);
1346 if( !( i_type
&VLC_VAR_ISCOMMAND
) )
1348 vlc_object_release( p_obj
);
1350 *psz_msg
= strdup( "Variable doesn't exist or isn't a command." );
1351 return VLC_EGENERIC
;
1354 i_type
&= VLC_VAR_CLASS
;
1357 case VLC_VAR_INTEGER
:
1358 i_ret
= var_SetInteger( p_obj
, psz_cmd
, atoi( psz_arg
) );
1361 i_ret
= var_SetFloat( p_obj
, psz_cmd
, us_atof( psz_arg
) );
1363 case VLC_VAR_STRING
:
1364 i_ret
= var_SetString( p_obj
, psz_cmd
, psz_arg
);
1367 i_ret
= var_SetBool( p_obj
, psz_cmd
, atoi( psz_arg
) );
1370 i_ret
= VLC_EGENERIC
;
1374 vlc_object_release( p_obj
);
1378 if( asprintf( psz_msg
, "%s on object %s returned %i (%s)",
1379 psz_cmd
, psz_name
, i_ret
, vlc_error( i_ret
) ) == -1)
1388 * Free a list and the associated strings
1389 * @param p_val: the list variable
1390 * @param p_val2: the variable associated or NULL
1392 void var_FreeList( vlc_value_t
*p_val
, vlc_value_t
*p_val2
)
1395 if( p_val2
&& p_val2
->p_list
)
1397 for( int i
= 0; i
< p_val2
->p_list
->i_count
; i
++ )
1398 free( p_val2
->p_list
->p_values
[i
].psz_string
);
1399 if( p_val2
->p_list
->i_count
)
1401 free( p_val2
->p_list
->p_values
);
1402 free( p_val2
->p_list
->pi_types
);
1404 free( p_val2
->p_list
);