variables.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:47k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * variables.c: routines for object variables handling
  3.  *****************************************************************************
  4.  * Copyright (C) 2002-2006 the VideoLAN team
  5.  * $Id: f045a51899f8a32d09dca3bc989d40eb9a5960a7 $
  6.  *
  7.  * Authors: Samuel Hocevar <sam@zoy.org>
  8.  *
  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.
  13.  *
  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.
  18.  *
  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.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <vlc_charset.h>
  31. #include "variables.h"
  32. #include "libvlc.h"
  33. #include "vlc_interface.h"
  34. #include <assert.h>
  35. /*****************************************************************************
  36.  * Private types
  37.  *****************************************************************************/
  38. struct callback_entry_t
  39. {
  40.     vlc_callback_t pf_callback;
  41.     void *         p_data;
  42. };
  43. /*****************************************************************************
  44.  * Local comparison functions, returns 0 if v == w, < 0 if v < w, > 0 if v > w
  45.  *****************************************************************************/
  46. 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; }
  47. 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; }
  48. static int CmpTime( vlc_value_t v, vlc_value_t w )
  49. {
  50.     return v.i_time == w.i_time ? 0 : v.i_time > w.i_time ? 1 : -1;
  51. }
  52. static int CmpString( vlc_value_t v, vlc_value_t w )
  53. {
  54.     if( !v.psz_string )
  55.         return !w.psz_string ? 0 : -1;
  56.     else
  57.         return !w.psz_string ? 1 : strcmp( v.psz_string, w.psz_string );
  58. }
  59. 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; }
  60. 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; }
  61. /*****************************************************************************
  62.  * Local duplication functions, and local deallocation functions
  63.  *****************************************************************************/
  64. static void DupDummy( vlc_value_t *p_val ) { (void)p_val; /* unused */ }
  65. static void DupString( vlc_value_t *p_val )
  66. {
  67.     p_val->psz_string = strdup( p_val->psz_string ? p_val->psz_string :  "" );
  68. }
  69. static void DupList( vlc_value_t *p_val )
  70. {
  71.     int i;
  72.     vlc_list_t *p_list = malloc( sizeof(vlc_list_t) );
  73.     p_list->i_count = p_val->p_list->i_count;
  74.     if( p_val->p_list->i_count )
  75.     {
  76.         p_list->p_values = malloc( p_list->i_count * sizeof(vlc_value_t) );
  77.         p_list->pi_types = malloc( p_list->i_count * sizeof(int) );
  78.     }
  79.     else
  80.     {
  81.         p_list->p_values = NULL;
  82.         p_list->pi_types = NULL;
  83.     }
  84.     for( i = 0; i < p_list->i_count; i++ )
  85.     {
  86.         p_list->p_values[i] = p_val->p_list->p_values[i];
  87.         p_list->pi_types[i] = p_val->p_list->pi_types[i];
  88.         switch( p_val->p_list->pi_types[i] & VLC_VAR_CLASS )
  89.         {
  90.         case VLC_VAR_STRING:
  91.             DupString( &p_list->p_values[i] );
  92.             break;
  93.         default:
  94.             break;
  95.         }
  96.     }
  97.     p_val->p_list = p_list;
  98. }
  99. static void FreeDummy( vlc_value_t *p_val ) { (void)p_val; /* unused */ }
  100. static void FreeString( vlc_value_t *p_val ) { free( p_val->psz_string ); }
  101. static void FreeMutex( vlc_value_t *p_val ) { vlc_mutex_destroy( (vlc_mutex_t*)p_val->p_address ); free( p_val->p_address ); }
  102. static void FreeList( vlc_value_t *p_val )
  103. {
  104.     int i;
  105.     for( i = 0; i < p_val->p_list->i_count; i++ )
  106.     {
  107.         switch( p_val->p_list->pi_types[i] & VLC_VAR_CLASS )
  108.         {
  109.         case VLC_VAR_STRING:
  110.             FreeString( &p_val->p_list->p_values[i] );
  111.             break;
  112.         case VLC_VAR_MUTEX:
  113.             FreeMutex( &p_val->p_list->p_values[i] );
  114.             break;
  115.         default:
  116.             break;
  117.         }
  118.     }
  119.     if( p_val->p_list->i_count )
  120.     {
  121.         free( p_val->p_list->p_values );
  122.         free( p_val->p_list->pi_types );
  123.     }
  124.     free( p_val->p_list );
  125. }
  126. static const struct variable_ops_t
  127. void_ops   = { NULL,       DupDummy,  FreeDummy,  },
  128. addr_ops   = { CmpAddress, DupDummy,  FreeDummy,  },
  129. bool_ops   = { CmpBool,    DupDummy,  FreeDummy,  },
  130. float_ops  = { CmpFloat,   DupDummy,  FreeDummy,  },
  131. int_ops    = { CmpInt,     DupDummy,  FreeDummy,  },
  132. list_ops   = { CmpAddress, DupList,   FreeList,   },
  133. mutex_ops  = { CmpAddress, DupDummy,  FreeMutex,  },
  134. string_ops = { CmpString,  DupString, FreeString, },
  135. time_ops   = { CmpTime,    DupDummy,  FreeDummy,  };
  136. /*****************************************************************************
  137.  * Local prototypes
  138.  *****************************************************************************/
  139. static int      GetUnused   ( vlc_object_t *, const char * );
  140. static uint32_t HashString  ( const char * );
  141. static int      Insert      ( variable_t *, int, const char * );
  142. static int      InsertInner ( variable_t *, int, uint32_t );
  143. static int      Lookup      ( variable_t *, size_t, const char * );
  144. static void     CheckValue  ( variable_t *, vlc_value_t * );
  145. static int      InheritValue( vlc_object_t *, const char *, vlc_value_t *,
  146.                               int );
  147. /**
  148.  * Initialize a vlc variable
  149.  *
  150.  * We hash the given string and insert it into the sorted list. The insertion
  151.  * may require slow memory copies, but think about what we gain in the log(n)
  152.  * lookup phase when setting/getting the variable value!
  153.  *
  154.  * param p_this The object in which to create the variable
  155.  * param psz_name The name of the variable
  156.  * param i_type The variables type. Must be one of ref var_type combined with
  157.  *               zero or more ref var_flags
  158.  */
  159. int __var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
  160. {
  161.     int i_new;
  162.     variable_t *p_var;
  163.     static vlc_list_t dummy_null_list = {0, NULL, NULL};
  164.     vlc_object_internals_t *p_priv = vlc_internals( p_this );
  165.     vlc_mutex_lock( &p_priv->var_lock );
  166.     /* FIXME: if the variable already exists, we don't duplicate it. But we
  167.      * duplicate the lookups. It's not that serious, but if anyone finds some
  168.      * time to rework Insert() so that only one lookup has to be done, feel
  169.      * free to do so. */
  170.     i_new = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
  171.     if( i_new >= 0 )
  172.     {
  173.         /* If the types differ, variable creation failed. */
  174.         if( (i_type & ~(VLC_VAR_DOINHERIT|VLC_VAR_ISCOMMAND)) != p_priv->p_vars[i_new].i_type )
  175.         {
  176.             vlc_mutex_unlock( &p_priv->var_lock );
  177.             return VLC_EBADVAR;
  178.         }
  179.         p_priv->p_vars[i_new].i_usage++;
  180.         if( i_type & VLC_VAR_ISCOMMAND )
  181.             p_priv->p_vars[i_new].i_type |= VLC_VAR_ISCOMMAND;
  182.         vlc_mutex_unlock( &p_priv->var_lock );
  183.         return VLC_SUCCESS;
  184.     }
  185.     i_new = Insert( p_priv->p_vars, p_priv->i_vars, psz_name );
  186.     if( (p_priv->i_vars & 15) == 15 )
  187.     {
  188.         p_priv->p_vars = realloc( p_priv->p_vars,
  189.                                   (p_priv->i_vars+17) * sizeof(variable_t) );
  190.     }
  191.     memmove( p_priv->p_vars + i_new + 1,
  192.              p_priv->p_vars + i_new,
  193.              (p_priv->i_vars - i_new) * sizeof(variable_t) );
  194.     p_priv->i_vars++;
  195.     p_var = &p_priv->p_vars[i_new];
  196.     memset( p_var, 0, sizeof(*p_var) );
  197.     p_var->i_hash = HashString( psz_name );
  198.     p_var->psz_name = strdup( psz_name );
  199.     p_var->psz_text = NULL;
  200.     p_var->i_type = i_type & ~VLC_VAR_DOINHERIT;
  201.     memset( &p_var->val, 0, sizeof(vlc_value_t) );
  202.     p_var->i_usage = 1;
  203.     p_var->i_default = -1;
  204.     p_var->choices.i_count = 0;
  205.     p_var->choices.p_values = NULL;
  206.     p_var->choices_text.i_count = 0;
  207.     p_var->choices_text.p_values = NULL;
  208.     p_var->b_incallback = false;
  209.     p_var->i_entries = 0;
  210.     p_var->p_entries = NULL;
  211.     /* Always initialize the variable, even if it is a list variable; this
  212.      * will lead to errors if the variable is not initialized, but it will
  213.      * not cause crashes in the variable handling. */
  214.     switch( i_type & VLC_VAR_CLASS )
  215.     {
  216.         case VLC_VAR_BOOL:
  217.             p_var->ops = &bool_ops;
  218.             p_var->val.b_bool = false;
  219.             break;
  220.         case VLC_VAR_INTEGER:
  221.             p_var->ops = &int_ops;
  222.             p_var->val.i_int = 0;
  223.             break;
  224.         case VLC_VAR_STRING:
  225.             p_var->ops = &string_ops;
  226.             p_var->val.psz_string = NULL;
  227.             break;
  228.         case VLC_VAR_FLOAT:
  229.             p_var->ops = &float_ops;
  230.             p_var->val.f_float = 0.0;
  231.             break;
  232.         case VLC_VAR_TIME:
  233.             p_var->ops = &time_ops;
  234.             p_var->val.i_time = 0;
  235.             break;
  236.         case VLC_VAR_ADDRESS:
  237.             p_var->ops = &addr_ops;
  238.             p_var->val.p_address = NULL;
  239.             break;
  240.         case VLC_VAR_MUTEX:
  241.             p_var->ops = &mutex_ops;
  242.             p_var->val.p_address = malloc( sizeof(vlc_mutex_t) );
  243.             vlc_mutex_init( (vlc_mutex_t*)p_var->val.p_address );
  244.             break;
  245.         case VLC_VAR_LIST:
  246.             p_var->ops = &list_ops;
  247.             p_var->val.p_list = &dummy_null_list;
  248.             break;
  249.         default:
  250.             p_var->ops = &void_ops;
  251.             break;
  252.     }
  253.     /* Duplicate the default data we stored. */
  254.     p_var->ops->pf_dup( &p_var->val );
  255.     if( i_type & VLC_VAR_DOINHERIT )
  256.     {
  257.         vlc_value_t val;
  258.         if( InheritValue( p_this, psz_name, &val, p_var->i_type )
  259.             == VLC_SUCCESS )
  260.         {
  261.             /* Free data if needed */
  262.             p_var->ops->pf_free( &p_var->val );
  263.             /* Set the variable */
  264.             p_var->val = val;
  265.             if( i_type & VLC_VAR_HASCHOICE )
  266.             {
  267.                 /* We must add the inherited value to our choice list */
  268.                 p_var->i_default = 0;
  269.                 INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count,
  270.                              0, val );
  271.                 INSERT_ELEM( p_var->choices_text.p_values,
  272.                              p_var->choices_text.i_count, 0, val );
  273.                 p_var->ops->pf_dup( &p_var->choices.p_values[0] );
  274.                 p_var->choices_text.p_values[0].psz_string = NULL;
  275.             }
  276.         }
  277.     }
  278.     vlc_mutex_unlock( &p_priv->var_lock );
  279.     return VLC_SUCCESS;
  280. }
  281. /**
  282.  * Destroy a vlc variable
  283.  *
  284.  * Look for the variable and destroy it if it is found. As in var_Create we
  285.  * do a call to memmove() but we have performance counterparts elsewhere.
  286.  *
  287.  * param p_this The object that holds the variable
  288.  * param psz_name The name of the variable
  289.  */
  290. int __var_Destroy( vlc_object_t *p_this, const char *psz_name )
  291. {
  292.     int i_var, i;
  293.     variable_t *p_var;
  294.     vlc_object_internals_t *p_priv = vlc_internals( p_this );
  295.     vlc_mutex_lock( &p_priv->var_lock );
  296.     i_var = GetUnused( p_this, psz_name );
  297.     if( i_var < 0 )
  298.     {
  299.         vlc_mutex_unlock( &p_priv->var_lock );
  300.         return i_var;
  301.     }
  302.     p_var = &p_priv->p_vars[i_var];
  303.     if( p_var->i_usage > 1 )
  304.     {
  305.         p_var->i_usage--;
  306.         vlc_mutex_unlock( &p_priv->var_lock );
  307.         return VLC_SUCCESS;
  308.     }
  309.     /* Free value if needed */
  310.     p_var->ops->pf_free( &p_var->val );
  311.     /* Free choice list if needed */
  312.     if( p_var->choices.i_count )
  313.     {
  314.         for( i = 0 ; i < p_var->choices.i_count ; i++ )
  315.         {
  316.             p_var->ops->pf_free( &p_var->choices.p_values[i] );
  317.             free( p_var->choices_text.p_values[i].psz_string );
  318.         }
  319.         free( p_var->choices.p_values );
  320.         free( p_var->choices_text.p_values );
  321.     }
  322.     /* Free callbacks if needed */
  323.     if( p_var->p_entries )
  324.     {
  325.         free( p_var->p_entries );
  326.     }
  327.     free( p_var->psz_name );
  328.     free( p_var->psz_text );
  329.     memmove( p_priv->p_vars + i_var,
  330.              p_priv->p_vars + i_var + 1,
  331.              (p_priv->i_vars - i_var - 1) * sizeof(variable_t) );
  332.     if( (p_priv->i_vars & 15) == 0 )
  333.     {
  334.         p_priv->p_vars = realloc( p_priv->p_vars,
  335.                           (p_priv->i_vars) * sizeof( variable_t ) );
  336.     }
  337.     p_priv->i_vars--;
  338.     vlc_mutex_unlock( &p_priv->var_lock );
  339.     return VLC_SUCCESS;
  340. }
  341. /**
  342.  * Perform an action on a variable
  343.  *
  344.  * param p_this The object that holds the variable
  345.  * param psz_name The name of the variable
  346.  * param i_action The action to perform. Must be one of ref var_action
  347.  * param p_val First action parameter
  348.  * param p_val2 Second action parameter
  349.  */
  350. int __var_Change( vlc_object_t *p_this, const char *psz_name,
  351.                   int i_action, vlc_value_t *p_val, vlc_value_t *p_val2 )
  352. {
  353.     int i_var, i;
  354.     variable_t *p_var;
  355.     vlc_value_t oldval;
  356.     vlc_object_internals_t *p_priv = vlc_internals( p_this );
  357.     vlc_mutex_lock( &p_priv->var_lock );
  358.     i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
  359.     if( i_var < 0 )
  360.     {
  361.         vlc_mutex_unlock( &p_priv->var_lock );
  362.         return VLC_ENOVAR;
  363.     }
  364.     p_var = &p_priv->p_vars[i_var];
  365.     switch( i_action )
  366.     {
  367.         case VLC_VAR_SETMIN:
  368.             if( p_var->i_type & VLC_VAR_HASMIN )
  369.             {
  370.                 p_var->ops->pf_free( &p_var->min );
  371.             }
  372.             p_var->i_type |= VLC_VAR_HASMIN;
  373.             p_var->min = *p_val;
  374.             p_var->ops->pf_dup( &p_var->min );
  375.             CheckValue( p_var, &p_var->val );
  376.             break;
  377.         case VLC_VAR_GETMIN:
  378.             if( p_var->i_type & VLC_VAR_HASMIN )
  379.             {
  380.                 *p_val = p_var->min;
  381.             }
  382.             break;
  383.         case VLC_VAR_SETMAX:
  384.             if( p_var->i_type & VLC_VAR_HASMAX )
  385.             {
  386.                 p_var->ops->pf_free( &p_var->max );
  387.             }
  388.             p_var->i_type |= VLC_VAR_HASMAX;
  389.             p_var->max = *p_val;
  390.             p_var->ops->pf_dup( &p_var->max );
  391.             CheckValue( p_var, &p_var->val );
  392.             break;
  393.         case VLC_VAR_GETMAX:
  394.             if( p_var->i_type & VLC_VAR_HASMAX )
  395.             {
  396.                 *p_val = p_var->max;
  397.             }
  398.             break;
  399.         case VLC_VAR_SETSTEP:
  400.             if( p_var->i_type & VLC_VAR_HASSTEP )
  401.             {
  402.                 p_var->ops->pf_free( &p_var->step );
  403.             }
  404.             p_var->i_type |= VLC_VAR_HASSTEP;
  405.             p_var->step = *p_val;
  406.             p_var->ops->pf_dup( &p_var->step );
  407.             CheckValue( p_var, &p_var->val );
  408.             break;
  409.         case VLC_VAR_GETSTEP:
  410.             if( p_var->i_type & VLC_VAR_HASSTEP )
  411.             {
  412.                 *p_val = p_var->step;
  413.             }
  414.             break;
  415.         case VLC_VAR_ADDCHOICE:
  416.             i = p_var->choices.i_count;
  417.             INSERT_ELEM( p_var->choices.p_values, p_var->choices.i_count,
  418.                          i, *p_val );
  419.             INSERT_ELEM( p_var->choices_text.p_values,
  420.                          p_var->choices_text.i_count, i, *p_val );
  421.             p_var->ops->pf_dup( &p_var->choices.p_values[i] );
  422.             p_var->choices_text.p_values[i].psz_string =
  423.                 ( p_val2 && p_val2->psz_string ) ?
  424.                 strdup( p_val2->psz_string ) : NULL;
  425.             CheckValue( p_var, &p_var->val );
  426.             break;
  427.         case VLC_VAR_DELCHOICE:
  428.             for( i = 0 ; i < p_var->choices.i_count ; i++ )
  429.             {
  430.                 if( p_var->ops->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 )
  431.                 {
  432.                     break;
  433.                 }
  434.             }
  435.             if( i == p_var->choices.i_count )
  436.             {
  437.                 /* Not found */
  438.                 vlc_mutex_unlock( &p_priv->var_lock );
  439.                 return VLC_EGENERIC;
  440.             }
  441.             if( p_var->i_default > i )
  442.             {
  443.                 p_var->i_default--;
  444.             }
  445.             else if( p_var->i_default == i )
  446.             {
  447.                 p_var->i_default = -1;
  448.             }
  449.             p_var->ops->pf_free( &p_var->choices.p_values[i] );
  450.             free( p_var->choices_text.p_values[i].psz_string );
  451.             REMOVE_ELEM( p_var->choices.p_values, p_var->choices.i_count, i );
  452.             REMOVE_ELEM( p_var->choices_text.p_values,
  453.                          p_var->choices_text.i_count, i );
  454.             CheckValue( p_var, &p_var->val );
  455.             break;
  456.         case VLC_VAR_CHOICESCOUNT:
  457.             p_val->i_int = p_var->choices.i_count;
  458.             break;
  459.         case VLC_VAR_CLEARCHOICES:
  460.             for( i = 0 ; i < p_var->choices.i_count ; i++ )
  461.             {
  462.                 p_var->ops->pf_free( &p_var->choices.p_values[i] );
  463.             }
  464.             for( i = 0 ; i < p_var->choices_text.i_count ; i++ )
  465.                 free( p_var->choices_text.p_values[i].psz_string );
  466.             if( p_var->choices.i_count ) free( p_var->choices.p_values );
  467.             if( p_var->choices_text.i_count ) free( p_var->choices_text.p_values );
  468.             p_var->choices.i_count = 0;
  469.             p_var->choices.p_values = NULL;
  470.             p_var->choices_text.i_count = 0;
  471.             p_var->choices_text.p_values = NULL;
  472.             p_var->i_default = -1;
  473.             break;
  474.         case VLC_VAR_SETDEFAULT:
  475.             /* FIXME: the list is sorted, dude. Use something cleverer. */
  476.             for( i = 0 ; i < p_var->choices.i_count ; i++ )
  477.             {
  478.                 if( p_var->ops->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 )
  479.                 {
  480.                     break;
  481.                 }
  482.             }
  483.             if( i == p_var->choices.i_count )
  484.             {
  485.                 /* Not found */
  486.                 break;
  487.             }
  488.             p_var->i_default = i;
  489.             CheckValue( p_var, &p_var->val );
  490.             break;
  491.         case VLC_VAR_SETVALUE:
  492.             /* Duplicate data if needed */
  493.             p_var->ops->pf_dup( p_val );
  494.             /* Backup needed stuff */
  495.             oldval = p_var->val;
  496.             /* Check boundaries and list */
  497.             CheckValue( p_var, p_val );
  498.             /* Set the variable */
  499.             p_var->val = *p_val;
  500.             /* Free data if needed */
  501.             p_var->ops->pf_free( &oldval );
  502.             break;
  503.         case VLC_VAR_GETCHOICES:
  504.         case VLC_VAR_GETLIST:
  505.             p_val->p_list = malloc( sizeof(vlc_list_t) );
  506.             if( p_val2 ) p_val2->p_list = malloc( sizeof(vlc_list_t) );
  507.             if( p_var->choices.i_count )
  508.             {
  509.                 p_val->p_list->p_values = malloc( p_var->choices.i_count
  510.                                                   * sizeof(vlc_value_t) );
  511.                 p_val->p_list->pi_types = malloc( p_var->choices.i_count
  512.                                                   * sizeof(int) );
  513.                 if( p_val2 )
  514.                 {
  515.                     p_val2->p_list->p_values =
  516.                         malloc( p_var->choices.i_count * sizeof(vlc_value_t) );
  517.                     p_val2->p_list->pi_types =
  518.                         malloc( p_var->choices.i_count * sizeof(int) );
  519.                 }
  520.             }
  521.             p_val->p_list->i_count = p_var->choices.i_count;
  522.             if( p_val2 ) p_val2->p_list->i_count = p_var->choices.i_count;
  523.             for( i = 0 ; i < p_var->choices.i_count ; i++ )
  524.             {
  525.                 p_val->p_list->p_values[i] = p_var->choices.p_values[i];
  526.                 p_val->p_list->pi_types[i] = p_var->i_type;
  527.                 p_var->ops->pf_dup( &p_val->p_list->p_values[i] );
  528.                 if( p_val2 )
  529.                 {
  530.                     p_val2->p_list->p_values[i].psz_string =
  531.                         p_var->choices_text.p_values[i].psz_string ?
  532.                     strdup(p_var->choices_text.p_values[i].psz_string) : NULL;
  533.                     p_val2->p_list->pi_types[i] = VLC_VAR_STRING;
  534.                 }
  535.             }
  536.             break;
  537.         case VLC_VAR_FREELIST:
  538.             FreeList( p_val );
  539.             if( p_val2 && p_val2->p_list )
  540.             {
  541.                 for( i = 0; i < p_val2->p_list->i_count; i++ )
  542.                     free( p_val2->p_list->p_values[i].psz_string );
  543.                 if( p_val2->p_list->i_count )
  544.                 {
  545.                     free( p_val2->p_list->p_values );
  546.                     free( p_val2->p_list->pi_types );
  547.                 }
  548.                 free( p_val2->p_list );
  549.             }
  550.             break;
  551.         case VLC_VAR_SETTEXT:
  552.             free( p_var->psz_text );
  553.             if( p_val && p_val->psz_string )
  554.                 p_var->psz_text = strdup( p_val->psz_string );
  555.             else
  556.                 p_var->psz_text = NULL;
  557.             break;
  558.         case VLC_VAR_GETTEXT:
  559.             p_val->psz_string = NULL;
  560.             if( p_var->psz_text )
  561.             {
  562.                 p_val->psz_string = strdup( p_var->psz_text );
  563.             }
  564.             break;
  565.         case VLC_VAR_INHERITVALUE:
  566.             {
  567.                 vlc_value_t val;
  568.                 if( InheritValue( p_this,
  569.                                   p_val2 ? p_val2->psz_string :  psz_name,
  570.                                   &val, p_var->i_type )
  571.                     == VLC_SUCCESS )
  572.                 {
  573.                     /* Duplicate already done */
  574.                     /* Backup needed stuff */
  575.                     oldval = p_var->val;
  576.                     /* Check boundaries and list */
  577.                     CheckValue( p_var, &val );
  578.                     /* Set the variable */
  579.                     p_var->val = val;
  580.                     /* Free data if needed */
  581.                     p_var->ops->pf_free( &oldval );
  582.                 }
  583.                 if( p_val )
  584.                 {
  585.                     *p_val = p_var->val;
  586.                     p_var->ops->pf_dup( p_val );
  587.                 }
  588.             }
  589.             break;
  590.         case VLC_VAR_SETISCOMMAND:
  591.             p_var->i_type |= VLC_VAR_ISCOMMAND;
  592.             break;
  593.         default:
  594.             break;
  595.     }
  596.     vlc_mutex_unlock( &p_priv->var_lock );
  597.     return VLC_SUCCESS;
  598. }
  599. /**
  600.  * Request a variable's type
  601.  *
  602.  * return The variable type if it exists, or 0 if the
  603.  * variable could not be found.
  604.  * see ref var_type
  605.  */
  606. int __var_Type( vlc_object_t *p_this, const char *psz_name )
  607. {
  608.     int i_var, i_type;
  609.     vlc_object_internals_t *p_priv = vlc_internals( p_this );
  610.     vlc_mutex_lock( &p_priv->var_lock );
  611.     i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
  612.     if( i_var < 0 )
  613.     {
  614.         vlc_mutex_unlock( &p_priv->var_lock );
  615.         return 0;
  616.     }
  617.     i_type = p_priv->p_vars[i_var].i_type;
  618.     vlc_mutex_unlock( &p_priv->var_lock );
  619.     return i_type;
  620. }
  621. int var_SetChecked( vlc_object_t *p_this, const char *psz_name,
  622.                     int expected_type, vlc_value_t val )
  623. {
  624.     int i_var;
  625.     variable_t *p_var;
  626.     vlc_value_t oldval;
  627.     vlc_object_internals_t *p_priv = vlc_internals( p_this );
  628.     vlc_mutex_lock( &p_priv->var_lock );
  629.     i_var = GetUnused( p_this, psz_name );
  630.     if( i_var < 0 )
  631.     {
  632.         vlc_mutex_unlock( &p_priv->var_lock );
  633.         return i_var;
  634.     }
  635.     p_var = &p_priv->p_vars[i_var];
  636.     assert( (p_var->i_type & VLC_VAR_CLASS) == 0 || expected_type == 0 ||
  637.             (p_var->i_type & VLC_VAR_CLASS) == expected_type );
  638.     /* Duplicate data if needed */
  639.     p_var->ops->pf_dup( &val );
  640.     /* Backup needed stuff */
  641.     oldval = p_var->val;
  642.     /* Check boundaries and list */
  643.     CheckValue( p_var, &val );
  644.     /* Set the variable */
  645.     p_var->val = val;
  646.     /* Deal with callbacks. Tell we're in a callback, release the lock,
  647.      * call stored functions, retake the lock. */
  648.     if( p_var->i_entries )
  649.     {
  650.         int i_var;
  651.         int i_entries = p_var->i_entries;
  652.         callback_entry_t *p_entries = p_var->p_entries;
  653.         p_var->b_incallback = true;
  654.         vlc_mutex_unlock( &p_priv->var_lock );
  655.         /* The real calls */
  656.         for( ; i_entries-- ; )
  657.         {
  658.             p_entries[i_entries].pf_callback( p_this, psz_name, oldval, val,
  659.                                               p_entries[i_entries].p_data );
  660.         }
  661.         vlc_mutex_lock( &p_priv->var_lock );
  662.         i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
  663.         if( i_var < 0 )
  664.         {
  665.             msg_Err( p_this, "variable %s has disappeared", psz_name );
  666.             vlc_mutex_unlock( &p_priv->var_lock );
  667.             return VLC_ENOVAR;
  668.         }
  669.         p_var = &p_priv->p_vars[i_var];
  670.         p_var->b_incallback = false;
  671.         vlc_cond_broadcast( &p_priv->var_wait );
  672.     }
  673.     /* Free data if needed */
  674.     p_var->ops->pf_free( &oldval );
  675.     vlc_mutex_unlock( &p_priv->var_lock );
  676.     return VLC_SUCCESS;
  677. }
  678. /**
  679.  * Set a variable's value
  680.  *
  681.  * param p_this The object that hold the variable
  682.  * param psz_name The name of the variable
  683.  * param val the value to set
  684.  */
  685. int __var_Set( vlc_object_t *p_this, const char *psz_name, vlc_value_t val )
  686. {
  687.     return var_SetChecked( p_this, psz_name, 0, val );
  688. }
  689. int var_GetChecked( vlc_object_t *p_this, const char *psz_name,
  690.                     int expected_type, vlc_value_t *p_val )
  691. {
  692.     vlc_object_internals_t *p_priv = vlc_internals( p_this );
  693.     int i_var, err = VLC_SUCCESS;
  694.     vlc_mutex_lock( &p_priv->var_lock );
  695.     i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
  696.     if( i_var >= 0 )
  697.     {
  698.         variable_t *p_var = &p_priv->p_vars[i_var];
  699.         assert( (p_var->i_type & VLC_VAR_CLASS) == 0 || expected_type == 0 ||
  700.                 (p_var->i_type & VLC_VAR_CLASS) == expected_type );
  701.         /* Really get the variable */
  702.         *p_val = p_var->val;
  703.         /* Duplicate value if needed */
  704.         p_var->ops->pf_dup( p_val );
  705.     }
  706.     else
  707.         err = VLC_ENOVAR;
  708.     vlc_mutex_unlock( &p_priv->var_lock );
  709.     return err;
  710. }
  711. /**
  712.  * Get a variable's value
  713.  *
  714.  * param p_this The object that holds the variable
  715.  * param psz_name The name of the variable
  716.  * param p_val Pointer to a vlc_value_t that will hold the variable's value
  717.  *              after the function is finished
  718.  */
  719. int __var_Get( vlc_object_t *p_this, const char *psz_name, vlc_value_t *p_val )
  720. {
  721.     return var_GetChecked( p_this, psz_name, 0, p_val );
  722. }
  723. /**
  724.  * Register a callback in a variable
  725.  *
  726.  * We store a function pointer that will be called upon variable
  727.  * modification.
  728.  *
  729.  * param p_this The object that holds the variable
  730.  * param psz_name The name of the variable
  731.  * param pf_callback The function pointer
  732.  * param p_data A generic pointer that will be passed as the last
  733.  *               argument to the callback function.
  734.  *
  735.  * warning The callback function is run in the thread that calls var_Set on
  736.  *          the variable. Use proper locking. This thread may not have much
  737.  *          time to spare, so keep callback functions short.
  738.  */
  739. int __var_AddCallback( vlc_object_t *p_this, const char *psz_name,
  740.                        vlc_callback_t pf_callback, void *p_data )
  741. {
  742.     int i_var;
  743.     variable_t *p_var;
  744.     callback_entry_t entry;
  745.     vlc_object_internals_t *p_priv = vlc_internals( p_this );
  746.     entry.pf_callback = pf_callback;
  747.     entry.p_data = p_data;
  748.     vlc_mutex_lock( &p_priv->var_lock );
  749.     i_var = GetUnused( p_this, psz_name );
  750.     if( i_var < 0 )
  751.     {
  752.         vlc_mutex_unlock( &p_priv->var_lock );
  753.         return i_var;
  754.     }
  755.     p_var = &p_priv->p_vars[i_var];
  756.     INSERT_ELEM( p_var->p_entries,
  757.                  p_var->i_entries,
  758.                  p_var->i_entries,
  759.                  entry );
  760.     vlc_mutex_unlock( &p_priv->var_lock );
  761.     return VLC_SUCCESS;
  762. }
  763. /**
  764.  * Remove a callback from a variable
  765.  *
  766.  * pf_callback and p_data have to be given again, because different objects
  767.  * might have registered the same callback function.
  768.  */
  769. int __var_DelCallback( vlc_object_t *p_this, const char *psz_name,
  770.                        vlc_callback_t pf_callback, void *p_data )
  771. {
  772.     int i_entry, i_var;
  773.     variable_t *p_var;
  774.     vlc_object_internals_t *p_priv = vlc_internals( p_this );
  775.     vlc_mutex_lock( &p_priv->var_lock );
  776.     i_var = GetUnused( p_this, psz_name );
  777.     if( i_var < 0 )
  778.     {
  779.         vlc_mutex_unlock( &p_priv->var_lock );
  780.         return i_var;
  781.     }
  782.     p_var = &p_priv->p_vars[i_var];
  783.     for( i_entry = p_var->i_entries ; i_entry-- ; )
  784.     {
  785.         if( p_var->p_entries[i_entry].pf_callback == pf_callback
  786.             && p_var->p_entries[i_entry].p_data == p_data )
  787.         {
  788.             break;
  789.         }
  790.     }
  791.     if( i_entry < 0 )
  792.     {
  793.         vlc_mutex_unlock( &p_priv->var_lock );
  794.         return VLC_EGENERIC;
  795.     }
  796.     REMOVE_ELEM( p_var->p_entries, p_var->i_entries, i_entry );
  797.     vlc_mutex_unlock( &p_priv->var_lock );
  798.     return VLC_SUCCESS;
  799. }
  800. /**
  801.  * Trigger callback on a variable
  802.  *
  803.  * param p_this The object that hold the variable
  804.  * param psz_name The name of the variable
  805.  */
  806. int __var_TriggerCallback( vlc_object_t *p_this, const char *psz_name )
  807. {
  808.     int i_var;
  809.     variable_t *p_var;
  810.     vlc_value_t oldval;
  811.     vlc_object_internals_t *p_priv = vlc_internals( p_this );
  812.     vlc_mutex_lock( &p_priv->var_lock );
  813.     i_var = GetUnused( p_this, psz_name );
  814.     if( i_var < 0 )
  815.     {
  816.         vlc_mutex_unlock( &p_priv->var_lock );
  817.         return i_var;
  818.     }
  819.     p_var = &p_priv->p_vars[i_var];
  820.     /* Backup needed stuff */
  821.     oldval = p_var->val;
  822.     /* Deal with callbacks. Tell we're in a callback, release the lock,
  823.      * call stored functions, retake the lock. */
  824.     if( p_var->i_entries )
  825.     {
  826.         int i_var;
  827.         int i_entries = p_var->i_entries;
  828.         callback_entry_t *p_entries = p_var->p_entries;
  829.         p_var->b_incallback = true;
  830.         vlc_mutex_unlock( &p_priv->var_lock );
  831.         /* The real calls */
  832.         for( ; i_entries-- ; )
  833.         {
  834.             p_entries[i_entries].pf_callback( p_this, psz_name, oldval, oldval,
  835.                                               p_entries[i_entries].p_data );
  836.         }
  837.         vlc_mutex_lock( &p_priv->var_lock );
  838.         i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
  839.         if( i_var < 0 )
  840.         {
  841.             msg_Err( p_this, "variable %s has disappeared", psz_name );
  842.             vlc_mutex_unlock( &p_priv->var_lock );
  843.             return VLC_ENOVAR;
  844.         }
  845.         p_var = &p_priv->p_vars[i_var];
  846.         p_var->b_incallback = false;
  847.         vlc_cond_broadcast( &p_priv->var_wait );
  848.     }
  849.     vlc_mutex_unlock( &p_priv->var_lock );
  850.     return VLC_SUCCESS;
  851. }
  852. /** Parse a stringified option
  853.  * This function parse a string option and create the associated object
  854.  * variable
  855.  * The option must be of the form "[no[-]]foo[=bar]" where foo is the
  856.  * option name and bar is the value of the option.
  857.  * param p_obj the object in which the variable must be created
  858.  * param psz_option the option to parse
  859.  * param trusted whether the option is set by a trusted input or not
  860.  * return nothing
  861.  */
  862. void var_OptionParse( vlc_object_t *p_obj, const char *psz_option,
  863.                       bool trusted )
  864. {
  865.     char *psz_name, *psz_value;
  866.     int  i_type;
  867.     bool b_isno = false;
  868.     vlc_value_t val;
  869.     val.psz_string = NULL;
  870.     /* It's too much of a hassle to remove the ':' when we parse
  871.      * the cmd line :) */
  872.     if( psz_option[0] == ':' )
  873.         psz_option++;
  874.     if( !psz_option[0] )
  875.         return;
  876.     psz_name = strdup( psz_option );
  877.     if( psz_name == NULL )
  878.         return;
  879.     psz_value = strchr( psz_name, '=' );
  880.     if( psz_value != NULL )
  881.         *psz_value++ = '';
  882.     /* FIXME: :programs should be handled generically */
  883.     if( !strcmp( psz_name, "programs" ) )
  884.         i_type = VLC_VAR_LIST;
  885.     else
  886.         i_type = config_GetType( p_obj, psz_name );
  887.     if( !i_type && !psz_value )
  888.     {
  889.         /* check for "no-foo" or "nofoo" */
  890.         if( !strncmp( psz_name, "no-", 3 ) )
  891.         {
  892.             memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
  893.         }
  894.         else if( !strncmp( psz_name, "no", 2 ) )
  895.         {
  896.             memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
  897.         }
  898.         else goto cleanup;           /* Option doesn't exist */
  899.         b_isno = true;
  900.         i_type = config_GetType( p_obj, psz_name );
  901.     }
  902.     if( !i_type ) goto cleanup; /* Option doesn't exist */
  903.     if( ( i_type != VLC_VAR_BOOL ) &&
  904.         ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */
  905.     /* check if option is unsafe */
  906.     if( !trusted )
  907.     {
  908.         module_config_t *p_config = config_FindConfig( p_obj, psz_name );
  909.         if( !p_config || !p_config->b_safe )
  910.         {
  911.             msg_Err( p_obj, "unsafe option "%s" has been ignored for "
  912.                             "security reasons", psz_name );
  913.             free( psz_name );
  914.             return;
  915.         }
  916.     }
  917.     /* Create the variable in the input object.
  918.      * Children of the input object will be able to retreive this value
  919.      * thanks to the inheritance property of the object variables. */
  920.     var_Create( p_obj, psz_name, i_type );
  921.     switch( i_type )
  922.     {
  923.     case VLC_VAR_BOOL:
  924.         val.b_bool = !b_isno;
  925.         break;
  926.     case VLC_VAR_INTEGER:
  927.         val.i_int = strtol( psz_value, NULL, 0 );
  928.         break;
  929.     case VLC_VAR_FLOAT:
  930.         val.f_float = us_atof( psz_value );
  931.         break;
  932.     case VLC_VAR_STRING:
  933.     case VLC_VAR_MODULE:
  934.     case VLC_VAR_FILE:
  935.     case VLC_VAR_DIRECTORY:
  936.         val.psz_string = psz_value;
  937.         break;
  938.     case VLC_VAR_LIST:
  939.     {
  940.         char *psz_orig, *psz_var;
  941.         vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
  942.         val.p_list = p_list;
  943.         p_list->i_count = 0;
  944.         psz_var = psz_orig = strdup(psz_value);
  945.         while( psz_var && *psz_var )
  946.         {
  947.             char *psz_item = psz_var;
  948.             vlc_value_t val2;
  949.             while( *psz_var && *psz_var != ',' ) psz_var++;
  950.             if( *psz_var == ',' )
  951.             {
  952.                 *psz_var = '';
  953.                 psz_var++;
  954.             }
  955.             val2.i_int = strtol( psz_item, NULL, 0 );
  956.             INSERT_ELEM( p_list->p_values, p_list->i_count,
  957.                          p_list->i_count, val2 );
  958.             /* p_list->i_count is incremented twice by INSERT_ELEM */
  959.             p_list->i_count--;
  960.             INSERT_ELEM( p_list->pi_types, p_list->i_count,
  961.                          p_list->i_count, VLC_VAR_INTEGER );
  962.         }
  963.         free( psz_orig );
  964.         break;
  965.     }
  966.     default:
  967.         goto cleanup;
  968.     }
  969.     var_Set( p_obj, psz_name, val );
  970.     // If that's a list, remove all elements allocated
  971.     if( i_type == VLC_VAR_LIST )
  972.         FreeList( &val );
  973. cleanup:
  974.     free( psz_name );
  975. }
  976. /* Following functions are local */
  977. /*****************************************************************************
  978.  * GetUnused: find an unused (not in callback) variable from its name
  979.  *****************************************************************************
  980.  * We do i_tries tries before giving up, just in case the variable is being
  981.  * modified and called from a callback.
  982.  *****************************************************************************/
  983. static int GetUnused( vlc_object_t *p_this, const char *psz_name )
  984. {
  985.     vlc_object_internals_t *p_priv = vlc_internals( p_this );
  986.     while( true )
  987.     {
  988.         int i_var;
  989.         i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
  990.         if( i_var < 0 )
  991.         {
  992.             return VLC_ENOVAR;
  993.         }
  994.         if( ! p_priv->p_vars[i_var].b_incallback )
  995.         {
  996.             return i_var;
  997.         }
  998.         mutex_cleanup_push( &p_priv->var_lock );
  999.         vlc_cond_wait( &p_priv->var_wait, &p_priv->var_lock );
  1000.         vlc_cleanup_pop( );
  1001.     }
  1002. }
  1003. /*****************************************************************************
  1004.  * HashString: our cool hash function
  1005.  *****************************************************************************
  1006.  * This function is not intended to be crypto-secure, we only want it to be
  1007.  * fast and not suck too much. This one is pretty fast and did 0 collisions
  1008.  * in wenglish's dictionary.
  1009.  *****************************************************************************/
  1010. static uint32_t HashString( const char *psz_string )
  1011. {
  1012.     uint32_t i_hash = 0;
  1013.     while( *psz_string )
  1014.     {
  1015.         i_hash += *psz_string++;
  1016.         i_hash += i_hash << 10;
  1017.         i_hash ^= i_hash >> 8;
  1018.     }
  1019.     return i_hash;
  1020. }
  1021. /*****************************************************************************
  1022.  * Insert: find an empty slot to insert a new variable
  1023.  *****************************************************************************
  1024.  * We use a recursive inner function indexed on the hash. This function does
  1025.  * nothing in the rare cases where a collision may occur, see Lookup()
  1026.  * to see how we handle them.
  1027.  * XXX: does this really need to be written recursively?
  1028.  *****************************************************************************/
  1029. static int Insert( variable_t *p_vars, int i_count, const char *psz_name )
  1030. {
  1031.     if( i_count == 0 )
  1032.     {
  1033.         return 0;
  1034.     }
  1035.     return InsertInner( p_vars, i_count, HashString( psz_name ) );
  1036. }
  1037. static int InsertInner( variable_t *p_vars, int i_count, uint32_t i_hash )
  1038. {
  1039.     int i_middle;
  1040.     if( i_hash <= p_vars[0].i_hash )
  1041.     {
  1042.         return 0;
  1043.     }
  1044.     if( i_hash >= p_vars[i_count - 1].i_hash )
  1045.     {
  1046.         return i_count;
  1047.     }
  1048.     i_middle = i_count / 2;
  1049.     /* We know that 0 < i_middle */
  1050.     if( i_hash < p_vars[i_middle].i_hash )
  1051.     {
  1052.         return InsertInner( p_vars, i_middle, i_hash );
  1053.     }
  1054.     /* We know that i_middle + 1 < i_count */
  1055.     if( i_hash > p_vars[i_middle + 1].i_hash )
  1056.     {
  1057.         return i_middle + 1 + InsertInner( p_vars + i_middle + 1,
  1058.                                            i_count - i_middle - 1,
  1059.                                            i_hash );
  1060.     }
  1061.     return i_middle + 1;
  1062. }
  1063. static int u32cmp( const void *key, const void *data )
  1064. {
  1065.     const variable_t *p_var = data;
  1066.     uint32_t hash = *(const uint32_t *)key ;
  1067.     if( hash > p_var->i_hash )
  1068.         return 1;
  1069.     if( hash < p_var->i_hash )
  1070.         return -1;
  1071.     return 0;
  1072. }
  1073. /*****************************************************************************
  1074.  * Lookup: find an existing variable given its name
  1075.  *****************************************************************************
  1076.  * We use a recursive inner function indexed on the hash. Care is taken of
  1077.  * possible hash collisions.
  1078.  *****************************************************************************/
  1079. static int Lookup( variable_t *p_vars, size_t i_count, const char *psz_name )
  1080. {
  1081.     variable_t *p_var;
  1082.     uint32_t i_hash;
  1083.     i_hash = HashString( psz_name );
  1084.     p_var = bsearch( &i_hash, p_vars, i_count, sizeof( *p_var ), u32cmp );
  1085.     /* Hash not found */
  1086.     if( p_var == NULL )
  1087.         return -1;
  1088.     assert( i_count > 0 );
  1089.     /* Find the first entry with the right hash */
  1090.     while( (p_var > p_vars) && (i_hash == p_var[-1].i_hash) )
  1091.         p_var--;
  1092.     assert( p_var->i_hash == i_hash );
  1093.     /* Hash collision should be very unlikely, but we cannot guarantee
  1094.      * it will never happen. So we do an exhaustive search amongst all
  1095.      * entries with the same hash. Typically, there is only one anyway. */
  1096.     for( variable_t *p_end = p_vars + i_count;
  1097.          (p_var < p_end) && (i_hash == p_var->i_hash);
  1098.          p_var++ )
  1099.     {
  1100.         if( !strcmp( psz_name, p_var->psz_name ) )
  1101.             return p_var - p_vars;
  1102.     }
  1103.     /* Hash found, but entry not found */
  1104.     return -1;
  1105. }
  1106. /*****************************************************************************
  1107.  * CheckValue: check that a value is valid wrt. a variable
  1108.  *****************************************************************************
  1109.  * This function checks p_val's value against p_var's limitations such as
  1110.  * minimal and maximal value, step, in-list position, and modifies p_val if
  1111.  * necessary.
  1112.  ****************************************************************************/
  1113. static void CheckValue ( variable_t *p_var, vlc_value_t *p_val )
  1114. {
  1115.     /* Check that our variable is in the list */
  1116.     if( p_var->i_type & VLC_VAR_HASCHOICE && p_var->choices.i_count )
  1117.     {
  1118.         int i;
  1119.         /* FIXME: the list is sorted, dude. Use something cleverer. */
  1120.         for( i = p_var->choices.i_count ; i-- ; )
  1121.         {
  1122.             if( p_var->ops->pf_cmp( *p_val, p_var->choices.p_values[i] ) == 0 )
  1123.             {
  1124.                 break;
  1125.             }
  1126.         }
  1127.         /* If not found, change it to anything vaguely valid */
  1128.         if( i < 0 )
  1129.         {
  1130.             /* Free the old variable, get the new one, dup it */
  1131.             p_var->ops->pf_free( p_val );
  1132.             *p_val = p_var->choices.p_values[p_var->i_default >= 0
  1133.                                           ? p_var->i_default : 0 ];
  1134.             p_var->ops->pf_dup( p_val );
  1135.         }
  1136.     }
  1137.     /* Check that our variable is within the bounds */
  1138.     switch( p_var->i_type & VLC_VAR_TYPE )
  1139.     {
  1140.         case VLC_VAR_INTEGER:
  1141.             if( p_var->i_type & VLC_VAR_HASSTEP && p_var->step.i_int
  1142.                  && (p_val->i_int % p_var->step.i_int) )
  1143.             {
  1144.                 p_val->i_int = (p_val->i_int + (p_var->step.i_int / 2))
  1145.                                / p_var->step.i_int * p_var->step.i_int;
  1146.             }
  1147.             if( p_var->i_type & VLC_VAR_HASMIN
  1148.                  && p_val->i_int < p_var->min.i_int )
  1149.             {
  1150.                 p_val->i_int = p_var->min.i_int;
  1151.             }
  1152.             if( p_var->i_type & VLC_VAR_HASMAX
  1153.                  && p_val->i_int > p_var->max.i_int )
  1154.             {
  1155.                 p_val->i_int = p_var->max.i_int;
  1156.             }
  1157.             break;
  1158.         case VLC_VAR_FLOAT:
  1159.             if( p_var->i_type & VLC_VAR_HASSTEP && p_var->step.f_float )
  1160.             {
  1161.                 float f_round = p_var->step.f_float * (float)(int)( 0.5 +
  1162.                                         p_val->f_float / p_var->step.f_float );
  1163.                 if( p_val->f_float != f_round )
  1164.                 {
  1165.                     p_val->f_float = f_round;
  1166.                 }
  1167.             }
  1168.             if( p_var->i_type & VLC_VAR_HASMIN
  1169.                  && p_val->f_float < p_var->min.f_float )
  1170.             {
  1171.                 p_val->f_float = p_var->min.f_float;
  1172.             }
  1173.             if( p_var->i_type & VLC_VAR_HASMAX
  1174.                  && p_val->f_float > p_var->max.f_float )
  1175.             {
  1176.                 p_val->f_float = p_var->max.f_float;
  1177.             }
  1178.             break;
  1179.         case VLC_VAR_TIME:
  1180.             /* FIXME: TODO */
  1181.             break;
  1182.     }
  1183. }
  1184. /*****************************************************************************
  1185.  * InheritValue: try to inherit the value of this variable from the same one
  1186.  * in our closest parent, libvlc or ultimately from the configuration.
  1187.  * The function should always be entered with the object var_lock locked.
  1188.  *****************************************************************************/
  1189. static int InheritValue( vlc_object_t *p_this, const char *psz_name,
  1190.                          vlc_value_t *p_val, int i_type )
  1191. {
  1192.     int i_var;
  1193.     variable_t *p_var;
  1194.     if( p_this->p_parent || ( p_this->p_libvlc && p_this != (vlc_object_t*) p_this->p_libvlc ) )
  1195.     {
  1196.         vlc_object_internals_t *p_priv;
  1197.         if( p_this->p_parent )
  1198.             p_priv = vlc_internals( p_this->p_parent );
  1199.         else
  1200.             p_priv = vlc_internals( p_this->p_libvlc );
  1201.         i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
  1202.         if( i_var >= 0 )
  1203.         {
  1204.             /* We found it! */
  1205.             p_var = &p_priv->p_vars[i_var];
  1206.             /* Really get the variable */
  1207.             *p_val = p_var->val;
  1208.             /* Duplicate value if needed */
  1209.             p_var->ops->pf_dup( p_val );
  1210.             /*msg_Dbg( p_this, "Inherited value for var %s from object %s",
  1211.                      psz_name ? psz_name : "(null)",
  1212.                      p_this->psz_object_name
  1213.                          ? p_this->psz_object_name : "(Unknown)" );*/
  1214.             return VLC_SUCCESS;
  1215.         }
  1216.         else if ( p_this->p_parent ) /* We are still not there */
  1217.             return InheritValue( p_this->p_parent, psz_name, p_val, i_type );
  1218.         /* else take value from config */
  1219.     }
  1220.     switch( i_type & VLC_VAR_CLASS )
  1221.     {
  1222.         case VLC_VAR_STRING:
  1223.             p_val->psz_string = config_GetPsz( p_this, psz_name );
  1224.             if( !p_val->psz_string ) p_val->psz_string = strdup("");
  1225.             break;
  1226.         case VLC_VAR_FLOAT:
  1227.             p_val->f_float = config_GetFloat( p_this, psz_name );
  1228.             break;
  1229.         case VLC_VAR_INTEGER:
  1230.             p_val->i_int = config_GetInt( p_this, psz_name );
  1231.             break;
  1232.         case VLC_VAR_BOOL:
  1233.             p_val->b_bool = config_GetInt( p_this, psz_name );
  1234.             break;
  1235.         case VLC_VAR_LIST:
  1236.         {
  1237.             char *psz_orig, *psz_var;
  1238.             vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
  1239.             p_val->p_list = p_list;
  1240.             p_list->i_count = 0;
  1241.             psz_var = psz_orig = config_GetPsz( p_this, psz_name );
  1242.             while( psz_var && *psz_var )
  1243.             {
  1244.                 char *psz_item = psz_var;
  1245.                 vlc_value_t val;
  1246.                 while( *psz_var && *psz_var != ',' ) psz_var++;
  1247.                 if( *psz_var == ',' )
  1248.                 {
  1249.                     *psz_var = '';
  1250.                     psz_var++;
  1251.                 }
  1252.                 val.i_int = strtol( psz_item, NULL, 0 );
  1253.                 INSERT_ELEM( p_list->p_values, p_list->i_count,
  1254.                              p_list->i_count, val );
  1255.                 /* p_list->i_count is incremented twice by INSERT_ELEM */
  1256.                 p_list->i_count--;
  1257.                 INSERT_ELEM( p_list->pi_types, p_list->i_count,
  1258.                              p_list->i_count, VLC_VAR_INTEGER );
  1259.             }
  1260.             free( psz_orig );
  1261.             break;
  1262.         }
  1263.         default:
  1264.             msg_Warn( p_this, "Could not inherit value for var %s "
  1265.                               "from config. Invalid Type", psz_name );
  1266.             return VLC_ENOOBJ;
  1267.             break;
  1268.     }
  1269.     /*msg_Dbg( p_this, "Inherited value for var %s from config", psz_name );*/
  1270.     return VLC_SUCCESS;
  1271. }
  1272. /**********************************************************************
  1273.  * Execute a var command on an object identified by its name
  1274.  **********************************************************************/
  1275. int __var_Command( vlc_object_t *p_this, const char *psz_name,
  1276.                    const char *psz_cmd, const char *psz_arg, char **psz_msg )
  1277. {
  1278.     vlc_object_t *p_obj = vlc_object_find_name( p_this->p_libvlc,
  1279.                                                 psz_name, FIND_CHILD );
  1280.     int i_type, i_ret;
  1281.     if( !p_obj )
  1282.     {
  1283.         if( psz_msg )
  1284.             *psz_msg = strdup( "Unknown destination object." );
  1285.         return VLC_ENOOBJ;
  1286.     }
  1287.     i_type = var_Type( p_obj, psz_cmd );
  1288.     if( !( i_type&VLC_VAR_ISCOMMAND ) )
  1289.     {
  1290.         vlc_object_release( p_obj );
  1291.         if( psz_msg )
  1292.             *psz_msg = strdup( "Variable doesn't exist or isn't a command." );
  1293.         return VLC_EGENERIC;
  1294.     }
  1295.     i_type &= VLC_VAR_CLASS;
  1296.     switch( i_type )
  1297.     {
  1298.         case VLC_VAR_INTEGER:
  1299.             i_ret = var_SetInteger( p_obj, psz_cmd, atoi( psz_arg ) );
  1300.             break;
  1301.         case VLC_VAR_FLOAT:
  1302.             i_ret = var_SetFloat( p_obj, psz_cmd, us_atof( psz_arg ) );
  1303.             break;
  1304.         case VLC_VAR_STRING:
  1305.             i_ret = var_SetString( p_obj, psz_cmd, psz_arg );
  1306.             break;
  1307.         case VLC_VAR_BOOL:
  1308.             i_ret = var_SetBool( p_obj, psz_cmd, atoi( psz_arg ) );
  1309.             break;
  1310.         default:
  1311.             i_ret = VLC_EGENERIC;
  1312.             break;
  1313.     }
  1314.     vlc_object_release( p_obj );
  1315.     if( psz_msg )
  1316.     {
  1317.         if( asprintf( psz_msg, "%s on object %s returned %i (%s)",
  1318.                   psz_cmd, psz_name, i_ret, vlc_error( i_ret ) ) == -1)
  1319.             *psz_msg = NULL;
  1320.     }
  1321.     return i_ret;
  1322. }