reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

commit 76ba324156336015937bf3a27397766c20eac191
parent e70477c00758909ef539c056f9bb1f5eb98420a3
Author: cfillion <cfillion@users.noreply.github.com>
Date:   Wed,  6 Sep 2017 01:13:27 -0700

abstract away most of the UTF-8 to UTF-16 conversion for Windows

Diffstat:
Msrc/about.cpp | 126++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/archive.cpp | 34++++++++++++++++++----------------
Msrc/archive.hpp | 10++++------
Msrc/browser.cpp | 132++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/browser_entry.cpp | 56++++++++++++++++++++++++--------------------------------
Msrc/config.cpp | 82+++++++++++++++++++++++++++++++++++--------------------------------------------
Msrc/config.hpp | 22++++++++--------------
Msrc/dialog.cpp | 26++++----------------------
Msrc/dialog.hpp | 2--
Msrc/download.cpp | 15+++++++--------
Msrc/download.hpp | 3+--
Dsrc/encoding.cpp | 45---------------------------------------------
Dsrc/encoding.hpp | 58----------------------------------------------------------
Msrc/filedialog.cpp | 64++++++++++++++++++++++++++++++++++------------------------------
Msrc/filedialog.hpp | 16+++++-----------
Msrc/filesystem.cpp | 44+++++++++++++++++++++-----------------------
Msrc/filesystem.hpp | 2+-
Msrc/import.cpp | 48+++++++++++++++++++++++-------------------------
Msrc/index.cpp | 3+--
Msrc/listview.cpp | 15+++++++++------
Msrc/listview.hpp | 7+++----
Msrc/main.cpp | 55++++++++++++++++++++++++++++---------------------------
Msrc/manager.cpp | 150+++++++++++++++++++++++++++++++++++--------------------------------------------
Msrc/menu.cpp | 20+++++++++++++++-----
Msrc/menu.hpp | 12++++++------
Msrc/obsquery.cpp | 9++++-----
Msrc/progress.cpp | 25+++++++++++++------------
Msrc/progress.hpp | 3+--
Msrc/reapack.cpp | 39++++++++++++++++++---------------------
Msrc/reapack.hpp | 2+-
Msrc/report.cpp | 9++++-----
Msrc/richedit-win32.cpp | 10++++------
Msrc/tabbar.cpp | 4+++-
Msrc/tabbar.hpp | 3+--
Msrc/task.cpp | 2+-
Msrc/thread.cpp | 2+-
Msrc/transaction.cpp | 2+-
Asrc/win32.cpp | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/win32.hpp | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dtest/encoding.cpp | 32--------------------------------
Atest/win32.cpp | 37+++++++++++++++++++++++++++++++++++++
41 files changed, 690 insertions(+), 699 deletions(-)

