aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2008-10-05 00:36:55 -0700
committerEric Wong <normalperson@yhbt.net>2008-10-05 00:36:55 -0700
commitc4802008b899cc2d272d5e9b6c7000736ed3a6df (patch)
tree5d9146af43e9999ed32e726d52de7e0d2674958c
parent9beb6b61ab28122de049da918afad424b1e92c42 (diff)
parent1533279fb18b2b0f53345f0e0727d2f0f968c00d (diff)
downloadmpd-c4802008b899cc2d272d5e9b6c7000736ed3a6df.tar.gz
mpd-c4802008b899cc2d272d5e9b6c7000736ed3a6df.tar.xz
mpd-c4802008b899cc2d272d5e9b6c7000736ed3a6df.zip
Merge commit '1533279fb18b2b0f53345f0e0727d2f0f968c00d'
* commit '1533279fb18b2b0f53345f0e0727d2f0f968c00d': directory: reuse existing directory if found on update song: better handling of existing songs when rereading DB tag: merge clearMpdTag into tag_free song: start avoiding race in updateSongInfo command: get rid of specialized list handlers directory: simplify list update handling logic main_notify: define main_task so we can use it for assertions directory: streamline deletes song: start avoiding race in updateSongInfo playlist: small lines of code reduction Revert "Start using song pointers in core data structures" Conflicts: src/playlist.c
-rw-r--r--src/command.c218
-rw-r--r--src/decode.c33
-rw-r--r--src/decode.h2
-rw-r--r--src/directory.c165
-rw-r--r--src/directory.h7
-rw-r--r--src/inputPlugins/wavpack_plugin.c6
-rw-r--r--src/main_notify.c3
-rw-r--r--src/main_notify.h4
-rw-r--r--src/outputBuffer.c1
-rw-r--r--src/player_error.c36
-rw-r--r--src/player_error.h5
-rw-r--r--src/playlist.c142
-rw-r--r--src/playlist.h2
-rw-r--r--src/song.c38
-rw-r--r--src/tag.c14
15 files changed, 283 insertions, 393 deletions
diff --git a/src/command.c b/src/command.c
index 28b6ee3bb..cc5f615c7 100644
--- a/src/command.c
+++ b/src/command.c
@@ -127,8 +127,6 @@
typedef struct _CommandEntry CommandEntry;
typedef int (*CommandHandlerFunction) (int, int *, int, char **);
-typedef int (*CommandListHandlerFunction)
- (int, int *, int, char **, struct strnode *, CommandEntry *);
/* if min: -1 don't check args *
* if max: -1 no max args */
@@ -138,7 +136,6 @@ struct _CommandEntry {
int max;
int reqPermission;
CommandHandlerFunction handler;
- CommandListHandlerFunction listHandler;
};
/* this should really be "need a non-negative integer": */
@@ -152,23 +149,8 @@ static const char check_non_negative[] = "\"%s\" is not an integer >= 0";
static const char *current_command;
static int command_listNum;
-
-static CommandEntry *getCommandEntryFromString(char *string, int *permission);
-
static List *commandList;
-static CommandEntry *newCommandEntry(void)
-{
- CommandEntry *cmd = xmalloc(sizeof(CommandEntry));
- cmd->cmd = NULL;
- cmd->min = 0;
- cmd->max = 0;
- cmd->handler = NULL;
- cmd->listHandler = NULL;
- cmd->reqPermission = 0;
- return cmd;
-}
-
static void command_error_va(int fd, int error, const char *fmt, va_list args)
{
if (current_command && fd != STDERR_FILENO) {
@@ -271,15 +253,13 @@ static void addCommand(const char *name,
int reqPermission,
int minargs,
int maxargs,
- CommandHandlerFunction handler_func,
- CommandListHandlerFunction listHandler_func)
+ CommandHandlerFunction handler_func)
{
- CommandEntry *cmd = newCommandEntry();
+ CommandEntry *cmd = xmalloc(sizeof(CommandEntry));
cmd->cmd = name;
cmd->min = minargs;
cmd->max = maxargs;
cmd->handler = handler_func;
- cmd->listHandler = listHandler_func;
cmd->reqPermission = reqPermission;
insertInList(commandList, cmd->cmd, cmd);
@@ -813,47 +793,17 @@ static int print_update_result(int fd, int ret)
return -1;
}
-static int listHandleUpdate(int fd,
- mpd_unused int *permission,
- mpd_unused int argc,
- char *argv[],
- struct strnode *cmdnode, CommandEntry * cmd)
-{
- static char **pathv;
- static int pathc;
- CommandEntry *nextCmd = NULL;
- struct strnode *next = cmdnode->next;
- int last = pathc++;
-
- pathv = xrealloc(pathv, pathc * sizeof(char *));
- pathv[last] = sanitizePathDup(argc == 2 ? argv[1] : "");
-
- if (next)
- nextCmd = getCommandEntryFromString(next->data, permission);
-
- if (cmd != nextCmd) {
- int ret = print_update_result(fd, updateInit(pathc, pathv));
- if (pathc) {
- assert(pathv);
- free(pathv);
- pathv = NULL;
- pathc = 0;
- }
- return ret;
- }
-
- return 0;
-}
-
static int handleUpdate(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
- char *pathv[1];
+ char *path = NULL;
assert(argc <= 2);
- if (argc == 2)
- pathv[0] = sanitizePathDup(argv[1]);
- return print_update_result(fd, updateInit(argc - 1, pathv));
+ if (argc == 2 && !(path = sanitizePathDup(argv[1]))) {
+ commandError(fd, ACK_ERROR_ARG, "invalid path");
+ return -1;
+ }
+ return print_update_result(fd, directory_update_init(path));
}
static int handleNext(mpd_unused int fd, mpd_unused int *permission,
@@ -1263,70 +1213,70 @@ void initCommands(void)
{
commandList = makeList(free, 1);
- /* addCommand(name, permission, min, max, handler, list handler); */
- addCommand(COMMAND_PLAY, PERMISSION_CONTROL, 0, 1, handlePlay, NULL);
- addCommand(COMMAND_PLAYID, PERMISSION_CONTROL, 0, 1, handlePlayId, NULL);
- addCommand(COMMAND_STOP, PERMISSION_CONTROL, 0, 0, handleStop, NULL);
- addCommand(COMMAND_CURRENTSONG, PERMISSION_READ, 0, 0, handleCurrentSong, NULL);
- addCommand(COMMAND_PAUSE, PERMISSION_CONTROL, 0, 1, handlePause, NULL);
- addCommand(COMMAND_STATUS, PERMISSION_READ, 0, 0, commandStatus, NULL);
- addCommand(COMMAND_KILL, PERMISSION_ADMIN, -1, -1, handleKill, NULL);
- addCommand(COMMAND_CLOSE, PERMISSION_NONE, -1, -1, handleClose, NULL);
- addCommand(COMMAND_ADD, PERMISSION_ADD, 1, 1, handleAdd, NULL);
- addCommand(COMMAND_ADDID, PERMISSION_ADD, 1, 2, handleAddId, NULL);
- addCommand(COMMAND_DELETE, PERMISSION_CONTROL, 1, 1, handleDelete, NULL);
- addCommand(COMMAND_DELETEID, PERMISSION_CONTROL, 1, 1, handleDeleteId, NULL);
- addCommand(COMMAND_PLAYLIST, PERMISSION_READ, 0, 0, handlePlaylist, NULL);
- addCommand(COMMAND_PLAYLISTID, PERMISSION_READ, 0, 1, handlePlaylistId, NULL);
- addCommand(COMMAND_SHUFFLE, PERMISSION_CONTROL, 0, 0, handleShuffle, NULL);
- addCommand(COMMAND_CLEAR, PERMISSION_CONTROL, 0, 0, handleClear, NULL);
- addCommand(COMMAND_SAVE, PERMISSION_CONTROL, 1, 1, handleSave, NULL);
- addCommand(COMMAND_LOAD, PERMISSION_ADD, 1, 1, handleLoad, NULL);
- addCommand(COMMAND_LISTPLAYLIST, PERMISSION_READ, 1, 1, handleListPlaylist, NULL);
- addCommand(COMMAND_LISTPLAYLISTINFO, PERMISSION_READ, 1, 1, handleListPlaylistInfo, NULL);
- addCommand(COMMAND_LSINFO, PERMISSION_READ, 0, 1, handleLsInfo, NULL);
- addCommand(COMMAND_RM, PERMISSION_CONTROL, 1, 1, handleRm, NULL);
- addCommand(COMMAND_PLAYLISTINFO, PERMISSION_READ, 0, 1, handlePlaylistInfo, NULL);
- addCommand(COMMAND_FIND, PERMISSION_READ, 2, -1, handleFind, NULL);
- addCommand(COMMAND_SEARCH, PERMISSION_READ, 2, -1, handleSearch, NULL);
- addCommand(COMMAND_UPDATE, PERMISSION_ADMIN, 0, 1, handleUpdate, listHandleUpdate);
- addCommand(COMMAND_NEXT, PERMISSION_CONTROL, 0, 0, handleNext, NULL);
- addCommand(COMMAND_PREVIOUS, PERMISSION_CONTROL, 0, 0, handlePrevious, NULL);
- addCommand(COMMAND_LISTALL, PERMISSION_READ, 0, 1, handleListAll, NULL);
- addCommand(COMMAND_VOLUME, PERMISSION_CONTROL, 1, 1, handleVolume, NULL);
- addCommand(COMMAND_REPEAT, PERMISSION_CONTROL, 1, 1, handleRepeat, NULL);
- addCommand(COMMAND_RANDOM, PERMISSION_CONTROL, 1, 1, handleRandom, NULL);
- addCommand(COMMAND_STATS, PERMISSION_READ, 0, 0, handleStats, NULL);
- addCommand(COMMAND_CLEAR_ERROR, PERMISSION_CONTROL, 0, 0, handleClearError, NULL);
- addCommand(COMMAND_LIST, PERMISSION_READ, 1, -1, handleList, NULL);
- addCommand(COMMAND_MOVE, PERMISSION_CONTROL, 2, 2, handleMove, NULL);
- addCommand(COMMAND_MOVEID, PERMISSION_CONTROL, 2, 2, handleMoveId, NULL);
- addCommand(COMMAND_SWAP, PERMISSION_CONTROL, 2, 2, handleSwap, NULL);
- addCommand(COMMAND_SWAPID, PERMISSION_CONTROL, 2, 2, handleSwapId, NULL);
- addCommand(COMMAND_SEEK, PERMISSION_CONTROL, 2, 2, handleSeek, NULL);
- addCommand(COMMAND_SEEKID, PERMISSION_CONTROL, 2, 2, handleSeekId, NULL);
- addCommand(COMMAND_LISTALLINFO, PERMISSION_READ, 0, 1, handleListAllInfo, NULL);
- addCommand(COMMAND_PING, PERMISSION_NONE, 0, 0, handlePing, NULL);
- addCommand(COMMAND_SETVOL, PERMISSION_CONTROL, 1, 1, handleSetVol, NULL);
- addCommand(COMMAND_PASSWORD, PERMISSION_NONE, 1, 1, handlePassword, NULL);
- addCommand(COMMAND_CROSSFADE, PERMISSION_CONTROL, 1, 1, handleCrossfade, NULL);
- addCommand(COMMAND_URL_HANDLERS, PERMISSION_READ, 0, 0, handleUrlHandlers, NULL);
- addCommand(COMMAND_PLCHANGES, PERMISSION_READ, 1, 1, handlePlaylistChanges, NULL);
- addCommand(COMMAND_PLCHANGESPOSID, PERMISSION_READ, 1, 1, handlePlaylistChangesPosId, NULL);
- addCommand(COMMAND_ENABLE_DEV, PERMISSION_ADMIN, 1, 1, handleEnableDevice, NULL);
- addCommand(COMMAND_DISABLE_DEV, PERMISSION_ADMIN, 1, 1, handleDisableDevice, NULL);
- addCommand(COMMAND_DEVICES, PERMISSION_READ, 0, 0, handleDevices, NULL);
- addCommand(COMMAND_COMMANDS, PERMISSION_NONE, 0, 0, handleCommands, NULL);
- addCommand(COMMAND_NOTCOMMANDS, PERMISSION_NONE, 0, 0, handleNotcommands, NULL);
- addCommand(COMMAND_PLAYLISTCLEAR, PERMISSION_CONTROL, 1, 1, handlePlaylistClear, NULL);
- addCommand(COMMAND_PLAYLISTADD, PERMISSION_CONTROL, 2, 2, handlePlaylistAdd, NULL);
- addCommand(COMMAND_PLAYLISTFIND, PERMISSION_READ, 2, -1, handlePlaylistFind, NULL);
- addCommand(COMMAND_PLAYLISTSEARCH, PERMISSION_READ, 2, -1, handlePlaylistSearch, NULL);
- addCommand(COMMAND_PLAYLISTMOVE, PERMISSION_CONTROL, 3, 3, handlePlaylistMove, NULL);
- addCommand(COMMAND_PLAYLISTDELETE, PERMISSION_CONTROL, 2, 2, handlePlaylistDelete, NULL);
- addCommand(COMMAND_TAGTYPES, PERMISSION_READ, 0, 0, handleTagTypes, NULL);
- addCommand(COMMAND_COUNT, PERMISSION_READ, 2, -1, handleCount, NULL);
- addCommand(COMMAND_RENAME, PERMISSION_CONTROL, 2, 2, handleRename, NULL);
+ /* addCommand(name, permission, min, max, handler); */
+ addCommand(COMMAND_PLAY, PERMISSION_CONTROL, 0, 1, handlePlay);
+ addCommand(COMMAND_PLAYID, PERMISSION_CONTROL, 0, 1, handlePlayId);
+ addCommand(COMMAND_STOP, PERMISSION_CONTROL, 0, 0, handleStop);
+ addCommand(COMMAND_CURRENTSONG, PERMISSION_READ, 0, 0, handleCurrentSong);
+ addCommand(COMMAND_PAUSE, PERMISSION_CONTROL, 0, 1, handlePause);
+ addCommand(COMMAND_STATUS, PERMISSION_READ, 0, 0, commandStatus);
+ addCommand(COMMAND_KILL, PERMISSION_ADMIN, -1, -1, handleKill);
+ addCommand(COMMAND_CLOSE, PERMISSION_NONE, -1, -1, handleClose);
+ addCommand(COMMAND_ADD, PERMISSION_ADD, 1, 1, handleAdd);
+ addCommand(COMMAND_ADDID, PERMISSION_ADD, 1, 2, handleAddId);
+ addCommand(COMMAND_DELETE, PERMISSION_CONTROL, 1, 1, handleDelete);
+ addCommand(COMMAND_DELETEID, PERMISSION_CONTROL, 1, 1, handleDeleteId);
+ addCommand(COMMAND_PLAYLIST, PERMISSION_READ, 0, 0, handlePlaylist);
+ addCommand(COMMAND_PLAYLISTID, PERMISSION_READ, 0, 1, handlePlaylistId);
+ addCommand(COMMAND_SHUFFLE, PERMISSION_CONTROL, 0, 0, handleShuffle);
+ addCommand(COMMAND_CLEAR, PERMISSION_CONTROL, 0, 0, handleClear);
+ addCommand(COMMAND_SAVE, PERMISSION_CONTROL, 1, 1, handleSave);
+ addCommand(COMMAND_LOAD, PERMISSION_ADD, 1, 1, handleLoad);
+ addCommand(COMMAND_LISTPLAYLIST, PERMISSION_READ, 1, 1, handleListPlaylist);
+ addCommand(COMMAND_LISTPLAYLISTINFO, PERMISSION_READ, 1, 1, handleListPlaylistInfo);
+ addCommand(COMMAND_LSINFO, PERMISSION_READ, 0, 1, handleLsInfo);
+ addCommand(COMMAND_RM, PERMISSION_CONTROL, 1, 1, handleRm);
+ addCommand(COMMAND_PLAYLISTINFO, PERMISSION_READ, 0, 1, handlePlaylistInfo);
+ addCommand(COMMAND_FIND, PERMISSION_READ, 2, -1, handleFind);
+ addCommand(COMMAND_SEARCH, PERMISSION_READ, 2, -1, handleSearch);
+ addCommand(COMMAND_UPDATE, PERMISSION_ADMIN, 0, 1, handleUpdate);
+ addCommand(COMMAND_NEXT, PERMISSION_CONTROL, 0, 0, handleNext);
+ addCommand(COMMAND_PREVIOUS, PERMISSION_CONTROL, 0, 0, handlePrevious);
+ addCommand(COMMAND_LISTALL, PERMISSION_READ, 0, 1, handleListAll);
+ addCommand(COMMAND_VOLUME, PERMISSION_CONTROL, 1, 1, handleVolume);
+ addCommand(COMMAND_REPEAT, PERMISSION_CONTROL, 1, 1, handleRepeat);
+ addCommand(COMMAND_RANDOM, PERMISSION_CONTROL, 1, 1, handleRandom);
+ addCommand(COMMAND_STATS, PERMISSION_READ, 0, 0, handleStats);
+ addCommand(COMMAND_CLEAR_ERROR, PERMISSION_CONTROL, 0, 0, handleClearError);
+ addCommand(COMMAND_LIST, PERMISSION_READ, 1, -1, handleList);
+ addCommand(COMMAND_MOVE, PERMISSION_CONTROL, 2, 2, handleMove);
+ addCommand(COMMAND_MOVEID, PERMISSION_CONTROL, 2, 2, handleMoveId);
+ addCommand(COMMAND_SWAP, PERMISSION_CONTROL, 2, 2, handleSwap);
+ addCommand(COMMAND_SWAPID, PERMISSION_CONTROL, 2, 2, handleSwapId);
+ addCommand(COMMAND_SEEK, PERMISSION_CONTROL, 2, 2, handleSeek);
+ addCommand(COMMAND_SEEKID, PERMISSION_CONTROL, 2, 2, handleSeekId);
+ addCommand(COMMAND_LISTALLINFO, PERMISSION_READ, 0, 1, handleListAllInfo);
+ addCommand(COMMAND_PING, PERMISSION_NONE, 0, 0, handlePing);
+ addCommand(COMMAND_SETVOL, PERMISSION_CONTROL, 1, 1, handleSetVol);
+ addCommand(COMMAND_PASSWORD, PERMISSION_NONE, 1, 1, handlePassword);
+ addCommand(COMMAND_CROSSFADE, PERMISSION_CONTROL, 1, 1, handleCrossfade);
+ addCommand(COMMAND_URL_HANDLERS, PERMISSION_READ, 0, 0, handleUrlHandlers);
+ addCommand(COMMAND_PLCHANGES, PERMISSION_READ, 1, 1, handlePlaylistChanges);
+ addCommand(COMMAND_PLCHANGESPOSID, PERMISSION_READ, 1, 1, handlePlaylistChangesPosId);
+ addCommand(COMMAND_ENABLE_DEV, PERMISSION_ADMIN, 1, 1, handleEnableDevice);
+ addCommand(COMMAND_DISABLE_DEV, PERMISSION_ADMIN, 1, 1, handleDisableDevice);
+ addCommand(COMMAND_DEVICES, PERMISSION_READ, 0, 0, handleDevices);
+ addCommand(COMMAND_COMMANDS, PERMISSION_NONE, 0, 0, handleCommands);
+ addCommand(COMMAND_NOTCOMMANDS, PERMISSION_NONE, 0, 0, handleNotcommands);
+ addCommand(COMMAND_PLAYLISTCLEAR, PERMISSION_CONTROL, 1, 1, handlePlaylistClear);
+ addCommand(COMMAND_PLAYLISTADD, PERMISSION_CONTROL, 2, 2, handlePlaylistAdd);
+ addCommand(COMMAND_PLAYLISTFIND, PERMISSION_READ, 2, -1, handlePlaylistFind);
+ addCommand(COMMAND_PLAYLISTSEARCH, PERMISSION_READ, 2, -1, handlePlaylistSearch);
+ addCommand(COMMAND_PLAYLISTMOVE, PERMISSION_CONTROL, 3, 3, handlePlaylistMove);
+ addCommand(COMMAND_PLAYLISTDELETE, PERMISSION_CONTROL, 2, 2, handlePlaylistDelete);
+ addCommand(COMMAND_TAGTYPES, PERMISSION_READ, 0, 0, handleTagTypes);
+ addCommand(COMMAND_COUNT, PERMISSION_READ, 2, -1, handleCount);
+ addCommand(COMMAND_RENAME, PERMISSION_CONTROL, 2, 2, handleRename);
sortList(commandList);
}
@@ -1407,24 +1357,6 @@ static CommandEntry *getCommandEntryAndCheckArgcAndPermission(int fd,
return cmd;
}
-static CommandEntry *getCommandEntryFromString(char *string, int *permission)
-{
- CommandEntry *cmd = NULL;
- char *argv[COMMAND_ARGV_MAX] = { NULL };
- char *duplicated = xstrdup(string);
- int argc = buffer2array(duplicated, argv, COMMAND_ARGV_MAX);
-
- if (0 == argc)
- goto out;
-
- cmd = getCommandEntryAndCheckArgcAndPermission(0, permission,
- argc, argv);
-
-out:
- free(duplicated);
- return cmd;
-}
-
static int processCommandInternal(int fd, mpd_unused int *permission,
char *commandString, struct strnode *cmdnode)
{
@@ -1440,12 +1372,8 @@ static int processCommandInternal(int fd, mpd_unused int *permission,
if ((cmd = getCommandEntryAndCheckArgcAndPermission(fd, permission,
argc, argv))) {
- if (!cmdnode || !cmd->listHandler) {
+ if (!cmdnode)
ret = cmd->handler(fd, permission, argc, argv);
- } else {
- ret = cmd->listHandler(fd, permission, argc, argv,
- cmdnode, cmd);
- }
}
current_command = NULL;
diff --git a/src/decode.c b/src/decode.c
index e0685e0e9..dd1ea9396 100644
--- a/src/decode.c
+++ b/src/decode.c
@@ -173,12 +173,9 @@ static int decode_start(void)
InputStream is;
InputPlugin *plugin = NULL;
char path_max_fs[MPD_PATH_MAX];
- char path_max_utf8[MPD_PATH_MAX];
assert(pthread_equal(pthread_self(), dc.thread));
assert(dc.state == DC_STATE_DECODE);
- assert(dc.current_song);
- get_song_url(path_max_utf8, dc.current_song);
- assert(*path_max_utf8);
+ assert(*dc.utf8url);
switch (dc.action) {
case DC_ACTION_START:
@@ -193,20 +190,20 @@ static int decode_start(void)
default: assert("unknown action!" && 0);
}
- if (isRemoteUrl(path_max_utf8)) {
- pathcpy_trunc(path_max_fs, path_max_utf8);
+ if (isRemoteUrl(dc.utf8url)) {
+ pathcpy_trunc(path_max_fs, dc.utf8url);
} else {
rmp2amp_r(path_max_fs,
- utf8_to_fs_charset(path_max_fs, path_max_utf8));
+ utf8_to_fs_charset(path_max_fs, dc.utf8url));
}
if (openInputStream(&is, path_max_fs) < 0) {
DEBUG("couldn't open song: %s\n", path_max_fs);
- player_seterror(PLAYER_ERROR_FILENOTFOUND, dc.current_song);
+ player_seterror(PLAYER_ERROR_FILENOTFOUND, dc.utf8url);
return err;
}
- if (isRemoteUrl(path_max_utf8)) {
+ if (isRemoteUrl(dc.utf8url)) {
unsigned int next = 0;
/* first we try mime types: */
@@ -224,7 +221,7 @@ static int decode_start(void)
/* if that fails, try suffix matching the URL: */
if (plugin == NULL) {
- const char *s = getSuffix(path_max_utf8);
+ const char *s = getSuffix(dc.utf8url);
next = 0;
while (err && (plugin = getInputPluginFromSuffix(s, next++))) {
if (!plugin->streamDecodeFunc)
@@ -250,7 +247,7 @@ static int decode_start(void)
}
} else {
unsigned int next = 0;
- const char *s = getSuffix(path_max_utf8);
+ const char *s = getSuffix(dc.utf8url);
while (err && (plugin = getInputPluginFromSuffix(s, next++))) {
if (!plugin->streamTypes & INPUT_PLUGIN_STREAM_FILE)
continue;
@@ -273,9 +270,9 @@ static int decode_start(void)
if (err) {
if (plugin)
- player_seterror(PLAYER_ERROR_SYSTEM, dc.current_song);
+ player_seterror(PLAYER_ERROR_SYSTEM, dc.utf8url);
else
- player_seterror(PLAYER_ERROR_UNKTYPE, dc.current_song);
+ player_seterror(PLAYER_ERROR_UNKTYPE, dc.utf8url);
}
if (player_errno)
ERROR("player_error: %s\n", player_strerror());
@@ -299,20 +296,18 @@ static void * decoder_task(mpd_unused void *arg)
case DC_STATE_DECODE:
/* DEBUG(__FILE__": %s %d\n", __func__, __LINE__); */
/* DEBUG("dc.action: %d\n", (int)dc.action); */
- if ((dc.current_song = playlist_queued_song())) {
- char p[MPD_PATH_MAX];
+ if (playlist_queued_url(dc.utf8url)) {
int err;
ob_advance_sequence();
- get_song_url(p, dc.current_song);
- DEBUG("decoding song: %s\n", p);
+ DEBUG("decoding song: %s\n", dc.utf8url);
err = decode_start();
- DEBUG("DONE decoding song: %s\n", p);
+ DEBUG("DONE decoding song: %s\n", dc.utf8url);
if (err)
ob_trigger_action(OB_ACTION_RESET);
else
ob_flush();
- dc.current_song = NULL;
+ dc.utf8url[0] = '\0';
}
finalize_per_track_actions();
playlist_queue_next();
diff --git a/src/decode.h b/src/decode.h
index 61eeee078..71e7a498e 100644
--- a/src/decode.h
+++ b/src/decode.h
@@ -43,7 +43,7 @@ enum dc_state {
};
struct decoder_control {
- Song * current_song; /* only needed for wavpack, remove? */
+ char utf8url[MPD_PATH_MAX]; /* only needed for wavpack, remove? */
enum dc_state state; /* rw=dc.thread, r=main */
enum dc_action action; /* rw protected by action_cond */
float total_time; /* w=dc.thread, r=main */
diff --git a/src/directory.c b/src/directory.c
index fc9c6b41d..773b16db6 100644
--- a/src/directory.c
+++ b/src/directory.c
@@ -52,13 +52,18 @@ enum update_progress {
UPDATE_PROGRESS_DONE = 2
} progress;
+/* make this dynamic?, or maybe this is big enough... */
+static char *update_paths[32];
+static size_t update_paths_nr;
+
static Directory *music_root;
static time_t directory_dbModTime;
static pthread_t update_thr;
-static int directory_updateJobId;
+static const int update_task_id_max = 1 << 15;
+static int update_task_id;
static int addToDirectory(Directory * directory, const char *name);
@@ -70,8 +75,7 @@ static enum update_return updateDirectory(Directory * directory);
static void deleteEmptyDirectoriesInDirectory(Directory * directory);
-static void removeSongFromDirectory(Directory * directory,
- const char *shortname);
+static void delete_song(Directory *dir, Song *del);
static enum update_return addSubDirectoryToDirectory(Directory * directory,
const char *name, struct stat *st);
@@ -98,87 +102,84 @@ static char *getDbFile(void)
int isUpdatingDB(void)
{
- return (progress != UPDATE_PROGRESS_IDLE) ? directory_updateJobId : 0;
-}
-
-void reap_update_task(void)
-{
- enum update_return ret;
-
- if (progress != UPDATE_PROGRESS_DONE)
- return;
- if (pthread_join(update_thr, (void **)&ret))
- FATAL("error joining update thread: %s\n", strerror(errno));
- if (ret == UPDATE_RETURN_UPDATED)
- playlistVersionChange();
- progress = UPDATE_PROGRESS_IDLE;
+ return (progress != UPDATE_PROGRESS_IDLE) ? update_task_id : 0;
}
-/* @argv represents a null-terminated array of (null-terminated) strings */
-static void * update_task(void *argv)
+static void * update_task(void *_path)
{
enum update_return ret = UPDATE_RETURN_NOUPDATE;
- if (argv) {
- char **pathv;
- for (pathv = (char **)argv; *pathv; pathv++) {
- switch (updatePath(*pathv)) {
- case UPDATE_RETURN_ERROR:
- ret = UPDATE_RETURN_ERROR;
- goto out;
- case UPDATE_RETURN_NOUPDATE:
- break;
- case UPDATE_RETURN_UPDATED:
- ret = UPDATE_RETURN_UPDATED;
- }
- free(*pathv);
- }
- free(argv);
+ if (_path) {
+ ret = updatePath((char *)_path);
+ free(_path);
} else {
ret = updateDirectory(music_root);
}
if (ret == UPDATE_RETURN_UPDATED && writeDirectoryDB() < 0)
ret = UPDATE_RETURN_ERROR;
-out:
progress = UPDATE_PROGRESS_DONE;
wakeup_main_task();
return (void *)ret;
}
-int updateInit(int argc, char *argv[])
+static void spawn_update_task(char *path)
{
pthread_attr_t attr;
- char **pathv = NULL;
- int i;
-
- if (progress != UPDATE_PROGRESS_IDLE) {
- for (i = argc; --i >= 0; )
- free(argv[i]);
- return -1;
- }
- for (i = argc; --i >= 0; ) {
- if (!argv[i])
- return -2;
- }
+ assert(pthread_equal(pthread_self(), main_task));
progress = UPDATE_PROGRESS_RUNNING;
- if (argc > 0) {
- pathv = xmalloc((argc + 1) * sizeof(char *));
- memcpy(pathv, argv, argc * sizeof(char *));
- pathv[argc] = NULL;
- }
-
pthread_attr_init(&attr);
- if (pthread_create(&update_thr, &attr, update_task, pathv))
+ if (pthread_create(&update_thr, &attr, update_task, path))
FATAL("Failed to spawn update task: %s\n", strerror(errno));
- directory_updateJobId++;
- if (directory_updateJobId > 1 << 15)
- directory_updateJobId = 1;
- DEBUG("updateInit: spawned update thread for update job id %i\n",
- (int)directory_updateJobId);
- return directory_updateJobId;
+ if (++update_task_id > update_task_id_max)
+ update_task_id = 1;
+ DEBUG("spawned thread for update job id %i\n", update_task_id);
+}
+
+void reap_update_task(void)
+{
+ enum update_return ret;
+
+ assert(pthread_equal(pthread_self(), main_task));
+
+ if (progress != UPDATE_PROGRESS_DONE)
+ return;
+ if (pthread_join(update_thr, (void **)&ret))
+ FATAL("error joining update thread: %s\n", strerror(errno));
+ if (ret == UPDATE_RETURN_UPDATED)
+ playlistVersionChange();
+
+ if (update_paths_nr) {
+ char *path = update_paths[0];
+ memmove(&update_paths[0], &update_paths[1],
+ --update_paths_nr * sizeof(char *));
+ spawn_update_task(path);
+ } else {
+ progress = UPDATE_PROGRESS_IDLE;
+ }
+}
+
+int directory_update_init(char *path)
+{
+ assert(pthread_equal(pthread_self(), main_task));
+
+ if (progress != UPDATE_PROGRESS_IDLE) {
+ int next_task_id;
+
+ if (!path)
+ return -1;
+ if (update_paths_nr == ARRAY_SIZE(update_paths))
+ return -1;
+ assert(update_paths_nr < ARRAY_SIZE(update_paths));
+ update_paths[update_paths_nr++] = path;
+ next_task_id = update_task_id + update_paths_nr;
+
+ return next_task_id > update_task_id_max ? 1 : next_task_id;
+ }
+ spawn_update_task(path);
+ return update_task_id;
}
static void directory_set_stat(Directory * dir, const struct stat *st)
@@ -212,16 +213,12 @@ static void freeDirectory(Directory * directory)
/*getDirectoryPath(NULL); */
}
-static void removeSongFromDirectory(Directory * directory, const char *shortname)
+static void delete_song(Directory *dir, Song *del)
{
- Song *song = songvec_find(&directory->songs, shortname);
-
- if (song) {
- char path_max_tmp[MPD_PATH_MAX]; /* wasteful */
- LOG("removing: %s\n", get_song_url(path_max_tmp, song));
- songvec_delete(&directory->songs, song);
- freeSong(song); /* FIXME racy */
- }
+ char path_max_tmp[MPD_PATH_MAX]; /* wasteful */
+ LOG("removing: %s\n", get_song_url(path_max_tmp, del));
+ songvec_delete(&dir->songs, del);
+ freeSong(del); /* FIXME racy */
}
static void deleteEmptyDirectoriesInDirectory(Directory * directory)
@@ -256,7 +253,7 @@ updateInDirectory(Directory * directory, const char *name)
} else if (st.st_mtime != song->mtime) {
LOG("updating %s\n", name);
if (updateSongInfo(song) < 0)
- removeSongFromDirectory(directory, shortname);
+ delete_song(directory, song);
return UPDATE_RETURN_UPDATED;
}
} else if (S_ISDIR(st.st_mode)) {
@@ -308,7 +305,7 @@ removeDeletedFromDirectory(char *path_max_tmp, Directory * directory)
strcpy(path_max_tmp, song->url);
if (!isFile(path_max_tmp, NULL)) {
- removeSongFromDirectory(directory, song->url);
+ delete_song(directory, song);
ret = UPDATE_RETURN_UPDATED;
}
}
@@ -322,6 +319,7 @@ static Directory *addDirectoryPathToDB(const char *utf8path)
char *parent;
Directory *parentDirectory;
Directory *directory;
+ Song *conflicting;
parent = parent_path(path_max_tmp, utf8path);
@@ -348,7 +346,10 @@ static Directory *addDirectoryPathToDB(const char *utf8path)
/* if we're adding directory paths, make sure to delete filenames
with potentially the same name */
- removeSongFromDirectory(parentDirectory, mpd_basename(directory->path));
+ conflicting = songvec_find(&parentDirectory->songs,
+ mpd_basename(directory->path));
+ if (conflicting)
+ delete_song(parentDirectory, conflicting);
return directory;
}
@@ -419,14 +420,13 @@ static enum update_return updatePath(const char *utf8path)
else if (updateSongInfo(song) == 0)
return UPDATE_RETURN_UPDATED;
else {
- removeSongFromDirectory(parentDirectory,
- song->url);
+ delete_song(parentDirectory, song);
return UPDATE_RETURN_UPDATED;
}
}
/* if updateDirectory fails, means we should delete it */
else {
- removeSongFromDirectory(parentDirectory, song->url);
+ delete_song(parentDirectory, song);
ret = UPDATE_RETURN_UPDATED;
/* don't return, path maybe a directory now */
}
@@ -723,12 +723,13 @@ static void readDirectoryInfo(FILE * fp, Directory * directory)
char buffer[MPD_PATH_MAX * 2];
int bufferSize = MPD_PATH_MAX * 2;
char key[MPD_PATH_MAX * 2];
- Directory *subDirectory;
char *name;
while (myFgets(buffer, bufferSize, fp)
&& prefixcmp(buffer, DIRECTORY_END)) {
if (!prefixcmp(buffer, DIRECTORY_DIR)) {
+ Directory *subdir;
+
strcpy(key, &(buffer[strlen(DIRECTORY_DIR)]));
if (!myFgets(buffer, bufferSize, fp))
FATAL("Error reading db, fgets\n");
@@ -740,9 +741,13 @@ static void readDirectoryInfo(FILE * fp, Directory * directory)
if (prefixcmp(buffer, DIRECTORY_BEGIN))
FATAL("Error reading db at line: %s\n", buffer);
name = &(buffer[strlen(DIRECTORY_BEGIN)]);
- subDirectory = newDirectory(name, directory);
- dirvec_add(&directory->children, subDirectory);
- readDirectoryInfo(fp, subDirectory);
+ if ((subdir = getDirectory(name))) {
+ assert(subdir->parent == directory);
+ } else {
+ subdir = newDirectory(name, directory);
+ dirvec_add(&directory->children, subdir);
+ }
+ readDirectoryInfo(fp, subdir);
} else if (!prefixcmp(buffer, SONG_BEGIN)) {
readSongInfoIntoList(fp, directory);
} else {
diff --git a/src/directory.h b/src/directory.h
index eb1b35aa7..20b784166 100644
--- a/src/directory.h
+++ b/src/directory.h
@@ -43,11 +43,10 @@ int isUpdatingDB(void);
/*
* returns the non-negative update job ID on success,
- * -1 if busy, -2 if invalid argument
- * @argv itself is safe to free once updateInit returns, but the
- * string values contained by @argv MUST NOT be freed manually
+ * returns -1 if busy
+ * @path will be freed by this function and should not be reused
*/
-int updateInit(int argc, char *argv[]);
+int directory_update_init(char *path);
void directory_init(void);
diff --git a/src/inputPlugins/wavpack_plugin.c b/src/inputPlugins/wavpack_plugin.c
index 8bba8ae2b..b6da51e5e 100644
--- a/src/inputPlugins/wavpack_plugin.c
+++ b/src/inputPlugins/wavpack_plugin.c
@@ -429,10 +429,8 @@ static int wavpack_open_wvc(InputStream *is_wvc)
char wvc_url[MPD_PATH_MAX];
size_t len;
- /* This is the only reader of dc.current_song */
- if (!get_song_url(wvc_url, dc.current_song))
- return 0;
-
+ /* This is the only reader of dc.utf8url (in inputPlugins) */
+ pathcpy_trunc(wvc_url, dc.utf8url);
len = strlen(wvc_url);
if ((len + 2) >= MPD_PATH_MAX)
return 0;
diff --git a/src/main_notify.c b/src/main_notify.c
index 2c546633d..04ceac62d 100644
--- a/src/main_notify.c
+++ b/src/main_notify.c
@@ -24,6 +24,8 @@
#include "gcc.h"
#include "log.h"
+pthread_t main_task;
+
static struct ioOps main_notify_IO;
static int main_pipe[2];
@@ -55,6 +57,7 @@ static int ioops_consume(int fd_count, fd_set * rfds,
void init_main_notify(void)
{
+ main_task = pthread_self();
init_async_pipe(main_pipe);
main_notify_IO.fdset = ioops_fdset;
main_notify_IO.consume = ioops_consume;
diff --git a/src/main_notify.h b/src/main_notify.h
index db36042a7..dc743b833 100644
--- a/src/main_notify.h
+++ b/src/main_notify.h
@@ -21,6 +21,10 @@
#ifndef MAIN_NOTIFY_H
#define MAIN_NOTIFY_H
+#include <pthread.h>
+
+extern pthread_t main_task;
+
void init_main_notify(void);
void wakeup_main_task(void);
diff --git a/src/outputBuffer.c b/src/outputBuffer.c
index 9a659db41..7216a9c9c 100644
--- a/src/outputBuffer.c
+++ b/src/outputBuffer.c
@@ -22,7 +22,6 @@
#include "normalize.h"
#include "ringbuf.h"
#include "condition.h"
-#include "song.h"
#include "main_notify.h"
#include "player_error.h"
#include "log.h"
diff --git a/src/player_error.c b/src/player_error.c
index 4c7f7b9de..38e76e2c4 100644
--- a/src/player_error.c
+++ b/src/player_error.c
@@ -4,50 +4,52 @@
#include "path.h"
enum player_error player_errno;
-Song *player_errsong;
+static char errsong_url[MPD_PATH_MAX];
void player_clearerror(void)
{
player_errno = PLAYER_ERROR_NONE;
- player_errsong = NULL;
+ *errsong_url = '\0';
}
-void player_seterror(enum player_error err, Song *song)
+void player_seterror(enum player_error err, const char *url)
{
if (player_errno)
ERROR("Clobbering existing error: %s\n", player_strerror());
player_errno = err;
- player_errsong = song;
+ pathcpy_trunc(errsong_url, url);
}
const char *player_strerror(void)
{
/* static OK here, only one user in main task */
static char error[MPD_PATH_MAX + 64]; /* still too much */
- char path_max_tmp[MPD_PATH_MAX];
- *error = '\0'; /* likely */
+ const char *ret = NULL;
switch (player_errno) {
- case PLAYER_ERROR_NONE: break;
+ case PLAYER_ERROR_NONE:
+ ret = "";
+ break;
case PLAYER_ERROR_FILE:
- snprintf(error, sizeof(error), "problems decoding \"%s\"",
- get_song_url(path_max_tmp, player_errsong));
+ snprintf(error, sizeof(error),
+ "problems decoding \"%s\"", errsong_url);
break;
case PLAYER_ERROR_AUDIO:
- strcpy(error, "problems opening audio device");
+ ret = "problems opening audio device";
break;
case PLAYER_ERROR_SYSTEM:
- strcpy(error, "system error occured");
+ /* DONTFIX: misspelling "occurred" here is client-visible */
+ ret = "system error occured";
break;
case PLAYER_ERROR_UNKTYPE:
- snprintf(error, sizeof(error), "file type of \"%s\" is unknown",
- get_song_url(path_max_tmp, player_errsong));
- case PLAYER_ERROR_FILENOTFOUND:
snprintf(error, sizeof(error),
- "file \"%s\" does not exist or is inaccessible",
- get_song_url(path_max_tmp, player_errsong));
+ "file type of \"%s\" is unknown", errsong_url);
break;
+ case PLAYER_ERROR_FILENOTFOUND:
+ snprintf(error, sizeof(error),
+ "file \"%s\" does not exist or is inaccessible",
+ errsong_url);
}
- return *error ? error : NULL;
+ return ret ? ret : error;
}
diff --git a/src/player_error.h b/src/player_error.h
index c90c98420..997cb4604 100644
--- a/src/player_error.h
+++ b/src/player_error.h
@@ -19,8 +19,6 @@
#ifndef PLAYER_ERROR_H
#define PLAYER_ERROR_H
-#include "song.h"
-
enum player_error {
PLAYER_ERROR_NONE = 0,
PLAYER_ERROR_FILE,
@@ -31,10 +29,9 @@ enum player_error {
};
extern enum player_error player_errno;
-extern Song *player_errsong;
void player_clearerror(void);
-void player_seterror(enum player_error err, Song *song);
+void player_seterror(enum player_error err, const char *url);
const char *player_strerror(void);
#endif /* PLAYER_ERROR_H */
diff --git a/src/playlist.c b/src/playlist.c
index 80352602f..a91553140 100644
--- a/src/playlist.c
+++ b/src/playlist.c
@@ -100,14 +100,10 @@ static void randomizeOrder(int start, int end);
static void incrPlaylistVersion(void)
{
static unsigned long max = ((uint32_t) 1 << 31) - 1;
- playlist.version++;
- if (playlist.version >= max) {
- int i;
-
- for (i = 0; i < playlist.length; i++) {
- playlist.songMod[i] = 0;
- }
+ if (++playlist.version >= max) {
+ memset(playlist.songMod, 0,
+ playlist.length * sizeof(*playlist.songMod));
playlist.version = 1;
}
}
@@ -116,9 +112,8 @@ void playlistVersionChange(void)
{
int i;
- for (i = 0; i < playlist.length; i++) {
+ for (i = playlist.length; --i >= 0; )
playlist.songMod[i] = playlist.version;
- }
incrPlaylistVersion();
}
@@ -128,12 +123,9 @@ static void incrPlaylistCurrent(void)
if (playlist.current < 0)
return;
- if (playlist.current >= playlist.length - 1) {
- if (playlist.repeat)
- playlist.current = 0;
- else
- playlist.current = -1;
- } else
+ if (playlist.current >= playlist.length - 1)
+ playlist.current = playlist.repeat ? 0 : -1;
+ else
playlist.current++;
}
@@ -154,10 +146,9 @@ void initPlaylist(void)
if (param) {
playlist_max_length = strtol(param->value, &test, 10);
- if (*test != '\0') {
+ if (*test != '\0')
FATAL("max playlist length \"%s\" is not an integer, "
"line %i\n", param->value, param->line);
- }
}
playlist_saveAbsolutePaths = getBoolConfigParam(
@@ -166,20 +157,17 @@ void initPlaylist(void)
playlist_saveAbsolutePaths =
DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS;
- playlist.songs = xmalloc(sizeof(Song *) * playlist_max_length);
+ playlist.songs = xcalloc(playlist_max_length, sizeof(Song *));
playlist.songMod = xmalloc(sizeof(uint32_t) * playlist_max_length);
playlist.order = xmalloc(sizeof(int) * playlist_max_length);
playlist.idToPosition = xmalloc(sizeof(int) * playlist_max_length *
PLAYLIST_HASH_MULT);
playlist.positionToId = xmalloc(sizeof(int) * playlist_max_length);
- memset(playlist.songs, 0, sizeof(char *) * playlist_max_length);
-
srandom(time(NULL));
- for (i = 0; i < playlist_max_length * PLAYLIST_HASH_MULT; i++) {
+ for (i = playlist_max_length * PLAYLIST_HASH_MULT; --i >= 0; )
playlist.idToPosition[i] = -1;
- }
}
static int getNextId(void)
@@ -187,10 +175,8 @@ static int getNextId(void)
static int cur = -1;
do {
- cur++;
- if (cur >= playlist_max_length * PLAYLIST_HASH_MULT) {
+ if (++cur >= playlist_max_length * PLAYLIST_HASH_MULT)
cur = 0;
- }
} while (playlist.idToPosition[cur] != -1);
return cur;
@@ -199,10 +185,10 @@ static int getNextId(void)
void finishPlaylist(void)
{
int i;
- for (i = 0; i < playlist.length; i++) {
- if (playlist.songs[i]->type == SONG_TYPE_URL) {
+
+ for (i = playlist.length; --i >= 0; ) {
+ if (playlist.songs[i]->type == SONG_TYPE_URL)
freeJustSong(playlist.songs[i]);
- }
}
playlist.length = 0;
@@ -225,10 +211,9 @@ void clearPlaylist(void)
stopPlaylist();
- for (i = 0; i < playlist.length; i++) {
- if (playlist.songs[i]->type == SONG_TYPE_URL) {
+ for (i = playlist.length; --i >= 0 ; ) {
+ if (playlist.songs[i]->type == SONG_TYPE_URL)
freeJustSong(playlist.songs[i]);
- }
playlist.idToPosition[playlist.positionToId[i]] = -1;
playlist.songs[i] = NULL;
}
@@ -248,10 +233,9 @@ void showPlaylist(int fd)
int i;
char path_max_tmp[MPD_PATH_MAX];
- for (i = 0; i < playlist.length; i++) {
+ for (i = 0; i < playlist.length; i++)
fdprintf(fd, "%i:%s\n", i,
get_song_url(path_max_tmp, playlist.songs[i]));
- }
}
void savePlaylistState(int fd)
@@ -305,10 +289,9 @@ static void loadPlaylistFromStateFile(FILE *fp, char *buffer,
&& current == song) {
if (state == OB_STATE_PAUSE)
ob_trigger_action(OB_ACTION_PAUSE_SET);
- if (state != OB_STATE_STOP) {
+ if (state != OB_STATE_STOP)
seekSongInPlaylist(playlist.length - 1,
seek_time);
- }
}
if (!myFgets(buffer, PLAYLIST_BUFFER_SIZE, fp))
state_file_fatal();
@@ -388,9 +371,8 @@ int playlistChanges(int fd, uint32_t version)
for (i = 0; i < playlist.length; i++) {
if (version > playlist.version ||
playlist.songMod[i] >= version ||
- playlist.songMod[i] == 0) {
+ playlist.songMod[i] == 0)
printPlaylistSongInfo(fd, i);
- }
}
return 0;
@@ -403,10 +385,9 @@ int playlistChangesPosId(int fd, uint32_t version)
for (i = 0; i < playlist.length; i++) {
if (version > playlist.version ||
playlist.songMod[i] >= version ||
- playlist.songMod[i] == 0) {
+ playlist.songMod[i] == 0)
fdprintf(fd, "cpos: %i\nId: %i\n",
i, playlist.positionToId[i]);
- }
}
return 0;
@@ -522,7 +503,6 @@ static void queueNextSongInPlaylist(void)
playlist.current = -1;
}
} else if (dc.state == DC_STATE_STOP) {
- /* DEBUG("%s:%d (%d)\n", __func__, __LINE__, playlist.queued);*/
dc_trigger_action(DC_ACTION_START, 0);
}
}
@@ -554,11 +534,15 @@ void playlist_queue_next(void)
wakeup_main_task();
}
-Song *playlist_queued_song(void)
+char *playlist_queued_url(char utf8url[MPD_PATH_MAX])
{
+ Song *song;
+
assert(pthread_equal(pthread_self(), dc.thread));
pthread_mutex_lock(&queue_lock);
- return song_at(playlist.queued);
+ song = song_at(playlist.queued);
+
+ return song ? get_song_url(utf8url, song) : NULL;
}
static void queue_song_locked(int order_num)
@@ -605,15 +589,13 @@ int addToStoredPlaylist(const char *url, const char *utf8file)
DEBUG("add to stored playlist: %s\n", url);
- song = getSongFromDB(url);
- if (song)
+ if ((song = getSongFromDB(url)))
return appendSongToStoredPlaylistByPath(utf8file, song);
if (!isValidRemoteUtf8Url(url))
return ACK_ERROR_NO_EXIST;
- song = newSong(url, SONG_TYPE_URL, NULL);
- if (song) {
+ if ((song = newSong(url, SONG_TYPE_URL, NULL))) {
int ret = appendSongToStoredPlaylistByPath(utf8file, song);
freeJustSong(song);
return ret;
@@ -629,11 +611,10 @@ enum playlist_result addSongToPlaylist(Song * song, int *added_id)
if (playlist.length == playlist_max_length)
return PLAYLIST_RESULT_TOO_LARGE;
- if (playlist_state == PLAYLIST_STATE_PLAY) {
- if (playlist.queued >= 0
- && playlist.current == playlist.length - 1)
- clear_queue();
- }
+ if (playlist_state == PLAYLIST_STATE_PLAY &&
+ playlist.queued >= 0 &&
+ playlist.current == playlist.length - 1)
+ clear_queue();
id = getNextId();
@@ -684,9 +665,8 @@ enum playlist_result swapSongsInPlaylist(int song1, int song2)
return PLAYLIST_RESULT_BAD_RANGE;
if (playlist_state == PLAYLIST_STATE_PLAY) {
- if (playlist.queued >= 0) {
+ if (playlist.queued >= 0)
queuedSong = playlist.order[playlist.queued];
- }
assert(playlist.current >= 0 &&
playlist.current < playlist.length);
currentSong = playlist.order[playlist.current];
@@ -755,21 +735,18 @@ enum playlist_result deleteFromPlaylist(int song)
if (prev_queued >= 0
&& (playlist.order[prev_queued] == song
|| playlist.order[playlist.current] == song)) {
- /* DEBUG(__FILE__": %d (clearing)\n", __LINE__); */
clear_queue();
}
}
- if (playlist.songs[song]->type == SONG_TYPE_URL) {
+ if (playlist.songs[song]->type == SONG_TYPE_URL)
freeJustSong(playlist.songs[song]);
- }
playlist.idToPosition[playlist.positionToId[song]] = -1;
/* delete song from songs array */
- for (i = song; i < playlist.length - 1; i++) {
+ for (i = song; i < playlist.length - 1; i++)
moveSongFromTo(i + 1, i);
- }
/* now find it in the order array */
for (i = 0; i < playlist.length - 1; i++) {
if (playlist.order[i] == song)
@@ -790,8 +767,6 @@ enum playlist_result deleteFromPlaylist(int song)
incrPlaylistVersion();
- /* DEBUG("current: %d, songOrder: %d\n", playlist.current, songOrder); */
- /* DEBUG("playlist_state: %d\n", playlist_state); */
if (playlist_state != PLAYLIST_STATE_STOP
&& playlist.current == songOrder)
stop_current = 1;
@@ -804,13 +779,11 @@ enum playlist_result deleteFromPlaylist(int song)
incrPlaylistCurrent();
}
if (stop_current) {
- /* DEBUG(__FILE__": %d\n", __LINE__); */
if (playlist.current >= 0 && songOrder > 0)
play_order_num(playlist.current, 0);
else
stopPlaylist();
} else {
- /* DEBUG(__FILE__": %d\n", __LINE__); */
queueNextSongInPlaylist();
}
@@ -832,10 +805,9 @@ void deleteASongFromPlaylist(const Song * song)
if (NULL == playlist.songs)
return;
- for (i = 0; i < playlist.length; i++) {
- if (song == playlist.songs[i]) {
+ for (i = playlist.length; --i >= 0; ) {
+ if (mpd_unlikely(song == playlist.songs[i]))
deleteFromPlaylist(i);
- }
}
}
@@ -884,8 +856,6 @@ enum playlist_result playPlaylist(int song, int stopOnError)
{
int i = song;
- DEBUG("%s %d song(%d)\n", __func__, __LINE__, song);
-
player_clearerror();
if (song == -1) {
@@ -935,9 +905,8 @@ enum playlist_result playPlaylist(int song, int stopOnError)
enum playlist_result playPlaylistById(int id, int stopOnError)
{
- if (id == -1) {
+ if (id == -1)
return playPlaylist(id, stopOnError);
- }
if (!song_id_exists(id))
return PLAYLIST_RESULT_NO_SUCH_SONG;
@@ -963,8 +932,7 @@ static void sync_metadata(void)
if (!(tag = metadata_pipe_current()))
return;
song = song_at(playlist.current);
- if (!song || song->type != SONG_TYPE_URL ||
- tag_equal(song->tag, tag)) {
+ if (!song || song->type != SONG_TYPE_URL || tag_equal(song->tag, tag)) {
tag_free(tag);
return;
}
@@ -987,9 +955,8 @@ void syncPlayerAndPlaylist(void)
playlist.queued != playlist.current &&
ob_synced() &&
dc.state == DC_STATE_STOP &&
- ob_get_state() != OB_STATE_PAUSE) {
+ ob_get_state() != OB_STATE_PAUSE)
dc_trigger_action(DC_ACTION_START, 0);
- }
}
void nextSongInPlaylist(void)
@@ -1021,10 +988,9 @@ int getPlaylistRandomStatus(void)
void setPlaylistRepeatStatus(int status)
{
- if (playlist_state == PLAYLIST_STATE_PLAY) {
- if (playlist.repeat && !status && playlist.queued == 0)
- clear_queue();
- }
+ if (playlist_state == PLAYLIST_STATE_PLAY &&
+ playlist.repeat && !status && playlist.queued == 0)
+ clear_queue();
playlist.repeat = status;
}
@@ -1072,9 +1038,8 @@ enum playlist_result moveSongInPlaylist(int from, int to)
tmpSong = playlist.songs[from];
tmpId = playlist.positionToId[from];
/* move songs to one less in from->to */
- for (i = from; i < to; i++) {
+ for (i = from; i < to; i++)
moveSongFromTo(i + 1, i);
- }
/* move songs to one more in to->from */
for (i = from; i > to; i--) {
moveSongFromTo(i - 1, i);
@@ -1097,13 +1062,12 @@ enum playlist_result moveSongInPlaylist(int from, int to)
}
}
} else {
- if (playlist.current == from) {
+ if (playlist.current == from)
playlist.current = to;
- } else if (playlist.current > from && playlist.current <= to) {
+ else if (playlist.current > from && playlist.current <= to)
playlist.current--;
- } else if (playlist.current >= to && playlist.current < from) {
+ else if (playlist.current >= to && playlist.current < from)
playlist.current++;
- }
if (queued_is_current)
playlist.queued = playlist.current;
}
@@ -1135,7 +1099,7 @@ static void orderPlaylist(void)
if (queued_is_current)
playlist.queued = playlist.current;
}
- for (i = 0; i < playlist.length; i++)
+ for (i = playlist.length; --i >= 0; )
playlist.order[i] = i;
}
@@ -1160,7 +1124,6 @@ static void randomizeOrder(int start, int end)
int queued_is_current = (playlist.queued == playlist.current);
DEBUG("playlist: randomize from %i to %i\n", start, end);
- DEBUG("%s:%d current: %d\n", __func__, __LINE__, playlist.current);
if (!queued_is_current &&
playlist_state == PLAYLIST_STATE_PLAY &&
@@ -1178,7 +1141,6 @@ static void randomizeOrder(int start, int end)
}
if (queued_is_current)
playlist.queued = playlist.current;
- DEBUG("%s:%d current: %d\n", __func__, __LINE__, playlist.current);
}
void setPlaylistRandomStatus(int status)
@@ -1192,11 +1154,8 @@ void setPlaylistRandomStatus(int status)
randomizeOrder(0, playlist.length - 1);
else
orderPlaylist();
- if (playlist_state == PLAYLIST_STATE_PLAY) {
+ if (playlist_state == PLAYLIST_STATE_PLAY)
queueNextSongInPlaylist();
- DEBUG("%s:%d queued: %d\n",
- __func__,__LINE__,playlist.queued);
- }
}
}
@@ -1409,9 +1368,8 @@ int PlaylistInfo(int fd, const char *utf8file, int detail)
}
}
- if (!wrote) {
+ if (!wrote)
fdprintf(fd, SONG_FILE "%s\n", temp);
- }
node = node->nextNode;
}
diff --git a/src/playlist.h b/src/playlist.h
index 265b58356..df1bd9e7b 100644
--- a/src/playlist.h
+++ b/src/playlist.h
@@ -68,7 +68,7 @@ enum playlist_result playlistInfo(int fd, int song);
enum playlist_result playlistId(int fd, int song);
-Song *playlist_queued_song(void);
+char *playlist_queued_url(char utf8url[MPD_PATH_MAX]);
void playlist_queue_next(void);
diff --git a/src/song.c b/src/song.c
index 5c5024391..4f7b2f8bb 100644
--- a/src/song.c
+++ b/src/song.c
@@ -123,11 +123,20 @@ static void insertSongIntoList(struct songvec *sv, Song *newsong)
tag_end_add(newsong->tag);
} else { /* prevent dupes, just update the existing song info */
if (existing->mtime != newsong->mtime) {
- tag_free(existing->tag);
- if (newsong->tag)
- tag_end_add(newsong->tag);
- existing->tag = newsong->tag;
existing->mtime = newsong->mtime;
+ if (tag_equal(existing->tag, newsong->tag)) {
+ if (newsong->tag)
+ tag_free(newsong->tag);
+ } else {
+ struct mpd_tag *old_tag = existing->tag;
+
+ if (newsong->tag)
+ tag_end_add(newsong->tag);
+ existing->tag = newsong->tag;
+ if (old_tag)
+ tag_free(old_tag);
+ }
+ /* prevent tag_free in freeJustSong */
newsong->tag = NULL;
}
freeJustSong(newsong);
@@ -207,19 +216,22 @@ int updateSongInfo(Song * song)
unsigned int next = 0;
char path_max_tmp[MPD_PATH_MAX];
char abs_path[MPD_PATH_MAX];
+ struct mpd_tag *old_tag = song->tag;
+ struct mpd_tag *new_tag = NULL;
utf8_to_fs_charset(abs_path, get_song_url(path_max_tmp, song));
rmp2amp_r(abs_path, abs_path);
- if (song->tag)
- tag_free(song->tag);
-
- song->tag = NULL;
-
- while (!song->tag && (plugin = isMusic(abs_path,
- &(song->mtime),
- next++))) {
- song->tag = plugin->tagDupFunc(abs_path);
+ while ((plugin = isMusic(abs_path, &song->mtime, next++))) {
+ if ((new_tag = plugin->tagDupFunc(abs_path)))
+ break;
+ }
+ if (new_tag && tag_equal(new_tag, old_tag)) {
+ tag_free(new_tag);
+ } else {
+ song->tag = new_tag;
+ if (old_tag)
+ tag_free(old_tag);
}
if (!song->tag || song->tag->time < 0)
return -1;
diff --git a/src/tag.c b/src/tag.c
index 2dcaf4ef8..db446836c 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -296,12 +296,12 @@ void tag_clear_items_by_type(struct mpd_tag *tag, enum tag_type type)
}
}
-static void clearMpdTag(struct mpd_tag *tag)
+void tag_free(struct mpd_tag *tag)
{
int i;
pthread_mutex_lock(&tag_pool_lock);
- for (i = 0; i < tag->numOfItems; i++)
+ for (i = tag->numOfItems; --i >= 0; )
tag_pool_put_item(tag->items[i]);
pthread_mutex_unlock(&tag_pool_lock);
@@ -314,16 +314,6 @@ static void clearMpdTag(struct mpd_tag *tag)
free(tag->items);
}
- tag->items = NULL;
-
- tag->numOfItems = 0;
-
- tag->time = -1;
-}
-
-void tag_free(struct mpd_tag *tag)
-{
- clearMpdTag(tag);
free(tag);
}