refactor: More cleanup of the main file
This commit is contained in:
parent
27b5d13733
commit
daf4e5cad6
@ -401,8 +401,6 @@ namespace hex {
|
||||
|
||||
void setGPUVendor(const std::string &vendor);
|
||||
|
||||
void setPortableVersion(bool enabled);
|
||||
|
||||
void addInitArgument(const std::string &key, const std::string &value = { });
|
||||
|
||||
void setLastFrameTime(double time);
|
||||
|
@ -19,7 +19,8 @@ namespace hex::log {
|
||||
[[maybe_unused]] void redirectToFile();
|
||||
[[maybe_unused]] void enableColorPrinting();
|
||||
|
||||
extern std::mutex g_loggerMutex;
|
||||
[[nodiscard]] std::mutex& getLoggerMutex();
|
||||
[[nodiscard]] bool isLoggingSuspended();
|
||||
|
||||
struct LogEntry {
|
||||
std::string project;
|
||||
@ -33,7 +34,10 @@ namespace hex::log {
|
||||
[[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level, const char *projectName);
|
||||
|
||||
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto && ... args) {
|
||||
std::scoped_lock lock(g_loggerMutex);
|
||||
if (isLoggingSuspended()) [[unlikely]]
|
||||
return;
|
||||
|
||||
std::scoped_lock lock(getLoggerMutex());
|
||||
|
||||
auto dest = getDestination();
|
||||
printPrefix(dest, ts, level, IMHEX_PROJECT_NAME);
|
||||
@ -47,6 +51,9 @@ namespace hex::log {
|
||||
|
||||
}
|
||||
|
||||
void suspendLogging();
|
||||
void resumeLogging();
|
||||
|
||||
[[maybe_unused]] void debug(const std::string &fmt, auto && ... args) {
|
||||
#if defined(DEBUG)
|
||||
hex::log::impl::print(fg(fmt::color::light_green) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
|
||||
@ -73,7 +80,7 @@ namespace hex::log {
|
||||
|
||||
|
||||
[[maybe_unused]] void print(const std::string &fmt, auto && ... args) {
|
||||
std::scoped_lock lock(impl::g_loggerMutex);
|
||||
std::scoped_lock lock(impl::getLoggerMutex());
|
||||
|
||||
auto dest = impl::getDestination();
|
||||
auto message = fmt::format(fmt::runtime(fmt), args...);
|
||||
@ -82,7 +89,7 @@ namespace hex::log {
|
||||
}
|
||||
|
||||
[[maybe_unused]] void println(const std::string &fmt, auto && ... args) {
|
||||
std::scoped_lock lock(impl::g_loggerMutex);
|
||||
std::scoped_lock lock(impl::getLoggerMutex());
|
||||
|
||||
auto dest = impl::getDestination();
|
||||
auto message = fmt::format(fmt::runtime(fmt), args...);
|
||||
|
@ -453,11 +453,6 @@ namespace hex {
|
||||
s_gpuVendor = vendor;
|
||||
}
|
||||
|
||||
static bool s_portableVersion = false;
|
||||
void setPortableVersion(bool enabled) {
|
||||
s_portableVersion = enabled;
|
||||
}
|
||||
|
||||
static AutoReset<std::map<std::string, std::string>> s_initArguments;
|
||||
void addInitArgument(const std::string &key, const std::string &value) {
|
||||
static std::mutex initArgumentsMutex;
|
||||
@ -588,7 +583,19 @@ namespace hex {
|
||||
}
|
||||
|
||||
bool isPortableVersion() {
|
||||
return impl::s_portableVersion;
|
||||
static std::optional<bool> portable;
|
||||
if (portable.has_value())
|
||||
return portable.value();
|
||||
|
||||
if (const auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value()) {
|
||||
const auto flagFile = executablePath->parent_path() / "PORTABLE";
|
||||
|
||||
portable = wolv::io::fs::exists(flagFile) && wolv::io::fs::isRegularFile(flagFile);
|
||||
} else {
|
||||
portable = false;
|
||||
}
|
||||
|
||||
return portable.value();
|
||||
}
|
||||
|
||||
std::string getOSName() {
|
||||
|
@ -86,7 +86,7 @@ namespace hex {
|
||||
|
||||
Plugin::~Plugin() {
|
||||
if (isLoaded()) {
|
||||
log::debug("Trying to unload plugin '{}'", getPluginName());
|
||||
log::info("Trying to unload plugin '{}'", getPluginName());
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
|
@ -12,100 +12,125 @@
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
namespace hex::log::impl {
|
||||
namespace hex::log {
|
||||
|
||||
static wolv::io::File s_loggerFile;
|
||||
static bool s_colorOutputEnabled = false;
|
||||
std::mutex g_loggerMutex;
|
||||
namespace {
|
||||
|
||||
wolv::io::File s_loggerFile;
|
||||
bool s_colorOutputEnabled = false;
|
||||
std::mutex s_loggerMutex;
|
||||
bool s_loggingSuspended = false;
|
||||
|
||||
FILE *getDestination() {
|
||||
if (s_loggerFile.isValid())
|
||||
return s_loggerFile.getHandle();
|
||||
else
|
||||
return stdout;
|
||||
}
|
||||
|
||||
wolv::io::File& getFile() {
|
||||
return s_loggerFile;
|
||||
void suspendLogging() {
|
||||
s_loggingSuspended = true;
|
||||
}
|
||||
|
||||
bool isRedirected() {
|
||||
return s_loggerFile.isValid();
|
||||
void resumeLogging() {
|
||||
s_loggingSuspended = false;
|
||||
}
|
||||
|
||||
void redirectToFile() {
|
||||
if (s_loggerFile.isValid()) return;
|
||||
namespace impl {
|
||||
|
||||
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Logs, true)) {
|
||||
wolv::io::fs::createDirectories(path);
|
||||
s_loggerFile = wolv::io::File(path / hex::format("{0:%Y%m%d_%H%M%S}.log", fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()))), wolv::io::File::Mode::Create);
|
||||
s_loggerFile.disableBuffering();
|
||||
|
||||
if (s_loggerFile.isValid()) {
|
||||
s_colorOutputEnabled = true;
|
||||
break;
|
||||
}
|
||||
std::mutex& getLoggerMutex() {
|
||||
return s_loggerMutex;
|
||||
}
|
||||
}
|
||||
|
||||
void enableColorPrinting() {
|
||||
s_colorOutputEnabled = true;
|
||||
bool isLoggingSuspended() {
|
||||
return s_loggingSuspended;
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hConsole != INVALID_HANDLE_VALUE) {
|
||||
DWORD mode = 0;
|
||||
if (::GetConsoleMode(hConsole, &mode) == TRUE) {
|
||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT;
|
||||
::SetConsoleMode(hConsole, mode);
|
||||
FILE *getDestination() {
|
||||
if (s_loggerFile.isValid())
|
||||
return s_loggerFile.getHandle();
|
||||
else
|
||||
return stdout;
|
||||
}
|
||||
|
||||
wolv::io::File& getFile() {
|
||||
return s_loggerFile;
|
||||
}
|
||||
|
||||
bool isRedirected() {
|
||||
return s_loggerFile.isValid();
|
||||
}
|
||||
|
||||
void redirectToFile() {
|
||||
if (s_loggerFile.isValid()) return;
|
||||
|
||||
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Logs, true)) {
|
||||
wolv::io::fs::createDirectories(path);
|
||||
s_loggerFile = wolv::io::File(path / hex::format("{0:%Y%m%d_%H%M%S}.log", fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()))), wolv::io::File::Mode::Create);
|
||||
s_loggerFile.disableBuffering();
|
||||
|
||||
if (s_loggerFile.isValid()) {
|
||||
s_colorOutputEnabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void enableColorPrinting() {
|
||||
s_colorOutputEnabled = true;
|
||||
|
||||
std::vector<LogEntry>& getLogEntries() {
|
||||
static std::vector<LogEntry> logEntries;
|
||||
return logEntries;
|
||||
}
|
||||
|
||||
void addLogEntry(std::string_view project, std::string_view level, std::string_view message) {
|
||||
getLogEntries().emplace_back(project.data(), level.data(), message.data());
|
||||
}
|
||||
|
||||
|
||||
void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level, const char *projectName) {
|
||||
const auto now = fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()));
|
||||
|
||||
fmt::print(dest, "[{0:%H:%M:%S}] ", now);
|
||||
|
||||
if (s_colorOutputEnabled)
|
||||
fmt::print(dest, ts, "{0} ", level);
|
||||
else
|
||||
fmt::print(dest, "{0} ", level);
|
||||
|
||||
std::string projectThreadTag = projectName;
|
||||
if (auto threadName = TaskManager::getCurrentThreadName(); !threadName.empty())
|
||||
projectThreadTag += fmt::format(" | {0}", threadName);
|
||||
|
||||
constexpr static auto MaxTagLength = 25;
|
||||
if (projectThreadTag.length() > MaxTagLength)
|
||||
projectThreadTag.resize(MaxTagLength);
|
||||
|
||||
fmt::print(dest, "[{0}] ", projectThreadTag);
|
||||
|
||||
const auto projectNameLength = projectThreadTag.length();
|
||||
fmt::print(dest, "{0}", std::string(projectNameLength > MaxTagLength ? 0 : MaxTagLength - projectNameLength, ' '));
|
||||
}
|
||||
|
||||
void assertionHandler(bool expr, const char* exprString, const char* file, int line) {
|
||||
if (!expr) {
|
||||
log::error("Assertion failed: {} at {}:{}", exprString, file, line);
|
||||
|
||||
#if defined (DEBUG)
|
||||
std::abort();
|
||||
#if defined(OS_WINDOWS)
|
||||
auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hConsole != INVALID_HANDLE_VALUE) {
|
||||
DWORD mode = 0;
|
||||
if (::GetConsoleMode(hConsole, &mode) == TRUE) {
|
||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT;
|
||||
::SetConsoleMode(hConsole, mode);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
std::vector<LogEntry>& getLogEntries() {
|
||||
static std::vector<LogEntry> logEntries;
|
||||
return logEntries;
|
||||
}
|
||||
|
||||
void addLogEntry(std::string_view project, std::string_view level, std::string_view message) {
|
||||
getLogEntries().emplace_back(project.data(), level.data(), message.data());
|
||||
}
|
||||
|
||||
|
||||
void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level, const char *projectName) {
|
||||
const auto now = fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()));
|
||||
|
||||
fmt::print(dest, "[{0:%H:%M:%S}] ", now);
|
||||
|
||||
if (s_colorOutputEnabled)
|
||||
fmt::print(dest, ts, "{0} ", level);
|
||||
else
|
||||
fmt::print(dest, "{0} ", level);
|
||||
|
||||
std::string projectThreadTag = projectName;
|
||||
if (auto threadName = TaskManager::getCurrentThreadName(); !threadName.empty())
|
||||
projectThreadTag += fmt::format(" | {0}", threadName);
|
||||
|
||||
constexpr static auto MaxTagLength = 25;
|
||||
if (projectThreadTag.length() > MaxTagLength)
|
||||
projectThreadTag.resize(MaxTagLength);
|
||||
|
||||
fmt::print(dest, "[{0}] ", projectThreadTag);
|
||||
|
||||
const auto projectNameLength = projectThreadTag.length();
|
||||
fmt::print(dest, "{0}", std::string(projectNameLength > MaxTagLength ? 0 : MaxTagLength - projectNameLength, ' '));
|
||||
}
|
||||
|
||||
void assertionHandler(bool expr, const char* exprString, const char* file, int line) {
|
||||
if (!expr) {
|
||||
log::error("Assertion failed: {} at {}:{}", exprString, file, line);
|
||||
|
||||
#if defined (DEBUG)
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -23,6 +23,7 @@ add_executable(main ${APPLICATION_TYPE}
|
||||
source/init/run/common.cpp
|
||||
source/init/run/native.cpp
|
||||
source/init/run/web.cpp
|
||||
source/init/run/cli.cpp
|
||||
|
||||
${IMHEX_ICON}
|
||||
)
|
||||
|
76
main/gui/source/init/run/cli.cpp
Normal file
76
main/gui/source/init/run/cli.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
#include "messaging.hpp"
|
||||
|
||||
#include <hex/subcommands/subcommands.hpp>
|
||||
|
||||
#include <hex/api/plugin_manager.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <wolv/utils/guards.hpp>
|
||||
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <codecvt>
|
||||
#endif
|
||||
|
||||
namespace hex::init {
|
||||
|
||||
/**
|
||||
* @brief Handles commands passed to ImHex via the command line
|
||||
* @param argc Argument count
|
||||
* @param argv Argument values
|
||||
*/
|
||||
void runCommandLine(int argc, char **argv) {
|
||||
// Suspend logging while processing command line arguments so
|
||||
// we don't spam the console with log messages while printing
|
||||
// CLI tool messages
|
||||
log::suspendLogging();
|
||||
ON_SCOPE_EXIT {
|
||||
log::resumeLogging();
|
||||
};
|
||||
|
||||
std::vector<std::string> args;
|
||||
|
||||
#if defined (OS_WINDOWS)
|
||||
hex::unused(argv);
|
||||
|
||||
// On Windows, argv contains UTF-16 encoded strings, so we need to convert them to UTF-8
|
||||
auto convertedCommandLine = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
|
||||
if (convertedCommandLine == nullptr) {
|
||||
log::error("Failed to convert command line arguments to UTF-8");
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Skip the first argument (the executable path) and convert the rest to a vector of UTF-8 strings
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
std::wstring wcharArg = convertedCommandLine[i];
|
||||
std::string utf8Arg = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(wcharArg);
|
||||
|
||||
args.push_back(utf8Arg);
|
||||
}
|
||||
|
||||
::LocalFree(convertedCommandLine);
|
||||
#else
|
||||
// Skip the first argument (the executable path) and convert the rest to a vector of strings
|
||||
args = { argv + 1, argv + argc };
|
||||
#endif
|
||||
|
||||
|
||||
// Load all plugins but don't initialize them
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Plugins)) {
|
||||
PluginManager::load(dir);
|
||||
}
|
||||
|
||||
// Setup messaging system to allow sending commands to the main ImHex instance
|
||||
hex::messaging::setupMessaging();
|
||||
|
||||
// Process the arguments
|
||||
hex::subcommands::processArguments(args);
|
||||
|
||||
// Unload plugins again
|
||||
PluginManager::unload();
|
||||
}
|
||||
|
||||
}
|
@ -3,96 +3,19 @@
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include "window.hpp"
|
||||
#include "crash_handlers.hpp"
|
||||
#include "messaging.hpp"
|
||||
|
||||
#include "init/splash_window.hpp"
|
||||
|
||||
#include "crash_handlers.hpp"
|
||||
|
||||
#include <hex/api/task_manager.hpp>
|
||||
#include <hex/api/plugin_manager.hpp>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include "hex/subcommands/subcommands.hpp"
|
||||
namespace hex::init {
|
||||
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <codecvt>
|
||||
#endif
|
||||
|
||||
using namespace hex;
|
||||
|
||||
namespace hex::init { int runImHex(); }
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief Handles commands passed to ImHex via the command line
|
||||
* @param argc Argument count
|
||||
* @param argv Argument values
|
||||
*/
|
||||
void handleCommandLineInterface(int argc, char **argv) {
|
||||
std::vector<std::string> args;
|
||||
|
||||
#if defined (OS_WINDOWS)
|
||||
hex::unused(argv);
|
||||
|
||||
// On Windows, argv contains UTF-16 encoded strings, so we need to convert them to UTF-8
|
||||
auto convertedCommandLine = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
|
||||
if (convertedCommandLine == nullptr) {
|
||||
log::error("Failed to convert command line arguments to UTF-8");
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
std::wstring wcharArg = convertedCommandLine[i];
|
||||
std::string utf8Arg = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(wcharArg);
|
||||
|
||||
args.push_back(utf8Arg);
|
||||
}
|
||||
|
||||
::LocalFree(convertedCommandLine);
|
||||
#else
|
||||
// Skip the first argument (the executable path) and convert the rest to a vector of strings
|
||||
args = { argv + 1, argv + argc };
|
||||
#endif
|
||||
|
||||
|
||||
// Load all plugins but don't initialize them
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Plugins)) {
|
||||
PluginManager::load(dir);
|
||||
}
|
||||
|
||||
// Setup messaging system to allow sending commands to the main ImHex instance
|
||||
hex::messaging::setupMessaging();
|
||||
|
||||
// Process the arguments
|
||||
hex::subcommands::processArguments(args);
|
||||
|
||||
// Unload plugins again
|
||||
PluginManager::unload();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the portable version of ImHex is installed
|
||||
* @note The portable version is detected by the presence of a file named "PORTABLE" in the same directory as the executable
|
||||
* @return True if ImHex is running in portable mode, false otherwise
|
||||
*/
|
||||
bool isPortableVersion() {
|
||||
if (const auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value()) {
|
||||
const auto flagFile = executablePath->parent_path() / "PORTABLE";
|
||||
|
||||
if (wolv::io::fs::exists(flagFile) && wolv::io::fs::isRegularFile(flagFile))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
int runImHex();
|
||||
void runCommandLine(int argc, char **argv);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main entry point of ImHex
|
||||
* @param argc Argument count
|
||||
@ -100,19 +23,27 @@ namespace {
|
||||
* @return Exit code
|
||||
*/
|
||||
int main(int argc, char **argv) {
|
||||
using namespace hex;
|
||||
|
||||
// Set the main thread's name to "Main"
|
||||
TaskManager::setCurrentThreadName("Main");
|
||||
Window::initNative();
|
||||
|
||||
// Setup crash handlers right away to catch crashes as early as possible
|
||||
crash::setupCrashHandlers();
|
||||
|
||||
// Run platform-specific initialization code
|
||||
Window::initNative();
|
||||
|
||||
// Handle command line arguments if any have been passed
|
||||
if (argc > 1) {
|
||||
handleCommandLineInterface(argc, argv);
|
||||
init::runCommandLine(argc, argv);
|
||||
}
|
||||
|
||||
// Log some system information to aid debugging when users share their logs
|
||||
log::info("Welcome to ImHex {}!", ImHexApi::System::getImHexVersion());
|
||||
log::info("Compiled using commit {}@{}", ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash());
|
||||
log::info("Running on {} {} ({})", ImHexApi::System::getOSName(), ImHexApi::System::getOSVersion(), ImHexApi::System::getArchitecture());
|
||||
|
||||
ImHexApi::System::impl::setPortableVersion(isPortableVersion());
|
||||
|
||||
// Run ImHex
|
||||
return init::runImHex();
|
||||
}
|
||||
|
@ -319,6 +319,7 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
log::println("{}", llvm::demangle(args[0]));
|
||||
std::exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user