+ *psz++ = strtol( val, NULL, 16 );
+ }
+ else if( *p == '+' )
+ {
+ *psz++ = ' ';
+ p++;
+ }
+ else
+ {
+ *psz++ = *p++;
+ }
+ }
+ *psz++ ='\0';
+ free( dup );
+}
+
+/*****************************************************************************
+ * ParseOption: parses the options for the input
+ *****************************************************************************
+ * This function parses the input (config) options and creates their associated
+ * object variables.
+ * Options are of the form "[no[-]]foo[=bar]" where foo is the option name and
+ * bar is the value of the option.
+ *****************************************************************************/
+static void ParseOption( input_thread_t *p_input, const char *psz_option )
+{
+ char *psz_name = (char *)psz_option;
+ char *psz_value = strchr( psz_option, '=' );
+ int i_name_len, i_type;
+ vlc_bool_t b_isno = VLC_FALSE;
+ vlc_value_t val;
+
+ if( psz_value ) i_name_len = psz_value - psz_option;
+ else i_name_len = strlen( psz_option );
+
+ /* It's too much of an hassle to remove the ':' when we parse
+ * the cmd line :) */
+ if( i_name_len && *psz_name == ':' )
+ {
+ psz_name++;
+ i_name_len--;
+ }
+
+ if( i_name_len == 0 ) return;
+
+ psz_name = strndup( psz_name, i_name_len );
+ if( psz_value ) psz_value++;
+
+ i_type = config_GetType( p_input, 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 = VLC_TRUE;
+ i_type = config_GetType( p_input, psz_name );
+
+ if( !i_type ) goto cleanup; /* Option doesn't exist */
+ }
+ else if( !i_type ) goto cleanup; /* Option doesn't exist */
+
+ if( ( i_type != VLC_VAR_BOOL ) &&
+ ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */
+
+ /* 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_input, psz_name, i_type );
+
+ switch( i_type )
+ {
+ case VLC_VAR_BOOL:
+ val.b_bool = !b_isno;
+ break;
+
+ case VLC_VAR_INTEGER:
+ val.i_int = atoi( psz_value );
+ 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;
+
+ default:
+ goto cleanup;
+ break;
+ }
+
+ var_Set( p_input, psz_name, val );
+
+ msg_Dbg( p_input, "set input option: %s to %s", psz_name, psz_value );
+
+ cleanup:
+ if( psz_name ) free( psz_name );
+ return;
+}
+
+/*****************************************************************************
+ * Callbacks (position, time, state, rate )
+ *****************************************************************************/
+static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *p_data )
+{
+ input_thread_t *p_input = (input_thread_t *)p_this;
+
+ msg_Dbg( p_input, "cmd=%s old=%f new=%f", psz_cmd,
+ oldval.f_float, newval.f_float );
+
+ if( !strcmp( psz_cmd, "position-offset" ) )
+ {
+ vlc_value_t val;
+ var_Get( p_input, "position", &val );
+
+ newval.f_float += val.f_float;
+ }
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_input->stream.p_selected_area->i_seek =
+ (int64_t)( newval.f_float *
+ (double)p_input->stream.p_selected_area->i_size );
+
+ if( p_input->stream.p_selected_area->i_seek < 0 )
+ {
+ p_input->stream.p_selected_area->i_seek = 0;
+ }
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ return VLC_SUCCESS;
+}
+
+static int TimeCallback( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+ input_thread_t *p_input = (input_thread_t *)p_this;
+ vlc_value_t val;
+
+ /* FIXME TODO FIXME */
+ msg_Dbg( p_input, "cmd=%s old=%lld new=%lld", psz_cmd,
+ oldval.i_time, newval.i_time );
+
+ var_Get( p_input, "length", &val );
+ if( val.i_time > 0 )
+ {
+ val.f_float = (double)newval.i_time / (double)val.i_time;
+ if( !strcmp( psz_cmd, "time-offset" ) )
+ {
+ var_Set( p_input, "position-offset", val );
+ }
+ else
+ {
+ var_Set( p_input, "position", val );
+ }
+ }
+ else
+ {
+ msg_Warn( p_input, "TimeCallback: length <= 0 -> can't seek" );
+ }
+ return VLC_SUCCESS;
+}
+
+static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *p_data )
+{
+ input_thread_t *p_input = (input_thread_t *)p_this;
+
+ msg_Dbg( p_input, "cmd=%s old=%d new=%d",
+ psz_cmd, oldval.i_int, newval.i_int );
+
+ switch( newval.i_int )
+ {
+ case PLAYING_S:
+ input_SetStatus( p_input, INPUT_STATUS_PLAY );
+ return VLC_SUCCESS;
+ case PAUSE_S:
+ input_SetStatus( p_input, INPUT_STATUS_PAUSE );
+ return VLC_SUCCESS;
+ case END_S:
+ input_SetStatus( p_input, INPUT_STATUS_END );
+ return VLC_SUCCESS;
+ default:
+ msg_Err( p_input, "cannot set new state (invalid)" );
+ return VLC_EGENERIC;
+ }
+}
+
+static int RateCallback( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+ input_thread_t *p_input = (input_thread_t *)p_this;
+
+ if( !strcmp( psz_cmd, "rate-slower" ) )
+ {
+ input_SetStatus( p_input, INPUT_STATUS_SLOWER );
+ }
+ else if( !strcmp( psz_cmd, "rate-faster" ) )
+ {
+ input_SetStatus( p_input, INPUT_STATUS_FASTER );
+ }
+ else
+ {
+ msg_Dbg( p_input, "cmd=%s old=%d new=%d",
+ psz_cmd, oldval.i_int, newval.i_int );
+ input_SetRate( p_input, newval.i_int );
+ }
+ return VLC_SUCCESS;
+}
+
+static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+ input_thread_t *p_input = (input_thread_t *)p_this;
+ return input_Control( p_input, INPUT_SET_BOOKMARK, newval );
+}