1 /********************************************************************
3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5 * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
6 * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
8 * THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2001 *
9 * by Stan Seibert <volsung@xiph.org> AND OTHER CONTRIBUTORS *
10 * http://www.xiph.org/ *
12 ********************************************************************
14 last mod: $Id: playlist.c,v 1.3 2002/07/13 17:57:10 volsung Exp $
16 ********************************************************************/
27 #include <sys/types.h>
34 /* Work with *BSD differences */
35 #if !defined(NAME_MAX) && defined(MAXNAMLEN)
36 #define NAME_MAX MAXNAMLEN
39 playlist_element_t
*playlist_element_create(char *filename
)
41 playlist_element_t
*element
= (playlist_element_t
*)
42 malloc(sizeof(playlist_t
));
44 if (element
== NULL
) {
46 _("Error: Out of memory in create_playlist_member().\n"));
51 element
->filename
= NULL
;
53 element
->filename
= strdup(filename
);
55 if (element
->filename
== NULL
) {
57 _("Error: Out of memory in create_playlist_member().\n"));
68 /* Only destroys the current node. Does not affect linked nodes. */
69 void playlist_element_destroy(playlist_element_t
*element
)
71 free(element
->filename
);
77 playlist_t
*playlist_create()
79 playlist_t
*list
= (playlist_t
*) malloc(sizeof(playlist_t
));
82 list
->head
= playlist_element_create(NULL
);
83 list
->last
= list
->head
;
90 void playlist_destroy(playlist_t
*list
) {
91 playlist_element_t
*next_element
;
93 while (list
->head
!= NULL
) {
94 next_element
= list
->head
->next
;
96 playlist_element_destroy(list
->head
);
98 list
->head
= next_element
;
105 /* All of the playlist_append_* functions return
106 1 if append was successful
107 0 if failure (either directory could not be accessed or playlist on disk
112 /* Add this filename to the playlist. Filename will be strdup()'ed. Note
113 that this function will never fail. */
114 int playlist_append_file(playlist_t
*list
, char *filename
)
116 list
->last
->next
= playlist_element_create(filename
);
117 list
->last
= list
->last
->next
;
119 return 1; /* No way to fail */
122 /* Recursively adds files from the directory and subdirectories */
123 int playlist_append_directory(playlist_t
*list
, char *dirname
)
126 int dir_len
= strlen(dirname
);
127 struct dirent
*entry
;
128 struct stat stat_buf
;
129 char nextfile
[NAME_MAX
+ 1];
131 dir
= opendir(dirname
);
137 entry
= readdir(dir
);
138 while (entry
!= NULL
) {
139 int sub_len
= strlen(entry
->d_name
);
141 /* Make sure full pathname is within limits and we don't parse the
142 relative directory entries. */
143 if (dir_len
+ sub_len
+ 1 < NAME_MAX
144 && strcmp(entry
->d_name
, ".") != 0
145 && strcmp(entry
->d_name
, "..") != 0 ) {
147 /* Build the new full pathname */
148 strcpy(nextfile
, dirname
);
149 strcat(nextfile
, "/");
150 strcat(nextfile
, entry
->d_name
);
152 if (stat(nextfile
, &stat_buf
) == 0) {
154 /* Decide what type of entry this is */
155 if (S_ISDIR(stat_buf
.st_mode
)) {
157 /* Recursively follow directories */
158 if ( playlist_append_directory(list
, nextfile
) == 0 ) {
160 _("Warning: Could not read directory %s.\n"),
164 /* Assume everything else is a file of some sort */
165 playlist_append_file(list
, nextfile
);
170 entry
= readdir(dir
);
179 /* Opens a file containing filenames, one per line, and adds them to the
181 int playlist_append_from_file(playlist_t
*list
, char *playlist_filename
)
184 char filename
[NAME_MAX
+1];
185 struct stat stat_buf
;
189 if (strcmp(playlist_filename
, "-") == 0)
192 fp
= fopen(playlist_filename
, "r");
199 if ( fgets(filename
, NAME_MAX
+1 /* no, really! */, fp
) == NULL
)
202 filename
[NAME_MAX
] = '\0'; /* Just to make sure */
203 length
= strlen(filename
);
205 /* Skip blank lines */
206 for (i
= 0; i
< length
&& isspace(filename
[i
]); i
++);
210 /* Crop off trailing newlines if present. Handle DOS (\r\n), Unix (\n)
211 * and MacOS<9 (\r) line endings. */
212 if (filename
[length
- 2] == '\r' && filename
[length
- 1] == '\n')
213 filename
[length
- 2] = '\0';
214 else if (filename
[length
- 1] == '\n' || filename
[length
- 1] == '\r')
215 filename
[length
- 1] = '\0';
217 if (stat(filename
, &stat_buf
) == 0) {
219 if (S_ISDIR(stat_buf
.st_mode
)) {
220 if (playlist_append_directory(list
, filename
) == 0)
222 _("Warning from playlist %s: "
223 "Could not read directory %s.\n"), playlist_filename
,
226 playlist_append_file(list
, filename
);
228 } else /* If we can't stat it, it might be a non-disk source */
229 playlist_append_file(list
, filename
);
237 /* Return the number of items in the playlist */
238 int playlist_length(playlist_t
*list
)
241 playlist_element_t
*element
;
243 element
= list
->head
;
244 length
= 0; /* don't count head node */
245 while (element
->next
!= NULL
) {
247 element
= element
->next
;
254 /* Convert the playlist to an array of strings. Strings are deep copied.
255 Size will be set to the number of elements in the array. */
256 char **playlist_to_array(playlist_t
*list
, int *size
)
260 playlist_element_t
*element
;
262 *size
= playlist_length(list
);
263 array
= calloc(*size
, sizeof(char *));
267 _("Error: Out of memory in playlist_to_array().\n"));
271 for (i
= 0, element
= list
->head
->next
;
273 i
++, element
= element
->next
) {
275 array
[i
] = strdup(element
->filename
);
277 if (array
[i
] == NULL
) {
279 _("Error: Out of memory in playlist_to_array().\n"));
289 /* Deallocate array and all contained strings created by playlist_to_array. */
290 void playlist_array_destroy(char **array
, int size
)
294 for (i
= 0; i
< size
; i
++)