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"
42 /*****************************************************************************
44 *****************************************************************************/
45 struct callback_entry_t
47 vlc_callback_t pf_callback
;
51 /*****************************************************************************
52 * Local comparison functions, returns 0 if v == w, < 0 if v < w, > 0 if v > w
53 *****************************************************************************/
54 static int CmpBool( vlc_value_t v
, vlc_value_t w
)
56 return v
.b_bool
? w
.b_bool
? 0 : 1 : w
.b_bool
? -1 : 0;
59 static int CmpInt( vlc_value_t v
, vlc_value_t w
)
61 return v
.i_int
== w
.i_int
? 0 : v
.i_int
> w
.i_int
? 1 : -1;
64 static int CmpTime( vlc_value_t v
, vlc_value_t w
)
66 return v
.i_time
== w
.i_time
? 0 : v
.i_time
> w
.i_time
? 1 : -1;
69 static int CmpString( vlc_value_t v
, vlc_value_t w
)
72 return !w
.psz_string
? 0 : -1;
74 return !w
.psz_string
? 1 : strcmp( v
.psz_string
, w
.psz_string
);
76 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; }
77 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; }
79 /*****************************************************************************
80 * Local duplication functions, and local deallocation functions
81 *****************************************************************************/
82 static void DupDummy( vlc_value_t
*p_val
) { (void)p_val
; /* unused */ }
83 static void DupString( vlc_value_t
*p_val
)
85 p_val
->psz_string
= strdup( p_val
->psz_string
? p_val
->psz_string
: "" );
88 static void FreeDummy( vlc_value_t
*p_val
) { (void)p_val
; /* unused */ }
89 static void FreeString( vlc_value_t
*p_val
) { free( p_val
->psz_string
); }
90 static void FreeMutex( vlc_value_t
*p_val
) { vlc_mutex_destroy( (vlc_mutex_t
*)p_val
->p_address
); free( p_val
->p_address
); }
92 static void FreeList( vlc_value_t
*p_val
)
95 for( i
= 0; i
< p_val
->p_list
->i_count
; i
++ )
97 switch( p_val
->p_list
->pi_types
[i
] & VLC_VAR_CLASS
)
100 FreeString( &p_val
->p_list
->p_values
[i
] );
103 FreeMutex( &p_val
->p_list
->p_values
[i
] );
110 if( p_val
->p_list
->i_count
)
112 free( p_val
->p_list
->p_values
);
113 free( p_val
->p_list
->pi_types
);
115 free( p_val
->p_list
);
118 static const struct variable_ops_t
119 void_ops
= { NULL
, DupDummy
, FreeDummy
, },
120 addr_ops
= { CmpAddress
, DupDummy
, FreeDummy
, },
121 bool_ops
= { CmpBool
, DupDummy
, FreeDummy
, },
122 float_ops
= { CmpFloat
, DupDummy
, FreeDummy
, },
123 int_ops
= { CmpInt
, DupDummy
, FreeDummy
, },
124 mutex_ops
= { CmpAddress
, DupDummy
, FreeMutex
, },
125 string_ops
= { CmpString
, DupString
, FreeString
, },
126 time_ops
= { CmpTime
, DupDummy
, FreeDummy
, },
127 coords_ops
= { NULL
, DupDummy
, FreeDummy
, };
129 /*****************************************************************************
131 *****************************************************************************/
132 static void WaitUnused ( vlc_object_t
*, variable_t
* );
134 static void CheckValue ( variable_t
*, vlc_value_t
* );
136 static int TriggerCallback( vlc_object_t
*, variable_t
*, const char *,
139 static int varcmp( const void *a
, const void *b
)
141 const variable_t
*va
= a
, *vb
= b
;
143 /* psz_name must be first */
144 assert( va
== (const void *)&va
->psz_name
);
145 return strcmp( va
->psz_name
, vb
->psz_name
);
148 static variable_t
*Lookup( vlc_object_t
*obj
, const char *psz_name
)
150 vlc_object_internals_t
*priv
= vlc_internals( obj
);
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
;
158 static void Destroy( variable_t
*p_var
)
160 p_var
->ops
->pf_free( &p_var
->val
);
161 if( p_var
->choices
.i_count
)
163 for( int i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
165 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
166 free( p_var
->choices_text
.p_values
[i
].psz_string
);
168 free( p_var
->choices
.p_values
);
169 free( p_var
->choices_text
.p_values
);
171 free( p_var
->psz_name
);
172 free( p_var
->psz_text
);
173 free( p_var
->p_entries
);
179 * Initialize a vlc variable
181 * We hash the given string and insert it into the sorted list. The insertion
182 * may require slow memory copies, but think about what we gain in the log(n)
183 * lookup phase when setting/getting the variable value!
185 * \param p_this The object in which to create the variable
186 * \param psz_name The name of the variable
187 * \param i_type The variables type. Must be one of \ref var_type combined with
188 * zero or more \ref var_flags
190 int var_Create( vlc_object_t
*p_this
, const char *psz_name
, int i_type
)
194 variable_t
*p_var
= calloc( 1, sizeof( *p_var
) );
198 p_var
->psz_name
= strdup( psz_name
);
199 p_var
->psz_text
= NULL
;
201 p_var
->i_type
= i_type
& ~VLC_VAR_DOINHERIT
;
205 p_var
->i_default
= -1;
206 p_var
->choices
.i_count
= 0;
207 p_var
->choices
.p_values
= NULL
;
208 p_var
->choices_text
.i_count
= 0;
209 p_var
->choices_text
.p_values
= NULL
;
211 p_var
->b_incallback
= false;
212 p_var
->i_entries
= 0;
213 p_var
->p_entries
= NULL
;
215 /* Always initialize the variable, even if it is a list variable; this
216 * will lead to errors if the variable is not initialized, but it will
217 * not cause crashes in the variable handling. */
218 switch( i_type
& VLC_VAR_CLASS
)
221 p_var
->ops
= &bool_ops
;
222 p_var
->val
.b_bool
= false;
224 case VLC_VAR_INTEGER
:
225 p_var
->ops
= &int_ops
;
226 p_var
->val
.i_int
= 0;
229 p_var
->ops
= &string_ops
;
230 p_var
->val
.psz_string
= NULL
;
233 p_var
->ops
= &float_ops
;
234 p_var
->val
.f_float
= 0.0;
237 p_var
->ops
= &time_ops
;
238 p_var
->val
.i_time
= 0;
241 p_var
->ops
= &coords_ops
;
242 p_var
->val
.coords
.x
= p_var
->val
.coords
.y
= 0;
244 case VLC_VAR_ADDRESS
:
245 p_var
->ops
= &addr_ops
;
246 p_var
->val
.p_address
= NULL
;
249 p_var
->ops
= &mutex_ops
;
250 p_var
->val
.p_address
= malloc( sizeof(vlc_mutex_t
) );
251 vlc_mutex_init( (vlc_mutex_t
*)p_var
->val
.p_address
);
254 p_var
->ops
= &void_ops
;
256 if( (i_type
& VLC_VAR_CLASS
) != VLC_VAR_VOID
)
257 msg_Err( p_this
, "Creating the variable '%s' without a type",
262 if( i_type
& VLC_VAR_DOINHERIT
)
264 if( var_Inherit( p_this
, psz_name
, i_type
, &p_var
->val
) )
265 msg_Err( p_this
, "cannot inherit value for %s", psz_name
);
266 else if( i_type
& VLC_VAR_HASCHOICE
)
268 /* We must add the inherited value to our choice list */
269 p_var
->i_default
= 0;
271 INSERT_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
,
273 INSERT_ELEM( p_var
->choices_text
.p_values
,
274 p_var
->choices_text
.i_count
, 0, p_var
->val
);
275 p_var
->ops
->pf_dup( &p_var
->choices
.p_values
[0] );
276 p_var
->choices_text
.p_values
[0].psz_string
= NULL
;
280 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
281 variable_t
**pp_var
, *p_oldvar
;
282 int ret
= VLC_SUCCESS
;
284 vlc_mutex_lock( &p_priv
->var_lock
);
286 pp_var
= tsearch( p_var
, &p_priv
->var_root
, varcmp
);
287 if( unlikely(pp_var
== NULL
) )
289 else if( (p_oldvar
= *pp_var
) == p_var
)
291 else if( unlikely((i_type
^ p_oldvar
->i_type
) & VLC_VAR_CLASS
) )
292 { /* If the types differ, variable creation failed. */
293 msg_Err( p_this
, "Variable '%s' (0x%04x) already exist "
294 "but with a different type (0x%04x)",
295 psz_name
, p_oldvar
->i_type
, i_type
);
301 p_oldvar
->i_type
|= i_type
& (VLC_VAR_ISCOMMAND
|VLC_VAR_HASCHOICE
);
303 vlc_mutex_unlock( &p_priv
->var_lock
);
305 /* If we did not need to create a new variable, free everything... */
313 * Destroy a vlc variable
315 * Look for the variable and destroy it if it is found. As in var_Create we
316 * do a call to memmove() but we have performance counterparts elsewhere.
318 * \param p_this The object that holds the variable
319 * \param psz_name The name of the variable
321 int var_Destroy( vlc_object_t
*p_this
, const char *psz_name
)
327 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
329 vlc_mutex_lock( &p_priv
->var_lock
);
331 p_var
= Lookup( p_this
, psz_name
);
334 vlc_mutex_unlock( &p_priv
->var_lock
);
338 WaitUnused( p_this
, p_var
);
340 if( --p_var
->i_usage
== 0 )
341 tdelete( p_var
, &p_priv
->var_root
, varcmp
);
344 vlc_mutex_unlock( &p_priv
->var_lock
);
351 static void CleanupVar( void *var
)
356 void var_DestroyAll( vlc_object_t
*obj
)
358 vlc_object_internals_t
*priv
= vlc_internals( obj
);
360 tdestroy( priv
->var_root
, CleanupVar
);
365 * Perform an action on a variable
367 * \param p_this The object that holds the variable
368 * \param psz_name The name of the variable
369 * \param i_action The action to perform. Must be one of \ref var_action
370 * \param p_val First action parameter
371 * \param p_val2 Second action parameter
373 int var_Change( vlc_object_t
*p_this
, const char *psz_name
,
374 int i_action
, vlc_value_t
*p_val
, vlc_value_t
*p_val2
)
383 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
385 vlc_mutex_lock( &p_priv
->var_lock
);
387 p_var
= Lookup( p_this
, psz_name
);
390 vlc_mutex_unlock( &p_priv
->var_lock
);
397 if( p_var
->i_type
& VLC_VAR_HASMIN
)
399 p_var
->ops
->pf_free( &p_var
->min
);
401 p_var
->i_type
|= VLC_VAR_HASMIN
;
403 p_var
->ops
->pf_dup( &p_var
->min
);
404 CheckValue( p_var
, &p_var
->val
);
407 if( p_var
->i_type
& VLC_VAR_HASMIN
)
413 if( p_var
->i_type
& VLC_VAR_HASMAX
)
415 p_var
->ops
->pf_free( &p_var
->max
);
417 p_var
->i_type
|= VLC_VAR_HASMAX
;
419 p_var
->ops
->pf_dup( &p_var
->max
);
420 CheckValue( p_var
, &p_var
->val
);
423 if( p_var
->i_type
& VLC_VAR_HASMAX
)
428 case VLC_VAR_SETSTEP
:
429 if( p_var
->i_type
& VLC_VAR_HASSTEP
)
431 p_var
->ops
->pf_free( &p_var
->step
);
433 p_var
->i_type
|= VLC_VAR_HASSTEP
;
434 p_var
->step
= *p_val
;
435 p_var
->ops
->pf_dup( &p_var
->step
);
436 CheckValue( p_var
, &p_var
->val
);
438 case VLC_VAR_GETSTEP
:
439 if( p_var
->i_type
& VLC_VAR_HASSTEP
)
441 *p_val
= p_var
->step
;
444 case VLC_VAR_ADDCHOICE
:
445 i
= p_var
->choices
.i_count
;
447 INSERT_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
,
449 INSERT_ELEM( p_var
->choices_text
.p_values
,
450 p_var
->choices_text
.i_count
, i
, *p_val
);
451 p_var
->ops
->pf_dup( &p_var
->choices
.p_values
[i
] );
452 p_var
->choices_text
.p_values
[i
].psz_string
=
453 ( p_val2
&& p_val2
->psz_string
) ?
454 strdup( p_val2
->psz_string
) : NULL
;
456 CheckValue( p_var
, &p_var
->val
);
458 case VLC_VAR_DELCHOICE
:
459 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
461 if( p_var
->ops
->pf_cmp( p_var
->choices
.p_values
[i
], *p_val
) == 0 )
467 if( i
== p_var
->choices
.i_count
)
470 vlc_mutex_unlock( &p_priv
->var_lock
);
474 if( p_var
->i_default
> i
)
478 else if( p_var
->i_default
== i
)
480 p_var
->i_default
= -1;
483 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
484 free( p_var
->choices_text
.p_values
[i
].psz_string
);
485 REMOVE_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
, i
);
486 REMOVE_ELEM( p_var
->choices_text
.p_values
,
487 p_var
->choices_text
.i_count
, i
);
489 CheckValue( p_var
, &p_var
->val
);
491 case VLC_VAR_CHOICESCOUNT
:
492 p_val
->i_int
= p_var
->choices
.i_count
;
494 case VLC_VAR_CLEARCHOICES
:
495 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
497 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
499 for( i
= 0 ; i
< p_var
->choices_text
.i_count
; i
++ )
500 free( p_var
->choices_text
.p_values
[i
].psz_string
);
502 if( p_var
->choices
.i_count
) free( p_var
->choices
.p_values
);
503 if( p_var
->choices_text
.i_count
) free( p_var
->choices_text
.p_values
);
505 p_var
->choices
.i_count
= 0;
506 p_var
->choices
.p_values
= NULL
;
507 p_var
->choices_text
.i_count
= 0;
508 p_var
->choices_text
.p_values
= NULL
;
509 p_var
->i_default
= -1;
511 case VLC_VAR_SETDEFAULT
:
512 /* FIXME: the list is sorted, dude. Use something cleverer. */
513 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
515 if( p_var
->ops
->pf_cmp( p_var
->choices
.p_values
[i
], *p_val
) == 0 )
521 if( i
== p_var
->choices
.i_count
)
527 p_var
->i_default
= i
;
528 CheckValue( p_var
, &p_var
->val
);
530 case VLC_VAR_SETVALUE
:
531 /* Duplicate data if needed */
533 p_var
->ops
->pf_dup( &newval
);
534 /* Backup needed stuff */
536 /* Check boundaries and list */
537 CheckValue( p_var
, &newval
);
538 /* Set the variable */
540 /* Free data if needed */
541 p_var
->ops
->pf_free( &oldval
);
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
)
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
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) );
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( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
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
] );
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
;
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
);
582 p_var
->psz_text
= NULL
;
584 case VLC_VAR_GETTEXT
:
585 p_val
->psz_string
= p_var
->psz_text
? strdup( p_var
->psz_text
)
588 case VLC_VAR_SETISCOMMAND
:
589 p_var
->i_type
|= VLC_VAR_ISCOMMAND
;
596 vlc_mutex_unlock( &p_priv
->var_lock
);
603 * Perform a Get and Set on a variable
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
611 int var_GetAndSet( vlc_object_t
*p_this
, const char *psz_name
, int i_action
,
621 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
623 vlc_mutex_lock( &p_priv
->var_lock
);
624 p_var
= Lookup( p_this
, psz_name
);
627 vlc_mutex_unlock( &p_priv
->var_lock
);
631 WaitUnused( p_this
, p_var
);
633 /* Duplicated data if needed */
634 //p_var->ops->pf_dup( &val );
636 /* Backup needed stuff */
639 /* depending of the action requiered */
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
;
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
;
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
;
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
;
659 vlc_mutex_unlock( &p_priv
->var_lock
);
663 /* Check boundaries */
664 CheckValue( p_var
, &p_var
->val
);
667 /* Deal with callbacks.*/
668 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, oldval
);
670 vlc_mutex_unlock( &p_priv
->var_lock
);
677 * Request a variable's type
679 * \return The variable type if it exists, or 0 if the
680 * variable could not be found.
683 int var_Type( vlc_object_t
*p_this
, const char *psz_name
)
690 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
692 vlc_mutex_lock( &p_priv
->var_lock
);
694 p_var
= Lookup( p_this
, psz_name
);
696 i_type
= p_var
->i_type
;
698 vlc_mutex_unlock( &p_priv
->var_lock
);
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
)
707 int i_ret
= VLC_SUCCESS
;
713 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
715 vlc_mutex_lock( &p_priv
->var_lock
);
717 p_var
= Lookup( p_this
, psz_name
);
720 vlc_mutex_unlock( &p_priv
->var_lock
);
724 assert( expected_type
== 0 ||
725 (p_var
->i_type
& VLC_VAR_CLASS
) == expected_type
);
727 /* Alert if the type is VLC_VAR_VOID */
728 if( ( p_var
->i_type
& VLC_VAR_TYPE
) == VLC_VAR_VOID
)
729 msg_Warn( p_this
, "Calling var_Set on the void variable '%s' (0x%04x)", psz_name
, p_var
->i_type
);
733 WaitUnused( p_this
, p_var
);
735 /* Duplicate data if needed */
736 p_var
->ops
->pf_dup( &val
);
738 /* Backup needed stuff */
741 /* Check boundaries and list */
742 CheckValue( p_var
, &val
);
744 /* Set the variable */
747 /* Deal with callbacks */
748 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, oldval
);
750 /* Free data if needed */
751 p_var
->ops
->pf_free( &oldval
);
753 vlc_mutex_unlock( &p_priv
->var_lock
);
760 * Set a variable's value
762 * \param p_this The object that hold the variable
763 * \param psz_name The name of the variable
764 * \param val the value to set
766 int var_Set( vlc_object_t
*p_this
, const char *psz_name
, vlc_value_t val
)
768 return var_SetChecked( p_this
, psz_name
, 0, val
);
771 #undef var_GetChecked
772 int var_GetChecked( vlc_object_t
*p_this
, const char *psz_name
,
773 int expected_type
, vlc_value_t
*p_val
)
777 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
779 int err
= VLC_SUCCESS
;
781 vlc_mutex_lock( &p_priv
->var_lock
);
783 p_var
= Lookup( p_this
, psz_name
);
786 assert( expected_type
== 0 ||
787 (p_var
->i_type
& VLC_VAR_CLASS
) == expected_type
);
789 /* Really get the variable */
793 /* Alert if the type is VLC_VAR_VOID */
794 if( ( p_var
->i_type
& VLC_VAR_TYPE
) == VLC_VAR_VOID
)
795 msg_Warn( p_this
, "Calling var_Get on the void variable '%s' (0x%04x)", psz_name
, p_var
->i_type
);
798 /* Duplicate value if needed */
799 p_var
->ops
->pf_dup( p_val
);
804 vlc_mutex_unlock( &p_priv
->var_lock
);
810 * Get a variable's value
812 * \param p_this The object that holds the variable
813 * \param psz_name The name of the variable
814 * \param p_val Pointer to a vlc_value_t that will hold the variable's value
815 * after the function is finished
817 int var_Get( vlc_object_t
*p_this
, const char *psz_name
, vlc_value_t
*p_val
)
819 return var_GetChecked( p_this
, psz_name
, 0, p_val
);
822 #undef var_AddCallback
824 * Register a callback in a variable
826 * We store a function pointer that will be called upon variable
829 * \param p_this The object that holds the variable
830 * \param psz_name The name of the variable
831 * \param pf_callback The function pointer
832 * \param p_data A generic pointer that will be passed as the last
833 * argument to the callback function.
835 * \warning The callback function is run in the thread that calls var_Set on
836 * the variable. Use proper locking. This thread may not have much
837 * time to spare, so keep callback functions short.
839 int var_AddCallback( vlc_object_t
*p_this
, const char *psz_name
,
840 vlc_callback_t pf_callback
, void *p_data
)
843 callback_entry_t entry
;
847 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
849 entry
.pf_callback
= pf_callback
;
850 entry
.p_data
= p_data
;
852 vlc_mutex_lock( &p_priv
->var_lock
);
854 p_var
= Lookup( p_this
, psz_name
);
858 msg_Warn( p_this
, "Failed to add a callback to the non-existing "
859 "variable '%s'", psz_name
);
861 vlc_mutex_unlock( &p_priv
->var_lock
);
865 WaitUnused( p_this
, p_var
);
866 INSERT_ELEM( p_var
->p_entries
,
871 vlc_mutex_unlock( &p_priv
->var_lock
);
876 #undef var_DelCallback
878 * Remove a callback from a variable
880 * pf_callback and p_data have to be given again, because different objects
881 * might have registered the same callback function.
883 int var_DelCallback( vlc_object_t
*p_this
, const char *psz_name
,
884 vlc_callback_t pf_callback
, void *p_data
)
889 bool b_found_similar
= false;
894 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
896 vlc_mutex_lock( &p_priv
->var_lock
);
898 p_var
= Lookup( p_this
, psz_name
);
901 vlc_mutex_unlock( &p_priv
->var_lock
);
905 WaitUnused( p_this
, p_var
);
907 for( i_entry
= p_var
->i_entries
; i_entry
-- ; )
909 if( p_var
->p_entries
[i_entry
].pf_callback
== pf_callback
910 && p_var
->p_entries
[i_entry
].p_data
== p_data
)
915 else if( p_var
->p_entries
[i_entry
].pf_callback
== pf_callback
)
916 b_found_similar
= true;
923 if( b_found_similar
)
924 fprintf( stderr
, "Calling var_DelCallback for '%s' with the same "
925 "function but not the same data.", psz_name
);
928 vlc_mutex_unlock( &p_priv
->var_lock
);
932 REMOVE_ELEM( p_var
->p_entries
, p_var
->i_entries
, i_entry
);
934 vlc_mutex_unlock( &p_priv
->var_lock
);
939 #undef var_TriggerCallback
941 * Trigger callback on a variable
943 * \param p_this The object that hold the variable
944 * \param psz_name The name of the variable
946 int var_TriggerCallback( vlc_object_t
*p_this
, const char *psz_name
)
953 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
955 vlc_mutex_lock( &p_priv
->var_lock
);
957 p_var
= Lookup( p_this
, psz_name
);
960 vlc_mutex_unlock( &p_priv
->var_lock
);
964 WaitUnused( p_this
, p_var
);
966 /* Deal with callbacks. Tell we're in a callback, release the lock,
967 * call stored functions, retake the lock. */
968 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, p_var
->val
);
970 vlc_mutex_unlock( &p_priv
->var_lock
);
974 /** Parse a stringified option
975 * This function parse a string option and create the associated object
977 * The option must be of the form "[no[-]]foo[=bar]" where foo is the
978 * option name and bar is the value of the option.
979 * \param p_obj the object in which the variable must be created
980 * \param psz_option the option to parse
981 * \param trusted whether the option is set by a trusted input or not
984 void var_OptionParse( vlc_object_t
*p_obj
, const char *psz_option
,
987 char *psz_name
, *psz_value
;
992 val
.psz_string
= NULL
;
994 /* It's too much of a hassle to remove the ':' when we parse
996 if( psz_option
[0] == ':' )
1002 psz_name
= strdup( psz_option
);
1003 if( psz_name
== NULL
)
1006 psz_value
= strchr( psz_name
, '=' );
1007 if( psz_value
!= NULL
)
1008 *psz_value
++ = '\0';
1010 i_type
= config_GetType( p_obj
, psz_name
);
1011 if( !i_type
&& !psz_value
)
1013 /* check for "no-foo" or "nofoo" */
1014 if( !strncmp( psz_name
, "no-", 3 ) )
1016 memmove( psz_name
, psz_name
+ 3, strlen(psz_name
) + 1 - 3 );
1018 else if( !strncmp( psz_name
, "no", 2 ) )
1020 memmove( psz_name
, psz_name
+ 2, strlen(psz_name
) + 1 - 2 );
1022 else goto cleanup
; /* Option doesn't exist */
1025 i_type
= config_GetType( p_obj
, psz_name
);
1027 if( !i_type
) goto cleanup
; /* Option doesn't exist */
1029 if( ( i_type
!= VLC_VAR_BOOL
) &&
1030 ( !psz_value
|| !*psz_value
) ) goto cleanup
; /* Invalid value */
1032 /* check if option is unsafe */
1035 module_config_t
*p_config
= config_FindConfig( p_obj
, psz_name
);
1036 if( !p_config
|| !p_config
->b_safe
)
1038 msg_Err( p_obj
, "unsafe option \"%s\" has been ignored for "
1039 "security reasons", psz_name
);
1045 /* Create the variable in the input object.
1046 * Children of the input object will be able to retreive this value
1047 * thanks to the inheritance property of the object variables. */
1048 var_Create( p_obj
, psz_name
, i_type
);
1053 val
.b_bool
= !b_isno
;
1056 case VLC_VAR_INTEGER
:
1057 val
.i_int
= strtoll( psz_value
, NULL
, 0 );
1061 val
.f_float
= us_atof( psz_value
);
1064 case VLC_VAR_STRING
:
1065 case VLC_VAR_MODULE
:
1067 case VLC_VAR_DIRECTORY
:
1068 val
.psz_string
= psz_value
;
1075 var_Set( p_obj
, psz_name
, val
);
1082 /* Following functions are local */
1085 * Waits until the variable is inactive (i.e. not executing a callback)
1087 static void WaitUnused( vlc_object_t
*p_this
, variable_t
*p_var
)
1089 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
1091 mutex_cleanup_push( &p_priv
->var_lock
);
1092 while( p_var
->b_incallback
)
1093 vlc_cond_wait( &p_priv
->var_wait
, &p_priv
->var_lock
);
1097 /*****************************************************************************
1098 * CheckValue: check that a value is valid wrt. a variable
1099 *****************************************************************************
1100 * This function checks p_val's value against p_var's limitations such as
1101 * minimal and maximal value, step, in-list position, and modifies p_val if
1103 ****************************************************************************/
1104 static void CheckValue ( variable_t
*p_var
, vlc_value_t
*p_val
)
1106 /* Check that our variable is in the list */
1107 if( p_var
->i_type
& VLC_VAR_HASCHOICE
&& p_var
->choices
.i_count
)
1111 /* This list is not sorted so go throug it (this is a small list) */
1112 for( i
= p_var
->choices
.i_count
; i
-- ; )
1114 if( p_var
->ops
->pf_cmp( *p_val
, p_var
->choices
.p_values
[i
] ) == 0 )
1120 /* If not found, change it to anything vaguely valid */
1123 /* Free the old variable, get the new one, dup it */
1124 p_var
->ops
->pf_free( p_val
);
1125 *p_val
= p_var
->choices
.p_values
[p_var
->i_default
>= 0
1126 ? p_var
->i_default
: 0 ];
1127 p_var
->ops
->pf_dup( p_val
);
1131 /* Check that our variable is within the bounds */
1132 switch( p_var
->i_type
& VLC_VAR_TYPE
)
1134 case VLC_VAR_INTEGER
:
1135 if( p_var
->i_type
& VLC_VAR_HASSTEP
&& p_var
->step
.i_int
1136 && (p_val
->i_int
% p_var
->step
.i_int
) )
1138 p_val
->i_int
= (p_val
->i_int
+ (p_var
->step
.i_int
/ 2))
1139 / p_var
->step
.i_int
* p_var
->step
.i_int
;
1141 if( p_var
->i_type
& VLC_VAR_HASMIN
1142 && p_val
->i_int
< p_var
->min
.i_int
)
1144 p_val
->i_int
= p_var
->min
.i_int
;
1146 if( p_var
->i_type
& VLC_VAR_HASMAX
1147 && p_val
->i_int
> p_var
->max
.i_int
)
1149 p_val
->i_int
= p_var
->max
.i_int
;
1153 if( p_var
->i_type
& VLC_VAR_HASSTEP
&& p_var
->step
.f_float
)
1155 float f_round
= p_var
->step
.f_float
* (float)(int)( 0.5 +
1156 p_val
->f_float
/ p_var
->step
.f_float
);
1157 if( p_val
->f_float
!= f_round
)
1159 p_val
->f_float
= f_round
;
1162 if( p_var
->i_type
& VLC_VAR_HASMIN
1163 && p_val
->f_float
< p_var
->min
.f_float
)
1165 p_val
->f_float
= p_var
->min
.f_float
;
1167 if( p_var
->i_type
& VLC_VAR_HASMAX
1168 && p_val
->f_float
> p_var
->max
.f_float
)
1170 p_val
->f_float
= p_var
->max
.f_float
;
1180 * Finds the value of a variable. If the specified object does not hold a
1181 * variable with the specified name, try the parent object, and iterate until
1182 * the top of the tree. If no match is found, the value is read from the
1185 int var_Inherit( vlc_object_t
*p_this
, const char *psz_name
, int i_type
,
1186 vlc_value_t
*p_val
)
1189 if (p_this
!= VLC_OBJECT(p_this
->p_libvlc
)
1190 && unlikely(p_this
->p_parent
== NULL
))
1192 msg_Info (p_this
, "%s(%s) on detached object", __func__
, psz_name
);
1196 i_type
&= VLC_VAR_CLASS
;
1197 for( vlc_object_t
*obj
= p_this
; obj
!= NULL
; obj
= obj
->p_parent
)
1199 if( var_GetChecked( obj
, psz_name
, i_type
, p_val
) == VLC_SUCCESS
)
1202 if (obj
!= p_this
&& obj
!= VLC_OBJECT(p_this
->p_libvlc
)
1203 && unlikely(obj
->p_parent
== NULL
))
1205 msg_Info (p_this
, "%s(%s) on detached tree [%p] %s", __func__
,
1206 psz_name
, obj
, obj
->psz_object_type
);
1212 /* else take value from config */
1213 switch( i_type
& VLC_VAR_CLASS
)
1215 case VLC_VAR_STRING
:
1216 p_val
->psz_string
= config_GetPsz( p_this
, psz_name
);
1217 if( !p_val
->psz_string
) p_val
->psz_string
= strdup("");
1220 p_val
->f_float
= config_GetFloat( p_this
, psz_name
);
1222 case VLC_VAR_INTEGER
:
1223 p_val
->i_int
= config_GetInt( p_this
, psz_name
);
1226 p_val
->b_bool
= config_GetInt( p_this
, psz_name
);
1228 case VLC_VAR_ADDRESS
:
1231 msg_Warn( p_this
, "Could not inherit value for var %s "
1232 "from config. Invalid Type", psz_name
);
1235 /*msg_Dbg( p_this, "Inherited value for var %s from config", psz_name );*/
1241 * It inherits a string as an unsigned rational number (it also accepts basic
1244 * It returns an error if the rational number cannot be parsed (0/0 is valid).
1245 * The rational is already reduced.
1247 int (var_InheritURational
)(vlc_object_t
*object
,
1248 unsigned *num
, unsigned *den
,
1256 char *tmp
= var_InheritString(object
, var
);
1261 unsigned n
= strtol(tmp
, &next
, 0);
1262 unsigned d
= strtol(*next
? &next
[1] : "0", NULL
, 0);
1265 /* Interpret as a float number */
1266 double r
= us_atof(tmp
);
1281 vlc_ureduce(num
, den
, n
, d
, 0);
1288 return VLC_EGENERIC
;
1291 /**********************************************************************
1292 * Trigger the callbacks.
1293 * Tell we're in a callback, release the lock, call stored functions,
1295 **********************************************************************/
1296 static int TriggerCallback( vlc_object_t
*p_this
, variable_t
*p_var
,
1297 const char *psz_name
, vlc_value_t oldval
)
1301 int i_entries
= p_var
->i_entries
;
1302 if( i_entries
== 0 )
1305 callback_entry_t
*p_entries
= p_var
->p_entries
;
1306 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
1308 assert( !p_var
->b_incallback
);
1309 p_var
->b_incallback
= true;
1310 vlc_mutex_unlock( &p_priv
->var_lock
);
1312 /* The real calls */
1313 for( ; i_entries
-- ; )
1315 p_entries
[i_entries
].pf_callback( p_this
, psz_name
, oldval
, p_var
->val
,
1316 p_entries
[i_entries
].p_data
);
1319 vlc_mutex_lock( &p_priv
->var_lock
);
1320 p_var
->b_incallback
= false;
1321 vlc_cond_broadcast( &p_priv
->var_wait
);
1327 /**********************************************************************
1328 * Execute a var command on an object identified by its name
1329 **********************************************************************/
1330 int var_Command( vlc_object_t
*p_this
, const char *psz_name
,
1331 const char *psz_cmd
, const char *psz_arg
, char **psz_msg
)
1333 vlc_object_t
*p_obj
= vlc_object_find_name( p_this
->p_libvlc
,
1334 psz_name
, FIND_CHILD
);
1340 *psz_msg
= strdup( "Unknown destination object." );
1344 i_type
= var_Type( p_obj
, psz_cmd
);
1345 if( !( i_type
&VLC_VAR_ISCOMMAND
) )
1347 vlc_object_release( p_obj
);
1349 *psz_msg
= strdup( "Variable doesn't exist or isn't a command." );
1350 return VLC_EGENERIC
;
1353 i_type
&= VLC_VAR_CLASS
;
1356 case VLC_VAR_INTEGER
:
1357 i_ret
= var_SetInteger( p_obj
, psz_cmd
, atoi( psz_arg
) );
1360 i_ret
= var_SetFloat( p_obj
, psz_cmd
, us_atof( psz_arg
) );
1362 case VLC_VAR_STRING
:
1363 i_ret
= var_SetString( p_obj
, psz_cmd
, psz_arg
);
1366 i_ret
= var_SetBool( p_obj
, psz_cmd
, atoi( psz_arg
) );
1369 i_ret
= VLC_EGENERIC
;
1373 vlc_object_release( p_obj
);
1377 if( asprintf( psz_msg
, "%s on object %s returned %i (%s)",
1378 psz_cmd
, psz_name
, i_ret
, vlc_error( i_ret
) ) == -1)
1387 * Free a list and the associated strings
1388 * @param p_val: the list variable
1389 * @param p_val2: the variable associated or NULL
1391 void var_FreeList( vlc_value_t
*p_val
, vlc_value_t
*p_val2
)
1394 if( p_val2
&& p_val2
->p_list
)
1396 for( int i
= 0; i
< p_val2
->p_list
->i_count
; i
++ )
1397 free( p_val2
->p_list
->p_values
[i
].psz_string
);
1398 if( p_val2
->p_list
->i_count
)
1400 free( p_val2
->p_list
->p_values
);
1401 free( p_val2
->p_list
->pi_types
);
1403 free( p_val2
->p_list
);