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
);
203 * Initialize a vlc variable
205 * We hash the given string and insert it into the sorted list. The insertion
206 * may require slow memory copies, but think about what we gain in the log(n)
207 * lookup phase when setting/getting the variable value!
209 * \param p_this The object in which to create the variable
210 * \param psz_name The name of the variable
211 * \param i_type The variables type. Must be one of \ref var_type combined with
212 * zero or more \ref var_flags
214 int var_Create( vlc_object_t
*p_this
, const char *psz_name
, int i_type
)
216 static vlc_list_t dummy_null_list
= {0, NULL
, NULL
};
219 variable_t
*p_var
= calloc( 1, sizeof( *p_var
) );
223 p_var
->psz_name
= strdup( psz_name
);
224 p_var
->psz_text
= NULL
;
226 p_var
->i_type
= i_type
& ~VLC_VAR_DOINHERIT
;
230 p_var
->i_default
= -1;
231 p_var
->choices
.i_count
= 0;
232 p_var
->choices
.p_values
= NULL
;
233 p_var
->choices_text
.i_count
= 0;
234 p_var
->choices_text
.p_values
= NULL
;
236 p_var
->b_incallback
= false;
237 p_var
->i_entries
= 0;
238 p_var
->p_entries
= NULL
;
240 /* Always initialize the variable, even if it is a list variable; this
241 * will lead to errors if the variable is not initialized, but it will
242 * not cause crashes in the variable handling. */
243 switch( i_type
& VLC_VAR_CLASS
)
246 p_var
->ops
= &bool_ops
;
247 p_var
->val
.b_bool
= false;
249 case VLC_VAR_INTEGER
:
250 p_var
->ops
= &int_ops
;
251 p_var
->val
.i_int
= 0;
254 p_var
->ops
= &string_ops
;
255 p_var
->val
.psz_string
= NULL
;
258 p_var
->ops
= &float_ops
;
259 p_var
->val
.f_float
= 0.0;
262 p_var
->ops
= &time_ops
;
263 p_var
->val
.i_time
= 0;
265 case VLC_VAR_ADDRESS
:
266 p_var
->ops
= &addr_ops
;
267 p_var
->val
.p_address
= NULL
;
270 p_var
->ops
= &mutex_ops
;
271 p_var
->val
.p_address
= malloc( sizeof(vlc_mutex_t
) );
272 vlc_mutex_init( (vlc_mutex_t
*)p_var
->val
.p_address
);
275 p_var
->ops
= &list_ops
;
276 p_var
->val
.p_list
= &dummy_null_list
;
279 p_var
->ops
= &void_ops
;
281 if( (i_type
& VLC_VAR_CLASS
) != VLC_VAR_VOID
)
282 msg_Err( p_this
, "Creating the variable '%s' without a type",
287 if( i_type
& VLC_VAR_DOINHERIT
)
289 if( var_Inherit( p_this
, psz_name
, i_type
, &p_var
->val
) )
290 msg_Err( p_this
, "cannot inherit value for %s", psz_name
);
291 else if( i_type
& VLC_VAR_HASCHOICE
)
293 /* We must add the inherited value to our choice list */
294 p_var
->i_default
= 0;
296 INSERT_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
,
298 INSERT_ELEM( p_var
->choices_text
.p_values
,
299 p_var
->choices_text
.i_count
, 0, p_var
->val
);
300 p_var
->ops
->pf_dup( &p_var
->choices
.p_values
[0] );
301 p_var
->choices_text
.p_values
[0].psz_string
= NULL
;
305 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
306 variable_t
**pp_var
, *p_oldvar
;
307 int ret
= VLC_SUCCESS
;
309 vlc_mutex_lock( &p_priv
->var_lock
);
311 pp_var
= tsearch( p_var
, &p_priv
->var_root
, varcmp
);
312 if( unlikely(pp_var
== NULL
) )
314 else if( (p_oldvar
= *pp_var
) == p_var
)
316 else if( unlikely((i_type
^ p_oldvar
->i_type
) & VLC_VAR_CLASS
) )
317 { /* If the types differ, variable creation failed. */
318 msg_Err( p_this
, "Variable '%s' (0x%04x) already exist "
319 "but with a different type (0x%04x)",
320 psz_name
, p_oldvar
->i_type
, i_type
);
326 p_oldvar
->i_type
|= i_type
& (VLC_VAR_ISCOMMAND
|VLC_VAR_HASCHOICE
);
328 vlc_mutex_unlock( &p_priv
->var_lock
);
330 /* If we did not need to create a new variable, free everything... */
338 * Destroy a vlc variable
340 * Look for the variable and destroy it if it is found. As in var_Create we
341 * do a call to memmove() but we have performance counterparts elsewhere.
343 * \param p_this The object that holds the variable
344 * \param psz_name The name of the variable
346 int var_Destroy( vlc_object_t
*p_this
, const char *psz_name
)
352 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
354 vlc_mutex_lock( &p_priv
->var_lock
);
356 p_var
= Lookup( p_this
, psz_name
);
359 vlc_mutex_unlock( &p_priv
->var_lock
);
363 WaitUnused( p_this
, p_var
);
365 if( --p_var
->i_usage
== 0 )
366 tdelete( p_var
, &p_priv
->var_root
, varcmp
);
369 vlc_mutex_unlock( &p_priv
->var_lock
);
376 static void CleanupVar( void *var
)
381 void var_DestroyAll( vlc_object_t
*obj
)
383 vlc_object_internals_t
*priv
= vlc_internals( obj
);
385 tdestroy( priv
->var_root
, CleanupVar
);
390 * Perform an action on a variable
392 * \param p_this The object that holds the variable
393 * \param psz_name The name of the variable
394 * \param i_action The action to perform. Must be one of \ref var_action
395 * \param p_val First action parameter
396 * \param p_val2 Second action parameter
398 int var_Change( vlc_object_t
*p_this
, const char *psz_name
,
399 int i_action
, vlc_value_t
*p_val
, vlc_value_t
*p_val2
)
408 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
410 vlc_mutex_lock( &p_priv
->var_lock
);
412 p_var
= Lookup( p_this
, psz_name
);
415 vlc_mutex_unlock( &p_priv
->var_lock
);
422 if( p_var
->i_type
& VLC_VAR_HASMIN
)
424 p_var
->ops
->pf_free( &p_var
->min
);
426 p_var
->i_type
|= VLC_VAR_HASMIN
;
428 p_var
->ops
->pf_dup( &p_var
->min
);
429 CheckValue( p_var
, &p_var
->val
);
432 if( p_var
->i_type
& VLC_VAR_HASMIN
)
438 if( p_var
->i_type
& VLC_VAR_HASMAX
)
440 p_var
->ops
->pf_free( &p_var
->max
);
442 p_var
->i_type
|= VLC_VAR_HASMAX
;
444 p_var
->ops
->pf_dup( &p_var
->max
);
445 CheckValue( p_var
, &p_var
->val
);
448 if( p_var
->i_type
& VLC_VAR_HASMAX
)
453 case VLC_VAR_SETSTEP
:
454 if( p_var
->i_type
& VLC_VAR_HASSTEP
)
456 p_var
->ops
->pf_free( &p_var
->step
);
458 p_var
->i_type
|= VLC_VAR_HASSTEP
;
459 p_var
->step
= *p_val
;
460 p_var
->ops
->pf_dup( &p_var
->step
);
461 CheckValue( p_var
, &p_var
->val
);
463 case VLC_VAR_GETSTEP
:
464 if( p_var
->i_type
& VLC_VAR_HASSTEP
)
466 *p_val
= p_var
->step
;
469 case VLC_VAR_ADDCHOICE
:
470 i
= p_var
->choices
.i_count
;
472 INSERT_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
,
474 INSERT_ELEM( p_var
->choices_text
.p_values
,
475 p_var
->choices_text
.i_count
, i
, *p_val
);
476 p_var
->ops
->pf_dup( &p_var
->choices
.p_values
[i
] );
477 p_var
->choices_text
.p_values
[i
].psz_string
=
478 ( p_val2
&& p_val2
->psz_string
) ?
479 strdup( p_val2
->psz_string
) : NULL
;
481 CheckValue( p_var
, &p_var
->val
);
483 case VLC_VAR_DELCHOICE
:
484 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
486 if( p_var
->ops
->pf_cmp( p_var
->choices
.p_values
[i
], *p_val
) == 0 )
492 if( i
== p_var
->choices
.i_count
)
495 vlc_mutex_unlock( &p_priv
->var_lock
);
499 if( p_var
->i_default
> i
)
503 else if( p_var
->i_default
== i
)
505 p_var
->i_default
= -1;
508 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
509 free( p_var
->choices_text
.p_values
[i
].psz_string
);
510 REMOVE_ELEM( p_var
->choices
.p_values
, p_var
->choices
.i_count
, i
);
511 REMOVE_ELEM( p_var
->choices_text
.p_values
,
512 p_var
->choices_text
.i_count
, i
);
514 CheckValue( p_var
, &p_var
->val
);
516 case VLC_VAR_CHOICESCOUNT
:
517 p_val
->i_int
= p_var
->choices
.i_count
;
519 case VLC_VAR_CLEARCHOICES
:
520 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
522 p_var
->ops
->pf_free( &p_var
->choices
.p_values
[i
] );
524 for( i
= 0 ; i
< p_var
->choices_text
.i_count
; i
++ )
525 free( p_var
->choices_text
.p_values
[i
].psz_string
);
527 if( p_var
->choices
.i_count
) free( p_var
->choices
.p_values
);
528 if( p_var
->choices_text
.i_count
) free( p_var
->choices_text
.p_values
);
530 p_var
->choices
.i_count
= 0;
531 p_var
->choices
.p_values
= NULL
;
532 p_var
->choices_text
.i_count
= 0;
533 p_var
->choices_text
.p_values
= NULL
;
534 p_var
->i_default
= -1;
536 case VLC_VAR_SETDEFAULT
:
537 /* FIXME: the list is sorted, dude. Use something cleverer. */
538 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
540 if( p_var
->ops
->pf_cmp( p_var
->choices
.p_values
[i
], *p_val
) == 0 )
546 if( i
== p_var
->choices
.i_count
)
552 p_var
->i_default
= i
;
553 CheckValue( p_var
, &p_var
->val
);
555 case VLC_VAR_SETVALUE
:
556 /* Duplicate data if needed */
558 p_var
->ops
->pf_dup( &newval
);
559 /* Backup needed stuff */
561 /* Check boundaries and list */
562 CheckValue( p_var
, &newval
);
563 /* Set the variable */
565 /* Free data if needed */
566 p_var
->ops
->pf_free( &oldval
);
568 case VLC_VAR_GETCHOICES
:
569 case VLC_VAR_GETLIST
:
570 p_val
->p_list
= malloc( sizeof(vlc_list_t
) );
571 if( p_val2
) p_val2
->p_list
= malloc( sizeof(vlc_list_t
) );
572 if( p_var
->choices
.i_count
)
574 p_val
->p_list
->p_values
= malloc( p_var
->choices
.i_count
575 * sizeof(vlc_value_t
) );
576 p_val
->p_list
->pi_types
= malloc( p_var
->choices
.i_count
580 p_val2
->p_list
->p_values
=
581 malloc( p_var
->choices
.i_count
* sizeof(vlc_value_t
) );
582 p_val2
->p_list
->pi_types
=
583 malloc( p_var
->choices
.i_count
* sizeof(int) );
586 p_val
->p_list
->i_count
= p_var
->choices
.i_count
;
587 if( p_val2
) p_val2
->p_list
->i_count
= p_var
->choices
.i_count
;
588 for( i
= 0 ; i
< p_var
->choices
.i_count
; i
++ )
590 p_val
->p_list
->p_values
[i
] = p_var
->choices
.p_values
[i
];
591 p_val
->p_list
->pi_types
[i
] = p_var
->i_type
;
592 p_var
->ops
->pf_dup( &p_val
->p_list
->p_values
[i
] );
595 p_val2
->p_list
->p_values
[i
].psz_string
=
596 p_var
->choices_text
.p_values
[i
].psz_string
?
597 strdup(p_var
->choices_text
.p_values
[i
].psz_string
) : NULL
;
598 p_val2
->p_list
->pi_types
[i
] = VLC_VAR_STRING
;
602 case VLC_VAR_SETTEXT
:
603 free( p_var
->psz_text
);
604 if( p_val
&& p_val
->psz_string
)
605 p_var
->psz_text
= strdup( p_val
->psz_string
);
607 p_var
->psz_text
= NULL
;
609 case VLC_VAR_GETTEXT
:
610 p_val
->psz_string
= p_var
->psz_text
? strdup( p_var
->psz_text
)
613 case VLC_VAR_SETISCOMMAND
:
614 p_var
->i_type
|= VLC_VAR_ISCOMMAND
;
621 vlc_mutex_unlock( &p_priv
->var_lock
);
628 * Perform a Get and Set on a variable
630 * \param p_this: The object that hold the variable
631 * \param psz_name: the name of the variable
632 * \param i_action: the action to perform
633 * \param p_val: The action parameter
634 * \return vlc error codes
636 int var_GetAndSet( vlc_object_t
*p_this
, const char *psz_name
, int i_action
,
646 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
648 vlc_mutex_lock( &p_priv
->var_lock
);
649 p_var
= Lookup( p_this
, psz_name
);
652 vlc_mutex_unlock( &p_priv
->var_lock
);
656 WaitUnused( p_this
, p_var
);
658 /* Duplicated data if needed */
659 //p_var->ops->pf_dup( &val );
661 /* Backup needed stuff */
664 /* depending of the action requiered */
667 case VLC_VAR_BOOL_TOGGLE
:
668 assert( ( p_var
->i_type
& VLC_VAR_BOOL
) == VLC_VAR_BOOL
);
669 p_var
->val
.b_bool
= !p_var
->val
.b_bool
;
671 case VLC_VAR_INTEGER_ADD
:
672 assert( ( p_var
->i_type
& VLC_VAR_INTEGER
) == VLC_VAR_INTEGER
);
673 p_var
->val
.i_int
+= p_val
->i_int
;
675 case VLC_VAR_INTEGER_OR
:
676 assert( ( p_var
->i_type
& VLC_VAR_INTEGER
) == VLC_VAR_INTEGER
);
677 p_var
->val
.i_int
|= p_val
->i_int
;
679 case VLC_VAR_INTEGER_NAND
:
680 assert( ( p_var
->i_type
& VLC_VAR_INTEGER
) == VLC_VAR_INTEGER
);
681 p_var
->val
.i_int
&= ~p_val
->i_int
;
684 vlc_mutex_unlock( &p_priv
->var_lock
);
688 /* Check boundaries */
689 CheckValue( p_var
, &p_var
->val
);
692 /* Deal with callbacks.*/
693 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, oldval
);
695 vlc_mutex_unlock( &p_priv
->var_lock
);
702 * Request a variable's type
704 * \return The variable type if it exists, or 0 if the
705 * variable could not be found.
708 int var_Type( vlc_object_t
*p_this
, const char *psz_name
)
715 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
717 vlc_mutex_lock( &p_priv
->var_lock
);
719 p_var
= Lookup( p_this
, psz_name
);
721 i_type
= p_var
->i_type
;
723 vlc_mutex_unlock( &p_priv
->var_lock
);
728 int var_SetChecked( vlc_object_t
*p_this
, const char *psz_name
,
729 int expected_type
, vlc_value_t val
)
731 int i_ret
= VLC_SUCCESS
;
737 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
739 vlc_mutex_lock( &p_priv
->var_lock
);
741 p_var
= Lookup( p_this
, psz_name
);
744 vlc_mutex_unlock( &p_priv
->var_lock
);
748 assert( expected_type
== 0 ||
749 (p_var
->i_type
& VLC_VAR_CLASS
) == expected_type
);
751 WaitUnused( p_this
, p_var
);
753 /* Duplicate data if needed */
754 p_var
->ops
->pf_dup( &val
);
756 /* Backup needed stuff */
759 /* Check boundaries and list */
760 CheckValue( p_var
, &val
);
762 /* Set the variable */
765 /* Deal with callbacks */
766 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, oldval
);
768 /* Free data if needed */
769 p_var
->ops
->pf_free( &oldval
);
771 vlc_mutex_unlock( &p_priv
->var_lock
);
778 * Set a variable's value
780 * \param p_this The object that hold the variable
781 * \param psz_name The name of the variable
782 * \param val the value to set
784 int var_Set( vlc_object_t
*p_this
, const char *psz_name
, vlc_value_t val
)
786 return var_SetChecked( p_this
, psz_name
, 0, val
);
789 int var_GetChecked( vlc_object_t
*p_this
, const char *psz_name
,
790 int expected_type
, vlc_value_t
*p_val
)
794 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
796 int err
= VLC_SUCCESS
;
798 vlc_mutex_lock( &p_priv
->var_lock
);
800 p_var
= Lookup( p_this
, psz_name
);
803 assert( expected_type
== 0 ||
804 (p_var
->i_type
& VLC_VAR_CLASS
) == expected_type
);
806 /* Really get the variable */
810 /* Alert if the type is VLC_VAR_VOID */
811 if( ( p_var
->i_type
& VLC_VAR_TYPE
) == VLC_VAR_VOID
)
812 msg_Warn( p_this
, "Calling var_GetVoid on the void variable '%s' (0x%04x)", psz_name
, p_var
->i_type
);
815 /* Duplicate value if needed */
816 p_var
->ops
->pf_dup( p_val
);
821 vlc_mutex_unlock( &p_priv
->var_lock
);
827 * Get a variable's value
829 * \param p_this The object that holds the variable
830 * \param psz_name The name of the variable
831 * \param p_val Pointer to a vlc_value_t that will hold the variable's value
832 * after the function is finished
834 int var_Get( vlc_object_t
*p_this
, const char *psz_name
, vlc_value_t
*p_val
)
836 return var_GetChecked( p_this
, psz_name
, 0, p_val
);
839 #undef var_AddCallback
841 * Register a callback in a variable
843 * We store a function pointer that will be called upon variable
846 * \param p_this The object that holds the variable
847 * \param psz_name The name of the variable
848 * \param pf_callback The function pointer
849 * \param p_data A generic pointer that will be passed as the last
850 * argument to the callback function.
852 * \warning The callback function is run in the thread that calls var_Set on
853 * the variable. Use proper locking. This thread may not have much
854 * time to spare, so keep callback functions short.
856 int var_AddCallback( vlc_object_t
*p_this
, const char *psz_name
,
857 vlc_callback_t pf_callback
, void *p_data
)
860 callback_entry_t entry
;
864 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
866 entry
.pf_callback
= pf_callback
;
867 entry
.p_data
= p_data
;
869 vlc_mutex_lock( &p_priv
->var_lock
);
871 p_var
= Lookup( p_this
, psz_name
);
875 msg_Warn( p_this
, "Failed to add a callback to the non-existing "
876 "variable '%s'", psz_name
);
878 vlc_mutex_unlock( &p_priv
->var_lock
);
882 WaitUnused( p_this
, p_var
);
883 INSERT_ELEM( p_var
->p_entries
,
888 vlc_mutex_unlock( &p_priv
->var_lock
);
893 #undef var_DelCallback
895 * Remove a callback from a variable
897 * pf_callback and p_data have to be given again, because different objects
898 * might have registered the same callback function.
900 int var_DelCallback( vlc_object_t
*p_this
, const char *psz_name
,
901 vlc_callback_t pf_callback
, void *p_data
)
906 bool b_found_similar
= false;
911 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
913 vlc_mutex_lock( &p_priv
->var_lock
);
915 p_var
= Lookup( p_this
, psz_name
);
918 vlc_mutex_unlock( &p_priv
->var_lock
);
922 WaitUnused( p_this
, p_var
);
924 for( i_entry
= p_var
->i_entries
; i_entry
-- ; )
926 if( p_var
->p_entries
[i_entry
].pf_callback
== pf_callback
927 && p_var
->p_entries
[i_entry
].p_data
== p_data
)
932 else if( p_var
->p_entries
[i_entry
].pf_callback
== pf_callback
)
933 b_found_similar
= true;
940 if( b_found_similar
)
941 fprintf( stderr
, "Calling var_DelCallback for '%s' with the same "
942 "function but not the same data.", psz_name
);
945 vlc_mutex_unlock( &p_priv
->var_lock
);
949 REMOVE_ELEM( p_var
->p_entries
, p_var
->i_entries
, i_entry
);
951 vlc_mutex_unlock( &p_priv
->var_lock
);
956 #undef var_TriggerCallback
958 * Trigger callback on a variable
960 * \param p_this The object that hold the variable
961 * \param psz_name The name of the variable
963 int var_TriggerCallback( vlc_object_t
*p_this
, const char *psz_name
)
970 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
972 vlc_mutex_lock( &p_priv
->var_lock
);
974 p_var
= Lookup( p_this
, psz_name
);
977 vlc_mutex_unlock( &p_priv
->var_lock
);
981 WaitUnused( p_this
, p_var
);
983 /* Deal with callbacks. Tell we're in a callback, release the lock,
984 * call stored functions, retake the lock. */
985 i_ret
= TriggerCallback( p_this
, p_var
, psz_name
, p_var
->val
);
987 vlc_mutex_unlock( &p_priv
->var_lock
);
991 /** Parse a stringified option
992 * This function parse a string option and create the associated object
994 * The option must be of the form "[no[-]]foo[=bar]" where foo is the
995 * option name and bar is the value of the option.
996 * \param p_obj the object in which the variable must be created
997 * \param psz_option the option to parse
998 * \param trusted whether the option is set by a trusted input or not
1001 void var_OptionParse( vlc_object_t
*p_obj
, const char *psz_option
,
1004 char *psz_name
, *psz_value
;
1006 bool b_isno
= false;
1009 val
.psz_string
= NULL
;
1011 /* It's too much of a hassle to remove the ':' when we parse
1012 * the cmd line :) */
1013 if( psz_option
[0] == ':' )
1016 if( !psz_option
[0] )
1019 psz_name
= strdup( psz_option
);
1020 if( psz_name
== NULL
)
1023 psz_value
= strchr( psz_name
, '=' );
1024 if( psz_value
!= NULL
)
1025 *psz_value
++ = '\0';
1027 /* FIXME: :programs should be handled generically */
1028 if( !strcmp( psz_name
, "programs" ) )
1029 i_type
= VLC_VAR_LIST
;
1031 i_type
= config_GetType( p_obj
, psz_name
);
1033 if( !i_type
&& !psz_value
)
1035 /* check for "no-foo" or "nofoo" */
1036 if( !strncmp( psz_name
, "no-", 3 ) )
1038 memmove( psz_name
, psz_name
+ 3, strlen(psz_name
) + 1 - 3 );
1040 else if( !strncmp( psz_name
, "no", 2 ) )
1042 memmove( psz_name
, psz_name
+ 2, strlen(psz_name
) + 1 - 2 );
1044 else goto cleanup
; /* Option doesn't exist */
1047 i_type
= config_GetType( p_obj
, psz_name
);
1049 if( !i_type
) goto cleanup
; /* Option doesn't exist */
1051 if( ( i_type
!= VLC_VAR_BOOL
) &&
1052 ( !psz_value
|| !*psz_value
) ) goto cleanup
; /* Invalid value */
1054 /* check if option is unsafe */
1057 module_config_t
*p_config
= config_FindConfig( p_obj
, psz_name
);
1058 if( !p_config
|| !p_config
->b_safe
)
1060 msg_Err( p_obj
, "unsafe option \"%s\" has been ignored for "
1061 "security reasons", psz_name
);
1067 /* Create the variable in the input object.
1068 * Children of the input object will be able to retreive this value
1069 * thanks to the inheritance property of the object variables. */
1070 var_Create( p_obj
, psz_name
, i_type
);
1075 val
.b_bool
= !b_isno
;
1078 case VLC_VAR_INTEGER
:
1079 val
.i_int
= strtol( psz_value
, NULL
, 0 );
1083 val
.f_float
= us_atof( psz_value
);
1086 case VLC_VAR_STRING
:
1087 case VLC_VAR_MODULE
:
1089 case VLC_VAR_DIRECTORY
:
1090 val
.psz_string
= psz_value
;
1095 char *psz_orig
, *psz_var
;
1096 vlc_list_t
*p_list
= malloc(sizeof(vlc_list_t
));
1097 val
.p_list
= p_list
;
1098 p_list
->i_count
= 0;
1100 psz_var
= psz_orig
= strdup(psz_value
);
1101 while( psz_var
&& *psz_var
)
1103 char *psz_item
= psz_var
;
1105 while( *psz_var
&& *psz_var
!= ',' ) psz_var
++;
1106 if( *psz_var
== ',' )
1111 val2
.i_int
= strtol( psz_item
, NULL
, 0 );
1112 INSERT_ELEM( p_list
->p_values
, p_list
->i_count
,
1113 p_list
->i_count
, val2
);
1114 /* p_list->i_count is incremented twice by INSERT_ELEM */
1116 INSERT_ELEM( p_list
->pi_types
, p_list
->i_count
,
1117 p_list
->i_count
, VLC_VAR_INTEGER
);
1127 var_Set( p_obj
, psz_name
, val
);
1129 /* If that's a list, remove all elements allocated */
1130 if( i_type
== VLC_VAR_LIST
)
1138 /* Following functions are local */
1141 * Waits until the variable is inactive (i.e. not executing a callback)
1143 static void WaitUnused( vlc_object_t
*p_this
, variable_t
*p_var
)
1145 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
1147 mutex_cleanup_push( &p_priv
->var_lock
);
1148 while( p_var
->b_incallback
)
1149 vlc_cond_wait( &p_priv
->var_wait
, &p_priv
->var_lock
);
1153 /*****************************************************************************
1154 * CheckValue: check that a value is valid wrt. a variable
1155 *****************************************************************************
1156 * This function checks p_val's value against p_var's limitations such as
1157 * minimal and maximal value, step, in-list position, and modifies p_val if
1159 ****************************************************************************/
1160 static void CheckValue ( variable_t
*p_var
, vlc_value_t
*p_val
)
1162 /* Check that our variable is in the list */
1163 if( p_var
->i_type
& VLC_VAR_HASCHOICE
&& p_var
->choices
.i_count
)
1167 /* This list is not sorted so go throug it (this is a small list) */
1168 for( i
= p_var
->choices
.i_count
; i
-- ; )
1170 if( p_var
->ops
->pf_cmp( *p_val
, p_var
->choices
.p_values
[i
] ) == 0 )
1176 /* If not found, change it to anything vaguely valid */
1179 /* Free the old variable, get the new one, dup it */
1180 p_var
->ops
->pf_free( p_val
);
1181 *p_val
= p_var
->choices
.p_values
[p_var
->i_default
>= 0
1182 ? p_var
->i_default
: 0 ];
1183 p_var
->ops
->pf_dup( p_val
);
1187 /* Check that our variable is within the bounds */
1188 switch( p_var
->i_type
& VLC_VAR_TYPE
)
1190 case VLC_VAR_INTEGER
:
1191 if( p_var
->i_type
& VLC_VAR_HASSTEP
&& p_var
->step
.i_int
1192 && (p_val
->i_int
% p_var
->step
.i_int
) )
1194 p_val
->i_int
= (p_val
->i_int
+ (p_var
->step
.i_int
/ 2))
1195 / p_var
->step
.i_int
* p_var
->step
.i_int
;
1197 if( p_var
->i_type
& VLC_VAR_HASMIN
1198 && p_val
->i_int
< p_var
->min
.i_int
)
1200 p_val
->i_int
= p_var
->min
.i_int
;
1202 if( p_var
->i_type
& VLC_VAR_HASMAX
1203 && p_val
->i_int
> p_var
->max
.i_int
)
1205 p_val
->i_int
= p_var
->max
.i_int
;
1209 if( p_var
->i_type
& VLC_VAR_HASSTEP
&& p_var
->step
.f_float
)
1211 float f_round
= p_var
->step
.f_float
* (float)(int)( 0.5 +
1212 p_val
->f_float
/ p_var
->step
.f_float
);
1213 if( p_val
->f_float
!= f_round
)
1215 p_val
->f_float
= f_round
;
1218 if( p_var
->i_type
& VLC_VAR_HASMIN
1219 && p_val
->f_float
< p_var
->min
.f_float
)
1221 p_val
->f_float
= p_var
->min
.f_float
;
1223 if( p_var
->i_type
& VLC_VAR_HASMAX
1224 && p_val
->f_float
> p_var
->max
.f_float
)
1226 p_val
->f_float
= p_var
->max
.f_float
;
1236 * Finds the value of a variable. If the specified object does not hold a
1237 * variable with the specified name, try the parent object, and iterate until
1238 * the top of the tree. If no match is found, the value is read from the
1241 int var_Inherit( vlc_object_t
*p_this
, const char *psz_name
, int i_type
,
1242 vlc_value_t
*p_val
)
1245 if (p_this
!= VLC_OBJECT(p_this
->p_libvlc
)
1246 && unlikely(p_this
->p_parent
== NULL
))
1248 msg_Info (p_this
, "%s(%s) on detached object", __func__
, psz_name
);
1252 i_type
&= VLC_VAR_CLASS
;
1253 for( vlc_object_t
*obj
= p_this
; obj
!= NULL
; obj
= obj
->p_parent
)
1255 if( var_GetChecked( obj
, psz_name
, i_type
, p_val
) == VLC_SUCCESS
)
1258 if (obj
!= p_this
&& obj
!= VLC_OBJECT(p_this
->p_libvlc
)
1259 && unlikely(obj
->p_parent
== NULL
))
1261 msg_Info (p_this
, "%s(%s) on detached tree [%p] %s", __func__
,
1262 psz_name
, obj
, obj
->psz_object_type
);
1268 /* else take value from config */
1269 switch( i_type
& VLC_VAR_CLASS
)
1271 case VLC_VAR_STRING
:
1272 p_val
->psz_string
= config_GetPsz( p_this
, psz_name
);
1273 if( !p_val
->psz_string
) p_val
->psz_string
= strdup("");
1276 p_val
->f_float
= config_GetFloat( p_this
, psz_name
);
1278 case VLC_VAR_INTEGER
:
1279 p_val
->i_int
= config_GetInt( p_this
, psz_name
);
1282 p_val
->b_bool
= config_GetInt( p_this
, psz_name
);
1286 char *psz_orig
, *psz_var
;
1287 vlc_list_t
*p_list
= malloc(sizeof(vlc_list_t
));
1288 p_val
->p_list
= p_list
;
1289 p_list
->i_count
= 0;
1291 psz_var
= psz_orig
= config_GetPsz( p_this
, psz_name
);
1292 while( psz_var
&& *psz_var
)
1294 char *psz_item
= psz_var
;
1296 while( *psz_var
&& *psz_var
!= ',' ) psz_var
++;
1297 if( *psz_var
== ',' )
1302 val
.i_int
= strtol( psz_item
, NULL
, 0 );
1303 INSERT_ELEM( p_list
->p_values
, p_list
->i_count
,
1304 p_list
->i_count
, val
);
1305 /* p_list->i_count is incremented twice by INSERT_ELEM */
1307 INSERT_ELEM( p_list
->pi_types
, p_list
->i_count
,
1308 p_list
->i_count
, VLC_VAR_INTEGER
);
1314 msg_Warn( p_this
, "Could not inherit value for var %s "
1315 "from config. Invalid Type", psz_name
);
1318 /*msg_Dbg( p_this, "Inherited value for var %s from config", psz_name );*/
1323 /**********************************************************************
1324 * Trigger the callbacks.
1325 * Tell we're in a callback, release the lock, call stored functions,
1327 **********************************************************************/
1328 static int TriggerCallback( vlc_object_t
*p_this
, variable_t
*p_var
,
1329 const char *psz_name
, vlc_value_t oldval
)
1333 int i_entries
= p_var
->i_entries
;
1334 if( i_entries
== 0 )
1337 callback_entry_t
*p_entries
= p_var
->p_entries
;
1338 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
1340 assert( !p_var
->b_incallback
);
1341 p_var
->b_incallback
= true;
1342 vlc_mutex_unlock( &p_priv
->var_lock
);
1344 /* The real calls */
1345 for( ; i_entries
-- ; )
1347 p_entries
[i_entries
].pf_callback( p_this
, psz_name
, oldval
, p_var
->val
,
1348 p_entries
[i_entries
].p_data
);
1351 vlc_mutex_lock( &p_priv
->var_lock
);
1352 p_var
->b_incallback
= false;
1353 vlc_cond_broadcast( &p_priv
->var_wait
);
1359 /**********************************************************************
1360 * Execute a var command on an object identified by its name
1361 **********************************************************************/
1362 int var_Command( vlc_object_t
*p_this
, const char *psz_name
,
1363 const char *psz_cmd
, const char *psz_arg
, char **psz_msg
)
1365 vlc_object_t
*p_obj
= vlc_object_find_name( p_this
->p_libvlc
,
1366 psz_name
, FIND_CHILD
);
1372 *psz_msg
= strdup( "Unknown destination object." );
1376 i_type
= var_Type( p_obj
, psz_cmd
);
1377 if( !( i_type
&VLC_VAR_ISCOMMAND
) )
1379 vlc_object_release( p_obj
);
1381 *psz_msg
= strdup( "Variable doesn't exist or isn't a command." );
1382 return VLC_EGENERIC
;
1385 i_type
&= VLC_VAR_CLASS
;
1388 case VLC_VAR_INTEGER
:
1389 i_ret
= var_SetInteger( p_obj
, psz_cmd
, atoi( psz_arg
) );
1392 i_ret
= var_SetFloat( p_obj
, psz_cmd
, us_atof( psz_arg
) );
1394 case VLC_VAR_STRING
:
1395 i_ret
= var_SetString( p_obj
, psz_cmd
, psz_arg
);
1398 i_ret
= var_SetBool( p_obj
, psz_cmd
, atoi( psz_arg
) );
1401 i_ret
= VLC_EGENERIC
;
1405 vlc_object_release( p_obj
);
1409 if( asprintf( psz_msg
, "%s on object %s returned %i (%s)",
1410 psz_cmd
, psz_name
, i_ret
, vlc_error( i_ret
) ) == -1)
1419 * Free a list and the associated strings
1420 * @param p_val: the list variable
1421 * @param p_val2: the variable associated or NULL
1423 void var_FreeList( vlc_value_t
*p_val
, vlc_value_t
*p_val2
)
1426 if( p_val2
&& p_val2
->p_list
)
1428 for( int i
= 0; i
< p_val2
->p_list
->i_count
; i
++ )
1429 free( p_val2
->p_list
->p_values
[i
].psz_string
);
1430 if( p_val2
->p_list
->i_count
)
1432 free( p_val2
->p_list
->p_values
);
1433 free( p_val2
->p_list
->pi_types
);
1435 free( p_val2
->p_list
);