+ int i_files;
+ httpd_file_callback_args_t **pp_files;
+
+ playlist_t *p_playlist;
+ input_thread_t *p_input;
+};
+
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+#define HOST_TEXT N_( "Host address" )
+#define HOST_LONGTEXT N_( \
+ "You can set the address and port on which the http interface will bind" )
+#define SRC_TEXT N_( "Source directory" )
+#define SRC_LONGTEXT N_( "Source directory" )
+
+vlc_module_begin();
+ set_description( _("HTTP remote control interface") );
+ add_category_hint( N_("HTTP remote control"), NULL, VLC_TRUE );
+ add_string ( "http-host", NULL, NULL, HOST_TEXT, HOST_LONGTEXT, VLC_TRUE );
+#if defined(SYS_DARWIN) || defined(SYS_BEOS) \
+ || (defined(WIN32) && !defined(UNDER_CE))
+ add_string ( "http-src", NULL, NULL, SRC_TEXT, SRC_LONGTEXT, VLC_TRUE );
+#else
+ add_string ( "http-src", "share/http", NULL, SRC_TEXT, SRC_LONGTEXT, VLC_TRUE );
+#endif
+ set_capability( "interface", 0 );
+ set_callbacks( Activate, Close );
+vlc_module_end();
+
+/*****************************************************************************
+ * Activate: initialize and create stuff
+ *****************************************************************************/
+static int Activate( vlc_object_t *p_this )
+{
+ intf_thread_t *p_intf = (intf_thread_t*)p_this;
+ intf_sys_t *p_sys;
+ char *psz_host;
+ char *psz_address = "";
+ int i_port = 0;
+ char *psz_src;
+
+ psz_host = config_GetPsz( p_intf, "http-host" );
+ if( psz_host )
+ {
+ char *psz_parser;
+ psz_address = psz_host;
+
+ psz_parser = strchr( psz_host, ':' );
+ if( psz_parser )
+ {
+ *psz_parser++ = '\0';
+ i_port = atoi( psz_parser );
+ }
+ }
+ if( i_port <= 0 )
+ {
+ i_port= 8080;
+ }
+
+ msg_Dbg( p_intf, "base %s:%d", psz_address, i_port );
+ p_intf->p_sys = p_sys = malloc( sizeof( intf_sys_t ) );
+ p_sys->p_playlist = NULL;
+ p_sys->p_input = NULL;
+
+ if( ( p_sys->p_httpd = httpd_Find( VLC_OBJECT(p_intf), VLC_TRUE ) ) == NULL )
+ {
+ msg_Err( p_intf, "cannot create/find httpd" );
+ free( p_sys );
+ return VLC_EGENERIC;
+ }
+
+ if( ( p_sys->p_httpd_host =
+ p_sys->p_httpd->pf_register_host( p_sys->p_httpd,
+ psz_address, i_port ) ) == NULL )
+ {
+ msg_Err( p_intf, "cannot listen on %s:%d", psz_address, i_port );
+ httpd_Release( p_sys->p_httpd );
+ free( p_sys );
+ return VLC_EGENERIC;
+ }
+
+ if( psz_host )
+ {
+ free( psz_host );
+ }
+
+ p_sys->i_files = 0;
+ p_sys->pp_files = malloc( sizeof( httpd_file_callback_args_t *) );
+
+#if defined(SYS_DARWIN) || defined(SYS_BEOS) || \
+ ( defined(WIN32) && !defined(UNDER_CE ) )
+ if ( ( psz_src = config_GetPsz( p_intf, "http-src" )) == NULL )
+ {
+ char * psz_vlcpath = p_intf->p_libvlc->psz_vlcpath;
+ psz_src = malloc( strlen(psz_vlcpath) + strlen("/share/http" ) + 1 );
+ sprintf( psz_src, "%s/share/http", psz_vlcpath);
+ }
+#else
+ psz_src = config_GetPsz( p_intf, "http-src" );
+#endif
+ if( !psz_src || *psz_src == '\0' )
+ {
+ msg_Err( p_intf, "invalid src dir" );
+ goto failed;
+ }
+
+ /* remove trainling \ or / */
+ if( psz_src[strlen( psz_src ) - 1] == '\\' ||
+ psz_src[strlen( psz_src ) - 1] == '/' )
+ {
+ psz_src[strlen( psz_src ) - 1] = '\0';
+ }
+
+ ParseDirectory( p_intf, psz_src, psz_src );
+
+
+ if( p_sys->i_files <= 0 )
+ {
+ msg_Err( p_intf, "cannot find any files" );
+ goto failed;
+ }
+ p_intf->pf_run = Run;
+
+ return VLC_SUCCESS;
+
+failed:
+ free( p_sys->pp_files );
+ p_sys->p_httpd->pf_unregister_host( p_sys->p_httpd,
+ p_sys->p_httpd_host );
+ httpd_Release( p_sys->p_httpd );
+ free( p_sys );
+ return VLC_EGENERIC;
+}
+
+/*****************************************************************************
+ * CloseIntf: destroy interface
+ *****************************************************************************/
+void Close ( vlc_object_t *p_this )
+{
+ intf_thread_t *p_intf = (intf_thread_t *)p_this;
+ intf_sys_t *p_sys = p_intf->p_sys;
+
+ int i;
+
+ for( i = 0; i < p_sys->i_files; i++ )
+ {
+ p_sys->p_httpd->pf_unregister_file( p_sys->p_httpd,
+ p_sys->pp_files[i]->p_file );
+ /* do not free mime */
+ free( p_sys->pp_files[i]->file );
+ free( p_sys->pp_files[i]->name );
+ free( p_sys->pp_files[i] );
+ }
+ free( p_sys->pp_files );
+ p_sys->p_httpd->pf_unregister_host( p_sys->p_httpd,
+ p_sys->p_httpd_host );
+ httpd_Release( p_sys->p_httpd );
+ free( p_sys );
+}
+
+/*****************************************************************************
+ * Run: http interface thread
+ *****************************************************************************/
+static void Run( intf_thread_t *p_intf )
+{
+ intf_sys_t *p_sys = p_intf->p_sys;
+
+ while( !p_intf->b_die )
+ {
+ /* get the playlist */
+ if( p_sys->p_playlist == NULL )
+ {
+ p_sys->p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
+ }
+
+ /* Manage the input part */
+ if( p_sys->p_input == NULL )
+ {
+ if( p_sys->p_playlist )
+ {
+ p_sys->p_input =
+ vlc_object_find( p_sys->p_playlist,
+ VLC_OBJECT_INPUT,
+ FIND_CHILD );
+ }
+ }
+ else if( p_sys->p_input->b_dead )
+ {
+ vlc_object_release( p_sys->p_input );
+ p_sys->p_input = NULL;
+ }
+
+
+ /* Wait a bit */
+ msleep( INTF_IDLE_SLEEP );
+ }
+
+ if( p_sys->p_input )
+ {
+ vlc_object_release( p_sys->p_input );
+ p_sys->p_input = NULL;
+ }
+
+ if( p_sys->p_playlist )
+ {
+ vlc_object_release( p_sys->p_playlist );
+ p_sys->p_playlist = NULL;
+ }
+}
+
+
+/*****************************************************************************
+ * Local functions
+ *****************************************************************************/
+#define MAX_DIR_SIZE 10240
+
+/****************************************************************************
+ * FileToUrl: create a good name for an url from filename
+ ****************************************************************************/
+static char *FileToUrl( char *name )
+{
+ char *url, *p;
+
+ url = p = malloc( strlen( name ) + 1 );
+
+#ifdef WIN32
+ while( *name == '\\' || *name == '/' )
+#else
+ while( *name == '/' )
+#endif
+ {
+ name++;
+ }
+
+ *p++ = '/';
+ strcpy( p, name );
+
+#ifdef WIN32
+ /* convert '\\' into '/' */
+ name = p;
+ while( *name )
+ {
+ if( *name == '\\' )
+ {
+ *p++ = '/';
+ }
+ name++;
+ }
+#endif
+
+ /* index.* -> / */
+ if( ( p = strrchr( url, '/' ) ) != NULL )
+ {
+ if( !strncmp( p, "/index.", 7 ) )
+ {
+ p[1] = '\0';
+ }
+ }
+ return url;
+}
+
+/****************************************************************************
+ * FileToMime: XXX duplicated with modules/access_out/http.c
+ ****************************************************************************/
+static struct
+{
+ char *psz_ext;
+ char *psz_mime;
+} http_mime[] =
+{
+ { ".htm", "text/html" },
+ { ".html", "text/html" },
+
+ /* media mime */
+ { ".avi", "video/avi" },
+ { ".asf", "video/x-ms-asf" },
+ { ".m1a", "audio/mpeg" },
+ { ".m2a", "audio/mpeg" },
+ { ".m1v", "video/mpeg" },
+ { ".m2v", "video/mpeg" },
+ { ".mp2", "audio/mpeg" },
+ { ".mp3", "audio/mpeg" },
+ { ".mpa", "audio/mpeg" },
+ { ".mpg", "video/mpeg" },
+ { ".mpeg", "video/mpeg" },
+ { ".mpe", "video/mpeg" },
+ { ".mov", "video/quicktime" },
+ { ".moov", "video/quicktime" },
+ { ".ogg", "application/ogg" },
+ { ".ogm", "application/ogg" },
+ { ".wav", "audio/wav" },
+
+ /* end */
+ { NULL, NULL }
+};
+
+static char *FileToMime( char *psz_name )
+{
+ char *psz_ext;
+
+ psz_ext = strrchr( psz_name, '.' );
+ if( psz_ext )
+ {
+ int i;
+
+ for( i = 0; http_mime[i].psz_ext != NULL ; i++ )
+ {
+ if( !strcmp( http_mime[i].psz_ext, psz_ext ) )
+ {
+ return( http_mime[i].psz_mime );
+ }
+ }
+ }
+ return( "application/octet-stream" );
+}
+
+/****************************************************************************
+ * ParseDirectory: parse recursively a directory, adding each file
+ ****************************************************************************/
+static int ParseDirectory( intf_thread_t *p_intf, char *psz_root,
+ char *psz_dir )
+{
+ intf_sys_t *p_sys = p_intf->p_sys;
+ char dir[MAX_DIR_SIZE];
+#ifdef HAVE_SYS_STAT_H
+ struct stat stat_info;
+#endif
+ DIR *p_dir;
+ struct dirent *p_dir_content;
+ FILE *file;
+
+ char *user = NULL;
+ char *password = NULL;
+
+#ifdef HAVE_SYS_STAT_H
+ if( stat( psz_dir, &stat_info ) == -1 || !S_ISDIR( stat_info.st_mode ) )
+ {
+ return VLC_EGENERIC;
+ }
+#endif
+
+ if( ( p_dir = opendir( psz_dir ) ) == NULL )
+ {
+ msg_Err( p_intf, "cannot open dir (%s)", psz_dir );
+ return VLC_EGENERIC;
+ }
+
+ msg_Dbg( p_intf, "dir=%s", psz_dir );
+
+ sprintf( dir, "%s/.access", psz_dir );
+ if( ( file = fopen( dir, "r" ) ) != NULL )
+ {
+ char line[1024];
+ int i_size;
+
+ msg_Dbg( p_intf, "find .access in dir=%s", psz_dir );
+
+ i_size = fread( line, 1, 1023, file );
+ if( i_size > 0 )
+ {
+ char *p;
+ while( i_size > 0 && ( line[i_size-1] == '\n' ||
+ line[i_size-1] == '\r' ) )
+ {
+ i_size--;
+ }
+
+ line[i_size] = '\0';
+
+ p = strchr( line, ':' );
+ if( p )
+ {
+ *p++ = '\0';
+ user = strdup( line );
+ password = strdup( p );
+ }
+ }
+ msg_Dbg( p_intf, "using user=%s password=%s (read=%d)",
+ user, password, i_size );
+
+ fclose( file );
+ }
+
+ for( ;; )
+ {
+ /* parse psz_src dir */
+ if( ( p_dir_content = readdir( p_dir ) ) == NULL )
+ {
+ break;
+ }
+
+ if( p_dir_content->d_name[0] == '.' )
+ {
+ continue;
+ }
+ sprintf( dir, "%s/%s", psz_dir, p_dir_content->d_name );
+ if( ParseDirectory( p_intf, psz_root, dir ) )
+ {
+#define f p_sys->pp_files[p_sys->i_files]
+ f = malloc( sizeof( httpd_file_callback_args_t ) );
+ f->p_intf = p_intf;
+ f->file = strdup( dir );
+ f->name = FileToUrl( &dir[strlen( psz_root )] );
+ f->mime = FileToMime( &dir[strlen( psz_root )] );
+
+ msg_Dbg( p_intf, "file=%s (url=%s mime=%s)",
+ f->file, f->name, f->mime );
+
+ f->p_file =
+ p_sys->p_httpd->pf_register_file( p_sys->p_httpd,
+ f->name, f->mime,
+ user, password,
+ http_get, http_get,
+ f );
+ if( f->p_file )
+ {
+ p_sys->i_files++;
+ p_sys->pp_files = realloc( p_sys->pp_files,
+ (p_sys->i_files+1) * sizeof( httpd_file_callback_args_t ) );
+ }
+#define fold p_sys->pp_files[p_sys->i_files-1]
+
+ /* FIXME for rep/ add rep (it would be better to do a redirection) */
+ if( strlen(fold->name) > 1 &&
+ fold->name[strlen(fold->name) - 1] == '/' )
+ {
+ f = malloc( sizeof( httpd_file_callback_args_t ) );
+ f->p_intf = p_intf;
+ f->file = strdup( fold->file );
+ f->name = strdup( fold->name );
+ f->mime = fold->mime;
+
+ f->name[strlen(f->name) - 1] = '\0';
+ msg_Dbg( p_intf, "file=%s (url=%s mime=%s)", f->file, f->name,
+ f->mime );
+ f->p_file =
+ p_sys->p_httpd->pf_register_file( p_sys->p_httpd,
+ f->name, f->mime,
+ user, password,
+ http_get, http_get,
+ f );
+ if( f->p_file )
+ {
+ p_sys->i_files++;
+ p_sys->pp_files =
+ realloc( p_sys->pp_files, (p_sys->i_files+1) *
+ sizeof( httpd_file_callback_args_t ) );
+ }
+ }
+#undef fold
+#undef f
+ }
+ }
+
+ if( user )
+ {
+ free( user );
+ }
+ if( password )
+ {
+ free( password );
+ }
+ return VLC_SUCCESS;
+}
+
+/****************************************************************************
+ * var and set handling
+ ****************************************************************************/
+
+static mvar_t *mvar_New( char *name, char *value )
+{
+ mvar_t *v = malloc( sizeof( mvar_t ) );
+
+ v->name = strdup( name );
+ v->value = strdup( value ? value : "" );
+
+ v->i_field = 0;
+ v->field = malloc( sizeof( mvar_t * ) );
+ v->field[0] = NULL;
+
+ return v;
+}
+
+static void mvar_Delete( mvar_t *v )
+{
+ int i;
+
+ free( v->name );
+ free( v->value );
+
+ for( i = 0; i < v->i_field; i++ )
+ {
+ mvar_Delete( v->field[i] );
+ }
+ free( v->field );
+ free( v );
+}
+
+static void mvar_AppendVar( mvar_t *v, mvar_t *f )
+{
+ v->field = realloc( v->field, sizeof( mvar_t * ) * ( v->i_field + 2 ) );
+ v->field[v->i_field] = f;
+ v->i_field++;
+}
+
+static mvar_t *mvar_Duplicate( mvar_t *v )
+{
+ int i;
+ mvar_t *n;
+
+ n = mvar_New( v->name, v->value );
+ for( i = 0; i < v->i_field; i++ )
+ {
+ mvar_AppendVar( n, mvar_Duplicate( v->field[i] ) );
+ }
+
+ return n;
+}
+
+static void mvar_PushVar( mvar_t *v, mvar_t *f )
+{
+ v->field = realloc( v->field, sizeof( mvar_t * ) * ( v->i_field + 2 ) );
+ if( v->i_field > 0 )
+ {
+ memmove( &v->field[1], &v->field[0], sizeof( mvar_t * ) * v->i_field );
+ }
+ v->field[0] = f;
+ v->i_field++;
+}
+
+static void mvar_RemoveVar( mvar_t *v, mvar_t *f )
+{
+ int i;
+ for( i = 0; i < v->i_field; i++ )
+ {
+ if( v->field[i] == f )
+ {
+ break;
+ }
+ }
+ if( i >= v->i_field )
+ {
+ return;
+ }
+
+ if( i + 1 < v->i_field )
+ {
+ memmove( &v->field[i], &v->field[i+1], sizeof( mvar_t * ) * ( v->i_field - i - 1 ) );
+ }
+ v->i_field--;
+ /* FIXME should do a realloc */
+}
+
+static mvar_t *mvar_GetVar( mvar_t *s, char *name )
+{
+ int i;
+ char base[512], *field, *p;
+ int i_index;
+
+ /* format: name[index].field */
+
+ field = strchr( name, '.' );
+ if( field )
+ {
+ int i = field - name;
+ strncpy( base, name, i );
+ base[i] = '\0';
+ field++;
+ }
+ else
+ {
+ strcpy( base, name );
+ }
+
+ if( ( p = strchr( base, '[' ) ) )
+ {
+ *p++ = '\0';
+ sscanf( p, "%d]", &i_index );
+ if( i_index < 0 )
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ i_index = 0;
+ }
+
+ for( i = 0; i < s->i_field; i++ )
+ {
+ if( !strcmp( s->field[i]->name, base ) )
+ {
+ if( i_index > 0 )
+ {
+ i_index--;
+ }
+ else
+ {
+ if( field )
+ {
+ return mvar_GetVar( s->field[i], field );
+ }
+ else
+ {
+ return s->field[i];
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
+static char *mvar_GetValue( mvar_t *v, char *field )
+{
+ if( *field == '\0' )
+ {
+ return v->value;
+ }
+ else
+ {
+ mvar_t *f = mvar_GetVar( v, field );
+ if( f )
+ {
+ return f->value;
+ }
+ else
+ {
+ return field;
+ }
+ }
+}
+
+static void mvar_PushNewVar( mvar_t *vars, char *name, char *value )
+{
+ mvar_t *f = mvar_New( name, value );
+ mvar_PushVar( vars, f );
+}
+
+static void mvar_AppendNewVar( mvar_t *vars, char *name, char *value )
+{
+ mvar_t *f = mvar_New( name, value );
+ mvar_AppendVar( vars, f );
+}
+
+
+/* arg= start[:stop[:step]],.. */
+static mvar_t *mvar_IntegerSetNew( char *name, char *arg )
+{
+ char *dup = strdup( arg );
+ char *str = dup;
+ mvar_t *s = mvar_New( name, "set" );
+
+ fprintf( stderr," mvar_IntegerSetNew: name=`%s' arg=`%s'\n", name, str );
+
+ while( str )
+ {
+ char *p;
+ int i_start,i_stop,i_step;
+ int i_match;
+
+ p = strchr( str, ',' );
+ if( p )
+ {
+ *p++ = '\0';
+ }
+
+ i_step = 0;
+ i_match = sscanf( str, "%d:%d:%d", &i_start, &i_stop, &i_step );
+ fprintf( stderr," mvar_IntegerSetNew: m=%d start=%d stop=%d step=%d\n", i_match, i_start, i_stop, i_step );
+
+ if( i_match == 1 )
+ {
+ i_stop = i_start;
+ i_step = 1;
+ }
+ else if( i_match == 2 )
+ {
+ i_step = i_start < i_stop ? 1 : -1;
+ }
+
+ if( i_match >= 1 )
+ {
+ int i;
+
+ if( ( i_start < i_stop && i_step > 0 ) ||
+ ( i_start > i_stop && i_step < 0 ) )
+ {
+ for( i = i_start; ; i += i_step )
+ {
+ char value[512];
+
+ if( ( i_step > 0 && i > i_stop ) ||
+ ( i_step < 0 && i < i_stop ) )
+ {
+ break;
+ }
+
+ fprintf( stderr," mvar_IntegerSetNew: adding %d\n", i );
+ sprintf( value, "%d", i );
+
+ mvar_PushNewVar( s, name, value );
+ }
+ }
+ }
+ str = p;
+ }
+
+ free( dup );
+ return s;
+}
+
+static mvar_t *mvar_PlaylistSetNew( char *name, playlist_t *p_pl )
+{
+ mvar_t *s = mvar_New( name, "set" );
+ int i;
+
+ fprintf( stderr," mvar_PlaylistSetNew: name=`%s'\n", name );
+
+ vlc_mutex_lock( &p_pl->object_lock );
+ for( i = 0; i < p_pl->i_size; i++ )
+ {
+ mvar_t *itm = mvar_New( name, "set" );
+ char value[512];
+
+ sprintf( value, "%d", i == p_pl->i_index ? 1 : 0 );
+ mvar_AppendNewVar( itm, "current", value );
+
+ sprintf( value, "%d", i );
+ mvar_AppendNewVar( itm, "index", value );
+
+ mvar_AppendNewVar( itm, "name", p_pl->pp_items[i]->psz_name );
+
+ mvar_AppendVar( s, itm );
+ }
+ vlc_mutex_unlock( &p_pl->object_lock );
+
+ return s;
+}
+
+static mvar_t *mvar_InfoSetNew( char *name, input_thread_t *p_input )
+{
+ mvar_t *s = mvar_New( name, "set" );
+
+ input_info_category_t * p_category;
+ input_info_t * p_info;
+
+ fprintf( stderr," mvar_InfoSetNew: name=`%s'\n", name );
+ if( p_input == NULL )
+ {
+ return s;
+ }
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_category = p_input->stream.p_info;
+ while ( p_category )
+ {
+ mvar_t *cat = mvar_New( name, "set" );
+ mvar_t *iset = mvar_New( "info", "set" );
+
+ mvar_AppendNewVar( cat, "name", p_category->psz_name );
+ mvar_AppendVar( cat, iset );
+
+ p_info = p_category->p_info;
+ while ( p_info )
+ {
+ mvar_t *info = mvar_New( "info", "" );
+
+ msg_Dbg( p_input, "adding info name=%s value=%s", p_info->psz_name, p_info->psz_value );
+ mvar_AppendNewVar( info, "name", p_info->psz_name );
+ mvar_AppendNewVar( info, "value", p_info->psz_value );
+ mvar_AppendVar( iset, info );
+ p_info = p_info->p_next;
+ }
+ mvar_AppendVar( s, cat );
+ p_category = p_category->p_next;
+ }
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ return s;
+}
+
+static mvar_t *mvar_HttpdInfoSetNew( char *name, httpd_t *p_httpd, int i_type )
+{
+ mvar_t *s = mvar_New( name, "set" );
+ httpd_info_t info;
+ int i;
+
+ fprintf( stderr," mvar_HttpdInfoSetNew: name=`%s'\n", name );
+ if( !p_httpd->pf_control( p_httpd, i_type, &info, NULL ) )
+ {
+ for( i= 0; i < info.i_count; )
+ {
+ mvar_t *inf;
+
+ inf = mvar_New( name, "set" );
+ do
+ {
+ /* fprintf( stderr," mvar_HttpdInfoSetNew: append name=`%s' value=`%s'\n",
+ info.info[i].psz_name, info.info[i].psz_value ); */
+ mvar_AppendNewVar( inf,
+ info.info[i].psz_name,
+ info.info[i].psz_value );
+ i++;
+ } while( i < info.i_count && strcmp( info.info[i].psz_name, "id" ) );
+ mvar_AppendVar( s, inf );
+ }
+ }
+
+ /* free mem */
+ for( i = 0; i < info.i_count; i++ )
+ {
+ free( info.info[i].psz_name );
+ free( info.info[i].psz_value );
+ }
+
+ return s;
+}
+static mvar_t *mvar_FileSetNew( char *name, char *psz_dir )
+{
+ mvar_t *s = mvar_New( name, "set" );
+ char tmp[MAX_DIR_SIZE], *p, *src;
+#ifdef HAVE_SYS_STAT_H
+ struct stat stat_info;
+#endif
+ DIR *p_dir;
+ struct dirent *p_dir_content;
+ char sep;
+
+ /* convert all / to native separator */
+#if defined( WIN32 )
+ while( (p = strchr( psz_dir, '/' )) )
+ {
+ *p = '\\';
+ }
+ sep = '\\';
+#else
+ sep = '/';
+#endif
+
+ /* remove trailling separoator */
+ while( strlen( psz_dir ) > 1 && psz_dir[strlen( psz_dir ) -1 ] == sep )
+ {
+ psz_dir[strlen( psz_dir ) -1 ] ='\0';
+ }
+ /* remove double separator */
+ for( p = src = psz_dir; *src != '\0'; src++, p++ )
+ {
+ if( src[0] == sep && src[1] == sep )
+ {
+ src++;
+ }
+ *p = *src;
+ }
+ *p = '\0';
+
+ if( *psz_dir == '\0' )
+ {
+ return s;
+ }
+ /* first fix all .. dir */
+ p = src = psz_dir;
+ while( *src )
+ {
+ if( src[0] == '.' && src[1] == '.' )
+ {
+ src += 2;
+ if( p <= &psz_dir[1] )
+ {
+ continue;
+ }
+
+ p -= 2;
+
+ while( p > &psz_dir[1] && *p != sep )
+ {
+ p--;
+ }
+ }
+ else if( *src == sep )
+ {
+ if( p > psz_dir && p[-1] == sep )
+ {
+ src++;
+ }
+ else
+ {
+ *p++ = *src++;
+ }
+ }
+ else
+ {
+ do
+ {
+ *p++ = *src++;
+ } while( *src && *src != sep );
+ }
+ }
+ *p = '\0';
+
+ fprintf( stderr," mvar_FileSetNew: name=`%s' dir=`%s'\n", name, psz_dir );
+
+#ifdef HAVE_SYS_STAT_H
+ if( stat( psz_dir, &stat_info ) == -1 || !S_ISDIR( stat_info.st_mode ) )
+ {
+ return s;
+ }
+#endif
+
+ if( ( p_dir = opendir( psz_dir ) ) == NULL )
+ {
+ fprintf( stderr, "cannot open dir (%s)", psz_dir );
+ return s;
+ }
+
+ /* remove traling / or \ */
+ for( p = &psz_dir[strlen( psz_dir) - 1]; p >= psz_dir && ( *p =='/' || *p =='\\' ); p-- )
+ {
+ *p = '\0';
+ }
+
+ for( ;; )
+ {
+ mvar_t *f;
+
+ /* parse psz_src dir */
+ if( ( p_dir_content = readdir( p_dir ) ) == NULL )
+ {
+ break;
+ }
+ if( !strcmp( p_dir_content->d_name, "." ) )
+ {
+ continue;
+ }
+
+#if defined( WIN32 )
+ sprintf( tmp, "%s\\%s", psz_dir, p_dir_content->d_name );
+#else
+ sprintf( tmp, "%s/%s", psz_dir, p_dir_content->d_name );
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+ if( stat( tmp, &stat_info ) == -1 )
+ {
+ continue;
+ }
+#endif
+ f = mvar_New( name, "set" );
+ mvar_AppendNewVar( f, "name", tmp );
+#ifdef HAVE_SYS_STAT_H
+ if( S_ISDIR( stat_info.st_mode ) )
+ {
+ mvar_AppendNewVar( f, "type", "directory" );
+ }
+ else if( S_ISREG( stat_info.st_mode ) )
+ {
+ mvar_AppendNewVar( f, "type", "file" );
+ }
+ else
+ {
+ mvar_AppendNewVar( f, "type", "unknown" );
+ }
+
+ sprintf( tmp, "%lld", stat_info.st_size );
+ mvar_AppendNewVar( f, "size", tmp );
+
+ /* FIXME memory leak FIXME */
+#ifdef HAVE_CTIME_R
+ ctime_r( &stat_info.st_mtime, tmp );
+ mvar_AppendNewVar( f, "date", tmp );
+#else
+ mvar_AppendNewVar( f, "date", ctime( &stat_info.st_mtime ) );
+#endif
+
+#else
+ mvar_AppendNewVar( f, "type", "unknown" );
+ mvar_AppendNewVar( f, "size", "unknown" );
+ mvar_AppendNewVar( f, "date", "unknown" );
+#endif
+ mvar_AppendVar( s, f );
+ }
+
+ return s;
+}
+
+static void SSInit( rpn_stack_t * );
+static void SSClean( rpn_stack_t * );
+static void EvaluateRPN( mvar_t *, rpn_stack_t *, char * );
+
+static void SSPush ( rpn_stack_t *, char * );
+static char *SSPop ( rpn_stack_t * );
+
+static void SSPushN ( rpn_stack_t *, int );
+static int SSPopN ( rpn_stack_t *, mvar_t * );
+
+
+/****************************************************************************
+ * Macro handling
+ ****************************************************************************/
+typedef struct
+{
+ char *id;
+ char *param1;
+ char *param2;
+} macro_t;
+
+static int FileLoad( FILE *f, uint8_t **pp_data, int *pi_data )
+{
+ int i_read;
+
+ /* just load the file */
+ *pi_data = 0;
+ *pp_data = malloc( 1025 ); /* +1 for \0 */
+ while( ( i_read = fread( &(*pp_data)[*pi_data], 1, 1024, f ) ) == 1024 )
+ {
+ *pi_data += 1024;
+ *pp_data = realloc( *pp_data, *pi_data + 1025 );
+ }
+ if( i_read > 0 )
+ {
+ *pi_data += i_read;
+ }
+ (*pp_data)[*pi_data] = '\0';
+
+ return VLC_SUCCESS;
+}
+
+static int MacroParse( macro_t *m, uint8_t *psz_src )
+{
+ uint8_t *dup = strdup( psz_src );
+ uint8_t *src = dup;
+ uint8_t *p;
+ int i_skip;
+
+#define EXTRACT( name, l ) \
+ src += l; \
+ p = strchr( src, '"' ); \
+ if( p ) \
+ { \
+ *p++ = '\0'; \
+ } \
+ m->name = strdup( src ); \
+ if( !p ) \
+ { \
+ break; \
+ } \
+ src = p;
+
+ /* init m */
+ m->id = NULL;
+ m->param1 = NULL;
+ m->param2 = NULL;
+
+ /* parse */
+ src += 4;
+
+ while( *src )
+ {
+ while( *src == ' ')
+ {
+ src++;
+ }
+ if( !strncmp( src, "id=\"", 4 ) )
+ {
+ EXTRACT( id, 4 );
+ }
+ else if( !strncmp( src, "param1=\"", 8 ) )
+ {
+ EXTRACT( param1, 8 );
+ }
+ else if( !strncmp( src, "param2=\"", 8 ) )
+ {
+ EXTRACT( param2, 8 );
+ }
+ else
+ {
+ break;
+ }
+ }
+ if( strstr( src, "/>" ) )
+ {
+ src = strstr( src, "/>" ) + 2;
+ }
+ else
+ {
+ src += strlen( src );
+ }
+
+ if( m->id == NULL )
+ {
+ m->id = strdup( "" );
+ }
+ if( m->param1 == NULL )
+ {
+ m->param1 = strdup( "" );
+ }
+ if( m->param2 == NULL )
+ {
+ m->param2 = strdup( "" );
+ }
+ i_skip = src - dup;
+
+ free( dup );
+ return i_skip;
+#undef EXTRACT
+}
+
+static void MacroClean( macro_t *m )
+{
+ free( m->id );
+ free( m->param1 );
+ free( m->param2 );
+}
+
+enum macroType
+{
+ MVLC_UNKNOWN = 0,
+ MVLC_CONTROL,
+ MVLC_PLAY,
+ MVLC_STOP,
+ MVLC_PAUSE,
+ MVLC_NEXT,
+ MVLC_PREVIOUS,
+ MVLC_ADD,
+ MVLC_DEL,
+ MVLC_EMPTY,
+
+ MVLC_CLOSE,
+ MVLC_SHUTDOWN,
+ MVLC_FOREACH,
+ MVLC_IF,
+ MVLC_RPN,
+ MVLC_ELSE,
+ MVLC_END,
+ MVLC_GET,
+ MVLC_SET,
+ MVLC_INT,
+ MVLC_FLOAT,
+ MVLC_STRING,
+
+ MVLC_VALUE