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 DupList( vlc_value_t
*p_val
)
91 vlc_list_t
*p_list
= malloc( sizeof(vlc_list_t
) );
93 p_list
->i_count
= p_val
->p_list
->i_count
;
94 if( p_val
->p_list
->i_count
)
96 p_list
->p_values
= malloc( p_list
->i_count
* sizeof(vlc_value_t
) );
97 p_list
->pi_types
= malloc( p_list
->i_count
* sizeof(int) );
101 p_list
->p_values
= NULL
;
102 p_list
->pi_types
= NULL
;
105 for( i
= 0; i
< p_list
->i_count
; i
++ )
107 p_list
->p_values
[i
] = p_val
->p_list
->p_values
[i
];
108 p_list
->pi_types
[i
] = p_val
->p_list
->pi_types
[i
];
109 switch( p_val
->p_list
->pi_types
[i
] & VLC_VAR_CLASS
)
113 DupString( &p_list
->p_values
[i
] );
120 p_val
->p_list
= p_list
;
123 static void FreeDummy( vlc_value_t
*p_val
) { (void)p_val
; /* unused */ }
124 static void FreeString( vlc_value_t
*p_val
) { free( p_val
->psz_string
); }
125 static void FreeMutex( vlc_value_t
*p_val
) { vlc_mutex_destroy( (vlc_mutex_t
*)p_val
->p_address
); free( p_val
->p_address
); }
127 static void FreeList( vlc_value_t
*p_val
)
130 for( i
= 0; i
< p_val
->p_list
->i_count
; i
++ )
132 switch( p_val
->p_list
->pi_types
[i
] & VLC_VAR_CLASS
)
135 FreeString( &p_val
->p_list
->p_values
[i
] );
138 FreeMutex( &p_val
->p_list
->p_values
[i
] );
145 if( p_val
->p_list
->i_count
)
147 free( p_val
->p_list
->p_values
);
148 free( p_val
->p_list
->pi_types
);
150 free( p_val
->p_list
);
153 static const struct variable_ops_t
154 void_ops
= { NULL
, DupDummy
, FreeDummy
, },
155 addr_ops
= { CmpAddress
, DupDummy
, FreeDummy
, },
156 bool_ops
= { CmpBool
, DupDummy
, FreeDummy
, },
157 float_ops
= { CmpFloat
, DupDummy
, FreeDummy
, },
158 int_ops
= { CmpInt
, DupDummy
, FreeDummy
, },
159 list_ops
= { CmpAddress
, DupList
, FreeList
, },
160 mutex_ops
= { CmpAddress
, DupDummy
, FreeMutex
, },
161 string_ops
= { CmpString
, DupString
, FreeString
, },
162 time_ops
= { CmpTime
, DupDummy
, FreeDummy
, },
163 coords_ops
= { NULL
, DupDummy
, FreeDummy
, };
165 /*****************************************************************************
167 *****************************************************************************/
168 static void WaitUnused ( vlc_object_t
*, variable_t
* );
170 static void CheckValue ( variable_t
*, vlc_value_t
* );
172 static int TriggerCallback( vlc_object_t
*, variable_t
*, const char *,
175 static int varcmp( const void *a
, const void *b
)
177 const variable_t
*va
= a
, *vb
= b
;
179 /* psz_name must be first */
180 assert( va
== (const void *)&va
->psz_name
);
181 return strcmp( va
->psz_name
, vb
->psz_name
);
184 static variable_t
*Lookup( vlc_object_t
*obj
, const char *psz_name
)
186 vlc_object_internals_t
*priv
= vlc_internals( obj
);
189 vlc_assert_locked( &priv
->var_lock
);
190 pp_var
= tfind( &psz_name
, &priv
->var_root
, varcmp
);
191 return (pp_var
!= NULL
) ? *pp_var
: NULL
;
194 static void Destroy( variable_t
*p_var
)
196 p_var
->ops
->pf_free( &p_var
->val
);
197 if( p_var
->choices
.i_count
)
199 for( int i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
201 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
202 free( p_var
->choices_text
.p_values
[i
].psz_string
);
204 free( p_var
->choices
.p_values
);
205 free( p_var
->choices_text
.p_values
);
207 free( p_var
->psz_name
);
208 free( p_var
->psz_text
);
209 free( p_var
->p_entries
);
215 * Initialize a vlc variable
217 * We hash the given string and insert it into the sorted list. The insertion
218 * may require slow memory copies, but think about what we gain in the log(n)
219 * lookup phase when setting/getting the variable value!
221 * \param p_this The object in which to create the variable
222 * \param psz_name The name of the variable
223 * \param i_type The variables type. Must be one of \ref var_type combined with
224 * zero or more \ref var_flags
226 int var_Create( vlc_object_t
*p_this
, const char *psz_name
, int i_type
)
228 static vlc_list_t dummy_null_list
= {0, NULL
, NULL
};
231 variable_t
*p_var
= calloc( 1, sizeof( *p_var
) );
235 p_var
->psz_name
= strdup( psz_name
);
236 p_var
->psz_text
= NULL
;
238 p_var
->i_type
= i_type
& ~VLC_VAR_DOINHERIT
;
242 p_var
->i_default
= -1;
243 p_var
->choices
.i_count
= 0;
244 p_var
->choices
.p_values
= NULL
;
245 p_var
->choices_text
.i_count
= 0;
246 p_var
->choices_text
.p_values
= NULL
;
248 p_var
->b_incallback
= false;
249 p_var
->i_entries
= 0;
250 p_var
->p_entries
= NULL
;
252 /* Always initialize the variable, even if it is a list variable; this
253 * will lead to errors if the variable is not initialized, but it will
254 * not cause crashes in the variable handling. */
255 switch( i_type
& VLC_VAR_CLASS
)
258 p_var
->ops
= &bool_ops
;
259 p_var
->val
.b_bool
= false;
261 case VLC_VAR_INTEGER
:
262 p_var
->ops
= &int_ops
;
263 p_var
->val
.i_int
= 0;
266 p_var
->ops
= &string_ops
;
267 p_var
->val
.psz_string
= NULL
;
270 p_var
->ops
= &float_ops
;
271 p_var
->val
.f_float
= 0.0;
274 p_var
->ops
= &time_ops
;
275 p_var
->val
.i_time
= 0;
278 p_var
->ops
= &coords_ops
;
279 p_var
->val
.coords
.x
= p_var
->val
.coords
.y
= 0;
281 case VLC_VAR_ADDRESS
:
282 p_var
->ops
= &addr_ops
;
283 p_var
->val
.p_address
= NULL
;
286 p_var
->ops
= &mutex_ops
;
287 p_var
->val
.p_address
= malloc( sizeof(vlc_mutex_t
) );
288 vlc_mutex_init( (vlc_mutex_t
*)p_var
->val
.p_address
);
291 p_var
->ops
= &list_ops
;
292 p_var
->val
.p_list
= &dummy_null_list
;
295 p_var
->ops
= &void_ops
;
297 if( (i_type
& VLC_VAR_CLASS
) != VLC_VAR_VOID
)
298 msg_Err( p_this
, "Creating the variable '%s' without a type",
303 if( i_type
& VLC_VAR_DOINHERIT
)
305 if( var_Inherit( p_this
, psz_name
, i_type
, &p_var
->val
) )
306 msg_Err( p_this
, "cannot inherit value for %s", psz_name
);
307 else if( i_type
& VLC_VAR_HASCHOICE
)
309 /* We must add the inherited value to our choice list */
310 p_var
->i_default
= 0;
312 INSERT_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
,
314 INSERT_ELEM( p_var
->choices_text
.p_values
,
315 p_var
->choices_text
.i_count
, 0, p_var
->val
);
316 p_var
->ops
->pf_dup( &p_var
->choices
.p_values
[0] );
317 p_var
->choices_text
.p_values
[0].psz_string
= NULL
;
321 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
322 variable_t
**pp_var
, *p_oldvar
;
323 int ret
= VLC_SUCCESS
;
325 vlc_mutex_lock( &p_priv
->var_lock
);
327 pp_var
= tsearch( p_var
, &p_priv
->var_root
, varcmp
);
328 if( unlikely(pp_var
== NULL
) )
330 else if( (p_oldvar
= *pp_var
) == p_var
)
332 else if( unlikely((i_type
^ p_oldvar
->i_type
) & VLC_VAR_CLASS
) )
333 { /* If the types differ, variable creation failed. */
334 msg_Err( p_this
, "Variable '%s' (0x%04x) already exist "
335 "but with a different type (0x%04x)",
336 psz_name
, p_oldvar
->i_type
, i_type
);
342 p_oldvar
->i_type
|= i_type
& (VLC_VAR_ISCOMMAND
|VLC_VAR_HASCHOICE
);
344 vlc_mutex_unlock( &p_priv
->var_lock
);
346 /* If we did not need to create a new variable, free everything... */
354 * Destroy a vlc variable
356 * Look for the variable and destroy it if it is found. As in var_Create we
357 * do a call to memmove() but we have performance counterparts elsewhere.
359 * \param p_this The object that holds the variable
360 * \param psz_name The name of the variable
362 int var_Destroy( vlc_object_t
*p_this
, const char *psz_name
)
368 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
370 vlc_mutex_lock( &p_priv
->var_lock
);
372 p_var
= Lookup( p_this
, psz_name
);
375 vlc_mutex_unlock( &p_priv
->var_lock
);
379 WaitUnused( p_this
, p_var
);
381 if( --p_var
->i_usage
== 0 )
382 tdelete( p_var
, &p_priv
->var_root
, varcmp
);
385 vlc_mutex_unlock( &p_priv
->var_lock
);
392 static void CleanupVar( void *var
)
397 void var_DestroyAll( vlc_object_t
*obj
)
399 vlc_object_internals_t
*priv
= vlc_internals( obj
);
401 tdestroy( priv
->var_root
, CleanupVar
);
406 * Perform an action on a variable
408 * \param p_this The object that holds the variable
409 * \param psz_name The name of the variable
410 * \param i_action The action to perform. Must be one of \ref var_action
411 * \param p_val First action parameter
412 * \param p_val2 Second action parameter
414 int var_Change( vlc_object_t
*p_this
, const char *psz_name
,
415 int i_action
, vlc_value_t
*p_val
, vlc_value_t
*p_val2
)
424 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
426 vlc_mutex_lock( &p_priv
->var_lock
);
428 p_var
= Lookup( p_this
, psz_name
);
431 vlc_mutex_unlock( &p_priv
->var_lock
);
438 if( p_var
->i_type
& VLC_VAR_HASMIN
)
440 p_var
->ops
->pf_free( &p_var
->min
);
442 p_var
->i_type
|= VLC_VAR_HASMIN
;
444 p_var
->ops
->pf_dup( &p_var
->min
);
445 CheckValue( p_var
, &p_var
->val
);
448 if( p_var
->i_type
& VLC_VAR_HASMIN
)
454 if( p_var
->i_type
& VLC_VAR_HASMAX
)
456 p_var
->ops
->pf_free( &p_var
->max
);
458 p_var
->i_type
|= VLC_VAR_HASMAX
;
460 p_var
->ops
->pf_dup( &p_var
->max
);
461 CheckValue( p_var
, &p_var
->val
);
464 if( p_var
->i_type
& VLC_VAR_HASMAX
)
469 case VLC_VAR_SETSTEP
:
470 if( p_var
->i_type
& VLC_VAR_HASSTEP
)
472 p_var
->ops
->pf_free( &p_var
->step
);
474 p_var
->i_type
|= VLC_VAR_HASSTEP
;
475 p_var
->step
= *p_val
;
476 p_var
->ops
->pf_dup( &p_var
->step
);
477 CheckValue( p_var
, &p_var
->val
);
479 case VLC_VAR_GETSTEP
:
480 if( p_var
->i_type
& VLC_VAR_HASSTEP
)
482 *p_val
= p_var
->step
;
485 case VLC_VAR_ADDCHOICE
:
486 i
= p_var
->choices
.i_count
;
488 INSERT_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
,
490 INSERT_ELEM( p_var
->choices_text
.p_values
,
491 p_var
->choices_text
.i_count
, i
, *p_val
);
492 p_var
->ops
->pf_dup( &p_var
->choices
.p_values
[i
] );
493 p_var
->choices_text
.p_values
[i
].psz_string
=
494 ( p_val2
&& p_val2
->psz_string
) ?
495 strdup( p_val2
->psz_string
) : NULL
;
497 CheckValue( p_var
, &p_var
->val
);
499 case VLC_VAR_DELCHOICE
:
500 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
502 if( p_var
->ops
->pf_cmp( p_var
->choices
.p_values
[i
], *p_val
) == 0 )
508 if( i
== p_var
->choices
.i_count
)
511 vlc_mutex_unlock( &p_priv
->var_lock
);
515 if( p_var
->i_default
> i
)
519 else if( p_var
->i_default
== i
)
521 p_var
->i_default
= -1;
524 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
525 free( p_var
->choices_text
.p_values
[i
].psz_string
);
526 REMOVE_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
, i
);
527 REMOVE_ELEM( p_var
->choices_text
.p_values
,
528 p_var
->choices_text
.i_count
, i
);
530 CheckValue( p_var
, &p_var
->val
);
532 case VLC_VAR_CHOICESCOUNT
:
533 p_val
->i_int
= p_var
->choices
.i_count
;
535 case VLC_VAR_CLEARCHOICES
:
536 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
538 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
540 for( i
= 0 ; i
< p_var
->choices_text
.i_count
; i
++ )
541 free( p_var
->choices_text
.p_values
[i
].psz_string
);
543 if( p_var
->choices
.i_count
) free( p_var
->choices
.p_values
);
544 if( p_var
->choices_text
.i_count
) free( p_var
->choices_text
.p_values
);
546 p_var
->choices
.i_count
= 0;
547 p_var
->choices
.p_values
= NULL
;
548 p_var
->choices_text
.i_count
= 0;
549 p_var
->choices_text
.p_values
= NULL
;
550 p_var
->i_default
= -1;
552 case VLC_VAR_SETDEFAULT
:
553 /* FIXME: the list is sorted, dude. Use something cleverer. */
554 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
556 if( p_var
->ops
->pf_cmp( p_var
->choices
.p_values
[i
], *p_val
) == 0 )
562 if( i
== p_var
->choices
.i_count
)
568 p_var
->i_default
= i
;
569 CheckValue( p_var
, &p_var
->val
);
571 case VLC_VAR_SETVALUE
:
572 /* Duplicate data if needed */
574 p_var
->ops
->pf_dup( &newval
);
575 /* Backup needed stuff */
577 /* Check boundaries and list */
578 CheckValue( p_var
, &newval
);
579 /* Set the variable */
581 /* Free data if needed */
582 p_var
->ops
->pf_free( &oldval
);
584 case VLC_VAR_GETCHOICES
:
585 case VLC_VAR_GETLIST
:
586 p_val
->p_list
= malloc( sizeof(vlc_list_t
) );
587 if( p_val2
) p_val2
->p_list
= malloc( sizeof(vlc_list_t
) );
588 if( p_var
->choices
.i_count
)
590 p_val
->p_list
->p_values
= malloc( p_var
->choices
.i_count
591 * sizeof(vlc_value_t
) );
592 p_val
->p_list
->pi_types
= malloc( p_var
->choices
.i_count
596 p_val2
->p_list
->p_values
=
597 malloc( p_var
->choices
.i_count
* sizeof(vlc_value_t
) );
598 p_val2
->p_list
->pi_types
=
599 malloc( p_var
->choices
.i_count
* sizeof(int) );
602 p_val
->p_list
->i_count
= p_var
->choices
.i_count
;
603 if( p_val2
) p_val2
->p_list
->i_count
= p_var
->choices
.i_count
;
604 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
606 p_val
->p_list
->p_values
[i
] = p_var
->choices
.p_values
[i
];
607 p_val
->p_list
->pi_types
[i
] = p_var
->i_type
;
608 p_var
->ops
->pf_dup( &p_val
->p_list
->p_values
[i
] );
611 p_val2
->p_list
->p_values
[i
].psz_string
=
612 p_var
->choices_text
.p_values
[i
].psz_string
?
613 strdup(p_var
->choices_text
.p_values
[i
].psz_string
) : NULL
;
614 p_val2
->p_list
->pi_types
[i
] = VLC_VAR_STRING
;
618 case VLC_VAR_SETTEXT
:
619 free( p_var
->psz_text
);
620 if( p_val
&& p_val
->psz_string
)
621 p_var
->psz_text
= strdup( p_val
->psz_string
);
623 p_var
->psz_text
= NULL
;
625 case VLC_VAR_GETTEXT
:
626 p_val
->psz_string
= p_var
->psz_text
? strdup( p_var
->psz_text
)
629 case VLC_VAR_SETISCOMMAND
:
630 p_var
->i_type
|= VLC_VAR_ISCOMMAND
;
637 vlc_mutex_unlock( &p_priv
->var_lock
);
644 * Perform a Get and Set on a variable
646 * \param p_this: The object that hold the variable
647 * \param psz_name: the name of the variable
648 * \param i_action: the action to perform
649 * \param p_val: The action parameter
650 * \return vlc error codes
652 int var_GetAndSet( vlc_object_t
*p_this
, const char *psz_name
, int i_action
,
662 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
664 vlc_mutex_lock( &p_priv
->var_lock
);
665 p_var
= Lookup( p_this
, psz_name
);
668 vlc_mutex_unlock( &p_priv
->var_lock
);
672 WaitUnused( p_this
, p_var
);
674 /* Duplicated data if needed */
675 //p_var->ops->pf_dup( &val );
677 /* Backup needed stuff */
680 /* depending of the action requiered */
683 case VLC_VAR_BOOL_TOGGLE
:
684 assert( ( p_var
->i_type
& VLC_VAR_BOOL
) == VLC_VAR_BOOL
);
685 p_var
->val
.b_bool
= !p_var
->val
.b_bool
;
687 case VLC_VAR_INTEGER_ADD
:
688 assert( ( p_var
->i_type
& VLC_VAR_INTEGER
) == VLC_VAR_INTEGER
);
689 p_var
->val
.i_int
+= p_val
->i_int
;
691 case VLC_VAR_INTEGER_OR
:
692 assert( ( p_var
->i_type
& VLC_VAR_INTEGER
) == VLC_VAR_INTEGER
);
693 p_var
->val
.i_int
|= p_val
->i_int
;
695 case VLC_VAR_INTEGER_NAND
:
696 assert( ( p_var
->i_type
& VLC_VAR_INTEGER
) == VLC_VAR_INTEGER
);
697 p_var
->val
.i_int
&= ~p_val
->i_int
;
700 vlc_mutex_unlock( &p_priv
->var_lock
);
704 /* Check boundaries */
705 CheckValue( p_var
, &p_var
->val
);
708 /* Deal with callbacks.*/
709 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, oldval
);
711 vlc_mutex_unlock( &p_priv
->var_lock
);
718 * Request a variable's type
720 * \return The variable type if it exists, or 0 if the
721 * variable could not be found.
724 int var_Type( vlc_object_t
*p_this
, const char *psz_name
)
731 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
733 vlc_mutex_lock( &p_priv
->var_lock
);
735 p_var
= Lookup( p_this
, psz_name
);
737 i_type
= p_var
->i_type
;
739 vlc_mutex_unlock( &p_priv
->var_lock
);
744 #undef var_SetChecked
745 int var_SetChecked( vlc_object_t
*p_this
, const char *psz_name
,
746 int expected_type
, vlc_value_t val
)
748 int i_ret
= VLC_SUCCESS
;
754 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
756 vlc_mutex_lock( &p_priv
->var_lock
);
758 p_var
= Lookup( p_this
, psz_name
);
761 vlc_mutex_unlock( &p_priv
->var_lock
);
765 assert( expected_type
== 0 ||
766 (p_var
->i_type
& VLC_VAR_CLASS
) == expected_type
);
768 /* Alert if the type is VLC_VAR_VOID */
769 if( ( p_var
->i_type
& VLC_VAR_TYPE
) == VLC_VAR_VOID
)
770 msg_Warn( p_this
, "Calling var_Set on the void variable '%s' (0x%04x)", psz_name
, p_var
->i_type
);
774 WaitUnused( p_this
, p_var
);
776 /* Duplicate data if needed */
777 p_var
->ops
->pf_dup( &val
);
779 /* Backup needed stuff */
782 /* Check boundaries and list */
783 CheckValue( p_var
, &val
);
785 /* Set the variable */
788 /* Deal with callbacks */
789 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, oldval
);
791 /* Free data if needed */
792 p_var
->ops
->pf_free( &oldval
);
794 vlc_mutex_unlock( &p_priv
->var_lock
);
801 * Set a variable's value
803 * \param p_this The object that hold the variable
804 * \param psz_name The name of the variable
805 * \param val the value to set
807 int var_Set( vlc_object_t
*p_this
, const char *psz_name
, vlc_value_t val
)
809 return var_SetChecked( p_this
, psz_name
, 0, val
);
812 #undef var_GetChecked
813 int var_GetChecked( vlc_object_t
*p_this
, const char *psz_name
,
814 int expected_type
, vlc_value_t
*p_val
)
818 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
820 int err
= VLC_SUCCESS
;
822 vlc_mutex_lock( &p_priv
->var_lock
);
824 p_var
= Lookup( p_this
, psz_name
);
827 assert( expected_type
== 0 ||
828 (p_var
->i_type
& VLC_VAR_CLASS
) == expected_type
);
830 /* Really get the variable */
834 /* Alert if the type is VLC_VAR_VOID */
835 if( ( p_var
->i_type
& VLC_VAR_TYPE
) == VLC_VAR_VOID
)
836 msg_Warn( p_this
, "Calling var_Get on the void variable '%s' (0x%04x)", psz_name
, p_var
->i_type
);
839 /* Duplicate value if needed */
840 p_var
->ops
->pf_dup( p_val
);
845 vlc_mutex_unlock( &p_priv
->var_lock
);
851 * Get a variable's value
853 * \param p_this The object that holds the variable
854 * \param psz_name The name of the variable
855 * \param p_val Pointer to a vlc_value_t that will hold the variable's value
856 * after the function is finished
858 int var_Get( vlc_object_t
*p_this
, const char *psz_name
, vlc_value_t
*p_val
)
860 return var_GetChecked( p_this
, psz_name
, 0, p_val
);
863 #undef var_AddCallback
865 * Register a callback in a variable
867 * We store a function pointer that will be called upon variable
870 * \param p_this The object that holds the variable
871 * \param psz_name The name of the variable
872 * \param pf_callback The function pointer
873 * \param p_data A generic pointer that will be passed as the last
874 * argument to the callback function.
876 * \warning The callback function is run in the thread that calls var_Set on
877 * the variable. Use proper locking. This thread may not have much
878 * time to spare, so keep callback functions short.
880 int var_AddCallback( vlc_object_t
*p_this
, const char *psz_name
,
881 vlc_callback_t pf_callback
, void *p_data
)
884 callback_entry_t entry
;
888 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
890 entry
.pf_callback
= pf_callback
;
891 entry
.p_data
= p_data
;
893 vlc_mutex_lock( &p_priv
->var_lock
);
895 p_var
= Lookup( p_this
, psz_name
);
899 msg_Warn( p_this
, "Failed to add a callback to the non-existing "
900 "variable '%s'", psz_name
);
902 vlc_mutex_unlock( &p_priv
->var_lock
);
906 WaitUnused( p_this
, p_var
);
907 INSERT_ELEM( p_var
->p_entries
,
912 vlc_mutex_unlock( &p_priv
->var_lock
);
917 #undef var_DelCallback
919 * Remove a callback from a variable
921 * pf_callback and p_data have to be given again, because different objects
922 * might have registered the same callback function.
924 int var_DelCallback( vlc_object_t
*p_this
, const char *psz_name
,
925 vlc_callback_t pf_callback
, void *p_data
)
930 bool b_found_similar
= false;
935 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
937 vlc_mutex_lock( &p_priv
->var_lock
);
939 p_var
= Lookup( p_this
, psz_name
);
942 vlc_mutex_unlock( &p_priv
->var_lock
);
946 WaitUnused( p_this
, p_var
);
948 for( i_entry
= p_var
->i_entries
; i_entry
-- ; )
950 if( p_var
->p_entries
[i_entry
].pf_callback
== pf_callback
951 && p_var
->p_entries
[i_entry
].p_data
== p_data
)
956 else if( p_var
->p_entries
[i_entry
].pf_callback
== pf_callback
)
957 b_found_similar
= true;
964 if( b_found_similar
)
965 fprintf( stderr
, "Calling var_DelCallback for '%s' with the same "
966 "function but not the same data.", psz_name
);
969 vlc_mutex_unlock( &p_priv
->var_lock
);
973 REMOVE_ELEM( p_var
->p_entries
, p_var
->i_entries
, i_entry
);
975 vlc_mutex_unlock( &p_priv
->var_lock
);
980 #undef var_TriggerCallback
982 * Trigger callback on a variable
984 * \param p_this The object that hold the variable
985 * \param psz_name The name of the variable
987 int var_TriggerCallback( vlc_object_t
*p_this
, const char *psz_name
)
994 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
996 vlc_mutex_lock( &p_priv
->var_lock
);
998 p_var
= Lookup( p_this
, psz_name
);
1001 vlc_mutex_unlock( &p_priv
->var_lock
);
1005 WaitUnused( p_this
, p_var
);
1007 /* Deal with callbacks. Tell we're in a callback, release the lock,
1008 * call stored functions, retake the lock. */
1009 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, p_var
->val
);
1011 vlc_mutex_unlock( &p_priv
->var_lock
);
1015 /** Parse a stringified option
1016 * This function parse a string option and create the associated object
1018 * The option must be of the form "[no[-]]foo[=bar]" where foo is the
1019 * option name and bar is the value of the option.
1020 * \param p_obj the object in which the variable must be created
1021 * \param psz_option the option to parse
1022 * \param trusted whether the option is set by a trusted input or not
1025 void var_OptionParse( vlc_object_t
*p_obj
, const char *psz_option
,
1028 char *psz_name
, *psz_value
;
1030 bool b_isno
= false;
1033 val
.psz_string
= NULL
;
1035 /* It's too much of a hassle to remove the ':' when we parse
1036 * the cmd line :) */
1037 if( psz_option
[0] == ':' )
1040 if( !psz_option
[0] )
1043 psz_name
= strdup( psz_option
);
1044 if( psz_name
== NULL
)
1047 psz_value
= strchr( psz_name
, '=' );
1048 if( psz_value
!= NULL
)
1049 *psz_value
++ = '\0';
1051 /* FIXME: :programs should be handled generically */
1052 if( !strcmp( psz_name
, "programs" ) )
1053 i_type
= VLC_VAR_LIST
;
1055 i_type
= config_GetType( p_obj
, psz_name
);
1057 if( !i_type
&& !psz_value
)
1059 /* check for "no-foo" or "nofoo" */
1060 if( !strncmp( psz_name
, "no-", 3 ) )
1062 memmove( psz_name
, psz_name
+ 3, strlen(psz_name
) + 1 - 3 );
1064 else if( !strncmp( psz_name
, "no", 2 ) )
1066 memmove( psz_name
, psz_name
+ 2, strlen(psz_name
) + 1 - 2 );
1068 else goto cleanup
; /* Option doesn't exist */
1071 i_type
= config_GetType( p_obj
, psz_name
);
1073 if( !i_type
) goto cleanup
; /* Option doesn't exist */
1075 if( ( i_type
!= VLC_VAR_BOOL
) &&
1076 ( !psz_value
|| !*psz_value
) ) goto cleanup
; /* Invalid value */
1078 /* check if option is unsafe */
1081 module_config_t
*p_config
= config_FindConfig( p_obj
, psz_name
);
1082 if( !p_config
|| !p_config
->b_safe
)
1084 msg_Err( p_obj
, "unsafe option \"%s\" has been ignored for "
1085 "security reasons", psz_name
);
1091 /* Create the variable in the input object.
1092 * Children of the input object will be able to retreive this value
1093 * thanks to the inheritance property of the object variables. */
1094 var_Create( p_obj
, psz_name
, i_type
);
1099 val
.b_bool
= !b_isno
;
1102 case VLC_VAR_INTEGER
:
1103 val
.i_int
= strtol( psz_value
, NULL
, 0 );
1107 val
.f_float
= us_atof( psz_value
);
1110 case VLC_VAR_STRING
:
1111 case VLC_VAR_MODULE
:
1113 case VLC_VAR_DIRECTORY
:
1114 val
.psz_string
= psz_value
;
1119 char *psz_orig
, *psz_var
;
1120 vlc_list_t
*p_list
= malloc(sizeof(vlc_list_t
));
1121 val
.p_list
= p_list
;
1122 p_list
->i_count
= 0;
1124 psz_var
= psz_orig
= strdup(psz_value
);
1125 while( psz_var
&& *psz_var
)
1127 char *psz_item
= psz_var
;
1129 while( *psz_var
&& *psz_var
!= ',' ) psz_var
++;
1130 if( *psz_var
== ',' )
1135 val2
.i_int
= strtol( psz_item
, NULL
, 0 );
1136 INSERT_ELEM( p_list
->p_values
, p_list
->i_count
,
1137 p_list
->i_count
, val2
);
1138 /* p_list->i_count is incremented twice by INSERT_ELEM */
1140 INSERT_ELEM( p_list
->pi_types
, p_list
->i_count
,
1141 p_list
->i_count
, VLC_VAR_INTEGER
);
1151 var_Set( p_obj
, psz_name
, val
);
1153 /* If that's a list, remove all elements allocated */
1154 if( i_type
== VLC_VAR_LIST
)
1162 /* Following functions are local */
1165 * Waits until the variable is inactive (i.e. not executing a callback)
1167 static void WaitUnused( vlc_object_t
*p_this
, variable_t
*p_var
)
1169 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
1171 mutex_cleanup_push( &p_priv
->var_lock
);
1172 while( p_var
->b_incallback
)
1173 vlc_cond_wait( &p_priv
->var_wait
, &p_priv
->var_lock
);
1177 /*****************************************************************************
1178 * CheckValue: check that a value is valid wrt. a variable
1179 *****************************************************************************
1180 * This function checks p_val's value against p_var's limitations such as
1181 * minimal and maximal value, step, in-list position, and modifies p_val if
1183 ****************************************************************************/
1184 static void CheckValue ( variable_t
*p_var
, vlc_value_t
*p_val
)
1186 /* Check that our variable is in the list */
1187 if( p_var
->i_type
& VLC_VAR_HASCHOICE
&& p_var
->choices
.i_count
)
1191 /* This list is not sorted so go throug it (this is a small list) */
1192 for( i
= p_var
->choices
.i_count
; i
-- ; )
1194 if( p_var
->ops
->pf_cmp( *p_val
, p_var
->choices
.p_values
[i
] ) == 0 )
1200 /* If not found, change it to anything vaguely valid */
1203 /* Free the old variable, get the new one, dup it */
1204 p_var
->ops
->pf_free( p_val
);
1205 *p_val
= p_var
->choices
.p_values
[p_var
->i_default
>= 0
1206 ? p_var
->i_default
: 0 ];
1207 p_var
->ops
->pf_dup( p_val
);
1211 /* Check that our variable is within the bounds */
1212 switch( p_var
->i_type
& VLC_VAR_TYPE
)
1214 case VLC_VAR_INTEGER
:
1215 if( p_var
->i_type
& VLC_VAR_HASSTEP
&& p_var
->step
.i_int
1216 && (p_val
->i_int
% p_var
->step
.i_int
) )
1218 p_val
->i_int
= (p_val
->i_int
+ (p_var
->step
.i_int
/ 2))
1219 / p_var
->step
.i_int
* p_var
->step
.i_int
;
1221 if( p_var
->i_type
& VLC_VAR_HASMIN
1222 && p_val
->i_int
< p_var
->min
.i_int
)
1224 p_val
->i_int
= p_var
->min
.i_int
;
1226 if( p_var
->i_type
& VLC_VAR_HASMAX
1227 && p_val
->i_int
> p_var
->max
.i_int
)
1229 p_val
->i_int
= p_var
->max
.i_int
;
1233 if( p_var
->i_type
& VLC_VAR_HASSTEP
&& p_var
->step
.f_float
)
1235 float f_round
= p_var
->step
.f_float
* (float)(int)( 0.5 +
1236 p_val
->f_float
/ p_var
->step
.f_float
);
1237 if( p_val
->f_float
!= f_round
)
1239 p_val
->f_float
= f_round
;
1242 if( p_var
->i_type
& VLC_VAR_HASMIN
1243 && p_val
->f_float
< p_var
->min
.f_float
)
1245 p_val
->f_float
= p_var
->min
.f_float
;
1247 if( p_var
->i_type
& VLC_VAR_HASMAX
1248 && p_val
->f_float
> p_var
->max
.f_float
)
1250 p_val
->f_float
= p_var
->max
.f_float
;
1260 * Finds the value of a variable. If the specified object does not hold a
1261 * variable with the specified name, try the parent object, and iterate until
1262 * the top of the tree. If no match is found, the value is read from the
1265 int var_Inherit( vlc_object_t
*p_this
, const char *psz_name
, int i_type
,
1266 vlc_value_t
*p_val
)
1269 if (p_this
!= VLC_OBJECT(p_this
->p_libvlc
)
1270 && unlikely(p_this
->p_parent
== NULL
))
1272 msg_Info (p_this
, "%s(%s) on detached object", __func__
, psz_name
);
1276 i_type
&= VLC_VAR_CLASS
;
1277 for( vlc_object_t
*obj
= p_this
; obj
!= NULL
; obj
= obj
->p_parent
)
1279 if( var_GetChecked( obj
, psz_name
, i_type
, p_val
) == VLC_SUCCESS
)
1282 if (obj
!= p_this
&& obj
!= VLC_OBJECT(p_this
->p_libvlc
)
1283 && unlikely(obj
->p_parent
== NULL
))
1285 msg_Info (p_this
, "%s(%s) on detached tree [%p] %s", __func__
,
1286 psz_name
, obj
, obj
->psz_object_type
);
1292 /* else take value from config */
1293 switch( i_type
& VLC_VAR_CLASS
)
1295 case VLC_VAR_STRING
:
1296 p_val
->psz_string
= config_GetPsz( p_this
, psz_name
);
1297 if( !p_val
->psz_string
) p_val
->psz_string
= strdup("");
1300 p_val
->f_float
= config_GetFloat( p_this
, psz_name
);
1302 case VLC_VAR_INTEGER
:
1303 p_val
->i_int
= config_GetInt( p_this
, psz_name
);
1306 p_val
->b_bool
= config_GetInt( p_this
, psz_name
);
1310 char *psz_orig
, *psz_var
;
1311 vlc_list_t
*p_list
= malloc(sizeof(vlc_list_t
));
1312 p_val
->p_list
= p_list
;
1313 p_list
->i_count
= 0;
1315 psz_var
= psz_orig
= config_GetPsz( p_this
, psz_name
);
1316 while( psz_var
&& *psz_var
)
1318 char *psz_item
= psz_var
;
1320 while( *psz_var
&& *psz_var
!= ',' ) psz_var
++;
1321 if( *psz_var
== ',' )
1326 val
.i_int
= strtol( psz_item
, NULL
, 0 );
1327 INSERT_ELEM( p_list
->p_values
, p_list
->i_count
,
1328 p_list
->i_count
, val
);
1329 /* p_list->i_count is incremented twice by INSERT_ELEM */
1331 INSERT_ELEM( p_list
->pi_types
, p_list
->i_count
,
1332 p_list
->i_count
, VLC_VAR_INTEGER
);
1338 msg_Warn( p_this
, "Could not inherit value for var %s "
1339 "from config. Invalid Type", psz_name
);
1342 /*msg_Dbg( p_this, "Inherited value for var %s from config", psz_name );*/
1348 * It inherits a string as an unsigned rational number (it also accepts basic
1351 * It returns an error if the rational number cannot be parsed (0/0 is valid).
1352 * The rational is already reduced.
1354 int (var_InheritURational
)(vlc_object_t
*object
,
1355 unsigned *num
, unsigned *den
,
1363 char *tmp
= var_InheritString(object
, var
);
1368 unsigned n
= strtol(tmp
, &next
, 0);
1369 unsigned d
= strtol(*next
? &next
[1] : "0", NULL
, 0);
1372 /* Interpret as a float number */
1373 double r
= us_atof(tmp
);
1388 vlc_ureduce(num
, den
, n
, d
, 0);
1395 return VLC_EGENERIC
;
1398 /**********************************************************************
1399 * Trigger the callbacks.
1400 * Tell we're in a callback, release the lock, call stored functions,
1402 **********************************************************************/
1403 static int TriggerCallback( vlc_object_t
*p_this
, variable_t
*p_var
,
1404 const char *psz_name
, vlc_value_t oldval
)
1408 int i_entries
= p_var
->i_entries
;
1409 if( i_entries
== 0 )
1412 callback_entry_t
*p_entries
= p_var
->p_entries
;
1413 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
1415 assert( !p_var
->b_incallback
);
1416 p_var
->b_incallback
= true;
1417 vlc_mutex_unlock( &p_priv
->var_lock
);
1419 /* The real calls */
1420 for( ; i_entries
-- ; )
1422 p_entries
[i_entries
].pf_callback( p_this
, psz_name
, oldval
, p_var
->val
,
1423 p_entries
[i_entries
].p_data
);
1426 vlc_mutex_lock( &p_priv
->var_lock
);
1427 p_var
->b_incallback
= false;
1428 vlc_cond_broadcast( &p_priv
->var_wait
);
1434 /**********************************************************************
1435 * Execute a var command on an object identified by its name
1436 **********************************************************************/
1437 int var_Command( vlc_object_t
*p_this
, const char *psz_name
,
1438 const char *psz_cmd
, const char *psz_arg
, char **psz_msg
)
1440 vlc_object_t
*p_obj
= vlc_object_find_name( p_this
->p_libvlc
,
1441 psz_name
, FIND_CHILD
);
1447 *psz_msg
= strdup( "Unknown destination object." );
1451 i_type
= var_Type( p_obj
, psz_cmd
);
1452 if( !( i_type
&VLC_VAR_ISCOMMAND
) )
1454 vlc_object_release( p_obj
);
1456 *psz_msg
= strdup( "Variable doesn't exist or isn't a command." );
1457 return VLC_EGENERIC
;
1460 i_type
&= VLC_VAR_CLASS
;
1463 case VLC_VAR_INTEGER
:
1464 i_ret
= var_SetInteger( p_obj
, psz_cmd
, atoi( psz_arg
) );
1467 i_ret
= var_SetFloat( p_obj
, psz_cmd
, us_atof( psz_arg
) );
1469 case VLC_VAR_STRING
:
1470 i_ret
= var_SetString( p_obj
, psz_cmd
, psz_arg
);
1473 i_ret
= var_SetBool( p_obj
, psz_cmd
, atoi( psz_arg
) );
1476 i_ret
= VLC_EGENERIC
;
1480 vlc_object_release( p_obj
);
1484 if( asprintf( psz_msg
, "%s on object %s returned %i (%s)",
1485 psz_cmd
, psz_name
, i_ret
, vlc_error( i_ret
) ) == -1)
1494 * Free a list and the associated strings
1495 * @param p_val: the list variable
1496 * @param p_val2: the variable associated or NULL
1498 void var_FreeList( vlc_value_t
*p_val
, vlc_value_t
*p_val2
)
1501 if( p_val2
&& p_val2
->p_list
)
1503 for( int i
= 0; i
< p_val2
->p_list
->i_count
; i
++ )
1504 free( p_val2
->p_list
->p_values
[i
].psz_string
);
1505 if( p_val2
->p_list
->i_count
)
1507 free( p_val2
->p_list
->p_values
);
1508 free( p_val2
->p_list
->pi_types
);
1510 free( p_val2
->p_list
);