]> git.sesse.net Git - vlc/blob - src/interface/intf_playlist.c
* Fixed the BeOS compile typo.
[vlc] / src / interface / intf_playlist.c
1 /*****************************************************************************
2  * intf_playlist.c : Playlist management functions
3  *****************************************************************************
4  * Copyright (C) 1999, 2000 VideoLAN
5  * $Id: intf_playlist.c,v 1.7 2001/05/30 17:03:12 sam Exp $
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23 #include "defs.h"
24
25 #include "config.h"
26
27 #include <stdlib.h>                                      /* free(), strtol() */
28 #include <stdio.h>                                              /* sprintf() */
29 #include <string.h>                                            /* strerror() */
30 #include <errno.h>                                                 /* ENOMEM */
31
32 #include "common.h"
33 #include "threads.h"
34
35 #include "intf_msg.h"
36 #include "intf_playlist.h"
37
38 #include "main.h"
39
40 /*****************************************************************************
41  * Local prototypes
42  *****************************************************************************/
43 static void NextItem( playlist_t * p_playlist );
44
45 /*****************************************************************************
46  * intf_PlaylistCreate: create playlist
47  *****************************************************************************
48  * Create a playlist structure.
49  *****************************************************************************/
50 playlist_t * intf_PlaylistCreate ( void )
51 {
52     playlist_t *p_playlist;
53
54     /* Allocate structure */
55     p_playlist = malloc( sizeof( playlist_t ) );
56     if( !p_playlist )
57     {
58         intf_ErrMsg( "intf error: couldn't create playlist (%s)",
59                      strerror( ENOMEM ) );
60         return( NULL );
61     }
62
63     return( p_playlist );
64 }
65
66 /*****************************************************************************
67  * intf_PlaylistInit: initialize playlist
68  *****************************************************************************
69  * Initialize a playlist structure.
70  *****************************************************************************/
71 void intf_PlaylistInit ( playlist_t * p_playlist )
72 {
73     vlc_mutex_init( &p_playlist->change_lock );
74
75     p_playlist->i_index = -1;    /* -1 means we are not playing anything yet */
76     p_playlist->i_size = 0;
77
78     p_playlist->i_mode = PLAYLIST_FORWARD;
79     p_playlist->i_seed = 0;
80     p_playlist->b_stopped = 0;
81
82     /* There is no current item */
83     p_playlist->current.i_type = 0;
84     p_playlist->current.i_status = 0;
85     p_playlist->current.psz_name = NULL;
86
87     /* The playlist is empty */
88     p_playlist->p_item = NULL;
89
90     intf_WarnMsg( 3, "intf: playlist initialized" );
91 }
92
93 /*****************************************************************************
94  * intf_PlaylistAdd: add an item to the playlist
95  *****************************************************************************
96  * Add an item to the playlist at position i_pos. If i_pos is PLAYLIST_END,
97  * add it at the end regardless of the playlist current size.
98  *****************************************************************************/
99 int intf_PlaylistAdd( playlist_t * p_playlist, int i_pos,
100                       const char * psz_item )
101 {
102     int i_index;
103     playlist_item_t * p_item;
104
105     vlc_mutex_lock( &p_playlist->change_lock );
106
107     if( i_pos == PLAYLIST_END )
108     {
109         i_pos = p_playlist->i_size;
110     }
111     else if( i_pos > p_playlist->i_size )
112     {
113         intf_ErrMsg( "intf error: inserting item beyond playlist size" );
114         vlc_mutex_unlock( &p_playlist->change_lock );
115         return( -1 );
116     }
117
118     /* Increment playlist size */
119     p_playlist->i_size++;
120     p_playlist->p_item = realloc( p_playlist->p_item,
121                     p_playlist->i_size * sizeof( playlist_item_t ) );
122
123     /* Move second place of the playlist to make room for new item */
124     for( i_index = p_playlist->i_size - 1; i_index > i_pos; i_index-- )
125     {
126         p_playlist->p_item[ i_index ] = p_playlist->p_item[ i_index - 1 ];
127     }
128
129     /* Insert the new item */
130     p_item = &p_playlist->p_item[ i_pos ];
131
132     p_item->i_type = 0;
133     p_item->i_status = 0;
134     p_item->psz_name = strdup( psz_item );
135
136     intf_WarnMsg( 3, "intf: added `%s' to playlist", psz_item );
137
138     vlc_mutex_unlock( &p_playlist->change_lock );
139
140     return( 0 );
141 }
142
143 /*****************************************************************************
144  * intf_PlaylistNext: switch to next playlist item
145  *****************************************************************************
146  * Switch to the next item of the playlist. If there is no next item, the
147  * position of the resulting item is set to -1.
148  *****************************************************************************/
149 void intf_PlaylistNext( playlist_t * p_playlist )
150 {
151     vlc_mutex_lock( &p_playlist->change_lock );
152
153     NextItem( p_playlist );
154
155     vlc_mutex_unlock( &p_playlist->change_lock );
156 }
157
158 /*****************************************************************************
159  * intf_PlaylistPrev: switch to previous playlist item
160  *****************************************************************************
161  * Switch to the previous item of the playlist. If there is no previous
162  * item, the position of the resulting item is set to -1.
163  *****************************************************************************/
164 void intf_PlaylistPrev( playlist_t * p_playlist )
165 {
166     vlc_mutex_lock( &p_playlist->change_lock );
167     p_playlist->i_mode = -p_playlist->i_mode;
168     
169     NextItem( p_playlist );
170
171     p_playlist->i_mode = -p_playlist->i_mode;
172     vlc_mutex_unlock( &p_playlist->change_lock );
173 }
174
175 /*****************************************************************************
176  * intf_PlaylistDelete: delete an item from the playlist
177  *****************************************************************************
178  * Delete the item in the playlist with position i_pos.
179  *****************************************************************************/
180 int intf_PlaylistDelete( playlist_t * p_playlist, int i_pos )
181 {
182     int i_index;
183     char * psz_name;
184
185     vlc_mutex_lock( &p_playlist->change_lock );
186
187     if( !p_playlist->i_size || i_pos >= p_playlist->i_size )
188     {
189         intf_ErrMsg( "intf error: deleting item beyond playlist size" );
190         vlc_mutex_unlock( &p_playlist->change_lock );
191         return( -1 );
192     }
193
194     /* Store the location of the item's name */
195     psz_name = p_playlist->p_item[ i_pos ].psz_name;
196
197     /* Fill the room by moving the next items */
198     for( i_index = i_pos; i_index < p_playlist->i_size - 1; i_index++ )
199     {
200         p_playlist->p_item[ i_index ] = p_playlist->p_item[ i_index + 1 ];
201     }
202
203     if( i_pos < p_playlist->i_index )
204         p_playlist->i_index--;
205         
206     
207     /* Decrement playlist size */
208     p_playlist->i_size--;
209     p_playlist->p_item = realloc( p_playlist->p_item,
210                     p_playlist->i_size * sizeof( playlist_item_t ) );
211
212     intf_WarnMsg( 3, "intf: removed `%s' from playlist", psz_name );
213     
214
215     /* Delete the item */
216     free( psz_name );
217
218     vlc_mutex_unlock( &p_playlist->change_lock );
219
220     return( 0 );
221 }
222
223 /*****************************************************************************
224  * intf_PlaylistDestroy: destroy the playlist
225  *****************************************************************************
226  * Delete all items in the playlist and free the playlist structure.
227  *****************************************************************************/
228 void intf_PlaylistDestroy( playlist_t * p_playlist )
229 {
230     int i_index;
231
232     for( i_index = p_playlist->i_size - 1; p_playlist->i_size; i_index-- )
233     {
234         intf_PlaylistDelete( p_playlist, i_index );
235     }
236
237     vlc_mutex_destroy( &p_playlist->change_lock );
238
239     if( p_playlist->current.psz_name != NULL )
240     {
241         free( p_playlist->current.psz_name );
242     }
243
244     free( p_playlist );
245
246     intf_WarnMsg( 3, "intf: playlist destroyed" );
247 }
248
249 /*****************************************************************************
250  * intf_PlaylistJumpto: go to a specified position in playlist.
251  *****************************************************************************/
252 void intf_PlaylistJumpto( playlist_t * p_playlist , int i_pos)
253 {
254     vlc_mutex_lock( &p_playlist->change_lock );
255  
256     p_playlist->i_index = i_pos;
257     
258     if( p_playlist->i_index != -1 )
259     {
260         if( p_playlist->current.psz_name != NULL )
261         {
262             free( p_playlist->current.psz_name );
263         }
264
265         p_playlist->current = p_playlist->p_item[ p_playlist->i_index ];
266         p_playlist->current.psz_name
267                             = strdup( p_playlist->current.psz_name );
268
269     }
270     p_main->p_playlist->b_stopped = 0;
271
272     vlc_mutex_unlock( &p_playlist->change_lock );
273 }   
274
275 /* URL-decode a file: URL path, return NULL if it's not what we expect */
276 void intf_UrlDecode( char *encoded_path )
277 {
278     char *tmp = NULL, *cur = NULL, *ext = NULL;
279     int realchar;
280
281     if( !encoded_path || *encoded_path == '\0' )
282     {
283         return;
284     }
285     
286     cur = encoded_path ;
287     
288     tmp = calloc(strlen(encoded_path) + 1,  sizeof(char) );
289     
290     while ( ( ext = strchr(cur, '%') ) != NULL)
291     {
292         strncat(tmp, cur, (ext - cur) / sizeof(char));
293         ext++;
294
295         if (!sscanf(ext, "%2x", &realchar))
296         {
297             free(tmp);
298             return;
299         }
300
301         tmp[strlen(tmp)] = (char)realchar;
302         
303         cur = ext + 2;
304     }
305
306     strcat(tmp, cur);
307     strcpy(encoded_path,tmp);
308 }
309
310 /*****************************************************************************
311  * Following functions are local
312  *****************************************************************************/
313
314 /*****************************************************************************
315  * NextItem: select next playlist item
316  *****************************************************************************
317  * This function copies the next playlist item to the current structure,
318  * depending on the playlist browsing mode.
319  *****************************************************************************/
320 static void NextItem( playlist_t * p_playlist )
321 {
322     if( !p_playlist->i_size )
323     {
324         p_playlist->i_index = -1;
325     }
326     else
327     {
328         switch( p_playlist->i_mode )
329         {
330         case PLAYLIST_FORWARD:
331             p_playlist->i_index++;
332             if( p_playlist->i_index > p_playlist->i_size - 1 )
333             {
334                 p_playlist->i_index = -1;
335             }
336         break;
337
338         case PLAYLIST_FORWARD_LOOP:
339             p_playlist->i_index++;
340             if( p_playlist->i_index > p_playlist->i_size - 1 )
341             {
342                 p_playlist->i_index = 0;
343             }
344         break;
345
346         case PLAYLIST_BACKWARD:
347             p_playlist->i_index--;
348             if( p_playlist->i_index < 0 )
349             {
350                 p_playlist->i_index = -1;
351             }
352         break;
353
354         case PLAYLIST_BACKWARD_LOOP:
355             p_playlist->i_index--;
356             if( p_playlist->i_index < 0 )
357             {
358                 p_playlist->i_index = p_playlist->i_size - 1;
359             }
360         break;
361
362         case PLAYLIST_REPEAT_CURRENT:
363             /* Just repeat what we were doing */
364             if( p_playlist->i_index < 0
365                     || p_playlist->i_index > p_playlist->i_size - 1 )
366             {
367                 p_playlist->i_index = 0;
368             }
369         break;
370
371         case PLAYLIST_RANDOM:
372             /* FIXME: TODO ! */
373             p_playlist->i_index++;
374             if( p_playlist->i_index > p_playlist->i_size - 1 )
375             {
376                 p_playlist->i_index = 0;
377             }
378         break;
379         }
380
381         /* Duplicate the playlist entry */
382         if( p_playlist->i_index != -1 )
383         {
384             if( p_playlist->current.psz_name != NULL )
385             {
386                 free( p_playlist->current.psz_name );
387             }
388             p_playlist->current = p_playlist->p_item[ p_playlist->i_index ];
389             p_playlist->current.psz_name
390                                 = strdup( p_playlist->current.psz_name );
391         }
392     }
393 }
394