From 7298b6c84652a98140805f3d4c85c3d5263c407a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 27 Sep 2012 22:55:57 +0200 Subject: stored_playlist, playlist_save: use C++ compiler --- Makefile.am | 9 +- src/DatabasePlaylist.cxx | 6 +- src/OtherCommands.cxx | 6 +- src/PlaylistCommands.cxx | 4 +- src/PlaylistFile.cxx | 537 +++++++++++++++++++++++++++++++++++++++++++++++ src/PlaylistFile.h | 92 ++++++++ src/PlaylistMapper.cxx | 113 ++++++++++ src/PlaylistMapper.h | 43 ++++ src/PlaylistPrint.cxx | 2 +- src/PlaylistSave.cxx | 151 +++++++++++++ src/PlaylistSave.hxx | 61 ++++++ src/main.c | 2 +- src/playlist_any.c | 2 +- src/playlist_mapper.c | 110 ---------- src/playlist_mapper.h | 39 ---- src/playlist_save.c | 149 ------------- src/playlist_save.h | 61 ------ src/stored_playlist.c | 533 ---------------------------------------------- src/stored_playlist.h | 88 -------- 19 files changed, 1011 insertions(+), 997 deletions(-) create mode 100644 src/PlaylistFile.cxx create mode 100644 src/PlaylistFile.h create mode 100644 src/PlaylistMapper.cxx create mode 100644 src/PlaylistMapper.h create mode 100644 src/PlaylistSave.cxx create mode 100644 src/PlaylistSave.hxx delete mode 100644 src/playlist_mapper.c delete mode 100644 src/playlist_mapper.h delete mode 100644 src/playlist_save.c delete mode 100644 src/playlist_save.h delete mode 100644 src/stored_playlist.c delete mode 100644 src/stored_playlist.h diff --git a/Makefile.am b/Makefile.am index ff5754564..7b9c49e9d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -152,11 +152,9 @@ mpd_headers = \ src/playlist.h \ src/playlist_error.h \ src/playlist_internal.h \ - src/playlist_save.h \ src/playlist_state.h \ src/playlist_plugin.h \ src/playlist_list.h \ - src/playlist_mapper.h \ src/playlist_any.h \ src/playlist_song.h \ src/playlist_queue.h \ @@ -208,7 +206,6 @@ mpd_headers = \ src/string_util.h \ src/volume.h \ src/zeroconf.h src/zeroconf-internal.h \ - src/stored_playlist.h \ src/timer.h \ src/archive_api.h \ src/archive_internal.h \ @@ -322,8 +319,8 @@ src_mpd_SOURCES = \ src/playlist_control.c \ src/playlist_edit.c \ src/PlaylistPrint.cxx src/PlaylistPrint.hxx \ - src/playlist_save.c \ - src/playlist_mapper.c \ + src/PlaylistSave.cxx src/PlaylistSave.hxx \ + src/PlaylistMapper.cxx src/PlaylistMapper.h \ src/playlist_any.c \ src/playlist_song.c \ src/playlist_state.c \ @@ -359,7 +356,7 @@ src_mpd_SOURCES = \ src/string_util.c \ src/volume.c \ src/SongFilter.cxx src/SongFilter.hxx \ - src/stored_playlist.c \ + src/PlaylistFile.cxx src/PlaylistFile.h \ src/timer.c # diff --git a/src/DatabasePlaylist.cxx b/src/DatabasePlaylist.cxx index f9934bab2..3020b3274 100644 --- a/src/DatabasePlaylist.cxx +++ b/src/DatabasePlaylist.cxx @@ -20,11 +20,7 @@ #include "config.h" #include "DatabasePlaylist.hxx" #include "DatabaseSelection.hxx" - -extern "C" { -#include "stored_playlist.h" -} - +#include "PlaylistFile.h" #include "DatabaseGlue.hxx" #include "DatabasePlugin.hxx" diff --git a/src/OtherCommands.cxx b/src/OtherCommands.cxx index 1442ef05a..ab7321953 100644 --- a/src/OtherCommands.cxx +++ b/src/OtherCommands.cxx @@ -35,7 +35,11 @@ extern "C" { #include "volume.h" #include "stats.h" #include "permission.h" -#include "stored_playlist.h" +} + +#include "PlaylistFile.h" + +extern "C" { #include "client.h" #include "client_idle.h" #include "client_file.h" diff --git a/src/PlaylistCommands.cxx b/src/PlaylistCommands.cxx index 2789e6c43..108318c2f 100644 --- a/src/PlaylistCommands.cxx +++ b/src/PlaylistCommands.cxx @@ -22,17 +22,17 @@ #include "DatabasePlaylist.hxx" #include "CommandError.hxx" #include "PlaylistPrint.hxx" +#include "PlaylistSave.hxx" +#include "PlaylistFile.h" extern "C" { #include "protocol/argparser.h" #include "protocol/result.h" #include "playlist.h" -#include "playlist_save.h" #include "playlist_queue.h" #include "time_print.h" #include "ls.h" #include "uri.h" -#include "stored_playlist.h" #include "client_internal.h" } diff --git a/src/PlaylistFile.cxx b/src/PlaylistFile.cxx new file mode 100644 index 000000000..9beae76ad --- /dev/null +++ b/src/PlaylistFile.cxx @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "PlaylistFile.h" +#include "PlaylistSave.hxx" +#include "song.h" + +extern "C" { +#include "text_file.h" +#include "mapper.h" +#include "path.h" +#include "uri.h" +#include "database.h" +#include "idle.h" +#include "conf.h" +} + +#include "glib_compat.h" + +#include +#include +#include +#include +#include +#include +#include + +static const char PLAYLIST_COMMENT = '#'; + +static unsigned playlist_max_length; +bool playlist_saveAbsolutePaths = DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS; + +void +spl_global_init(void) +{ + playlist_max_length = config_get_positive(CONF_MAX_PLAYLIST_LENGTH, + DEFAULT_PLAYLIST_MAX_LENGTH); + + playlist_saveAbsolutePaths = + config_get_bool(CONF_SAVE_ABSOLUTE_PATHS, + DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS); +} + +bool +spl_valid_name(const char *name_utf8) +{ + /* + * Not supporting '/' was done out of laziness, and we should + * really strive to support it in the future. + * + * Not supporting '\r' and '\n' is done out of protocol + * limitations (and arguably laziness), but bending over head + * over heels to modify the protocol (and compatibility with + * all clients) to support idiots who put '\r' and '\n' in + * filenames isn't going to happen, either. + */ + + return strchr(name_utf8, '/') == NULL && + strchr(name_utf8, '\n') == NULL && + strchr(name_utf8, '\r') == NULL; +} + +static const char * +spl_map(GError **error_r) +{ + const char *path_fs = map_spl_path(); + if (path_fs == NULL) + g_set_error_literal(error_r, playlist_quark(), + PLAYLIST_RESULT_DISABLED, + "Stored playlists are disabled"); + + return path_fs; +} + +static bool +spl_check_name(const char *name_utf8, GError **error_r) +{ + if (!spl_valid_name(name_utf8)) { + g_set_error_literal(error_r, playlist_quark(), + PLAYLIST_RESULT_BAD_NAME, + "Bad playlist name"); + return false; + } + + return true; +} + +static char * +spl_map_to_fs(const char *name_utf8, GError **error_r) +{ + if (spl_map(error_r) == NULL || + !spl_check_name(name_utf8, error_r)) + return NULL; + + char *path_fs = map_spl_utf8_to_fs(name_utf8); + if (path_fs == NULL) + g_set_error_literal(error_r, playlist_quark(), + PLAYLIST_RESULT_BAD_NAME, + "Bad playlist name"); + + return path_fs; +} + +/** + * Create a GError for the current errno. + */ +static void +playlist_errno(GError **error_r) +{ + switch (errno) { + case ENOENT: + g_set_error_literal(error_r, playlist_quark(), + PLAYLIST_RESULT_NO_SUCH_LIST, + "No such playlist"); + break; + + default: + g_set_error_literal(error_r, g_file_error_quark(), errno, + g_strerror(errno)); + break; + } +} + +static struct stored_playlist_info * +load_playlist_info(const char *parent_path_fs, const char *name_fs) +{ + size_t name_length = strlen(name_fs); + + if (name_length < sizeof(PLAYLIST_FILE_SUFFIX) || + memchr(name_fs, '\n', name_length) != NULL) + return NULL; + + if (!g_str_has_suffix(name_fs, PLAYLIST_FILE_SUFFIX)) + return NULL; + + char *path_fs = g_build_filename(parent_path_fs, name_fs, NULL); + struct stat st; + int ret = stat(path_fs, &st); + g_free(path_fs); + if (ret < 0 || !S_ISREG(st.st_mode)) + return NULL; + + char *name = g_strndup(name_fs, + name_length + 1 - sizeof(PLAYLIST_FILE_SUFFIX)); + char *name_utf8 = fs_charset_to_utf8(name); + g_free(name); + if (name_utf8 == NULL) + return NULL; + + struct stored_playlist_info *playlist = + g_new(struct stored_playlist_info, 1); + playlist->name = name_utf8; + playlist->mtime = st.st_mtime; + return playlist; +} + +GPtrArray * +spl_list(GError **error_r) +{ + const char *parent_path_fs = spl_map(error_r); + if (parent_path_fs == NULL) + return NULL; + + DIR *dir = opendir(parent_path_fs); + if (dir == NULL) { + g_set_error_literal(error_r, g_file_error_quark(), errno, + g_strerror(errno)); + return NULL; + } + + GPtrArray *list = g_ptr_array_new(); + + struct dirent *ent; + while ((ent = readdir(dir)) != NULL) { + struct stored_playlist_info *playlist = + load_playlist_info(parent_path_fs, ent->d_name); + if (playlist != NULL) + g_ptr_array_add(list, playlist); + } + + closedir(dir); + return list; +} + +void +spl_list_free(GPtrArray *list) +{ + for (unsigned i = 0; i < list->len; ++i) { + struct stored_playlist_info *playlist = + (struct stored_playlist_info *) + g_ptr_array_index(list, i); + g_free(playlist->name); + g_free(playlist); + } + + g_ptr_array_free(list, true); +} + +static bool +spl_save(GPtrArray *list, const char *utf8path, GError **error_r) +{ + assert(utf8path != NULL); + + if (spl_map(error_r) == NULL) + return false; + + char *path_fs = spl_map_to_fs(utf8path, error_r); + if (path_fs == NULL) + return false; + + FILE *file = fopen(path_fs, "w"); + g_free(path_fs); + if (file == NULL) { + playlist_errno(error_r); + return false; + } + + for (unsigned i = 0; i < list->len; ++i) { + const char *uri = (const char *)g_ptr_array_index(list, i); + playlist_print_uri(file, uri); + } + + fclose(file); + return true; +} + +GPtrArray * +spl_load(const char *utf8path, GError **error_r) +{ + if (spl_map(error_r) == NULL) + return NULL; + + char *path_fs = spl_map_to_fs(utf8path, error_r); + if (path_fs == NULL) + return NULL; + + FILE *file = fopen(path_fs, "r"); + g_free(path_fs); + if (file == NULL) { + playlist_errno(error_r); + return NULL; + } + + GPtrArray *list = g_ptr_array_new(); + + GString *buffer = g_string_sized_new(1024); + char *s; + while ((s = read_text_line(file, buffer)) != NULL) { + if (*s == 0 || *s == PLAYLIST_COMMENT) + continue; + + if (!uri_has_scheme(s)) { + char *path_utf8; + + path_utf8 = map_fs_to_utf8(s); + if (path_utf8 == NULL) + continue; + + s = path_utf8; + } else + s = g_strdup(s); + + g_ptr_array_add(list, s); + + if (list->len >= playlist_max_length) + break; + } + + fclose(file); + return list; +} + +void +spl_free(GPtrArray *list) +{ + for (unsigned i = 0; i < list->len; ++i) { + char *uri = (char *)g_ptr_array_index(list, i); + g_free(uri); + } + + g_ptr_array_free(list, true); +} + +static char * +spl_remove_index_internal(GPtrArray *list, unsigned idx) +{ + assert(idx < list->len); + + char *uri = (char *)g_ptr_array_remove_index(list, idx); + assert(uri != NULL); + return uri; +} + +static void +spl_insert_index_internal(GPtrArray *list, unsigned idx, char *uri) +{ + assert(idx <= list->len); + + g_ptr_array_add(list, uri); + + memmove(list->pdata + idx + 1, list->pdata + idx, + (list->len - idx - 1) * sizeof(list->pdata[0])); + g_ptr_array_index(list, idx) = uri; +} + +bool +spl_move_index(const char *utf8path, unsigned src, unsigned dest, + GError **error_r) +{ + if (src == dest) + /* this doesn't check whether the playlist exists, but + what the hell.. */ + return true; + + GPtrArray *list = spl_load(utf8path, error_r); + if (list == NULL) + return false; + + if (src >= list->len || dest >= list->len) { + spl_free(list); + g_set_error_literal(error_r, playlist_quark(), + PLAYLIST_RESULT_BAD_RANGE, + "Bad range"); + return false; + } + + char *uri = spl_remove_index_internal(list, src); + spl_insert_index_internal(list, dest, uri); + + bool result = spl_save(list, utf8path, error_r); + + spl_free(list); + + idle_add(IDLE_STORED_PLAYLIST); + return result; +} + +bool +spl_clear(const char *utf8path, GError **error_r) +{ + FILE *file; + + if (spl_map(error_r) == NULL) + return false; + + char *path_fs = spl_map_to_fs(utf8path, error_r); + if (path_fs == NULL) + return false; + + file = fopen(path_fs, "w"); + g_free(path_fs); + if (file == NULL) { + playlist_errno(error_r); + return false; + } + + fclose(file); + + idle_add(IDLE_STORED_PLAYLIST); + return true; +} + +bool +spl_delete(const char *name_utf8, GError **error_r) +{ + char *path_fs = spl_map_to_fs(name_utf8, error_r); + if (path_fs == NULL) + return false; + + int ret = unlink(path_fs); + g_free(path_fs); + if (ret < 0) { + playlist_errno(error_r); + return false; + } + + idle_add(IDLE_STORED_PLAYLIST); + return true; +} + +bool +spl_remove_index(const char *utf8path, unsigned pos, GError **error_r) +{ + GPtrArray *list = spl_load(utf8path, error_r); + if (list == NULL) + return false; + + if (pos >= list->len) { + spl_free(list); + g_set_error_literal(error_r, playlist_quark(), + PLAYLIST_RESULT_BAD_RANGE, + "Bad range"); + return false; + } + + char *uri = spl_remove_index_internal(list, pos); + g_free(uri); + bool result = spl_save(list, utf8path, error_r); + + spl_free(list); + + idle_add(IDLE_STORED_PLAYLIST); + return result; +} + +bool +spl_append_song(const char *utf8path, struct song *song, GError **error_r) +{ + FILE *file; + + if (spl_map(error_r) == NULL) + return false; + + char *path_fs = spl_map_to_fs(utf8path, error_r); + if (path_fs == NULL) + return false; + + file = fopen(path_fs, "a"); + g_free(path_fs); + if (file == NULL) { + playlist_errno(error_r); + return false; + } + + struct stat st; + if (fstat(fileno(file), &st) < 0) { + playlist_errno(error_r); + fclose(file); + return false; + } + + if (st.st_size / (MPD_PATH_MAX + 1) >= (off_t)playlist_max_length) { + fclose(file); + g_set_error_literal(error_r, playlist_quark(), + PLAYLIST_RESULT_TOO_LARGE, + "Stored playlist is too large"); + return false; + } + + playlist_print_song(file, song); + + fclose(file); + + idle_add(IDLE_STORED_PLAYLIST); + return true; +} + +bool +spl_append_uri(const char *url, const char *utf8file, GError **error_r) +{ + if (uri_has_scheme(url)) { + struct song *song = song_remote_new(url); + bool success = spl_append_song(utf8file, song, error_r); + song_free(song); + return success; + } else { + struct song *song = db_get_song(url); + if (song == NULL) { + g_set_error_literal(error_r, playlist_quark(), + PLAYLIST_RESULT_NO_SUCH_SONG, + "No such song"); + return false; + } + + bool success = spl_append_song(utf8file, song, error_r); + db_return_song(song); + return success; + } +} + +static bool +spl_rename_internal(const char *from_path_fs, const char *to_path_fs, + GError **error_r) +{ + if (!g_file_test(from_path_fs, G_FILE_TEST_IS_REGULAR)) { + g_set_error_literal(error_r, playlist_quark(), + PLAYLIST_RESULT_NO_SUCH_LIST, + "No such playlist"); + return false; + } + + if (g_file_test(to_path_fs, G_FILE_TEST_EXISTS)) { + g_set_error_literal(error_r, playlist_quark(), + PLAYLIST_RESULT_LIST_EXISTS, + "Playlist exists already"); + return false; + } + + if (rename(from_path_fs, to_path_fs) < 0) { + playlist_errno(error_r); + return false; + } + + idle_add(IDLE_STORED_PLAYLIST); + return true; +} + +bool +spl_rename(const char *utf8from, const char *utf8to, GError **error_r) +{ + if (spl_map(error_r) == NULL) + return false; + + char *from_path_fs = spl_map_to_fs(utf8from, error_r); + if (from_path_fs == NULL) + return false; + + char *to_path_fs = spl_map_to_fs(utf8to, error_r); + if (to_path_fs == NULL) { + g_free(from_path_fs); + return false; + } + + bool success = spl_rename_internal(from_path_fs, to_path_fs, error_r); + + g_free(from_path_fs); + g_free(to_path_fs); + + return success; +} diff --git a/src/PlaylistFile.h b/src/PlaylistFile.h new file mode 100644 index 000000000..35eda6d7b --- /dev/null +++ b/src/PlaylistFile.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_STORED_PLAYLIST_H +#define MPD_STORED_PLAYLIST_H + +#include +#include +#include + +struct song; + +struct stored_playlist_info { + char *name; + + time_t mtime; +}; + +extern bool playlist_saveAbsolutePaths; + +G_BEGIN_DECLS + +/** + * Perform some global initialization, e.g. load configuration values. + */ +void +spl_global_init(void); + +/** + * Determines whether the specified string is a valid name for a + * stored playlist. + */ +bool +spl_valid_name(const char *name_utf8); + +/** + * Returns a list of stored_playlist_info struct pointers. Returns + * NULL if an error occurred. + */ +GPtrArray * +spl_list(GError **error_r); + +void +spl_list_free(GPtrArray *list); + +GPtrArray * +spl_load(const char *utf8path, GError **error_r); + +void +spl_free(GPtrArray *list); + +bool +spl_move_index(const char *utf8path, unsigned src, unsigned dest, + GError **error_r); + +bool +spl_clear(const char *utf8path, GError **error_r); + +bool +spl_delete(const char *name_utf8, GError **error_r); + +bool +spl_remove_index(const char *utf8path, unsigned pos, GError **error_r); + +bool +spl_append_song(const char *utf8path, struct song *song, GError **error_r); + +bool +spl_append_uri(const char *file, const char *utf8file, GError **error_r); + +bool +spl_rename(const char *utf8from, const char *utf8to, GError **error_r); + +G_END_DECLS + +#endif diff --git a/src/PlaylistMapper.cxx b/src/PlaylistMapper.cxx new file mode 100644 index 000000000..415f8ba2f --- /dev/null +++ b/src/PlaylistMapper.cxx @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "PlaylistMapper.h" +#include "PlaylistFile.h" + +extern "C" { +#include "playlist_list.h" +#include "mapper.h" +#include "uri.h" +} + +#include + +static struct playlist_provider * +playlist_open_path(const char *path_fs, GMutex *mutex, GCond *cond, + struct input_stream **is_r) +{ + struct playlist_provider *playlist; + + playlist = playlist_list_open_uri(path_fs, mutex, cond); + if (playlist != NULL) + *is_r = NULL; + else + playlist = playlist_list_open_path(path_fs, mutex, cond, is_r); + + return playlist; +} + +/** + * Load a playlist from the configured playlist directory. + */ +static struct playlist_provider * +playlist_open_in_playlist_dir(const char *uri, GMutex *mutex, GCond *cond, + struct input_stream **is_r) +{ + char *path_fs; + + assert(spl_valid_name(uri)); + + const char *playlist_directory_fs = map_spl_path(); + if (playlist_directory_fs == NULL) + return NULL; + + path_fs = g_build_filename(playlist_directory_fs, uri, NULL); + + struct playlist_provider *playlist = + playlist_open_path(path_fs, mutex, cond, is_r); + g_free(path_fs); + + return playlist; +} + +/** + * Load a playlist from the configured music directory. + */ +static struct playlist_provider * +playlist_open_in_music_dir(const char *uri, GMutex *mutex, GCond *cond, + struct input_stream **is_r) +{ + char *path_fs; + + assert(uri_safe_local(uri)); + + path_fs = map_uri_fs(uri); + if (path_fs == NULL) + return NULL; + + struct playlist_provider *playlist = + playlist_open_path(path_fs, mutex, cond, is_r); + g_free(path_fs); + + return playlist; +} + +struct playlist_provider * +playlist_mapper_open(const char *uri, GMutex *mutex, GCond *cond, + struct input_stream **is_r) +{ + struct playlist_provider *playlist; + + if (spl_valid_name(uri)) { + playlist = playlist_open_in_playlist_dir(uri, mutex, cond, + is_r); + if (playlist != NULL) + return playlist; + } + + if (uri_safe_local(uri)) { + playlist = playlist_open_in_music_dir(uri, mutex, cond, is_r); + if (playlist != NULL) + return playlist; + } + + return NULL; +} diff --git a/src/PlaylistMapper.h b/src/PlaylistMapper.h new file mode 100644 index 000000000..829aac988 --- /dev/null +++ b/src/PlaylistMapper.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_PLAYLIST_MAPPER_H +#define MPD_PLAYLIST_MAPPER_H + +#include + +struct input_stream; + +G_BEGIN_DECLS + +/** + * Opens a playlist from an URI relative to the playlist or music + * directory. + * + * @param is_r on success, an input_stream object may be returned + * here, which must be closed after the playlist_provider object is + * freed + */ +struct playlist_provider * +playlist_mapper_open(const char *uri, GMutex *mutex, GCond *cond, + struct input_stream **is_r); + +G_END_DECLS + +#endif diff --git a/src/PlaylistPrint.cxx b/src/PlaylistPrint.cxx index 345506d5e..832f49cfd 100644 --- a/src/PlaylistPrint.cxx +++ b/src/PlaylistPrint.cxx @@ -19,6 +19,7 @@ #include "config.h" #include "PlaylistPrint.hxx" +#include "PlaylistFile.h" #include "QueuePrint.hxx" extern "C" { @@ -27,7 +28,6 @@ extern "C" { #include "playlist_any.h" #include "playlist_song.h" #include "playlist.h" -#include "stored_playlist.h" #include "song_print.h" #include "song.h" #include "database.h" diff --git a/src/PlaylistSave.cxx b/src/PlaylistSave.cxx new file mode 100644 index 000000000..00de539d9 --- /dev/null +++ b/src/PlaylistSave.cxx @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "PlaylistSave.hxx" +#include "PlaylistFile.h" +#include "song.h" + +extern "C" { +#include "playlist.h" +#include "mapper.h" +#include "path.h" +#include "uri.h" +#include "idle.h" +} + +#include "glib_compat.h" + +#include + +void +playlist_print_song(FILE *file, const struct song *song) +{ + if (playlist_saveAbsolutePaths && song_in_database(song)) { + char *path = map_song_fs(song); + if (path != NULL) { + fprintf(file, "%s\n", path); + g_free(path); + } + } else { + char *uri = song_get_uri(song), *uri_fs; + + uri_fs = utf8_to_fs_charset(uri); + g_free(uri); + + fprintf(file, "%s\n", uri_fs); + g_free(uri_fs); + } +} + +void +playlist_print_uri(FILE *file, const char *uri) +{ + char *s; + + if (playlist_saveAbsolutePaths && !uri_has_scheme(uri) && + !g_path_is_absolute(uri)) + s = map_uri_fs(uri); + else + s = utf8_to_fs_charset(uri); + + if (s != NULL) { + fprintf(file, "%s\n", s); + g_free(s); + } +} + +enum playlist_result +spl_save_queue(const char *name_utf8, const struct queue *queue) +{ + char *path_fs; + FILE *file; + + if (map_spl_path() == NULL) + return PLAYLIST_RESULT_DISABLED; + + if (!spl_valid_name(name_utf8)) + return PLAYLIST_RESULT_BAD_NAME; + + path_fs = map_spl_utf8_to_fs(name_utf8); + if (path_fs == NULL) + return PLAYLIST_RESULT_BAD_NAME; + + if (g_file_test(path_fs, G_FILE_TEST_EXISTS)) { + g_free(path_fs); + return PLAYLIST_RESULT_LIST_EXISTS; + } + + file = fopen(path_fs, "w"); + g_free(path_fs); + + if (file == NULL) + return PLAYLIST_RESULT_ERRNO; + + for (unsigned i = 0; i < queue_length(queue); i++) + playlist_print_song(file, queue_get(queue, i)); + + fclose(file); + + idle_add(IDLE_STORED_PLAYLIST); + return PLAYLIST_RESULT_SUCCESS; +} + +enum playlist_result +spl_save_playlist(const char *name_utf8, const struct playlist *playlist) +{ + return spl_save_queue(name_utf8, &playlist->queue); +} + +bool +playlist_load_spl(struct playlist *playlist, struct player_control *pc, + const char *name_utf8, + unsigned start_index, unsigned end_index, + GError **error_r) +{ + GPtrArray *list; + + list = spl_load(name_utf8, error_r); + if (list == NULL) + return false; + + if (list->len < end_index) + end_index = list->len; + + for (unsigned i = start_index; i < end_index; ++i) { + const char *temp = (const char *)g_ptr_array_index(list, i); + if ((playlist_append_uri(playlist, pc, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { + /* for windows compatibility, convert slashes */ + char *temp2 = g_strdup(temp); + char *p = temp2; + while (*p) { + if (*p == '\\') + *p = '/'; + p++; + } + if ((playlist_append_uri(playlist, pc, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { + g_warning("can't add file \"%s\"", temp2); + } + g_free(temp2); + } + } + + spl_free(list); + return true; +} diff --git a/src/PlaylistSave.hxx b/src/PlaylistSave.hxx new file mode 100644 index 000000000..20b2ca425 --- /dev/null +++ b/src/PlaylistSave.hxx @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_PLAYLIST_SAVE_H +#define MPD_PLAYLIST_SAVE_H + +#include "playlist_error.h" + +#include +#include + +struct song; +struct queue; +struct playlist; +struct player_control; + +void +playlist_print_song(FILE *fp, const struct song *song); + +void +playlist_print_uri(FILE *fp, const char *uri); + +/** + * Saves a queue object into a stored playlist file. + */ +enum playlist_result +spl_save_queue(const char *name_utf8, const struct queue *queue); + +/** + * Saves a playlist object into a stored playlist file. + */ +enum playlist_result +spl_save_playlist(const char *name_utf8, const struct playlist *playlist); + +/** + * Loads a stored playlist file, and append all songs to the global + * playlist. + */ +bool +playlist_load_spl(struct playlist *playlist, struct player_control *pc, + const char *name_utf8, + unsigned start_index, unsigned end_index, + GError **error_r); + +#endif diff --git a/src/main.c b/src/main.c index f08a2ec31..39778aad6 100644 --- a/src/main.c +++ b/src/main.c @@ -26,7 +26,7 @@ #include "idle.h" #include "AllCommands.h" #include "playlist.h" -#include "stored_playlist.h" +#include "PlaylistFile.h" #include "database.h" #include "update.h" #include "player_thread.h" diff --git a/src/playlist_any.c b/src/playlist_any.c index 450ca5932..e4017ac0d 100644 --- a/src/playlist_any.c +++ b/src/playlist_any.c @@ -20,7 +20,7 @@ #include "config.h" #include "playlist_any.h" #include "playlist_list.h" -#include "playlist_mapper.h" +#include "PlaylistMapper.h" #include "uri.h" #include "input_stream.h" diff --git a/src/playlist_mapper.c b/src/playlist_mapper.c deleted file mode 100644 index 13adb80d0..000000000 --- a/src/playlist_mapper.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "playlist_mapper.h" -#include "playlist_list.h" -#include "stored_playlist.h" -#include "mapper.h" -#include "uri.h" - -#include - -static struct playlist_provider * -playlist_open_path(const char *path_fs, GMutex *mutex, GCond *cond, - struct input_stream **is_r) -{ - struct playlist_provider *playlist; - - playlist = playlist_list_open_uri(path_fs, mutex, cond); - if (playlist != NULL) - *is_r = NULL; - else - playlist = playlist_list_open_path(path_fs, mutex, cond, is_r); - - return playlist; -} - -/** - * Load a playlist from the configured playlist directory. - */ -static struct playlist_provider * -playlist_open_in_playlist_dir(const char *uri, GMutex *mutex, GCond *cond, - struct input_stream **is_r) -{ - char *path_fs; - - assert(spl_valid_name(uri)); - - const char *playlist_directory_fs = map_spl_path(); - if (playlist_directory_fs == NULL) - return NULL; - - path_fs = g_build_filename(playlist_directory_fs, uri, NULL); - - struct playlist_provider *playlist = - playlist_open_path(path_fs, mutex, cond, is_r); - g_free(path_fs); - - return playlist; -} - -/** - * Load a playlist from the configured music directory. - */ -static struct playlist_provider * -playlist_open_in_music_dir(const char *uri, GMutex *mutex, GCond *cond, - struct input_stream **is_r) -{ - char *path_fs; - - assert(uri_safe_local(uri)); - - path_fs = map_uri_fs(uri); - if (path_fs == NULL) - return NULL; - - struct playlist_provider *playlist = - playlist_open_path(path_fs, mutex, cond, is_r); - g_free(path_fs); - - return playlist; -} - -struct playlist_provider * -playlist_mapper_open(const char *uri, GMutex *mutex, GCond *cond, - struct input_stream **is_r) -{ - struct playlist_provider *playlist; - - if (spl_valid_name(uri)) { - playlist = playlist_open_in_playlist_dir(uri, mutex, cond, - is_r); - if (playlist != NULL) - return playlist; - } - - if (uri_safe_local(uri)) { - playlist = playlist_open_in_music_dir(uri, mutex, cond, is_r); - if (playlist != NULL) - return playlist; - } - - return NULL; -} diff --git a/src/playlist_mapper.h b/src/playlist_mapper.h deleted file mode 100644 index 9a7187d93..000000000 --- a/src/playlist_mapper.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPD_PLAYLIST_MAPPER_H -#define MPD_PLAYLIST_MAPPER_H - -#include - -struct input_stream; - -/** - * Opens a playlist from an URI relative to the playlist or music - * directory. - * - * @param is_r on success, an input_stream object may be returned - * here, which must be closed after the playlist_provider object is - * freed - */ -struct playlist_provider * -playlist_mapper_open(const char *uri, GMutex *mutex, GCond *cond, - struct input_stream **is_r); - -#endif diff --git a/src/playlist_save.c b/src/playlist_save.c deleted file mode 100644 index 122eca332..000000000 --- a/src/playlist_save.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "playlist_save.h" -#include "playlist.h" -#include "stored_playlist.h" -#include "queue.h" -#include "song.h" -#include "mapper.h" -#include "path.h" -#include "uri.h" -#include "database.h" -#include "idle.h" -#include "glib_compat.h" - -#include - -void -playlist_print_song(FILE *file, const struct song *song) -{ - if (playlist_saveAbsolutePaths && song_in_database(song)) { - char *path = map_song_fs(song); - if (path != NULL) { - fprintf(file, "%s\n", path); - g_free(path); - } - } else { - char *uri = song_get_uri(song), *uri_fs; - - uri_fs = utf8_to_fs_charset(uri); - g_free(uri); - - fprintf(file, "%s\n", uri_fs); - g_free(uri_fs); - } -} - -void -playlist_print_uri(FILE *file, const char *uri) -{ - char *s; - - if (playlist_saveAbsolutePaths && !uri_has_scheme(uri) && - !g_path_is_absolute(uri)) - s = map_uri_fs(uri); - else - s = utf8_to_fs_charset(uri); - - if (s != NULL) { - fprintf(file, "%s\n", s); - g_free(s); - } -} - -enum playlist_result -spl_save_queue(const char *name_utf8, const struct queue *queue) -{ - char *path_fs; - FILE *file; - - if (map_spl_path() == NULL) - return PLAYLIST_RESULT_DISABLED; - - if (!spl_valid_name(name_utf8)) - return PLAYLIST_RESULT_BAD_NAME; - - path_fs = map_spl_utf8_to_fs(name_utf8); - if (path_fs == NULL) - return PLAYLIST_RESULT_BAD_NAME; - - if (g_file_test(path_fs, G_FILE_TEST_EXISTS)) { - g_free(path_fs); - return PLAYLIST_RESULT_LIST_EXISTS; - } - - file = fopen(path_fs, "w"); - g_free(path_fs); - - if (file == NULL) - return PLAYLIST_RESULT_ERRNO; - - for (unsigned i = 0; i < queue_length(queue); i++) - playlist_print_song(file, queue_get(queue, i)); - - fclose(file); - - idle_add(IDLE_STORED_PLAYLIST); - return PLAYLIST_RESULT_SUCCESS; -} - -enum playlist_result -spl_save_playlist(const char *name_utf8, const struct playlist *playlist) -{ - return spl_save_queue(name_utf8, &playlist->queue); -} - -bool -playlist_load_spl(struct playlist *playlist, struct player_control *pc, - const char *name_utf8, - unsigned start_index, unsigned end_index, - GError **error_r) -{ - GPtrArray *list; - - list = spl_load(name_utf8, error_r); - if (list == NULL) - return false; - - if (list->len < end_index) - end_index = list->len; - - for (unsigned i = start_index; i < end_index; ++i) { - const char *temp = g_ptr_array_index(list, i); - if ((playlist_append_uri(playlist, pc, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { - /* for windows compatibility, convert slashes */ - char *temp2 = g_strdup(temp); - char *p = temp2; - while (*p) { - if (*p == '\\') - *p = '/'; - p++; - } - if ((playlist_append_uri(playlist, pc, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { - g_warning("can't add file \"%s\"", temp2); - } - g_free(temp2); - } - } - - spl_free(list); - return true; -} diff --git a/src/playlist_save.h b/src/playlist_save.h deleted file mode 100644 index a6c31a9a6..000000000 --- a/src/playlist_save.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPD_PLAYLIST_SAVE_H -#define MPD_PLAYLIST_SAVE_H - -#include "playlist_error.h" - -#include -#include - -struct song; -struct queue; -struct playlist; -struct player_control; - -void -playlist_print_song(FILE *fp, const struct song *song); - -void -playlist_print_uri(FILE *fp, const char *uri); - -/** - * Saves a queue object into a stored playlist file. - */ -enum playlist_result -spl_save_queue(const char *name_utf8, const struct queue *queue); - -/** - * Saves a playlist object into a stored playlist file. - */ -enum playlist_result -spl_save_playlist(const char *name_utf8, const struct playlist *playlist); - -/** - * Loads a stored playlist file, and append all songs to the global - * playlist. - */ -bool -playlist_load_spl(struct playlist *playlist, struct player_control *pc, - const char *name_utf8, - unsigned start_index, unsigned end_index, - GError **error_r); - -#endif diff --git a/src/stored_playlist.c b/src/stored_playlist.c deleted file mode 100644 index 121349bd8..000000000 --- a/src/stored_playlist.c +++ /dev/null @@ -1,533 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "stored_playlist.h" -#include "playlist_save.h" -#include "text_file.h" -#include "song.h" -#include "mapper.h" -#include "path.h" -#include "uri.h" -#include "database.h" -#include "idle.h" -#include "conf.h" -#include "glib_compat.h" - -#include -#include -#include -#include -#include -#include -#include - -static const char PLAYLIST_COMMENT = '#'; - -static unsigned playlist_max_length; -bool playlist_saveAbsolutePaths = DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS; - -void -spl_global_init(void) -{ - playlist_max_length = config_get_positive(CONF_MAX_PLAYLIST_LENGTH, - DEFAULT_PLAYLIST_MAX_LENGTH); - - playlist_saveAbsolutePaths = - config_get_bool(CONF_SAVE_ABSOLUTE_PATHS, - DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS); -} - -bool -spl_valid_name(const char *name_utf8) -{ - /* - * Not supporting '/' was done out of laziness, and we should - * really strive to support it in the future. - * - * Not supporting '\r' and '\n' is done out of protocol - * limitations (and arguably laziness), but bending over head - * over heels to modify the protocol (and compatibility with - * all clients) to support idiots who put '\r' and '\n' in - * filenames isn't going to happen, either. - */ - - return strchr(name_utf8, '/') == NULL && - strchr(name_utf8, '\n') == NULL && - strchr(name_utf8, '\r') == NULL; -} - -static const char * -spl_map(GError **error_r) -{ - const char *path_fs = map_spl_path(); - if (path_fs == NULL) - g_set_error_literal(error_r, playlist_quark(), - PLAYLIST_RESULT_DISABLED, - "Stored playlists are disabled"); - - return path_fs; -} - -static bool -spl_check_name(const char *name_utf8, GError **error_r) -{ - if (!spl_valid_name(name_utf8)) { - g_set_error_literal(error_r, playlist_quark(), - PLAYLIST_RESULT_BAD_NAME, - "Bad playlist name"); - return false; - } - - return true; -} - -static char * -spl_map_to_fs(const char *name_utf8, GError **error_r) -{ - if (spl_map(error_r) == NULL || - !spl_check_name(name_utf8, error_r)) - return NULL; - - char *path_fs = map_spl_utf8_to_fs(name_utf8); - if (path_fs == NULL) - g_set_error_literal(error_r, playlist_quark(), - PLAYLIST_RESULT_BAD_NAME, - "Bad playlist name"); - - return path_fs; -} - -/** - * Create a GError for the current errno. - */ -static void -playlist_errno(GError **error_r) -{ - switch (errno) { - case ENOENT: - g_set_error_literal(error_r, playlist_quark(), - PLAYLIST_RESULT_NO_SUCH_LIST, - "No such playlist"); - break; - - default: - g_set_error_literal(error_r, g_file_error_quark(), errno, - g_strerror(errno)); - break; - } -} - -static struct stored_playlist_info * -load_playlist_info(const char *parent_path_fs, const char *name_fs) -{ - size_t name_length = strlen(name_fs); - - if (name_length < sizeof(PLAYLIST_FILE_SUFFIX) || - memchr(name_fs, '\n', name_length) != NULL) - return NULL; - - if (!g_str_has_suffix(name_fs, PLAYLIST_FILE_SUFFIX)) - return NULL; - - char *path_fs = g_build_filename(parent_path_fs, name_fs, NULL); - struct stat st; - int ret = stat(path_fs, &st); - g_free(path_fs); - if (ret < 0 || !S_ISREG(st.st_mode)) - return NULL; - - char *name = g_strndup(name_fs, - name_length + 1 - sizeof(PLAYLIST_FILE_SUFFIX)); - char *name_utf8 = fs_charset_to_utf8(name); - g_free(name); - if (name_utf8 == NULL) - return NULL; - - struct stored_playlist_info *playlist = - g_new(struct stored_playlist_info, 1); - playlist->name = name_utf8; - playlist->mtime = st.st_mtime; - return playlist; -} - -GPtrArray * -spl_list(GError **error_r) -{ - const char *parent_path_fs = spl_map(error_r); - - if (parent_path_fs == NULL) - return NULL; - - DIR *dir = opendir(parent_path_fs); - if (dir == NULL) { - g_set_error_literal(error_r, g_file_error_quark(), errno, - g_strerror(errno)); - return NULL; - } - - GPtrArray *list = g_ptr_array_new(); - - struct dirent *ent; - while ((ent = readdir(dir)) != NULL) { - struct stored_playlist_info *playlist = - load_playlist_info(parent_path_fs, ent->d_name); - if (playlist != NULL) - g_ptr_array_add(list, playlist); - } - - closedir(dir); - return list; -} - -void -spl_list_free(GPtrArray *list) -{ - for (unsigned i = 0; i < list->len; ++i) { - struct stored_playlist_info *playlist = - g_ptr_array_index(list, i); - g_free(playlist->name); - g_free(playlist); - } - - g_ptr_array_free(list, true); -} - -static bool -spl_save(GPtrArray *list, const char *utf8path, GError **error_r) -{ - assert(utf8path != NULL); - - if (spl_map(error_r) == NULL) - return false; - - char *path_fs = spl_map_to_fs(utf8path, error_r); - if (path_fs == NULL) - return false; - - FILE *file = fopen(path_fs, "w"); - g_free(path_fs); - if (file == NULL) { - playlist_errno(error_r); - return false; - } - - for (unsigned i = 0; i < list->len; ++i) { - const char *uri = g_ptr_array_index(list, i); - playlist_print_uri(file, uri); - } - - fclose(file); - return true; -} - -GPtrArray * -spl_load(const char *utf8path, GError **error_r) -{ - if (spl_map(error_r) == NULL) - return NULL; - - char *path_fs = spl_map_to_fs(utf8path, error_r); - if (path_fs == NULL) - return NULL; - - FILE *file = fopen(path_fs, "r"); - g_free(path_fs); - if (file == NULL) { - playlist_errno(error_r); - return NULL; - } - - GPtrArray *list = g_ptr_array_new(); - - GString *buffer = g_string_sized_new(1024); - char *s; - while ((s = read_text_line(file, buffer)) != NULL) { - if (*s == 0 || *s == PLAYLIST_COMMENT) - continue; - - if (!uri_has_scheme(s)) { - char *path_utf8; - - path_utf8 = map_fs_to_utf8(s); - if (path_utf8 == NULL) - continue; - - s = path_utf8; - } else - s = g_strdup(s); - - g_ptr_array_add(list, s); - - if (list->len >= playlist_max_length) - break; - } - - fclose(file); - return list; -} - -void -spl_free(GPtrArray *list) -{ - for (unsigned i = 0; i < list->len; ++i) { - char *uri = g_ptr_array_index(list, i); - g_free(uri); - } - - g_ptr_array_free(list, true); -} - -static char * -spl_remove_index_internal(GPtrArray *list, unsigned idx) -{ - assert(idx < list->len); - - char *uri = g_ptr_array_remove_index(list, idx); - assert(uri != NULL); - return uri; -} - -static void -spl_insert_index_internal(GPtrArray *list, unsigned idx, char *uri) -{ - assert(idx <= list->len); - - g_ptr_array_add(list, uri); - - memmove(list->pdata + idx + 1, list->pdata + idx, - (list->len - idx - 1) * sizeof(list->pdata[0])); - g_ptr_array_index(list, idx) = uri; -} - -bool -spl_move_index(const char *utf8path, unsigned src, unsigned dest, - GError **error_r) -{ - if (src == dest) - /* this doesn't check whether the playlist exists, but - what the hell.. */ - return true; - - GPtrArray *list = spl_load(utf8path, error_r); - if (list == NULL) - return false; - - if (src >= list->len || dest >= list->len) { - spl_free(list); - g_set_error_literal(error_r, playlist_quark(), - PLAYLIST_RESULT_BAD_RANGE, - "Bad range"); - return false; - } - - char *uri = spl_remove_index_internal(list, src); - spl_insert_index_internal(list, dest, uri); - - bool result = spl_save(list, utf8path, error_r); - - spl_free(list); - - idle_add(IDLE_STORED_PLAYLIST); - return result; -} - -bool -spl_clear(const char *utf8path, GError **error_r) -{ - FILE *file; - - if (spl_map(error_r) == NULL) - return false; - - char *path_fs = spl_map_to_fs(utf8path, error_r); - if (path_fs == NULL) - return false; - - file = fopen(path_fs, "w"); - g_free(path_fs); - if (file == NULL) { - playlist_errno(error_r); - return false; - } - - fclose(file); - - idle_add(IDLE_STORED_PLAYLIST); - return true; -} - -bool -spl_delete(const char *name_utf8, GError **error_r) -{ - char *path_fs = spl_map_to_fs(name_utf8, error_r); - if (path_fs == NULL) - return false; - - int ret = unlink(path_fs); - g_free(path_fs); - if (ret < 0) { - playlist_errno(error_r); - return false; - } - - idle_add(IDLE_STORED_PLAYLIST); - return true; -} - -bool -spl_remove_index(const char *utf8path, unsigned pos, GError **error_r) -{ - GPtrArray *list = spl_load(utf8path, error_r); - if (list == NULL) - return false; - - if (pos >= list->len) { - spl_free(list); - g_set_error_literal(error_r, playlist_quark(), - PLAYLIST_RESULT_BAD_RANGE, - "Bad range"); - return false; - } - - char *uri = spl_remove_index_internal(list, pos); - g_free(uri); - bool result = spl_save(list, utf8path, error_r); - - spl_free(list); - - idle_add(IDLE_STORED_PLAYLIST); - return result; -} - -bool -spl_append_song(const char *utf8path, struct song *song, GError **error_r) -{ - FILE *file; - - if (spl_map(error_r) == NULL) - return false; - - char *path_fs = spl_map_to_fs(utf8path, error_r); - if (path_fs == NULL) - return false; - - file = fopen(path_fs, "a"); - g_free(path_fs); - if (file == NULL) { - playlist_errno(error_r); - return false; - } - - struct stat st; - if (fstat(fileno(file), &st) < 0) { - playlist_errno(error_r); - fclose(file); - return false; - } - - if (st.st_size / (MPD_PATH_MAX + 1) >= (off_t)playlist_max_length) { - fclose(file); - g_set_error_literal(error_r, playlist_quark(), - PLAYLIST_RESULT_TOO_LARGE, - "Stored playlist is too large"); - return false; - } - - playlist_print_song(file, song); - - fclose(file); - - idle_add(IDLE_STORED_PLAYLIST); - return true; -} - -bool -spl_append_uri(const char *url, const char *utf8file, GError **error_r) -{ - if (uri_has_scheme(url)) { - struct song *song = song_remote_new(url); - bool success = spl_append_song(utf8file, song, error_r); - song_free(song); - return success; - } else { - struct song *song = db_get_song(url); - if (song == NULL) { - g_set_error_literal(error_r, playlist_quark(), - PLAYLIST_RESULT_NO_SUCH_SONG, - "No such song"); - return false; - } - - bool success = spl_append_song(utf8file, song, error_r); - db_return_song(song); - return success; - } -} - -static bool -spl_rename_internal(const char *from_path_fs, const char *to_path_fs, - GError **error_r) -{ - if (!g_file_test(from_path_fs, G_FILE_TEST_IS_REGULAR)) { - g_set_error_literal(error_r, playlist_quark(), - PLAYLIST_RESULT_NO_SUCH_LIST, - "No such playlist"); - return false; - } - - if (g_file_test(to_path_fs, G_FILE_TEST_EXISTS)) { - g_set_error_literal(error_r, playlist_quark(), - PLAYLIST_RESULT_LIST_EXISTS, - "Playlist exists already"); - return false; - } - - if (rename(from_path_fs, to_path_fs) < 0) { - playlist_errno(error_r); - return false; - } - - idle_add(IDLE_STORED_PLAYLIST); - return true; -} - -bool -spl_rename(const char *utf8from, const char *utf8to, GError **error_r) -{ - if (spl_map(error_r) == NULL) - return false; - - char *from_path_fs = spl_map_to_fs(utf8from, error_r); - if (from_path_fs == NULL) - return false; - - char *to_path_fs = spl_map_to_fs(utf8to, error_r); - if (to_path_fs == NULL) { - g_free(from_path_fs); - return false; - } - - bool success = spl_rename_internal(from_path_fs, to_path_fs, error_r); - - g_free(from_path_fs); - g_free(to_path_fs); - - return success; -} diff --git a/src/stored_playlist.h b/src/stored_playlist.h deleted file mode 100644 index cfe49633c..000000000 --- a/src/stored_playlist.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPD_STORED_PLAYLIST_H -#define MPD_STORED_PLAYLIST_H - -#include -#include -#include - -struct song; - -struct stored_playlist_info { - char *name; - - time_t mtime; -}; - -extern bool playlist_saveAbsolutePaths; - -/** - * Perform some global initialization, e.g. load configuration values. - */ -void -spl_global_init(void); - -/** - * Determines whether the specified string is a valid name for a - * stored playlist. - */ -bool -spl_valid_name(const char *name_utf8); - -/** - * Returns a list of stored_playlist_info struct pointers. Returns - * NULL if an error occurred. - */ -GPtrArray * -spl_list(GError **error_r); - -void -spl_list_free(GPtrArray *list); - -GPtrArray * -spl_load(const char *utf8path, GError **error_r); - -void -spl_free(GPtrArray *list); - -bool -spl_move_index(const char *utf8path, unsigned src, unsigned dest, - GError **error_r); - -bool -spl_clear(const char *utf8path, GError **error_r); - -bool -spl_delete(const char *name_utf8, GError **error_r); - -bool -spl_remove_index(const char *utf8path, unsigned pos, GError **error_r); - -bool -spl_append_song(const char *utf8path, struct song *song, GError **error_r); - -bool -spl_append_uri(const char *file, const char *utf8file, GError **error_r); - -bool -spl_rename(const char *utf8from, const char *utf8to, GError **error_r); - -#endif -- cgit v1.2.3