+/**
+ * Trigger callback on a variable
+ *
+ * \param p_this The object that hold the variable
+ * \param psz_name The name of the variable
+ */
+int __var_TriggerCallback( vlc_object_t *p_this, const char *psz_name )
+{
+ int i_var;
+ variable_t *p_var;
+ vlc_value_t oldval;
+ vlc_object_internals_t *p_priv = vlc_internals( p_this );
+
+ vlc_mutex_lock( &p_priv->var_lock );
+
+ i_var = GetUnused( p_this, psz_name );
+ if( i_var < 0 )
+ {
+ vlc_mutex_unlock( &p_priv->var_lock );
+ return i_var;
+ }
+
+ p_var = &p_priv->p_vars[i_var];
+
+ /* Backup needed stuff */
+ oldval = p_var->val;
+
+ /* Deal with callbacks. Tell we're in a callback, release the lock,
+ * call stored functions, retake the lock. */
+ if( p_var->i_entries )
+ {
+ int i_var;
+ int i_entries = p_var->i_entries;
+ callback_entry_t *p_entries = p_var->p_entries;
+
+ p_var->b_incallback = true;
+ vlc_mutex_unlock( &p_priv->var_lock );
+
+ /* The real calls */
+ for( ; i_entries-- ; )
+ {
+ p_entries[i_entries].pf_callback( p_this, psz_name, oldval, oldval,
+ p_entries[i_entries].p_data );
+ }
+
+ vlc_mutex_lock( &p_priv->var_lock );
+
+ i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
+ if( i_var < 0 )
+ {
+ msg_Err( p_this, "variable %s has disappeared", psz_name );
+ vlc_mutex_unlock( &p_priv->var_lock );
+ return VLC_ENOVAR;
+ }
+
+ p_var = &p_priv->p_vars[i_var];
+ p_var->b_incallback = false;
+ }
+
+ vlc_mutex_unlock( &p_priv->var_lock );
+ return VLC_SUCCESS;
+}
+
+/** Parse a stringified option
+ * This function parse a string option and create the associated object
+ * variable
+ * The option must be of the form "[no[-]]foo[=bar]" where foo is the
+ * option name and bar is the value of the option.
+ * \param p_obj the object in which the variable must be created
+ * \param psz_option the option to parse
+ * \param trusted whether the option is set by a trusted input or not
+ * \return nothing
+ */
+void var_OptionParse( vlc_object_t *p_obj, const char *psz_option,
+ bool trusted )
+{
+ char *psz_name, *psz_value;
+ int i_type;
+ bool b_isno = false;
+ vlc_value_t val;
+
+ val.psz_string = NULL;
+
+ /* It's too much of a hassle to remove the ':' when we parse
+ * the cmd line :) */
+ if( psz_option[0] == ':' )
+ psz_option++;
+
+ if( !psz_option[0] )
+ return;
+
+ psz_name = strdup( psz_option );
+ if( psz_name == NULL )
+ return;
+
+ psz_value = strchr( psz_name, '=' );
+ if( psz_value != NULL )
+ *psz_value++ = '\0';
+
+ /* FIXME: :programs should be handled generically */
+ if( !strcmp( psz_name, "programs" ) )
+ i_type = VLC_VAR_LIST;
+ else
+ i_type = config_GetType( p_obj, psz_name );
+
+ if( !i_type && !psz_value )
+ {
+ /* check for "no-foo" or "nofoo" */
+ if( !strncmp( psz_name, "no-", 3 ) )
+ {
+ memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
+ }
+ else if( !strncmp( psz_name, "no", 2 ) )
+ {
+ memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
+ }
+ else goto cleanup; /* Option doesn't exist */
+
+ b_isno = true;
+ i_type = config_GetType( p_obj, psz_name );
+ }
+ if( !i_type ) goto cleanup; /* Option doesn't exist */
+
+ if( ( i_type != VLC_VAR_BOOL ) &&
+ ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */
+
+ /* check if option is unsafe */
+ if( !trusted )
+ {
+ module_config_t *p_config = config_FindConfig( p_obj, psz_name );
+ if( !p_config->b_safe )
+ {
+ msg_Err( p_obj, "unsafe option \"%s\" has been ignored for "
+ "security reasons", psz_name );
+ return;
+ }
+ }
+
+ /* Create the variable in the input object.
+ * Children of the input object will be able to retreive this value
+ * thanks to the inheritance property of the object variables. */
+ var_Create( p_obj, psz_name, i_type );
+
+ switch( i_type )
+ {
+ case VLC_VAR_BOOL:
+ val.b_bool = !b_isno;
+ break;
+
+ case VLC_VAR_INTEGER:
+ val.i_int = strtol( psz_value, NULL, 0 );
+ break;
+
+ case VLC_VAR_FLOAT:
+ val.f_float = atof( psz_value );
+ break;
+
+ case VLC_VAR_STRING:
+ case VLC_VAR_MODULE:
+ case VLC_VAR_FILE:
+ case VLC_VAR_DIRECTORY:
+ val.psz_string = psz_value;
+ break;
+
+ case VLC_VAR_LIST:
+ {
+ char *psz_orig, *psz_var;
+ vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
+ val.p_list = p_list;
+ p_list->i_count = 0;
+
+ psz_var = psz_orig = strdup(psz_value);
+ while( psz_var && *psz_var )
+ {
+ char *psz_item = psz_var;
+ vlc_value_t val2;
+ while( *psz_var && *psz_var != ',' ) psz_var++;
+ if( *psz_var == ',' )
+ {
+ *psz_var = '\0';
+ psz_var++;
+ }
+ val2.i_int = strtol( psz_item, NULL, 0 );
+ INSERT_ELEM( p_list->p_values, p_list->i_count,
+ p_list->i_count, val2 );
+ /* p_list->i_count is incremented twice by INSERT_ELEM */
+ p_list->i_count--;
+ INSERT_ELEM( p_list->pi_types, p_list->i_count,
+ p_list->i_count, VLC_VAR_INTEGER );
+ }
+ free( psz_orig );
+ break;
+ }
+
+ default:
+ goto cleanup;
+ }
+
+ var_Set( p_obj, psz_name, val );
+
+cleanup:
+ free( psz_name );
+}
+
+