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"
40 /*****************************************************************************
42 *****************************************************************************/
43 struct callback_entry_t
45 vlc_callback_t pf_callback
;
49 /*****************************************************************************
50 * Local comparison functions, returns 0 if v == w, < 0 if v < w, > 0 if v > w
51 *****************************************************************************/
52 static int CmpBool( vlc_value_t v
, vlc_value_t w
) { return v
.b_bool
? w
.b_bool
? 0 : 1 : w
.b_bool
? -1 : 0; }
53 static int CmpInt( vlc_value_t v
, vlc_value_t w
) { return v
.i_int
== w
.i_int
? 0 : v
.i_int
> w
.i_int
? 1 : -1; }
54 static int CmpTime( vlc_value_t v
, vlc_value_t w
)
56 return v
.i_time
== w
.i_time
? 0 : v
.i_time
> w
.i_time
? 1 : -1;
58 static int CmpString( vlc_value_t v
, vlc_value_t w
)
61 return !w
.psz_string
? 0 : -1;
63 return !w
.psz_string
? 1 : strcmp( v
.psz_string
, w
.psz_string
);
65 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; }
66 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; }
68 /*****************************************************************************
69 * Local duplication functions, and local deallocation functions
70 *****************************************************************************/
71 static void DupDummy( vlc_value_t
*p_val
) { (void)p_val
; /* unused */ }
72 static void DupString( vlc_value_t
*p_val
)
74 p_val
->psz_string
= strdup( p_val
->psz_string
? p_val
->psz_string
: "" );
77 static void DupList( vlc_value_t
*p_val
)
80 vlc_list_t
*p_list
= malloc( sizeof(vlc_list_t
) );
82 p_list
->i_count
= p_val
->p_list
->i_count
;
83 if( p_val
->p_list
->i_count
)
85 p_list
->p_values
= malloc( p_list
->i_count
* sizeof(vlc_value_t
) );
86 p_list
->pi_types
= malloc( p_list
->i_count
* sizeof(int) );
90 p_list
->p_values
= NULL
;
91 p_list
->pi_types
= NULL
;
94 for( i
= 0; i
< p_list
->i_count
; i
++ )
96 p_list
->p_values
[i
] = p_val
->p_list
->p_values
[i
];
97 p_list
->pi_types
[i
] = p_val
->p_list
->pi_types
[i
];
98 switch( p_val
->p_list
->pi_types
[i
] & VLC_VAR_CLASS
)
102 DupString( &p_list
->p_values
[i
] );
109 p_val
->p_list
= p_list
;
112 static void FreeDummy( vlc_value_t
*p_val
) { (void)p_val
; /* unused */ }
113 static void FreeString( vlc_value_t
*p_val
) { free( p_val
->psz_string
); }
114 static void FreeMutex( vlc_value_t
*p_val
) { vlc_mutex_destroy( (vlc_mutex_t
*)p_val
->p_address
); free( p_val
->p_address
); }
116 static void FreeList( vlc_value_t
*p_val
)
119 for( i
= 0; i
< p_val
->p_list
->i_count
; i
++ )
121 switch( p_val
->p_list
->pi_types
[i
] & VLC_VAR_CLASS
)
124 FreeString( &p_val
->p_list
->p_values
[i
] );
127 FreeMutex( &p_val
->p_list
->p_values
[i
] );
134 if( p_val
->p_list
->i_count
)
136 free( p_val
->p_list
->p_values
);
137 free( p_val
->p_list
->pi_types
);
139 free( p_val
->p_list
);
142 static const struct variable_ops_t
143 void_ops
= { NULL
, DupDummy
, FreeDummy
, },
144 addr_ops
= { CmpAddress
, DupDummy
, FreeDummy
, },
145 bool_ops
= { CmpBool
, DupDummy
, FreeDummy
, },
146 float_ops
= { CmpFloat
, DupDummy
, FreeDummy
, },
147 int_ops
= { CmpInt
, DupDummy
, FreeDummy
, },
148 list_ops
= { CmpAddress
, DupList
, FreeList
, },
149 mutex_ops
= { CmpAddress
, DupDummy
, FreeMutex
, },
150 string_ops
= { CmpString
, DupString
, FreeString
, },
151 time_ops
= { CmpTime
, DupDummy
, FreeDummy
, };
153 /*****************************************************************************
155 *****************************************************************************/
156 static void WaitUnused ( vlc_object_t
*, variable_t
* );
158 static void CheckValue ( variable_t
*, vlc_value_t
* );
160 static int TriggerCallback( vlc_object_t
*, variable_t
*, const char *,
163 static int varcmp( const void *a
, const void *b
)
165 const variable_t
*va
= a
, *vb
= b
;
167 /* psz_name must be first */
168 assert( va
== (const void *)&va
->psz_name
);
169 return strcmp( va
->psz_name
, vb
->psz_name
);
172 static variable_t
*Lookup( vlc_object_t
*obj
, const char *psz_name
)
174 vlc_object_internals_t
*priv
= vlc_internals( obj
);
177 vlc_assert_locked( &priv
->var_lock
);
178 pp_var
= tfind( &psz_name
, &priv
->var_root
, varcmp
);
179 return (pp_var
!= NULL
) ? *pp_var
: NULL
;
182 static void Destroy( variable_t
*p_var
)
184 p_var
->ops
->pf_free( &p_var
->val
);
185 if( p_var
->choices
.i_count
)
187 for( int i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
189 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
190 free( p_var
->choices_text
.p_values
[i
].psz_string
);
192 free( p_var
->choices
.p_values
);
193 free( p_var
->choices_text
.p_values
);
195 free( p_var
->psz_name
);
196 free( p_var
->psz_text
);
197 free( p_var
->p_entries
);
202 * Initialize a vlc variable
204 * We hash the given string and insert it into the sorted list. The insertion
205 * may require slow memory copies, but think about what we gain in the log(n)
206 * lookup phase when setting/getting the variable value!
208 * \param p_this The object in which to create the variable
209 * \param psz_name The name of the variable
210 * \param i_type The variables type. Must be one of \ref var_type combined with
211 * zero or more \ref var_flags
213 int __var_Create( vlc_object_t
*p_this
, const char *psz_name
, int i_type
)
215 static vlc_list_t dummy_null_list
= {0, NULL
, NULL
};
218 variable_t
*p_var
= calloc( 1, sizeof( *p_var
) );
222 p_var
->psz_name
= strdup( psz_name
);
223 p_var
->psz_text
= NULL
;
225 p_var
->i_type
= i_type
& ~VLC_VAR_DOINHERIT
;
229 p_var
->i_default
= -1;
230 p_var
->choices
.i_count
= 0;
231 p_var
->choices
.p_values
= NULL
;
232 p_var
->choices_text
.i_count
= 0;
233 p_var
->choices_text
.p_values
= NULL
;
235 p_var
->b_incallback
= false;
236 p_var
->i_entries
= 0;
237 p_var
->p_entries
= NULL
;
239 /* Always initialize the variable, even if it is a list variable; this
240 * will lead to errors if the variable is not initialized, but it will
241 * not cause crashes in the variable handling. */
242 switch( i_type
& VLC_VAR_CLASS
)
245 p_var
->ops
= &bool_ops
;
246 p_var
->val
.b_bool
= false;
248 case VLC_VAR_INTEGER
:
249 p_var
->ops
= &int_ops
;
250 p_var
->val
.i_int
= 0;
253 p_var
->ops
= &string_ops
;
254 p_var
->val
.psz_string
= NULL
;
257 p_var
->ops
= &float_ops
;
258 p_var
->val
.f_float
= 0.0;
261 p_var
->ops
= &time_ops
;
262 p_var
->val
.i_time
= 0;
264 case VLC_VAR_ADDRESS
:
265 p_var
->ops
= &addr_ops
;
266 p_var
->val
.p_address
= NULL
;
269 p_var
->ops
= &mutex_ops
;
270 p_var
->val
.p_address
= malloc( sizeof(vlc_mutex_t
) );
271 vlc_mutex_init( (vlc_mutex_t
*)p_var
->val
.p_address
);
274 p_var
->ops
= &list_ops
;
275 p_var
->val
.p_list
= &dummy_null_list
;
278 p_var
->ops
= &void_ops
;
282 if( i_type
& VLC_VAR_DOINHERIT
)
284 if( var_Inherit( p_this
, psz_name
, i_type
, &p_var
->val
) )
285 msg_Err( p_this
, "cannot inherit value for %s", psz_name
);
286 else if( i_type
& VLC_VAR_HASCHOICE
)
288 /* We must add the inherited value to our choice list */
289 p_var
->i_default
= 0;
291 INSERT_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
,
293 INSERT_ELEM( p_var
->choices_text
.p_values
,
294 p_var
->choices_text
.i_count
, 0, p_var
->val
);
295 p_var
->ops
->pf_dup( &p_var
->choices
.p_values
[0] );
296 p_var
->choices_text
.p_values
[0].psz_string
= NULL
;
300 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
301 variable_t
**pp_var
, *p_oldvar
;
302 int ret
= VLC_SUCCESS
;
304 vlc_mutex_lock( &p_priv
->var_lock
);
306 pp_var
= tsearch( p_var
, &p_priv
->var_root
, varcmp
);
307 if( unlikely(pp_var
== NULL
) )
309 else if( (p_oldvar
= *pp_var
) == p_var
)
311 else if( unlikely((i_type
^ p_oldvar
->i_type
) & VLC_VAR_CLASS
) )
312 { /* If the types differ, variable creation failed. */
313 msg_Err( p_this
, "Variable '%s' (0x%04x) already exist "
314 "but with a different type (0x%04x)",
315 psz_name
, p_oldvar
->i_type
, i_type
);
321 p_oldvar
->i_type
|= i_type
& (VLC_VAR_ISCOMMAND
|VLC_VAR_HASCHOICE
);
323 vlc_mutex_unlock( &p_priv
->var_lock
);
325 /* If we did not need to create a new variable, free everything... */
332 * Destroy a vlc variable
334 * Look for the variable and destroy it if it is found. As in var_Create we
335 * do a call to memmove() but we have performance counterparts elsewhere.
337 * \param p_this The object that holds the variable
338 * \param psz_name The name of the variable
340 int __var_Destroy( vlc_object_t
*p_this
, const char *psz_name
)
346 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
348 vlc_mutex_lock( &p_priv
->var_lock
);
350 p_var
= Lookup( p_this
, psz_name
);
353 vlc_mutex_unlock( &p_priv
->var_lock
);
357 WaitUnused( p_this
, p_var
);
359 if( --p_var
->i_usage
== 0 )
360 tdelete( p_var
, &p_priv
->var_root
, varcmp
);
363 vlc_mutex_unlock( &p_priv
->var_lock
);
370 static void CleanupVar( void *var
)
375 void var_DestroyAll( vlc_object_t
*obj
)
377 vlc_object_internals_t
*priv
= vlc_internals( obj
);
379 tdestroy( priv
->var_root
, CleanupVar
);
383 * Perform an action on a variable
385 * \param p_this The object that holds the variable
386 * \param psz_name The name of the variable
387 * \param i_action The action to perform. Must be one of \ref var_action
388 * \param p_val First action parameter
389 * \param p_val2 Second action parameter
391 int __var_Change( vlc_object_t
*p_this
, const char *psz_name
,
392 int i_action
, vlc_value_t
*p_val
, vlc_value_t
*p_val2
)
401 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
403 vlc_mutex_lock( &p_priv
->var_lock
);
405 p_var
= Lookup( p_this
, psz_name
);
408 vlc_mutex_unlock( &p_priv
->var_lock
);
415 if( p_var
->i_type
& VLC_VAR_HASMIN
)
417 p_var
->ops
->pf_free( &p_var
->min
);
419 p_var
->i_type
|= VLC_VAR_HASMIN
;
421 p_var
->ops
->pf_dup( &p_var
->min
);
422 CheckValue( p_var
, &p_var
->val
);
425 if( p_var
->i_type
& VLC_VAR_HASMIN
)
431 if( p_var
->i_type
& VLC_VAR_HASMAX
)
433 p_var
->ops
->pf_free( &p_var
->max
);
435 p_var
->i_type
|= VLC_VAR_HASMAX
;
437 p_var
->ops
->pf_dup( &p_var
->max
);
438 CheckValue( p_var
, &p_var
->val
);
441 if( p_var
->i_type
& VLC_VAR_HASMAX
)
446 case VLC_VAR_SETSTEP
:
447 if( p_var
->i_type
& VLC_VAR_HASSTEP
)
449 p_var
->ops
->pf_free( &p_var
->step
);
451 p_var
->i_type
|= VLC_VAR_HASSTEP
;
452 p_var
->step
= *p_val
;
453 p_var
->ops
->pf_dup( &p_var
->step
);
454 CheckValue( p_var
, &p_var
->val
);
456 case VLC_VAR_GETSTEP
:
457 if( p_var
->i_type
& VLC_VAR_HASSTEP
)
459 *p_val
= p_var
->step
;
462 case VLC_VAR_ADDCHOICE
:
463 i
= p_var
->choices
.i_count
;
465 INSERT_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
,
467 INSERT_ELEM( p_var
->choices_text
.p_values
,
468 p_var
->choices_text
.i_count
, i
, *p_val
);
469 p_var
->ops
->pf_dup( &p_var
->choices
.p_values
[i
] );
470 p_var
->choices_text
.p_values
[i
].psz_string
=
471 ( p_val2
&& p_val2
->psz_string
) ?
472 strdup( p_val2
->psz_string
) : NULL
;
474 CheckValue( p_var
, &p_var
->val
);
476 case VLC_VAR_DELCHOICE
:
477 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
479 if( p_var
->ops
->pf_cmp( p_var
->choices
.p_values
[i
], *p_val
) == 0 )
485 if( i
== p_var
->choices
.i_count
)
488 vlc_mutex_unlock( &p_priv
->var_lock
);
492 if( p_var
->i_default
> i
)
496 else if( p_var
->i_default
== i
)
498 p_var
->i_default
= -1;
501 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
502 free( p_var
->choices_text
.p_values
[i
].psz_string
);
503 REMOVE_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
, i
);
504 REMOVE_ELEM( p_var
->choices_text
.p_values
,
505 p_var
->choices_text
.i_count
, i
);
507 CheckValue( p_var
, &p_var
->val
);
509 case VLC_VAR_CHOICESCOUNT
:
510 p_val
->i_int
= p_var
->choices
.i_count
;
512 case VLC_VAR_CLEARCHOICES
:
513 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
515 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
517 for( i
= 0 ; i
< p_var
->choices_text
.i_count
; i
++ )
518 free( p_var
->choices_text
.p_values
[i
].psz_string
);
520 if( p_var
->choices
.i_count
) free( p_var
->choices
.p_values
);
521 if( p_var
->choices_text
.i_count
) free( p_var
->choices_text
.p_values
);
523 p_var
->choices
.i_count
= 0;
524 p_var
->choices
.p_values
= NULL
;
525 p_var
->choices_text
.i_count
= 0;
526 p_var
->choices_text
.p_values
= NULL
;
527 p_var
->i_default
= -1;
529 case VLC_VAR_SETDEFAULT
:
530 /* FIXME: the list is sorted, dude. Use something cleverer. */
531 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
533 if( p_var
->ops
->pf_cmp( p_var
->choices
.p_values
[i
], *p_val
) == 0 )
539 if( i
== p_var
->choices
.i_count
)
545 p_var
->i_default
= i
;
546 CheckValue( p_var
, &p_var
->val
);
548 case VLC_VAR_SETVALUE
:
549 /* Duplicate data if needed */
551 p_var
->ops
->pf_dup( &newval
);
552 /* Backup needed stuff */
554 /* Check boundaries and list */
555 CheckValue( p_var
, &newval
);
556 /* Set the variable */
558 /* Free data if needed */
559 p_var
->ops
->pf_free( &oldval
);
561 case VLC_VAR_GETCHOICES
:
562 case VLC_VAR_GETLIST
:
563 p_val
->p_list
= malloc( sizeof(vlc_list_t
) );
564 if( p_val2
) p_val2
->p_list
= malloc( sizeof(vlc_list_t
) );
565 if( p_var
->choices
.i_count
)
567 p_val
->p_list
->p_values
= malloc( p_var
->choices
.i_count
568 * sizeof(vlc_value_t
) );
569 p_val
->p_list
->pi_types
= malloc( p_var
->choices
.i_count
573 p_val2
->p_list
->p_values
=
574 malloc( p_var
->choices
.i_count
* sizeof(vlc_value_t
) );
575 p_val2
->p_list
->pi_types
=
576 malloc( p_var
->choices
.i_count
* sizeof(int) );
579 p_val
->p_list
->i_count
= p_var
->choices
.i_count
;
580 if( p_val2
) p_val2
->p_list
->i_count
= p_var
->choices
.i_count
;
581 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
583 p_val
->p_list
->p_values
[i
] = p_var
->choices
.p_values
[i
];
584 p_val
->p_list
->pi_types
[i
] = p_var
->i_type
;
585 p_var
->ops
->pf_dup( &p_val
->p_list
->p_values
[i
] );
588 p_val2
->p_list
->p_values
[i
].psz_string
=
589 p_var
->choices_text
.p_values
[i
].psz_string
?
590 strdup(p_var
->choices_text
.p_values
[i
].psz_string
) : NULL
;
591 p_val2
->p_list
->pi_types
[i
] = VLC_VAR_STRING
;
595 case VLC_VAR_SETTEXT
:
596 free( p_var
->psz_text
);
597 if( p_val
&& p_val
->psz_string
)
598 p_var
->psz_text
= strdup( p_val
->psz_string
);
600 p_var
->psz_text
= NULL
;
602 case VLC_VAR_GETTEXT
:
603 p_val
->psz_string
= p_var
->psz_text
? strdup( p_var
->psz_text
)
606 case VLC_VAR_SETISCOMMAND
:
607 p_var
->i_type
|= VLC_VAR_ISCOMMAND
;
614 vlc_mutex_unlock( &p_priv
->var_lock
);
621 * Perform a Get and Set on a variable
623 * \param p_this: The object that hold the variable
624 * \param psz_name: the name of the variable
625 * \param i_action: the action to perform
626 * \param p_val: The action parameter
627 * \return vlc error codes
629 int __var_GetAndSet( vlc_object_t
*p_this
, const char *psz_name
, int i_action
,
638 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
640 vlc_mutex_lock( &p_priv
->var_lock
);
641 p_var
= Lookup( p_this
, psz_name
);
644 vlc_mutex_unlock( &p_priv
->var_lock
);
648 WaitUnused( p_this
, p_var
);
650 /* Duplicated data if needed */
651 //p_var->ops->pf_dup( &val );
653 /* Backup needed stuff */
656 /* depending of the action requiered */
659 case VLC_VAR_TOGGLE_BOOL
:
660 assert( ( p_var
->i_type
& VLC_VAR_BOOL
) == VLC_VAR_BOOL
);
661 p_var
->val
.b_bool
= !p_var
->val
.b_bool
;
663 case VLC_VAR_INTEGER_INCDEC
:
664 assert( ( p_var
->i_type
& VLC_VAR_INTEGER
) == VLC_VAR_INTEGER
);
665 p_var
->val
.i_int
+= val
.i_int
;
668 vlc_mutex_unlock( &p_priv
->var_lock
);
672 /* Check boundaries */
673 CheckValue( p_var
, &p_var
->val
);
675 /* Deal with callbacks.*/
676 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, oldval
);
678 vlc_mutex_unlock( &p_priv
->var_lock
);
685 * Request a variable's type
687 * \return The variable type if it exists, or 0 if the
688 * variable could not be found.
691 int __var_Type( vlc_object_t
*p_this
, const char *psz_name
)
698 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
700 vlc_mutex_lock( &p_priv
->var_lock
);
702 p_var
= Lookup( p_this
, psz_name
);
704 i_type
= p_var
->i_type
;
706 vlc_mutex_unlock( &p_priv
->var_lock
);
711 int var_SetChecked( vlc_object_t
*p_this
, const char *psz_name
,
712 int expected_type
, vlc_value_t val
)
714 int i_ret
= VLC_SUCCESS
;
720 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
722 vlc_mutex_lock( &p_priv
->var_lock
);
724 p_var
= Lookup( p_this
, psz_name
);
727 vlc_mutex_unlock( &p_priv
->var_lock
);
731 assert( expected_type
== 0 ||
732 (p_var
->i_type
& VLC_VAR_CLASS
) == expected_type
);
734 WaitUnused( p_this
, p_var
);
736 /* Duplicate data if needed */
737 p_var
->ops
->pf_dup( &val
);
739 /* Backup needed stuff */
742 /* Check boundaries and list */
743 CheckValue( p_var
, &val
);
745 /* Set the variable */
748 /* Deal with callbacks */
749 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, oldval
);
751 /* Free data if needed */
752 p_var
->ops
->pf_free( &oldval
);
754 vlc_mutex_unlock( &p_priv
->var_lock
);
761 * Set a variable's value
763 * \param p_this The object that hold the variable
764 * \param psz_name The name of the variable
765 * \param val the value to set
767 int __var_Set( vlc_object_t
*p_this
, const char *psz_name
, vlc_value_t val
)
769 return var_SetChecked( p_this
, psz_name
, 0, val
);
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_GetVoid 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
);
809 * Get a variable's value
811 * \param p_this The object that holds the variable
812 * \param psz_name The name of the variable
813 * \param p_val Pointer to a vlc_value_t that will hold the variable's value
814 * after the function is finished
816 int __var_Get( vlc_object_t
*p_this
, const char *psz_name
, vlc_value_t
*p_val
)
818 return var_GetChecked( p_this
, psz_name
, 0, p_val
);
822 * Register a callback in a variable
824 * We store a function pointer that will be called upon variable
827 * \param p_this The object that holds the variable
828 * \param psz_name The name of the variable
829 * \param pf_callback The function pointer
830 * \param p_data A generic pointer that will be passed as the last
831 * argument to the callback function.
833 * \warning The callback function is run in the thread that calls var_Set on
834 * the variable. Use proper locking. This thread may not have much
835 * time to spare, so keep callback functions short.
837 int __var_AddCallback( vlc_object_t
*p_this
, const char *psz_name
,
838 vlc_callback_t pf_callback
, void *p_data
)
841 callback_entry_t entry
;
845 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
847 entry
.pf_callback
= pf_callback
;
848 entry
.p_data
= p_data
;
850 vlc_mutex_lock( &p_priv
->var_lock
);
852 p_var
= Lookup( p_this
, psz_name
);
856 msg_Warn( p_this
, "Failed to add a callback to the non-existing "
857 "variable '%s'", psz_name
);
859 vlc_mutex_unlock( &p_priv
->var_lock
);
863 WaitUnused( p_this
, p_var
);
864 INSERT_ELEM( p_var
->p_entries
,
869 vlc_mutex_unlock( &p_priv
->var_lock
);
875 * Remove a callback from a variable
877 * pf_callback and p_data have to be given again, because different objects
878 * might have registered the same callback function.
880 int __var_DelCallback( vlc_object_t
*p_this
, const char *psz_name
,
881 vlc_callback_t pf_callback
, void *p_data
)
886 bool b_found_similar
= false;
891 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
893 vlc_mutex_lock( &p_priv
->var_lock
);
895 p_var
= Lookup( p_this
, psz_name
);
898 vlc_mutex_unlock( &p_priv
->var_lock
);
902 WaitUnused( p_this
, p_var
);
904 for( i_entry
= p_var
->i_entries
; i_entry
-- ; )
906 if( p_var
->p_entries
[i_entry
].pf_callback
== pf_callback
907 && p_var
->p_entries
[i_entry
].p_data
== p_data
)
912 else if( p_var
->p_entries
[i_entry
].pf_callback
== pf_callback
)
913 b_found_similar
= true;
920 if( b_found_similar
)
921 fprintf( stderr
, "Calling var_DelCallback for '%s' with the same "
922 "function but not the same data.", psz_name
);
925 vlc_mutex_unlock( &p_priv
->var_lock
);
929 REMOVE_ELEM( p_var
->p_entries
, p_var
->i_entries
, i_entry
);
931 vlc_mutex_unlock( &p_priv
->var_lock
);
937 * Trigger callback on a variable
939 * \param p_this The object that hold the variable
940 * \param psz_name The name of the variable
942 int __var_TriggerCallback( vlc_object_t
*p_this
, const char *psz_name
)
949 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
951 vlc_mutex_lock( &p_priv
->var_lock
);
953 p_var
= Lookup( p_this
, psz_name
);
956 vlc_mutex_unlock( &p_priv
->var_lock
);
960 WaitUnused( p_this
, p_var
);
962 /* Deal with callbacks. Tell we're in a callback, release the lock,
963 * call stored functions, retake the lock. */
964 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, p_var
->val
);
966 vlc_mutex_unlock( &p_priv
->var_lock
);
970 /** Parse a stringified option
971 * This function parse a string option and create the associated object
973 * The option must be of the form "[no[-]]foo[=bar]" where foo is the
974 * option name and bar is the value of the option.
975 * \param p_obj the object in which the variable must be created
976 * \param psz_option the option to parse
977 * \param trusted whether the option is set by a trusted input or not
980 void var_OptionParse( vlc_object_t
*p_obj
, const char *psz_option
,
983 char *psz_name
, *psz_value
;
988 val
.psz_string
= NULL
;
990 /* It's too much of a hassle to remove the ':' when we parse
992 if( psz_option
[0] == ':' )
998 psz_name
= strdup( psz_option
);
999 if( psz_name
== NULL
)
1002 psz_value
= strchr( psz_name
, '=' );
1003 if( psz_value
!= NULL
)
1004 *psz_value
++ = '\0';
1006 /* FIXME: :programs should be handled generically */
1007 if( !strcmp( psz_name
, "programs" ) )
1008 i_type
= VLC_VAR_LIST
;
1010 i_type
= config_GetType( p_obj
, psz_name
);
1012 if( !i_type
&& !psz_value
)
1014 /* check for "no-foo" or "nofoo" */
1015 if( !strncmp( psz_name
, "no-", 3 ) )
1017 memmove( psz_name
, psz_name
+ 3, strlen(psz_name
) + 1 - 3 );
1019 else if( !strncmp( psz_name
, "no", 2 ) )
1021 memmove( psz_name
, psz_name
+ 2, strlen(psz_name
) + 1 - 2 );
1023 else goto cleanup
; /* Option doesn't exist */
1026 i_type
= config_GetType( p_obj
, psz_name
);
1028 if( !i_type
) goto cleanup
; /* Option doesn't exist */
1030 if( ( i_type
!= VLC_VAR_BOOL
) &&
1031 ( !psz_value
|| !*psz_value
) ) goto cleanup
; /* Invalid value */
1033 /* check if option is unsafe */
1036 module_config_t
*p_config
= config_FindConfig( p_obj
, psz_name
);
1037 if( !p_config
|| !p_config
->b_safe
)
1039 msg_Err( p_obj
, "unsafe option \"%s\" has been ignored for "
1040 "security reasons", psz_name
);
1046 /* Create the variable in the input object.
1047 * Children of the input object will be able to retreive this value
1048 * thanks to the inheritance property of the object variables. */
1049 __var_Create( p_obj
, psz_name
, i_type
);
1054 val
.b_bool
= !b_isno
;
1057 case VLC_VAR_INTEGER
:
1058 val
.i_int
= strtol( psz_value
, NULL
, 0 );
1062 val
.f_float
= us_atof( psz_value
);
1065 case VLC_VAR_STRING
:
1066 case VLC_VAR_MODULE
:
1068 case VLC_VAR_DIRECTORY
:
1069 val
.psz_string
= psz_value
;
1074 char *psz_orig
, *psz_var
;
1075 vlc_list_t
*p_list
= malloc(sizeof(vlc_list_t
));
1076 val
.p_list
= p_list
;
1077 p_list
->i_count
= 0;
1079 psz_var
= psz_orig
= strdup(psz_value
);
1080 while( psz_var
&& *psz_var
)
1082 char *psz_item
= psz_var
;
1084 while( *psz_var
&& *psz_var
!= ',' ) psz_var
++;
1085 if( *psz_var
== ',' )
1090 val2
.i_int
= strtol( psz_item
, NULL
, 0 );
1091 INSERT_ELEM( p_list
->p_values
, p_list
->i_count
,
1092 p_list
->i_count
, val2
);
1093 /* p_list->i_count is incremented twice by INSERT_ELEM */
1095 INSERT_ELEM( p_list
->pi_types
, p_list
->i_count
,
1096 p_list
->i_count
, VLC_VAR_INTEGER
);
1106 __var_Set( p_obj
, psz_name
, val
);
1108 /* If that's a list, remove all elements allocated */
1109 if( i_type
== VLC_VAR_LIST
)
1117 /* Following functions are local */
1120 * Waits until the variable is inactive (i.e. not executing a callback)
1122 static void WaitUnused( vlc_object_t
*p_this
, variable_t
*p_var
)
1124 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
1126 mutex_cleanup_push( &p_priv
->var_lock
);
1127 while( p_var
->b_incallback
)
1128 vlc_cond_wait( &p_priv
->var_wait
, &p_priv
->var_lock
);
1132 /*****************************************************************************
1133 * CheckValue: check that a value is valid wrt. a variable
1134 *****************************************************************************
1135 * This function checks p_val's value against p_var's limitations such as
1136 * minimal and maximal value, step, in-list position, and modifies p_val if
1138 ****************************************************************************/
1139 static void CheckValue ( variable_t
*p_var
, vlc_value_t
*p_val
)
1141 /* Check that our variable is in the list */
1142 if( p_var
->i_type
& VLC_VAR_HASCHOICE
&& p_var
->choices
.i_count
)
1146 /* This list is not sorted so go throug it (this is a small list) */
1147 for( i
= p_var
->choices
.i_count
; i
-- ; )
1149 if( p_var
->ops
->pf_cmp( *p_val
, p_var
->choices
.p_values
[i
] ) == 0 )
1155 /* If not found, change it to anything vaguely valid */
1158 /* Free the old variable, get the new one, dup it */
1159 p_var
->ops
->pf_free( p_val
);
1160 *p_val
= p_var
->choices
.p_values
[p_var
->i_default
>= 0
1161 ? p_var
->i_default
: 0 ];
1162 p_var
->ops
->pf_dup( p_val
);
1166 /* Check that our variable is within the bounds */
1167 switch( p_var
->i_type
& VLC_VAR_TYPE
)
1169 case VLC_VAR_INTEGER
:
1170 if( p_var
->i_type
& VLC_VAR_HASSTEP
&& p_var
->step
.i_int
1171 && (p_val
->i_int
% p_var
->step
.i_int
) )
1173 p_val
->i_int
= (p_val
->i_int
+ (p_var
->step
.i_int
/ 2))
1174 / p_var
->step
.i_int
* p_var
->step
.i_int
;
1176 if( p_var
->i_type
& VLC_VAR_HASMIN
1177 && p_val
->i_int
< p_var
->min
.i_int
)
1179 p_val
->i_int
= p_var
->min
.i_int
;
1181 if( p_var
->i_type
& VLC_VAR_HASMAX
1182 && p_val
->i_int
> p_var
->max
.i_int
)
1184 p_val
->i_int
= p_var
->max
.i_int
;
1188 if( p_var
->i_type
& VLC_VAR_HASSTEP
&& p_var
->step
.f_float
)
1190 float f_round
= p_var
->step
.f_float
* (float)(int)( 0.5 +
1191 p_val
->f_float
/ p_var
->step
.f_float
);
1192 if( p_val
->f_float
!= f_round
)
1194 p_val
->f_float
= f_round
;
1197 if( p_var
->i_type
& VLC_VAR_HASMIN
1198 && p_val
->f_float
< p_var
->min
.f_float
)
1200 p_val
->f_float
= p_var
->min
.f_float
;
1202 if( p_var
->i_type
& VLC_VAR_HASMAX
1203 && p_val
->f_float
> p_var
->max
.f_float
)
1205 p_val
->f_float
= p_var
->max
.f_float
;
1215 * Finds the value of a variable. If the specified object does not hold a
1216 * variable with the specified name, try the parent object, and iterate until
1217 * the top of the tree. If no match is found, the value is read from the
1220 int var_Inherit( vlc_object_t
*p_this
, const char *psz_name
, int i_type
,
1221 vlc_value_t
*p_val
)
1223 i_type
&= VLC_VAR_CLASS
;
1224 for( vlc_object_t
*obj
= p_this
; obj
!= NULL
; obj
= obj
->p_parent
)
1225 if( var_GetChecked( obj
, psz_name
, i_type
, p_val
) == VLC_SUCCESS
)
1228 /* else take value from config */
1229 switch( i_type
& VLC_VAR_CLASS
)
1231 case VLC_VAR_STRING
:
1232 p_val
->psz_string
= config_GetPsz( p_this
, psz_name
);
1233 if( !p_val
->psz_string
) p_val
->psz_string
= strdup("");
1236 p_val
->f_float
= config_GetFloat( p_this
, psz_name
);
1238 case VLC_VAR_INTEGER
:
1239 p_val
->i_int
= config_GetInt( p_this
, psz_name
);
1242 p_val
->b_bool
= config_GetInt( p_this
, psz_name
);
1246 char *psz_orig
, *psz_var
;
1247 vlc_list_t
*p_list
= malloc(sizeof(vlc_list_t
));
1248 p_val
->p_list
= p_list
;
1249 p_list
->i_count
= 0;
1251 psz_var
= psz_orig
= config_GetPsz( p_this
, psz_name
);
1252 while( psz_var
&& *psz_var
)
1254 char *psz_item
= psz_var
;
1256 while( *psz_var
&& *psz_var
!= ',' ) psz_var
++;
1257 if( *psz_var
== ',' )
1262 val
.i_int
= strtol( psz_item
, NULL
, 0 );
1263 INSERT_ELEM( p_list
->p_values
, p_list
->i_count
,
1264 p_list
->i_count
, val
);
1265 /* p_list->i_count is incremented twice by INSERT_ELEM */
1267 INSERT_ELEM( p_list
->pi_types
, p_list
->i_count
,
1268 p_list
->i_count
, VLC_VAR_INTEGER
);
1274 msg_Warn( p_this
, "Could not inherit value for var %s "
1275 "from config. Invalid Type", psz_name
);
1278 /*msg_Dbg( p_this, "Inherited value for var %s from config", psz_name );*/
1283 /**********************************************************************
1284 * Trigger the callbacks.
1285 * Tell we're in a callback, release the lock, call stored functions,
1287 **********************************************************************/
1288 static int TriggerCallback( vlc_object_t
*p_this
, variable_t
*p_var
,
1289 const char *psz_name
, vlc_value_t oldval
)
1293 int i_entries
= p_var
->i_entries
;
1294 if( i_entries
== 0 )
1297 callback_entry_t
*p_entries
= p_var
->p_entries
;
1298 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
1300 assert( !p_var
->b_incallback
);
1301 p_var
->b_incallback
= true;
1302 vlc_mutex_unlock( &p_priv
->var_lock
);
1304 /* The real calls */
1305 for( ; i_entries
-- ; )
1307 p_entries
[i_entries
].pf_callback( p_this
, psz_name
, oldval
, p_var
->val
,
1308 p_entries
[i_entries
].p_data
);
1311 vlc_mutex_lock( &p_priv
->var_lock
);
1312 p_var
->b_incallback
= false;
1313 vlc_cond_broadcast( &p_priv
->var_wait
);
1319 /**********************************************************************
1320 * Execute a var command on an object identified by its name
1321 **********************************************************************/
1322 int __var_Command( vlc_object_t
*p_this
, const char *psz_name
,
1323 const char *psz_cmd
, const char *psz_arg
, char **psz_msg
)
1325 vlc_object_t
*p_obj
= vlc_object_find_name( p_this
->p_libvlc
,
1326 psz_name
, FIND_CHILD
);
1332 *psz_msg
= strdup( "Unknown destination object." );
1336 i_type
= var_Type( p_obj
, psz_cmd
);
1337 if( !( i_type
&VLC_VAR_ISCOMMAND
) )
1339 vlc_object_release( p_obj
);
1341 *psz_msg
= strdup( "Variable doesn't exist or isn't a command." );
1342 return VLC_EGENERIC
;
1345 i_type
&= VLC_VAR_CLASS
;
1348 case VLC_VAR_INTEGER
:
1349 i_ret
= var_SetInteger( p_obj
, psz_cmd
, atoi( psz_arg
) );
1352 i_ret
= var_SetFloat( p_obj
, psz_cmd
, us_atof( psz_arg
) );
1354 case VLC_VAR_STRING
:
1355 i_ret
= var_SetString( p_obj
, psz_cmd
, psz_arg
);
1358 i_ret
= var_SetBool( p_obj
, psz_cmd
, atoi( psz_arg
) );
1361 i_ret
= VLC_EGENERIC
;
1365 vlc_object_release( p_obj
);
1369 if( asprintf( psz_msg
, "%s on object %s returned %i (%s)",
1370 psz_cmd
, psz_name
, i_ret
, vlc_error( i_ret
) ) == -1)
1379 * Free a list and the associated strings
1380 * @param p_val: the list variable
1381 * @param p_val2: the variable associated or NULL
1383 void var_FreeList( vlc_value_t
*p_val
, vlc_value_t
*p_val2
)
1386 if( p_val2
&& p_val2
->p_list
)
1388 for( int i
= 0; i
< p_val2
->p_list
->i_count
; i
++ )
1389 free( p_val2
->p_list
->p_values
[i
].psz_string
);
1390 if( p_val2
->p_list
->i_count
)
1392 free( p_val2
->p_list
->p_values
);
1393 free( p_val2
->p_list
->pi_types
);
1395 free( p_val2
->p_list
);