diff --git a/build/libaegisub/libaegisub.vcxproj b/build/libaegisub/libaegisub.vcxproj index d688c5161..a778d8d15 100644 --- a/build/libaegisub/libaegisub.vcxproj +++ b/build/libaegisub/libaegisub.vcxproj @@ -54,6 +54,7 @@ + @@ -104,6 +105,7 @@ + diff --git a/build/libaegisub/libaegisub.vcxproj.filters b/build/libaegisub/libaegisub.vcxproj.filters index 9608b93dd..71d5059d4 100644 --- a/build/libaegisub/libaegisub.vcxproj.filters +++ b/build/libaegisub/libaegisub.vcxproj.filters @@ -170,6 +170,9 @@ Header Files + + Header Files + Header Files diff --git a/libaegisub/common/color.cpp b/libaegisub/common/color.cpp index 387b27a93..7381e92ff 100644 --- a/libaegisub/common/color.cpp +++ b/libaegisub/common/color.cpp @@ -16,7 +16,7 @@ #include "parser.h" -#include +#include "libaegisub/format.h" namespace agi { @@ -29,11 +29,11 @@ Color::Color(std::string const& str) { } std::string Color::GetAssStyleFormatted() const { - return str(boost::format("&H%02X%02X%02X%02X") % (int)a % (int)b % (int)g % (int)r); + return agi::format("&H%02X%02X%02X%02X", a, b, g, r); } std::string Color::GetAssOverrideFormatted() const { - return str(boost::format("&H%02X%02X%02X&") % (int)b % (int)g % (int)r); + return agi::format("&H%02X%02X%02X&", b, g, r); } std::string Color::GetSsaFormatted() const { @@ -42,12 +42,12 @@ std::string Color::GetSsaFormatted() const { std::string Color::GetHexFormatted(bool rgba) const { if (rgba) - return str(boost::format("#%02X%02X%02X%02X") % (int)r % (int)g % (int)b % (int)a); - return str(boost::format("#%02X%02X%02X") % (int)r % (int)g % (int)b); + return agi::format("#%02X%02X%02X%02X", r, g, b, a); + return agi::format("#%02X%02X%02X", r, g, b); } std::string Color::GetRgbFormatted() const { - return str(boost::format("rgb(%d, %d, %d)") % (int)r % (int)g % (int)b); + return agi::format("rgb(%d, %d, %d)", r, g, b); } bool Color::operator==(Color const& col) const { diff --git a/libaegisub/include/libaegisub/format.h b/libaegisub/include/libaegisub/format.h new file mode 100644 index 000000000..bda534f2a --- /dev/null +++ b/libaegisub/include/libaegisub/format.h @@ -0,0 +1,324 @@ +// Copyright (c) 2014, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ + +#include +#include +#include +#include + +namespace agi { namespace format_detail { +// A static cast which throws at runtime if the cast is invalid rather than +// failing to compile, as with format strings we don't know what type to cast +// to at compile time. +template::value> +struct runtime_cast_helper { + static Out cast(In const&) { throw std::bad_cast(); } +}; + +template +struct runtime_cast_helper { + static Out cast(In const& value) { + return static_cast(value); + } +}; + +template +Out runtime_cast(In const& value) { + return runtime_cast_helper::cast(value); +} + +template +void write_string(std::ostream& out, int, T const& value) { + out << value; +} + +// Check length for string types +inline void write_string(std::ostream& out, int max_len, const char *value) { + if (max_len <= 0) + out << value; + else { + std::streamsize len = 0; + for (; len < max_len && value[len]; ++len) ; + out.write(value, len); + } +} + +inline void write_string(std::ostream& out, int max_len, std::string const& value) { + if (max_len > 0 && static_cast(max_len) < value.size()) + out.write(value.data(), max_len); + else + out << value; +} + +class formatter { + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; + + std::ostream& out; + const char *fmt; + const char *fmt_cur = nullptr; + + bool read_width = false; + bool read_precision = false; + bool pending = false; + + int width = 0; + int precision = 0; + + boost::io::ios_all_saver saver; + + void read_and_append_up_to_next_specifier() { + for (std::streamsize len = 0; ; ++len) { + // Ran out of format specifiers; not an error due to that + // translated strings may not need them all + if (!fmt[len]) { + out.write(fmt, len); + fmt += len; + return; + } + + if (fmt[len] == '%') { + if (fmt[len + 1] == '%') { + out.write(fmt, len); + fmt += len + 1; + len = 0; + continue; + } + + out.write(fmt, len); + fmt += len; + break; + } + } + } + + int read_int() { + int i = 0; + for (; *fmt_cur >= '0' && *fmt_cur <= '9'; ++fmt_cur) + i = 10 * i + (*fmt_cur - '0'); + return i; + } + + void parse_flags() { + for (; ; ++fmt_cur) { + switch (*fmt_cur) { + // Not supported: ' ' (add a space before positive numers to align with negative) + case '#': + out.setf(std::ios::showpoint | std::ios::showbase); + continue; + case '0': + // overridden by left alignment ('-' flag) + if (!(out.flags() & std::ios::left)) { + // Use internal padding so that numeric values are + // formatted correctly, eg -00010 rather than 000-10 + out.fill('0'); + out.setf(std::ios::internal, std::ios::adjustfield); + } + continue; + case '-': + out.fill(' '); + out.setf(std::ios::left, std::ios::adjustfield); + continue; + case '+': + out.setf(std::ios::showpos); + continue; + } + break; + } + } + + void parse_width() { + if (*fmt_cur >= '0' && *fmt_cur <= '9') + width = read_int(); + else if (*fmt_cur == '*') { + read_width = true; + pending = true; + ++fmt_cur; + } + } + + void parse_precision() { + if (*fmt_cur != '.') return; + ++fmt_cur; + + // Ignoring negative precision because it's dumb and pointless + if (*fmt_cur >= '0' && *fmt_cur <= '9') + precision = read_int(); + else if (*fmt_cur == '*') { + read_precision = true; + pending = true; + ++fmt_cur; + } + else + precision = 0; + } + + void parse_length_modifiers() { + // Where "parse" means "skip" since we don't need them + for (char c = *fmt_cur; + c == 'l' || c == 'h' || c == 'L' || c == 'j' || c == 'z' || c == 't'; + c = *++fmt_cur); + } + + void parse_format_specifier() { + width = 0; + precision = -1; + out.fill(' '); + out.unsetf( + std::ios::adjustfield | + std::ios::basefield | + std::ios::boolalpha | + std::ios::floatfield | + std::ios::showbase | + std::ios::showpoint | + std::ios::showpos | + std::ios::uppercase); + + // Don't touch fmt until the specifier is fully applied so that if we + // have insufficient arguments it'll get passed through to the output + fmt_cur = fmt + 1; + + parse_flags(); + parse_width(); + parse_precision(); + parse_length_modifiers(); + } + +public: + formatter(std::ostream& out, const char *fmt) : out(out), fmt(fmt), saver(out) { } + ~formatter() { + // Write remaining formatting string + for (std::streamsize len = 0; ; ++len) { + if (!fmt[len]) { + out.write(fmt, len); + return; + } + + if (fmt[len] == '%' && fmt[len + 1] == '%') { + out.write(fmt, len); + fmt += len + 1; + len = 0; + continue; + } + } + } + + template + void operator()(T&& value) { + if (!pending) { + read_and_append_up_to_next_specifier(); + if (!*fmt) return; + parse_format_specifier(); + } + + if (read_width) { + width = runtime_cast(value); + read_width = false; + return; + } + + if (read_precision) { + precision = runtime_cast(value); + read_precision = false; + return; + } + pending = false; + + if (width < 0) { + out.fill(' '); + out.setf(std::ios::left, std::ios::adjustfield); + width = -width; + } + out.width(width); + out.precision(precision < 0 ? 6 : precision); + + char c = *fmt_cur ? fmt_cur[0] : 's'; + if (c >= 'A' && c <= 'Z') { + out.setf(std::ios::uppercase); + c += 'a' - 'A'; + } + + switch (c) { + case 'c': + out.setf(std::ios::dec, std::ios::basefield); + out << runtime_cast(value); + break; + case 'd': case 'i': + out.setf(std::ios::dec, std::ios::basefield); + out << runtime_cast(value); + break; + case 'o': + out.setf(std::ios::oct, std::ios::basefield); + out << runtime_cast(value); + break; + case 'x': + out.setf(std::ios::hex, std::ios::basefield); + out << runtime_cast(value); + break; + case 'u': + out.setf(std::ios::dec, std::ios::basefield); + out << runtime_cast(value); + break; + case 'e': + out.setf(std::ios::scientific, std::ios::floatfield); + out.setf(std::ios::dec, std::ios::basefield); + out << runtime_cast(value); + break; + case 'f': + out.setf(std::ios::fixed, std::ios::floatfield); + out << runtime_cast(value); + break; + case 'g': + out.setf(std::ios::dec, std::ios::basefield); + out.flags(out.flags() & ~std::ios::floatfield); + out << runtime_cast(value); + break; + case 'p': + out.setf(std::ios::hex, std::ios::basefield); + out << runtime_cast(value); + break; + default: // s and other + out.setf(std::ios::boolalpha); + write_string(out, precision, value); + break; + } + + fmt = *fmt_cur ? fmt_cur + 1 : fmt_cur; + } +}; + +// Base case for variadic template recursion +inline void format(formatter&&) { } + +template +void format(formatter&& fmt, T&& first, Args&&... rest) { + fmt(first); + format(std::move(fmt), std::forward(rest)...); +} +} // namespace format_detail + +template +void format(std::ostream& out, const char *fmt, Args&&... args) { + format(format_detail::formatter(out, fmt), std::forward(args)...); +} + +template +std::string format(const char *fmt, Args&&... args) { + boost::interprocess::basic_vectorstream out; + format(out, fmt, std::forward(args)...); + return out.vector(); +} +} diff --git a/libaegisub/lua/utils.cpp b/libaegisub/lua/utils.cpp index cab65aef8..8a5770e3d 100644 --- a/libaegisub/lua/utils.cpp +++ b/libaegisub/lua/utils.cpp @@ -16,11 +16,11 @@ #include "libaegisub/lua/utils.h" +#include "libaegisub/format.h" #include "libaegisub/log.h" #include #include -#include #include #include @@ -170,9 +170,9 @@ int add_stack_trace(lua_State *L) { else if (*ar.what == 'C') function = '?'; else if (!*ar.namewhat) - function = str(boost::format("") % real_line(ar.linedefined) % real_line(ar.lastlinedefined - 1)); + function = agi::format("", real_line(ar.linedefined), real_line(ar.lastlinedefined - 1)); - frames.emplace_back(str(boost::format(" File \"%s\", line %d\n%s") % file % real_line(ar.currentline) % function)); + frames.emplace_back(agi::format(" File \"%s\", line %d\n%s", file, real_line(ar.currentline), function)); } } diff --git a/libaegisub/windows/access.cpp b/libaegisub/windows/access.cpp index 01d0df643..d817ef553 100644 --- a/libaegisub/windows/access.cpp +++ b/libaegisub/windows/access.cpp @@ -18,12 +18,13 @@ #include +#include +#include #include #include #include #include -#include #include @@ -63,7 +64,7 @@ void Check(fs::path const& file, acs::Type type) { case ERROR_ACCESS_DENIED: throw fs::ReadDenied(file); default: - throw fs::FileSystemUnknownError(str(boost::format("Unexpected error when getting attributes for \"%s\": %s") % file % util::ErrorString(GetLastError()))); + throw fs::FileSystemUnknownError(agi::format("Unexpected error when getting attributes for \"%s\": %s", file, util::ErrorString(GetLastError()))); } } diff --git a/src/ass_export_filter.cpp b/src/ass_export_filter.cpp index 65ee02715..4f092d351 100644 --- a/src/ass_export_filter.cpp +++ b/src/ass_export_filter.cpp @@ -34,7 +34,7 @@ #include "ass_export_filter.h" -#include +#include static FilterList& filters() { static FilterList instance; @@ -53,7 +53,7 @@ void AssExportFilterChain::Register(std::unique_ptr filter) { std::string name = filter->name; // Find a unique name while (GetFilter(name)) - name = str(boost::format("%s (%d)") % filter->name % filter_copy++); + name = agi::format("%s (%d)", filter->name, filter_copy++); filter->name = name; diff --git a/src/ass_karaoke.cpp b/src/ass_karaoke.cpp index 7d9c100f0..fab0621ca 100644 --- a/src/ass_karaoke.cpp +++ b/src/ass_karaoke.cpp @@ -18,7 +18,8 @@ #include "ass_dialogue.h" -#include +#include + #include #include @@ -26,7 +27,7 @@ std::string AssKaraoke::Syllable::GetText(bool k_tag) const { std::string ret; if (k_tag) - ret = str(boost::format("{%s%d}") % tag_type % ((duration + 5) / 10)); + ret = agi::format("{%s%d}", tag_type, ((duration + 5) / 10)); size_t idx = 0; for (auto const& ovr : ovr_tags) { diff --git a/src/ass_override.cpp b/src/ass_override.cpp index 2491ff6c7..abcca5531 100644 --- a/src/ass_override.cpp +++ b/src/ass_override.cpp @@ -38,12 +38,12 @@ #include "utils.h" #include +#include #include #include #include #include -#include #include #include #include @@ -128,7 +128,7 @@ template<> void AssOverrideParameter::Set(std::string new_value) { template<> void AssOverrideParameter::Set(int new_value) { if (classification == AssParameterClass::ALPHA) - Set(str(boost::format("&H%02X&") % mid(0, new_value, 255))); + Set(agi::format("&H%02X&", mid(0, new_value, 255))); else Set(std::to_string(new_value)); } diff --git a/src/ass_style.cpp b/src/ass_style.cpp index 0fd93413b..901ddbeab 100644 --- a/src/ass_style.cpp +++ b/src/ass_style.cpp @@ -37,10 +37,10 @@ #include "subtitle_format.h" #include "utils.h" +#include #include #include -#include #include #include @@ -175,17 +175,17 @@ void AssStyle::UpdateData() { replace(name.begin(), name.end(), ',', ';'); replace(font.begin(), font.end(), ',', ';'); - data = str(boost::format("Style: %s,%s,%g,%s,%s,%s,%s,%d,%d,%d,%d,%g,%g,%g,%g,%d,%g,%g,%i,%i,%i,%i,%i") - % name % font % fontsize - % primary.GetAssStyleFormatted() - % secondary.GetAssStyleFormatted() - % outline.GetAssStyleFormatted() - % shadow.GetAssStyleFormatted() - % (bold? -1 : 0) % (italic ? -1 : 0) - % (underline ? -1 : 0) % (strikeout ? -1 : 0) - % scalex % scaley % spacing % angle - % borderstyle % outline_w % shadow_w % alignment - % Margin[0] % Margin[1] % Margin[2] % encoding); + data = agi::format("Style: %s,%s,%g,%s,%s,%s,%s,%d,%d,%d,%d,%g,%g,%g,%g,%d,%g,%g,%i,%i,%i,%i,%i", + name, font, fontsize, + primary.GetAssStyleFormatted(), + secondary.GetAssStyleFormatted(), + outline.GetAssStyleFormatted(), + shadow.GetAssStyleFormatted(), + (bold? -1 : 0), (italic ? -1 : 0), + (underline ? -1 : 0), (strikeout ? -1 : 0), + scalex, scaley, spacing, angle, + borderstyle, outline_w, shadow_w, alignment, + Margin[0], Margin[1], Margin[2], encoding); } void AssStyle::GetEncodings(wxArrayString &encodingStrings) { diff --git a/src/ass_time.cpp b/src/ass_time.cpp index 070bbd5eb..585fa7cf7 100644 --- a/src/ass_time.cpp +++ b/src/ass_time.cpp @@ -23,12 +23,12 @@ #include "utils.h" +#include #include #include #include #include -#include #include AssTime::AssTime(int time) : time(mid(0, time, 10 * 60 * 60 * 1000 - 1)) { } @@ -94,7 +94,7 @@ SmpteFormatter::SmpteFormatter(agi::vfr::Framerate fps, std::string sep) std::string SmpteFormatter::ToSMPTE(AssTime time) const { int h=0, m=0, s=0, f=0; fps.SmpteAtTime(time, &h, &m, &s, &f); - return str(boost::format("%02d%s%02d%s%02d%c%02d") % h % sep % m % sep % s % sep % f); + return agi::format("%02d%s%02d%s%02d%c%02d", h, sep, m, sep, s, sep, f); } AssTime SmpteFormatter::FromSMPTE(std::string const& str) const { diff --git a/src/audio_provider_hd.cpp b/src/audio_provider_hd.cpp index 2ad845b01..bc191af82 100644 --- a/src/audio_provider_hd.cpp +++ b/src/audio_provider_hd.cpp @@ -20,12 +20,12 @@ #include "options.h" #include +#include #include #include #include #include -#include #include #include @@ -64,9 +64,8 @@ public: if ((uint64_t)num_samples * bytes_per_sample > agi::fs::FreeSpace(cache_dir)) throw agi::AudioCacheOpenError("Not enough free disk space in " + cache_dir.string() + " to cache the audio", nullptr); - auto filename = str(boost::format("audio-%lld-%lld") - % (long long)time(nullptr) - % (long long)boost::interprocess::ipcdetail::get_current_process_id()); + auto filename = agi::format("audio-%lld-%lld", time(nullptr), + boost::interprocess::ipcdetail::get_current_process_id()); file = agi::make_unique(cache_dir / filename, num_samples * bytes_per_sample); decoder = std::thread([&] { diff --git a/src/auto4_base.cpp b/src/auto4_base.cpp index f113a544e..f2af62ba7 100644 --- a/src/auto4_base.cpp +++ b/src/auto4_base.cpp @@ -39,13 +39,13 @@ #include "subs_controller.h" #include +#include #include #include #include #include #include -#include #include #include @@ -490,7 +490,7 @@ namespace Automation4 { std::string filter(fact->GetFilenamePattern()); boost::replace_all(filter, ",", ";"); - fnfilter += str(boost::format("%s scripts (%s)|%s|") % fact->GetEngineName() % fact->GetFilenamePattern() % filter); + fnfilter += agi::format("%s scripts (%s)|%s|", fact->GetEngineName(), fact->GetFilenamePattern(), filter); catchall += filter + ";"; } fnfilter += from_wx(_("All Files")) + " (*.*)|*.*"; diff --git a/src/auto4_lua.cpp b/src/auto4_lua.cpp index 4ee7dae6f..2d3569963 100644 --- a/src/auto4_lua.cpp +++ b/src/auto4_lua.cpp @@ -50,17 +50,17 @@ #include "video_controller.h" #include "utils.h" +#include #include #include #include -#include #include +#include #include #include #include #include -#include #include #include #include @@ -475,7 +475,7 @@ namespace { // don't thread this, as there's no point in it and it seems to break on wx 2.8.3, for some reason if (lua_pcall(L, 0, 0, 0)) { // error occurred, assumed to be on top of Lua stack - description = str(boost::format("Error initialising Lua script \"%s\":\n\n%s") % GetPrettyFilename().string() % get_string_or_default(L, -1)); + description = agi::format("Error initialising Lua script \"%s\":\n\n%s", GetPrettyFilename().string(), get_string_or_default(L, -1)); lua_pop(L, 1); return; } @@ -655,7 +655,7 @@ namespace { , cmd_type(cmd::COMMAND_NORMAL) { lua_getfield(L, LUA_REGISTRYINDEX, "filename"); - cmd_name = str(boost::format("automation/lua/%s/%s") % check_string(L, -1) % check_string(L, 1)); + cmd_name = agi::format("automation/lua/%s/%s", check_string(L, -1), check_string(L, 1)); if (!lua_isfunction(L, 3)) error(L, "The macro processing function must be a function"); diff --git a/src/command/edit.cpp b/src/command/edit.cpp index 288a2dfd7..196cc79d3 100644 --- a/src/command/edit.cpp +++ b/src/command/edit.cpp @@ -50,12 +50,12 @@ #include "../video_controller.h" #include +#include #include #include #include #include -#include #include #include #include @@ -358,7 +358,7 @@ void show_color_picker(const agi::Context *c, agi::Color (AssStyle::*field), con for (auto& line : lines) { int shift = line.second.set_tag(tag, new_color.GetAssOverrideFormatted(), norm_sel_start, sel_start); if (new_color.a != line.first.a) { - shift += line.second.set_tag(alpha, str(boost::format("&H%02X&") % (int)new_color.a), norm_sel_start, sel_start + shift); + shift += line.second.set_tag(alpha, agi::format("&H%02X&", (int)new_color.a), norm_sel_start, sel_start + shift); line.first.a = new_color.a; } diff --git a/src/command/video.cpp b/src/command/video.cpp index 49e4b2be0..115aa6c86 100644 --- a/src/command/video.cpp +++ b/src/command/video.cpp @@ -50,6 +50,7 @@ #include "../video_display.h" #include "../video_frame.h" +#include #include #include #include @@ -58,7 +59,6 @@ #include #include #include -#include #include #include @@ -487,7 +487,7 @@ static void save_snapshot(agi::Context *c, bool raw) { int session_shot_count = 1; std::string path; do { - path = str(boost::format("%s_%03d_%d.png") % basepath.string() % session_shot_count++ % c->videoController->GetFrameN()); + path = agi::format("%s_%03d_%d.png", basepath.string(), session_shot_count++, c->videoController->GetFrameN()); } while (agi::fs::FileExists(path)); get_image(c, raw).SaveFile(to_wx(path), wxBITMAP_TYPE_PNG); diff --git a/src/crash_writer.cpp b/src/crash_writer.cpp index 336301f70..ab521be5f 100644 --- a/src/crash_writer.cpp +++ b/src/crash_writer.cpp @@ -18,10 +18,10 @@ #include "version.h" +#include #include #include -#include #include #include @@ -41,8 +41,8 @@ public: if (!fp.good()) return; fp << util::strftime("--- %y-%m-%d %H:%M:%S ------------------\n"); - fp << boost::format("VER - %s\n") % GetAegisubLongVersionString(); - fp << boost::format("FTL - Beginning stack dump for \"%s\": \n") % cause; + fp << agi::format("VER - %s\n", GetAegisubLongVersionString()); + fp << agi::format("FTL - Beginning stack dump for \"%s\": \n", cause); } ~StackWalker() { @@ -55,9 +55,9 @@ public: void OnStackFrame(wxStackFrame const& frame) override final { if (!fp.good()) return; - fp << boost::format("%03u - %p: %s") % frame.GetLevel() % frame.GetAddress() % frame.GetName().utf8_str().data(); + fp << agi::format("%03u - %p: %s", frame.GetLevel(), frame.GetAddress(), frame.GetName().utf8_str().data()); if (frame.HasSourceLocation()) - fp << boost::format(" on %s:%u") % frame.GetFileName().utf8_str().data() % frame.GetLine(); + fp << agi::format(" on %s:%u", frame.GetFileName().utf8_str().data(), frame.GetLine()); fp << "\n"; } @@ -83,8 +83,8 @@ void Write(std::string const& error) { boost::filesystem::ofstream file(crashlog_path, std::ios::app); if (file.is_open()) { file << util::strftime("--- %y-%m-%d %H:%M:%S ------------------\n"); - file << boost::format("VER - %s\n") % GetAegisubLongVersionString(); - file << boost::format("EXC - Aegisub has crashed with unhandled exception \"%s\".\n") % error; + file << agi::format("VER - %s\n", GetAegisubLongVersionString()); + file << agi::format("EXC - Aegisub has crashed with unhandled exception \"%s\".\n", error); file << "----------------------------------------\n\n"; file.close(); } diff --git a/src/crash_writer_minidump.cpp b/src/crash_writer_minidump.cpp index 526df912f..5481273cd 100644 --- a/src/crash_writer_minidump.cpp +++ b/src/crash_writer_minidump.cpp @@ -18,13 +18,13 @@ #include "version.h" +#include #include #include #include #include #include -#include #include #include #include @@ -143,10 +143,9 @@ void Write(std::string const& error) { boost::filesystem::ofstream file(crashlog_path, std::ios::app); if (file.is_open()) { file << agi::util::strftime("--- %y-%m-%d %H:%M:%S ------------------\n"); - file << boost::format("VER - %s\n") % GetAegisubLongVersionString(); - file << boost::format("EXC - Aegisub has crashed with unhandled exception \"%s\".\n") % error; + agi::format(file, "VER - %s\n", GetAegisubLongVersionString()); + agi::format(file, "EXC - Aegisub has crashed with unhandled exception \"%s\".\n", error); file << "----------------------------------------\n\n"; - file.close(); } } } diff --git a/src/dialog_version_check.cpp b/src/dialog_version_check.cpp index 3339d4d37..8aef014f0 100644 --- a/src/dialog_version_check.cpp +++ b/src/dialog_version_check.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -47,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -287,21 +287,20 @@ void DoCheck(bool interactive) { if (!stream) throw VersionCheckError(from_wx(_("Could not connect to updates server."))); - stream << boost::format( + stream << agi::format( "GET %s?rev=%d&rel=%d&os=%s&lang=%s&aegilang=%s HTTP/1.0\r\n" "User-Agent: Aegisub %s\r\n" "Host: %s\r\n" "Accept: */*\r\n" - "Connection: close\r\n\r\n") - % UPDATE_CHECKER_BASE_URL - % GetSVNRevision() - % (GetIsOfficialRelease() ? 1 : 0) - % GetOSShortName() - % GetSystemLanguage() - % GetAegisubLanguage() - % GetAegisubLongVersionString() - % UPDATE_CHECKER_SERVER - ; + "Connection: close\r\n\r\n" + , UPDATE_CHECKER_BASE_URL + , GetSVNRevision() + , (GetIsOfficialRelease() ? 1 : 0) + , GetOSShortName() + , GetSystemLanguage() + , GetAegisubLanguage() + , GetAegisubLongVersionString() + , UPDATE_CHECKER_SERVER); std::string http_version; stream >> http_version; diff --git a/src/main.cpp b/src/main.cpp index 4ee7b3ede..357f2eb30 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,6 +55,7 @@ #include "version.h" #include +#include #include #include #include @@ -62,7 +63,6 @@ #include #include -#include #include #include #include @@ -378,7 +378,7 @@ static void UnhandledExeception(bool stackWalk, agi::Context *c) { agi::fs::CreateDirectory(path); auto filename = c->subsController->Filename().stem(); - filename.replace_extension(str(boost::format("%s.ass") % agi::util::strftime("%Y-%m-%d-%H-%M-%S"))); + filename.replace_extension(agi::format("%s.ass", agi::util::strftime("%Y-%m-%d-%H-%M-%S"))); path /= filename; c->subsController->Save(path); diff --git a/src/mkv_wrap.cpp b/src/mkv_wrap.cpp index 1fa1cfab7..78aee3f6d 100644 --- a/src/mkv_wrap.cpp +++ b/src/mkv_wrap.cpp @@ -42,11 +42,11 @@ #include "MatroskaParser.h" #include +#include #include #include #include -#include #include #include #include @@ -143,18 +143,18 @@ static void read_subtitles(agi::ProgressSink *ps, MatroskaFile *file, MkvStdIO * subList.emplace_back( boost::lexical_cast(str_range(readBuf, first)), - str(boost::format("Dialogue: %d,%s,%s,%s") - % boost::lexical_cast(str_range(first + 1, second)) - % subStart.GetAssFormated() - % subEnd.GetAssFormated() - % str_range(second + 1, readBufEnd))); + agi::format("Dialogue: %d,%s,%s,%s" + , boost::lexical_cast(str_range(first + 1, second)) + , subStart.GetAssFormated() + , subEnd.GetAssFormated() + , str_range(second + 1, readBufEnd))); } // Process SRT else { - auto line = str(boost::format("Dialogue: 0,%s,%s,Default,,0,0,0,,%s") - % subStart.GetAssFormated() - % subEnd.GetAssFormated() - % str_range(readBuf, readBufEnd)); + auto line = agi::format("Dialogue: 0,%s,%s,Default,,0,0,0,,%s" + , subStart.GetAssFormated() + , subEnd.GetAssFormated() + , str_range(readBuf, readBufEnd)); boost::replace_all(line, "\r\n", "\\N"); boost::replace_all(line, "\r", "\\N"); boost::replace_all(line, "\n", "\\N"); @@ -191,7 +191,7 @@ void MatroskaWrapper::GetSubtitles(agi::fs::path const& filename, AssFile *targe std::string CodecID(trackInfo->CodecID); if (CodecID == "S_TEXT/SSA" || CodecID == "S_TEXT/ASS" || CodecID == "S_TEXT/UTF8") { tracksFound.push_back(track); - tracksNames.emplace_back(str(boost::format("%d (%s %s)") % track % CodecID % trackInfo->Language)); + tracksNames.emplace_back(agi::format("%d (%s %s)", track, CodecID, trackInfo->Language)); if (trackInfo->Name) { tracksNames.back() += ": "; tracksNames.back() += trackInfo->Name; diff --git a/src/spellchecker_hunspell.cpp b/src/spellchecker_hunspell.cpp index 17000db49..53ee66f84 100644 --- a/src/spellchecker_hunspell.cpp +++ b/src/spellchecker_hunspell.cpp @@ -24,6 +24,7 @@ #include "options.h" #include +#include #include #include #include @@ -31,7 +32,6 @@ #include #include -#include #include #include @@ -177,8 +177,8 @@ std::vector HunspellSpellChecker::GetLanguageList() { } static bool check_path(agi::fs::path const& path, std::string const& language, agi::fs::path& aff, agi::fs::path& dic) { - aff = path/str(boost::format("%s.aff") % language); - dic = path/str(boost::format("%s.dic") % language); + aff = path/agi::format("%s.aff", language); + dic = path/agi::format("%s.dic", language); return agi::fs::FileExists(aff) && agi::fs::FileExists(dic); } @@ -204,7 +204,7 @@ void HunspellSpellChecker::OnLanguageChanged() { conv = agi::make_unique("utf-8", hunspell->get_dic_encoding()); rconv = agi::make_unique(hunspell->get_dic_encoding(), "utf-8"); - userDicPath = config::path->Decode("?user/dictionaries")/str(boost::format("user_%s.dic") % language); + userDicPath = config::path->Decode("?user/dictionaries")/agi::format("user_%s.dic", language); ReadUserDictionary(); for (auto const& word : customWords) { diff --git a/src/string_codec.cpp b/src/string_codec.cpp index 6e19c7fbb..6ad7c7ca7 100644 --- a/src/string_codec.cpp +++ b/src/string_codec.cpp @@ -37,15 +37,14 @@ #include "string_codec.h" -#include +#include std::string inline_string_encode(const std::string &input) { std::string output; output.reserve(input.size()); - auto format = boost::format("#%02X"); for (char c : input) { if (c <= 0x1F || c == 0x23 || c == 0x2C || c == 0x3A || c == 0x7C) - output += str(format % (int)(unsigned char)c); + output += agi::format("#%02X", (unsigned char)c); else output += c; } diff --git a/src/subs_controller.cpp b/src/subs_controller.cpp index 5f0a80f0f..358811ba2 100644 --- a/src/subs_controller.cpp +++ b/src/subs_controller.cpp @@ -31,11 +31,11 @@ #include "subtitle_format.h" #include "text_selection_controller.h" +#include #include #include #include -#include #include namespace { @@ -277,7 +277,7 @@ agi::fs::path SubsController::AutoSave() { if (name.empty()) name = "Untitled"; - path /= str(boost::format("%s.%s.AUTOSAVE.ass") % name.string() % agi::util::strftime("%Y-%m-%d-%H-%M-%S")); + path /= agi::format("%s.%s.AUTOSAVE.ass", name.string(), agi::util::strftime("%Y-%m-%d-%H-%M-%S")); SubtitleFormat::GetWriter(path)->WriteFile(context->ass.get(), path, 0); autosaved_commit_id = commit_id; diff --git a/src/subtitle_format_encore.cpp b/src/subtitle_format_encore.cpp index 59d23be27..865dda902 100644 --- a/src/subtitle_format_encore.cpp +++ b/src/subtitle_format_encore.cpp @@ -38,7 +38,7 @@ #include "ass_file.h" #include "text_file_writer.h" -#include +#include EncoreSubtitleFormat::EncoreSubtitleFormat() : SubtitleFormat("Adobe Encore") @@ -70,5 +70,5 @@ void EncoreSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& fi int i = 0; TextFileWriter file(filename, "UTF-8"); for (auto const& current : copy.Events) - file.WriteLineToFile(str(boost::format("%i %s %s %s") % ++i % ft.ToSMPTE(current.Start) % ft.ToSMPTE(current.End) % current.Text)); + file.WriteLineToFile(agi::format("%i %s %s %s", ++i, ft.ToSMPTE(current.Start), ft.ToSMPTE(current.End), current.Text)); } diff --git a/src/subtitle_format_microdvd.cpp b/src/subtitle_format_microdvd.cpp index af8f4bcf6..d2e981bc1 100644 --- a/src/subtitle_format_microdvd.cpp +++ b/src/subtitle_format_microdvd.cpp @@ -41,11 +41,11 @@ #include "text_file_reader.h" #include "text_file_writer.h" +#include #include #include #include -#include #include #include @@ -135,13 +135,13 @@ void MicroDVDSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& // Write FPS line if (!fps.IsVFR()) - file.WriteLineToFile(str(boost::format("{1}{1}%.6f") % fps.FPS())); + file.WriteLineToFile(agi::format("{1}{1}%.6f", fps.FPS())); // Write lines for (auto const& current : copy.Events) { int start = fps.FrameAtTime(current.Start, agi::vfr::START); int end = fps.FrameAtTime(current.End, agi::vfr::END); - file.WriteLineToFile(str(boost::format("{%i}{%i}%s") % start % end % boost::replace_all_copy(current.Text.get(), "\\N", "|"))); + file.WriteLineToFile(agi::format("{%i}{%i}%s", start, end, boost::replace_all_copy(current.Text.get(), "\\N", "|"))); } } diff --git a/src/subtitle_format_srt.cpp b/src/subtitle_format_srt.cpp index ac89d0744..2b8817d35 100644 --- a/src/subtitle_format_srt.cpp +++ b/src/subtitle_format_srt.cpp @@ -41,13 +41,13 @@ #include "text_file_reader.h" #include "text_file_writer.h" +#include #include #include #include #include #include -#include #include #include @@ -200,11 +200,11 @@ public: // handle the attributes if (attr_name == "face") - new_attribs.face = str(boost::format("{\\fn%s}") % attr_value); + new_attribs.face = agi::format("{\\fn%s}", attr_value); else if (attr_name == "size") - new_attribs.size = str(boost::format("{\\fs%s}") % attr_value); + new_attribs.size = agi::format("{\\fs%s}", attr_value); else if (attr_name == "color") - new_attribs.color = str(boost::format("{\\c%s}") % agi::Color(attr_value).GetAssOverrideFormatted()); + new_attribs.color = agi::format("{\\c%s}", agi::Color(attr_value).GetAssOverrideFormatted()); // remove this attribute to prepare for the next tag_attrs = result.suffix().str(); @@ -320,7 +320,7 @@ milliseconds: std::string WriteSRTTime(AssTime const& ts) { - return str(boost::format("%02d:%02d:%02d,%03d") % ts.GetTimeHours() % ts.GetTimeMinutes() % ts.GetTimeSeconds() % ts.GetTimeMiliseconds()); + return agi::format("%02d:%02d:%02d,%03d", ts.GetTimeHours(), ts.GetTimeMinutes(), ts.GetTimeSeconds(), ts.GetTimeMiliseconds()); } } @@ -382,11 +382,11 @@ void SRTSubtitleFormat::ReadFile(AssFile *target, agi::fs::path const& filename, if (regex_search(text_line, timestamp_match, timestamp_regex)) goto found_timestamps; - throw SRTParseError(str(boost::format("Parsing SRT: Expected subtitle index at line %d") % line_num), nullptr); + throw SRTParseError(agi::format("Parsing SRT: Expected subtitle index at line %d", line_num), nullptr); case STATE_TIMESTAMP: if (!regex_search(text_line, timestamp_match, timestamp_regex)) - throw SRTParseError(str(boost::format("Parsing SRT: Expected timestamp pair at line %d") % line_num), nullptr); + throw SRTParseError(agi::format("Parsing SRT: Expected timestamp pair at line %d", line_num), nullptr); found_timestamps: if (line) { // finalize active line @@ -524,9 +524,9 @@ std::string SRTSubtitleFormat::ConvertTags(const AssDialogue *diag) const { if (it != tag_states.end()) { bool temp = tag.Params[0].Get(false); if (temp && !it->second) - final += str(boost::format("<%c>") % it->first); + final += agi::format("<%c>", it->first); if (!temp && it->second) - final += str(boost::format("") % it->first); + final += agi::format("", it->first); it->second = temp; } } @@ -541,7 +541,7 @@ std::string SRTSubtitleFormat::ConvertTags(const AssDialogue *diag) const { // Otherwise unclosed overrides might affect lines they shouldn't, see bug #809 for example for (auto it : tag_states) { if (it.second) - final += str(boost::format("") % it.first); + final += agi::format("", it.first); } return final; diff --git a/src/subtitle_format_ssa.cpp b/src/subtitle_format_ssa.cpp index e7a2b3570..3a66f2856 100644 --- a/src/subtitle_format_ssa.cpp +++ b/src/subtitle_format_ssa.cpp @@ -24,9 +24,10 @@ #include "text_file_writer.h" #include "version.h" +#include + #include #include -#include namespace { std::string replace_commas(std::string str) { @@ -54,14 +55,14 @@ void SsaSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filen file.WriteLineToFile("[V4 Styles]"); file.WriteLineToFile("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding"); for (auto const& line : src->Styles) - file.WriteLineToFile(str(boost::format("Style: %s,%s,%g,%s,%s,0,%s,%d,%d,%d,%g,%g,%d,%d,%d,%d,0,%i") - % line.name % line.font % line.fontsize - % line.primary.GetSsaFormatted() - % line.secondary.GetSsaFormatted() - % line.shadow.GetSsaFormatted() - % (line.bold? -1 : 0) % (line.italic ? -1 : 0) - % line.borderstyle % line.outline_w % line.shadow_w % AssStyle::AssToSsa(line.alignment) - % line.Margin[0] % line.Margin[1] % line.Margin[2] % line.encoding)); + file.WriteLineToFile(agi::format("Style: %s,%s,%g,%s,%s,0,%s,%d,%d,%d,%g,%g,%d,%d,%d,%d,0,%i" + , line.name, line.font, line.fontsize + , line.primary.GetSsaFormatted() + , line.secondary.GetSsaFormatted() + , line.shadow.GetSsaFormatted() + , (line.bold? -1 : 0), (line.italic ? -1 : 0) + , line.borderstyle, line.outline_w, line.shadow_w, AssStyle::AssToSsa(line.alignment) + , line.Margin[0], line.Margin[1], line.Margin[2], line.encoding)); file.WriteLineToFile(""); file.WriteLineToFile("[Fonts]"); @@ -81,11 +82,11 @@ void SsaSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filen file.WriteLineToFile("[Events]"); file.WriteLineToFile("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"); for (auto const& line : src->Events) - file.WriteLineToFile(str(boost::format("%s: Marked=0,%s,%s,%s,%s,%d,%d,%d,%s,%s") - % (line.Comment ? "Comment" : "Dialogue") - % line.Start.GetAssFormated() % line.End.GetAssFormated() - % replace_commas(line.Style) % replace_commas(line.Actor) - % line.Margin[0] % line.Margin[1] % line.Margin[2] - % replace_commas(line.Effect) - % strip_newlines(line.Text))); + file.WriteLineToFile(agi::format("%s: Marked=0,%s,%s,%s,%s,%d,%d,%d,%s,%s" + , (line.Comment ? "Comment" : "Dialogue") + , line.Start.GetAssFormated(), line.End.GetAssFormated() + , replace_commas(line.Style), replace_commas(line.Actor) + , line.Margin[0], line.Margin[1], line.Margin[2] + , replace_commas(line.Effect) + , strip_newlines(line.Text))); } diff --git a/src/subtitle_format_transtation.cpp b/src/subtitle_format_transtation.cpp index d1a68216c..8ac2c7ba7 100644 --- a/src/subtitle_format_transtation.cpp +++ b/src/subtitle_format_transtation.cpp @@ -40,7 +40,7 @@ #include "ass_time.h" #include "text_file_writer.h" -#include +#include TranStationSubtitleFormat::TranStationSubtitleFormat() : SubtitleFormat("TranStation") @@ -109,6 +109,6 @@ std::string TranStationSubtitleFormat::ConvertLine(AssFile *file, const AssDialo if (nextl_start > 0 && end == nextl_start) end = fps.TimeAtFrame(fps.FrameAtTime(end, agi::vfr::END) - 1, agi::vfr::END); - std::string header = str(boost::format("SUB[%i%s%s %s>%s]\r\n") % valign % halign % type % ft.ToSMPTE(current->Start) % ft.ToSMPTE(end)); + std::string header = agi::format("SUB[%i%s%s %s>%s]\r\n", valign, halign, type, ft.ToSMPTE(current->Start), ft.ToSMPTE(end)); return header + current->Text.get(); } diff --git a/src/thesaurus.cpp b/src/thesaurus.cpp index 02f4ae811..dbf5be3a4 100644 --- a/src/thesaurus.cpp +++ b/src/thesaurus.cpp @@ -23,16 +23,16 @@ #include "options.h" -#include -#include -#include - #include +#include #include #include +#include #include #include -#include + +#include +#include Thesaurus::Thesaurus() : lang_listener(OPT_SUB("Tool/Thesaurus/Language", &Thesaurus::OnLanguageChanged, this)) @@ -76,8 +76,8 @@ std::vector Thesaurus::GetLanguageList() const { } static bool check_path(agi::fs::path const& path, std::string const& language, agi::fs::path& idx, agi::fs::path& dat) { - idx = path/str(boost::format("th_%s.idx") % language); - dat = path/str(boost::format("th_%s.dat") % language); + idx = path/agi::format("th_%s.idx", language); + dat = path/agi::format("th_%s.dat", language); return agi::fs::FileExists(idx) && agi::fs::FileExists(dat); } diff --git a/src/utils.cpp b/src/utils.cpp index 0c17fa0fd..f6cf5497b 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -27,11 +27,6 @@ // // Aegisub Project http://www.aegisub.org/ -/// @file utils.cpp -/// @brief Misc. utility functions -/// @ingroup utility -/// - #include "utils.h" #include "compat.h" @@ -39,6 +34,7 @@ #include "retina_helper.h" #include +#include #include #include @@ -46,7 +42,6 @@ #include #endif #include -#include #include #include #include @@ -81,7 +76,7 @@ wxString PrettySize(int bytes) { } std::string float_to_string(double val) { - std::string s = str(boost::format("%.3f") % val); + std::string s = agi::format("%.3f", val); size_t pos = s.find_last_not_of("0"); if (pos != s.find(".")) ++pos; s.erase(begin(s) + pos, end(s)); @@ -184,8 +179,8 @@ void CleanCache(agi::fs::path const& directory, std::string const& file_type, ui } if (cachefiles.size() <= max_files && total_size <= max_size) { - LOG_D("utils/clean_cache") << boost::format("cache does not need cleaning (maxsize=%d, cursize=%d, maxfiles=%d, numfiles=%d), exiting") - % max_size % total_size % max_files % cachefiles.size(); + LOG_D("utils/clean_cache") << agi::format("cache does not need cleaning (maxsize=%d, cursize=%d, maxfiles=%d, numfiles=%d), exiting" + , max_size, total_size, max_files, cachefiles.size()); return; } diff --git a/src/vector2d.cpp b/src/vector2d.cpp index a8dfae25c..d9ef5b9aa 100644 --- a/src/vector2d.cpp +++ b/src/vector2d.cpp @@ -23,7 +23,8 @@ #include "utils.h" -#include +#include + #include Vector2D::Vector2D() @@ -83,7 +84,7 @@ std::string Vector2D::PStr(char sep) const { } std::string Vector2D::DStr(char sep) const { - return str(boost::format("%d%c%d") % (int)x % sep % (int)y); + return agi::format("%d%c%d", (int)x, sep, (int)y); } std::string Vector2D::Str(char sep) const { diff --git a/src/video_provider_dummy.cpp b/src/video_provider_dummy.cpp index 8b3377080..3ac660db1 100644 --- a/src/video_provider_dummy.cpp +++ b/src/video_provider_dummy.cpp @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include DummyVideoProvider::DummyVideoProvider(double fps, int frames, int width, int height, agi::Color colour, bool pattern) @@ -89,7 +89,7 @@ DummyVideoProvider::DummyVideoProvider(double fps, int frames, int width, int he } std::string DummyVideoProvider::MakeFilename(double fps, int frames, int width, int height, agi::Color colour, bool pattern) { - return str(boost::format("?dummy:%f:%d:%d:%d:%d:%d:%d:%s") % fps % frames % width % height % (int)colour.r % (int)colour.g % (int)colour.b % (pattern ? "c" : "")); + return agi::format("?dummy:%f:%d:%d:%d:%d:%d:%d:%s", fps, frames, width, height, (int)colour.r, (int)colour.g, (int)colour.b, (pattern ? "c" : "")); } std::shared_ptr DummyVideoProvider::GetFrame(int) { diff --git a/src/visual_tool.cpp b/src/visual_tool.cpp index 5aecc92df..049286291 100644 --- a/src/visual_tool.cpp +++ b/src/visual_tool.cpp @@ -32,10 +32,10 @@ #include "visual_tool_drag.h" #include "visual_tool_vector_clip.h" +#include #include #include -#include const wxColour VisualToolBase::colour[] = { wxColour(106,32,19), @@ -500,11 +500,11 @@ std::string VisualToolBase::GetLineVectorClip(AssDialogue *diag, int &scale, boo tag = find_tag(blocks, "\\clip"); if (tag && tag->size() == 4) { - return str(boost::format("m %d %d l %d %d %d %d %d %d") - % (*tag)[0].Get() % (*tag)[1].Get() - % (*tag)[2].Get() % (*tag)[1].Get() - % (*tag)[2].Get() % (*tag)[3].Get() - % (*tag)[0].Get() % (*tag)[3].Get()); + return agi::format("m %d %d l %d %d %d %d %d %d" + , (*tag)[0].Get(), (*tag)[1].Get() + , (*tag)[2].Get(), (*tag)[1].Get() + , (*tag)[2].Get(), (*tag)[3].Get() + , (*tag)[0].Get(), (*tag)[3].Get()); } if (tag) { scale = std::max((*tag)[0].Get(scale), 1); diff --git a/src/visual_tool_clip.cpp b/src/visual_tool_clip.cpp index ea12f3fe8..b9e41f3c1 100644 --- a/src/visual_tool_clip.cpp +++ b/src/visual_tool_clip.cpp @@ -24,7 +24,8 @@ #include "include/aegisub/context.h" #include "selection_controller.h" -#include +#include + #include VisualToolClip::VisualToolClip(VideoDisplay *parent, agi::Context *context) @@ -102,7 +103,7 @@ void VisualToolClip::UpdateHold() { } void VisualToolClip::CommitHold() { - std::string value = str(boost::format("(%s,%s)") % ToScriptCoords(cur_1.Min(cur_2)).Str() % ToScriptCoords(cur_1.Max(cur_2)).Str()); + std::string value = agi::format("(%s,%s)", ToScriptCoords(cur_1.Min(cur_2)).Str(), ToScriptCoords(cur_1.Max(cur_2)).Str()); for (auto line : c->selectionController->GetSelectedSet()) { // This check is technically not correct as it could be outside of an diff --git a/src/visual_tool_cross.cpp b/src/visual_tool_cross.cpp index 7d1bffbb8..ffbf5329b 100644 --- a/src/visual_tool_cross.cpp +++ b/src/visual_tool_cross.cpp @@ -26,10 +26,9 @@ #include "video_display.h" #include +#include #include -#include - VisualToolCross::VisualToolCross(VideoDisplay *parent, agi::Context *context) : VisualTool(parent, context) , gl_text(agi::make_unique()) @@ -49,9 +48,9 @@ void VisualToolCross::OnDoubleClick() { int t1, t2; if (GetLineMove(line, p1, p2, t1, t2)) { if (t1 > 0 || t2 > 0) - SetOverride(line, "\\move", str(boost::format("(%s,%s,%d,%d)") % Text(p1 + d) % Text(p2 + d) % t1 % t2)); + SetOverride(line, "\\move", agi::format("(%s,%s,%d,%d)", Text(p1 + d), Text(p2 + d), t1, t2)); else - SetOverride(line, "\\move", str(boost::format("(%s,%s)") % Text(p1 + d) % Text(p2 + d))); + SetOverride(line, "\\move", agi::format("(%s,%s)", Text(p1 + d), Text(p2 + d))); } else SetOverride(line, "\\pos", "(" + Text(GetLinePosition(line) + d) + ")"); diff --git a/src/visual_tool_drag.cpp b/src/visual_tool_drag.cpp index c2a7dfd2b..63236dc7f 100644 --- a/src/visual_tool_drag.cpp +++ b/src/visual_tool_drag.cpp @@ -29,10 +29,10 @@ #include "video_controller.h" #include "video_display.h" +#include #include #include -#include #include #include @@ -91,7 +91,7 @@ void VisualToolDrag::OnSubTool(wxCommandEvent &) { // Round the start and end times to exact frames int start = vc->TimeAtFrame(vc->FrameAtTime(line->Start, agi::vfr::START)) - line->Start; int end = vc->TimeAtFrame(vc->FrameAtTime(line->Start, agi::vfr::END)) - line->Start; - SetOverride(line, "\\move", str(boost::format("(%s,%s,%d,%d)") % p1.Str() % p1.Str() % start % end)); + SetOverride(line, "\\move", agi::format("(%s,%s,%d,%d)", p1.Str(), p1.Str(), start, end)); } } @@ -298,11 +298,10 @@ void VisualToolDrag::UpdateDrag(Feature *feature) { if (!feature->parent) SetOverride(feature->line, "\\pos", ToScriptCoords(feature->pos).PStr()); else - SetOverride(feature->line, "\\move", - str(boost::format("(%s,%s,%d,%d)") - % ToScriptCoords(feature->pos).Str() - % ToScriptCoords(end_feature->pos).Str() - % feature->time % end_feature->time)); + SetOverride(feature->line, "\\move", agi::format("(%s,%s,%d,%d)" + , ToScriptCoords(feature->pos).Str() + , ToScriptCoords(end_feature->pos).Str() + , feature->time , end_feature->time)); } void VisualToolDrag::OnDoubleClick() { @@ -313,9 +312,9 @@ void VisualToolDrag::OnDoubleClick() { int t1, t2; if (GetLineMove(line, p1, p2, t1, t2)) { if (t1 > 0 || t2 > 0) - SetOverride(line, "\\move", str(boost::format("(%s,%s,%d,%d)") % (p1 + d).Str() % (p2 + d).Str() % t1 % t2)); + SetOverride(line, "\\move", agi::format("(%s,%s,%d,%d)", (p1 + d).Str(), (p2 + d).Str(), t1, t2)); else - SetOverride(line, "\\move", str(boost::format("(%s,%s)") % (p1 + d).Str() % (p2 + d).Str())); + SetOverride(line, "\\move", agi::format("(%s,%s)", (p1 + d).Str(), (p2 + d).Str())); } else SetOverride(line, "\\pos", (GetLinePosition(line) + d).PStr()); diff --git a/src/visual_tool_rotatexy.cpp b/src/visual_tool_rotatexy.cpp index 1e2ea62c8..40020b197 100644 --- a/src/visual_tool_rotatexy.cpp +++ b/src/visual_tool_rotatexy.cpp @@ -20,7 +20,8 @@ #include "visual_tool_rotatexy.h" -#include +#include + #include #include @@ -162,8 +163,8 @@ void VisualToolRotateXY::UpdateHold() { angle_x = fmodf(angle_x + 360.f, 360.f); angle_y = fmodf(angle_y + 360.f, 360.f); - SetSelectedOverride("\\frx", str(boost::format("%.4g") % angle_x)); - SetSelectedOverride("\\fry", str(boost::format("%.4g") % angle_y)); + SetSelectedOverride("\\frx", agi::format("%.4g", angle_x)); + SetSelectedOverride("\\fry", agi::format("%.4g", angle_y)); } void VisualToolRotateXY::UpdateDrag(Feature *feature) { diff --git a/src/visual_tool_rotatez.cpp b/src/visual_tool_rotatez.cpp index 4f8ba7ca8..eac48c8f9 100644 --- a/src/visual_tool_rotatez.cpp +++ b/src/visual_tool_rotatez.cpp @@ -20,7 +20,8 @@ #include "visual_tool_rotatez.h" -#include +#include + #include #include @@ -108,7 +109,7 @@ void VisualToolRotateZ::UpdateHold() { angle = fmodf(angle + 360.f, 360.f); - SetSelectedOverride("\\frz", str(boost::format("%.4g") % angle)); + SetSelectedOverride("\\frz", agi::format("%.4g", angle)); } void VisualToolRotateZ::UpdateDrag(Feature *feature) { diff --git a/tests/Makefile b/tests/Makefile index 21d98ca1b..957038775 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -24,6 +24,7 @@ SRC = \ tests/cajun.cpp \ tests/color.cpp \ tests/dialogue_lexer.cpp \ + tests/format.cpp \ tests/fs.cpp \ tests/hotkey.cpp \ tests/iconv.cpp \ diff --git a/tests/tests/format.cpp b/tests/tests/format.cpp new file mode 100644 index 000000000..3e8f8d453 --- /dev/null +++ b/tests/tests/format.cpp @@ -0,0 +1,119 @@ +// Copyright (c) 2014, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ + +#include "main.h" +#include "util.h" + +#include + +TEST(lagi_format, s) { + EXPECT_EQ("hello", agi::format("%s", "hello")); + EXPECT_EQ("he", agi::format("%.2s", "hello")); + EXPECT_EQ("hello", agi::format("%.8s", "hello")); + EXPECT_EQ("he", agi::format("%.*s", 2, "hello")); + EXPECT_EQ("hello", agi::format("%", "hello")); + EXPECT_EQ("hello", agi::format("%s", std::string("hello"))); + EXPECT_EQ("he", agi::format("%.2s", std::string("hello"))); + + EXPECT_EQ("true", agi::format("%s", true)); + EXPECT_EQ("false", agi::format("%s", false)); +} + +TEST(lagi_format, c) { + EXPECT_EQ("a", agi::format("%c", 'a')); + EXPECT_EQ("a", agi::format("%c", (int)'a')); +} + +TEST(lagi_format, d) { + EXPECT_EQ("10", agi::format("%i", 10)); + EXPECT_EQ("10", agi::format("%d", 10)); + EXPECT_EQ("-10", agi::format("%d", -10)); + EXPECT_EQ("1", agi::format("%d", 1.1)); + EXPECT_EQ("97", agi::format("%d", 'a')); + EXPECT_EQ("97", agi::format("%d", (int)'a')); + EXPECT_EQ("1", agi::format("%d", true)); +} + +TEST(lagi_format, o) { + EXPECT_EQ("15", agi::format("%o", 015)); +} + +TEST(lagi_format, u) { + EXPECT_EQ("10", agi::format("%u", 10)); + EXPECT_EQ(std::to_string(static_cast(-10)), agi::format("%u", -10)); +} + +TEST(lagi_format, x) { + EXPECT_EQ("deadbeef", agi::format("%x", 0xdeadbeef)); + EXPECT_EQ("DEADBEEF", agi::format("%X", 0xDEADBEEF)); +} + +TEST(lagi_format, e) { + EXPECT_EQ("1.234560e+10", agi::format("%e", 1.23456e10)); + EXPECT_EQ("-1.234560E+10", agi::format("%E", -1.23456E10)); +} + +TEST(lagi_format, f) { + EXPECT_EQ("-9.876500", agi::format("%f", -9.8765)); + EXPECT_EQ("9.876500", agi::format("%F", 9.8765)); +} + +TEST(lagi_format, g) { + EXPECT_EQ("10", agi::format("%g", 10)); + EXPECT_EQ("100", agi::format("%G", 100)); +} + +TEST(lagi_format, escape) { + EXPECT_EQ("%d", agi::format("%%d")); + EXPECT_EQ("%d", agi::format("%%d", 5)); +} + +TEST(lagi_format, length_modifiers) { + EXPECT_EQ("10", agi::format("%hd", 10)); + EXPECT_EQ("10", agi::format("%ld", 10)); + EXPECT_EQ("10", agi::format("%lld", 10)); + EXPECT_EQ("10", agi::format("%zd", 10)); + EXPECT_EQ("10", agi::format("%td", 10)); + EXPECT_EQ("10", agi::format("%jd", 10)); +} + +TEST(lagi_format, precision_width) { + EXPECT_EQ("05", agi::format("%02X", 5)); + EXPECT_EQ(" -10", agi::format("%10d", -10)); + EXPECT_EQ("0010", agi::format("%04d", 10)); + EXPECT_EQ(" 1234.1235", agi::format("%10.4f", 1234.1234567890)); + EXPECT_EQ("10", agi::format("%.f", 10.1)); + EXPECT_EQ("0000000100", agi::format("%010d", 100)); + EXPECT_EQ("-000000010", agi::format("%010d", -10)); + EXPECT_EQ("0X0000BEEF", agi::format("%#010X", 0xBEEF)); +} + +TEST(lagi_format, flags) { + EXPECT_EQ("0x271828", agi::format("%#x", 0x271828)); + EXPECT_EQ("011614050", agi::format("%#o", 0x271828)); + EXPECT_EQ("3.000000", agi::format("%#f", 3.0)); + EXPECT_EQ("+3", agi::format("%+d", 3)); + EXPECT_EQ("+0", agi::format("%+d", 0)); + EXPECT_EQ("-3", agi::format("%+d", -3)); + + EXPECT_EQ("10 ", agi::format("%-010d", 10)); + EXPECT_EQ("10 ", agi::format("%0-10d", 10)); +} + +TEST(lagi_format, bad_cast) { + EXPECT_THROW(agi::format("%d", "hello"), std::bad_cast); + EXPECT_THROW(agi::format("%.*s", "hello", "str"), std::bad_cast); +} diff --git a/tests/tests/word_split.cpp b/tests/tests/word_split.cpp index 4c19de763..0b3847757 100644 --- a/tests/tests/word_split.cpp +++ b/tests/tests/word_split.cpp @@ -28,7 +28,7 @@ TEST(lagi_word_split, empty) { SplitWords(text, tokens); EXPECT_TRUE(tokens.empty()); - tokens.emplace_back(0, 0); + tokens.push_back(DialogueToken{0, 0}); SplitWords(text, tokens); EXPECT_EQ(1u, tokens.size()); } @@ -134,7 +134,7 @@ TEST(lagi_word_split, unclosed_ovr) { text = "{"; tokens.clear(); - tokens.emplace_back(dt::OVR_BEGIN, 1); + tokens.push_back(DialogueToken{dt::OVR_BEGIN, 1}); SplitWords(text, tokens); ASSERT_EQ(1u, tokens.size());