diff --git a/src/Makefile.am b/src/Makefile.am index 7b54ed03..e5293b27 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,8 +2,8 @@ bin_PROGRAMS = ncmpcpp ncmpcpp_SOURCES = browser.cpp charset.cpp clock.cpp conv.cpp display.cpp \ error.cpp help.cpp helpers.cpp info.cpp lyrics.cpp media_library.cpp menu.cpp \ misc.cpp mpdpp.cpp ncmpcpp.cpp outputs.cpp playlist.cpp playlist_editor.cpp \ - scrollpad.cpp search_engine.cpp settings.cpp song.cpp status.cpp str_pool.c \ - tag_editor.cpp tiny_tag_editor.cpp visualizer.cpp window.cpp + scrollpad.cpp search_engine.cpp settings.cpp song.cpp status.cpp tag_editor.cpp \ + tiny_tag_editor.cpp visualizer.cpp window.cpp # set the include path found by configure INCLUDES= $(all_includes) diff --git a/src/charset.cpp b/src/charset.cpp index f3ab8bbf..0051c3da 100644 --- a/src/charset.cpp +++ b/src/charset.cpp @@ -30,7 +30,6 @@ #include #include "settings.h" -#include "str_pool.h" namespace { @@ -55,7 +54,7 @@ namespace return false; } - void charset_convert(const char *from, const char *to, const char *&inbuf, size_t len = 0) + void charset_convert(const char *from, const char *to, const char *&inbuf, bool delete_old, size_t len = 0) { if (!inbuf || !from || !to) return; @@ -74,14 +73,16 @@ namespace if (iconv(cd, const_cast(&inbuf), &len, &outbuf, &buflen) == size_t(-1)) { + inbuf = instart; delete [] outstart; iconv_close(cd); return; } iconv_close(cd); *outbuf = 0; - str_pool_put(instart); - inbuf = str_pool_get(outstart); + if (delete_old) + delete [] instart; + inbuf = strdup(outstart); delete [] outstart; } } @@ -90,10 +91,10 @@ void utf_to_locale(std::string &s) { if (s.empty() || Config.system_encoding.empty() || !has_non_ascii_chars(s)) return; - const char *tmp = str_pool_get(s.c_str()); - charset_convert("utf-8", Config.system_encoding.c_str(), tmp, s.length()); + const char *tmp = strdup(s.c_str()); + charset_convert("utf-8", Config.system_encoding.c_str(), tmp, 1, s.length()); s = tmp; - str_pool_put(tmp); + delete [] tmp; } std::string utf_to_locale_cpy(const std::string &s) @@ -107,10 +108,10 @@ void locale_to_utf(std::string &s) { if (s.empty() || Config.system_encoding.empty() || !has_non_ascii_chars(s)) return; - const char *tmp = str_pool_get(s.c_str()); - charset_convert(Config.system_encoding.c_str(), "utf-8", tmp, s.length()); + const char *tmp = strdup(s.c_str()); + charset_convert(Config.system_encoding.c_str(), "utf-8", tmp, 1, s.length()); s = tmp; - str_pool_put(tmp); + delete [] tmp; } std::string locale_to_utf_cpy(const std::string &s) @@ -120,18 +121,18 @@ std::string locale_to_utf_cpy(const std::string &s) return result; } -void str_pool_utf_to_locale(const char *&s) +void utf_to_locale(const char *&s, bool delete_old) { if (!s || Config.system_encoding.empty() || !has_non_ascii_chars(s)) return; - charset_convert("utf-8", Config.system_encoding.c_str(), s); + charset_convert("utf-8", Config.system_encoding.c_str(), s, delete_old); } -void str_pool_locale_to_utf(const char *&s) +void locale_to_utf(const char *&s, bool delete_old) { if (!s || Config.system_encoding.empty() || !has_non_ascii_chars(s)) return; - charset_convert(Config.system_encoding.c_str(), "utf-8", s); + charset_convert(Config.system_encoding.c_str(), "utf-8", s, delete_old); } #endif // HAVE_ICONV_H diff --git a/src/charset.h b/src/charset.h index 5c875355..e728d344 100644 --- a/src/charset.h +++ b/src/charset.h @@ -35,8 +35,8 @@ void locale_to_utf(std::string &); std::string utf_to_locale_cpy(const std::string &s); std::string locale_to_utf_cpy(const std::string &s); -void str_pool_utf_to_locale(const char *&); -void str_pool_locale_to_utf(const char *&); +void utf_to_locale(const char *&, bool); +void locale_to_utf(const char *&, bool); #else @@ -46,9 +46,6 @@ void str_pool_locale_to_utf(const char *&); #define utf_to_locale_cpy(x) (x) #define locale_to_utf_cpy(x) (x) -#define str_pool_utf_to_locale(x); -#define str_pool_locale_to_utf(x); - #endif // HAVE_ICONV_H #endif diff --git a/src/ncmpcpp.cpp b/src/ncmpcpp.cpp index d272e7f2..7acc0574 100644 --- a/src/ncmpcpp.cpp +++ b/src/ncmpcpp.cpp @@ -574,13 +574,13 @@ int main(int argc, char *argv[]) Playlist::BlockUpdate = 1; myPlaylist->UpdateTimer(); // needed for keeping proper position of now playing song. - if (myPlaylist->NowPlaying > myPlaylist->CurrentSong()->GetPosition()-del_counter) - myPlaylist->NowPlaying--; + if (myPlaylist->NowPlaying > int(myPlaylist->CurrentSong()->GetPosition())-del_counter) + --myPlaylist->NowPlaying; Mpd.DeleteID(myPlaylist->CurrentSong()->GetID()); myPlaylist->Items->DeleteOption(id); myPlaylist->Items->Refresh(); myPlaylist->Items->ReadKey(input); - del_counter++; + ++del_counter; } myPlaylist->FixPositions(myPlaylist->Items->Choice()); myPlaylist->Items->SetTimeout(ncmpcpp_window_timeout); diff --git a/src/playlist.cpp b/src/playlist.cpp index e2b27620..9087a94b 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -201,7 +201,7 @@ void Playlist::EnterPressed() { for (size_t i = 0; i < playlist.size(); ++i) { - if (playlist[i]->GetPosition() > int(i)) + if (playlist[i]->GetPosition() > i) { Mpd.Swap(playlist[i]->GetPosition(), i); std::swap(cmp[playlist[i]->GetPosition()], cmp[i]); diff --git a/src/song.cpp b/src/song.cpp index 6b6a79d1..c15b2608 100644 --- a/src/song.cpp +++ b/src/song.cpp @@ -44,6 +44,7 @@ namespace } MPD::Song::Song(mpd_song *s, bool copy_ptr) : itsSong(s), + itsFile(0), itsSlash(std::string::npos), itsHash(0), copyPtr(copy_ptr), @@ -54,6 +55,7 @@ MPD::Song::Song(mpd_song *s, bool copy_ptr) : itsSong(s), } MPD::Song::Song(const Song &s) : itsSong(0), + itsFile(s.itsFile ? strdup(s.itsFile) : 0), itsNewName(s.itsNewName), itsSlash(s.itsSlash), itsHash(s.itsHash), @@ -67,6 +69,7 @@ MPD::Song::~Song() { if (itsSong) mpd_song_free(itsSong); + delete [] itsFile; } std::string MPD::Song::GetLength() const @@ -80,19 +83,25 @@ void MPD::Song::Localize() # ifdef HAVE_ICONV_H if (isLocalised) return; - str_pool_utf_to_locale(itsSong->file); - SetHashAndSlash(); - str_pool_utf_to_locale(itsSong->artist); - str_pool_utf_to_locale(itsSong->title); - str_pool_utf_to_locale(itsSong->album); - str_pool_utf_to_locale(itsSong->track); - str_pool_utf_to_locale(itsSong->name); - str_pool_utf_to_locale(itsSong->date); - str_pool_utf_to_locale(itsSong->genre); - str_pool_utf_to_locale(itsSong->composer); - str_pool_utf_to_locale(itsSong->performer); - str_pool_utf_to_locale(itsSong->disc); - str_pool_utf_to_locale(itsSong->comment); + const char *tag, *conv_tag; + conv_tag = tag = mpd_song_get_uri(itsSong); + utf_to_locale(conv_tag, 0); + if (tag != conv_tag) // file has been converted + { + itsFile = conv_tag; + SetHashAndSlash(); + } + for (unsigned t = MPD_TAG_ARTIST; t <= MPD_TAG_DISC; ++t) + { + tag = conv_tag = mpd_song_get_tag(itsSong, mpd_tag_type(t), 0); + utf_to_locale(conv_tag, 0); + if (tag != conv_tag) // tag has been converted + { + mpd_song_clear_tag(itsSong, mpd_tag_type(t)); + mpd_song_add_tag(itsSong, mpd_tag_type(t), conv_tag); + delete [] conv_tag; + } + } isLocalised = 1; # endif // HAVE_ICONV_H } @@ -101,6 +110,8 @@ void MPD::Song::Clear() { if (itsSong) mpd_song_free(itsSong); + delete [] itsFile; + itsFile = 0; itsSong = 0; itsNewName.clear(); itsSlash = std::string::npos; @@ -121,12 +132,12 @@ bool MPD::Song::isFromDB() const bool MPD::Song::isStream() const { - return !strncmp(mpd_song_get_uri(itsSong), "http://", 7); + return !strncmp(MyFilename(), "http://", 7); } std::string MPD::Song::GetFile() const { - return mpd_song_get_uri(itsSong); + return MyFilename(); } std::string MPD::Song::GetName() const @@ -134,9 +145,9 @@ std::string MPD::Song::GetName() const if (const char *name = mpd_song_get_tag(itsSong, MPD_TAG_NAME, 0)) return name; else if (itsSlash != std::string::npos) - return mpd_song_get_uri(itsSong)+itsSlash+1; + return MyFilename()+itsSlash+1; else - return mpd_song_get_uri(itsSong); + return MyFilename(); } std::string MPD::Song::GetDirectory() const @@ -146,7 +157,7 @@ std::string MPD::Song::GetDirectory() const else if (itsSlash == std::string::npos) return "/"; else - return std::string(mpd_song_get_uri(itsSong), itsSlash); + return std::string(MyFilename(), itsSlash); } std::string MPD::Song::GetArtist() const @@ -247,14 +258,6 @@ std::string MPD::Song::GetComment() const return ""; } -/*void MPD::Song::SetFile(const std::string &str) -{ - if (itsSong->file) - str_pool_put(itsSong->file); - itsSong->file = str.empty() ? 0 : str_pool_get(str.c_str()); - SetHashAndSlash(); -}*/ - void MPD::Song::SetArtist(const std::string &str) { mpd_song_clear_tag(itsSong, MPD_TAG_ARTIST); @@ -528,12 +531,18 @@ void MPD::Song::ValidateFormat(const std::string &type, const std::string &s) void MPD::Song::SetHashAndSlash() { - const char *filename = mpd_song_get_uri(itsSong); + const char *filename = MyFilename(); if (!isStream()) { const char *tmp = strrchr(filename, '/'); itsSlash = tmp ? tmp-filename : std::string::npos; } - itsHash = calc_hash(filename); + if (!itsFile) + itsHash = calc_hash(filename); +} + +const char *MPD::Song::MyFilename() const +{ + return itsFile ? itsFile : mpd_song_get_uri(itsSong); } diff --git a/src/song.h b/src/song.h index d710ca0a..3b7266b5 100644 --- a/src/song.h +++ b/src/song.h @@ -34,7 +34,7 @@ namespace MPD typedef void (Song::*SetFunction)(const std::string &); typedef std::string (Song::*GetFunction)() const; - Song() : itsSong(0), itsSlash(std::string::npos), itsHash(0), copyPtr(0), isLocalised(0) { } + Song() : itsSong(0), itsFile(0), itsSlash(std::string::npos), itsHash(0), copyPtr(0), isLocalised(0) { } Song(mpd_song *, bool = 0); Song(const Song &); ~Song(); @@ -60,7 +60,6 @@ namespace MPD unsigned GetPosition() const { return mpd_song_get_pos(itsSong); } unsigned GetID() const { return mpd_song_get_id(itsSong); } - //void SetFile(const std::string &); void SetArtist(const std::string &); void SetTitle(const std::string &); void SetAlbum(const std::string &); @@ -100,8 +99,21 @@ namespace MPD void SetHashAndSlash(); std::string ParseFormat(std::string::const_iterator &it) const; + /// Used internally for handling filename, since we don't have + /// write access to file string in mpd_song, manage our own if + /// localization was done and there is localized filename that + /// is different than the original one. + /// + const char *MyFilename() const; + + /// internal mpd_song structure mpd_song *itsSong; + + /// localized version of filename + const char *itsFile; + std::string itsNewName; + size_t itsSlash; unsigned itsHash; bool copyPtr; diff --git a/src/str_pool.c b/src/str_pool.c deleted file mode 100644 index e258a849..00000000 --- a/src/str_pool.c +++ /dev/null @@ -1,125 +0,0 @@ -/* ncmpc - * Copyright (C) 2008 Max Kellermann - * This project's homepage is: 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 St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "str_pool.h" - -//#include -#include -#include -#include - -#define NUM_SLOTS 4096 - -struct slot { - struct slot *next; - unsigned char ref; - char value[1]; -} __attribute__((packed)); - -struct slot *slots[NUM_SLOTS]; - -inline unsigned -calc_hash(const char *p) -{ - unsigned hash = 5381; - - //assert(p != NULL); - - while (*p != 0) - hash = (hash << 5) + hash + *p++; - - return hash; -} - -static inline struct slot * -value_to_slot(const char *value) -{ - return (struct slot*)(value - offsetof(struct slot, value)); -} - -static struct slot *slot_alloc(struct slot *next, const char *value) -{ - size_t length = strlen(value); - struct slot *slot = malloc(sizeof(*slot) + length); - if (slot == NULL) - abort(); /* XXX */ - - slot->next = next; - slot->ref = 1; - memcpy(slot->value, value, length + 1); - return slot; -} - -const char *str_pool_get(const char *value) -{ - struct slot **slot_p, *slot; - - slot_p = &slots[calc_hash(value) % NUM_SLOTS]; - for (slot = *slot_p; slot != NULL; slot = slot->next) { - if (strcmp(value, slot->value) == 0 && slot->ref < 0xff) { - //assert(slot->ref > 0); - ++slot->ref; - return slot->value; - } - } - - slot = slot_alloc(*slot_p, value); - *slot_p = slot; - return slot->value; -} - -const char *str_pool_dup(const char *value) -{ - struct slot *slot = value_to_slot(value); - - //assert(slot->ref > 0); - - if (slot->ref < 0xff) { - ++slot->ref; - return value; - } else { - /* the reference counter overflows above 0xff; - duplicate the value, and start with 1 */ - struct slot **slot_p = - &slots[calc_hash(slot->value) % NUM_SLOTS]; - slot = slot_alloc(*slot_p, slot->value); - *slot_p = slot; - return slot->value; - } -} - -void str_pool_put(const char *value) -{ - struct slot **slot_p, *slot; - - slot = value_to_slot(value); - //assert(slot->ref > 0); - --slot->ref; - - if (slot->ref > 0) - return; - - for (slot_p = &slots[calc_hash(value) % NUM_SLOTS]; - *slot_p != slot; - slot_p = &(*slot_p)->next) { - //assert(*slot_p != NULL); - } - - *slot_p = slot->next; - free(slot); -} diff --git a/src/str_pool.h b/src/str_pool.h deleted file mode 100644 index c21b70f7..00000000 --- a/src/str_pool.h +++ /dev/null @@ -1,39 +0,0 @@ -/* ncmpc - * Copyright (C) 2008 Max Kellermann - * This project's homepage is: 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 St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef STR_POOL_H -#define STR_POOL_H - -#ifdef __cplusplus -extern "C" { -#endif - -unsigned calc_hash(const char *p); - -const char *str_pool_get(const char *value); - -const char *str_pool_dup(const char *value); - -void str_pool_put(const char *value); - -#ifdef __cplusplus -} -#endif - -#endif -