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