Commit 49004d4b authored by Stan Seibert's avatar Stan Seibert

Playlist support. Now both files and directories can be specified on the

command line.  Directories are recursively examined and files added to the
playlist.

svn path=/trunk/vorbis-tools/; revision=3530
parent 17066e9f
......@@ -27,10 +27,11 @@ ogg123_DEPENDENCIES = @SHARE_LIBS@
ogg123_SOURCES = audio.c buffer.c callbacks.c \
cfgfile_options.c cmdline_options.c \
file_transport.c format.c http_transport.c \
ogg123.c oggvorbis_format.c status.c transport.c \
ogg123.c oggvorbis_format.c playlist.c \
status.c transport.c \
audio.h buffer.h callbacks.h compat.h \
cfgfile_options.h cmdline_options.h \
format.h ogg123.h status.h transport.h
format.h ogg123.h playlist.h status.h transport.h
man_MANS = $(mans)
doc_DATA = $(docs)
......
......@@ -14,7 +14,7 @@
* *
********************************************************************
last mod: $Id: ogg123.c,v 1.61 2002/06/02 03:07:11 volsung Exp $
last mod: $Id: ogg123.c,v 1.62 2002/07/06 03:23:13 volsung Exp $
********************************************************************/
......@@ -28,6 +28,8 @@
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <locale.h>
#include "audio.h"
......@@ -38,6 +40,7 @@
#include "format.h"
#include "transport.h"
#include "status.h"
#include "playlist.h"
#include "compat.h"
#include "ogg123.h"
......@@ -270,6 +273,11 @@ void print_audio_devices_info(audio_device_t *d)
int main(int argc, char **argv)
{
int optind;
char **playlist_array;
playlist_t *list = playlist_create();
int items;
struct stat stat_buf;
int i;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
......@@ -286,23 +294,39 @@ int main(int argc, char **argv)
audio_play_arg.devices = options.devices;
audio_play_arg.stat_format = stat_format;
/* Don't use status_message until after this point! */
status_set_verbosity(options.verbosity);
/* Add remaining arguments to playlist */
for (i = optind; i < argc; i++) {
if (stat(argv[i], &stat_buf) == 0) {
print_audio_devices_info(options.devices);
if (S_ISDIR(stat_buf.st_mode)) {
if (playlist_append_directory(list, argv[i]) == 0)
fprintf(stderr,
_("Warning: Could not read directory %s.\n"), argv[i]);
} else {
playlist_append_file(list, argv[i]);
}
} else
fprintf(stderr,
_("Warning: Could not access %s.\n"), argv[i]);
/* Setup signal handlers and callbacks */
}
ATEXIT (exit_cleanup);
signal (SIGINT, signal_handler);
signal (SIGTSTP, signal_handler);
signal (SIGCONT, signal_handler);
/* Do we have anything left to play? */
if (optind == argc) {
if (playlist_length(list) == 0) {
cmdline_usage();
exit(1);
} else {
playlist_array = playlist_to_array(list, &items);
playlist_destroy(list);
list = NULL;
}
/* Don't use status_message until after this point! */
status_set_verbosity(options.verbosity);
print_audio_devices_info(options.devices);
/* Setup buffer */
if (options.buffer_size > 0) {
......@@ -324,21 +348,30 @@ int main(int argc, char **argv)
srandom(time(NULL));
for (i = optind; i < argc; i++) {
int j = i + random() % (argc - i);
char *temp = argv[i];
argv[i] = argv[j];
argv[j] = temp;
for (i = 0; i < items; i++) {
int j = i + random() % (items - i);
char *temp = playlist_array[i];
playlist_array[i] = playlist_array[j];
playlist_array[j] = temp;
}
}
/* Play the files/streams */
/* Setup signal handlers and callbacks */
while (optind < argc && !sig_request.exit) {
play(argv[optind]);
optind++;
ATEXIT (exit_cleanup);
signal (SIGINT, signal_handler);
signal (SIGTSTP, signal_handler);
signal (SIGCONT, signal_handler);
/* Play the files/streams */
i = 0;
while (i < items && !sig_request.exit) {
play(playlist_array[i]);
i++;
}
playlist_array_destroy(playlist_array, items);
exit (0);
}
......
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
* THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
* PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2001 *
* by Stan Seibert <volsung@xiph.org> AND OTHER CONTRIBUTORS *
* http://www.xiph.org/ *
* *
********************************************************************
last mod: $Id: playlist.c,v 1.1 2002/07/06 03:23:13 volsung Exp $
********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include "playlist.h"
#include "i18n.h"
playlist_element_t *playlist_element_create(char *filename)
{
playlist_element_t *element = (playlist_element_t *)
malloc(sizeof(playlist_t));
if (element == NULL) {
fprintf(stderr,
_("Error: Out of memory in create_playlist_member().\n"));
exit(1);
}
if (filename == NULL)
element->filename = NULL;
else {
element->filename = strdup(filename);
if (element->filename == NULL) {
fprintf(stderr,
_("Error: Out of memory in create_playlist_member().\n"));
exit(1);
}
}
element->next = NULL;
return element;
}
/* Only destroys the current node. Does not affect linked nodes. */
void playlist_element_destroy(playlist_element_t *element)
{
free(element->filename);
free(element);
}
playlist_t *playlist_create()
{
playlist_t *list = (playlist_t *) malloc(sizeof(playlist_t));
if (list != NULL) {
list->head = playlist_element_create(NULL);
list->last = list->head;
}
return list;
}
void playlist_destroy(playlist_t *list) {
playlist_element_t *next_element;
while (list->head != NULL) {
next_element = list->head->next;
playlist_element_destroy(list->head);
list->head = next_element;
}
free(list);
}
/* All of the playlist_append_* functions return
1 if append was successful
0 if failure (either directory could not be accessed or playlist on disk
could not be opened)
*/
/* Add this filename to the playlist. Filename will be strdup()'ed. Note
that this function will never fail. */
int playlist_append_file(playlist_t *list, char *filename)
{
list->last->next = playlist_element_create(filename);
list->last = list->last->next;
return 1; /* No way to fail */
}
/* Recursively adds files from the directory and subdirectories */
int playlist_append_directory(playlist_t *list, char *dirname)
{
DIR *dir;
int dir_len = strlen(dirname);
struct dirent *entry;
struct stat stat_buf;
char nextfile[NAME_MAX + 1];
dir = opendir(dirname);
if (dir == NULL) {
return 0;
}
entry = readdir(dir);
while (entry != NULL) {
int sub_len = strlen(entry->d_name);
/* Make sure full pathname is within limits and we don't parse the
relative directory entries. */
if (dir_len + sub_len + 1 < NAME_MAX
&& strcmp(entry->d_name, ".") != 0
&& strcmp(entry->d_name, "..") != 0 ) {
/* Build the new full pathname */
strcpy(nextfile, dirname);
strcat(nextfile, "/");
strcat(nextfile, entry->d_name);
if (stat(nextfile, &stat_buf) == 0) {
/* Decide what type of entry this is */
if (S_ISDIR(stat_buf.st_mode)) {
/* Recursively follow directories */
if ( playlist_append_directory(list, nextfile) == 0 ) {
fprintf(stderr,
_("Warning: Could not read directory %s.\n"),
nextfile);
}
} else {
/* Assume everything else is a file of some sort */
playlist_append_file(list, nextfile);
}
}
}
entry = readdir(dir);
}
closedir(dir);
return 1;
}
/* Opens a file containing filenames, one per line, and adds them to the
playlist */
int playlist_append_from_file(playlist_t *list, char *playlist_filename)
{
FILE *fp;
char filename[NAME_MAX+1];
int length;
int i;
fp = fopen(playlist_filename, "r");
if (fp == NULL)
return 0;
while (!feof(fp)) {
fgets(filename, NAME_MAX+1 /* no, really! */, fp);
length = strlen(filename);
// Skip blank lines
for (i = 0; i < length && isspace(filename[i]); i++);
if (i == length)
continue;
// Crop off last \n if present
if (filename[length - 1] == '\n')
filename[length - 1] = '\0';
playlist_append_file(list, filename);
}
return 1;
}
/* Return the number of items in the playlist */
int playlist_length(playlist_t *list)
{
int length;
playlist_element_t *element;
element = list->head;
length = 0; // don't count head node
while (element->next != NULL) {
length++;
element = element->next;
}
return length;
}
/* Convert the playlist to an array of strings. Strings are deep copied.
Size will be set to the number of elements in the array. */
char **playlist_to_array(playlist_t *list, int *size)
{
char **array;
int i;
playlist_element_t *element;
*size = playlist_length(list);
array = calloc(*size, sizeof(char *));
if (array == NULL) {
fprintf(stderr,
_("Error: Out of memory in playlist_to_array().\n"));
exit(1);
}
for (i = 0, element = list->head->next;
i < *size;
i++, element = element->next) {
array[i] = strdup(element->filename);
if (array[i] == NULL) {
fprintf(stderr,
_("Error: Out of memory in playlist_to_array().\n"));
exit(1);
}
}
return array;
}
/* Deallocate array and all contained strings created by playlist_to_array. */
void playlist_array_destroy(char **array, int size)
{
int i;
for (i = 0; i < size; i++)
free(array[i]);
free(array);
}
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
* THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
* PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2002 *
* by Kenneth C. Arnold <ogg@arnoldnet.net> AND OTHER CONTRIBUTORS *
* http://www.xiph.org/ *
* *
********************************************************************
last mod: $Id: playlist.h,v 1.1 2002/07/06 03:23:13 volsung Exp $
********************************************************************/
#ifndef __PLAYLIST_H__
#define __PLAYLIST_H__
typedef struct playlist_element_t {
char *filename;
struct playlist_element_t *next;
} playlist_element_t;
/* Actual playlist structure */
typedef struct playlist_t {
/* Linked list with empty head node */
playlist_element_t *head;
/* Keep track of this for speedy appends */
playlist_element_t *last;
} playlist_t;
playlist_t *playlist_create();
void playlist_destroy(playlist_t *list);
/* All of the playlist_append_* functions return
1 if append was successful
0 if failure (either directory could not be accessed or playlist on disk
could not be opened)
*/
/* Add this filename to the playlist. Filename will be strdup()'ed. Note
that this function will never fail. */
int playlist_append_file(playlist_t *list, char *filename);
/* Recursively adds files from the directory and subdirectories */
int playlist_append_directory(playlist_t *list, char *dirname);
/* Opens a file containing filenames, one per line, and adds them to the
playlist */
int playlist_append_from_file(playlist_t *list, char *playlist_filename);
/* Return the number of items in the playlist */
int playlist_length(playlist_t *list);
/* Convert the playlist to an array of strings. Strings are deep copied.
Size will be set to the number of elements in the array. */
char **playlist_to_array(playlist_t *list, int *size);
/* Deallocate array and all contained strings created by playlist_to_array. */
void playlist_array_destroy(char **array, int size);
#endif /* __PLAYLIST_H__ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment