Skip to content

Commit

Permalink
refactor: More cleanup of the main file
Browse files Browse the repository at this point in the history
  • Loading branch information
WerWolv committed Feb 11, 2024
1 parent 27b5d13 commit daf4e5c
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 164 deletions.
2 changes: 0 additions & 2 deletions lib/libimhex/include/hex/api/imhex_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
15 changes: 11 additions & 4 deletions lib/libimhex/include/hex/helpers/logger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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...);
Expand All @@ -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...);
Expand All @@ -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...);
Expand Down
19 changes: 13 additions & 6 deletions lib/libimhex/source/api/imhex_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion lib/libimhex/source/api/plugin_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
155 changes: 90 additions & 65 deletions lib/libimhex/source/helpers/logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
std::mutex& getLoggerMutex() {
return s_loggerMutex;
}

if (s_loggerFile.isValid()) {
s_colorOutputEnabled = true;
break;
}
bool isLoggingSuspended() {
return s_loggingSuspended;
}
}

void enableColorPrinting() {
s_colorOutputEnabled = true;
FILE *getDestination() {
if (s_loggerFile.isValid())
return s_loggerFile.getHandle();
else
return stdout;
}

wolv::io::File& getFile() {
return s_loggerFile;
}

#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);
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;

#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());
}
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);
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()));

if (s_colorOutputEnabled)
fmt::print(dest, ts, "{0} ", level);
else
fmt::print(dest, "{0} ", level);
fmt::print(dest, "[{0:%H:%M:%S}] ", now);

std::string projectThreadTag = projectName;
if (auto threadName = TaskManager::getCurrentThreadName(); !threadName.empty())
projectThreadTag += fmt::format(" | {0}", threadName);
if (s_colorOutputEnabled)
fmt::print(dest, ts, "{0} ", level);
else
fmt::print(dest, "{0} ", level);

constexpr static auto MaxTagLength = 25;
if (projectThreadTag.length() > MaxTagLength)
projectThreadTag.resize(MaxTagLength);
std::string projectThreadTag = projectName;
if (auto threadName = TaskManager::getCurrentThreadName(); !threadName.empty())
projectThreadTag += fmt::format(" | {0}", threadName);

fmt::print(dest, "[{0}] ", projectThreadTag);
constexpr static auto MaxTagLength = 25;
if (projectThreadTag.length() > MaxTagLength)
projectThreadTag.resize(MaxTagLength);

const auto projectNameLength = projectThreadTag.length();
fmt::print(dest, "{0}", std::string(projectNameLength > MaxTagLength ? 0 : MaxTagLength - projectNameLength, ' '));
}
fmt::print(dest, "[{0}] ", projectThreadTag);

void assertionHandler(bool expr, const char* exprString, const char* file, int line) {
if (!expr) {
log::error("Assertion failed: {} at {}:{}", exprString, file, line);
const auto projectNameLength = projectThreadTag.length();
fmt::print(dest, "{0}", std::string(projectNameLength > MaxTagLength ? 0 : MaxTagLength - projectNameLength, ' '));
}

#if defined (DEBUG)
std::abort();
#endif
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
}
}

}

}
1 change: 1 addition & 0 deletions main/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}
)
Expand Down
76 changes: 76 additions & 0 deletions main/gui/source/init/run/cli.cpp
Original file line number Diff line number Diff line change
@@ -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();
}

}
Loading

0 comments on commit daf4e5c

Please sign in to comment.