From 84326efc461cadb3024d35d6aa7ba6eba143a268 Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Sat, 8 Sep 2012 18:42:59 +0200 Subject: [PATCH] move wstring related functions to wide_char file --- src/Makefile.am | 2 + src/actions.cpp | 44 +++++++-------- src/bindings.cpp | 1 + src/browser.cpp | 8 +-- src/display.cpp | 8 +-- src/help.cpp | 1 + src/helpers.cpp | 14 +---- src/helpers.h | 3 +- src/lastfm.cpp | 4 +- src/lyrics.cpp | 4 +- src/scrollpad.cpp | 1 + src/settings.cpp | 8 +-- src/song.cpp | 31 ++++------- src/status.cpp | 6 +-- src/strbuffer.h | 3 +- src/tag_editor.cpp | 4 +- src/tiny_tag_editor.cpp | 6 +-- src/utility/string.cpp | 25 --------- src/utility/string.h | 3 -- src/utility/wide_string.cpp | 105 ++++++++++++++++++++++++++++++++++++ src/utility/wide_string.h | 34 ++++++++++++ src/window.cpp | 28 +--------- src/window.h | 12 ----- 23 files changed, 204 insertions(+), 151 deletions(-) create mode 100644 src/utility/wide_string.cpp create mode 100644 src/utility/wide_string.h diff --git a/src/Makefile.am b/src/Makefile.am index 5a71fda1..1280e7e2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,6 +4,7 @@ ncmpcpp_SOURCES = \ utility/html.cpp \ utility/string.cpp \ utility/type_conversions.cpp \ + utility/wide_string.cpp \ actions.cpp \ bindings.cpp \ browser.cpp \ @@ -52,6 +53,7 @@ noinst_HEADERS = \ utility/string.h \ utility/numeric_conversions.h \ utility/type_conversions.h \ + utility/wide_string.h \ bindings.h \ browser.h \ charset.h \ diff --git a/src/actions.cpp b/src/actions.cpp index 2fb38aa5..daee4796 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -800,7 +800,7 @@ void Delete::Run() question = "Delete "; question += itemTypeToString(item.type); question += " \""; - question += Shorten(ToWString(name), COLS-question.size()-10); + question += ToString(wideShorten(ToWString(name), COLS-question.size()-10)); question += "\"?"; } bool yes = AskYesNoQuestion(question, TraceMpdStatus); @@ -814,13 +814,13 @@ void Delete::Run() std::string name = i.type == MPD::itSong ? i.song->getName() : i.name; if (myBrowser->deleteItem(i)) { - const char msg[] = "\"%s\" deleted"; - ShowMessage(msg, Shorten(ToWString(name), COLS-const_strlen(msg)).c_str()); + const char msg[] = "\"%ls\" deleted"; + ShowMessage(msg, wideShorten(ToWString(name), COLS-const_strlen(msg)).c_str()); } else { - const char msg[] = "Couldn't delete \"%s\": %s"; - ShowMessage(msg, Shorten(ToWString(name), COLS-const_strlen(msg)-25).c_str(), strerror(errno)); + const char msg[] = "Couldn't delete \"%ls\": %s"; + ShowMessage(msg, wideShorten(ToWString(name), COLS-const_strlen(msg)-25).c_str(), strerror(errno)); success = false; break; } @@ -845,7 +845,7 @@ void Delete::Run() else { question = "Delete playlist \""; - question += Shorten(ToWString(myPlaylistEditor->Playlists->current().value()), COLS-question.size()-10); + question += ToString(wideShorten(ToWString(myPlaylistEditor->Playlists->current().value()), COLS-question.size()-10)); question += "\"?"; } bool yes = AskYesNoQuestion(question, TraceMpdStatus); @@ -1384,8 +1384,8 @@ void EditLibraryTag::Run() std::string path = Config.mpd_music_dir + es.getURI(); if (!TagEditor::WriteTags(es)) { - const char msg[] = "Error while updating tags in \"%s\""; - ShowMessage(msg, Shorten(ToWString(es.getURI()), COLS-const_strlen(msg)).c_str()); + const char msg[] = "Error while updating tags in \"%ls\""; + ShowMessage(msg, wideShorten(ToWString(es.getURI()), COLS-const_strlen(msg)).c_str()); success = false; break; } @@ -1430,16 +1430,16 @@ void EditLibraryAlbum::Run() TagLib::FileRef f(path.c_str()); if (f.isNull()) { - const char msg[] = "Error while opening file \"%s\""; - ShowMessage(msg, Shorten(ToWString((*myLibrary->Songs)[i].value().getURI()), COLS-const_strlen(msg)).c_str()); + const char msg[] = "Error while opening file \"%ls\""; + ShowMessage(msg, wideShorten(ToWString((*myLibrary->Songs)[i].value().getURI()), COLS-const_strlen(msg)).c_str()); success = 0; break; } f.tag()->setAlbum(ToWString(new_album)); if (!f.save()) { - const char msg[] = "Error while writing tags in \"%s\""; - ShowMessage(msg, Shorten(ToWString((*myLibrary->Songs)[i].value().getURI()), COLS-const_strlen(msg)).c_str()); + const char msg[] = "Error while writing tags in \"%ls\""; + ShowMessage(msg, wideShorten(ToWString((*myLibrary->Songs)[i].value().getURI()), COLS-const_strlen(msg)).c_str()); success = 0; break; } @@ -1491,16 +1491,16 @@ void EditDirectoryName::Run() int rename_result = rename(full_old_dir.c_str(), full_new_dir.c_str()); if (rename_result == 0) { - const char msg[] = "Directory renamed to \"%s\""; - ShowMessage(msg, Shorten(ToWString(new_dir), COLS-const_strlen(msg)).c_str()); + const char msg[] = "Directory renamed to \"%ls\""; + ShowMessage(msg, wideShorten(ToWString(new_dir), COLS-const_strlen(msg)).c_str()); if (!myBrowser->isLocal()) Mpd.UpdateDirectory(locale_to_utf_cpy(getSharedDirectory(old_dir, new_dir))); myBrowser->GetDirectory(myBrowser->CurrentDir()); } else { - const char msg[] = "Couldn't rename \"%s\": %s"; - ShowMessage(msg, Shorten(ToWString(old_dir), COLS-const_strlen(msg)-25).c_str(), strerror(errno)); + const char msg[] = "Couldn't rename \"%ls\": %s"; + ShowMessage(msg, wideShorten(ToWString(old_dir), COLS-const_strlen(msg)-25).c_str(), strerror(errno)); } } } @@ -1518,14 +1518,14 @@ void EditDirectoryName::Run() std::string full_new_dir = Config.mpd_music_dir + myTagEditor->CurrentDir() + "/" + locale_to_utf_cpy(new_dir); if (rename(full_old_dir.c_str(), full_new_dir.c_str()) == 0) { - const char msg[] = "Directory renamed to \"%s\""; - ShowMessage(msg, Shorten(ToWString(new_dir), COLS-const_strlen(msg)).c_str()); + const char msg[] = "Directory renamed to \"%ls\""; + ShowMessage(msg, wideShorten(ToWString(new_dir), COLS-const_strlen(msg)).c_str()); Mpd.UpdateDirectory(myTagEditor->CurrentDir()); } else { - const char msg[] = "Couldn't rename \"%s\": %s"; - ShowMessage(msg, Shorten(ToWString(old_dir), COLS-const_strlen(msg)-25).c_str(), strerror(errno)); + const char msg[] = "Couldn't rename \"%ls\": %s"; + ShowMessage(msg, wideShorten(ToWString(old_dir), COLS-const_strlen(msg)-25).c_str(), strerror(errno)); } } } @@ -1558,8 +1558,8 @@ void EditPlaylistName::Run() { if (Mpd.Rename(locale_to_utf_cpy(old_name), locale_to_utf_cpy(new_name))) { - const char msg[] = "Playlist renamed to \"%s\""; - ShowMessage(msg, Shorten(ToWString(new_name), COLS-const_strlen(msg)).c_str()); + const char msg[] = "Playlist renamed to \"%ls\""; + ShowMessage(msg, wideShorten(ToWString(new_name), COLS-const_strlen(msg)).c_str()); if (myBrowser->Main() && !myBrowser->isLocal()) myBrowser->GetDirectory("/"); if (myPlaylistEditor->Main()) diff --git a/src/bindings.cpp b/src/bindings.cpp index 5de8c232..9f6dea73 100644 --- a/src/bindings.cpp +++ b/src/bindings.cpp @@ -23,6 +23,7 @@ #include "global.h" #include "bindings.h" #include "utility/string.h" +#include "utility/wide_string.h" BindingsConfiguration Bindings; diff --git a/src/browser.cpp b/src/browser.cpp index 4bd72b90..98be9235 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -549,13 +549,13 @@ void Browser::ClearDirectory(const std::string &path) const ClearDirectory(full_path); if (remove(full_path.c_str()) == 0) { - const char msg[] = "Deleting \"%s\"..."; - ShowMessage(msg, Shorten(ToWString(full_path), COLS-const_strlen(msg)).c_str()); + const char msg[] = "Deleting \"%ls\"..."; + ShowMessage(msg, wideShorten(ToWString(full_path), COLS-const_strlen(msg)).c_str()); } else { - const char msg[] = "Couldn't remove \"%s\": %s"; - ShowMessage(msg, Shorten(ToWString(full_path), COLS-const_strlen(msg)-25).c_str(), strerror(errno)); + const char msg[] = "Couldn't remove \"%ls\": %s"; + ShowMessage(msg, wideShorten(ToWString(full_path), COLS-const_strlen(msg)-25).c_str(), strerror(errno)); } } closedir(dir); diff --git a/src/display.cpp b/src/display.cpp index e6925164..e0b49ad9 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -225,7 +225,7 @@ void showSongsInColumns(NC::Menu &menu, const MPD::Song &s, HasSongs &screen) } if (tag.empty() && it->display_empty_tag) tag = ToWString(Config.empty_tag); - NC::Window::cut(tag, width); + wideCut(tag, width); if (!discard_colors && it->color != NC::clDefault) menu << it->color; @@ -234,7 +234,7 @@ void showSongsInColumns(NC::Menu &menu, const MPD::Song &s, HasSongs &screen) // if column uses right alignment, calculate proper offset. // otherwise just assume offset is 0, ie. we start from the left. if (it->right_alignment) - x_off = std::max(0, width - int(NC::Window::length(tag))); + x_off = std::max(0, width - int(wideLength(tag))); whline(menu.raw(), KEY_SPACE, width); menu.goToXY(x + x_off, y); @@ -314,9 +314,9 @@ std::string Display::Columns(size_t list_width) } else name = it->name; - NC::Window::cut(name, width); + wideCut(name, width); - int x_off = std::max(0, width - int(NC::Window::length(name))); + int x_off = std::max(0, width - int(wideLength(name))); if (it->right_alignment) { result += std::string(x_off, KEY_SPACE); diff --git a/src/help.cpp b/src/help.cpp index 7f19218a..2fc520d4 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -25,6 +25,7 @@ #include "help.h" #include "settings.h" #include "status.h" +#include "utility/wide_string.h" using Global::MainHeight; using Global::MainStartY; diff --git a/src/helpers.cpp b/src/helpers.cpp index d770268c..70e9d7bf 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -296,7 +296,7 @@ std::wstring Scroller(const std::wstring &str, size_t &pos, size_t width) if (!Config.header_text_scrolling) return s; std::wstring result; - size_t len = NC::Window::length(s); + size_t len = wideLength(s); if (len > width) { @@ -322,15 +322,3 @@ std::wstring Scroller(const std::wstring &str, size_t &pos, size_t width) result = s; return result; } - -std::string Shorten(const std::wstring &s, size_t max_length) -{ - if (s.length() <= max_length) - return ToString(s); - if (max_length < 2) - return ""; - std::wstring result(s, 0, max_length/2-!(max_length%2)); - result += L".."; - result += s.substr(s.length()-max_length/2+1); - return ToString(result); -} diff --git a/src/helpers.h b/src/helpers.h index 733fd319..96a13c12 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -26,6 +26,7 @@ #include "screen.h" #include "settings.h" #include "status.h" +#include "utility/wide_string.h" inline HasSongs *hasSongs(BasicScreen *screen) { @@ -463,6 +464,4 @@ void markSongsInPlaylist(std::shared_ptr pl); std::wstring Scroller(const std::wstring &str, size_t &pos, size_t width); -std::string Shorten(const std::wstring &s, size_t max_length); - #endif diff --git a/src/lastfm.cpp b/src/lastfm.cpp index e8d5c425..880d7ae1 100644 --- a/src/lastfm.cpp +++ b/src/lastfm.cpp @@ -210,8 +210,8 @@ void Lastfm::Refetch() { if (remove(itsFilename.c_str()) && errno != ENOENT) { - const char msg[] = "Couldn't remove \"%s\": %s"; - ShowMessage(msg, Shorten(ToWString(itsFilename), COLS-const_strlen(msg)-25).c_str(), strerror(errno)); + const char msg[] = "Couldn't remove \"%ls\": %s"; + ShowMessage(msg, wideShorten(ToWString(itsFilename), COLS-const_strlen(msg)-25).c_str(), strerror(errno)); return; } Load(); diff --git a/src/lyrics.cpp b/src/lyrics.cpp index 8fbb3ead..df38bf51 100644 --- a/src/lyrics.cpp +++ b/src/lyrics.cpp @@ -405,8 +405,8 @@ void Lyrics::Refetch() { if (remove(itsFilename.c_str()) && errno != ENOENT) { - const char msg[] = "Couldn't remove \"%s\": %s"; - ShowMessage(msg, Shorten(ToWString(itsFilename), COLS-const_strlen(msg)-25).c_str(), strerror(errno)); + const char msg[] = "Couldn't remove \"%ls\": %s"; + ShowMessage(msg, wideShorten(ToWString(itsFilename), COLS-const_strlen(msg)-25).c_str(), strerror(errno)); return; } Load(); diff --git a/src/scrollpad.cpp b/src/scrollpad.cpp index fe1edbd3..d05f8b06 100644 --- a/src/scrollpad.cpp +++ b/src/scrollpad.cpp @@ -21,6 +21,7 @@ #include #include "scrollpad.h" +#include "utility/wide_string.h" namespace NC {// diff --git a/src/settings.cpp b/src/settings.cpp index 2e7337ba..ab2c8ae4 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -545,7 +545,7 @@ void Configuration::Read() { selected_item_prefix.clear(); String2Buffer(v, selected_item_prefix); - selected_item_prefix_length = NC::Window::length(ToWString(selected_item_prefix.str())); + selected_item_prefix_length = wideLength(ToWString(selected_item_prefix.str())); } } else if (name == "selected_item_suffix") @@ -554,7 +554,7 @@ void Configuration::Read() { selected_item_suffix.clear(); String2Buffer(v, selected_item_suffix); - selected_item_suffix_length = NC::Window::length(ToWString(selected_item_suffix.str())); + selected_item_suffix_length = wideLength(ToWString(selected_item_suffix.str())); } } else if (name == "now_playing_prefix") @@ -563,7 +563,7 @@ void Configuration::Read() { now_playing_prefix.clear(); String2Buffer(v, now_playing_prefix); - now_playing_prefix_length = NC::Window::length(ToWString(now_playing_prefix.str())); + now_playing_prefix_length = wideLength(ToWString(now_playing_prefix.str())); } } else if (name == "now_playing_suffix") @@ -572,7 +572,7 @@ void Configuration::Read() { now_playing_suffix.clear(); String2Buffer(ToWString(v), now_playing_suffix); - now_playing_suffix_length = NC::Window::length(now_playing_suffix.str()); + now_playing_suffix_length = wideLength(now_playing_suffix.str()); } } else if (name == "color1") diff --git a/src/song.cpp b/src/song.cpp index 330157c6..534be967 100644 --- a/src/song.cpp +++ b/src/song.cpp @@ -26,6 +26,7 @@ #include "song.h" #include "utility/numeric_conversions.h" #include "utility/type_conversions.h" +#include "utility/wide_string.h" #include "window.h" namespace {// @@ -38,19 +39,6 @@ size_t calc_hash(const char* s, unsigned seed = 0) return hash; } -// temporary hack, it won't work properly with wide characters -std::string Shorten(const std::wstring &s, size_t max_length) -{ - if (s.length() <= max_length) - return ToString(s); - if (max_length < 2) - return ""; - std::wstring result(s, 0, max_length/2-!(max_length%2)); - result += L".."; - result += s.substr(s.length()-max_length/2+1); - return ToString(result); -} - } namespace MPD {// @@ -289,10 +277,12 @@ std::string Song::ShowTime(unsigned length) length -= minutes*60; int seconds = length; + std::string result; if (hours > 0) - return print<32, std::string>::apply("%d:%02d:%02d", hours, minutes, seconds); + result = print<32, std::string>::apply("%d:%02d:%02d", hours, minutes, seconds); else - return print<32, std::string>::apply("%d:%02d", minutes, seconds); + result = print<32, std::string>::apply("%d:%02d", minutes, seconds); + return result; } bool MPD::Song::isFormatOk(const std::string &type, const std::string &fmt) @@ -324,7 +314,8 @@ bool MPD::Song::isFormatOk(const std::string &type, const std::string &fmt) return true; } -std::string Song::ParseFormat(std::string::const_iterator &it, const std::string &tag_separator, const std::string &escape_chars) const +std::string Song::ParseFormat(std::string::const_iterator &it, const std::string &tag_separator, + const std::string &escape_chars) const { std::string result; bool has_some_tags = 0; @@ -371,12 +362,8 @@ std::string Song::ParseFormat(std::string::const_iterator &it, const std::string } if (!tag.empty() && (get != &MPD::Song::getLength || getDuration() > 0)) { - if (delimiter) - { - std::wstring s = ToWString(tag); - if (NC::Window::length(s) > delimiter) - tag = Shorten(s, delimiter); - } + if (delimiter && tag.size() > delimiter) + tag = ToString(wideShorten(ToWString(tag), delimiter)); has_some_tags = 1; result += tag; } diff --git a/src/status.cpp b/src/status.cpp index 7418663c..20969183 100644 --- a/src/status.cpp +++ b/src/status.cpp @@ -447,11 +447,11 @@ void NcmpcppStatusChanged(MPD::Connection *, MPD::StatusChanges changed, void *) String2Buffer(ToWString(utf_to_locale_cpy(np.toString(Config.new_header_first_line, "$"))), first); String2Buffer(ToWString(utf_to_locale_cpy(np.toString(Config.new_header_second_line, "$"))), second); - size_t first_len = NC::Window::length(first.str()); + size_t first_len = wideLength(first.str()); size_t first_margin = (std::max(tracklength.length()+1, VolumeState.length()))*2; size_t first_start = first_len < COLS-first_margin ? (COLS-first_len)/2 : tracklength.length()+1; - size_t second_len = NC::Window::length(second.str()); + size_t second_len = wideLength(second.str()); size_t second_margin = (std::max(player_state.length(), size_t(8))+1)*2; size_t second_start = second_len < COLS-second_margin ? (COLS-second_len)/2 : player_state.length()+1; @@ -654,7 +654,7 @@ void DrawHeader() *wHeader << NC::fmtBold << Config.alternative_ui_separator_color; mvwhline(wHeader->raw(), 2, 0, 0, COLS); mvwhline(wHeader->raw(), 4, 0, 0, COLS); - *wHeader << NC::XY((COLS-NC::Window::length(title))/2, 3); + *wHeader << NC::XY((COLS-wideLength(title))/2, 3); *wHeader << Config.header_color << title << NC::clEnd; *wHeader << NC::clEnd << NC::fmtBoldEnd; } diff --git a/src/strbuffer.h b/src/strbuffer.h index dd7ab648..f75472e0 100644 --- a/src/strbuffer.h +++ b/src/strbuffer.h @@ -23,6 +23,7 @@ #include #include "utility/numeric_conversions.h" +#include "utility/wide_string.h" #include "window.h" namespace NC {// @@ -306,7 +307,7 @@ template void basic_buffer::write( ) const { std::basic_string s = m_string; - size_t len = Window::length(s); + size_t len = wideLength(s); if (len > width) { diff --git a/src/tag_editor.cpp b/src/tag_editor.cpp index 16111b77..ef71577a 100644 --- a/src/tag_editor.cpp +++ b/src/tag_editor.cpp @@ -596,8 +596,8 @@ void TagEditor::EnterPressed() ShowMessage("Writing tags in \"%s\"...", (*it)->getName().c_str()); if (!WriteTags(**it)) { - const char msg[] = "Error while writing tags in \"%s\""; - ShowMessage(msg, Shorten(ToWString((*it)->getURI()), COLS-const_strlen(msg)).c_str()); + const char msg[] = "Error while writing tags in \"%ls\""; + ShowMessage(msg, wideShorten(ToWString((*it)->getURI()), COLS-const_strlen(msg)).c_str()); success = 0; break; } diff --git a/src/tiny_tag_editor.cpp b/src/tiny_tag_editor.cpp index f628cab0..9202ddec 100644 --- a/src/tiny_tag_editor.cpp +++ b/src/tiny_tag_editor.cpp @@ -91,10 +91,8 @@ void TinyTagEditor::SwitchTo() full_path += Config.mpd_music_dir; full_path += itsEdited.getURI(); - std::string message = "Couldn't read file \""; - message += Shorten(ToWString(full_path), COLS-message.length()-3); - message += "\"!"; - ShowMessage("%s", message.c_str()); + const char msg[] = "Couldn't read file \"%ls\""; + ShowMessage(msg, wideShorten(ToWString(full_path), COLS-const_strlen(msg)).c_str()); } } diff --git a/src/utility/string.cpp b/src/utility/string.cpp index d75806b5..134a2a3e 100644 --- a/src/utility/string.cpp +++ b/src/utility/string.cpp @@ -44,31 +44,6 @@ bool isInteger(const char *s, bool accept_signed) return true; } -std::string ToString(const std::wstring &ws) -{ - std::string result; - char s[MB_CUR_MAX]; - for (size_t i = 0; i < ws.length(); ++i) - { - int n = wcrtomb(s, ws[i], 0); - if (n > 0) - result.append(s, n); - } - return result; -} - -std::wstring ToWString(const std::string &s) -{ - std::wstring result; - wchar_t *ws = new wchar_t[s.length()]; - const char *c_s = s.c_str(); - int n = mbsrtowcs(ws, &c_s, s.length(), 0); - if (n > 0) - result.append(ws, n); - delete [] ws; - return result; -} - std::vector split(const std::string &s, const std::string &delimiter) { if (delimiter.empty()) diff --git a/src/utility/string.h b/src/utility/string.h index f1f058c5..70e994a9 100644 --- a/src/utility/string.h +++ b/src/utility/string.h @@ -67,9 +67,6 @@ int stringToInt(const std::string &s); long stringToLongInt(const std::string &s); bool isInteger(const char *s, bool accept_signed); -std::string ToString(const std::wstring &ws); -std::wstring ToWString(const std::string &s); - std::vector split(const std::string &s, const std::string &delimiter); void replace(std::string &s, const std::string &from, const std::string &to); diff --git a/src/utility/wide_string.cpp b/src/utility/wide_string.cpp new file mode 100644 index 00000000..71c2383a --- /dev/null +++ b/src/utility/wide_string.cpp @@ -0,0 +1,105 @@ +/*************************************************************************** + * Copyright (C) 2008-2012 by Andrzej Rybczak * + * electricityispower@gmail.com * + * * + * 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 "utility/wide_string.h" + +std::string ToString(const std::wstring &ws) +{ + std::string result; + char s[MB_CUR_MAX]; + for (size_t i = 0; i < ws.length(); ++i) + { + int n = wcrtomb(s, ws[i], 0); + if (n > 0) + result.append(s, n); + } + return result; +} + +std::wstring ToWString(const std::string &s) +{ + std::wstring result; + wchar_t *ws = new wchar_t[s.length()]; + const char *c_s = s.c_str(); + int n = mbsrtowcs(ws, &c_s, s.length(), 0); + if (n > 0) + result.append(ws, n); + delete [] ws; + return result; +} + +size_t wideLength(const std::wstring &ws) +{ + int len = wcswidth(ws.c_str(), -1); + if (len < 0) + return ws.length(); + else + return len; +} + +void wideCut(std::wstring &ws, size_t max_length) +{ + size_t i = 0; + int remained_len = max_length; + for (; i < ws.length(); ++i) + { + remained_len -= wcwidth(ws[i]); + if (remained_len < 0) + { + ws.resize(i); + break; + } + } +} + +std::wstring wideShorten(const std::wstring &ws, size_t max_length) +{ + std::wstring result; + if (wideLength(ws) > max_length) + { + const size_t half_max = max_length/2 - 1; + size_t len = 0; + // get beginning of string + for (auto it = ws.begin(); it != ws.end(); ++it) + { + len += wcwidth(*it); + if (len > half_max) + break; + result += *it; + } + len = 0; + std::wstring end; + // get end of string in reverse order + for (auto it = ws.rbegin(); it != ws.rend(); ++it) + { + len += wcwidth(*it); + if (len > half_max) + break; + end += *it; + } + // apply end of string to its beginning + result += L".."; + result.append(end.rbegin(), end.rend()); + } + else + result = ws; + return result; +} + diff --git a/src/utility/wide_string.h b/src/utility/wide_string.h new file mode 100644 index 00000000..06e78d2a --- /dev/null +++ b/src/utility/wide_string.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2008-2012 by Andrzej Rybczak * + * electricityispower@gmail.com * + * * + * 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 _UTILITY_WIDE_STRING +#define _UTILITY_WIDE_STRING + +#include + +std::string ToString(const std::wstring &ws); +std::wstring ToWString(const std::string &s); + +size_t wideLength(const std::wstring &ws); + +void wideCut(std::wstring &ws, size_t max_length); +std::wstring wideShorten(const std::wstring &ws, size_t max_length); + +#endif // _UTILITY_WIDE_STRING diff --git a/src/window.cpp b/src/window.cpp index 04e9063c..45a38bbe 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -30,6 +30,7 @@ #include "error.h" #include "utility/string.h" +#include "utility/wide_string.h" #include "window.h" namespace NC {// @@ -456,7 +457,7 @@ std::string Window::getString(const std::string &base, size_t length_, size_t wi block_scrolling = 0; maxbeginning = block_scrolling ? 0 : (tmp->length() < width ? 0 : tmp->length()-width); - maxx = minx + (Window::length(*tmp) < width ? Window::length(*tmp) : width); + maxx = minx + (wideLength(*tmp) < width ? wideLength(*tmp) : width); real_maxx = minx + (tmp->length() < width ? tmp->length() : width); @@ -902,29 +903,4 @@ Window &Window::operator<<(size_t s) return *this; } -size_t Window::length(const std::wstring &ws) -{ -# ifdef WIN32 - return ws.length(); -# else - int len = wcswidth(ws.c_str(), -1); - return len < 0 ? ws.length() : len; -# endif // WIN32 -} - -void Window::cut(std::wstring &ws, size_t max_len) -{ - size_t i = 0; - int remained_len = max_len; - for (; i < ws.length(); ++i) - { - remained_len -= wcwidth(ws[i]); - if (remained_len < 0) - { - ws.resize(i); - break; - } - } -} - } diff --git a/src/window.h b/src/window.h index c06a725a..234eac6d 100644 --- a/src/window.h +++ b/src/window.h @@ -413,18 +413,6 @@ struct Window /// @param ws wide string to be printed /// @return reference to itself Window &operator<<(const std::wstring &ws); - - /// Measures real length of wide string (required if e.g. asian characters are used) - /// @param ws wide string that real length has to be measured - /// @return real length of wide string - static size_t length(const std::wstring &ws); - - /// Cuts string so it fits desired length on the screen. Note that it uses - /// wcwidth to check real width of all characters it contains. If string - /// fits requested length it's not modified at all. - /// @param ws wide string to be cut - /// @param max_len maximal length of string - static void cut(std::wstring &ws, size_t max_len); protected: /// Sets colors of window (interal use only) /// @param fg foregound color