diff --git a/Utilities/File.cpp b/Utilities/File.cpp index 9a7d9370c6..e41d1a0c43 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -627,7 +627,7 @@ void fs::file::xnull() const void fs::file::xfail() const { - throw fmt::exception("Unexpected fs::error %u", g_tls_error); + throw fmt::exception("Unexpected fs::error %s", g_tls_error); } bool fs::file::open(const std::string& path, bitset_t mode) diff --git a/Utilities/File.h b/Utilities/File.h index 25ebe364b2..0f86a810e7 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -463,3 +463,21 @@ namespace fs // Error code returned extern thread_local error g_tls_error; } + +template<> +struct unveil +{ + static inline const char* get(fs::error error) + { + switch (error) + { + case fs::error::ok: return "OK"; + + case fs::error::inval: return "Invalid arguments"; + case fs::error::noent: return "Not found"; + case fs::error::exist: return "Already exists"; + + default: throw error; + } + } +}; diff --git a/Utilities/Log.cpp b/Utilities/Log.cpp index b1d7718c55..b1f7faaae1 100644 --- a/Utilities/Log.cpp +++ b/Utilities/Log.cpp @@ -2,6 +2,7 @@ #include "File.h" #include "StrFmt.h" +#include "rpcs3_version.h" #include #include @@ -14,15 +15,6 @@ constexpr DECLARE(bijective::map); namespace logs { - struct listener - { - listener() = default; - - virtual ~listener() = default; - - virtual void log(const channel& ch, level sev, const std::string& text) = 0; - }; - class file_writer { // Could be memory-mapped file @@ -34,10 +26,7 @@ namespace logs virtual ~file_writer() = default; // Append raw data - void log(const std::string& text); - - // Get current file size (may be used by secondary readers) - std::size_t size() const; + void log(const char* text, std::size_t size); }; struct file_listener : public file_writer, public listener @@ -46,17 +35,19 @@ namespace logs : file_writer(name) , listener() { + const std::string& start = fmt::format("\xEF\xBB\xBF" "RPCS3 v%s\n", rpcs3::version.to_string()); + file_writer::log(start.data(), start.size()); } // Encode level, current thread name, channel name and write log message - virtual void log(const channel& ch, level sev, const std::string& text) override; + virtual void log(const message& msg) override; }; - static file_listener& get_logger() + static file_listener* get_logger() { // Use magic static static file_listener logger("RPCS3.log"); - return logger; + return &logger; } channel GENERAL(nullptr, level::notice); @@ -69,12 +60,44 @@ namespace logs channel ARMv7("ARMv7"); } +void logs::listener::add(logs::listener* _new) +{ + // Get first (main) listener + listener* lis = get_logger(); + + // Install new listener at the end of linked list + while (lis->m_next || !lis->m_next.compare_and_swap_test(nullptr, _new)) + { + lis = lis->m_next; + } +} + void logs::channel::broadcast(const logs::channel& ch, logs::level sev, const char* fmt...) { va_list args; va_start(args, fmt); - get_logger().log(ch, sev, fmt::unsafe_vformat(fmt, args)); + std::string&& text = fmt::unsafe_vformat(fmt, args); + std::string&& prefix = g_tls_log_prefix ? g_tls_log_prefix() : ""; va_end(args); + + // Prepare message information + message msg; + msg.ch = &ch; + msg.sev = sev; + msg.text = text.data(); + msg.text_size = text.size(); + msg.prefix = prefix.data(); + msg.prefix_size = prefix.size(); + + // Get first (main) listener + listener* lis = get_logger(); + + // Send message to all listeners + while (lis) + { + lis->log(msg); + lis = lis->m_next; + } } [[noreturn]] extern void catch_all_exceptions(); @@ -85,7 +108,7 @@ logs::file_writer::file_writer(const std::string& name) { if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append)) { - throw fmt::exception("Can't create log file %s (error %d)", name, fs::g_tls_error); + throw fmt::exception("Can't create log file %s (error %s)", name, fs::g_tls_error); } } catch (...) @@ -94,54 +117,47 @@ logs::file_writer::file_writer(const std::string& name) } } -void logs::file_writer::log(const std::string& text) +void logs::file_writer::log(const char* text, std::size_t size) { - m_file.write(text); + m_file.write(text, size); } -std::size_t logs::file_writer::size() const +void logs::file_listener::log(const logs::message& msg) { - return m_file.pos(); -} - -void logs::file_listener::log(const logs::channel& ch, logs::level sev, const std::string& text) -{ - std::string msg; msg.reserve(text.size() + 200); + std::string text; text.reserve(msg.text_size + msg.prefix_size + 200); // Used character: U+00B7 (Middle Dot) - switch (sev) + switch (msg.sev) { - case level::always: msg = u8"·A "; break; - case level::fatal: msg = u8"·F "; break; - case level::error: msg = u8"·E "; break; - case level::todo: msg = u8"·U "; break; - case level::success: msg = u8"·S "; break; - case level::warning: msg = u8"·W "; break; - case level::notice: msg = u8"·! "; break; - case level::trace: msg = u8"·T "; break; + case level::always: text = u8"·A "; break; + case level::fatal: text = u8"·F "; break; + case level::error: text = u8"·E "; break; + case level::todo: text = u8"·U "; break; + case level::success: text = u8"·S "; break; + case level::warning: text = u8"·W "; break; + case level::notice: text = u8"·! "; break; + case level::trace: text = u8"·T "; break; } // TODO: print time? - if (auto prefix = g_tls_log_prefix) + if (msg.prefix_size > 0) { - msg += '{'; - msg += prefix(); - msg += "} "; + text += fmt::format("{%s} ", msg.prefix); } - if (ch.name) + if (msg.ch->name) { - msg += ch.name; - msg += sev == level::todo ? " TODO: " : ": "; + text += msg.ch->name; + text += msg.sev == level::todo ? " TODO: " : ": "; } - else if (sev == level::todo) + else if (msg.sev == level::todo) { - msg += "TODO: "; + text += "TODO: "; } - msg += text; - msg += '\n'; + text += msg.text; + text += '\n'; - file_writer::log(msg); + file_writer::log(text.data(), text.size()); } diff --git a/Utilities/Log.h b/Utilities/Log.h index 0918e74554..1bc78e8f1d 100644 --- a/Utilities/Log.h +++ b/Utilities/Log.h @@ -17,6 +17,39 @@ namespace logs trace, // lowest level (usually disabled) }; + struct channel; + + // Message information (temporary data) + struct message + { + const channel* ch; + level sev; + + const char* prefix; + std::size_t prefix_size; + const char* text; + std::size_t text_size; + }; + + class listener + { + // Next listener (linked list) + atomic_t m_next{}; + + friend struct channel; + + public: + constexpr listener() = default; + + virtual ~listener() = default; + + // Process log message + virtual void log(const message& msg) = 0; + + // Add new listener + static void add(listener*); + }; + struct channel { // Channel prefix (added to every log message) @@ -60,7 +93,6 @@ namespace logs GEN_LOG_METHOD(trace) #undef GEN_LOG_METHOD - private: // Send log message to global logger instance static void broadcast(const channel& ch, level sev, const char* fmt...); diff --git a/Utilities/version.cpp b/Utilities/version.cpp index dcbd910b4b..3f722109cf 100644 --- a/Utilities/version.cpp +++ b/Utilities/version.cpp @@ -14,26 +14,12 @@ namespace utils case version_type::release: return "Release"; } - throw; + throw type; } - version::version(std::uint8_t hi, std::uint8_t mid, std::uint8_t lo) - : m_hi(hi) - , m_mid(mid) - , m_lo(lo) + uint version::to_hex() const { - } - - version& version::type(version_type type, std::uint8_t type_index) - { - m_type = type; - m_type_index = type_index; - return *this; - } - - std::uint16_t version::to_hex() const - { - return (m_hi << 24) | (m_mid << 16) | (m_lo << 8) | ((std::uint8_t(m_type) & 0xf) << 4) | (m_type_index & 0xf); + return (m_hi << 24) | (m_mid << 16) | (m_lo << 8) | ((uint(m_type) & 0xf) << 4) | (m_type_index & 0xf); } std::string version::to_string() const diff --git a/Utilities/version.h b/Utilities/version.h index af75c1f764..da66a675d4 100644 --- a/Utilities/version.h +++ b/Utilities/version.h @@ -1,10 +1,11 @@ #pragma once + +#include "types.h" #include -#include namespace utils { - enum class version_type : std::uint8_t + enum class version_type : uint { pre_alpha, alpha, @@ -17,29 +18,35 @@ namespace utils class version { - std::uint8_t m_hi; - std::uint8_t m_mid; - std::uint8_t m_lo; + uint m_hi; + uint m_mid; + uint m_lo; version_type m_type = version_type::release; - std::uint8_t m_type_index = 1; - std::string m_postfix; + uint m_type_index = 1; + const char* m_postfix; public: - version(std::uint8_t hi, std::uint8_t mid, std::uint8_t lo = 0); + constexpr version(uint hi, uint mid, uint lo, version_type type, uint type_index, const char* postfix) + : m_hi(hi) + , m_mid(mid) + , m_lo(lo) + , m_type(type) + , m_type_index(type_index) + , m_postfix(postfix) + { + } - version& type(version_type type, std::uint8_t type_index = 1); - - std::uint8_t hi() const + uint hi() const { return m_hi; } - std::uint8_t mid() const + uint mid() const { return m_mid; } - std::uint8_t lo() const + uint lo() const { return m_lo; } @@ -54,18 +61,12 @@ namespace utils return m_postfix; } - version& postfix(const std::string& value) - { - m_postfix = value; - return *this; - } - - std::uint8_t type_index() const + uint type_index() const { return m_type_index; } - std::uint16_t to_hex() const; + uint to_hex() const; std::string to_string() const; }; } diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index 22969c1da0..acc9622121 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -410,7 +410,7 @@ ppu_error_code sys_fs_rmdir(vm::cptr path) switch (auto error = fs::g_tls_error) { case fs::error::noent: return CELL_ENOENT; - default: sys_fs.error("sys_fs_rmdir(): unknown error %d", error); + default: sys_fs.error("sys_fs_rmdir(): unknown error %s", error); } return CELL_EIO; // ??? @@ -430,7 +430,7 @@ ppu_error_code sys_fs_unlink(vm::cptr path) switch (auto error = fs::g_tls_error) { case fs::error::noent: return CELL_ENOENT; - default: sys_fs.error("sys_fs_unlink(): unknown error %d", error); + default: sys_fs.error("sys_fs_unlink(): unknown error %s", error); } return CELL_EIO; // ??? @@ -559,7 +559,7 @@ ppu_error_code sys_fs_truncate(vm::cptr path, u64 size) switch (auto error = fs::g_tls_error) { case fs::error::noent: return CELL_ENOENT; - default: sys_fs.error("sys_fs_truncate(): unknown error %d", error); + default: sys_fs.error("sys_fs_truncate(): unknown error %s", error); } return CELL_EIO; // ??? @@ -586,7 +586,7 @@ ppu_error_code sys_fs_ftruncate(u32 fd, u64 size) switch (auto error = fs::g_tls_error) { case fs::error::ok: - default: sys_fs.error("sys_fs_ftruncate(): unknown error %d", error); + default: sys_fs.error("sys_fs_ftruncate(): unknown error %s", error); } return CELL_EIO; // ??? diff --git a/rpcs3/Gui/AboutDialog.h b/rpcs3/Gui/AboutDialog.h index 1fdae020ad..e2d678960e 100644 --- a/rpcs3/Gui/AboutDialog.h +++ b/rpcs3/Gui/AboutDialog.h @@ -12,7 +12,7 @@ class AboutDialog : public wxDialog public: AboutDialog(wxWindow* parent) - : wxDialog(parent, wxID_ANY, "About " _PRGNAME_, wxDefaultPosition) + : wxDialog(parent, wxID_ANY, "About RPCS3", wxDefaultPosition) { wxBoxSizer* s_panel(new wxBoxSizer(wxVERTICAL)); @@ -20,18 +20,18 @@ public: wxPanel* s_panel_logo(new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(512, 92))); s_panel_logo->SetBackgroundColour(wxColor(100, 100, 100)); - wxStaticText* t_name = new wxStaticText(this, wxID_ANY, _PRGNAME_); + wxStaticText* t_name = new wxStaticText(this, wxID_ANY, "RPCS3"); t_name->SetFont(wxFont(28, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD)); t_name->SetBackgroundColour(wxColor(100, 100, 100)); t_name->SetForegroundColour(wxColor(255, 255, 255)); t_name->SetPosition(wxPoint(10, 6)); - wxStaticText* t_descr = new wxStaticText(this, wxID_ANY, "An early but promising PS3 emulator and debugger."); + wxStaticText* t_descr = new wxStaticText(this, wxID_ANY, "PS3 emulator and debugger."); t_descr->SetBackgroundColour(wxColor(100, 100, 100)); t_descr->SetForegroundColour(wxColor(255, 255, 255)); t_descr->SetPosition(wxPoint(12, 50)); - wxStaticText* t_version = new wxStaticText(this, wxID_ANY, std::string(_PRGNAME_ " Version: ") + rpcs3::version.to_string()); + wxStaticText* t_version = new wxStaticText(this, wxID_ANY, "RPCS3 Version: " + rpcs3::version.to_string()); t_version->SetBackgroundColour(wxColor(100, 100, 100)); t_version->SetForegroundColour(wxColor(200, 200, 200)); t_version->SetPosition(wxPoint(12, 66)); diff --git a/rpcs3/Gui/ConLogFrame.cpp b/rpcs3/Gui/ConLogFrame.cpp index f363c0e2e9..9525e53bbd 100644 --- a/rpcs3/Gui/ConLogFrame.cpp +++ b/rpcs3/Gui/ConLogFrame.cpp @@ -2,8 +2,99 @@ #include "stdafx_gui.h" #include "Gui/ConLogFrame.h" +#include "rpcs3_version.h" #include +struct gui_listener : logs::listener +{ + atomic_t enabled{}; + + struct packet + { + atomic_t next{}; + + logs::level sev{}; + std::string msg; + + ~packet() + { + for (auto ptr = next.raw(); UNLIKELY(ptr);) + { + delete std::exchange(ptr, std::exchange(ptr->next.raw(), nullptr)); + } + } + }; + + atomic_t last; // Packet for writing another packet + atomic_t read; // Packet for reading + + gui_listener() + : logs::listener() + { + // Initialize packets + read = new packet; + last = new packet; + read->next = last.load(); + last->msg = fmt::format("RPCS3 v%s\n", rpcs3::version.to_string()); + + // Self-registration + logs::listener::add(this); + } + + ~gui_listener() + { + delete read; + } + + void log(const logs::message& msg) + { + if (msg.sev <= enabled) + { + const auto _new = new packet; + _new->sev = msg.sev; + + if (msg.prefix_size > 0) + { + _new->msg = fmt::format("{%s} ", msg.prefix); + } + + if (msg.ch->name) + { + _new->msg += msg.ch->name; + _new->msg += msg.sev == logs::level::todo ? " TODO: " : ": "; + } + else if (msg.sev == logs::level::todo) + { + _new->msg += "TODO: "; + } + + _new->msg += msg.text; + _new->msg += '\n'; + + last = last->next = _new; + } + } + + void pop() + { + if (const auto head = read->next.exchange(nullptr)) + { + delete read.exchange(head); + } + } + + void clear() + { + while (read->next) + { + pop(); + } + } +}; + +// GUI Listener instance +static gui_listener s_gui_listener; + enum { id_log_copy, // Copy log to ClipBoard @@ -28,9 +119,8 @@ LogFrame::LogFrame(wxWindow* parent) , m_cfg_level(g_gui_cfg["Log Level"]) , m_cfg_tty(g_gui_cfg["Log TTY"]) { - // Open or create RPCS3.log; TTY.log - m_log_file.open(fs::get_config_dir() + "RPCS3.log", fs::read + fs::create); - m_tty_file.open(fs::get_config_dir() + "TTY.log", fs::read + fs::create); + // Open or create TTY.log + m_tty_file.open(fs::get_config_dir() + "TTY.log", fs::read + fs::create); m_tty->SetBackgroundColour(wxColour("Black")); m_log->SetBackgroundColour(wxColour("Black")); @@ -52,6 +142,9 @@ LogFrame::LogFrame(wxWindow* parent) Show(); + // Update listener info + s_gui_listener.enabled = get_cfg_level(); + // Check for updates every ~10 ms m_timer.Start(10); } @@ -103,7 +196,7 @@ void LogFrame::OnContextMenu(wxCommandEvent& event) case id_log_clear: { m_log->Clear(); - m_log_file.seek(0, fs::seek_end); + s_gui_listener.clear(); break; } @@ -132,6 +225,7 @@ void LogFrame::OnContextMenu(wxCommandEvent& event) if (id >= id_log_level && id < id_log_level + 8) { m_cfg_level = id - id_log_level; + s_gui_listener.enabled = static_cast(id - id_log_level); break; } } @@ -182,68 +276,37 @@ void LogFrame::OnTimer(wxTimerEvent& event) } // Check main logs - while (const u64 size = std::min(sizeof(buf), m_log_file.size() - m_log_file.pos())) + while (const auto packet = s_gui_listener.read->next.load()) { - const wxString& text = get_utf8(m_log_file, size); - - // Append text if necessary - auto flush_logs = [&](u64 start, u64 pos) + // Confirm log level + if (packet->sev <= s_gui_listener.enabled) { - if (pos != start && m_level <= get_cfg_level()) // TODO + // Get text color + wxColour color; + wxString text; + switch (packet->sev) { - m_log->SetDefaultStyle(m_color); - m_log->AppendText(text.substr(start, pos - start)); - } - }; - - // Parse log level formatting - for (std::size_t start = 0, pos = 0;; pos++) - { - if (pos < text.size() && text[pos] == L'·') - { - if (text.size() - pos <= 3) - { - // Cannot get log formatting: abort - m_log_file.seek(0 - text.substr(pos).ToUTF8().length(), fs::seek_cur); - - flush_logs(start, pos); - break; - } - - if (text[pos + 2] == ' ') - { - logs::level level; - wxColour color; - - switch (text[pos + 1].GetValue()) - { - case 'A': level = logs::level::always; color.Set(0x00, 0xFF, 0xFF); break; // Cyan - case 'F': level = logs::level::fatal; color.Set(0xFF, 0x00, 0xFF); break; // Fuchsia - case 'E': level = logs::level::error; color.Set(0xFF, 0x00, 0x00); break; // Red - case 'U': level = logs::level::todo; color.Set(0xFF, 0x60, 0x00); break; // Orange - case 'S': level = logs::level::success; color.Set(0x00, 0xFF, 0x00); break; // Green - case 'W': level = logs::level::warning; color.Set(0xFF, 0xFF, 0x00); break; // Yellow - case '!': level = logs::level::notice; color.Set(0xFF, 0xFF, 0xFF); break; // White - case 'T': level = logs::level::trace; color.Set(0x80, 0x80, 0x80); break; // Gray - default: continue; - } - - flush_logs(start, pos); - - start = pos + 3; - m_level = level; - m_color = color; - } + case logs::level::always: color.Set(0x00, 0xFF, 0xFF); break; // Cyan + case logs::level::fatal: text = "F "; color.Set(0xFF, 0x00, 0xFF); break; // Fuchsia + case logs::level::error: text = "E "; color.Set(0xFF, 0x00, 0x00); break; // Red + case logs::level::todo: text = "U "; color.Set(0xFF, 0x60, 0x00); break; // Orange + case logs::level::success: text = "S "; color.Set(0x00, 0xFF, 0x00); break; // Green + case logs::level::warning: text = "W "; color.Set(0xFF, 0xFF, 0x00); break; // Yellow + case logs::level::notice: text = "! "; color.Set(0xFF, 0xFF, 0xFF); break; // White + case logs::level::trace: text = "T "; color.Set(0x80, 0x80, 0x80); break; // Gray + default: continue; } - if (pos >= text.size()) - { - flush_logs(start, pos); - break; - } + // Print UTF-8 text + text += wxString::FromUTF8(packet->msg.data(), packet->msg.size()); + m_log->SetDefaultStyle(color); + m_log->AppendText(text); } + // Drop packet + s_gui_listener.pop(); + // Limit processing time - if (std::chrono::high_resolution_clock::now() >= start + 7ms || text.empty()) break; + if (std::chrono::high_resolution_clock::now() >= start + 7ms) break; } } diff --git a/rpcs3/Gui/ConLogFrame.h b/rpcs3/Gui/ConLogFrame.h index 10ae45834a..fff914d900 100644 --- a/rpcs3/Gui/ConLogFrame.h +++ b/rpcs3/Gui/ConLogFrame.h @@ -2,12 +2,8 @@ class LogFrame : public wxPanel { - fs::file m_log_file; fs::file m_tty_file; - logs::level m_level{ logs::level::always }; // current log level - wxColour m_color{ 0, 255, 255 }; // current log color - wxAuiNotebook m_tabs; wxTextCtrl *m_log; wxTextCtrl *m_tty; @@ -20,8 +16,15 @@ class LogFrame : public wxPanel YAML::Node m_cfg_level; YAML::Node m_cfg_tty; - logs::level get_cfg_level() const { return static_cast(m_cfg_level.as(4)); } - bool get_cfg_tty() const { return m_cfg_tty.as(true); } + logs::level get_cfg_level() const + { + return static_cast(m_cfg_level.as(4)); + } + + bool get_cfg_tty() const + { + return m_cfg_tty.as(true); + } public: LogFrame(wxWindow* parent); diff --git a/rpcs3/Gui/MainFrame.cpp b/rpcs3/Gui/MainFrame.cpp index efbf7b6217..798974f13b 100644 --- a/rpcs3/Gui/MainFrame.cpp +++ b/rpcs3/Gui/MainFrame.cpp @@ -2,7 +2,6 @@ #include "stdafx_gui.h" #include "rpcs3.h" #include "MainFrame.h" -#include "rpcs3_version.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" @@ -73,7 +72,7 @@ MainFrame::MainFrame() , m_sys_menu_opened(false) { - SetLabel(std::string(_PRGNAME_ " v") + rpcs3::version.to_string()); + SetLabel("RPCS3 v" + rpcs3::version.to_string()); wxMenuBar* menubar = new wxMenuBar(); @@ -164,9 +163,6 @@ MainFrame::MainFrame() wxGetApp().Bind(wxEVT_KEY_DOWN, &MainFrame::OnKeyDown, this); wxGetApp().Bind(wxEVT_DBG_COMMAND, &MainFrame::UpdateUI, this); - - LOG_NOTICE(GENERAL, "%s", (std::string(_PRGNAME_ " v") + rpcs3::version.to_string()).c_str()); - LOG_NOTICE(GENERAL, ""); } MainFrame::~MainFrame() diff --git a/rpcs3/rpcs3.cpp b/rpcs3/rpcs3.cpp index e645e2d82c..2a9a488dd3 100644 --- a/rpcs3/rpcs3.cpp +++ b/rpcs3/rpcs3.cpp @@ -195,7 +195,7 @@ bool Rpcs3App::OnInit() Emu.SetCallbacks(std::move(callbacks)); TheApp = this; - SetAppName(_PRGNAME_); + SetAppName("RPCS3"); wxInitAllImageHandlers(); Emu.Init(); diff --git a/rpcs3/rpcs3_version.cpp b/rpcs3/rpcs3_version.cpp index 2874f882ad..f76df55901 100644 --- a/rpcs3/rpcs3_version.cpp +++ b/rpcs3/rpcs3_version.cpp @@ -4,7 +4,5 @@ namespace rpcs3 { - const utils::version version = utils::version{ 0, 0, 1 } - .type(utils::version_type::pre_alpha) - .postfix(RPCS3_GIT_VERSION); + const extern utils::version version{ 0, 0, 1, utils::version_type::pre_alpha, 1, RPCS3_GIT_VERSION }; } diff --git a/rpcs3/stdafx.h b/rpcs3/stdafx.h index 4517df7b61..dabc2eeed5 100644 --- a/rpcs3/stdafx.h +++ b/rpcs3/stdafx.h @@ -41,8 +41,6 @@ using namespace std::literals; // Obsolete, throw fmt::exception directly. Use 'HERE' macro, if necessary. #define EXCEPTION(format_str, ...) fmt::exception("%s(): " format_str HERE, __FUNCTION__, ##__VA_ARGS__) -#define _PRGNAME_ "RPCS3" - #include "Utilities/types.h" #include "Utilities/Macro.h" #include "Utilities/Platform.h"