diff --git a/src/about.cpp b/src/about.cpp @@ -19,7 +19,6 @@ #include "browser.hpp" #include "config.hpp" -#include "encoding.hpp" #include "errors.hpp" #include "filesystem.hpp" #include "index.hpp" @@ -34,10 +33,10 @@ #include "richedit.hpp" #include "tabbar.hpp" #include "transaction.hpp" +#include "win32.hpp" #include <boost/algorithm/string.hpp> #include <iomanip> -#include <sstream> using namespace std; @@ -171,15 +170,14 @@ void About::setDelegate(const DelegatePtr &delegate, const bool focus) void About::setTitle(const string &what) { - auto_char title[255]; - auto_snprintf(title, auto_size(title), - AUTO_STR("About %s"), make_autostring(what).c_str()); - SetWindowText(handle(), title); + char title[255]; + snprintf(title, sizeof(title), "About %s", what.c_str()); + Win32::setWindowText(handle(), title); } void About::setMetadata(const Metadata *metadata, const bool substitution) { - string aboutText = metadata->about(); + string aboutText(metadata->about()); if(substitution) { boost::replace_all(aboutText, "[[REAPACK_VERSION]]", ReaPack::VERSION); @@ -187,7 +185,7 @@ void About::setMetadata(const Metadata *metadata, const bool substitution) } if(m_desc->setRichText(aboutText)) - m_tabs->addTab({AUTO_STR("About"), {m_desc->handle()}}); + m_tabs->addTab({"About", {m_desc->handle()}}); const auto &getLinkControl = [](const Metadata::LinkType type) { switch(type) { @@ -232,7 +230,7 @@ void About::setMetadata(const Metadata *metadata, const bool substitution) void About::setAction(const string &label) { HWND btn = getControl(IDC_ACTION); - SetWindowText(btn, make_autostring(label).c_str()); + Win32::setWindowText(btn, label.c_str()); show(btn); } @@ -244,7 +242,7 @@ void About::selectLink(const int ctrl) m_tabs->setFocus(); if(count == 1) { - openURL(links.front()->url); + Win32::shellExecute(links.front()->url.c_str()); return; } @@ -252,13 +250,13 @@ void About::selectLink(const int ctrl) for(int i = 0; i < count; i++) { const string &name = boost::replace_all_copy(links[i]->name, "&", "&&"); - menu.addAction(make_autostring(name).c_str(), i | (ctrl << 8)); + menu.addAction(name.c_str(), i | (ctrl << 8)); } const int choice = menu.show(getControl(ctrl), handle()); if(choice >> 8 == ctrl) - openURL(links[choice & 0xff]->url); + Win32::shellExecute(links[choice & 0xff]->url.c_str()); } void About::updateList() @@ -291,29 +289,29 @@ void AboutIndexDelegate::init(About *dialog) dialog->setMetadata(m_index->metadata(), m_index->name() == "ReaPack"); dialog->setAction("Install/update " + m_index->name()); - dialog->tabs()->addTab({AUTO_STR("Packages"), + dialog->tabs()->addTab({"Packages", {dialog->menu()->handle(), dialog->list()->handle()}}); - dialog->tabs()->addTab({AUTO_STR("Installed Files"), + dialog->tabs()->addTab({"Installed Files", {dialog->getControl(IDC_REPORT)}}); - dialog->menu()->addColumn({AUTO_STR("Category"), 142}); + dialog->menu()->addColumn({"Category", 142}); dialog->menu()->reserveRows(m_index->categories().size() + 1); - dialog->menu()->createRow()->setCell(0, AUTO_STR("<All Packages>")); + dialog->menu()->createRow()->setCell(0, "<All Packages>"); for(const Category *cat : m_index->categories()) - dialog->menu()->createRow()->setCell(0, make_autostring(cat->name())); + dialog->menu()->createRow()->setCell(0, cat->name()); - dialog->list()->addColumn({AUTO_STR("Package"), 382}); - dialog->list()->addColumn({AUTO_STR("Version"), 80, 0, ListView::VersionType}); - dialog->list()->addColumn({AUTO_STR("Author"), 90}); + dialog->list()->addColumn({"Package", 382}); + dialog->list()->addColumn({"Version", 80, 0, ListView::VersionType}); + dialog->list()->addColumn({"Author", 90}); initInstalledFiles(); } void AboutIndexDelegate::initInstalledFiles() { - HWND report = m_dialog->getControl(IDC_REPORT); + const HWND report = m_dialog->getControl(IDC_REPORT); set<Registry::File> allFiles; @@ -325,24 +323,21 @@ void AboutIndexDelegate::initInstalledFiles() } } catch(const reapack_error &e) { - const auto_string &desc = make_autostring(e.what()); - auto_char msg[255]; - auto_snprintf(msg, auto_size(msg), - AUTO_STR("The file list is currently unavailable.\x20") - AUTO_STR("Retry later when all installation task are completed.\r\n") - AUTO_STR("\r\nError description: %s"), - desc.c_str()); - SetWindowText(report, msg); + char msg[255]; + snprintf(msg, sizeof(msg), + "The file list is currently unavailable.\x20" + "Retry later when all installation task are completed.\r\n" + "\r\nError description: %s", e.what()); + Win32::setWindowText(report, msg); return; } if(allFiles.empty()) { - SetWindowText(report, - AUTO_STR( - "This repository does not own any file on your computer at this time.\r\n") + Win32::setWindowText(report, + "This repository does not own any file on your computer at this time.\r\n" - AUTO_STR("It is either not yet installed or it does not provide ") - AUTO_STR("any package compatible with your system.")); + "It is either not yet installed or it does not provide " + "any package compatible with your system."); } else { stringstream stream; @@ -354,7 +349,7 @@ void AboutIndexDelegate::initInstalledFiles() stream << "\r\n"; } - SetWindowText(report, make_autostring(stream.str()).c_str()); + Win32::setWindowText(report, stream.str().c_str()); } } @@ -377,9 +372,9 @@ void AboutIndexDelegate::updateList(const int index) const Version *lastVer = pkg->lastVersion(); auto row = m_dialog->list()->createRow((void *)pkg); - row->setCell(c++, make_autostring(pkg->displayName())); - row->setCell(c++, make_autostring(lastVer->name().toString()), (void *)&lastVer->name()); - row->setCell(c++, make_autostring(lastVer->displayAuthor())); + row->setCell(c++, pkg->displayName()); + row->setCell(c++, lastVer->name().toString(), (void *)&lastVer->name()); + row->setCell(c++, lastVer->displayAuthor()); } } @@ -388,8 +383,8 @@ bool AboutIndexDelegate::fillContextMenu(Menu &menu, const int index) const if(index < 0) return false; - menu.addAction(AUTO_STR("Find in the &browser"), ACTION_FIND_IN_BROWSER); - menu.addAction(AUTO_STR("About this &package"), ACTION_ABOUT_PKG); + menu.addAction("Find in the &browser", ACTION_FIND_IN_BROWSER); + menu.addAction("About this &package", ACTION_ABOUT_PKG); return true; } @@ -458,8 +453,8 @@ void AboutIndexDelegate::install() enum { INSTALL_ALL = 80, UPDATE_ONLY }; Menu menu; - menu.addAction(AUTO_STR("Install all packages in this repository"), INSTALL_ALL); - menu.addAction(AUTO_STR("Update installed packages only"), UPDATE_ONLY); + menu.addAction("Install all packages in this repository", INSTALL_ALL); + menu.addAction("Update installed packages only", UPDATE_ONLY); const int choice = menu.show(m_dialog->getControl(IDC_ACTION), m_dialog->handle()); @@ -470,9 +465,9 @@ void AboutIndexDelegate::install() if(!remote) { // In case the user uninstalled the repository while this dialog was opened - MessageBox(m_dialog->handle(), - AUTO_STR("This repository cannot be found in your current configuration."), - AUTO_STR("ReaPack"), MB_OK); + Win32::messageBox(m_dialog->handle(), + "This repository cannot be found in your current configuration.", + "ReaPack", MB_OK); return; } @@ -480,12 +475,12 @@ void AboutIndexDelegate::install() if(choice == INSTALL_ALL && boost::logic::indeterminate(remote.autoInstall()) && !installOpts.autoInstall) { - const int btn = MessageBox(m_dialog->handle(), - AUTO_STR("Do you want ReaPack to install new packages from this repository") - AUTO_STR(" when synchronizing in the future?\r\n\r\nThis setting can also be") - AUTO_STR(" customized globally or on a per-repository basis in") - AUTO_STR(" ReaPack > Manage repositories."), - AUTO_STR("Install all packages in this repository"), MB_YESNOCANCEL); + const int btn = Win32::messageBox(m_dialog->handle(), + "Do you want ReaPack to install new packages from this repository" + " when synchronizing in the future?\r\n\r\nThis setting can also be" + " customized globally or on a per-repository basis in" + " ReaPack > Manage repositories.", + "Install all packages in this repository", MB_YESNOCANCEL); switch(btn) { case IDYES: @@ -523,21 +518,21 @@ void AboutPackageDelegate::init(About *dialog) dialog->setMetadata(m_package->metadata()); dialog->setAction("About " + m_index->name()); - dialog->tabs()->addTab({AUTO_STR("History"), + dialog->tabs()->addTab({"History", {dialog->menu()->handle(), dialog->getControl(IDC_CHANGELOG)}}); - dialog->tabs()->addTab({AUTO_STR("Contents"), + dialog->tabs()->addTab({"Contents", {dialog->menu()->handle(), dialog->list()->handle()}}); - dialog->menu()->addColumn({AUTO_STR("Version"), 142, 0, ListView::VersionType}); + dialog->menu()->addColumn({"Version", 142, 0, ListView::VersionType}); - dialog->list()->addColumn({AUTO_STR("File"), 474}); - dialog->list()->addColumn({AUTO_STR("Action List"), 84}); + dialog->list()->addColumn({"File", 474}); + dialog->list()->addColumn({"Action List", 84}); dialog->menu()->reserveRows(m_package->versions().size()); for(const Version *ver : m_package->versions()) { auto row = dialog->menu()->createRow(); - row->setCell(0, make_autostring(ver->name().toString()), (void *)&ver->name()); + row->setCell(0, ver->name().toString(), (void *)&ver->name()); if(m_current == ver->name()) dialog->menu()->select(row->index()); @@ -563,10 +558,10 @@ void AboutPackageDelegate::updateList(const int index) const Version *ver = m_package->version(index); OutputStream stream; stream << *ver; - SetWindowText(m_dialog->getControl(IDC_CHANGELOG), - make_autostring(stream.str()).c_str()); + Win32::setWindowText(m_dialog->getControl(IDC_CHANGELOG), stream.str().c_str()); m_dialog->list()->reserveRows(ver->sources().size()); + for(const Source *src : ver->sources()) { int sections = src->sections(); string actionList; @@ -593,8 +588,8 @@ void AboutPackageDelegate::updateList(const int index) int c = 0; auto row = m_dialog->list()->createRow((void *)src); - row->setCell(c++, make_autostring(src->targetPath().join())); - row->setCell(c++, make_autostring(actionList)); + row->setCell(c++, src->targetPath().join()); + row->setCell(c++, actionList); } } @@ -605,9 +600,9 @@ bool AboutPackageDelegate::fillContextMenu(Menu &menu, const int index) const auto src = (const Source *)m_dialog->list()->row(index)->userData; - menu.addAction(AUTO_STR("Copy source URL"), ACTION_COPY_URL); + menu.addAction("Copy source URL", ACTION_COPY_URL); menu.setEnabled(m_current.size() > 0 && FS::exists(src->targetPath()), - menu.addAction(AUTO_STR("Locate in explorer/finder"), ACTION_LOCATE)); + menu.addAction("Locate in explorer/finder", ACTION_LOCATE)); return true; } @@ -651,11 +646,10 @@ void AboutPackageDelegate::locate() if(!FS::exists(path)) return; - string arg = "/select,\""; + string arg("/select,\""); arg += Path::prefixRoot(path).join(); arg += '"'; - ShellExecute(nullptr, AUTO_STR("open"), AUTO_STR("explorer.exe"), - make_autostring(arg).c_str(), nullptr, SW_SHOW); + Win32::shellExecute("explorer.exe", arg.c_str()); } } diff --git a/src/archive.cpp b/src/archive.cpp @@ -24,6 +24,7 @@ #include "path.hpp" #include "reapack.hpp" #include "transaction.hpp" +#include "win32.hpp" #include <boost/format.hpp> #include <fstream> @@ -34,10 +35,10 @@ #include <zlib/unzip.h> #include <zlib/ioapi.h> -using namespace boost; +using boost::format; using namespace std; -static const Path ARCHIVE_TOC = Path("toc"); +static const Path ARCHIVE_TOC("toc"); static const size_t BUFFER_SIZE = 4096; #ifdef _WIN32 @@ -54,8 +55,10 @@ static void *wide_fopen(voidpf, const void *filename, int mode) FILE *file = nullptr; - if(filename && fopen_mode) - _wfopen_s(&file, static_cast<const wchar_t *>(filename), fopen_mode); + if(filename && fopen_mode) { + const auto &&wideFilename = Win32::widen(static_cast<const char *>(filename)); + _wfopen_s(&file, wideFilename.c_str(), fopen_mode); + } return file; } @@ -71,7 +74,7 @@ struct ImportArchive { IndexPtr m_lastIndex; }; -void Archive::import(const auto_string &path) +void Archive::import(const string &path) { ImportArchive state{make_shared<ArchiveReader>(path), &g_reapack->config()->remotes}; @@ -105,7 +108,7 @@ void Archive::import(const auto_string &path) } } catch(const reapack_error &e) { - state.m_tx->receipt()->addError({e.what(), from_autostring(path)}); + state.m_tx->receipt()->addError({e.what(), path}); } } @@ -152,15 +155,15 @@ void ImportArchive::importPackage(const string &data) const Version *ver = pkg ? pkg->findVersion(versionName) : nullptr; if(!ver) { - throw reapack_error(format("%s/%s/%s v%s cannot be found or is" - " incompatible with your operating system.") + throw reapack_error(format( + "%s/%s/%s v%s cannot be found or is incompatible with your operating system.") % m_lastIndex->name() % categoryName % packageName % versionName); } m_tx->install(ver, pinned, m_reader); } -ArchiveReader::ArchiveReader(const auto_string &path) +ArchiveReader::ArchiveReader(const string &path) { zlib_filefunc64_def filefunc; fill_fopen64_filefunc(&filefunc); @@ -168,10 +171,10 @@ ArchiveReader::ArchiveReader(const auto_string &path) filefunc.zopen64_file = wide_fopen; #endif - m_zip = unzOpen2_64(reinterpret_cast<const char *>(path.c_str()), &filefunc); + m_zip = unzOpen2_64(path.c_str(), &filefunc); if(!m_zip) - throw reapack_error(FS::lastError().c_str()); + throw reapack_error(FS::lastError()); } ArchiveReader::~ArchiveReader() @@ -241,7 +244,7 @@ bool FileExtractor::run() return true; } -size_t Archive::create(const auto_string &path, vector<string> *errors, +size_t Archive::create(const string &path, vector<string> *errors, ThreadPool *pool) { size_t count = 0; @@ -296,7 +299,7 @@ size_t Archive::create(const auto_string &path, vector<string> *errors, return count; } -ArchiveWriter::ArchiveWriter(const auto_string &path) +ArchiveWriter::ArchiveWriter(const string &path) { zlib_filefunc64_def filefunc; fill_fopen64_filefunc(&filefunc); @@ -304,11 +307,10 @@ ArchiveWriter::ArchiveWriter(const auto_string &path) filefunc.zopen64_file = wide_fopen; #endif - m_zip = zipOpen2_64(reinterpret_cast<const char *>(path.c_str()), - APPEND_STATUS_CREATE, nullptr, &filefunc); + m_zip = zipOpen2_64(path.c_str(), APPEND_STATUS_CREATE, nullptr, &filefunc); if(!m_zip) - throw reapack_error(FS::lastError().c_str()); + throw reapack_error(FS::lastError()); } ArchiveWriter::~ArchiveWriter() diff --git a/src/archive.hpp b/src/archive.hpp @@ -18,7 +18,6 @@ #ifndef REAPACK_ARCHIVE_HPP #define REAPACK_ARCHIVE_HPP -#include "encoding.hpp" #include "path.hpp" #include "thread.hpp" @@ -27,14 +26,13 @@ class ThreadPool; typedef void *zipFile; namespace Archive { - void import(const auto_string &path); - size_t create(const auto_string &path, - std::vector<std::string> *errors, ThreadPool *pool); + void import(const std::string &path); + size_t create(const std::string &path, std::vector<std::string> *errors, ThreadPool *pool); }; class ArchiveReader { public: - ArchiveReader(const auto_string &path); + ArchiveReader(const std::string &path); ~ArchiveReader(); int extractFile(const Path &); int extractFile(const Path &, std::ostream &) noexcept; @@ -47,7 +45,7 @@ typedef std::shared_ptr<ArchiveReader> ArchiveReaderPtr; class ArchiveWriter { public: - ArchiveWriter(const auto_string &path); + ArchiveWriter(const std::string &path); ~ArchiveWriter(); int addFile(const Path &fn); int addFile(const Path &fn, std::istream &) noexcept; diff --git a/src/browser.cpp b/src/browser.cpp @@ -20,7 +20,6 @@ #include "about.hpp" #include "browser_entry.hpp" #include "config.hpp" -#include "encoding.hpp" #include "errors.hpp" #include "index.hpp" #include "listview.hpp" @@ -28,6 +27,7 @@ #include "reapack.hpp" #include "resource.hpp" #include "transaction.hpp" +#include "win32.hpp" using namespace std; @@ -50,23 +50,23 @@ void Browser::onInit() disable(m_actionsBtn); // don't forget to update order of enum View in header file - SendMessage(m_view, CB_ADDSTRING, 0, (LPARAM)AUTO_STR("All")); - SendMessage(m_view, CB_ADDSTRING, 0, (LPARAM)AUTO_STR("Queued")); - SendMessage(m_view, CB_ADDSTRING, 0, (LPARAM)AUTO_STR("Installed")); - SendMessage(m_view, CB_ADDSTRING, 0, (LPARAM)AUTO_STR("Out of date")); - SendMessage(m_view, CB_ADDSTRING, 0, (LPARAM)AUTO_STR("Obsolete")); - SendMessage(m_view, CB_ADDSTRING, 0, (LPARAM)AUTO_STR("Uninstalled")); + SendMessage(m_view, CB_ADDSTRING, 0, (LPARAM)L("All")); + SendMessage(m_view, CB_ADDSTRING, 0, (LPARAM)L("Queued")); + SendMessage(m_view, CB_ADDSTRING, 0, (LPARAM)L("Installed")); + SendMessage(m_view, CB_ADDSTRING, 0, (LPARAM)L("Out of date")); + SendMessage(m_view, CB_ADDSTRING, 0, (LPARAM)L("Obsolete")); + SendMessage(m_view, CB_ADDSTRING, 0, (LPARAM)L("Uninstalled")); SendMessage(m_view, CB_SETCURSEL, 0, 0); m_list = createControl<ListView>(IDC_LIST, ListView::Columns{ - {AUTO_STR("Status"), 23, ListView::NoLabelFlag}, - {AUTO_STR("Package"), 345}, - {AUTO_STR("Category"), 105}, - {AUTO_STR("Version"), 55, 0, ListView::VersionType}, - {AUTO_STR("Author"), 95}, - {AUTO_STR("Type"), 70}, - {AUTO_STR("Repository"), 120, ListView::CollapseFlag}, - {AUTO_STR("Last Update"), 105, 0, ListView::TimeType}, + {"Status", 23, ListView::NoLabelFlag}, + {"Package", 345}, + {"Category", 105}, + {"Version", 55, 0, ListView::VersionType}, + {"Author", 95}, + {"Type", 70}, + {"Repository", 120, ListView::CollapseFlag}, + {"Last Update", 105, 0, ListView::TimeType}, }); m_list->onActivate([=] { aboutPackage(m_list->itemUnderMouse()); }); @@ -249,8 +249,8 @@ bool Browser::fillContextMenu(Menu &menu, const int index) if(!menu.empty()) menu.addSeparator(); - menu.addAction(AUTO_STR("&Select all"), IDC_SELECT); - menu.addAction(AUTO_STR("&Unselect all"), IDC_UNSELECT); + menu.addAction("&Select all", IDC_SELECT); + menu.addAction("&Unselect all", IDC_UNSELECT); return true; } @@ -260,14 +260,14 @@ void Browser::fillMenu(Menu &menu) const Entry *entry = getEntry(m_currentIndex); if(m_list->selectionSize() > 1) { - menu.addAction(AUTO_STR("&Install/update selection"), ACTION_LATEST_ALL); - menu.addAction(AUTO_STR("&Reinstall selection"), ACTION_REINSTALL_ALL); - menu.addAction(AUTO_STR("&Uninstall selection"), ACTION_UNINSTALL_ALL); - menu.addAction(AUTO_STR("&Clear queued actions"), ACTION_RESET_ALL); + menu.addAction("&Install/update selection", ACTION_LATEST_ALL); + menu.addAction("&Reinstall selection", ACTION_REINSTALL_ALL); + menu.addAction("&Uninstall selection", ACTION_UNINSTALL_ALL); + menu.addAction("&Clear queued actions", ACTION_RESET_ALL); menu.addSeparator(); if(entry) { - Menu pkgMenu = menu.addMenu(AUTO_STR("Package under cursor")); + Menu pkgMenu = menu.addMenu("Package under cursor"); entry->fillMenu(pkgMenu); } } @@ -277,32 +277,32 @@ void Browser::fillMenu(Menu &menu) void Browser::updateDisplayLabel() { - auto_char btnLabel[32]; - auto_snprintf(btnLabel, auto_size(btnLabel), AUTO_STR("%d/%zu package%s..."), + char btnLabel[32]; + snprintf(btnLabel, sizeof(btnLabel), "%d/%zu package%s...", m_list->rowCount(), m_entries.size(), - m_entries.size() == 1 ? AUTO_STR("") : AUTO_STR("s")); + m_entries.size() == 1 ? "" : "s"); - SetWindowText(m_displayBtn, btnLabel); + Win32::setWindowText(m_displayBtn, btnLabel); } void Browser::displayButton() { - static map<const auto_char *, Package::Type> types = { - {AUTO_STR("&Scripts"), Package::ScriptType}, - {AUTO_STR("&Effects"), Package::EffectType}, - {AUTO_STR("E&xtensions"), Package::ExtensionType}, - {AUTO_STR("&Themes"), Package::ThemeType}, - {AUTO_STR("&Language Packs"), Package::LangPackType}, - {AUTO_STR("&Web Interfaces"), Package::WebInterfaceType}, - {AUTO_STR("&Project Templates"), Package::ProjectTemplateType}, - {AUTO_STR("&Track Templates"), Package::TrackTemplateType}, - {AUTO_STR("&MIDI Note Names"), Package::MIDINoteNamesType}, - {AUTO_STR("&Other packages"), Package::UnknownType}, + static map<const char *, Package::Type> types = { + {"&Scripts", Package::ScriptType}, + {"&Effects", Package::EffectType}, + {"E&xtensions", Package::ExtensionType}, + {"&Themes", Package::ThemeType}, + {"&Language Packs", Package::LangPackType}, + {"&Web Interfaces", Package::WebInterfaceType}, + {"&Project Templates", Package::ProjectTemplateType}, + {"&Track Templates", Package::TrackTemplateType}, + {"&MIDI Note Names", Package::MIDINoteNamesType}, + {"&Other packages", Package::UnknownType}, }; Menu menu; - auto index = menu.addAction(AUTO_STR("&All packages"), ACTION_FILTERTYPE); + auto index = menu.addAction("&All packages", ACTION_FILTERTYPE); if(!m_typeFilter) menu.checkRadio(index); @@ -316,8 +316,8 @@ void Browser::displayButton() menu.addSeparator(); - menu.addAction(AUTO_STR("&Refresh repositories"), ACTION_REFRESH); - menu.addAction(AUTO_STR("&Manage repositories..."), ACTION_MANAGE); + menu.addAction("&Refresh repositories", ACTION_REFRESH); + menu.addAction("&Manage repositories...", ACTION_MANAGE); menu.show(m_displayBtn, handle()); } @@ -360,7 +360,7 @@ void Browser::updateFilter() { stopTimer(TIMER_FILTER); - const string &filter = getText(m_filterHandle); + const string &filter = Win32::getWindowText(m_filterHandle); if(m_filter != filter) { m_filter = filter; @@ -404,10 +404,9 @@ void Browser::refresh(const bool stale) if(!isVisible() || stale) { show(); - MessageBox(handle(), AUTO_STR("No repository enabled!\r\n") - AUTO_STR("Enable or import repositories from ") - AUTO_STR("Extensions > ReaPack > Manage repositories."), - AUTO_STR("Browse packages"), MB_OK); + Win32::messageBox(handle(), "No repository enabled!\r\n" + "Enable or import repositories from Extensions > ReaPack > Manage repositories.", + "Browse packages", MB_OK); } populate({}); @@ -434,7 +433,7 @@ void Browser::refresh(const bool stale) void Browser::setFilter(const string &newFilter) { - SetWindowText(m_filterHandle, make_autostring(newFilter).c_str()); + Win32::setWindowText(m_filterHandle, newFilter.c_str()); updateFilter(); // don't wait for the timer, update now! SetFocus(m_filterHandle); } @@ -465,14 +464,12 @@ void Browser::populate(const vector<IndexPtr> &indexes) fillList(); } catch(const reapack_error &e) { - const auto_string &desc = make_autostring(e.what()); - auto_char msg[255]; - auto_snprintf(msg, auto_size(msg), - AUTO_STR("ReaPack could not read from the local package registry.\r\n") - AUTO_STR("Retry later once all installation task are completed.\r\n") - AUTO_STR("\r\nError description: %s"), - desc.c_str()); - MessageBox(handle(), msg, AUTO_STR("ReaPack"), MB_OK); + char msg[255]; + snprintf(msg, sizeof(msg), + "ReaPack could not read from the local package registry.\r\n" + "Retry later once all installation task are completed.\r\n" + "\r\nError description: %s", e.what()); + Win32::messageBox(handle(), msg, "ReaPack", MB_OK); } if(!isVisible()) @@ -617,12 +614,11 @@ void Browser::installLatestAll() const bool isEverything = (size_t)m_list->selectionSize() == m_entries.size(); if(isEverything && !installOpts.autoInstall) { - const int btn = MessageBox(handle(), - AUTO_STR("Do you want ReaPack to install new packages automatically when") - AUTO_STR(" synchronizing in the future?\r\n\r\nThis setting can also be") - AUTO_STR(" customized globally or on a per-repository basis in") - AUTO_STR(" ReaPack > Manage repositories."), - AUTO_STR("Install every available packages"), MB_YESNOCANCEL); + const int btn = Win32::messageBox(handle(), "Do you want ReaPack to install new packages" + " automatically when synchronizing in the future?\r\n\r\nThis setting" + " can also be customized globally or on a per-repository basis in" + " ReaPack > Manage repositories.", + "Install every available packages", MB_YESNOCANCEL); switch(btn) { case IDYES: @@ -753,7 +749,7 @@ void Browser::updateAction(const int index) updateDisplayLabel(); } else - m_list->row(index)->setCell(0, make_autostring(entry->displayState())); + m_list->row(index)->setCell(0, entry->displayState()); if(m_actions.empty()) disable(m_applyBtn); @@ -798,15 +794,13 @@ bool Browser::confirm() const if(!count) return true; - auto_char msg[255]; - auto_snprintf(msg, auto_size(msg), - AUTO_STR("Are you sure to uninstall %zu package%s?\r\nThe files and settings will be permanently deleted from this computer."), - count, count == 1 ? AUTO_STR("") : AUTO_STR("s")); + char msg[255]; + snprintf(msg, sizeof(msg), + "Are you sure to uninstall %zu package%s?\r\nThe files and settings will" + " be permanently deleted from this computer.", + count, count == 1 ? "" : "s"); - const auto_char *title = AUTO_STR("ReaPack Query"); - const int btn = MessageBox(handle(), msg, title, MB_YESNO); - - return btn == IDYES; + return IDYES == Win32::messageBox(handle(), msg, "ReaPack Query", MB_YESNO); } bool Browser::apply() diff --git a/src/browser_entry.cpp b/src/browser_entry.cpp @@ -156,34 +156,32 @@ void Browser::Entry::updateRow(const ListView::RowPtr &row) const int c = 0; const Time *time = lastUpdate(); - row->setCell(c++, make_autostring(displayState())); - row->setCell(c++, make_autostring(displayName())); - row->setCell(c++, make_autostring(categoryName())); - row->setCell(c++, make_autostring(displayVersion()), (void *)sortVersion()); - row->setCell(c++, make_autostring(displayAuthor())); - row->setCell(c++, make_autostring(displayType())); - row->setCell(c++, make_autostring(indexName())); - row->setCell(c++, time ? make_autostring(time->toString()) : auto_string(), (void *)time); + row->setCell(c++, displayState()); + row->setCell(c++, displayName()); + row->setCell(c++, categoryName()); + row->setCell(c++, displayVersion(), (void *)sortVersion()); + row->setCell(c++, displayAuthor()); + row->setCell(c++, displayType()); + row->setCell(c++, indexName()); + row->setCell(c++, time ? time->toString() : string(), (void *)time); } void Browser::Entry::fillMenu(Menu &menu) const { if(test(InstalledFlag)) { if(test(OutOfDateFlag)) { - auto_char installLabel[32]; - auto_snprintf(installLabel, auto_size(installLabel), - AUTO_STR("U&pdate to v%s"), - make_autostring(latest->name().toString()).c_str()); + char installLabel[32]; + snprintf(installLabel, sizeof(installLabel), + "U&pdate to v%s", latest->name().toString().c_str()); const UINT actionIndex = menu.addAction(installLabel, ACTION_LATEST); if(target && *target == latest) menu.check(actionIndex); } - auto_char reinstallLabel[32]; - auto_snprintf(reinstallLabel, auto_size(reinstallLabel), - AUTO_STR("&Reinstall v%s"), - make_autostring(regEntry.version.toString()).c_str()); + char reinstallLabel[32]; + snprintf(reinstallLabel, sizeof(reinstallLabel), + "&Reinstall v%s", regEntry.version.toString().c_str()); const UINT actionIndex = menu.addAction(reinstallLabel, ACTION_REINSTALL); if(!current || test(ObsoleteFlag)) @@ -192,17 +190,16 @@ void Browser::Entry::fillMenu(Menu &menu) const menu.check(actionIndex); } else { - auto_char installLabel[32]; - auto_snprintf(installLabel, auto_size(installLabel), - AUTO_STR("&Install v%s"), - make_autostring(latest->name().toString()).c_str()); + char installLabel[32]; + snprintf(installLabel, sizeof(installLabel), + "&Install v%s", latest->name().toString().c_str()); const UINT actionIndex = menu.addAction(installLabel, ACTION_LATEST); if(target && *target == latest) menu.check(actionIndex); } - Menu versionMenu = menu.addMenu(AUTO_STR("Versions")); + Menu versionMenu = menu.addMenu("Versions"); const UINT versionMenuIndex = menu.size() - 1; if(test(ObsoleteFlag)) menu.disable(versionMenuIndex); @@ -211,8 +208,7 @@ void Browser::Entry::fillMenu(Menu &menu) const int verIndex = (int)versions.size(); for(const Version *ver : versions | boost::adaptors::reversed) { const UINT actionIndex = versionMenu.addAction( - make_autostring(ver->name().toString()).c_str(), - --verIndex | (ACTION_VERSION << 8)); + ver->name().toString().c_str(), --verIndex | (ACTION_VERSION << 8)); if(target ? *target == ver : ver == current) { if(target && ver != latest) @@ -223,15 +219,13 @@ void Browser::Entry::fillMenu(Menu &menu) const } } - const UINT pinIndex = menu.addAction( - AUTO_STR("&Pin current version"), ACTION_PIN); + const UINT pinIndex = menu.addAction("&Pin current version", ACTION_PIN); if(!canPin()) menu.disable(pinIndex); if(pin.value_or(regEntry.pinned)) menu.check(pinIndex); - const UINT uninstallIndex = - menu.addAction(AUTO_STR("&Uninstall"), ACTION_UNINSTALL); + const UINT uninstallIndex = menu.addAction("&Uninstall", ACTION_UNINSTALL); if(!test(InstalledFlag) || remote().isProtected()) menu.disable(uninstallIndex); else if(target && *target == nullptr) @@ -240,12 +234,10 @@ void Browser::Entry::fillMenu(Menu &menu) const menu.addSeparator(); menu.setEnabled(!test(ObsoleteFlag), - menu.addAction(AUTO_STR("About this &package"), ACTION_ABOUT_PKG)); + menu.addAction("About this &package", ACTION_ABOUT_PKG)); - auto_char aboutLabel[64]; - const auto_string &name = make_autostring(indexName()); - auto_snprintf(aboutLabel, auto_size(aboutLabel), - AUTO_STR("&About %s"), name.c_str()); + char aboutLabel[64]; + snprintf(aboutLabel, sizeof(aboutLabel), "&About %s", indexName().c_str()); menu.addAction(aboutLabel, ACTION_ABOUT_REMOTE); } diff --git a/src/config.cpp b/src/config.cpp @@ -18,6 +18,7 @@ #include "config.hpp" #include "path.hpp" +#include "win32.hpp" #ifdef _WIN32 # include <windows.h> @@ -27,37 +28,35 @@ using namespace std; -static const auto_char *GENERAL_GRP = AUTO_STR("general"); -static const auto_char *VERSION_KEY = AUTO_STR("version"); +static const char *GENERAL_GRP = "general"; +static const char *VERSION_KEY = "version"; -static const auto_char *INSTALL_GRP = AUTO_STR("install"); -static const auto_char *AUTOINSTALL_KEY = AUTO_STR("autoinstall"); -static const auto_char *PRERELEASES_KEY = AUTO_STR("prereleases"); -static const auto_char *PROMPTOBSOLETE_KEY = AUTO_STR("promptobsolete"); +static const char *INSTALL_GRP = "install"; +static const char *AUTOINSTALL_KEY = "autoinstall"; +static const char *PRERELEASES_KEY = "prereleases"; +static const char *PROMPTOBSOLETE_KEY = "promptobsolete"; -static const auto_char *ABOUT_GRP = AUTO_STR("about"); -static const auto_char *MANAGER_GRP = AUTO_STR("manager"); +static const char *ABOUT_GRP = "about"; +static const char *MANAGER_GRP = "manager"; -static const auto_char *BROWSER_GRP = AUTO_STR("browser"); -static const auto_char *STATE_KEY = AUTO_STR("state"); +static const char *BROWSER_GRP = "browser"; +static const char *STATE_KEY = "state"; -static const auto_char *NETWORK_GRP = AUTO_STR("network"); -static const auto_char *PROXY_KEY = AUTO_STR("proxy"); -static const auto_char *VERIFYPEER_KEY = AUTO_STR("verifypeer"); -static const auto_char *STALETHRSH_KEY = AUTO_STR("stalethreshold"); +static const char *NETWORK_GRP = "network"; +static const char *PROXY_KEY = "proxy"; +static const char *VERIFYPEER_KEY = "verifypeer"; +static const char *STALETHRSH_KEY = "stalethreshold"; -static const auto_char *SIZE_KEY = AUTO_STR("size"); +static const char *SIZE_KEY = "size"; -static const auto_char *REMOTES_GRP = AUTO_STR("remotes"); -static const auto_char *REMOTE_KEY = AUTO_STR("remote"); +static const char *REMOTES_GRP = "remotes"; +static const char *REMOTE_KEY = "remote"; -static auto_string ArrayKey(const auto_string &key, const unsigned int i) +inline static string nKey(const char *key, const unsigned int i) { - return key + to_autostring(i); + return key + to_string(i); } -static const int BUFFER_SIZE = 2083; - Config::Config() : m_isFirstRun(false), m_version(0), m_remotesIniSize(0) { @@ -133,7 +132,7 @@ void Config::migrate() void Config::read(const Path &path) { - m_path = make_autostring(path.join()); + m_path = path.join(); install.autoInstall = getBool(INSTALL_GRP, AUTOINSTALL_KEY, install.autoInstall); install.bleedingEdge = getBool(INSTALL_GRP, PRERELEASES_KEY, install.bleedingEdge); @@ -178,7 +177,7 @@ void Config::readRemotes() m_remotesIniSize = getUInt(REMOTES_GRP, SIZE_KEY); for(unsigned int i = 0; i < m_remotesIniSize; i++) { - const string data = getString(REMOTES_GRP, ArrayKey(REMOTE_KEY, i)); + const string data = getString(REMOTES_GRP, nKey(REMOTE_KEY, i).c_str()); remotes.add(Remote::fromString(data)); } @@ -190,56 +189,47 @@ void Config::writeRemotes() unsigned int i = 0; for(auto it = remotes.begin(); it != remotes.end(); it++, i++) - setString(REMOTES_GRP, ArrayKey(REMOTE_KEY, i), it->toString()); + setString(REMOTES_GRP, nKey(REMOTE_KEY, i).c_str(), it->toString()); cleanupArray(REMOTES_GRP, REMOTE_KEY, i, m_remotesIniSize); setUInt(REMOTES_GRP, SIZE_KEY, m_remotesIniSize = i); } -string Config::getString(const auto_char *group, - const auto_string &key, const string &fallback) const +string Config::getString(const char *group, const char *key, const string &fallback) const { - auto_char buffer[BUFFER_SIZE]; - GetPrivateProfileString(group, key.c_str(), make_autostring(fallback).c_str(), - buffer, sizeof(buffer), m_path.c_str()); - - return from_autostring(buffer); + return Win32::getPrivateProfileString(group, key, fallback.c_str(), m_path.c_str()); } -void Config::setString(const auto_char *group, - const auto_string &key, const string &val) const +void Config::setString(const char *group, const char *key, const string &val) const { - WritePrivateProfileString(group, key.c_str(), - make_autostring(val).c_str(), m_path.c_str()); + Win32::writePrivateProfileString(group, key, val.c_str(), m_path.c_str()); } -unsigned int Config::getUInt(const auto_char *group, - const auto_string &key, const unsigned int fallback) const +unsigned int Config::getUInt(const char *group, + const char *key, const unsigned int fallback) const { - return GetPrivateProfileInt(group, key.c_str(), fallback, m_path.c_str()); + return Win32::getPrivateProfileInt(group, key, fallback, m_path.c_str()); } -bool Config::getBool(const auto_char *group, - const auto_string &key, const bool fallback) const +bool Config::getBool(const char *group, const char *key, const bool fallback) const { return getUInt(group, key, fallback) > 0; } -void Config::setUInt(const auto_char *group, const auto_string &key, - const unsigned int val) const +void Config::setUInt(const char *group, const char *key, const unsigned int val) const { setString(group, key, to_string(val)); } -void Config::deleteKey(const auto_char *group, const auto_string &key) const +void Config::deleteKey(const char *group, const char *key) const { - WritePrivateProfileString(group, key.c_str(), 0, m_path.c_str()); + Win32::writePrivateProfileString(group, key, nullptr, m_path.c_str()); } -void Config::cleanupArray(const auto_char *group, const auto_string &key, +void Config::cleanupArray(const char *group, const char *key, const unsigned int begin, const unsigned int end) const { for(unsigned int i = begin; i < end; i++) - deleteKey(group, ArrayKey(key, i)); + deleteKey(group, nKey(key, i).c_str()); } diff --git a/src/config.hpp b/src/config.hpp @@ -20,7 +20,6 @@ #include <string> -#include "encoding.hpp" #include "remote.hpp" class Path; @@ -67,24 +66,19 @@ public: RemoteList remotes; private: - std::string getString(const auto_char *grp, - const auto_string &key, const std::string &fallback = {}) const; - void setString(const auto_char *grp, - const auto_string &key, const std::string &val) const; + std::string getString(const char *g, const char *k, const std::string &fallback = {}) const; + void setString(const char *g, const char *k, const std::string &v) const; - bool getBool(const auto_char *grp, - const auto_string &key, bool fallback = false) const; - unsigned int getUInt(const auto_char *grp, - const auto_string &key, unsigned int fallback = 0) const; - void setUInt(const auto_char *, const auto_string &, unsigned int) const; + bool getBool(const char *g, const char *k, bool fallback = false) const; + unsigned int getUInt(const char *g, const char *k, unsigned int fallback = 0) const; + void setUInt(const char *g, const char *k, unsigned int v) const; - void deleteKey(const auto_char *, const auto_string &) const; - void cleanupArray(const auto_char *, const auto_string &, - unsigned int begin, unsigned int end) const; + void deleteKey(const char *g, const char *k) const; + void cleanupArray(const char *g, const char *k, unsigned int begin, unsigned int end) const; void migrate(); - auto_string m_path; + std::string m_path; bool m_isFirstRun; unsigned int m_version; diff --git a/src/dialog.cpp b/src/dialog.cpp @@ -18,7 +18,6 @@ #include "dialog.hpp" #include "control.hpp" -#include "encoding.hpp" #include <algorithm> #include <boost/range/adaptor/map.hpp> @@ -331,11 +330,11 @@ void Dialog::stopTimer(int id) void Dialog::setClipboard(const string &text) { - const auto_string &data = make_autostring(text); - const size_t length = (data.size() + 1) * sizeof(auto_char); // null terminator + // calculate the size in bytes including the null terminator + const size_t size = (text.size() + 1) * sizeof(char); - HANDLE mem = GlobalAlloc(GMEM_MOVEABLE, length); - memcpy(GlobalLock(mem), data.c_str(), length); + HANDLE mem = GlobalAlloc(GMEM_MOVEABLE, size); + memcpy(GlobalLock(mem), text.c_str(), size); GlobalUnlock(mem); OpenClipboard(m_handle); @@ -354,28 +353,11 @@ void Dialog::setClipboard(const vector<string> &values) setClipboard(boost::algorithm::join(values, "\n")); } -void Dialog::openURL(const string &utf8) -{ - const auto_string &url = make_autostring(utf8); - ShellExecute(nullptr, AUTO_STR("open"), url.c_str(), nullptr, nullptr, SW_SHOW); -} - HWND Dialog::getControl(const int idc) { return GetDlgItem(m_handle, idc); } -string Dialog::getText(HWND handle) -{ - auto_string buffer(4096, 0); - GetWindowText(handle, &buffer[0], (int)buffer.size()); - - // remove extra nulls from the string - buffer.resize(buffer.find(AUTO_STR('\0'))); - - return from_autostring(buffer); -} - void Dialog::setAnchor(HWND handle, const int flags) { const float left = (float)min(1, flags & AnchorLeft); diff --git a/src/dialog.hpp b/src/dialog.hpp @@ -102,9 +102,7 @@ public: void stopTimer(int id); void setClipboard(const std::string &); void setClipboard(const std::vector<std::string> &); - static void openURL(const std::string &url); HWND getControl(int idc); - std::string getText(HWND); void setAnchor(HWND, int flags); void setAnchorPos(HWND, const LONG *left = nullptr, const LONG *top = nullptr, const LONG *right = nullptr, const LONG *bottom = nullptr); diff --git a/src/download.cpp b/src/download.cpp @@ -20,11 +20,8 @@ #include "filesystem.hpp" #include "reapack.hpp" -#include <boost/format.hpp> - #include <reaper_plugin_functions.h> -using boost::format; using namespace std; static const int DOWNLOAD_TIMEOUT = 15; @@ -68,10 +65,11 @@ DownloadContext::DownloadContext() { m_curl = curl_easy_init(); - const auto &userAgent = format("ReaPack/%s REAPER/%s") - % ReaPack::VERSION % GetAppVersion(); + char userAgent[64]; + snprintf(userAgent, sizeof(userAgent), "ReaPack/%s REAPER/%s", + ReaPack::VERSION, GetAppVersion()); - curl_easy_setopt(m_curl, CURLOPT_USERAGENT, userAgent.str().c_str()); + curl_easy_setopt(m_curl, CURLOPT_USERAGENT, userAgent); curl_easy_setopt(m_curl, CURLOPT_LOW_SPEED_LIMIT, 1); curl_easy_setopt(m_curl, CURLOPT_LOW_SPEED_TIME, DOWNLOAD_TIMEOUT); curl_easy_setopt(m_curl, CURLOPT_CONNECTTIMEOUT, DOWNLOAD_TIMEOUT); @@ -142,8 +140,9 @@ bool Download::run() closeStream(); if(res != CURLE_OK) { - const auto &err = format("%s (%d): %s") % curl_easy_strerror(res) % res % errbuf; - setError({err.str(), m_url}); + char err[255]; + snprintf(err, sizeof(err), "%s (%d): %s", curl_easy_strerror(res), res, errbuf); + setError({err, m_url}); return false; } diff --git a/src/download.hpp b/src/download.hpp @@ -22,11 +22,10 @@ #include "path.hpp" #include "thread.hpp" +#include <curl/curl.h> #include <fstream> #include <sstream> -#include <curl/curl.h> - struct DownloadContext { static void GlobalInit(); static void GlobalCleanup(); diff --git a/src/encoding.cpp b/src/encoding.cpp @@ -1,45 +0,0 @@ -/* ReaPack: Package manager for REAPER - * Copyright (C) 2015-2017 Christian Fillion - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "encoding.hpp" - -#ifdef _WIN32 - -auto_string make_autostring(const std::string &input, UINT codepage) -{ - const int size = MultiByteToWideChar(codepage, 0, - &input[0], -1, nullptr, 0) - 1; - - auto_string output(size, 0); - MultiByteToWideChar(codepage, 0, &input[0], -1, &output[0], size); - - return output; -} - -std::string from_autostring(const auto_string &input) -{ - const int size = WideCharToMultiByte(CP_UTF8, 0, - &input[0], -1, nullptr, 0, nullptr, nullptr) - 1; - - std::string output(size, 0); - WideCharToMultiByte(CP_UTF8, 0, - &input[0], -1, &output[0], size, nullptr, nullptr); - - return output; -} - -#endif diff --git a/src/encoding.hpp b/src/encoding.hpp @@ -1,58 +0,0 @@ -/* ReaPack: Package manager for REAPER - * Copyright (C) 2015-2017 Christian Fillion - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef REAPACK_ENCODING_HPP -#define REAPACK_ENCODING_HPP - -// This whole file is a huge hack to support unicode on Windows -// MultiByteToWideChar is required to make file path like -// "C:\Users\Test\Downloads\Новая папка" work on Windows... - -#include <cstdio> -#include <string> - -#ifdef _WIN32 - -#include <windows.h> - -typedef wchar_t auto_char; -typedef std::wstring auto_string; - -#define AUTO_STR(text) L##text -#define to_autostring std::to_wstring -#define auto_snprintf(buf, size, ...) _snwprintf(buf, size - 1, __VA_ARGS__) -auto_string make_autostring(const std::string &, UINT codepage = CP_UTF8); -#define make_autocstring(cstr) make_autostring(cstr).c_str() // temporary string! -std::string from_autostring(const auto_string &); - -#else - -typedef char auto_char; -typedef std::string auto_string; - -#define AUTO_STR(text) text -#define to_autostring std::to_string -#define auto_snprintf snprintf -#define make_autostring(string) (string) -#define make_autocstring(cstr) cstr -#define from_autostring(string) (string) - -#endif - -#define auto_size(buf) (sizeof(buf) / sizeof(auto_char)) - -#endif diff --git a/src/filedialog.cpp b/src/filedialog.cpp @@ -18,54 +18,58 @@ #include "filedialog.hpp" #include "path.hpp" +#include "win32.hpp" #ifndef _WIN32 # include <swell.h> #endif -auto_string FileDialog::getOpenFileName(HWND parent, HINSTANCE instance, - const auto_char *title, const Path &initialDir, - const auto_char *filters, const auto_char *defaultExt) -{ +using namespace std; + #ifdef _WIN32 - const auto_string &dirPath = make_autostring(initialDir.join()); - auto_char path[4096] = {}; +static string getFileName(BOOL(__stdcall *func)(LPOPENFILENAME), + HWND parent, HINSTANCE instance, const char *title, const Path &initialDir, + const Win32::char_type *filters, const Win32::char_type *defaultExt) +{ + const auto &&wideTitle = Win32::widen(title); + const auto &&wideInitialDir = Win32::widen(initialDir.join()); + + wchar_t pathBuffer[4096] = {}; OPENFILENAME of{sizeof(OPENFILENAME), parent, instance}; of.lpstrFilter = filters; - of.lpstrFile = path; - of.nMaxFile = auto_size(path); - of.lpstrInitialDir = dirPath.c_str(); - of.lpstrTitle = title; - of.Flags = OFN_HIDEREADONLY | OFN_EXPLORER | OFN_FILEMUSTEXIST; + of.lpstrFile = pathBuffer; + of.nMaxFile = lengthof(pathBuffer); + of.lpstrInitialDir = wideInitialDir.c_str(); + of.lpstrTitle = wideTitle.c_str(); + of.Flags = OFN_HIDEREADONLY | OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_OVERWRITEPROMPT; of.lpstrDefExt = defaultExt; - return GetOpenFileName(&of) ? path : auto_string(); + return func(&of) ? Win32::narrow(pathBuffer) : string(); +} +#endif + +string FileDialog::getOpenFileName(HWND parent, HINSTANCE instance, + const char *title, const Path &initialDir, + const Win32::char_type *filters, const Win32::char_type *defaultExt) +{ +#ifdef _WIN32 + return getFileName(&GetOpenFileName, parent, instance, + title, initialDir, filters, defaultExt); #else - char *path = BrowseForFiles(title, initialDir.join().c_str(), + const char *path = BrowseForFiles(title, initialDir.join().c_str(), nullptr, false, filters); - return path ? path : auto_string(); + return path ? path : string(); #endif } -auto_string FileDialog::getSaveFileName(HWND parent, HINSTANCE instance, - const auto_char *title, const Path &initialDir, - const auto_char *filters, const auto_char *defaultExt) +string FileDialog::getSaveFileName(HWND parent, HINSTANCE instance, + const char *title, const Path &initialDir, + const Win32::char_type *filters, const Win32::char_type *defaultExt) { #ifdef _WIN32 - const auto_string &dirPath = make_autostring(initialDir.join()); - auto_char path[4096] = {}; - - OPENFILENAME of{sizeof(OPENFILENAME), parent, instance}; - of.lpstrFilter = filters; - of.lpstrFile = path; - of.nMaxFile = auto_size(path); - of.lpstrInitialDir = dirPath.c_str(); - of.lpstrTitle = title; - of.Flags = OFN_HIDEREADONLY | OFN_EXPLORER | OFN_OVERWRITEPROMPT; - of.lpstrDefExt = defaultExt; - - return GetSaveFileName(&of) ? path : auto_string(); + return getFileName(&GetSaveFileName, parent, instance, + title, initialDir, filters, defaultExt); #else char path[4096] = {}; diff --git a/src/filedialog.hpp b/src/filedialog.hpp @@ -18,21 +18,15 @@ #ifndef REAPACK_FILEBROWSE_HPP #define REAPACK_FILEBROWSE_HPP -#include "encoding.hpp" - -#ifdef _WIN32 -# include <windows.h> -#else -# include <swell-types.h> -#endif +#include "win32.hpp" class Path; namespace FileDialog { - auto_string getOpenFileName(HWND, HINSTANCE, const auto_char *title, - const Path &directory, const auto_char *filters, const auto_char *defext); - auto_string getSaveFileName(HWND, HINSTANCE, const auto_char *title, - const Path &directory, const auto_char *filters, const auto_char *defext); + std::string getOpenFileName(HWND, HINSTANCE, const char *title, + const Path &directory, const Win32::char_type *filters, const Win32::char_type *defext); + std::string getSaveFileName(HWND, HINSTANCE, const char *title, + const Path &directory, const Win32::char_type *filters, const Win32::char_type *defext); }; #endif diff --git a/src/filesystem.cpp b/src/filesystem.cpp @@ -17,8 +17,8 @@ #include "filesystem.hpp" -#include "encoding.hpp" #include "path.hpp" +#include "win32.hpp" #include <cerrno> #include <cstdio> @@ -36,36 +36,34 @@ using namespace std; static bool stat(const Path &path, struct stat *out) { - const Path &fullPath = Path::prefixRoot(path); + const auto &&fullPath = Win32::widen(Path::prefixRoot(path).join()); #ifdef _WIN32 - if(_wstat(make_autostring(fullPath.join()).c_str(), out)) - return false; + constexpr auto func = &_wstat; #else - if(::stat(fullPath.join().c_str(), out)) - return false; + constexpr int(*func)(const char *, struct stat *) = &::stat; #endif - return true; + return !func(fullPath.c_str(), out); } FILE *FS::open(const Path &path) { - const Path &fullPath = Path::prefixRoot(path); + const auto &&fullPath = Win32::widen(Path::prefixRoot(path).join()); #ifdef _WIN32 FILE *file = nullptr; - _wfopen_s(&file, make_autostring(fullPath.join()).c_str(), L"rb"); + _wfopen_s(&file, fullPath.c_str(), L"rb"); return file; #else - return fopen(fullPath.join().c_str(), "rb"); + return fopen(fullPath.c_str(), "rb"); #endif } bool FS::open(ifstream &stream, const Path &path) { - const Path &fullPath = Path::prefixRoot(path); - stream.open(make_autostring(fullPath.join()), ios_base::binary); + const auto &&fullPath = Win32::widen(Path::prefixRoot(path).join()); + stream.open(fullPath, ios_base::binary); return stream.good(); } @@ -74,8 +72,8 @@ bool FS::open(ofstream &stream, const Path &path) if(!mkdir(path.dirname())) return false; - const Path &fullPath = Path::prefixRoot(path); - stream.open(make_autostring(fullPath.join()), ios_base::binary); + const auto &&fullPath = Win32::widen(Path::prefixRoot(path).join()); + stream.open(fullPath, ios_base::binary); return stream.good(); } @@ -102,21 +100,21 @@ bool FS::rename(const TempPath &path) bool FS::rename(const Path &from, const Path &to) { - const string &fullFrom = Path::prefixRoot(from).join(); - const string &fullTo = Path::prefixRoot(to).join(); + const auto &&fullFrom = Win32::widen(Path::prefixRoot(from).join()); + const auto &&fullTo = Win32::widen(Path::prefixRoot(to).join()); #ifdef _WIN32 - return !_wrename(make_autostring(fullFrom).c_str(), - make_autostring(fullTo).c_str()); + const auto func = &_wrename; #else - return !::rename(fullFrom.c_str(), fullTo.c_str()); + const auto func = &::rename; #endif + + return !func(fullFrom.c_str(), fullTo.c_str()); } bool FS::remove(const Path &path) { - const auto_string &fullPath = - make_autostring(Path::prefixRoot(path).join()); + const auto &&fullPath = Win32::widen(Path::prefixRoot(path).join()); #ifdef _WIN32 if(GetFileAttributes(fullPath.c_str()) == INVALID_FILE_ATTRIBUTES @@ -191,7 +189,7 @@ bool FS::mkdir(const Path &path) for(const string &dir : path) { fullPath.append(dir); - const auto_string &joined = make_autostring(fullPath.join()); + const auto &&joined = Win32::widen(fullPath.join()); #ifdef _WIN32 if(!CreateDirectory(joined.c_str(), nullptr) && GetLastError() != ERROR_ALREADY_EXISTS) @@ -205,7 +203,7 @@ bool FS::mkdir(const Path &path) return true; } -string FS::lastError() +const char *FS::lastError() { return strerror(errno); } diff --git a/src/filesystem.hpp b/src/filesystem.hpp @@ -36,7 +36,7 @@ namespace FS { bool exists(const Path &, bool dir = false); bool mkdir(const Path &); - std::string lastError(); + const char *lastError(); }; #endif diff --git a/src/import.cpp b/src/import.cpp @@ -26,13 +26,14 @@ #include "remote.hpp" #include "resource.hpp" #include "transaction.hpp" +#include "win32.hpp" #include <boost/algorithm/string/trim.hpp> using namespace std; -static const auto_char *TITLE = AUTO_STR("ReaPack: Import repositories"); -static const string DISCOVER_URL = "https://reapack.com/repos"; +static const char *TITLE = "ReaPack: Import repositories"; +static const char *DISCOVER_URL = "https://reapack.com/repos"; Import::Import() : Dialog(IDD_IMPORT_DIALOG), m_pool(nullptr), m_state(OK) @@ -43,7 +44,7 @@ void Import::onInit() { Dialog::onInit(); - SetWindowText(handle(), TITLE); + Win32::setWindowText(handle(), TITLE); m_url = getControl(IDC_URL); m_progress = getControl(IDC_PROGRESS); @@ -61,7 +62,7 @@ void Import::onCommand(const int id, int) fetch(); break; case IDC_DISCOVER: - openURL(DISCOVER_URL); + Win32::shellExecute(DISCOVER_URL); break; case IDCANCEL: if(m_pool) { @@ -120,7 +121,7 @@ void Import::fetch() const auto &opts = g_reapack->config()->network; size_t index = 0; - stringstream stream(getText(m_url)); + stringstream stream(Win32::getWindowText(m_url)); string url; while(getline(stream, url)) { boost::algorithm::trim(url); @@ -139,11 +140,10 @@ void Import::fetch() m_pool->abort(); break; case ThreadTask::Failure: { - auto_char msg[1024]; - auto_snprintf(msg, auto_size(msg), - AUTO_STR("Download failed: %s\r\nn%s"), - make_autostring(dl->error().message).c_str(), make_autostring(url).c_str()); - MessageBox(handle(), msg, TITLE, MB_OK); + char msg[1024]; + snprintf(msg, sizeof(msg), "Download failed: %s\r\n%s", + dl->error().message.c_str(), url.c_str()); + Win32::messageBox(handle(), msg, TITLE, MB_OK); m_pool->abort(); break; } @@ -163,7 +163,7 @@ void Import::fetch() bool Import::read(MemoryDownload *dl, const size_t idx) { - auto_char msg[1024]; + char msg[1024]; try { IndexPtr index = Index::load({}, dl->contents().c_str()); @@ -172,19 +172,19 @@ bool Import::read(MemoryDownload *dl, const size_t idx) if(exists && remote.url() != dl->url()) { if(remote.isProtected()) { - auto_snprintf(msg, auto_size(msg), - AUTO_STR("The repository %s is protected and cannot be overwritten."), - make_autostring(index->name()).c_str()); - MessageBox(handle(), msg, TITLE, MB_OK); + snprintf(msg, sizeof(msg), + "The repository %s is protected and cannot be overwritten.", + index->name().c_str()); + Win32::messageBox(handle(), msg, TITLE, MB_OK); return false; } else { - auto_snprintf(msg, auto_size(msg), - AUTO_STR("%s is already configured with a different URL.\r\n") - AUTO_STR("Do you want to overwrite it?"), - make_autostring(index->name()).c_str()); + snprintf(msg, sizeof(msg), + "%s is already configured with a different URL.\r\n" + "Do you want to overwrite it?", + index->name().c_str()); - const auto answer = MessageBox(handle(), msg, TITLE, MB_YESNO); + const auto answer = Win32::messageBox(handle(), msg, TITLE, MB_YESNO); if(answer != IDYES) return true; @@ -200,11 +200,9 @@ bool Import::read(MemoryDownload *dl, const size_t idx) return true; } catch(const reapack_error &e) { - auto_snprintf(msg, auto_size(msg), - AUTO_STR("The received file is invalid: %s\r\n%s"), - make_autostring(string(e.what())).c_str(), - make_autostring(dl->url()).c_str()); - MessageBox(handle(), msg, TITLE, MB_OK); + snprintf(msg, sizeof(msg), "The received file is invalid: %s\r\n%s", + e.what(), dl->url().c_str()); + Win32::messageBox(handle(), msg, TITLE, MB_OK); return false; } } diff --git a/src/index.cpp b/src/index.cpp @@ -17,7 +17,6 @@ #include "index.hpp" -#include "encoding.hpp" #include "errors.hpp" #include "filesystem.hpp" #include "path.hpp" @@ -42,7 +41,7 @@ IndexPtr Index::load(const string &name, const char *data) FILE *file = FS::open(pathFor(name)); if(!file) - throw reapack_error(FS::lastError().c_str()); + throw reapack_error(FS::lastError()); doc.LoadFile(file); fclose(file); diff --git a/src/listview.cpp b/src/listview.cpp @@ -20,6 +20,7 @@ #include "menu.hpp" #include "time.hpp" #include "version.hpp" +#include "win32.hpp" #include <boost/algorithm/string.hpp> @@ -57,9 +58,10 @@ int ListView::addColumn(const Column &col) item.mask |= LVCF_WIDTH; item.cx = col.test(CollapseFlag) ? 0 : adjustWidth(col.width); + const auto &&label = Win32::widen(col.label); if(!col.test(NoLabelFlag)) { item.mask |= LVCF_TEXT; - item.pszText = const_cast<auto_char *>(col.label.c_str()); + item.pszText = const_cast<Win32::char_type *>(label.c_str()); } const int index = columnCount(); @@ -91,8 +93,9 @@ auto ListView::createRow(void *data) -> RowPtr void ListView::updateCell(int row, int cell) { const int viewRowIndex = translate(row); + const auto &&text = Win32::widen(m_rows[row]->cell(cell).value); ListView_SetItemText(handle(), viewRowIndex, cell, - const_cast<auto_char *>(m_rows[row]->cell(cell).value.c_str())); + const_cast<Win32::char_type *>(text.c_str())); } void ListView::removeRow(const int userIndex) @@ -444,7 +447,7 @@ void ListView::headerMenu(const int x, const int y) } menu.addSeparator(); - menu.addAction(AUTO_STR("Reset columns"), ACTION_RESTORE); + menu.addAction("Reset columns", ACTION_RESTORE); const int id = menu.show(x, y, handle()); @@ -542,10 +545,10 @@ int ListView::Column::compare(const ListView::Cell &cl, const ListView::Cell &cr switch(dataType) { case UserType: { // arbitrary data or no data: sort by visible text - auto_string l = cl.value; + string l = cl.value; boost::algorithm::to_lower(l); - auto_string r = cr.value; + string r = cr.value; boost::algorithm::to_lower(r); return l.compare(r); @@ -567,7 +570,7 @@ ListView::Row::Row(const size_t size, void *data, ListView *list) { } -void ListView::Row::setCell(const int i, const auto_string &val, void *data) +void ListView::Row::setCell(const int i, const string &val, void *data) { Cell &cell = m_cells[i]; cell.value = val; diff --git a/src/listview.hpp b/src/listview.hpp @@ -25,7 +25,6 @@ #include <functional> #include <vector> -#include "encoding.hpp" #include "serializer.hpp" class Menu; @@ -49,7 +48,7 @@ public: Cell() : userData(nullptr) {} Cell(const Cell &) = delete; - auto_string value; + std::string value; void *userData; }; @@ -64,7 +63,7 @@ public: int index() const { return m_userIndex; } const Cell &cell(const int i) const { return m_cells[i]; } - void setCell(const int i, const auto_string &, void *data = nullptr); + void setCell(const int i, const std::string &, void *data = nullptr); protected: friend ListView; @@ -79,7 +78,7 @@ public: typedef std::shared_ptr<Row> RowPtr; struct Column { - auto_string label; + std::string label; int width; int flags; ColumnDataType dataType; diff --git a/src/main.cpp b/src/main.cpp @@ -19,6 +19,7 @@ #include "errors.hpp" #include "menu.hpp" #include "reapack.hpp" +#include "win32.hpp" #define REAPERAPI_IMPLEMENT #include <reaper_plugin_functions.h> @@ -50,14 +51,14 @@ static bool loadAPI(void *(*getFunc)(const char *)) *func.ptr = getFunc(func.name); if(func.required && *func.ptr == nullptr) { - auto_char msg[1024]; - auto_snprintf(msg, auto_size(msg), - AUTO_STR("ReaPack v%s is incompatible with this version of REAPER.\r\n\r\n") - AUTO_STR("(Unable to import the following API function: %s)"), - make_autocstring(ReaPack::VERSION), make_autocstring(func.name)); + char msg[1024]; + snprintf(msg, sizeof(msg), + "ReaPack v%s is incompatible with this version of REAPER.\r\n\r\n" + "(Unable to import the following API function: %s)", + ReaPack::VERSION, func.name); - MessageBox(Splash_GetWnd ? Splash_GetWnd() : nullptr, - msg, AUTO_STR("ReaPack: Fatal Error"), MB_OK); + Win32::messageBox(Splash_GetWnd ? Splash_GetWnd() : nullptr, + msg, "ReaPack: Fatal Error", MB_OK); return false; } @@ -76,25 +77,25 @@ static void menuHook(const char *name, HMENU handle, int f) if(strcmp(name, "Main extensions") || f != 0) return; - Menu menu = Menu(handle).addMenu(AUTO_STR("ReaPack")); + Menu menu = Menu(handle).addMenu("ReaPack"); - menu.addAction(AUTO_STR("&Synchronize packages"), + menu.addAction("&Synchronize packages", NamedCommandLookup("_REAPACK_SYNC")); - menu.addAction(AUTO_STR("&Browse packages..."), + menu.addAction("&Browse packages...", NamedCommandLookup("_REAPACK_BROWSE")); - menu.addAction(AUTO_STR("&Import repositories..."), + menu.addAction("&Import repositories...", NamedCommandLookup("_REAPACK_IMPORT")); - menu.addAction(AUTO_STR("&Manage repositories..."), + menu.addAction("&Manage repositories...", NamedCommandLookup("_REAPACK_MANAGE")); menu.addSeparator(); - auto_char aboutLabel[32]; - auto_snprintf(aboutLabel, auto_size(aboutLabel), - AUTO_STR("&About ReaPack v%s"), make_autocstring(ReaPack::VERSION)); + char aboutLabel[32]; + snprintf(aboutLabel, sizeof(aboutLabel), + "&About ReaPack v%s", ReaPack::VERSION); menu.addAction(aboutLabel, NamedCommandLookup("_REAPACK_ABOUT")); } @@ -106,9 +107,9 @@ static bool checkLocation(REAPER_PLUGIN_HINSTANCE module) expected.append(REAPACK_FILE); #ifdef _WIN32 - auto_char self[MAX_PATH] = {}; - GetModuleFileName(module, self, auto_size(self)); - Path current(from_autostring(self).c_str()); + Win32::char_type self[MAX_PATH] = {}; + GetModuleFileName(module, self, lengthof(self)); + Path current(Win32::narrow(self)); #else Dl_info info{}; dladdr((const void *)checkLocation, &info); @@ -119,16 +120,16 @@ static bool checkLocation(REAPER_PLUGIN_HINSTANCE module) if(current == expected) return true; - auto_char msg[4096]; - auto_snprintf(msg, auto_size(msg), - AUTO_STR("ReaPack was not loaded from the standard extension path") - AUTO_STR(" or its filename was altered.\n") - AUTO_STR("Move or rename it to the expected location and retry.\n\n") - AUTO_STR("Current:\xa0%s\n\nExpected:\xa0%s"), - self, make_autostring(expected.join()).c_str()); + char msg[4096]; + snprintf(msg, sizeof(msg), + "ReaPack was not loaded from the standard extension path" + " or its filename was altered.\n" + "Move or rename it to the expected location and retry.\n\n" + "Current: %s\n\nExpected: %s", + current.join().c_str(), expected.join().c_str()); - MessageBox(Splash_GetWnd(), msg, - AUTO_STR("ReaPack: Installation path mismatch"), MB_OK); + Win32::messageBox(Splash_GetWnd(), msg, + "ReaPack: Installation path mismatch", MB_OK); return false; } diff --git a/src/manager.cpp b/src/manager.cpp @@ -20,7 +20,6 @@ #include "about.hpp" #include "archive.hpp" #include "config.hpp" -#include "encoding.hpp" #include "errors.hpp" #include "filedialog.hpp" #include "import.hpp" @@ -31,12 +30,13 @@ #include "remote.hpp" #include "resource.hpp" #include "transaction.hpp" +#include "win32.hpp" #include <boost/algorithm/string/join.hpp> -static const auto_char *ARCHIVE_FILTER = - AUTO_STR("ReaPack Offline Archive (*.ReaPackArchive)\0*.ReaPackArchive\0"); -static const auto_char *ARCHIVE_EXT = AUTO_STR("ReaPackArchive"); +static const Win32::char_type *ARCHIVE_FILTER = + L("ReaPack Offline Archive (*.ReaPackArchive)\0*.ReaPackArchive\0"); +static const Win32::char_type *ARCHIVE_EXT = L("ReaPackArchive"); using namespace std; @@ -67,9 +67,9 @@ void Manager::onInit() disable(m_apply); m_list = createControl<ListView>(IDC_LIST, ListView::Columns{ - {AUTO_STR("Name"), 115}, - {AUTO_STR("Index URL"), 415}, - {AUTO_STR("State"), 60}, + {"Name", 115}, + {"Index URL", 415}, + {"State", 60}, }); m_list->onActivate(bind(&Manager::aboutRepo, this, true)); @@ -212,39 +212,38 @@ bool Manager::fillContextMenu(Menu &menu, const int index) const const Remote &remote = getRemote(index); if(!remote) { - menu.addAction(AUTO_STR("&Select all"), ACTION_SELECT); - menu.addAction(AUTO_STR("&Unselect all"), ACTION_UNSELECT); + menu.addAction("&Select all", ACTION_SELECT); + menu.addAction("&Unselect all", ACTION_UNSELECT); return true; } const UINT enableAction = - menu.addAction(AUTO_STR("&Enable"), ACTION_ENABLE); + menu.addAction("&Enable", ACTION_ENABLE); const UINT disableAction = - menu.addAction(AUTO_STR("&Disable"), ACTION_DISABLE); + menu.addAction("&Disable", ACTION_DISABLE); menu.addSeparator(); - menu.addAction(AUTO_STR("&Refresh"), ACTION_REFRESH); + menu.addAction("&Refresh", ACTION_REFRESH); - Menu autoInstallMenu = menu.addMenu(AUTO_STR("&Install new packages")); + Menu autoInstallMenu = menu.addMenu("&Install new packages"); const UINT autoInstallGlobal = autoInstallMenu.addAction( - AUTO_STR("Use &global setting"), ACTION_AUTOINSTALL_GLOBAL); + "Use &global setting", ACTION_AUTOINSTALL_GLOBAL); const UINT autoInstallOff = autoInstallMenu.addAction( - AUTO_STR("Manually"), ACTION_AUTOINSTALL_OFF); + "Manually", ACTION_AUTOINSTALL_OFF); const UINT autoInstallOn = autoInstallMenu.addAction( - AUTO_STR("When synchronizing"), ACTION_AUTOINSTALL_ON); + "When synchronizing", ACTION_AUTOINSTALL_ON); - menu.addAction(AUTO_STR("&Copy URL"), ACTION_COPYURL); + menu.addAction("&Copy URL", ACTION_COPYURL); const UINT uninstallAction = - menu.addAction(AUTO_STR("&Uninstall"), ACTION_UNINSTALL); + menu.addAction("&Uninstall", ACTION_UNINSTALL); menu.addSeparator(); - auto_char aboutLabel[64]; - const auto_string &name = make_autostring(remote.name()); - auto_snprintf(aboutLabel, auto_size(aboutLabel), - AUTO_STR("&About %s"), name.c_str()); + char aboutLabel[64]; + snprintf(aboutLabel, sizeof(aboutLabel), + "&About %s", remote.name().c_str()); menu.addAction(aboutLabel, index | (ACTION_ABOUT << 8)); bool allEnabled = true; @@ -319,7 +318,7 @@ void Manager::refresh() const vector<int> selection = m_list->selection(); vector<string> selected(selection.size()); for(size_t i = 0; i < selection.size(); i++) - selected[i] = from_autostring(m_list->row(selection[i])->cell(0).value); // TODO: use data ptr to Remote + selected[i] = m_list->row(selection[i])->cell(0).value; // TODO: use data ptr to Remote const auto &remotes = g_reapack->config()->remotes; @@ -332,8 +331,8 @@ void Manager::refresh() int c = 0; auto row = m_list->createRow(); - row->setCell(c++, make_autostring(remote.name())); - row->setCell(c++, make_autostring(remote.url())); + row->setCell(c++, remote.name()); + row->setCell(c++, remote.url()); updateEnabledCell(row->index(), remote); if(find(selected.begin(), selected.end(), remote.name()) != selected.end()) @@ -345,8 +344,7 @@ void Manager::refresh() void Manager::updateEnabledCell(int index, const Remote &remote) { - m_list->row(index)->setCell(2, isRemoteEnabled(remote) ? - AUTO_STR("Enabled") : AUTO_STR("Disabled")); + m_list->row(index)->setCell(2, isRemoteEnabled(remote) ? "Enabled" : "Disabled"); } void Manager::setMods(const ModsCallback &cb, const bool updateRow) @@ -498,10 +496,10 @@ void Manager::aboutRepo(const bool focus) void Manager::importExport() { Menu menu; - menu.addAction(AUTO_STR("Import &repositories..."), ACTION_IMPORT_REPO); + menu.addAction("Import &repositories...", ACTION_IMPORT_REPO); menu.addSeparator(); - menu.addAction(AUTO_STR("Import offline archive..."), ACTION_IMPORT_ARCHIVE); - menu.addAction(AUTO_STR("&Export offline archive..."), ACTION_EXPORT_ARCHIVE); + menu.addAction("Import offline archive...", ACTION_IMPORT_ARCHIVE); + menu.addAction("&Export offline archive...", ACTION_EXPORT_ARCHIVE); menu.show(getControl(IDC_IMPORT), handle()); } @@ -520,9 +518,9 @@ bool Manager::importRepo() void Manager::importArchive() { - const auto_char *title = AUTO_STR("Import offline archive"); + const char *title = "Import offline archive"; - const auto_string &path = FileDialog::getOpenFileName(handle(), instance(), + const string &path = FileDialog::getOpenFileName(handle(), instance(), title, Path::prefixRoot(Path::DATA), ARCHIVE_FILTER, ARCHIVE_EXT); if(path.empty()) @@ -532,23 +530,18 @@ void Manager::importArchive() Archive::import(path); } catch(const reapack_error &e) { - const auto_string &desc = make_autostring(e.what()); - - auto_char msg[512]; - auto_snprintf(msg, auto_size(msg), - AUTO_STR("An error occured while reading %s.\r\n\r\n%s."), - path.c_str(), desc.c_str() - ); - - MessageBox(handle(), msg, title, MB_OK); + char msg[512]; + snprintf(msg, sizeof(msg), "An error occured while reading %s.\r\n\r\n%s.", + path.c_str(), e.what()); + Win32::messageBox(handle(), msg, title, MB_OK); } } void Manager::exportArchive() { - const auto_char *title = AUTO_STR("Export offline archive"); + const char *title = "Export offline archive"; - const auto_string &path = FileDialog::getSaveFileName(handle(), instance(), + const string &path = FileDialog::getSaveFileName(handle(), instance(), title, Path::prefixRoot(Path::DATA), ARCHIVE_FILTER, ARCHIVE_EXT); if(path.empty()) @@ -564,22 +557,22 @@ void Manager::exportArchive() const auto finish = [=] { Dialog::Destroy(progress); - auto_char error[1024]; + char error[1024]; if(errors.empty()) error[0] = 0; else { - auto_snprintf(error, auto_size(error), - AUTO_STR("\r\n\r\n%zu file%s could not be archived. ") - AUTO_STR("Synchronize packages to repair any missing file.\r\n\r\n%s"), - errors.size(), errors.size() == 1 ? AUTO_STR("") : AUTO_STR("s"), - make_autostring(boost::algorithm::join(errors, "\r\n")).c_str()); + snprintf(error, sizeof(error), + "\r\n\r\n%zu file%s could not be archived. " + "Synchronize packages to repair any missing file.\r\n\r\n%s", + errors.size(), errors.size() == 1 ? "" : "s", + boost::algorithm::join(errors, "\r\n").c_str()); } - auto_char msg[2048]; - auto_snprintf(msg, auto_size(msg), - AUTO_STR("Done! %zu package%s were exported in the archive.%s"), - count, count == 1 ? AUTO_STR("") : AUTO_STR("s"), error); - MessageBox(handle(), msg, title, MB_OK); + char msg[2048]; + snprintf(msg, sizeof(msg), + "Done! %zu package%s were exported in the archive.%s", + count, count == 1 ? "" : "s", error); + Win32::messageBox(handle(), msg, title, MB_OK); delete pool; }; @@ -593,24 +586,19 @@ void Manager::exportArchive() Dialog::Destroy(progress); delete pool; - const auto_string &desc = make_autostring(e.what()); - - auto_char msg[512]; - auto_snprintf(msg, auto_size(msg), - AUTO_STR("An error occured while writing into %s.\r\n\r\n%s."), - path.c_str(), desc.c_str() + char msg[512]; + snprintf(msg, sizeof(msg), + "An error occured while writing into %s.\r\n\r\n%s.", + path.c_str(), e.what() ); - MessageBox(handle(), msg, title, MB_OK); + Win32::messageBox(handle(), msg, title, MB_OK); } } void Manager::launchBrowser() { - const auto promptApply = [&] { - const auto_char *title = AUTO_STR("ReaPack Query"); - const auto_char *msg = AUTO_STR("Apply unsaved changes?"); - const int btn = MessageBox(handle(), msg, title, MB_YESNO); - return btn == IDYES; + const auto promptApply = [this] { + return IDYES == Win32::messageBox(handle(), "Apply unsaved changes?", "ReaPack Query", MB_YESNO); }; if(m_changes && promptApply()) @@ -624,25 +612,25 @@ void Manager::options() Menu menu; UINT index = menu.addAction( - AUTO_STR("&Install new packages when synchronizing"), ACTION_AUTOINSTALL); + "&Install new packages when synchronizing", ACTION_AUTOINSTALL); if(m_autoInstall.value_or(g_reapack->config()->install.autoInstall)) menu.check(index); index = menu.addAction( - AUTO_STR("Enable &pre-releases globally (bleeding edge)"), ACTION_BLEEDINGEDGE); + "Enable &pre-releases globally (bleeding edge)", ACTION_BLEEDINGEDGE); if(m_bleedingEdge.value_or(g_reapack->config()->install.bleedingEdge)) menu.check(index); index = menu.addAction( - AUTO_STR("Prompt to uninstall obsolete packages"), ACTION_PROMPTOBSOLETE); + "Prompt to uninstall obsolete packages", ACTION_PROMPTOBSOLETE); if(m_promptObsolete.value_or(g_reapack->config()->install.promptObsolete)) menu.check(index); - menu.addAction(AUTO_STR("&Network settings..."), ACTION_NETCONFIG); + menu.addAction("&Network settings...", ACTION_NETCONFIG); menu.addSeparator(); - menu.addAction(AUTO_STR("&Restore default settings"), ACTION_RESETCONFIG); + menu.addAction("&Restore default settings", ACTION_RESETCONFIG); menu.show(getControl(IDC_OPTIONS), handle()); } @@ -660,16 +648,12 @@ bool Manager::confirm() const const size_t uninstallSize = m_uninstall.size(); - auto_char msg[255]; - auto_snprintf(msg, auto_size(msg), AUTO_STR("Uninstall %zu %s?\n") - AUTO_STR("Every file they contain will be removed from your computer."), - uninstallSize, - uninstallSize == 1 ? AUTO_STR("repository") : AUTO_STR("repositories")); - - const auto_char *title = AUTO_STR("ReaPack Query"); - const int btn = MessageBox(handle(), msg, title, MB_YESNO); + char msg[255]; + snprintf(msg, sizeof(msg), "Uninstall %zu %s?\n" + "Every file they contain will be removed from your computer.", + uninstallSize, uninstallSize == 1 ? "repository" : "repositories"); - return btn == IDYES; + return IDYES == Win32::messageBox(handle(), msg, "ReaPack Query", MB_YESNO); } bool Manager::apply() @@ -757,7 +741,7 @@ Remote Manager::getRemote(const int index) const if(index < 0 || index > m_list->rowCount() - 1) return {}; - const string &remoteName = from_autostring(m_list->row(index)->cell(0).value); + const string &remoteName = m_list->row(index)->cell(0).value; return g_reapack->config()->remotes.get(remoteName); } @@ -771,7 +755,7 @@ void NetworkConfig::onInit() Dialog::onInit(); m_proxy = getControl(IDC_PROXY); - SetWindowText(m_proxy, make_autostring(m_opts->proxy).c_str()); + Win32::setWindowText(m_proxy, m_opts->proxy.c_str()); m_verifyPeer = getControl(IDC_VERIFYPEER); setChecked(m_opts->verifyPeer, m_verifyPeer); @@ -794,7 +778,7 @@ void NetworkConfig::onCommand(const int id, int) void NetworkConfig::apply() { - m_opts->proxy = getText(m_proxy); + m_opts->proxy = Win32::getWindowText(m_proxy); m_opts->verifyPeer = isChecked(m_verifyPeer); m_opts->staleThreshold = isChecked(m_staleThreshold) ? NetworkOpts::OneWeekThreshold : NetworkOpts::NoThreshold; diff --git a/src/menu.cpp b/src/menu.cpp @@ -17,10 +17,18 @@ #include "menu.hpp" +#include "win32.hpp" + #ifndef MIIM_FTYPE // for SWELL -#define MIIM_FTYPE MIIM_TYPE +# define MIIM_FTYPE MIIM_TYPE +#endif + +#ifndef _WIN32 +# include <swell.h> #endif +using namespace std; + Menu::Menu(HMENU handle) : m_handle(handle), m_ownership(!handle) { @@ -39,14 +47,15 @@ Menu::~Menu() DestroyMenu(m_handle); } -UINT Menu::addAction(const auto_char *label, const int commandId) +UINT Menu::addAction(const string &label, const int commandId) { MENUITEMINFO mii{}; mii.cbSize = sizeof(MENUITEMINFO); mii.fMask |= MIIM_TYPE; mii.fType = MFT_STRING; - mii.dwTypeData = const_cast<auto_char *>(label); + const auto &&wideLabel = Win32::widen(label); + mii.dwTypeData = const_cast<Win32::char_type *>(wideLabel.c_str()); mii.fMask |= MIIM_ID; mii.wID = commandId; @@ -67,14 +76,15 @@ void Menu::addSeparator() append(mii); } -Menu Menu::addMenu(const auto_char *label) +Menu Menu::addMenu(const string &label) { MENUITEMINFO mii{}; mii.cbSize = sizeof(MENUITEMINFO); mii.fMask |= MIIM_TYPE; mii.fType = MFT_STRING; - mii.dwTypeData = const_cast<auto_char *>(label); + const auto &&wideLabel = Win32::widen(label); + mii.dwTypeData = const_cast<Win32::char_type *>(wideLabel.c_str()); mii.fMask |= MIIM_SUBMENU; mii.hSubMenu = CreatePopupMenu(); diff --git a/src/menu.hpp b/src/menu.hpp @@ -18,14 +18,14 @@ #ifndef REAPACK_MENU_HPP #define REAPACK_MENU_HPP +#include <string> + #ifdef _WIN32 -#include <windows.h> +# include <windows.h> #else -#include <swell/swell.h> +# include <swell-types.h> #endif -#include "encoding.hpp" - class Menu { public: Menu(HMENU handle = nullptr); @@ -34,9 +34,9 @@ public: UINT size() { return m_size; } bool empty() const { return m_size == 0; } - UINT addAction(const auto_char *label, int commandId); + UINT addAction(const std::string &label, int commandId); void addSeparator(); - Menu addMenu(const auto_char *label); + Menu addMenu(const std::string &label); int show(int x, int y, HWND parent) const; int show(HWND control, HWND parent) const; diff --git a/src/obsquery.cpp b/src/obsquery.cpp @@ -17,7 +17,6 @@ #include "obsquery.hpp" -#include "encoding.hpp" #include "listview.hpp" #include "menu.hpp" #include "package.hpp" @@ -42,13 +41,13 @@ void ObsoleteQuery::onInit() m_okBtn = getControl(IDOK); m_list = createControl<ListView>(IDC_LIST, ListView::Columns{ - {AUTO_STR("Package"), 550} + {"Package", 550} }); m_list->onSelect([=] { setEnabled(m_list->hasSelection(), m_okBtn); }); m_list->onContextMenu([=] (Menu &menu, int) { - menu.addAction(AUTO_STR("Select &all"), ACTION_SELECT_ALL); - menu.addAction(AUTO_STR("&Unselect all"), ACTION_UNSELECT_ALL); + menu.addAction("Select &all", ACTION_SELECT_ALL); + menu.addAction("&Unselect all", ACTION_UNSELECT_ALL); return true; }); @@ -58,7 +57,7 @@ void ObsoleteQuery::onInit() ostringstream stream; stream << entry.remote << '/' << entry.category << '/' << Package::displayName(entry.package, entry.description); - m_list->createRow()->setCell(0, make_autostring(stream.str())); + m_list->createRow()->setCell(0, stream.str()); } m_list->autoSizeHeader(); diff --git a/src/progress.cpp b/src/progress.cpp @@ -19,6 +19,7 @@ #include "thread.hpp" #include "resource.hpp" +#include "win32.hpp" using namespace std; @@ -35,9 +36,9 @@ void Progress::onInit() Dialog::onInit(); m_label = getControl(IDC_LABEL); - m_progress = GetDlgItem(handle(), IDC_PROGRESS); + m_progress = getControl(IDC_PROGRESS); - SetWindowText(m_label, AUTO_STR("Initializing...")); + Win32::setWindowText(m_label, "Initializing..."); } void Progress::onCommand(const int id, int) @@ -68,7 +69,7 @@ void Progress::addTask(ThreadTask *task) startTimer(100); task->onStart([=] { - m_current = make_autostring(task->summary()); + m_current = task->summary(); updateProgress(); }); @@ -80,22 +81,22 @@ void Progress::addTask(ThreadTask *task) void Progress::updateProgress() { - auto_char position[32]; - auto_snprintf(position, auto_size(position), AUTO_STR("%d of %d"), + char position[32]; + snprintf(position, sizeof(position), "%d of %d", min(m_done + 1, m_total), m_total); - auto_char label[1024]; - auto_snprintf(label, auto_size(label), m_current.c_str(), position); + char label[1024]; + snprintf(label, sizeof(label), m_current.c_str(), position); - SetWindowText(m_label, label); + Win32::setWindowText(m_label, label); const double pos = (double)(min(m_done+1, m_total)) / max(2, m_total); const int percent = (int)(pos * 100); - auto_char title[255]; - auto_snprintf(title, auto_size(title), - AUTO_STR("ReaPack: Operation in progress (%d%%)"), percent); + char title[255]; + snprintf(title, sizeof(title), + "ReaPack: Operation in progress (%d%%)", percent); SendMessage(m_progress, PBM_SETPOS, percent, 0); - SetWindowText(handle(), title); + Win32::setWindowText(handle(), title); } diff --git a/src/progress.hpp b/src/progress.hpp @@ -20,7 +20,6 @@ #include "dialog.hpp" -#include "encoding.hpp" class ThreadPool; class ThreadTask; @@ -39,7 +38,7 @@ private: void updateProgress(); ThreadPool *m_pool; - auto_string m_current; + std::string m_current; HWND m_label; HWND m_progress; diff --git a/src/reapack.cpp b/src/reapack.cpp @@ -31,6 +31,7 @@ #include "report.hpp" #include "richedit.hpp" #include "transaction.hpp" +#include "win32.hpp" #include <reaper_plugin_functions.h> @@ -48,7 +49,7 @@ ReaPack *ReaPack::s_instance = nullptr; static void CleanupTempFiles() { const Path &path = Path::prefixRoot(Path::DATA + "*.tmp"); - const auto_string &pattern = make_autostring(path.join()); + const wstring &pattern = Win32::widen(path.join()); WIN32_FIND_DATA fd = {}; HANDLE handle = FindFirstFile(pattern.c_str(), &fd); @@ -57,7 +58,7 @@ static void CleanupTempFiles() return; do { - auto_string file = pattern; + wstring file = pattern; file.replace(file.size() - 5, 5, fd.cFileName); // 5 == strlen("*.tmp") DeleteFile(file.c_str()); } while(FindNextFile(handle, &fd)); @@ -66,13 +67,13 @@ static void CleanupTempFiles() } #endif -std::string ReaPack::resourcePath() +Path ReaPack::resourcePath() { #ifdef _WIN32 // convert from the current system codepage to UTF-8 - return from_autostring(make_autostring(GetResourcePath(), CP_ACP)); + return Win32::narrow(Win32::widen(GetResourcePath(), CP_ACP)); #else - return GetResourcePath(); + return {GetResourcePath()}; #endif } @@ -336,15 +337,13 @@ Transaction *ReaPack::setupTransaction() m_tx = new Transaction; } catch(const reapack_error &e) { - const auto_string &desc = make_autostring(e.what()); - - auto_char msg[512]; - auto_snprintf(msg, auto_size(msg), - AUTO_STR("The following error occurred while creating a transaction:\n\n%s"), - desc.c_str() + char msg[512]; + snprintf(msg, sizeof(msg), + "The following error occurred while creating a transaction:\n\n%s", + e.what() ); - MessageBox(m_mainWindow, msg, AUTO_STR("ReaPack"), MB_OK); + Win32::messageBox(m_mainWindow, msg, "ReaPack", MB_OK); return nullptr; } @@ -420,16 +419,14 @@ void ReaPack::createDirectories() if(FS::mkdir(path)) return; - const auto_string &desc = make_autostring(FS::lastError()); - - auto_char msg[255]; - auto_snprintf(msg, auto_size(msg), - AUTO_STR("ReaPack could not create %s! ") - AUTO_STR("Please investigate or report this issue.\n\n") - AUTO_STR("Error description: %s"), - make_autostring(Path::prefixRoot(path).join()).c_str(), desc.c_str()); + char msg[255]; + snprintf(msg, sizeof(msg), + "ReaPack could not create %s! " + "Please investigate or report this issue.\n\n" + "Error description: %s", + Path::prefixRoot(path).join().c_str(), FS::lastError()); - MessageBox(Splash_GetWnd(), msg, AUTO_STR("ReaPack"), MB_OK); + Win32::messageBox(Splash_GetWnd(), msg, "ReaPack", MB_OK); } void ReaPack::registerSelf() diff --git a/src/reapack.hpp b/src/reapack.hpp @@ -47,7 +47,7 @@ public: static const char *BUILDTIME; static ReaPack *instance() { return s_instance; } - static std::string resourcePath(); + static Path resourcePath(); gaccel_register_t syncAction; gaccel_register_t browseAction; diff --git a/src/report.cpp b/src/report.cpp @@ -17,11 +17,11 @@ #include "report.hpp" -#include "encoding.hpp" #include "package.hpp" #include "resource.hpp" #include "source.hpp" #include "transaction.hpp" +#include "win32.hpp" #include <boost/range/adaptor/reversed.hpp> @@ -92,12 +92,11 @@ void Report::fillReport() printRemovals(); if(installs + updates + removals == 0) { - SetDlgItemText(handle(), IDC_LABEL, - AUTO_STR("Oops! The following error(s) occured:")); + Win32::setWindowText(getControl(IDC_LABEL), + "Oops! The following error(s) occured:"); } - const auto_string &str = make_autostring(m_stream.str()); - SetDlgItemText(handle(), IDC_REPORT, str.c_str()); + Win32::setWindowText(getControl(IDC_REPORT), m_stream.str().c_str()); } void Report::printInstalls() diff --git a/src/richedit-win32.cpp b/src/richedit-win32.cpp @@ -22,8 +22,6 @@ // Starting here and onward is the Win32 implementation of RichEdit // The OS X implementation can be found in richedit.mm -#include "encoding.hpp" - #include <memory> #include <richedit.h> #include <sstream> @@ -34,19 +32,19 @@ static void HandleLink(ENLINK *info, HWND handle) { const CHARRANGE &range = info->chrg; - auto_char *url = new auto_char[(range.cpMax - range.cpMin) + 1](); - unique_ptr<auto_char[]> ptr(url); + wchar_t *url = new wchar_t[(range.cpMax - range.cpMin) + 1](); + unique_ptr<wchar_t[]> ptr(url); TEXTRANGE tr{range, url}; SendMessage(handle, EM_GETTEXTRANGE, 0, (LPARAM)&tr); if(info->msg == WM_LBUTTONUP) - ShellExecute(nullptr, AUTO_STR("open"), url, nullptr, nullptr, SW_SHOW); + ShellExecute(nullptr, L"open", url, nullptr, nullptr, SW_SHOW); } void RichEdit::Init() { - LoadLibrary(AUTO_STR("Msftedit.dll")); + LoadLibrary(L"Msftedit.dll"); } RichEdit::RichEdit(HWND handle) diff --git a/src/tabbar.cpp b/src/tabbar.cpp @@ -18,6 +18,7 @@ #include "tabbar.hpp" #include "dialog.hpp" +#include "win32.hpp" #ifdef _WIN32 # include <commctrl.h> @@ -38,7 +39,8 @@ int TabBar::addTab(const Tab &tab) TCITEM item{}; item.mask |= TCIF_TEXT; - item.pszText = const_cast<auto_char *>(tab.text.c_str()); + const auto &&wideText = Win32::widen(tab.text); + item.pszText = const_cast<Win32::char_type *>(wideText.c_str()); TabCtrl_InsertItem(handle(), index, &item); diff --git a/src/tabbar.hpp b/src/tabbar.hpp @@ -22,14 +22,13 @@ #include <vector> -#include "encoding.hpp" class Dialog; class TabBar : public Control { public: typedef std::vector<HWND> Page; - struct Tab { auto_string text; Page page; }; + struct Tab { const char *text; Page page; }; typedef std::vector<Tab> Tabs; TabBar(HWND handle, Dialog *parent, const Tabs &tabs = {}); diff --git a/src/task.cpp b/src/task.cpp @@ -107,7 +107,7 @@ void InstallTask::commit() for(const TempPath &paths : m_newFiles) { if(!FS::rename(paths)) { - tx()->receipt()->addError({"Cannot rename to target: " + FS::lastError(), + tx()->receipt()->addError({string("Cannot rename to target: ") + FS::lastError(), paths.target().join()}); // it's a bit late to rollback here as some files might already have been diff --git a/src/thread.cpp b/src/thread.cpp @@ -78,7 +78,7 @@ void ThreadTask::exec() WorkerThread::WorkerThread() : m_exit(false) { - m_wake = CreateEvent(nullptr, true, false, AUTO_STR("WakeEvent")); + m_wake = CreateEvent(nullptr, true, false, nullptr); m_thread = CreateThread(nullptr, 0, run, (void *)this, 0, nullptr); } diff --git a/src/transaction.cpp b/src/transaction.cpp @@ -169,7 +169,7 @@ IndexPtr Transaction::loadIndex(const Remote &remote) } catch(const reapack_error &e) { m_receipt.addError({ - "Couldn't load repository: " + string(e.what()), remote.name()}); + string("Couldn't load repository: ") + e.what(), remote.name()}); return nullptr; } } diff --git a/src/win32.cpp b/src/win32.cpp @@ -0,0 +1,99 @@ +/* ReaPack: Package manager for REAPER + * Copyright (C) 2015-2017 Christian Fillion + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "win32.hpp" + +#ifdef _WIN32 +# define widen_cstr(cstr) widen(cstr).c_str() +#else +# include <swell/swell.h> +# define widen_cstr(cstr) cstr +#endif + +using namespace std; + +#ifdef _WIN32 +wstring Win32::widen(const char *input, const UINT codepage) +{ + const int size = MultiByteToWideChar(codepage, 0, input, -1, nullptr, 0) - 1; + + wstring output(size, 0); + MultiByteToWideChar(codepage, 0, input, -1, &output[0], size); + + return output; +} + +string Win32::narrow(const wchar_t *input) +{ + const int size = WideCharToMultiByte(CP_UTF8, 0, + input, -1, nullptr, 0, nullptr, nullptr) - 1; + + string output(size, 0); + WideCharToMultiByte(CP_UTF8, 0, input, -1, &output[0], size, nullptr, nullptr); + + return output; +} +#endif + +int Win32::messageBox(const HWND handle, const char *text, + const char *title, const unsigned int buttons) +{ + return MessageBox(handle, widen_cstr(text), widen_cstr(title), buttons); +} + +string Win32::getWindowText(const HWND handle) +{ + char_type buffer[4096]; + GetWindowText(handle, buffer, (int)lengthof(buffer)); + + return narrow(buffer); +} + +void Win32::setWindowText(const HWND handle, const char *text) +{ + SetWindowText(handle, widen_cstr(text)); +} + +void Win32::shellExecute(const char *what, const char *arg) +{ + ShellExecute(nullptr, L("open"), widen_cstr(what), widen_cstr(arg), nullptr, SW_SHOW); +} + +bool Win32::writePrivateProfileString(const char *group, const char *key, + const char *value, const char *path) +{ + // value can be null for deleting a key + return WritePrivateProfileString(widen_cstr(group), widen_cstr(key), + value ? widen_cstr(value) : nullptr, widen_cstr(path)); +} + +string Win32::getPrivateProfileString(const char *group, const char *key, + const char *fallback, const char *path) +{ + char_type buffer[4096]; + GetPrivateProfileString(widen_cstr(group), widen_cstr(key), + widen_cstr(fallback), buffer, lengthof(buffer), widen_cstr(path)); + + return narrow(buffer); +} + +unsigned int Win32::getPrivateProfileInt(const char *group, const char *key, + const unsigned int fallback, const char *path) +{ + return GetPrivateProfileInt(widen_cstr(group), widen_cstr(key), + fallback, widen_cstr(path)); +} diff --git a/src/win32.hpp b/src/win32.hpp @@ -0,0 +1,64 @@ +/* ReaPack: Package manager for REAPER + * Copyright (C) 2015-2017 Christian Fillion + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef REAPACK_WIN32_HPP +#define REAPACK_WIN32_HPP + +// Utility wrappers around the Windows Wide API + +#include <string> + +#ifdef _WIN32 +# define L(str) L##str +# include <windows.h> +#else +# define L(str) str +# include <swell-types.h> +#endif + +#define lengthof(t) (sizeof(t) / sizeof(*t)) + +namespace Win32 { +#ifdef _WIN32 + typedef wchar_t char_type; + + std::wstring widen(const char *, UINT codepage = CP_UTF8); + inline std::wstring widen(const std::string &str) { return widen(str.c_str(), CP_UTF8); } + + std::string narrow(const wchar_t *); + inline std::string narrow(const std::wstring &str) { return narrow(str.c_str()); } +#else + typedef char char_type; + + inline std::string widen(const char *s, UINT = 0) { return s; } + inline std::string widen(const std::string &s) { return s; } + + inline std::string narrow(const char *s) { return s; } + inline std::string narrow(const std::string &s) { return s; } +#endif + + int messageBox(HWND, const char *text, const char *title, unsigned int buttons); + void setWindowText(HWND handle, const char *text); + std::string getWindowText(HWND handle); + void shellExecute(const char *what, const char *arg = nullptr); + + bool writePrivateProfileString(const char *g, const char *k, const char *v, const char *p); + std::string getPrivateProfileString(const char *g, const char *k, const char *v, const char *p); + unsigned int getPrivateProfileInt(const char *g, const char *k, unsigned int f, const char *p); +}; + +#endif diff --git a/test/encoding.cpp b/test/encoding.cpp @@ -1,32 +0,0 @@ -#include <catch.hpp> - -#include <encoding.hpp> - -using namespace std; - -static const char *M = "[encoding]"; - -TEST_CASE("to_autostring", M) { - REQUIRE(to_autostring(42) == AUTO_STR("42")); -} - -TEST_CASE("string to wstring to string", M) { - SECTION("ascii") { - const auto_string &wstr = make_autostring("hello world"); - const string &str = from_autostring(wstr); - - REQUIRE(str == "hello world"); - } - - SECTION("cyrillic") { - const auto_string &wstr = make_autostring("Новая папка"); - const string &str = from_autostring(wstr); - - REQUIRE(str == "Новая папка"); - } -} - -TEST_CASE("auto_size", M) { - auto_char test[42] = {}; - REQUIRE(auto_size(test) == 42); -} diff --git a/test/win32.cpp b/test/win32.cpp @@ -0,0 +1,37 @@ +#include "helper.hpp" + +#include <win32.hpp> + +using namespace std; + +static const char *M = "[win32]"; + +TEST_CASE("widen string", M) { + SECTION("ascii") { + const auto &wide = Win32::widen("hello world"); + REQUIRE(wide == L("hello world")); + REQUIRE(wide.size() == 11); + } + + SECTION("cyrillic") { + const auto &wide = Win32::widen("世界"); + REQUIRE(wide == L("\u4e16\u754c")); +#ifdef _WIN32 + REQUIRE(wide.size() == 2); +#else + REQUIRE(wide.size() == 6); +#endif + } +} + +TEST_CASE("narrow string", M) { + SECTION("ascii") { + const auto &narrow = Win32::narrow(L("hello world")); + REQUIRE(narrow == "hello world"); + } + + SECTION("cyrillic") { + const auto &narrow = Win32::narrow(L("\u4e16\u754c")); + REQUIRE(narrow == "世界"); + } +}