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 $
7 * Authors: Samuel Hocevar <sam@zoy.org>
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.
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.
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 */
28 #include <videolan/vlc.h>
30 #include "intf_playlist.h"
32 /*****************************************************************************
34 *****************************************************************************/
35 static void NextItem( playlist_t
* p_playlist
);
37 /*****************************************************************************
38 * intf_PlaylistCreate: create playlist
39 *****************************************************************************
40 * Create a playlist structure.
41 *****************************************************************************/
42 playlist_t
* intf_PlaylistCreate ( void )
44 playlist_t
*p_playlist
;
46 /* Allocate structure */
47 p_playlist
= malloc( sizeof( playlist_t
) );
50 intf_ErrMsg( "intf error: couldn't create playlist (%s)",
58 /*****************************************************************************
59 * intf_PlaylistInit: initialize playlist
60 *****************************************************************************
61 * Initialize a playlist structure.
62 *****************************************************************************/
63 void intf_PlaylistInit ( playlist_t
* p_playlist
)
65 vlc_mutex_init( &p_playlist
->change_lock
);
67 p_playlist
->i_index
= -1; /* -1 means we are not playing anything yet */
68 p_playlist
->i_size
= 0;
70 p_playlist
->i_mode
= PLAYLIST_FORWARD
;
71 p_playlist
->i_seed
= 0;
72 p_playlist
->b_stopped
= 0;
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
;
79 /* The playlist is empty */
80 p_playlist
->p_item
= NULL
;
82 intf_WarnMsg( 3, "intf: playlist initialized" );
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
)
95 playlist_item_t
* p_item
;
97 vlc_mutex_lock( &p_playlist
->change_lock
);
99 if( i_pos
== PLAYLIST_END
)
101 i_pos
= p_playlist
->i_size
;
103 else if( i_pos
> p_playlist
->i_size
)
105 intf_ErrMsg( "intf error: inserting item beyond playlist size" );
106 vlc_mutex_unlock( &p_playlist
->change_lock
);
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
) );
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
-- )
118 p_playlist
->p_item
[ i_index
] = p_playlist
->p_item
[ i_index
- 1 ];
121 /* Insert the new item */
122 p_item
= &p_playlist
->p_item
[ i_pos
];
125 p_item
->i_status
= 0;
126 p_item
->psz_name
= strdup( psz_item
);
128 intf_WarnMsg( 3, "intf: added `%s' to playlist", psz_item
);
130 vlc_mutex_unlock( &p_playlist
->change_lock
);
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
)
143 vlc_mutex_lock( &p_playlist
->change_lock
);
145 NextItem( p_playlist
);
147 vlc_mutex_unlock( &p_playlist
->change_lock
);
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
)
158 vlc_mutex_lock( &p_playlist
->change_lock
);
160 p_playlist
->i_mode
= -p_playlist
->i_mode
;
161 NextItem( p_playlist
);
162 p_playlist
->i_mode
= -p_playlist
->i_mode
;
164 vlc_mutex_unlock( &p_playlist
->change_lock
);
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
)
177 vlc_mutex_lock( &p_playlist
->change_lock
);
179 if( !p_playlist
->i_size
|| i_pos
>= p_playlist
->i_size
)
181 intf_ErrMsg( "intf error: deleting item beyond playlist size" );
182 vlc_mutex_unlock( &p_playlist
->change_lock
);
186 /* Store the location of the item's name */
187 psz_name
= p_playlist
->p_item
[ i_pos
].psz_name
;
189 /* Fill the room by moving the next items */
190 for( i_index
= i_pos
; i_index
< p_playlist
->i_size
- 1; i_index
++ )
192 p_playlist
->p_item
[ i_index
] = p_playlist
->p_item
[ i_index
+ 1 ];
195 if( i_pos
< p_playlist
->i_index
)
196 p_playlist
->i_index
--;
199 /* Decrement playlist size */
200 p_playlist
->i_size
--;
201 if( p_playlist
->i_size
)
203 p_playlist
->p_item
= realloc( p_playlist
->p_item
,
204 p_playlist
->i_size
* sizeof( playlist_item_t
) );
208 free( p_playlist
->p_item
);
209 p_playlist
->p_item
= NULL
;
212 intf_WarnMsg( 3, "intf: removed `%s' from playlist", psz_name
);
215 /* Delete the item */
218 vlc_mutex_unlock( &p_playlist
->change_lock
);
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
)
232 for( i_index
= p_playlist
->i_size
- 1; p_playlist
->i_size
; i_index
-- )
234 intf_PlaylistDelete( p_playlist
, i_index
);
237 vlc_mutex_destroy( &p_playlist
->change_lock
);
239 if( p_playlist
->current
.psz_name
!= NULL
)
241 free( p_playlist
->current
.psz_name
);
246 intf_WarnMsg( 3, "intf: playlist destroyed" );
249 /*****************************************************************************
250 * intf_PlaylistJumpto: go to a specified position in playlist.
251 *****************************************************************************/
252 void intf_PlaylistJumpto( playlist_t
* p_playlist
, int i_pos
)
254 vlc_mutex_lock( &p_playlist
->change_lock
);
263 if( p_playlist
->current
.psz_name
!= NULL
)
265 free( p_playlist
->current
.psz_name
);
268 p_playlist
->current
= p_playlist
->p_item
[ i_pos
];
269 p_playlist
->current
.psz_name
= strdup( p_playlist
->current
.psz_name
);
272 p_playlist
->i_index
= i_pos
;
273 p_playlist
->b_stopped
= 0;
275 vlc_mutex_unlock( &p_playlist
->change_lock
);
278 /* URL-decode a file: URL path, return NULL if it's not what we expect */
279 void intf_UrlDecode( char *encoded_path
)
281 char *tmp
= NULL
, *cur
= NULL
, *ext
= NULL
;
284 if( !encoded_path
|| *encoded_path
== '\0' )
291 tmp
= calloc(strlen(encoded_path
) + 1, sizeof(char) );
293 while ( ( ext
= strchr(cur
, '%') ) != NULL
)
295 strncat(tmp
, cur
, (ext
- cur
) / sizeof(char));
298 if (!sscanf(ext
, "%2x", &realchar
))
304 tmp
[strlen(tmp
)] = (char)realchar
;
310 strcpy(encoded_path
,tmp
);
313 /*****************************************************************************
314 * Following functions are local
315 *****************************************************************************/
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
)
325 if( !p_playlist
->i_size
)
327 p_playlist
->i_index
= -1;
331 switch( p_playlist
->i_mode
)
333 case PLAYLIST_FORWARD
:
334 p_playlist
->i_index
++;
335 if( p_playlist
->i_index
> p_playlist
->i_size
- 1 )
337 p_playlist
->i_index
= -1;
341 case PLAYLIST_FORWARD_LOOP
:
342 p_playlist
->i_index
++;
343 if( p_playlist
->i_index
> p_playlist
->i_size
- 1 )
345 p_playlist
->i_index
= 0;
349 case PLAYLIST_BACKWARD
:
350 p_playlist
->i_index
--;
351 if( p_playlist
->i_index
< 0 )
353 p_playlist
->i_index
= -1;
357 case PLAYLIST_BACKWARD_LOOP
:
358 p_playlist
->i_index
--;
359 if( p_playlist
->i_index
< 0 )
361 p_playlist
->i_index
= p_playlist
->i_size
- 1;
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 )
370 p_playlist
->i_index
= 0;
374 case PLAYLIST_RANDOM
:
376 p_playlist
->i_index
++;
377 if( p_playlist
->i_index
> p_playlist
->i_size
- 1 )
379 p_playlist
->i_index
= 0;
384 /* Duplicate the playlist entry */
385 if( p_playlist
->i_index
!= -1 )
387 if( p_playlist
->current
.psz_name
!= NULL
)
389 free( p_playlist
->current
.psz_name
);
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
);