From e679190f31bd470a8c8bbcf134c5daad4e0cb802 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 19 May 2019 12:33:57 +0400 Subject: [PATCH] Introduce a custom format() function to get rid of boost::format() and hackish replace() --- apps/esmtool/labels.cpp | 28 +++++------ apps/esmtool/record.cpp | 39 +++++++-------- apps/openmw/mwgui/enchantingdialog.cpp | 2 +- apps/openmw/mwgui/jailscreen.cpp | 5 +- apps/openmw/mwgui/recharge.cpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwmechanics/disease.hpp | 2 +- apps/openmw/mwmechanics/npcstats.cpp | 3 +- apps/openmw/mwmechanics/repair.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwscript/containerextensions.cpp | 8 +-- apps/openmw/mwworld/actionharvest.cpp | 5 +- components/misc/stringops.hpp | 52 +++++++++++--------- 15 files changed, 80 insertions(+), 76 deletions(-) diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index 43d0a05eda..d844f68861 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include std::string bodyPartLabel(int idx) { @@ -659,7 +659,7 @@ std::string bodyPartFlags(int flags) (ESM::BodyPart::BPF_Female| ESM::BodyPart::BPF_NotPlayable)); if (flags & unused) properties += "Invalid "; - properties += str(boost::format("(0x%08X)") % flags); + properties += Misc::StringUtils::format("(0x%08X)", flags); return properties; } @@ -680,7 +680,7 @@ std::string cellFlags(int flags) ESM::Cell::QuasiEx| 0x00000040)); if (flags & unused) properties += "Invalid "; - properties += str(boost::format("(0x%08X)") % flags); + properties += Misc::StringUtils::format("(0x%08X)", flags); return properties; } @@ -696,7 +696,7 @@ std::string containerFlags(int flags) ESM::Container::Organic| ESM::Container::Respawn)); if (flags & unused) properties += "Invalid "; - properties += str(boost::format("(0x%08X)") % flags); + properties += Misc::StringUtils::format("(0x%08X)", flags); return properties; } @@ -722,7 +722,7 @@ std::string creatureFlags(int flags) ESM::Creature::Weapon| ESM::Creature::Essential)); if (flags & unused) properties += "Invalid "; - properties += str(boost::format("(0x%02X)") % flags); + properties += Misc::StringUtils::format("(0x%02X)", flags); return properties; } @@ -737,7 +737,7 @@ std::string landFlags(int flags) if (flags & 0x00000004) properties += "Unknown3 "; if (flags & 0x00000002) properties += "Unknown2 "; if (flags & 0xFFFFFFF8) properties += "Invalid "; - properties += str(boost::format("(0x%08X)") % flags); + properties += Misc::StringUtils::format("(0x%08X)", flags); return properties; } @@ -751,7 +751,7 @@ std::string itemListFlags(int flags) (ESM::ItemLevList::AllLevels| ESM::ItemLevList::Each)); if (flags & unused) properties += "Invalid "; - properties += str(boost::format("(0x%08X)") % flags); + properties += Misc::StringUtils::format("(0x%08X)", flags); return properties; } @@ -762,7 +762,7 @@ std::string creatureListFlags(int flags) if (flags & ESM::CreatureLevList::AllLevels) properties += "AllLevels "; int unused = (0xFFFFFFFF ^ ESM::CreatureLevList::AllLevels); if (flags & unused) properties += "Invalid "; - properties += str(boost::format("(0x%08X)") % flags); + properties += Misc::StringUtils::format("(0x%08X)", flags); return properties; } @@ -790,7 +790,7 @@ std::string lightFlags(int flags) ESM::Light::Negative| ESM::Light::OffDefault)); if (flags & unused) properties += "Invalid "; - properties += str(boost::format("(0x%08X)") % flags); + properties += Misc::StringUtils::format("(0x%08X)", flags); return properties; } @@ -816,7 +816,7 @@ std::string magicEffectFlags(int flags) if (flags & ESM::MagicEffect::NegativeLight) properties += "NegativeLight "; if (flags & 0xFFFC0000) properties += "Invalid "; - properties += str(boost::format("(0x%08X)") % flags); + properties += Misc::StringUtils::format("(0x%08X)", flags); return properties; } @@ -838,7 +838,7 @@ std::string npcFlags(int flags) ESM::NPC::Respawn| ESM::NPC::Essential)); if (flags & unused) properties += "Invalid "; - properties += str(boost::format("(0x%02X)") % flags); + properties += Misc::StringUtils::format("(0x%02X)", flags); return properties; } @@ -853,7 +853,7 @@ std::string raceFlags(int flags) (ESM::Race::Playable| ESM::Race::Beast)); if (flags & unused) properties += "Invalid "; - properties += str(boost::format("(0x%08X)") % flags); + properties += Misc::StringUtils::format("(0x%08X)", flags); return properties; } @@ -869,7 +869,7 @@ std::string spellFlags(int flags) ESM::Spell::F_PCStart| ESM::Spell::F_Always)); if (flags & unused) properties += "Invalid "; - properties += str(boost::format("(0x%08X)") % flags); + properties += Misc::StringUtils::format("(0x%08X)", flags); return properties; } @@ -886,6 +886,6 @@ std::string weaponFlags(int flags) (ESM::Weapon::Magical| ESM::Weapon::Silver)); if (flags & unused) properties += "Invalid "; - properties += str(boost::format("(0x%08X)") % flags); + properties += Misc::StringUtils::format("(0x%08X)", flags); return properties; } diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 2149d17729..c4b14a3413 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace { @@ -12,7 +12,7 @@ namespace void printAIPackage(ESM::AIPackage p) { std::cout << " AI Type: " << aiTypeLabel(p.mType) - << " (" << boost::format("0x%08X") % p.mType << ")" << std::endl; + << " (" << Misc::StringUtils::format("0x%08X", p.mType) << ")" << std::endl; if (p.mType == ESM::AI_Wander) { std::cout << " Distance: " << p.mWander.mDistance << std::endl; @@ -46,7 +46,7 @@ void printAIPackage(ESM::AIPackage p) std::cout << " Activate Unknown: " << p.mActivate.mUnk << std::endl; } else { - std::cout << " BadPackage: " << boost::format("0x%08x") % p.mType << std::endl; + std::cout << " BadPackage: " << Misc::StringUtils::format("0x%08X", p.mType) << std::endl; } if (!p.mCellName.empty()) @@ -64,7 +64,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) char indicator = rule[2]; std::string type_str = "INVALID"; - std::string func_str = str(boost::format("INVALID=%s") % rule.substr(1,3)); + std::string func_str = Misc::StringUtils::format("INVALID=%s", rule.substr(1,3)); int func; std::istringstream iss(rule.substr(2,2)); iss >> func; @@ -104,7 +104,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) // for all types not qual to one. If this wasn't true, go back to // the error message. if (type != '1' && rule[3] != 'X') - func_str = str(boost::format("INVALID=%s") % rule.substr(1,3)); + func_str = Misc::StringUtils::format("INVALID=%s", rule.substr(1,3)); char oper = rule[4]; std::string oper_str = "??"; @@ -122,8 +122,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) std::ostringstream stream; stream << ss.mValue; - std::string result = str(boost::format("%-12s %-32s %2s %s") - % type_str % func_str % oper_str % stream.str()); + std::string result = Misc::StringUtils::format("%-12s %-32s %2s %s", type_str, func_str, oper_str, stream.str()); return result; } @@ -156,13 +155,13 @@ void printTransport(const std::vector& transport) for (const ESM::Transport::Dest& dest : transport) { std::cout << " Destination Position: " - << boost::format("%12.3f") % dest.mPos.pos[0] << "," - << boost::format("%12.3f") % dest.mPos.pos[1] << "," - << boost::format("%12.3f") % dest.mPos.pos[2] << ")" << std::endl; + << Misc::StringUtils::format("%12.3f", dest.mPos.pos[0]) << "," + << Misc::StringUtils::format("%12.3f", dest.mPos.pos[1]) << "," + << Misc::StringUtils::format("%12.3f", dest.mPos.pos[2]) << ")" << std::endl; std::cout << " Destination Rotation: " - << boost::format("%9.6f") % dest.mPos.rot[0] << "," - << boost::format("%9.6f") % dest.mPos.rot[1] << "," - << boost::format("%9.6f") % dest.mPos.rot[2] << ")" << std::endl; + << Misc::StringUtils::format("%9.6f", dest.mPos.rot[0]) << "," + << Misc::StringUtils::format("%9.6f", dest.mPos.rot[1]) << "," + << Misc::StringUtils::format("%9.6f", dest.mPos.rot[2]) << ")" << std::endl; if (!dest.mCellName.empty()) std::cout << " Destination Cell: " << dest.mCellName << std::endl; } @@ -542,7 +541,7 @@ void Record::print() std::cout << " Water Level: " << mData.mWater << std::endl; } else - std::cout << " Map Color: " << boost::format("0x%08X") % mData.mMapColor << std::endl; + std::cout << " Map Color: " << Misc::StringUtils::format("0x%08X", mData.mMapColor) << std::endl; std::cout << " Water Level Int: " << mData.mWaterInt << std::endl; std::cout << " RefId counter: " << mData.mRefNumCounter << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl; @@ -607,7 +606,7 @@ void Record::print() std::cout << " Flags: " << containerFlags(mData.mFlags) << std::endl; std::cout << " Weight: " << mData.mWeight << std::endl; for (const ESM::ContItem &item : mData.mInventory.mList) - std::cout << " Inventory: Count: " << boost::format("%4d") % item.mCount + std::cout << " Inventory: Count: " << Misc::StringUtils::format("%4d", item.mCount) << " Item: " << item.mItem.toString() << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl; } @@ -653,7 +652,7 @@ void Record::print() std::cout << " Gold: " << mData.mData.mGold << std::endl; for (const ESM::ContItem &item : mData.mInventory.mList) - std::cout << " Inventory: Count: " << boost::format("%4d") % item.mCount + std::cout << " Inventory: Count: " << Misc::StringUtils::format("%4d", item.mCount) << " Item: " << item.mItem.toString() << std::endl; for (const std::string &spell : mData.mSpells.mList) @@ -669,7 +668,7 @@ void Record::print() std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl; std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl; std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl; - std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; + std::cout << " AI Services:" << Misc::StringUtils::format("0x%08X", mData.mAiData.mServices) << std::endl; for (const ESM::AIPackage &package : mData.mAiPackage.mList) printAIPackage(package); @@ -1073,7 +1072,7 @@ void Record::print() } for (const ESM::ContItem &item : mData.mInventory.mList) - std::cout << " Inventory: Count: " << boost::format("%4d") % item.mCount + std::cout << " Inventory: Count: " << Misc::StringUtils::format("%4d", item.mCount) << " Item: " << item.mItem.toString() << std::endl; for (const std::string &spell : mData.mSpells.mList) @@ -1089,7 +1088,7 @@ void Record::print() std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl; std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl; std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl; - std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; + std::cout << " AI Services:" << Misc::StringUtils::format("0x%08X", mData.mAiData.mServices) << std::endl; for (const ESM::AIPackage &package : mData.mAiPackage.mList) printAIPackage(package); @@ -1212,7 +1211,7 @@ void Record::print() std::cout << " ByteCode: "; for (const unsigned char &byte : mData.mScriptData) - std::cout << boost::format("%02X") % (int)(byte); + std::cout << Misc::StringUtils::format("%02X", (int)(byte)); std::cout << std::endl; if (mPrintPlain) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 64285b2a8c..41f82bd2f6 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -340,7 +340,7 @@ namespace MWGui if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(), mPtr)) { std::string msg = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage49")->mValue.getString(); - Misc::StringUtils::replace(msg, "%s", item.getClass().getName(item).c_str(), 2); + msg = Misc::StringUtils::format(msg, item.getClass().getName(item)); MWBase::Environment::get().getWindowManager()->messageBox(msg); MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, item, mPtr, 1); diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index e04ceac7a3..9c8fbfb17d 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -102,7 +102,7 @@ namespace MWGui else message = gmst.find("sNotifyMessage43")->mValue.getString(); - Misc::StringUtils::replace(message, "%d", std::to_string(mDays).c_str(), 2); + message = Misc::StringUtils::format(message, mDays); for (const int& skill : skills) { @@ -112,8 +112,7 @@ namespace MWGui if (skill == ESM::Skill::Sneak || skill == ESM::Skill::Security) skillMsg = gmst.find("sNotifyMessage39")->mValue.getString(); - Misc::StringUtils::replace(skillMsg, "%s", skillName.c_str(), 2); - Misc::StringUtils::replace(skillMsg, "%d", std::to_string(skillValue).c_str(), 2); + skillMsg = Misc::StringUtils::format(skillMsg, skillName, skillValue); message += "\n" + skillMsg; } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index e42db715bc..63da6092e4 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -177,7 +177,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item) if (gem.getRefData().getCount() == 0) { std::string message = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage51")->mValue.getString(); - Misc::StringUtils::replace(message, "%s", gem.getClass().getName(gem).c_str(), 2); + message = Misc::StringUtils::format(message, gem.getClass().getName(gem)); MWBase::Environment::get().getWindowManager()->messageBox(message); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 78d3e7d956..1cdc67f6a1 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -175,7 +175,7 @@ namespace MWGui MyGUI::TextBox* textBox; getWidget(textBox, labelWidgetName); std::string labelCaption = scroller->getUserString("SettingLabelCaption"); - Misc::StringUtils::replaceAll(labelCaption, "%s", value.c_str(), 2); + labelCaption = Misc::StringUtils::format(labelCaption, value); textBox->setCaptionWithReplacing(labelCaption); } } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 15cce183a5..3f39bd11dc 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -172,7 +172,7 @@ namespace MWGui mSpellToDelete = spellId; ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); - Misc::StringUtils::replace(question, "%s", spell->mName.c_str(), 2); + question = Misc::StringUtils::format(question, spell->mName); dialog->askForConfirmation(question); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 88e5be365d..00748a0986 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -309,7 +309,7 @@ namespace MWGui if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(itemStack.mBase.getCellRef().getRefId(), mPtr)) { std::string msg = gmst.find("sNotifyMessage49")->mValue.getString(); - Misc::StringUtils::replace(msg, "%s", itemStack.mBase.getClass().getName(itemStack.mBase).c_str(), 2); + msg = Misc::StringUtils::format(msg, itemStack.mBase.getClass().getName(itemStack.mBase)); MWBase::Environment::get().getWindowManager()->messageBox(msg); MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, itemStack.mBase, mPtr, itemStack.mCount); diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index 805707333e..0c57067754 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -61,7 +61,7 @@ namespace MWMechanics std::string msg = "sMagicContractDisease"; msg = MWBase::Environment::get().getWorld()->getStore().get().find(msg)->mValue.getString(); - Misc::StringUtils::replace(msg, "%s", spell->mName.c_str(), 2); + msg = Misc::StringUtils::format(msg, spell->mName); MWBase::Environment::get().getWindowManager()->messageBox(msg); } } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index ed4a7a4ade..7dca082b68 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -265,8 +265,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas MWBase::Environment::get().getWindowManager()->playSound("skillraise"); std::string message = MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", ""); - Misc::StringUtils::replace(message, "%s", ("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}").c_str(), 2); - Misc::StringUtils::replace(message, "%d", std::to_string(base).c_str(), 2); + message = Misc::StringUtils::format(message, ("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}"), base); if (readBook) message = "#{sBookSkillMessage}\n" + message; diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 28dfab0cdc..faa0e3b093 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -83,7 +83,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) std::string message = MWBase::Environment::get().getWorld()->getStore().get() .find("sNotifyMessage51")->mValue.getString(); - Misc::StringUtils::replace(message, "%s", mTool.getClass().getName(mTool).c_str(), 2); + message = Misc::StringUtils::format(message, mTool.getClass().getName(mTool)); MWBase::Environment::get().getWindowManager()->messageBox(message); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 1e4ac96bca..2de6f75fa0 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -1012,7 +1012,7 @@ namespace MWMechanics { // "X has no effect on you" std::string message = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage50")->mValue.getString(); - Misc::StringUtils::replace(message, "%s", ingredient->mName.c_str(), 2); + message = Misc::StringUtils::format(message, ingredient->mName); MWBase::Environment::get().getWindowManager()->messageBox(message); return false; } diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 38b7482ebf..7116b1c9f3 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -83,13 +83,13 @@ namespace MWScript if (count == 1) { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage60}"); + msgBox = ::Misc::StringUtils::format(msgBox, itemName); } else { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage61}"); - ::Misc::StringUtils::replace(msgBox, "%d", std::to_string(count).c_str(), 2); + msgBox = ::Misc::StringUtils::format(msgBox, count, itemName); } - ::Misc::StringUtils::replace(msgBox, "%s", itemName.c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msgBox, MWGui::ShowInDialogueMode_Only); } } @@ -171,13 +171,13 @@ namespace MWScript if (numRemoved > 1) { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}"); - ::Misc::StringUtils::replace(msgBox, "%d", std::to_string(numRemoved).c_str(), 2); + msgBox = ::Misc::StringUtils::format(msgBox, numRemoved, itemName); } else { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); + msgBox = ::Misc::StringUtils::format(msgBox, itemName); } - ::Misc::StringUtils::replace(msgBox, "%s", itemName.c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msgBox, MWGui::ShowInDialogueMode_Only); } } diff --git a/apps/openmw/mwworld/actionharvest.cpp b/apps/openmw/mwworld/actionharvest.cpp index 83280ec2fa..ff35938b2c 100644 --- a/apps/openmw/mwworld/actionharvest.cpp +++ b/apps/openmw/mwworld/actionharvest.cpp @@ -66,13 +66,12 @@ namespace MWWorld if (itemCount == 1) { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("\n#{sNotifyMessage60}"); - Misc::StringUtils::replace(msgBox, "%s", itemName.c_str(), 2); + msgBox = Misc::StringUtils::format(msgBox, itemName); } else { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("\n#{sNotifyMessage61}"); - Misc::StringUtils::replace(msgBox, "%d", std::to_string(itemCount).c_str(), 2); - Misc::StringUtils::replace(msgBox, "%s", itemName.c_str(), 2); + msgBox = Misc::StringUtils::format(msgBox, itemCount, itemName); } stream << msgBox; diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index f0b488f28e..ba27d47753 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -1,7 +1,6 @@ #ifndef MISC_STRINGOPS_H #define MISC_STRINGOPS_H -#include #include #include @@ -18,6 +17,19 @@ class StringUtils } }; + // Allow to convert complex arguments to C-style strings for format() function + template + static T argument(T value) noexcept + { + return value; + } + + template + static T const * argument(std::basic_string const & value) noexcept + { + return value.c_str(); + } + public: /// Plain and simple locale-unaware toLower. Anything from A to Z is lower-cased, multibyte characters are unchanged. @@ -212,30 +224,26 @@ public: return str; } - /** @brief Replaces the first occurrence of a string in another string. - * - * @param str The string to operate on. - * @param what The string to replace. - * @param with The replacement string. - * @param whatLen The length of the string to replace. - * @param withLen The length of the replacement string. - * - * @return A reference to the string passed in @p str. - */ - static std::string &replace(std::string &str, const char *what, const char *with, - std::size_t whatLen=std::string::npos, std::size_t withLen=std::string::npos) + // Requires some C++11 features: + // 1. std::string needs to be contiguous + // 2. std::snprintf with zero size (second argument) returns an output string size + // 3. variadic templates support + template + static std::string format(const char* fmt, Args const & ... args) { - if (whatLen == std::string::npos) - whatLen = strlen(what); + auto size = std::snprintf(nullptr, 0, fmt, argument(args) ...); + // Note: sprintf also writes a trailing null character. We should remove it. + std::string ret(size+1, '\0'); + std::sprintf(&ret[0], fmt, argument(args) ...); + ret.erase(size); - if (withLen == std::string::npos) - withLen = strlen(with); + return ret; + } - std::size_t found; - if ((found = str.find(what)) != std::string::npos) - str.replace(found, whatLen, with, withLen); - - return str; + template + static std::string format(const std::string& fmt, Args const & ... args) + { + return format(fmt.c_str(), args ...); } };