2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-12-08 11:44:55 +00:00

Use UTF-8 exclusively internally

This removes SystemString, SystemChar, etc.
All filepaths and log strings are assumed to be UTF-8,
with conversions to UTF-16 for Windows APIs as appropriate.

Updates amuse, athena, boo, kabufua and nod
This commit is contained in:
2021-06-30 14:20:45 -04:00
parent 6e12554026
commit 9ca1a38171
160 changed files with 2029 additions and 2753 deletions

View File

@@ -5,6 +5,5 @@ project(bintoc LANGUAGES C)
add_executable(bintoc bintoc.c)
add_subdirectory(../../extern/athena/extern/zlib zlib EXCLUDE_FROM_ALL)
target_link_libraries(bintoc PRIVATE ${ZLIB_LIBRARIES})
target_include_directories(bintoc PRIVATE ${ZLIB_INCLUDE_DIR})
install(TARGETS bintoc DESTINATION bin)

View File

@@ -19,11 +19,11 @@
extern logvisor::Module LogModule;
struct ToolPassInfo {
hecl::SystemString pname;
hecl::SystemString cwd;
std::vector<hecl::SystemString> args;
std::vector<hecl::SystemChar> flags;
hecl::SystemString output;
std::string pname;
std::string cwd;
std::vector<std::string> args;
std::vector<char> flags;
std::string output;
hecl::Database::Project* project = nullptr;
unsigned verbosityLevel = 0;
bool force = false;
@@ -55,9 +55,9 @@ protected:
bool continuePrompt() {
if (!m_info.yes) {
if (XTERM_COLOR)
fmt::print(FMT_STRING(_SYS_STR("\n" BLUE BOLD "Continue?" NORMAL " (Y/n) ")));
fmt::print(FMT_STRING("\n" BLUE BOLD "Continue?" NORMAL " (Y/n) "));
else
fmt::print(FMT_STRING(_SYS_STR("\nContinue? (Y/n) ")));
fmt::print(FMT_STRING("\nContinue? (Y/n) "));
fflush(stdout);
int ch;
@@ -73,7 +73,7 @@ protected:
#endif
{
if (ch == 'n' || ch == 'N') {
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING("\n"));
return false;
}
if (ch == 'y' || ch == 'Y' || ch == '\r' || ch == '\n')
@@ -83,7 +83,7 @@ protected:
tcsetattr(0, TCSANOW, &tioOld);
#endif
}
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING("\n"));
return true;
}
@@ -93,7 +93,7 @@ public:
hecl::GuiMode = info.gui;
}
virtual ~ToolBase() = default;
virtual hecl::SystemStringView toolName() const = 0;
virtual std::string_view toolName() const = 0;
virtual int run() = 0;
virtual void cancel() {}
explicit operator bool() const { return m_good; }
@@ -107,11 +107,11 @@ private:
FILE* m_sout = nullptr;
HelpFunc m_helpFunc;
int m_lineWidth;
hecl::SystemString m_wrapBuffer;
std::string m_wrapBuffer;
void _wrapBuf(hecl::SystemString& string) {
void _wrapBuf(std::string& string) {
int counter;
hecl::SystemString::iterator it = string.begin();
std::string::iterator it = string.begin();
while (it != string.end()) {
std::ptrdiff_t v = it - string.begin();
@@ -120,33 +120,33 @@ private:
for (counter = WRAP_INDENT; counter < m_lineWidth; ++counter) {
if (it >= string.end())
return;
if (*it == _SYS_STR('\n')) {
if (*it == '\n') {
counter = WRAP_INDENT;
++it;
}
if (counter == WRAP_INDENT) {
for (int i = 0; i < WRAP_INDENT; ++i)
it = string.insert(it, _SYS_STR(' ')) + 1;
it = string.insert(it, ' ') + 1;
}
if (it >= string.end())
return;
if (*it != _SYS_STR('\n'))
if (*it != '\n')
++it;
}
/* check for whitespace */
if (isspace(*it)) {
*it = _SYS_STR('\n');
*it = '\n';
counter = WRAP_INDENT;
++it;
} else {
/* check for nearest whitespace back in string */
for (hecl::SystemString::iterator k = it; k != string.begin(); --k) {
for (std::string::iterator k = it; k != string.begin(); --k) {
if (isspace(*k)) {
counter = WRAP_INDENT;
if (k - string.begin() < v)
k = string.insert(it, _SYS_STR('\n'));
k = string.insert(it, '\n');
else
*k = _SYS_STR('\n');
*k = '\n';
it = k + 1;
break;
}
@@ -175,61 +175,61 @@ public:
#endif
}
void print(const hecl::SystemChar* str) { fmt::print(m_sout, FMT_STRING(_SYS_STR("{}")), str); }
void print(const char* str) { fmt::print(m_sout, FMT_STRING("{}"), str); }
void printBold(const hecl::SystemChar* str) {
void printBold(const char* str) {
if (XTERM_COLOR)
fmt::print(m_sout, FMT_STRING(_SYS_STR("" BOLD "{}" NORMAL "")), str);
fmt::print(m_sout, FMT_STRING("" BOLD "{}" NORMAL ""), str);
else
fmt::print(m_sout, FMT_STRING(_SYS_STR("{}")), str);
fmt::print(m_sout, FMT_STRING("{}"), str);
}
void secHead(const hecl::SystemChar* headName) {
void secHead(const char* headName) {
if (XTERM_COLOR)
fmt::print(m_sout, FMT_STRING(_SYS_STR("" BOLD "{}" NORMAL "\n")), headName);
fmt::print(m_sout, FMT_STRING("" BOLD "{}" NORMAL "\n"), headName);
else
fmt::print(m_sout, FMT_STRING(_SYS_STR("{}\n")), headName);
fmt::print(m_sout, FMT_STRING("{}\n"), headName);
}
void optionHead(const hecl::SystemChar* flag, const hecl::SystemChar* synopsis) {
void optionHead(const char* flag, const char* synopsis) {
if (XTERM_COLOR)
fmt::print(m_sout, FMT_STRING(_SYS_STR("" BOLD "{}" NORMAL " ({})\n")), flag, synopsis);
fmt::print(m_sout, FMT_STRING("" BOLD "{}" NORMAL " ({})\n"), flag, synopsis);
else
fmt::print(m_sout, FMT_STRING(_SYS_STR("{} ({})\n")), flag, synopsis);
fmt::print(m_sout, FMT_STRING("{} ({})\n"), flag, synopsis);
}
void beginWrap() { m_wrapBuffer.clear(); }
void wrap(const hecl::SystemChar* str) { m_wrapBuffer += str; }
void wrap(const char* str) { m_wrapBuffer += str; }
void wrapBold(const hecl::SystemChar* str) {
void wrapBold(const char* str) {
if (XTERM_COLOR)
m_wrapBuffer += _SYS_STR("" BOLD "");
m_wrapBuffer += "" BOLD "";
m_wrapBuffer += str;
if (XTERM_COLOR)
m_wrapBuffer += _SYS_STR("" NORMAL "");
m_wrapBuffer += "" NORMAL "";
}
void endWrap() {
_wrapBuf(m_wrapBuffer);
m_wrapBuffer += _SYS_STR('\n');
fmt::print(m_sout, FMT_STRING(_SYS_STR("{}")), m_wrapBuffer);
m_wrapBuffer += '\n';
fmt::print(m_sout, FMT_STRING("{}"), m_wrapBuffer);
m_wrapBuffer.clear();
}
};
static hecl::SystemString MakePathArgAbsolute(const hecl::SystemString& arg, const hecl::SystemString& cwd) {
static std::string MakePathArgAbsolute(const std::string& arg, const std::string& cwd) {
#if _WIN32
if (arg.size() >= 2 && iswalpha(arg[0]) && arg[1] == _SYS_STR(':'))
if (arg.size() >= 2 && iswalpha(arg[0]) && arg[1] == ':')
return arg;
if (arg[0] == _SYS_STR('\\') || arg[0] == _SYS_STR('/'))
if (arg[0] == '\\' || arg[0] == '/')
return arg;
return cwd + _SYS_STR('\\') + arg;
return cwd + '\\' + arg;
#else
if (arg[0] == _SYS_STR('/') || arg[0] == _SYS_STR('\\'))
if (arg[0] == '/' || arg[0] == '\\')
return arg;
if (cwd.back() == _SYS_STR('/') || cwd.back() == _SYS_STR('\\'))
if (cwd.back() == '/' || cwd.back() == '\\')
return cwd + arg;
return cwd + _SYS_STR('/') + arg;
return cwd + '/' + arg;
#endif
}

View File

@@ -15,22 +15,22 @@ class ToolCook final : public ToolBase {
public:
explicit ToolCook(const ToolPassInfo& info) : ToolBase(info), m_useProj(info.project) {
/* Check for recursive flag */
for (hecl::SystemChar arg : info.flags)
if (arg == _SYS_STR('r'))
for (char arg : info.flags)
if (arg == 'r')
m_recursive = true;
/* Scan args */
if (info.args.size()) {
/* See if project path is supplied via args and use that over the getcwd one */
m_selectedItems.reserve(info.args.size());
for (const hecl::SystemString& arg : info.args) {
for (const std::string& arg : info.args) {
if (arg.empty())
continue;
else if (arg == _SYS_STR("--fast")) {
else if (arg == "--fast") {
m_fast = true;
continue;
} else if (arg.size() >= 8 && !arg.compare(0, 7, _SYS_STR("--spec="))) {
hecl::SystemString specName(arg.begin() + 7, arg.end());
} else if (arg.size() >= 8 && !arg.compare(0, 7, "--spec=")) {
std::string specName(arg.begin() + 7, arg.end());
for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) {
if (!hecl::StrCaseCmp(spec->m_name.data(), specName.c_str())) {
m_spec = spec;
@@ -38,12 +38,12 @@ public:
}
}
if (!m_spec)
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("unable to find data spec '{}'")), specName);
LogModule.report(logvisor::Fatal, FMT_STRING("unable to find data spec '{}'"), specName);
continue;
} else if (arg.size() >= 2 && arg[0] == _SYS_STR('-') && arg[1] == _SYS_STR('-'))
} else if (arg.size() >= 2 && arg[0] == '-' && arg[1] == '-')
continue;
hecl::SystemString subPath;
std::string subPath;
hecl::ProjectRootPath root = hecl::SearchForProject(MakePathArgAbsolute(arg, info.cwd), subPath);
if (root) {
if (!m_fallbackProj) {
@@ -51,8 +51,8 @@ public:
m_useProj = m_fallbackProj.get();
} else if (m_fallbackProj->getProjectRootPath() != root)
LogModule.report(logvisor::Fatal,
FMT_STRING(_SYS_STR("hecl cook can only process multiple items in the same project; ")
_SYS_STR("'{}' and '{}' are different projects")),
FMT_STRING("hecl cook can only process multiple items in the same project; "
"'{}' and '{}' are different projects"),
m_fallbackProj->getProjectRootPath().getAbsolutePath(),
root.getAbsolutePath());
m_selectedItems.emplace_back(*m_useProj, subPath);
@@ -67,85 +67,91 @@ public:
/* Default case: recursive at root */
if (m_selectedItems.empty()) {
m_selectedItems.reserve(1);
m_selectedItems.push_back({hecl::ProjectPath(*m_useProj, _SYS_STR(""))});
m_selectedItems.push_back({hecl::ProjectPath(*m_useProj, "")});
m_recursive = true;
}
}
static void Help(HelpOutput& help) {
help.secHead(_SYS_STR("NAME"));
help.secHead("NAME");
help.beginWrap();
help.wrap(_SYS_STR("hecl-cook - Cook objects within the project database\n"));
help.wrap("hecl-cook - Cook objects within the project database\n");
help.endWrap();
help.secHead(_SYS_STR("SYNOPSIS"));
help.secHead("SYNOPSIS");
help.beginWrap();
help.wrap(_SYS_STR("hecl cook [-rf] [--fast] [--spec=<spec>] [<pathspec>...]\n"));
help.wrap("hecl cook [-rf] [--fast] [--spec=<spec>] [<pathspec>...]\n");
help.endWrap();
help.secHead(_SYS_STR("DESCRIPTION"));
help.secHead("DESCRIPTION");
help.beginWrap();
help.wrap(_SYS_STR("This command initiates a cooking pass on the project database. Cooking ")
_SYS_STR("is analogous to compiling in software development. The resulting object buffers ")
_SYS_STR("are cached within the project database. HECL performs the following ")
_SYS_STR("tasks for each object during the cook process:\n\n"));
help.wrapBold(_SYS_STR("- Object Gather: "));
help.wrap(_SYS_STR("Files added with "));
help.wrapBold(_SYS_STR("hecl add"));
help.wrap(_SYS_STR(" are queried for their dependent files (e.g. "));
help.wrapBold(_SYS_STR(".blend"));
help.wrap(_SYS_STR(" files return any linked "));
help.wrapBold(_SYS_STR(".png"));
help.wrap(_SYS_STR(" images). If the dependent files are unable to be found, the cook process aborts.\n\n"));
help.wrapBold(_SYS_STR("- Modtime Comparison: "));
help.wrap(_SYS_STR("Files that have previously finished a cook pass are inspected for their time of ")
_SYS_STR("last modification. If the file hasn't changed since its previous cook-pass, the ") _SYS_STR(
"process is skipped. If the file has been moved or deleted, the object is automatically ")
_SYS_STR("removed from the project database.\n\n"));
help.wrapBold(_SYS_STR("- Cook: "));
help.wrap(_SYS_STR("A type-specific procedure compiles the file's contents into an efficient format ")
_SYS_STR("for use by the runtime. A data-buffer is provided to HECL.\n\n"));
help.wrapBold(_SYS_STR("- Hash and Compress: "));
help.wrap(_SYS_STR("The data-buffer is hashed and compressed before being cached in the object database.\n\n"));
help.wrap(
"This command initiates a cooking pass on the project database. Cooking "
"is analogous to compiling in software development. The resulting object buffers "
"are cached within the project database. HECL performs the following "
"tasks for each object during the cook process:\n\n");
help.wrapBold("- Object Gather: ");
help.wrap("Files added with ");
help.wrapBold("hecl add");
help.wrap(" are queried for their dependent files (e.g. ");
help.wrapBold(".blend");
help.wrap(" files return any linked ");
help.wrapBold(".png");
help.wrap(" images). If the dependent files are unable to be found, the cook process aborts.\n\n");
help.wrapBold("- Modtime Comparison: ");
help.wrap(
"Files that have previously finished a cook pass are inspected for their time of "
"last modification. If the file hasn't changed since its previous cook-pass, the "
"process is skipped. If the file has been moved or deleted, the object is automatically "
"removed from the project database.\n\n");
help.wrapBold("- Cook: ");
help.wrap(
"A type-specific procedure compiles the file's contents into an efficient format "
"for use by the runtime. A data-buffer is provided to HECL.\n\n");
help.wrapBold("- Hash and Compress: ");
help.wrap("The data-buffer is hashed and compressed before being cached in the object database.\n\n");
help.endWrap();
help.secHead(_SYS_STR("OPTIONS"));
help.optionHead(_SYS_STR("<pathspec>..."), _SYS_STR("input file(s)"));
help.secHead("OPTIONS");
help.optionHead("<pathspec>...", "input file(s)");
help.beginWrap();
help.wrap(_SYS_STR("Specifies working file(s) containing production data to be cooked by HECL. ")
_SYS_STR("Glob-strings may be specified (e.g. "));
help.wrapBold(_SYS_STR("*.blend"));
help.wrap(_SYS_STR(") to automatically cook all matching current-directory files in the project database. ")
_SYS_STR("If no path specified, all files in the project database are cooked.\n"));
help.wrap(
"Specifies working file(s) containing production data to be cooked by HECL. "
"Glob-strings may be specified (e.g. ");
help.wrapBold("*.blend");
help.wrap(
") to automatically cook all matching current-directory files in the project database. "
"If no path specified, all files in the project database are cooked.\n");
help.endWrap();
help.optionHead(_SYS_STR("-r"), _SYS_STR("recursion"));
help.optionHead("-r", "recursion");
help.beginWrap();
help.wrap(_SYS_STR("Enables recursive file-matching for cooking entire directories of working files.\n"));
help.wrap("Enables recursive file-matching for cooking entire directories of working files.\n");
help.endWrap();
help.optionHead(_SYS_STR("-f"), _SYS_STR("force"));
help.optionHead("-f", "force");
help.beginWrap();
help.wrap(_SYS_STR("Forces cooking of all matched files, ignoring timestamp differences.\n"));
help.wrap("Forces cooking of all matched files, ignoring timestamp differences.\n");
help.endWrap();
help.optionHead(_SYS_STR("--fast"), _SYS_STR("fast cook"));
help.optionHead("--fast", "fast cook");
help.beginWrap();
help.wrap(_SYS_STR("Performs draft-optimization cooking for supported data types.\n"));
help.wrap("Performs draft-optimization cooking for supported data types.\n");
help.endWrap();
help.optionHead(_SYS_STR("--spec=<spec>"), _SYS_STR("data specification"));
help.optionHead("--spec=<spec>", "data specification");
help.beginWrap();
help.wrap(_SYS_STR("Specifies a DataSpec to use when cooking. ")
_SYS_STR("This build of hecl supports the following values of <spec>:\n"));
help.wrap(
"Specifies a DataSpec to use when cooking. "
"This build of hecl supports the following values of <spec>:\n");
for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) {
if (!spec->m_factory)
continue;
help.wrap(_SYS_STR(" "));
help.wrap(" ");
help.wrapBold(spec->m_name.data());
help.wrap(_SYS_STR("\n"));
help.wrap("\n");
}
}
hecl::SystemStringView toolName() const override { return _SYS_STR("cook"sv); }
std::string_view toolName() const override { return "cook"sv; }
int run() override {
hecl::MultiProgressPrinter printer(true);

View File

@@ -32,18 +32,18 @@ public:
LogModule.report(logvisor::Fatal, FMT_STRING("hecl extract needs a source path as its first argument"));
if (!info.project) {
hecl::SystemString rootDir;
std::string rootDir;
if (info.output.empty()) {
/* Get name from input file and init project there */
hecl::SystemString baseFile = info.args.front();
size_t slashPos = baseFile.rfind(_SYS_STR('/'));
if (slashPos == hecl::SystemString::npos)
slashPos = baseFile.rfind(_SYS_STR('\\'));
if (slashPos != hecl::SystemString::npos)
std::string baseFile = info.args.front();
size_t slashPos = baseFile.rfind('/');
if (slashPos == std::string::npos)
slashPos = baseFile.rfind('\\');
if (slashPos != std::string::npos)
baseFile.assign(baseFile.begin() + slashPos + 1, baseFile.end());
size_t dotPos = baseFile.rfind(_SYS_STR('.'));
if (dotPos != hecl::SystemString::npos)
size_t dotPos = baseFile.rfind('.');
if (dotPos != std::string::npos)
baseFile.assign(baseFile.begin(), baseFile.begin() + dotPos);
if (baseFile.empty())
@@ -62,8 +62,8 @@ public:
newProjRoot.makeDir();
m_fallbackProj.reset(new hecl::Database::Project(newProjRoot));
if (logvisor::ErrorCount > ErrorRef)
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("unable to init project at '{}'")), rootDir);
LogModule.report(logvisor::Info, FMT_STRING(_SYS_STR("initialized project at '{}/.hecl'")), rootDir);
LogModule.report(logvisor::Fatal, FMT_STRING("unable to init project at '{}'"), rootDir);
LogModule.report(logvisor::Info, FMT_STRING("initialized project at '{}/.hecl'"), rootDir);
m_useProj = m_fallbackProj.get();
} else
m_useProj = info.project;
@@ -87,44 +87,44 @@ public:
}
static void Help(HelpOutput& help) {
help.secHead(_SYS_STR("NAME"));
help.secHead("NAME");
help.beginWrap();
help.wrap(_SYS_STR("hecl-extract - Extract objects from supported package/image formats\n"));
help.wrap("hecl-extract - Extract objects from supported package/image formats\n");
help.endWrap();
help.secHead(_SYS_STR("SYNOPSIS"));
help.secHead("SYNOPSIS");
help.beginWrap();
help.wrap(_SYS_STR("hecl extract <packagefile> [<subnode>...]\n"));
help.wrap("hecl extract <packagefile> [<subnode>...]\n");
help.endWrap();
help.secHead(_SYS_STR("DESCRIPTION"));
help.secHead("DESCRIPTION");
help.beginWrap();
help.wrap(_SYS_STR("This command recursively extracts all or part of a dataspec-supported ")
_SYS_STR("package format. Each object is decoded to a working format and added to the project.\n\n"));
help.wrap("This command recursively extracts all or part of a dataspec-supported "
"package format. Each object is decoded to a working format and added to the project.\n\n");
help.endWrap();
help.secHead(_SYS_STR("OPTIONS"));
help.optionHead(_SYS_STR("<packagefile>[/<subnode>...]"), _SYS_STR("input file"));
help.secHead("OPTIONS");
help.optionHead("<packagefile>[/<subnode>...]", "input file");
help.beginWrap();
help.wrap(_SYS_STR("Specifies the package file or disc image to source data from. ")
_SYS_STR("An optional subnode specifies a named hierarchical-node specific ")
_SYS_STR("to the game architecture (levels/areas)."));
help.wrap("Specifies the package file or disc image to source data from. "
"An optional subnode specifies a named hierarchical-node specific "
"to the game architecture (levels/areas).");
help.endWrap();
}
hecl::SystemStringView toolName() const override { return _SYS_STR("extract"sv); }
std::string_view toolName() const override { return "extract"sv; }
static void _recursivePrint(int level, hecl::Database::IDataSpec::ExtractReport& rep) {
for (int l = 0; l < level; ++l)
fmt::print(FMT_STRING(_SYS_STR(" ")));
fmt::print(FMT_STRING(" "));
if (XTERM_COLOR)
fmt::print(FMT_STRING(_SYS_STR("" BOLD "{}" NORMAL "")), rep.name);
fmt::print(FMT_STRING("" BOLD "{}" NORMAL ""), rep.name);
else
fmt::print(FMT_STRING(_SYS_STR("{}")), rep.name);
fmt::print(FMT_STRING("{}"), rep.name);
if (rep.desc.size())
fmt::print(FMT_STRING(_SYS_STR(" [{}]")), rep.desc);
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING(" [{}]"), rep.desc);
fmt::print(FMT_STRING("\n"));
for (hecl::Database::IDataSpec::ExtractReport& child : rep.childOpts)
_recursivePrint(level + 1, child);
}
@@ -132,32 +132,32 @@ public:
int run() override {
if (m_specPasses.empty()) {
if (XTERM_COLOR)
fmt::print(FMT_STRING(_SYS_STR("" RED BOLD "NOTHING TO EXTRACT" NORMAL "\n")));
fmt::print(FMT_STRING("" RED BOLD "NOTHING TO EXTRACT" NORMAL "\n"));
else
fmt::print(FMT_STRING(_SYS_STR("NOTHING TO EXTRACT\n")));
fmt::print(FMT_STRING("NOTHING TO EXTRACT\n"));
return 1;
}
if (XTERM_COLOR)
fmt::print(FMT_STRING(_SYS_STR("" GREEN BOLD "ABOUT TO EXTRACT:" NORMAL "\n")));
fmt::print(FMT_STRING("" GREEN BOLD "ABOUT TO EXTRACT:" NORMAL "\n"));
else
fmt::print(FMT_STRING(_SYS_STR("ABOUT TO EXTRACT:\n")));
fmt::print(FMT_STRING("ABOUT TO EXTRACT:\n"));
for (hecl::Database::IDataSpec::ExtractReport& rep : m_reps) {
_recursivePrint(0, rep);
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING("\n"));
}
fflush(stdout);
if (continuePrompt()) {
for (SpecExtractPass& ds : m_specPasses) {
if (XTERM_COLOR)
fmt::print(FMT_STRING(_SYS_STR("" MAGENTA BOLD "Using DataSpec {}:" NORMAL "\n")), ds.m_entry->m_name);
fmt::print(FMT_STRING("" MAGENTA BOLD "Using DataSpec {}:" NORMAL "\n"), ds.m_entry->m_name);
else
fmt::print(FMT_STRING(_SYS_STR("Using DataSpec {}:\n")), ds.m_entry->m_name);
fmt::print(FMT_STRING("Using DataSpec {}:\n"), ds.m_entry->m_name);
ds.m_instance->doExtract(m_einfo, {true});
fmt::print(FMT_STRING(_SYS_STR("\n\n")));
fmt::print(FMT_STRING("\n\n"));
}
}

View File

@@ -20,50 +20,50 @@ public:
static void Help(HelpOutput& help) {
/* clang-format off */
help.printBold(
_SYS_STR(" ___________ \n")
_SYS_STR(" ,.-'\"...........``~., \n")
_SYS_STR(" ,.-\".......................\"-., \n")
_SYS_STR(" ,/..................................\":, \n")
_SYS_STR(" .,?........................................, \n")
_SYS_STR(" /...........................................,}\n")
_SYS_STR(" ./........................................,:`^`..}\n")
_SYS_STR(" ./.......................................,:\"...../\n")
_SYS_STR(" ?.....__..................................:`...../\n")
_SYS_STR(" /__.(...\"~-,_...........................,:`....../\n")
_SYS_STR(" /(_....\"~,_....\"~,_.....................,:`...._/ \n")
_SYS_STR(" {.._$;_....\"=,_.....\"-,_......,.-~-,},.~\";/....} \n")
_SYS_STR(" ((...*~_......\"=-._...\";,,./`........../\"..../ \n")
_SYS_STR(" ,,,___.`~,......\"~.,....................`......}....../ \n")
_SYS_STR("............(....`=-,,...`.........................(...;_,,-\" \n")
_SYS_STR("............/.`~,......`-.................................../ \n")
_SYS_STR(".............`~.*-,.....................................|,./...,__ \n")
_SYS_STR(",,_..........}.>-._...................................|.......`=~-, \n")
_SYS_STR(".....`=~-,__......`,................................. \n")
_SYS_STR("...................`=~-,,.,........................... \n")
_SYS_STR(".........................`:,,..........................`\n")
_SYS_STR("...........................`=-,...............,%%`>--==`` \n")
_SYS_STR(".................................._.........._,-%%...` \n")
_SYS_STR("...................................,\n"));
" ___________ \n"
" ,.-'\"...........``~., \n"
" ,.-\".......................\"-., \n"
" ,/..................................\":, \n"
" .,?........................................, \n"
" /...........................................,}\n"
" ./........................................,:`^`..}\n"
" ./.......................................,:\"...../\n"
" ?.....__..................................:`...../\n"
" /__.(...\"~-,_...........................,:`....../\n"
" /(_....\"~,_....\"~,_.....................,:`...._/ \n"
" {.._$;_....\"=,_.....\"-,_......,.-~-,},.~\";/....} \n"
" ((...*~_......\"=-._...\";,,./`........../\"..../ \n"
" ,,,___.`~,......\"~.,....................`......}....../ \n"
"............(....`=-,,...`.........................(...;_,,-\" \n"
"............/.`~,......`-.................................../ \n"
".............`~.*-,.....................................|,./...,__ \n"
",,_..........}.>-._...................................|.......`=~-, \n"
".....`=~-,__......`,................................. \n"
"...................`=~-,,.,........................... \n"
".........................`:,,..........................`\n"
"...........................`=-,...............,%%`>--==`` \n"
".................................._.........._,-%%...` \n"
"...................................,\n");
/* clang-format on */
}
static void ShowHelp(const hecl::SystemString& toolName) {
static void ShowHelp(const std::string& toolName) {
/* Select tool's help-text streamer */
HelpOutput::HelpFunc helpFunc = nullptr;
if (toolName == _SYS_STR("init"))
if (toolName == "init")
helpFunc = ToolInit::Help;
else if (toolName == _SYS_STR("spec"))
else if (toolName == "spec")
helpFunc = ToolSpec::Help;
else if (toolName == _SYS_STR("extract"))
else if (toolName == "extract")
helpFunc = ToolExtract::Help;
else if (toolName == _SYS_STR("cook"))
else if (toolName == "cook")
helpFunc = ToolCook::Help;
else if (toolName == _SYS_STR("package") || toolName == _SYS_STR("pack"))
else if (toolName == "package" || toolName == "pack")
helpFunc = ToolPackage::Help;
else if (toolName == _SYS_STR("help"))
else if (toolName == "help")
helpFunc = ToolHelp::Help;
else {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unrecognized tool '{}' - can't help")), toolName);
LogModule.report(logvisor::Error, FMT_STRING("unrecognized tool '{}' - can't help"), toolName);
return;
}
@@ -71,7 +71,7 @@ public:
ho.go();
}
hecl::SystemStringView toolName() const override { return _SYS_STR("help"sv); }
std::string_view toolName() const override { return "help"sv; }
int run() override {
ShowHelp(m_info.args.front());

View File

@@ -22,11 +22,11 @@ public:
/* Scan args */
if (info.args.size()) {
/* See if project path is supplied via args and use that over the getcwd one */
for (const hecl::SystemString& arg : info.args) {
for (const std::string& arg : info.args) {
if (arg.empty())
continue;
hecl::SystemString subPath;
std::string subPath;
hecl::ProjectRootPath root = hecl::SearchForProject(MakePathArgAbsolute(arg, info.cwd), subPath);
if (root) {
@@ -47,83 +47,82 @@ public:
~ToolImage() override = default;
static void Help(HelpOutput& help) {
help.secHead(_SYS_STR("NAME"));
help.secHead("NAME");
help.beginWrap();
help.wrap(_SYS_STR("hecl-image - Generate GameCube/Wii disc image from packaged files\n"));
help.wrap("hecl-image - Generate GameCube/Wii disc image from packaged files\n");
help.endWrap();
help.secHead(_SYS_STR("SYNOPSIS"));
help.secHead("SYNOPSIS");
help.beginWrap();
help.wrap(_SYS_STR("hecl image [<input-dir>]\n"));
help.wrap("hecl image [<input-dir>]\n");
help.endWrap();
help.secHead(_SYS_STR("DESCRIPTION"));
help.secHead("DESCRIPTION");
help.beginWrap();
help.wrap(_SYS_STR("This command uses the current contents of `out` to generate a GameCube or ")
_SYS_STR("Wii disc image. `hecl package` must have been run previously to be effective.\n"));
help.wrap("This command uses the current contents of `out` to generate a GameCube or "
"Wii disc image. `hecl package` must have been run previously to be effective.\n");
help.endWrap();
help.secHead(_SYS_STR("OPTIONS"));
help.optionHead(_SYS_STR("<input-dir>"), _SYS_STR("input directory"));
help.secHead("OPTIONS");
help.optionHead("<input-dir>", "input directory");
help.beginWrap();
help.wrap(_SYS_STR("Specifies a project subdirectory to root the resulting image from. ")
_SYS_STR("Project must contain an out/sys and out/files directory to succeed.\n"));
help.wrap("Specifies a project subdirectory to root the resulting image from. "
"Project must contain an out/sys and out/files directory to succeed.\n");
help.endWrap();
}
hecl::SystemStringView toolName() const override { return _SYS_STR("image"sv); }
std::string_view toolName() const override { return "image"sv; }
int run() override {
if (XTERM_COLOR)
fmt::print(FMT_STRING(_SYS_STR("" GREEN BOLD "ABOUT TO IMAGE:" NORMAL "\n")));
fmt::print(FMT_STRING("" GREEN BOLD "ABOUT TO IMAGE:" NORMAL "\n"));
else
fmt::print(FMT_STRING(_SYS_STR("ABOUT TO IMAGE:\n")));
fmt::print(FMT_STRING("ABOUT TO IMAGE:\n"));
fmt::print(FMT_STRING(_SYS_STR(" {}\n")), m_useProj->getProjectRootPath().getAbsolutePath());
fmt::print(FMT_STRING(" {}\n"), m_useProj->getProjectRootPath().getAbsolutePath());
fflush(stdout);
if (continuePrompt()) {
hecl::ProjectPath outPath(m_useProj->getProjectWorkingPath(), _SYS_STR("out"));
hecl::ProjectPath outPath(m_useProj->getProjectWorkingPath(), "out");
if (!outPath.isDirectory()) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("{} is not a directory")), outPath.getAbsolutePath());
LogModule.report(logvisor::Error, FMT_STRING("{} is not a directory"), outPath.getAbsolutePath());
return 1;
}
hecl::ProjectPath bootBinPath(outPath, _SYS_STR("sys/boot.bin"));
hecl::ProjectPath bootBinPath(outPath, "sys/boot.bin");
if (!bootBinPath.isFile()) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("{} is not a file")), bootBinPath.getAbsolutePath());
LogModule.report(logvisor::Error, FMT_STRING("{} is not a file"), bootBinPath.getAbsolutePath());
return 1;
}
athena::io::FileReader r(bootBinPath.getAbsolutePath());
if (r.hasError()) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to open {}")), bootBinPath.getAbsolutePath());
LogModule.report(logvisor::Error, FMT_STRING("unable to open {}"), bootBinPath.getAbsolutePath());
return 1;
}
std::string id = r.readString(6);
r.close();
hecl::SystemStringConv idView(id);
hecl::SystemString fileOut = hecl::SystemString(outPath.getAbsolutePath()) + _SYS_STR('/') + idView.c_str();
std::string fileOut = std::string(outPath.getAbsolutePath()) + '/' + id;
hecl::MultiProgressPrinter printer(true);
auto progFunc = [&printer](float totalProg, nod::SystemStringView fileName, size_t fileBytesXfered) {
auto progFunc = [&printer](float totalProg, std::string_view fileName, size_t fileBytesXfered) {
printer.print(fileName, std::nullopt, totalProg);
};
if (id[0] == 'G') {
fileOut += _SYS_STR(".gcm");
fileOut += ".gcm";
if (nod::DiscBuilderGCN::CalculateTotalSizeRequired(outPath.getAbsolutePath()) == UINT64_MAX)
return 1;
LogModule.report(logvisor::Info, FMT_STRING(_SYS_STR("Generating {} as GameCube image")), fileOut);
LogModule.report(logvisor::Info, FMT_STRING("Generating {} as GameCube image"), fileOut);
nod::DiscBuilderGCN db(fileOut, progFunc);
if (db.buildFromDirectory(outPath.getAbsolutePath()) != nod::EBuildResult::Success)
return 1;
} else {
fileOut += _SYS_STR(".iso");
fileOut += ".iso";
bool dualLayer;
if (nod::DiscBuilderWii::CalculateTotalSizeRequired(outPath.getAbsolutePath(), dualLayer) == UINT64_MAX)
return 1;
LogModule.report(logvisor::Info, FMT_STRING(_SYS_STR("Generating {} as {}-layer Wii image")), fileOut,
dualLayer ? _SYS_STR("dual") : _SYS_STR("single"));
LogModule.report(logvisor::Info, FMT_STRING("Generating {} as {}-layer Wii image"), fileOut,
dualLayer ? "dual" : "single");
nod::DiscBuilderWii db(fileOut, dualLayer, progFunc);
if (db.buildFromDirectory(outPath.getAbsolutePath()) != nod::EBuildResult::Success)
return 1;

View File

@@ -4,12 +4,12 @@
#include <cstdio>
class ToolInit final : public ToolBase {
const hecl::SystemString* m_dir = nullptr;
const std::string* m_dir = nullptr;
public:
explicit ToolInit(const ToolPassInfo& info) : ToolBase(info) {
hecl::Sstat theStat;
const hecl::SystemString* dir;
const std::string* dir;
if (info.args.size())
dir = &info.args.front();
else
@@ -18,18 +18,18 @@ public:
if (hecl::Stat(dir->c_str(), &theStat)) {
hecl::MakeDir(dir->c_str());
if (hecl::Stat(dir->c_str(), &theStat)) {
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("unable to stat '{}'")), *dir);
LogModule.report(logvisor::Fatal, FMT_STRING("unable to stat '{}'"), *dir);
return;
}
}
if (!S_ISDIR(theStat.st_mode)) {
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("'{}' is not a directory")), *dir);
LogModule.report(logvisor::Fatal, FMT_STRING("'{}' is not a directory"), *dir);
return;
}
hecl::SystemString testPath = *dir + _SYS_STR("/.hecl/beacon");
std::string testPath = *dir + "/.hecl/beacon";
if (!hecl::Stat(testPath.c_str(), &theStat)) {
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("project already exists at '{}'")), *dir);
LogModule.report(logvisor::Fatal, FMT_STRING("project already exists at '{}'"), *dir);
return;
}
@@ -43,35 +43,35 @@ public:
hecl::Database::Project proj((hecl::ProjectRootPath(*m_dir)));
if (logvisor::ErrorCount > ErrorRef)
return 1;
LogModule.report(logvisor::Info, FMT_STRING(_SYS_STR("initialized project at '{}/.hecl'")), *m_dir);
LogModule.report(logvisor::Info, FMT_STRING("initialized project at '{}/.hecl'"), *m_dir);
return 0;
}
static void Help(HelpOutput& help) {
help.secHead(_SYS_STR("NAME"));
help.secHead("NAME");
help.beginWrap();
help.wrap(_SYS_STR("hecl-init - Initialize a brand-new project database\n"));
help.wrap("hecl-init - Initialize a brand-new project database\n");
help.endWrap();
help.secHead(_SYS_STR("SYNOPSIS"));
help.secHead("SYNOPSIS");
help.beginWrap();
help.wrap(_SYS_STR("hecl init [<dir>]\n"));
help.wrap("hecl init [<dir>]\n");
help.endWrap();
help.secHead(_SYS_STR("DESCRIPTION"));
help.secHead("DESCRIPTION");
help.beginWrap();
help.wrap(_SYS_STR("Creates a "));
help.wrapBold(_SYS_STR(".hecl"));
help.wrap(_SYS_STR(" directory within the selected directory with an initialized database index. ")
_SYS_STR("This constitutes an empty HECL project, ready for making stuff!!\n"));
help.wrap("Creates a ");
help.wrapBold(".hecl");
help.wrap(" directory within the selected directory with an initialized database index. "
"This constitutes an empty HECL project, ready for making stuff!!\n");
help.endWrap();
help.secHead(_SYS_STR("OPTIONS"));
help.optionHead(_SYS_STR("<dir>"), _SYS_STR("group directory path"));
help.secHead("OPTIONS");
help.optionHead("<dir>", "group directory path");
help.beginWrap();
help.wrap(_SYS_STR("Directory to create new project database in. If not specified, current directory is used.\n"));
help.wrap("Directory to create new project database in. If not specified, current directory is used.\n");
help.endWrap();
}
hecl::SystemStringView toolName() const override { return _SYS_STR("init"sv); }
std::string_view toolName() const override { return "init"sv; }
};

View File

@@ -13,22 +13,22 @@ public:
}
static void Help(HelpOutput& help) {
help.secHead(_SYS_STR("NAME"));
help.secHead("NAME");
help.beginWrap();
help.wrap(_SYS_STR("hecl-installaddon - Installs embedded Blender addon into local Blender\n"));
help.wrap("hecl-installaddon - Installs embedded Blender addon into local Blender\n");
help.endWrap();
help.secHead(_SYS_STR("SYNOPSIS"));
help.secHead("SYNOPSIS");
help.beginWrap();
help.wrap(_SYS_STR("hecl installaddon\n"));
help.wrap("hecl installaddon\n");
help.endWrap();
help.secHead(_SYS_STR("DESCRIPTION"));
help.secHead("DESCRIPTION");
help.beginWrap();
help.wrap(_SYS_STR("Installs the hecl Blender addon into Blender. The path to the blender executable ")
_SYS_STR("can be overridden by setting the BLENDER_BIN environment variable."));
help.wrap("Installs the hecl Blender addon into Blender. The path to the blender executable "
"can be overridden by setting the BLENDER_BIN environment variable.");
help.endWrap();
}
hecl::SystemStringView toolName() const override { return _SYS_STR("installaddon"sv); }
std::string_view toolName() const override { return "installaddon"sv; }
};

View File

@@ -21,8 +21,8 @@ class ToolPackage final : public ToolBase {
void CheckFile(const hecl::ProjectPath& path) {
auto lastComp = path.getLastComponent();
if (hecl::StringUtils::BeginsWith(lastComp, _SYS_STR("!world")) &&
hecl::StringUtils::EndsWith(lastComp, _SYS_STR(".blend")))
if (hecl::StringUtils::BeginsWith(lastComp, "!world") &&
hecl::StringUtils::EndsWith(lastComp, ".blend"))
AddSelectedItem(path);
}
@@ -47,8 +47,8 @@ class ToolPackage final : public ToolBase {
* and no nested !world.blend files == General PAK */
if (checkGeneral && origSize == m_selectedItems.size()) {
auto pathComps = path.getPathComponents();
if (pathComps.size() == 2 && pathComps[0] != _SYS_STR("out") && pathComps[1] != _SYS_STR("Shared") &&
pathComps[0].find(_SYS_STR(".app")) == hecl::SystemString::npos)
if (pathComps.size() == 2 && pathComps[0] != "out" && pathComps[1] != "Shared" &&
pathComps[0].find(".app") == std::string::npos)
AddSelectedItem(path);
}
}
@@ -62,14 +62,14 @@ public:
if (info.args.size()) {
/* See if project path is supplied via args and use that over the getcwd one */
m_selectedItems.reserve(info.args.size());
for (const hecl::SystemString& arg : info.args) {
for (const std::string& arg : info.args) {
if (arg.empty())
continue;
else if (arg == _SYS_STR("--fast")) {
else if (arg == "--fast") {
m_fast = true;
continue;
} else if (arg.size() >= 8 && !arg.compare(0, 7, _SYS_STR("--spec="))) {
hecl::SystemString specName(arg.begin() + 7, arg.end());
} else if (arg.size() >= 8 && !arg.compare(0, 7, "--spec=")) {
std::string specName(arg.begin() + 7, arg.end());
for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) {
if (!hecl::StrCaseCmp(spec->m_name.data(), specName.c_str())) {
m_spec = spec;
@@ -77,12 +77,12 @@ public:
}
}
if (!m_spec)
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("unable to find data spec '{}'")), specName);
LogModule.report(logvisor::Fatal, FMT_STRING("unable to find data spec '{}'"), specName);
continue;
} else if (arg.size() >= 2 && arg[0] == _SYS_STR('-') && arg[1] == _SYS_STR('-'))
} else if (arg.size() >= 2 && arg[0] == '-' && arg[1] == '-')
continue;
hecl::SystemString subPath;
std::string subPath;
hecl::ProjectRootPath root = hecl::SearchForProject(MakePathArgAbsolute(arg, info.cwd), subPath);
if (root) {
@@ -91,8 +91,8 @@ public:
m_useProj = m_fallbackProj.get();
} else if (m_fallbackProj->getProjectRootPath() != root)
LogModule.report(logvisor::Fatal,
FMT_STRING(_SYS_STR("hecl package can only process multiple items in the same project; ")
_SYS_STR("'{}' and '{}' are different projects")),
FMT_STRING("hecl package can only process multiple items in the same project; "
"'{}' and '{}' are different projects"),
m_fallbackProj->getProjectRootPath().getAbsolutePath(),
root.getAbsolutePath());
@@ -107,60 +107,65 @@ public:
/* Default case: recursive at root */
if (m_selectedItems.empty())
FindSelectedItems({*m_useProj, _SYS_STR("")}, true);
FindSelectedItems({*m_useProj, ""}, true);
}
static void Help(HelpOutput& help) {
help.secHead(_SYS_STR("NAME"));
help.secHead("NAME");
help.beginWrap();
help.wrap(_SYS_STR("hecl-pack\n") _SYS_STR("hecl-package - Package objects within the project database\n"));
help.wrap(
"hecl-pack\n"
"hecl-package - Package objects within the project database\n");
help.endWrap();
help.secHead(_SYS_STR("SYNOPSIS"));
help.secHead("SYNOPSIS");
help.beginWrap();
help.wrap(_SYS_STR("hecl package [--spec=<spec>] [<input-dir>]\n"));
help.wrap("hecl package [--spec=<spec>] [<input-dir>]\n");
help.endWrap();
help.secHead(_SYS_STR("DESCRIPTION"));
help.secHead("DESCRIPTION");
help.beginWrap();
help.wrap(_SYS_STR("This command initiates a packaging pass on the project database. Packaging ")
_SYS_STR("is analogous to linking in software development. All objects necessary to ") _SYS_STR(
"generate a complete package are gathered, grouped, and indexed within a .upak file.\n"));
help.wrap(
"This command initiates a packaging pass on the project database. Packaging "
"is analogous to linking in software development. All objects necessary to "
"generate a complete package are gathered, grouped, and indexed within a .upak file.\n");
help.endWrap();
help.secHead(_SYS_STR("OPTIONS"));
help.optionHead(_SYS_STR("--spec=<spec>"), _SYS_STR("data specification"));
help.secHead("OPTIONS");
help.optionHead("--spec=<spec>", "data specification");
help.beginWrap();
help.wrap(_SYS_STR("Specifies a DataSpec to use when cooking and generating the package. ")
_SYS_STR("This build of hecl supports the following values of <spec>:\n"));
help.wrap(
"Specifies a DataSpec to use when cooking and generating the package. "
"This build of hecl supports the following values of <spec>:\n");
for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) {
if (!spec->m_factory)
continue;
help.wrap(_SYS_STR(" "));
help.wrap(" ");
help.wrapBold(spec->m_name.data());
help.wrap(_SYS_STR("\n"));
help.wrap("\n");
}
help.endWrap();
help.secHead(_SYS_STR("OPTIONS"));
help.optionHead(_SYS_STR("<input-dir>"), _SYS_STR("input directory"));
help.secHead("OPTIONS");
help.optionHead("<input-dir>", "input directory");
help.beginWrap();
help.wrap(_SYS_STR("Specifies a project subdirectory to root the resulting package from. ")
_SYS_STR("If any dependent files fall outside this subdirectory, they will be implicitly ")
_SYS_STR("gathered and packaged.\n"));
help.wrap(
"Specifies a project subdirectory to root the resulting package from. "
"If any dependent files fall outside this subdirectory, they will be implicitly "
"gathered and packaged.\n");
help.endWrap();
}
hecl::SystemStringView toolName() const override { return _SYS_STR("package"sv); }
std::string_view toolName() const override { return "package"sv; }
int run() override {
if (XTERM_COLOR)
fmt::print(FMT_STRING(_SYS_STR("" GREEN BOLD "ABOUT TO PACKAGE:" NORMAL "\n")));
fmt::print(FMT_STRING("" GREEN BOLD "ABOUT TO PACKAGE:" NORMAL "\n"));
else
fmt::print(FMT_STRING(_SYS_STR("ABOUT TO PACKAGE:\n")));
fmt::print(FMT_STRING("ABOUT TO PACKAGE:\n"));
for (auto& item : m_selectedItems)
fmt::print(FMT_STRING(_SYS_STR(" {}\n")), item.getRelativePath());
fmt::print(FMT_STRING(" {}\n"), item.getRelativePath());
fflush(stdout);
if (continuePrompt()) {
@@ -168,7 +173,7 @@ public:
hecl::ClientProcess cp(&printer);
for (const hecl::ProjectPath& path : m_selectedItems) {
if (!m_useProj->packagePath(path, printer, m_fast, m_spec, &cp))
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("Unable to package {}")), path.getAbsolutePath());
LogModule.report(logvisor::Error, FMT_STRING("Unable to package {}"), path.getAbsolutePath());
}
cp.waitUntilComplete();
}

View File

@@ -16,12 +16,12 @@ public:
LogModule.report(logvisor::Fatal, FMT_STRING("hecl spec must be ran within a project directory"));
const auto& specs = info.project->getDataSpecs();
hecl::SystemString firstArg = info.args.front();
std::string firstArg = info.args.front();
hecl::ToLower(firstArg);
if (firstArg == _SYS_STR("enable"))
if (firstArg == "enable")
mode = MENABLE;
else if (firstArg == _SYS_STR("disable"))
else if (firstArg == "disable")
mode = MDISABLE;
else
return;
@@ -41,46 +41,46 @@ public:
}
}
if (!found)
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("'{}' is not found in the dataspec registry")), *it);
LogModule.report(logvisor::Fatal, FMT_STRING("'{}' is not found in the dataspec registry"), *it);
}
}
static void Help(HelpOutput& help) {
help.secHead(_SYS_STR("NAME"));
help.secHead("NAME");
help.beginWrap();
help.wrap(_SYS_STR("hecl-spec - Configure target data options\n"));
help.wrap("hecl-spec - Configure target data options\n");
help.endWrap();
help.secHead(_SYS_STR("SYNOPSIS"));
help.secHead("SYNOPSIS");
help.beginWrap();
help.wrap(_SYS_STR("hecl spec [enable|disable] [<specname>...]\n"));
help.wrap("hecl spec [enable|disable] [<specname>...]\n");
help.endWrap();
help.secHead(_SYS_STR("DESCRIPTION"));
help.secHead("DESCRIPTION");
help.beginWrap();
help.wrap(
_SYS_STR("This command configures the HECL project with the user's preferred target DataSpecs.\n\n")
_SYS_STR("Providing enable/disable argument will bulk-set the enable status of the provided spec(s)")
_SYS_STR("list. If enable/disable is not provided, a list of supported DataSpecs is printed.\n\n"));
"This command configures the HECL project with the user's preferred target DataSpecs.\n\n"
"Providing enable/disable argument will bulk-set the enable status of the provided spec(s)"
"list. If enable/disable is not provided, a list of supported DataSpecs is printed.\n\n");
help.endWrap();
help.secHead(_SYS_STR("OPTIONS"));
help.optionHead(_SYS_STR("<specname>..."), _SYS_STR("DataSpec name(s)"));
help.secHead("OPTIONS");
help.optionHead("<specname>...", "DataSpec name(s)");
help.beginWrap();
help.wrap(_SYS_STR("Specifies platform-names to enable/disable"));
help.wrap("Specifies platform-names to enable/disable");
help.endWrap();
}
hecl::SystemStringView toolName() const override { return _SYS_STR("spec"sv); }
std::string_view toolName() const override { return "spec"sv; }
int run() override {
if (!m_info.project) {
for (const hecl::Database::DataSpecEntry* spec : hecl::Database::DATA_SPEC_REGISTRY) {
if (XTERM_COLOR)
fmt::print(FMT_STRING(_SYS_STR("" BOLD CYAN "{}" NORMAL "\n")), spec->m_name);
fmt::print(FMT_STRING("" BOLD CYAN "{}" NORMAL "\n"), spec->m_name);
else
fmt::print(FMT_STRING(_SYS_STR("{}\n")), spec->m_name);
fmt::print(FMT_STRING(_SYS_STR(" {}\n")), spec->m_desc);
fmt::print(FMT_STRING("{}\n"), spec->m_name);
fmt::print(FMT_STRING(" {}\n"), spec->m_desc);
}
return 0;
}
@@ -89,28 +89,28 @@ public:
if (mode == MLIST) {
for (auto& spec : specs) {
if (XTERM_COLOR)
fmt::print(FMT_STRING(_SYS_STR("" BOLD CYAN "{}" NORMAL "")), spec.spec.m_name);
fmt::print(FMT_STRING("" BOLD CYAN "{}" NORMAL ""), spec.spec.m_name);
else
fmt::print(FMT_STRING(_SYS_STR("{}")), spec.spec.m_name);
fmt::print(FMT_STRING("{}"), spec.spec.m_name);
if (spec.active) {
if (XTERM_COLOR)
fmt::print(FMT_STRING(_SYS_STR(" " BOLD GREEN "[ENABLED]" NORMAL "")));
fmt::print(FMT_STRING(" " BOLD GREEN "[ENABLED]" NORMAL ""));
else
fmt::print(FMT_STRING(_SYS_STR(" [ENABLED]")));
fmt::print(FMT_STRING(" [ENABLED]"));
}
fmt::print(FMT_STRING(_SYS_STR("\n {}\n")), spec.spec.m_desc);
fmt::print(FMT_STRING("\n {}\n"), spec.spec.m_desc);
}
return 0;
}
std::vector<hecl::SystemString> opSpecs;
std::vector<std::string> opSpecs;
auto it = m_info.args.begin();
++it;
for (; it != m_info.args.end(); ++it) {
hecl::SystemString itName = *it;
std::string itName = *it;
hecl::ToLower(itName);
for (auto& spec : specs) {
hecl::SystemString compName(spec.spec.m_name);
std::string compName(spec.spec.m_name);
hecl::ToLower(compName);
if (itName == compName) {
opSpecs.emplace_back(spec.spec.m_name);

View File

@@ -46,27 +46,27 @@ bool XTERM_COLOR = false;
*/
/* Main usage message */
static void printHelp(const hecl::SystemChar* pname) {
static void printHelp(const char* pname) {
if (XTERM_COLOR)
fmt::print(FMT_STRING(_SYS_STR("" BOLD "HECL" NORMAL "")));
fmt::print(FMT_STRING("" BOLD "HECL" NORMAL ""));
else
fmt::print(FMT_STRING(_SYS_STR("HECL")));
fmt::print(FMT_STRING("HECL"));
#if HECL_HAS_NOD
#define TOOL_LIST "extract|init|cook|package|image|installaddon|help"
#else
#define TOOL_LIST "extract|init|cook|package|installaddon|help"
#endif
#if HECL_GIT
fmt::print(FMT_STRING(_SYS_STR(" Commit " HECL_GIT_S " " HECL_BRANCH_S "\nUsage: {} " TOOL_LIST "\n")), pname);
fmt::print(FMT_STRING(" Commit " HECL_GIT_S " " HECL_BRANCH_S "\nUsage: {} " TOOL_LIST "\n"), pname);
#elif HECL_VER
fmt::print(FMT_STRING(_SYS_STR(" Version " HECL_VER_S "\nUsage: {} " TOOL_LIST "\n")), pname);
fmt::print(FMT_STRING(" Version " HECL_VER_S "\nUsage: {} " TOOL_LIST "\n"), pname);
#else
fmt::print(FMT_STRING(_SYS_STR("\nUsage: {} " TOOL_LIST "\n")), pname);
fmt::print(FMT_STRING("\nUsage: {} " TOOL_LIST "\n"), pname);
#endif
}
/* Regex patterns */
static const hecl::SystemRegex regOPEN(_SYS_STR("-o([^\"]*|\\S*)"), std::regex::ECMAScript | std::regex::optimize);
static const std::regex regOPEN("-o([^\"]*|\\S*)", std::regex::ECMAScript | std::regex::optimize);
static ToolBase* ToolPtr = nullptr;
@@ -85,40 +85,36 @@ static void AthenaExc(athena::error::Level level, const char* file, const char*,
AthenaLog.vreport(logvisor::Level(level), fmt, args);
}
hecl::SystemString ExeDir;
std::string ExeDir;
#if _WIN32
static ToolPassInfo CreateInfo(int argc, const wchar_t** argv) {
#else
static ToolPassInfo CreateInfo(int argc, const char** argv) {
#endif
hecl::SystemChar cwdbuf[1024];
static ToolPassInfo CreateInfo(int argc, char** argv) {
char cwdbuf[1024];
ToolPassInfo info;
info.pname = argv[0];
if (hecl::Getcwd(cwdbuf, static_cast<int>(std::size(cwdbuf)))) {
info.cwd = cwdbuf;
if (info.cwd.size() && info.cwd.back() != _SYS_STR('/') && info.cwd.back() != _SYS_STR('\\')) {
if (info.cwd.size() && info.cwd.back() != '/' && info.cwd.back() != '\\') {
#if _WIN32
info.cwd += _SYS_STR('\\');
info.cwd += '\\';
#else
info.cwd += _SYS_STR('/');
info.cwd += '/';
#endif
}
if (hecl::PathRelative(argv[0])) {
ExeDir = hecl::SystemString(cwdbuf) + _SYS_STR('/');
ExeDir = std::string(cwdbuf) + '/';
}
hecl::SystemString Argv0(argv[0]);
hecl::SystemString::size_type lastIdx = Argv0.find_last_of(_SYS_STR("/\\"));
if (lastIdx != hecl::SystemString::npos) {
std::string Argv0(argv[0]);
std::string::size_type lastIdx = Argv0.find_last_of("/\\");
if (lastIdx != std::string::npos) {
ExeDir.insert(ExeDir.end(), Argv0.begin(), Argv0.begin() + lastIdx);
}
}
/* Concatenate args */
std::vector<hecl::SystemString> args;
std::vector<std::string> args;
args.reserve(argc - 2);
for (int i = 2; i < argc; ++i) {
args.emplace_back(argv[i]);
@@ -127,11 +123,11 @@ static ToolPassInfo CreateInfo(int argc, const char** argv) {
if (!args.empty()) {
/* Extract output argument */
for (auto it = args.cbegin(); it != args.cend();) {
const hecl::SystemString& arg = *it;
hecl::SystemRegexMatch oMatch;
const std::string& arg = *it;
std::smatch oMatch;
if (std::regex_search(arg, oMatch, regOPEN)) {
const hecl::SystemString& token = oMatch[1].str();
const std::string& token = oMatch[1].str();
if (token.size()) {
if (info.output.empty()) {
@@ -162,28 +158,28 @@ static ToolPassInfo CreateInfo(int argc, const char** argv) {
/* Iterate flags */
bool threadArg = false;
for (auto it = args.cbegin(); it != args.cend();) {
const hecl::SystemString& arg = *it;
const std::string& arg = *it;
if (threadArg) {
threadArg = false;
hecl::CpuCountOverride = int(hecl::StrToUl(arg.c_str(), nullptr, 0));
it = args.erase(it);
continue;
}
if (arg.size() < 2 || arg[0] != _SYS_STR('-') || arg[1] == _SYS_STR('-')) {
if (arg.size() < 2 || arg[0] != '-' || arg[1] == '-') {
++it;
continue;
}
for (auto chit = arg.cbegin() + 1; chit != arg.cend(); ++chit) {
if (*chit == _SYS_STR('v'))
if (*chit == 'v')
++info.verbosityLevel;
else if (*chit == _SYS_STR('f'))
else if (*chit == 'f')
info.force = true;
else if (*chit == _SYS_STR('y'))
else if (*chit == 'y')
info.yes = true;
else if (*chit == _SYS_STR('g'))
else if (*chit == 'g')
info.gui = true;
else if (*chit == _SYS_STR('j')) {
else if (*chit == 'j') {
++chit;
if (*chit)
hecl::CpuCountOverride = int(hecl::StrToUl(&*chit, nullptr, 0));
@@ -199,14 +195,14 @@ static ToolPassInfo CreateInfo(int argc, const char** argv) {
/* Gather remaining args */
info.args.reserve(args.size());
for (const hecl::SystemString& arg : args)
for (const std::string& arg : args)
info.args.push_back(arg);
}
return info;
}
static std::unique_ptr<hecl::Database::Project> FindProject(hecl::SystemStringView cwd) {
static std::unique_ptr<hecl::Database::Project> FindProject(std::string_view cwd) {
const hecl::ProjectRootPath rootPath = hecl::SearchForProject(cwd);
if (!rootPath) {
return nullptr;
@@ -224,47 +220,47 @@ static std::unique_ptr<hecl::Database::Project> FindProject(hecl::SystemStringVi
return newProj;
}
static std::unique_ptr<ToolBase> MakeSelectedTool(hecl::SystemString toolName, ToolPassInfo& info) {
hecl::SystemString toolNameLower = toolName;
static std::unique_ptr<ToolBase> MakeSelectedTool(std::string toolName, ToolPassInfo& info) {
std::string toolNameLower = toolName;
hecl::ToLower(toolNameLower);
if (toolNameLower == _SYS_STR("init")) {
if (toolNameLower == "init") {
return std::make_unique<ToolInit>(info);
}
if (toolNameLower == _SYS_STR("spec")) {
if (toolNameLower == "spec") {
return std::make_unique<ToolSpec>(info);
}
if (toolNameLower == _SYS_STR("extract")) {
if (toolNameLower == "extract") {
return std::make_unique<ToolExtract>(info);
}
if (toolNameLower == _SYS_STR("cook")) {
if (toolNameLower == "cook") {
return std::make_unique<ToolCook>(info);
}
if (toolNameLower == _SYS_STR("package") || toolNameLower == _SYS_STR("pack")) {
if (toolNameLower == "package" || toolNameLower == "pack") {
return std::make_unique<ToolPackage>(info);
}
#if HECL_HAS_NOD
if (toolNameLower == _SYS_STR("image")) {
if (toolNameLower == "image") {
return std::make_unique<ToolImage>(info);
}
#endif
if (toolNameLower == _SYS_STR("installaddon")) {
if (toolNameLower == "installaddon") {
return std::make_unique<ToolInstallAddon>(info);
}
if (toolNameLower == _SYS_STR("help")) {
if (toolNameLower == "help") {
return std::make_unique<ToolHelp>(info);
}
auto fp = hecl::FopenUnique(toolName.c_str(), _SYS_STR("rb"));
auto fp = hecl::FopenUnique(toolName.c_str(), "rb");
if (fp == nullptr) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unrecognized tool '{}'")), toolNameLower);
LogModule.report(logvisor::Error, FMT_STRING("unrecognized tool '{}'"), toolNameLower);
return nullptr;
}
fp.reset();
@@ -275,14 +271,16 @@ static std::unique_ptr<ToolBase> MakeSelectedTool(hecl::SystemString toolName, T
}
#if _WIN32
int wmain(int argc, const wchar_t** argv)
#include <nowide/args.hpp>
#else
/* SIGWINCH should do nothing */
static void SIGWINCHHandler(int sig) {}
int main(int argc, const char** argv)
#endif
{
if (argc > 1 && !hecl::StrCmp(argv[1], _SYS_STR("--dlpackage"))) {
int main(int argc, char** argv) {
#if _WIN32
nowide::args _(argc, argv);
#endif
if (argc > 1 && !hecl::StrCmp(argv[1], "--dlpackage")) {
fmt::print(FMT_STRING("{}\n"), METAFORCE_DLPACKAGE);
return 100;
}
@@ -295,9 +293,10 @@ int main(int argc, const char** argv)
/* Xterm check */
#if _WIN32
const char* conemuANSI = getenv("ConEmuANSI");
if (conemuANSI && !strcmp(conemuANSI, "ON"))
const auto conemuANSI = hecl::GetEnv("ConEmuANSI");
if (conemuANSI && conemuANSI == "ON") {
XTERM_COLOR = true;
}
#else
const char* term = getenv("TERM");
if (term && !strncmp(term, "xterm", 5))
@@ -311,8 +310,8 @@ int main(int argc, const char** argv)
atSetExceptionHandler(AthenaExc);
#if SENTRY_ENABLED
hecl::Runtime::FileStoreManager fileMgr{_SYS_STR("sentry-native-hecl")};
hecl::SystemUTF8Conv cacheDir{fileMgr.getStoreRoot()};
hecl::Runtime::FileStoreManager fileMgr{"sentry-native-hecl"};
std::string cacheDir{fileMgr.getStoreRoot()};
logvisor::RegisterSentry("hecl", METAFORCE_WC_DESCRIBE, cacheDir.c_str());
#endif
@@ -323,8 +322,9 @@ int main(int argc, const char** argv)
system("PAUSE");
#endif
return 0;
} else if (argc == 0) {
printHelp(_SYS_STR("hecl"));
}
if (argc == 0) {
printHelp("hecl");
#if WIN_PAUSE
system("PAUSE");
#endif
@@ -353,7 +353,7 @@ int main(int argc, const char** argv)
return 1;
}
if (info.verbosityLevel) {
LogModule.report(logvisor::Info, FMT_STRING(_SYS_STR("Constructed tool '{}' {}\n")), tool->toolName(),
LogModule.report(logvisor::Info, FMT_STRING("Constructed tool '{}' {}\n"), tool->toolName(),
info.verbosityLevel);
}

View File

@@ -731,7 +731,7 @@ class Connection {
BlendType m_loadedType = BlendType::None;
bool m_loadedRigged = false;
ProjectPath m_loadedBlend;
hecl::SystemString m_errPath;
std::string m_errPath;
uint32_t _readStr(char* buf, uint32_t bufSz);
uint32_t _writeStr(const char* str, uint32_t len, int wpipe);
uint32_t _writeStr(const char* str, uint32_t len) { return _writeStr(str, len, m_writepipe[1]); }
@@ -805,7 +805,7 @@ class Connection {
char readBuf[16];
_readStr(readBuf, 16);
if (status != readBuf)
BlenderLog.report(logvisor::Fatal, FMT_STRING("{}: {}: {}"), m_loadedBlend.getRelativePathUTF8(), action, readBuf);
BlenderLog.report(logvisor::Fatal, FMT_STRING("{}: {}: {}"), m_loadedBlend.getRelativePath(), action, readBuf);
}
void _checkReady(std::string_view action) { _checkStatus(action, "READY"sv); }
void _checkDone(std::string_view action) { _checkStatus(action, "DONE"sv); }

View File

@@ -0,0 +1,13 @@
#pragma once
#include "hecl/hecl.hpp"
namespace hecl::blender {
constexpr uint32_t MinBlenderMajorSearch = 2;
constexpr uint32_t MaxBlenderMajorSearch = 2;
constexpr uint32_t MinBlenderMinorSearch = 83;
constexpr uint32_t MaxBlenderMinorSearch = 92;
std::optional<std::string> FindBlender(int& major, int& minor);
} // namespace hecl::blender

View File

@@ -4,7 +4,6 @@
#include <vector>
#include "hecl/FourCC.hpp"
#include "hecl/SystemChar.hpp"
#include <athena/DNA.hpp>
@@ -65,12 +64,12 @@ class SDNARead {
SDNABlock m_sdnaBlock;
public:
explicit SDNARead(SystemStringView path);
explicit SDNARead(std::string_view path);
explicit operator bool() const { return !m_data.empty(); }
const SDNABlock& sdnaBlock() const { return m_sdnaBlock; }
void enumerate(const std::function<bool(const FileBlock& block, athena::io::MemoryReader& r)>& func) const;
};
BlendType GetBlendType(SystemStringView path);
BlendType GetBlendType(std::string_view path);
} // namespace hecl::blender

View File

@@ -88,7 +88,6 @@ public:
bool toBoolean(bool* isValid = nullptr) const;
int32_t toSigned(bool* isValid = nullptr) const;
uint32_t toUnsigned(bool* isValid = nullptr) const;
std::wstring toWideLiteral(bool* isValid = nullptr) const;
std::string toLiteral(bool* isValid = nullptr) const;
template <typename T>
@@ -106,9 +105,7 @@ public:
bool fromInteger(int32_t val);
bool fromInteger(uint32_t val);
bool fromLiteral(std::string_view val);
bool fromLiteral(std::wstring_view val);
bool fromLiteralToType(std::string_view val);
bool fromLiteralToType(std::wstring_view val);
bool isVec2f() const { return m_type == EType::Vec2f; }
bool isVec2d() const { return m_type == EType::Vec2d; }
@@ -153,7 +150,6 @@ public:
void addListener(ListenerFunc func) { m_listeners.push_back(std::move(func)); }
bool isValidInput(std::string_view input) const;
bool isValidInput(std::wstring_view input) const;
private:
CVar(std::string_view name, std::string_view help, EType type) : m_help(help), m_type(type) { m_name = name; }
@@ -239,12 +235,6 @@ inline bool CVar::toValue(uint32_t& value) const {
return isValid;
}
template <>
inline bool CVar::toValue(std::wstring& value) const {
bool isValid = false;
value = toWideLiteral(&isValid);
return isValid;
}
template <>
inline bool CVar::toValue(std::string& value) const {
bool isValid = false;
value = toLiteral(&isValid);
@@ -299,10 +289,6 @@ template <>
inline bool CVar::fromValue(std::string_view val) {
return fromLiteral(val);
}
template <>
inline bool CVar::fromValue(std::wstring_view val) {
return fromLiteral(val);
}
class CVarUnlocker {
CVar* m_cvar;

View File

@@ -6,7 +6,6 @@
#include <vector>
#include "hecl/CVar.hpp"
#include "hecl/SystemChar.hpp"
namespace hecl {
namespace Runtime {
@@ -107,7 +106,7 @@ public:
void setCheatsEnabled(bool v, bool setDeserialized = false);
bool restartRequired() const;
void parseCommandLine(const std::vector<SystemString>& args);
void parseCommandLine(const std::vector<std::string>& args);
private:
bool suppressDeveloper();

View File

@@ -10,7 +10,6 @@
#include "hecl/Blender/Token.hpp"
#include "hecl/hecl.hpp"
#include "hecl/SystemChar.hpp"
#include <boo/ThreadLocalPtr.hpp>
@@ -22,7 +21,7 @@ namespace hecl {
class MultiProgressPrinter;
extern int CpuCountOverride;
void SetCpuCountOverride(int argc, const SystemChar** argv);
void SetCpuCountOverride(int argc, char** argv);
class ClientProcess {
std::mutex m_mutex;

View File

@@ -38,12 +38,8 @@ class Console {
~LogVisorAdapter() override = default;
void report(const char* modName, logvisor::Level severity, fmt::string_view format, fmt::format_args args) override;
void report(const char* modName, logvisor::Level severity, fmt::wstring_view format,
fmt::wformat_args args) override;
void reportSource(const char* modName, logvisor::Level severity, const char* file, unsigned linenum,
fmt::string_view format, fmt::format_args args) override;
void reportSource(const char* modName, logvisor::Level severity, const char* file, unsigned linenum,
fmt::wstring_view format, fmt::wformat_args args) override;
};
public:

View File

@@ -55,7 +55,7 @@ class IDataSpec {
public:
IDataSpec(const DataSpecEntry* specEntry) : m_specEntry(specEntry) {}
virtual ~IDataSpec() = default;
using FCookProgress = std::function<void(const SystemChar*)>;
using FCookProgress = std::function<void(const char*)>;
/**
* @brief Extract Pass Info
@@ -64,8 +64,8 @@ public:
* reverses the cooking process by emitting editable resources
*/
struct ExtractPassInfo {
SystemString srcpath;
std::vector<SystemString> extractArgs;
std::string srcpath;
std::vector<std::string> extractArgs;
bool force;
};
@@ -76,8 +76,8 @@ public:
* to be extracted
*/
struct ExtractReport {
SystemString name;
SystemString desc;
std::string name;
std::string desc;
std::vector<ExtractReport> childOpts;
};
@@ -129,12 +129,12 @@ extern std::vector<const struct DataSpecEntry*> DATA_SPEC_REGISTRY;
* Auto-registers with data spec registry
*/
struct DataSpecEntry {
SystemStringView m_name;
SystemStringView m_desc;
SystemStringView m_pakExt;
std::string_view m_name;
std::string_view m_desc;
std::string_view m_pakExt;
std::function<std::unique_ptr<IDataSpec>(Project&, DataSpecTool)> m_factory;
DataSpecEntry(SystemStringView name, SystemStringView desc, SystemStringView pakExt,
DataSpecEntry(std::string_view name, std::string_view desc, std::string_view pakExt,
std::function<std::unique_ptr<IDataSpec>(Project& project, DataSpecTool)>&& factory)
: m_name(name), m_desc(desc), m_pakExt(pakExt), m_factory(std::move(factory)) {}
};
@@ -150,7 +150,7 @@ struct DataSpecEntry {
*/
class ObjectBase {
friend class Project;
SystemString m_path;
std::string m_path;
protected:
/**
@@ -209,9 +209,9 @@ protected:
virtual FourCC getType() const { return FourCC("NULL"); }
public:
ObjectBase(SystemStringView path) : m_path(path) {}
ObjectBase(std::string_view path) : m_path(path) {}
SystemStringView getPath() const { return m_path; }
std::string_view getPath() const { return m_path; }
};
/**
@@ -251,12 +251,12 @@ public:
* opening a locked handle for read/write transactions
*/
class ConfigFile {
SystemString m_filepath;
std::string m_filepath;
std::vector<std::string> m_lines;
UniqueFilePtr m_lockedFile;
public:
ConfigFile(const Project& project, SystemStringView name, SystemStringView subdir = _SYS_STR("/.hecl/"));
ConfigFile(const Project& project, std::string_view name, std::string_view subdir = "/.hecl/");
std::vector<std::string>& lockAndRead();
void addLine(std::string_view line);
void removeLine(std::string_view refLine);
@@ -360,14 +360,14 @@ public:
* @param specs String(s) representing unique spec(s) from getDataSpecs
* @return true on success
*/
bool enableDataSpecs(const std::vector<SystemString>& specs);
bool enableDataSpecs(const std::vector<std::string>& specs);
/**
* @brief Disable persistent user preference for particular spec string(s)
* @param specs String(s) representing unique spec(s) from getDataSpecs
* @return true on success
*/
bool disableDataSpecs(const std::vector<SystemString>& specs);
bool disableDataSpecs(const std::vector<std::string>& specs);
/**
* @brief Begin cook process for specified directory

View File

@@ -6,8 +6,6 @@
#include <thread>
#include <vector>
#include "hecl/SystemChar.hpp"
#if _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
@@ -32,7 +30,7 @@ class MultiProgressPrinter {
} m_termInfo;
struct ThreadStat {
hecl::SystemString m_message, m_submessage;
std::string m_message, m_submessage;
float m_factor = 0.f;
bool m_active = false;
void print(const TermInfo& tinfo) const;
@@ -56,7 +54,8 @@ class MultiProgressPrinter {
public:
MultiProgressPrinter(bool activate = false);
~MultiProgressPrinter();
void print(std::optional<hecl::SystemStringView> message, std::optional<hecl::SystemStringView> submessage,
void print(std::optional<std::string_view> message,
std::optional<std::string_view> submessage,
float factor = -1.f,
int threadIdx = 0) const;
void setMainFactor(float factor) const;

View File

@@ -408,7 +408,7 @@ class PipelineConverter : public PipelineConverterBase {
public:
PipelineConverter(boo::IGraphicsDataFactory* gfxF) : PipelineConverterBase(gfxF, P::Enum) {}
#if HECL_RUNTIME
bool loadFromFile(FactoryCtx& ctx, const hecl::SystemChar* path);
bool loadFromFile(FactoryCtx& ctx, const char* path);
#endif
template <class FromTp>

View File

@@ -3,8 +3,6 @@
#include <cstddef>
#include <memory>
#include "hecl/SystemChar.hpp"
#include <boo/BooObject.hpp>
#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
@@ -17,17 +15,17 @@ namespace Runtime {
* @brief Per-platform file store resolution
*/
class FileStoreManager {
SystemString m_domain;
SystemString m_storeRoot;
std::string m_domain;
std::string m_storeRoot;
public:
FileStoreManager(SystemStringView domain);
SystemStringView getDomain() const { return m_domain; }
FileStoreManager(std::string_view domain);
std::string_view getDomain() const { return m_domain; }
/**
* @brief Returns the full path to the file store, including domain
* @return Full path to store e.g /home/foo/.hecl/bar
*/
SystemStringView getStoreRoot() const { return m_storeRoot; }
std::string_view getStoreRoot() const { return m_storeRoot; }
};
/**

View File

@@ -1,9 +1,9 @@
#pragma once
#include "hecl/SystemChar.hpp"
#include <string>
namespace hecl {
hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name);
std::string FindCommonSteamApp(const char* name);
}
} // namespace hecl

View File

@@ -11,7 +11,6 @@
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <cwchar>
#endif
#include <string>
#include <string_view>
@@ -20,38 +19,4 @@
namespace hecl {
#if _WIN32 && UNICODE
#define HECL_UCS2 1
#endif
#if HECL_UCS2
typedef wchar_t SystemChar;
typedef std::wstring SystemString;
typedef std::wstring_view SystemStringView;
static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towlower); }
static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towupper); }
#ifndef _SYS_STR
#define _SYS_STR(val) L##val
#endif
typedef struct _stat Sstat;
#else
typedef char SystemChar;
typedef std::string SystemString;
typedef std::string_view SystemStringView;
static inline void ToLower(SystemString& str) {
std::transform(str.begin(), str.end(), str.begin(),
[](SystemChar c) { return std::tolower(static_cast<unsigned char>(c)); });
}
static inline void ToUpper(SystemString& str) {
std::transform(str.begin(), str.end(), str.begin(),
[](SystemChar c) { return std::toupper(static_cast<unsigned char>(c)); });
}
#ifndef _SYS_STR
#define _SYS_STR(val) val
#endif
typedef struct stat Sstat;
#endif
constexpr size_t StrLen(const SystemChar* str) { return std::char_traits<SystemChar>::length(str); }
} // namespace hecl

View File

@@ -25,6 +25,7 @@ extern "C" int rep_closefrom(int lower);
#include <cwctype>
#include <Shlwapi.h>
#include "winsupport.hpp"
#include <nowide/stackstring.hpp>
#endif
#include <algorithm>
@@ -41,7 +42,6 @@ extern "C" int rep_closefrom(int lower);
#include "logvisor/logvisor.hpp"
#include "athena/Global.hpp"
#include "xxhash/xxhash.h"
#include "SystemChar.hpp"
#include "FourCC.hpp"
#if defined(__has_feature)
@@ -92,10 +92,7 @@ extern unsigned VerbosityLevel;
extern bool GuiMode;
extern logvisor::Module LogModule;
std::string WideToUTF8(std::wstring_view src);
std::string Char16ToUTF8(std::u16string_view src);
std::wstring Char16ToWide(std::u16string_view src);
std::wstring UTF8ToWide(std::string_view src);
std::u16string UTF8ToChar16(std::string_view src);
/* humanize_number port from FreeBSD's libutil */
@@ -107,84 +104,29 @@ ENABLE_BITWISE_ENUM(HNScale)
std::string HumanizeNumber(int64_t quotient, size_t len, const char* suffix, int scale, HNFlags flags);
#if HECL_UCS2
class SystemUTF8Conv {
std::string m_utf8;
static inline void ToLower(std::string& str) {
std::transform(str.begin(), str.end(), str.begin(),
[](char c) { return std::tolower(static_cast<unsigned char>(c)); });
}
static inline void ToUpper(std::string& str) {
std::transform(str.begin(), str.end(), str.begin(),
[](char c) { return std::toupper(static_cast<unsigned char>(c)); });
}
public:
explicit SystemUTF8Conv(SystemStringView str) : m_utf8(WideToUTF8(str)) {}
std::string_view str() const { return m_utf8; }
const char* c_str() const { return m_utf8.c_str(); }
friend std::string operator+(const SystemUTF8Conv& lhs, std::string_view rhs) { return lhs.m_utf8 + rhs.data(); }
friend std::string operator+(std::string_view lhs, const SystemUTF8Conv& rhs) {
return std::string(lhs).append(rhs.m_utf8);
}
};
class SystemStringConv {
std::wstring m_sys;
public:
explicit SystemStringConv(std::string_view str) : m_sys(UTF8ToWide(str)) {}
SystemStringView sys_str() const { return m_sys; }
const SystemChar* c_str() const { return m_sys.c_str(); }
friend std::wstring operator+(const SystemStringConv& lhs, const std::wstring_view rhs) {
return lhs.m_sys + rhs.data();
}
friend std::wstring operator+(std::wstring_view lhs, const SystemStringConv& rhs) {
return std::wstring(lhs).append(rhs.m_sys);
}
};
inline hecl::SystemString UTF8StringToSysString(std::string_view src) { return UTF8ToWide(src); }
#if _WIN32
using Sstat = struct ::_stat64;
#else
class SystemUTF8Conv {
std::string_view m_utf8;
public:
explicit SystemUTF8Conv(SystemStringView str) : m_utf8(str) {}
std::string_view str() const { return m_utf8; }
const char* c_str() const { return m_utf8.data(); }
friend std::string operator+(const SystemUTF8Conv& lhs, std::string_view rhs) {
return std::string(lhs.m_utf8).append(rhs);
}
friend std::string operator+(std::string_view lhs, const SystemUTF8Conv& rhs) {
return std::string(lhs).append(rhs.m_utf8);
}
};
class SystemStringConv {
std::string_view m_sys;
public:
explicit SystemStringConv(std::string_view str) : m_sys(str) {}
SystemStringView sys_str() const { return m_sys; }
const SystemChar* c_str() const { return m_sys.data(); }
friend std::string operator+(const SystemStringConv& lhs, std::string_view rhs) {
return std::string(lhs.m_sys).append(rhs);
}
friend std::string operator+(std::string_view lhs, const SystemStringConv& rhs) {
return std::string(lhs).append(rhs.m_sys);
}
};
inline hecl::SystemString UTF8StringToSysString(std::string src) { return src; }
using SStat = struct stat;
#endif
void SanitizePath(std::string& path);
void SanitizePath(std::wstring& path);
constexpr size_t StrLen(const char* str) { return std::char_traits<char>::length(str); }
inline void Unlink(const SystemChar* file) {
void SanitizePath(std::string& path);
inline void Unlink(const char* file) {
#if _WIN32
_wunlink(file);
const nowide::wstackstring wfile(file);
_wunlink(wfile.get());
#else
unlink(file);
#endif
@@ -193,7 +135,8 @@ inline void Unlink(const SystemChar* file) {
inline void MakeDir(const char* dir) {
#if _WIN32
HRESULT err;
if (!CreateDirectoryA(dir, NULL))
const nowide::wstackstring wdir(dir);
if (!CreateDirectoryW(wdir.get(), NULL))
if ((err = GetLastError()) != ERROR_ALREADY_EXISTS)
LogModule.report(logvisor::Fatal, FMT_STRING("MakeDir({})"), dir);
#else
@@ -203,62 +146,68 @@ inline void MakeDir(const char* dir) {
#endif
}
#if _WIN32
inline void MakeDir(const wchar_t* dir) {
HRESULT err;
if (!CreateDirectoryW(dir, NULL))
if ((err = GetLastError()) != ERROR_ALREADY_EXISTS)
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("MakeDir({})")), dir);
}
#endif
int RecursiveMakeDir(const char* dir);
int RecursiveMakeDir(const SystemChar* dir);
inline const SystemChar* GetEnv(const SystemChar* name) {
inline std::optional<std::string> GetEnv(const char* name) {
#if WINDOWS_STORE
return nullptr;
#else
#if HECL_UCS2
return _wgetenv(name);
#if _WIN32
size_t sz = 0;
const nowide::wshort_stackstring wname(name);
_wgetenv_s(&sz, nullptr, 0, wname.get());
if (sz == 0) {
return {};
}
auto wbuf = std::make_unique<wchar_t[]>(sz);
_wgetenv_s(&sz, wbuf.get(), sz, wname.get());
return nowide::narrow(wbuf.get(), sz);
#else
return getenv(name);
#endif
#endif
}
inline SystemChar* Getcwd(SystemChar* buf, int maxlen) {
#if HECL_UCS2
return _wgetcwd(buf, maxlen);
inline char* Getcwd(char* buf, int maxlen) {
#if _WIN32
auto wbuf = std::make_unique<wchar_t[]>(maxlen);
wchar_t* result = _wgetcwd(wbuf.get(), maxlen);
if (result == nullptr) {
return nullptr;
}
return nowide::narrow(buf, maxlen, wbuf.get());
#else
return getcwd(buf, maxlen);
#endif
}
SystemString GetcwdStr();
std::string GetcwdStr();
inline bool IsAbsolute(SystemStringView path) {
inline bool IsAbsolute(std::string_view path) {
#if _WIN32
if (path.size() && (path[0] == _SYS_STR('\\') || path[0] == _SYS_STR('/')))
if (path.size() && (path[0] == '\\' || path[0] == '/'))
return true;
if (path.size() >= 2 && iswalpha(path[0]) && path[1] == _SYS_STR(':'))
if (path.size() >= 2 && iswalpha(path[0]) && path[1] == ':')
return true;
#else
if (path.size() && path[0] == _SYS_STR('/'))
if (path.size() && path[0] == '/')
return true;
#endif
return false;
}
const SystemChar* GetTmpDir();
std::string GetTmpDir();
#if !WINDOWS_STORE
int RunProcess(const SystemChar* path, const SystemChar* const args[]);
int RunProcess(const char* path, const char* const args[]);
#endif
enum class FileLockType { None = 0, Read, Write };
inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType lock = FileLockType::None) {
#if HECL_UCS2
FILE* fp = _wfopen(path, mode);
inline FILE* Fopen(const char* path, const char* mode, FileLockType lock = FileLockType::None) {
#if _WIN32
const nowide::wstackstring wpath(path);
const nowide::wshort_stackstring wmode(mode);
FILE* fp = _wfopen(wpath.get(), wmode.get());
if (!fp)
return nullptr;
#else
@@ -286,7 +235,7 @@ struct UniqueFileDeleter {
};
using UniqueFilePtr = std::unique_ptr<FILE, UniqueFileDeleter>;
inline UniqueFilePtr FopenUnique(const SystemChar* path, const SystemChar* mode,
inline UniqueFilePtr FopenUnique(const char* path, const char* mode,
FileLockType lock = FileLockType::None) {
return UniqueFilePtr{Fopen(path, mode, lock)};
}
@@ -311,76 +260,72 @@ inline int64_t FTell(FILE* fp) {
#endif
}
inline int Rename(const SystemChar* oldpath, const SystemChar* newpath) {
#if HECL_UCS2
// return _wrename(oldpath, newpath);
return MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) == 0;
inline int Rename(const char* oldpath, const char* newpath) {
#if _WIN32
const nowide::wstackstring woldpath(oldpath);
const nowide::wstackstring wnewpath(newpath);
return MoveFileExW(woldpath.get(), wnewpath.get(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) == 0;
#else
return rename(oldpath, newpath);
#endif
}
inline int Stat(const SystemChar* path, Sstat* statOut) {
#if HECL_UCS2
inline int Stat(const char* path, Sstat* statOut) {
#if _WIN32
size_t pos;
for (pos = 0; pos < 3 && path[pos] != L'\0'; ++pos) {}
if (pos == 2 && path[1] == L':') {
SystemChar fixPath[4] = {path[0], L':', L'/', L'\0'};
return _wstat(fixPath, statOut);
const nowide::wstackstring wpath(path);
const wchar_t* wpathP = wpath.get();
for (pos = 0; pos < 3 && wpathP[pos] != L'\0'; ++pos) {}
if (pos == 2 && wpathP[1] == L':') {
wchar_t fixPath[4] = {wpathP[0], L':', L'/', L'\0'};
return _wstat64(fixPath, statOut);
}
return _wstat(path, statOut);
return _wstat64(wpath.get(), statOut);
#else
return stat(path, statOut);
#endif
}
inline int StrCmp(const SystemChar* str1, const SystemChar* str2) {
inline int StrCmp(const char* str1, const char* str2) {
if (!str1 || !str2)
return str1 != str2;
#if HECL_UCS2
return wcscmp(str1, str2);
#else
return strcmp(str1, str2);
#endif
}
inline int StrNCmp(const SystemChar* str1, const SystemChar* str2, size_t count) {
inline int StrNCmp(const char* str1, const char* str2, size_t count) {
if (!str1 || !str2)
return str1 != str2;
return std::char_traits<SystemChar>::compare(str1, str2, count);
return std::char_traits<char>::compare(str1, str2, count);
}
inline int StrCaseCmp(const SystemChar* str1, const SystemChar* str2) {
inline int StrCaseCmp(const char* str1, const char* str2) {
if (!str1 || !str2)
return str1 != str2;
#if HECL_UCS2
return _wcsicmp(str1, str2);
#if _WIN32
return _stricmp(str1, str2);
#else
return strcasecmp(str1, str2);
#endif
}
inline unsigned long StrToUl(const SystemChar* str, SystemChar** endPtr, int base) {
#if HECL_UCS2
return wcstoul(str, endPtr, base);
#else
inline unsigned long StrToUl(const char* str, char** endPtr, int base) {
return strtoul(str, endPtr, base);
#endif
}
inline bool CheckFreeSpace(const SystemChar* path, size_t reqSz) {
inline bool CheckFreeSpace(const char* path, size_t reqSz) {
#if _WIN32
ULARGE_INTEGER freeBytes;
wchar_t buf[1024];
wchar_t* end;
DWORD ret = GetFullPathNameW(path, 1024, buf, &end);
const nowide::wstackstring wpath(path);
DWORD ret = GetFullPathNameW(wpath.get(), 1024, buf, &end);
if (!ret || ret > 1024)
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("GetFullPathNameW {}")), path);
LogModule.report(logvisor::Fatal, FMT_STRING("GetFullPathNameW {}"), path);
if (end)
end[0] = L'\0';
if (!GetDiskFreeSpaceExW(buf, &freeBytes, nullptr, nullptr))
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("GetDiskFreeSpaceExW {}: {}")), path, GetLastError());
LogModule.report(logvisor::Fatal, FMT_STRING("GetDiskFreeSpaceExW {}: {}"), path, GetLastError());
return reqSz < freeBytes.QuadPart;
#else
struct statvfs svfs;
@@ -390,11 +335,12 @@ inline bool CheckFreeSpace(const SystemChar* path, size_t reqSz) {
#endif
}
inline bool PathRelative(const SystemChar* path) {
inline bool PathRelative(const char* path) {
if (!path || !path[0])
return false;
#if _WIN32 && !WINDOWS_STORE
return PathIsRelative(path);
const nowide::wstackstring wpath(path);
return PathIsRelativeW(wpath.get());
#else
return path[0] != '/';
#endif
@@ -428,12 +374,6 @@ inline int ConsoleWidth(bool* ok = nullptr) {
class MultiProgressPrinter;
class ProjectRootPath;
using SystemRegex = std::basic_regex<SystemChar>;
using SystemRegexIterator = std::regex_iterator<SystemString::const_iterator>;
using SystemRegexMatch = std::match_results<SystemString::const_iterator>;
using SystemViewRegexMatch = std::match_results<SystemStringView::const_iterator>;
using SystemRegexTokenIterator = std::regex_token_iterator<SystemString::const_iterator>;
/**
* @brief Hash representation used for all storable and comparable objects
*
@@ -451,7 +391,6 @@ public:
constexpr Hash(uint64_t hashin) noexcept : hash(hashin) {}
explicit Hash(const void* buf, size_t len) noexcept : hash(XXH64(buf, len, 0)) {}
explicit Hash(std::string_view str) noexcept : hash(XXH64(str.data(), str.size(), 0)) {}
explicit Hash(std::wstring_view str) noexcept : hash(XXH64(str.data(), str.size() * 2, 0)) {}
constexpr uint32_t val32() const noexcept { return uint32_t(hash) ^ uint32_t(hash >> 32); }
constexpr uint64_t val64() const noexcept { return uint64_t(hash); }
@@ -505,7 +444,7 @@ public:
* @brief Case-insensitive comparator for std::map sorting
*/
struct CaseInsensitiveCompare {
// Allow heterogenous lookup with maps that use this comparator.
// Allow heterogeneous lookup with maps that use this comparator.
using is_transparent = void;
bool operator()(std::string_view lhs, std::string_view rhs) const {
@@ -513,12 +452,6 @@ struct CaseInsensitiveCompare {
return std::tolower(static_cast<unsigned char>(lhs)) < std::tolower(static_cast<unsigned char>(rhs));
});
}
bool operator()(std::wstring_view lhs, std::wstring_view rhs) const {
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](wchar_t lhs, wchar_t rhs) {
return std::towlower(lhs) < std::towlower(rhs);
});
}
};
/**
@@ -528,33 +461,28 @@ class DirectoryEnumerator {
public:
enum class Mode { Native, DirsSorted, FilesSorted, DirsThenFilesSorted };
struct Entry {
hecl::SystemString m_path;
hecl::SystemString m_name;
std::string m_path;
std::string m_name;
size_t m_fileSz;
bool m_isDir;
Entry(hecl::SystemString path, const hecl::SystemChar* name, size_t sz, bool isDir)
: m_path(std::move(path)), m_name(name), m_fileSz(sz), m_isDir(isDir) {}
Entry(std::string path, std::string name, size_t sz, bool isDir)
: m_path(std::move(path)), m_name(std::move(name)), m_fileSz(sz), m_isDir(isDir) {}
};
private:
std::vector<Entry> m_entries;
public:
DirectoryEnumerator(SystemStringView path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false,
DirectoryEnumerator(std::string_view path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false,
bool reverse = false, bool noHidden = false);
explicit operator bool() const { return m_entries.size() != 0; }
size_t size() const { return m_entries.size(); }
std::vector<Entry>::const_iterator begin() const { return m_entries.cbegin(); }
std::vector<Entry>::const_iterator end() const { return m_entries.cend(); }
explicit operator bool() const { return !m_entries.empty(); }
[[nodiscard]] size_t size() const { return m_entries.size(); }
[[nodiscard]] std::vector<Entry>::const_iterator begin() const { return m_entries.cbegin(); }
[[nodiscard]] std::vector<Entry>::const_iterator end() const { return m_entries.cend(); }
};
/**
* @brief Build list of common OS-specific directories
*/
std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations();
/**
* @brief Special ProjectRootPath class for opening Database::Project instances
*
@@ -562,7 +490,7 @@ std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations();
* resolve canonicalized relative paths.
*/
class ProjectRootPath {
SystemString m_projRoot;
std::string m_projRoot;
Hash m_hash = 0;
public:
@@ -582,7 +510,7 @@ public:
* @brief Construct a representation of a project root path
* @param path valid filesystem-path (relative or absolute) to project root
*/
ProjectRootPath(SystemStringView path) : m_projRoot(path) {
ProjectRootPath(std::string_view path) : m_projRoot(path) {
SanitizePath(m_projRoot);
m_hash = Hash(m_projRoot);
}
@@ -591,29 +519,29 @@ public:
* @brief Access fully-canonicalized absolute path
* @return Absolute path reference
*/
SystemStringView getAbsolutePath() const { return m_projRoot; }
std::string_view getAbsolutePath() const { return m_projRoot; }
/**
* @brief Make absolute path project relative
* @param absPath Absolute path
* @return SystemString of path relative to project root
* @return std::string of path relative to project root
*/
SystemString getProjectRelativeFromAbsolute(SystemStringView absPath) const {
std::string getProjectRelativeFromAbsolute(std::string_view absPath) const {
if (absPath.size() > m_projRoot.size()) {
SystemString absPathForward(absPath);
for (SystemChar& ch : absPathForward)
if (ch == _SYS_STR('\\'))
ch = _SYS_STR('/');
std::string absPathForward(absPath);
for (char& ch : absPathForward)
if (ch == '\\')
ch = '/';
if (!absPathForward.compare(0, m_projRoot.size(), m_projRoot)) {
auto beginIt = absPathForward.cbegin() + m_projRoot.size();
while (*beginIt == _SYS_STR('/'))
while (*beginIt == '/')
++beginIt;
return SystemString(beginIt, absPathForward.cend());
return std::string(beginIt, absPathForward.cend());
}
}
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("unable to resolve '{}' as project relative '{}'")), absPath,
LogModule.report(logvisor::Fatal, FMT_STRING("unable to resolve '{}' as project relative '{}'"), absPath,
m_projRoot);
return SystemString();
return std::string();
}
/**
@@ -636,9 +564,9 @@ public:
* @brief Obtain c-string of final path component
* @return Final component c-string (may be empty)
*/
SystemStringView getLastComponent() const {
size_t pos = m_projRoot.rfind(_SYS_STR('/'));
if (pos == SystemString::npos)
std::string_view getLastComponent() const {
size_t pos = m_projRoot.rfind('/');
if (pos == std::string::npos)
return {};
return {m_projRoot.c_str() + pos + 1, size_t(m_projRoot.size() - pos - 1)};
}
@@ -659,30 +587,15 @@ public:
*/
class ProjectPath {
Database::Project* m_proj = nullptr;
SystemString m_absPath;
SystemString m_relPath;
SystemString m_auxInfo;
std::string m_absPath;
std::string m_relPath;
std::string m_auxInfo;
Hash m_hash = 0;
#if HECL_UCS2
std::string m_utf8AbsPath;
std::string m_utf8RelPath;
std::string m_utf8AuxInfo;
#endif
void ComputeHash() {
#if HECL_UCS2
m_utf8AbsPath = WideToUTF8(m_absPath);
m_utf8RelPath = WideToUTF8(m_relPath);
m_utf8AuxInfo = WideToUTF8(m_auxInfo);
if (m_utf8AuxInfo.size())
m_hash = Hash(m_utf8RelPath + '|' + m_utf8AuxInfo);
else
m_hash = Hash(m_utf8RelPath);
#else
if (m_auxInfo.size())
m_hash = Hash(m_relPath + '|' + m_auxInfo);
else
m_hash = Hash(m_relPath);
#endif
}
public:
@@ -706,10 +619,6 @@ public:
m_absPath.clear();
m_relPath.clear();
m_hash = 0;
#if HECL_UCS2
m_utf8AbsPath.clear();
m_utf8RelPath.clear();
#endif
}
/**
@@ -717,26 +626,16 @@ public:
* @param project previously constructed Project to use root path of
* @param path valid filesystem-path (relative or absolute) to subpath
*/
ProjectPath(Database::Project& project, SystemStringView path) { assign(project, path); }
void assign(Database::Project& project, SystemStringView path);
#if HECL_UCS2
ProjectPath(Database::Project& project, std::string_view path) { assign(project, path); }
void assign(Database::Project& project, std::string_view path);
#endif
/**
* @brief Construct a project subpath representation within another subpath
* @param parentPath previously constructed ProjectPath which ultimately connects to a ProjectRootPath
* @param path valid filesystem-path (relative or absolute) to subpath
*/
ProjectPath(const ProjectPath& parentPath, SystemStringView path) { assign(parentPath, path); }
void assign(const ProjectPath& parentPath, SystemStringView path);
#if HECL_UCS2
ProjectPath(const ProjectPath& parentPath, std::string_view path) { assign(parentPath, path); }
void assign(const ProjectPath& parentPath, std::string_view path);
#endif
/**
* @brief Determine if ProjectPath represents project root directory
@@ -750,22 +649,22 @@ public:
* @param replace remove existing extension (if any) before appending new extension
* @return new path with extension
*/
ProjectPath getWithExtension(const SystemChar* ext, bool replace = false) const;
ProjectPath getWithExtension(const char* ext, bool replace = false) const;
/**
* @brief Access fully-canonicalized absolute path
* @return Absolute path reference
*/
SystemStringView getAbsolutePath() const { return m_absPath; }
std::string_view getAbsolutePath() const { return m_absPath; }
/**
* @brief Access fully-canonicalized project-relative path
* @return Relative pointer to within absolute-path or "." for project root-directory (use isRoot to detect)
*/
SystemStringView getRelativePath() const {
std::string_view getRelativePath() const {
if (m_relPath.size())
return m_relPath;
static const SystemString dot = _SYS_STR(".");
static const std::string dot = ".";
return dot;
}
@@ -783,47 +682,35 @@ public:
* This will not resolve outside the project root (error in that case)
*/
ProjectPath getParentPath() const {
if (m_relPath == _SYS_STR("."))
if (m_relPath == ".")
LogModule.report(logvisor::Fatal, FMT_STRING("attempted to resolve parent of root project path"));
size_t pos = m_relPath.rfind(_SYS_STR('/'));
if (pos == SystemString::npos)
return ProjectPath(*m_proj, _SYS_STR(""));
return ProjectPath(*m_proj, SystemString(m_relPath.begin(), m_relPath.begin() + pos));
size_t pos = m_relPath.rfind('/');
if (pos == std::string::npos)
return ProjectPath(*m_proj, "");
return ProjectPath(*m_proj, std::string(m_relPath.begin(), m_relPath.begin() + pos));
}
/**
* @brief Obtain c-string of final path component (stored within relative path)
* @return Final component c-string (may be empty)
*/
SystemStringView getLastComponent() const {
size_t pos = m_relPath.rfind(_SYS_STR('/'));
if (pos == SystemString::npos)
std::string_view getLastComponent() const {
size_t pos = m_relPath.rfind('/');
if (pos == std::string::npos)
return m_relPath;
return {m_relPath.c_str() + pos + 1, m_relPath.size() - pos - 1};
}
std::string_view getLastComponentUTF8() const {
size_t pos = m_relPath.rfind(_SYS_STR('/'));
#if HECL_UCS2
if (pos == SystemString::npos)
return m_utf8RelPath;
return {m_utf8RelPath.c_str() + pos + 1, size_t(m_utf8RelPath.size() - pos - 1)};
#else
if (pos == SystemString::npos)
return m_relPath;
return {m_relPath.c_str() + pos + 1, size_t(m_relPath.size() - pos - 1)};
#endif
}
/**
* @brief Obtain c-string of extension of final path component (stored within relative path)
* @return Final component extension c-string (may be empty)
*/
SystemStringView getLastComponentExt() const {
SystemStringView lastCompOrig = getLastComponent().data();
const SystemChar* end = lastCompOrig.data() + lastCompOrig.size();
const SystemChar* lastComp = end;
std::string_view getLastComponentExt() const {
std::string_view lastCompOrig = getLastComponent().data();
const char* end = lastCompOrig.data() + lastCompOrig.size();
const char* lastComp = end;
while (lastComp != lastCompOrig.data()) {
if (*lastComp == _SYS_STR('.'))
if (*lastComp == '.')
return {lastComp + 1, size_t(end - lastComp - 1)};
--lastComp;
}
@@ -834,51 +721,17 @@ public:
* @brief Build vector of project-relative directory/file components
* @return Vector of path components
*/
std::vector<hecl::SystemString> getPathComponents() const {
std::vector<hecl::SystemString> ret;
std::vector<std::string> getPathComponents() const {
std::vector<std::string> ret;
if (m_relPath.empty())
return ret;
auto it = m_relPath.cbegin();
if (*it == _SYS_STR('/')) {
ret.push_back(_SYS_STR("/"));
++it;
}
hecl::SystemString comp;
for (; it != m_relPath.cend(); ++it) {
if (*it == _SYS_STR('/')) {
if (comp.empty())
continue;
ret.push_back(std::move(comp));
comp.clear();
continue;
}
comp += *it;
}
if (comp.size())
ret.push_back(std::move(comp));
return ret;
}
/**
* @brief Build vector of project-relative directory/file components
* @return Vector of path components encoded as UTF8
*/
std::vector<std::string> getPathComponentsUTF8() const {
#if HECL_UCS2
const std::string& relPath = m_utf8RelPath;
#else
const std::string& relPath = m_relPath;
#endif
std::vector<std::string> ret;
if (relPath.empty())
return ret;
auto it = relPath.cbegin();
if (*it == '/') {
ret.push_back("/");
++it;
}
std::string comp;
for (; it != relPath.cend(); ++it) {
for (; it != m_relPath.cend(); ++it) {
if (*it == '/') {
if (comp.empty())
continue;
@@ -893,53 +746,19 @@ public:
return ret;
}
/**
* @brief Access fully-canonicalized absolute path in UTF-8
* @return Absolute path reference
*/
std::string_view getAbsolutePathUTF8() const {
#if HECL_UCS2
return m_utf8AbsPath;
#else
return m_absPath;
#endif
}
std::string_view getRelativePathUTF8() const {
#if HECL_UCS2
return m_utf8RelPath;
#else
return m_relPath;
#endif
}
SystemStringView getAuxInfo() const { return m_auxInfo; }
std::string_view getAuxInfoUTF8() const {
#if HECL_UCS2
return m_utf8AuxInfo;
#else
return m_auxInfo;
#endif
}
std::string_view getAuxInfo() const { return m_auxInfo; }
/**
* @brief Construct a path with the aux info overwritten with specified string
* @param auxStr string to replace existing auxInfo with
*/
ProjectPath ensureAuxInfo(SystemStringView auxStr) const {
ProjectPath ensureAuxInfo(std::string_view auxStr) const {
if (auxStr.empty())
return ProjectPath(getProject(), getRelativePath());
else
return ProjectPath(getProject(), SystemString(getRelativePath()) + _SYS_STR('|') + auxStr.data());
return ProjectPath(getProject(), std::string(getRelativePath()) + '|' + auxStr.data());
}
#if HECL_UCS2
ProjectPath ensureAuxInfo(std::string_view auxStr) const {
return ProjectPath(getProject(), SystemString(getRelativePath()) + _SYS_STR('|') + UTF8ToWide(auxStr));
}
#endif
template<typename StringT>
class EncodableString {
friend class ProjectPath;
@@ -956,20 +775,13 @@ public:
operator EncStringView() const { return m_stringView; }
};
EncodableString<SystemString> getEncodableString() const {
EncodableString<std::string> getEncodableString() const {
if (!getAuxInfo().empty())
return {SystemString(getRelativePath()) + _SYS_STR('|') + getAuxInfo().data()};
return {std::string(getRelativePath()) + '|' + getAuxInfo().data()};
else
return {getRelativePath()};
}
EncodableString<std::string> getEncodableStringUTF8() const {
if (!getAuxInfo().empty())
return {std::string(getRelativePathUTF8()) + '|' + getAuxInfoUTF8().data()};
else
return {getRelativePathUTF8()};
}
/**
* @brief Type of path
*/
@@ -1027,7 +839,7 @@ public:
* @brief Insert directory children into list
* @param outPaths list to append children to
*/
void getDirChildren(std::map<SystemString, ProjectPath>& outPaths) const;
void getDirChildren(std::map<std::string, ProjectPath>& outPaths) const;
/**
* @brief Construct DirectoryEnumerator set to project path
@@ -1046,8 +858,8 @@ public:
*/
size_t levelCount() const {
size_t count = 0;
for (SystemChar ch : m_relPath)
if (ch == _SYS_STR('/') || ch == _SYS_STR('\\'))
for (char ch : m_relPath)
if (ch == '/' || ch == '\\')
++count;
return count;
}
@@ -1066,11 +878,11 @@ public:
* directory, creating the final component
*/
void makeDirChain(bool includeLastComp) const {
std::vector<hecl::SystemString> comps = getPathComponents();
std::vector<std::string> comps = getPathComponents();
auto end = comps.cend();
if (end != comps.cbegin() && !includeLastComp)
--end;
ProjectPath compPath(*m_proj, _SYS_STR("."));
ProjectPath compPath(*m_proj, ".");
for (auto it = comps.cbegin(); it != end; ++it) {
compPath = ProjectPath(compPath, *it);
compPath.makeDir();
@@ -1103,29 +915,6 @@ public:
*/
class StringUtils {
public:
static bool BeginsWith(SystemStringView str, SystemStringView test) {
if (test.size() > str.size())
return false;
return str.compare(0, test.size(), test) == 0;
}
static bool EndsWith(SystemStringView str, SystemStringView test) {
if (test.size() > str.size())
return false;
return str.compare(str.size() - test.size(), SystemStringView::npos, test) == 0;
}
static std::string TrimWhitespace(std::string_view str) {
auto bit = str.begin();
while (bit != str.cend() && std::isspace(static_cast<unsigned char>(*bit)))
++bit;
auto eit = str.end();
while (eit != str.cbegin() && std::isspace(static_cast<unsigned char>(*(eit - 1))))
--eit;
return {bit, eit};
}
#if HECL_UCS2
static bool BeginsWith(std::string_view str, std::string_view test) {
if (test.size() > str.size())
return false;
@@ -1138,16 +927,15 @@ public:
return str.compare(str.size() - test.size(), std::string_view::npos, test) == 0;
}
static SystemString TrimWhitespace(SystemStringView str) {
static std::string TrimWhitespace(std::string_view str) {
auto bit = str.begin();
while (bit != str.cend() && std::iswspace(*bit))
while (bit != str.cend() && std::isspace(static_cast<unsigned char>(*bit)))
++bit;
auto eit = str.end();
while (eit != str.cbegin() && std::iswspace(*(eit - 1)))
while (eit != str.cbegin() && std::isspace(static_cast<unsigned char>(*(eit - 1))))
--eit;
return {bit, eit};
}
#endif
};
/**
@@ -1180,7 +968,7 @@ public:
* @param path absolute or relative file path to search from
* @return Newly-constructed root path (bool-evaluating to false if not found)
*/
ProjectRootPath SearchForProject(SystemStringView path);
ProjectRootPath SearchForProject(std::string_view path);
/**
* @brief Search from within provided directory for the project root
@@ -1188,7 +976,7 @@ ProjectRootPath SearchForProject(SystemStringView path);
* @param subpathOut remainder of provided path assigned to this ProjectPath
* @return Newly-constructed root path (bool-evaluating to false if not found)
*/
ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut);
ProjectRootPath SearchForProject(std::string_view path, std::string& subpathOut);
/**
* @brief Test if given path is a PNG (based on file header)
@@ -1391,6 +1179,3 @@ struct hash<hecl::Hash> {
size_t operator()(const hecl::Hash& val) const noexcept { return val.valSizeT(); }
};
} // namespace std
FMT_CUSTOM_FORMATTER(hecl::SystemUTF8Conv, "{}", obj.str())
FMT_CUSTOM_FORMATTER(hecl::SystemStringConv, "{}", obj.sys_str())

View File

@@ -1,8 +1,13 @@
set(BLENDER_SOURCES
Connection.cpp
MeshOptimizer.hpp
MeshOptimizer.cpp
SDNARead.cpp
HMDL.cpp)
Connection.cpp
MeshOptimizer.hpp
MeshOptimizer.cpp
SDNARead.cpp
HMDL.cpp)
hecl_add_list(Blender BLENDER_SOURCES)
set(FIND_BLENDER_SOURCES
FindBlender.cpp)
hecl_add_list(Blender FIND_BLENDER_SOURCES)

View File

@@ -14,6 +14,7 @@
#include <tuple>
#include "hecl/Blender/Connection.hpp"
#include "hecl/Blender/FindBlender.hpp"
#include "hecl/Blender/Token.hpp"
#include "hecl/Database.hpp"
#include "hecl/hecl.hpp"
@@ -48,20 +49,9 @@ using namespace std::literals;
namespace hecl::blender {
static const uint32_t MinBlenderMajorSearch = 2;
static const uint32_t MaxBlenderMajorSearch = 2;
static const uint32_t MinBlenderMinorSearch = 83;
static const uint32_t MaxBlenderMinorSearch = 92;
logvisor::Module BlenderLog("hecl::blender::Connection");
Token SharedBlenderToken;
#ifdef __APPLE__
#define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender"
#else
#define DEFAULT_BLENDER_BIN "blender"
#endif
extern "C" uint8_t HECL_BLENDERSHELL[];
extern "C" size_t HECL_BLENDERSHELL_SZ;
@@ -71,21 +61,21 @@ extern "C" size_t HECL_ADDON_SZ;
extern "C" uint8_t HECL_STARTUP[];
extern "C" size_t HECL_STARTUP_SZ;
static void InstallBlendershell(const SystemChar* path) {
auto fp = hecl::FopenUnique(path, _SYS_STR("w"));
static void InstallBlendershell(const char* path) {
auto fp = hecl::FopenUnique(path, "w");
if (fp == nullptr) {
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("unable to open {} for writing")), path);
BlenderLog.report(logvisor::Fatal, FMT_STRING("unable to open {} for writing"), path);
}
std::fwrite(HECL_BLENDERSHELL, 1, HECL_BLENDERSHELL_SZ, fp.get());
}
static void InstallAddon(const SystemChar* path) {
auto fp = hecl::FopenUnique(path, _SYS_STR("wb"));
static void InstallAddon(const char* path) {
auto fp = hecl::FopenUnique(path, "wb");
if (fp == nullptr) {
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Unable to install blender addon at '{}'")), path);
BlenderLog.report(logvisor::Fatal, FMT_STRING("Unable to install blender addon at '{}'"), path);
}
std::fwrite(HECL_ADDON, 1, HECL_ADDON_SZ, fp.get());
@@ -239,9 +229,8 @@ std::size_t Connection::_writeBuf(const void* buf, std::size_t len) {
ProjectPath Connection::_readPath() {
std::string path = _readStdString();
if (!path.empty()) {
SystemStringConv pathAbs(path);
SystemString meshPathRel =
getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(pathAbs.sys_str());
std::string meshPathRel =
getBlendPath().getProject().getProjectRootPath().getProjectRelativeFromAbsolute(path);
return ProjectPath(getBlendPath().getProject().getProjectWorkingPath(), meshPathRel);
}
return {};
@@ -261,7 +250,7 @@ void Connection::_closePipe() {
void Connection::_blenderDied() {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
auto errFp = hecl::FopenUnique(m_errPath.c_str(), _SYS_STR("r"));
auto errFp = hecl::FopenUnique(m_errPath.c_str(), "r");
if (errFp != nullptr) {
std::fseek(errFp.get(), 0, SEEK_END);
@@ -281,7 +270,7 @@ void Connection::_blenderDied() {
static std::atomic_bool BlenderFirstInit(false);
#if _WIN32
static bool RegFileExists(const hecl::SystemChar* path) {
static bool RegFileExists(const char* path) {
if (!path)
return false;
hecl::Sstat theStat;
@@ -295,16 +284,16 @@ Connection::Connection(int verbosityLevel) {
BlenderLog.report(logvisor::Info, FMT_STRING("Establishing BlenderConnection..."));
/* Put hecl_blendershell.py in temp dir */
const SystemChar* TMPDIR = GetTmpDir();
const std::string TMPDIR = GetTmpDir();
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#endif
hecl::SystemString blenderShellPath(TMPDIR);
blenderShellPath += _SYS_STR("/hecl_blendershell.py");
std::string blenderShellPath(TMPDIR);
blenderShellPath += "/hecl_blendershell.py";
hecl::SystemString blenderAddonPath(TMPDIR);
blenderAddonPath += _SYS_STR("/hecl_blenderaddon.zip");
std::string blenderAddonPath(TMPDIR);
blenderAddonPath += "/hecl_blenderaddon.zip";
bool FalseCmp = false;
if (BlenderFirstInit.compare_exchange_strong(FalseCmp, true)) {
@@ -345,54 +334,16 @@ Connection::Connection(int verbosityLevel) {
pipe(m_writepipe.data());
#endif
/* User-specified blender path */
#if _WIN32
wchar_t BLENDER_BIN_BUF[2048];
std::wstring blenderBinBuf;
const wchar_t* blenderBin = _wgetenv(L"BLENDER_BIN");
#else
const char* blenderBin = getenv("BLENDER_BIN");
#endif
/* Steam blender */
hecl::SystemString steamBlender;
/* Child process of blender */
#if _WIN32
if (!blenderBin || !RegFileExists(blenderBin)) {
/* Environment not set; try steam */
steamBlender = hecl::FindCommonSteamApp(_SYS_STR("Blender"));
if (steamBlender.size()) {
steamBlender += _SYS_STR("\\blender.exe");
blenderBin = steamBlender.c_str();
}
if (!RegFileExists(blenderBin)) {
/* No steam; try default */
wchar_t progFiles[256];
if (GetEnvironmentVariableW(L"ProgramFiles", progFiles, 256)) {
for (size_t major = MaxBlenderMajorSearch; major >= MinBlenderMajorSearch; --major) {
bool found = false;
for (size_t minor = MaxBlenderMinorSearch; minor >= MinBlenderMinorSearch; --minor) {
_snwprintf(BLENDER_BIN_BUF, 2048, L"%s\\Blender Foundation\\Blender %i.%i\\blender.exe", progFiles, major,
minor);
if (RegFileExists(BLENDER_BIN_BUF)) {
blenderBin = BLENDER_BIN_BUF;
found = true;
break;
}
}
if (found) {
break;
}
}
}
}
int blenderMajor = 0;
int blenderMinor = 0;
auto blenderBin = blender::FindBlender(blenderMajor, blenderMinor);
if (!blenderBin) {
BlenderLog.report(logvisor::Fatal, FMT_STRING("Failed to locate Blender installation"));
}
std::wstring cmdLine = fmt::format(FMT_STRING(L" --background -P \"{}\" -- {} {} {} \"{}\""), blenderShellPath,
uintptr_t(writehandle), uintptr_t(readhandle), verbosityLevel, blenderAddonPath);
#if _WIN32
std::string cmdLine = fmt::format(FMT_STRING(" --background -P \"{}\" -- {} {} {} \"{}\""), blenderShellPath,
uintptr_t(writehandle), uintptr_t(readhandle), verbosityLevel, blenderAddonPath);
STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
HANDLE nulHandle = CreateFileW(L"nul", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sattrs, OPEN_EXISTING,
@@ -407,14 +358,16 @@ Connection::Connection(int verbosityLevel) {
sinfo.hStdOutput = consoleOutWrite;
}
if (!CreateProcessW(blenderBin, cmdLine.data(), nullptr, nullptr, TRUE, NORMAL_PRIORITY_CLASS, nullptr, nullptr,
&sinfo, &m_pinfo)) {
const nowide::wstackstring wblenderBin(blenderBin.value());
nowide::wstackstring wcmdLine(cmdLine);
if (!CreateProcessW(wblenderBin.get(), wcmdLine.get(), nullptr, nullptr, TRUE, NORMAL_PRIORITY_CLASS, nullptr,
nullptr, &sinfo, &m_pinfo)) {
LPWSTR messageBuffer = nullptr;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0,
nullptr);
BlenderLog.report(logvisor::Fatal, FMT_STRING(L"unable to launch blender from {}: {}"), blenderBin,
messageBuffer);
BlenderLog.report(logvisor::Fatal, FMT_STRING("unable to launch blender from {}: {}"), blenderBin.value(),
nowide::narrow(messageBuffer));
}
close(m_writepipe[0]);
@@ -475,8 +428,8 @@ Connection::Connection(int verbosityLevel) {
/* Try user-specified blender first */
if (blenderBin) {
execlp(blenderBin, blenderBin, "--background", "-P", blenderShellPath.c_str(), "--", readfds.c_str(),
writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), nullptr);
execlp(blenderBin->c_str(), blenderBin->c_str(), "--background", "-P", blenderShellPath.c_str(), "--",
readfds.c_str(), writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), nullptr);
if (errno != ENOENT) {
errbuf = fmt::format(FMT_STRING("NOLAUNCH {}"), strerror(errno));
_writeStr(errbuf.c_str(), errbuf.size(), m_readpipe[1]);
@@ -485,16 +438,15 @@ Connection::Connection(int verbosityLevel) {
}
/* Try steam */
steamBlender = hecl::FindCommonSteamApp(_SYS_STR("Blender"));
steamBlender = hecl::FindCommonSteamApp("Blender");
if (steamBlender.size()) {
#ifdef __APPLE__
steamBlender += "/blender.app/Contents/MacOS/blender";
#else
steamBlender += "/blender";
#endif
blenderBin = steamBlender.c_str();
execlp(blenderBin, blenderBin, "--background", "-P", blenderShellPath.c_str(), "--", readfds.c_str(),
writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), nullptr);
execlp(steamBlender.c_str(), steamBlender.c_str(), "--background", "-P", blenderShellPath.c_str(), "--",
readfds.c_str(), writefds.c_str(), vLevel.c_str(), blenderAddonPath.c_str(), nullptr);
if (errno != ENOENT) {
errbuf = fmt::format(FMT_STRING("NOLAUNCH {}"), strerror(errno));
_writeStr(errbuf.c_str(), errbuf.size(), m_readpipe[1]);
@@ -522,11 +474,11 @@ Connection::Connection(int verbosityLevel) {
/* Stash error path and unlink existing file */
#if _WIN32
m_errPath = hecl::SystemString(TMPDIR) +
fmt::format(FMT_STRING(_SYS_STR("/hecl_{:016X}.derp")), (unsigned long long)m_pinfo.dwProcessId);
m_errPath = std::string(TMPDIR) +
fmt::format(FMT_STRING("/hecl_{:016X}.derp"), (unsigned long long)m_pinfo.dwProcessId);
#else
m_errPath = hecl::SystemString(TMPDIR) +
fmt::format(FMT_STRING(_SYS_STR("/hecl_{:016X}.derp")), (unsigned long long)m_blenderProc);
m_errPath = std::string(TMPDIR) +
fmt::format(FMT_STRING("/hecl_{:016X}.derp"), (unsigned long long)m_blenderProc);
#endif
hecl::Unlink(m_errPath.c_str());
@@ -539,25 +491,25 @@ Connection::Connection(int verbosityLevel) {
} else if (!lineStr.compare(0, 9, "NOBLENDER")) {
_closePipe();
#if _WIN32
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Unable to find blender at '{}'")), blenderBin);
BlenderLog.report(logvisor::Fatal, FMT_STRING("Unable to find blender at '{}'"), blenderBin.value());
#else
if (blenderBin)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Unable to find blender at '{}' or '{}'")), blenderBin,
BlenderLog.report(logvisor::Fatal, FMT_STRING("Unable to find blender at '{}' or '{}'"), blenderBin,
DEFAULT_BLENDER_BIN);
else
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Unable to find blender at '{}'")), DEFAULT_BLENDER_BIN);
BlenderLog.report(logvisor::Fatal, FMT_STRING("Unable to find blender at '{}'"), DEFAULT_BLENDER_BIN);
#endif
} else if (lineStr == "INVALIDBLENDERVER") {
_closePipe();
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Installed blender version must be >= {}.{}")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("Installed blender version must be >= {}.{}"),
MinBlenderMajorSearch, MinBlenderMinorSearch);
} else if (lineStr == "NOADDON") {
_closePipe();
if (blenderAddonPath != _SYS_STR("SKIPINSTALL"))
if (blenderAddonPath != "SKIPINSTALL")
InstallAddon(blenderAddonPath.c_str());
++installAttempt;
if (installAttempt >= 2)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("unable to install blender addon using '{}'")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("unable to install blender addon using '{}'"),
blenderAddonPath.c_str());
#ifndef _WIN32
waitpid(pid, nullptr, 0);
@@ -565,7 +517,7 @@ Connection::Connection(int verbosityLevel) {
continue;
} else if (lineStr == "ADDONINSTALLED") {
_closePipe();
blenderAddonPath = _SYS_STR("SKIPINSTALL");
blenderAddonPath = "SKIPINSTALL";
#ifndef _WIN32
waitpid(pid, nullptr, 0);
#endif
@@ -654,7 +606,7 @@ bool Connection::createBlend(const ProjectPath& path, BlendType type) {
FMT_STRING("BlenderConnection::createBlend() musn't be called with stream active"));
return false;
}
_writeStr(fmt::format(FMT_STRING("CREATE \"{}\" {}"), path.getAbsolutePathUTF8(), BlendTypeStrs[int(type)]));
_writeStr(fmt::format(FMT_STRING("CREATE \"{}\" {}"), path.getAbsolutePath(), BlendTypeStrs[int(type)]));
if (_isFinished()) {
/* Delete immediately in case save doesn't occur */
hecl::Unlink(path.getAbsolutePath().data());
@@ -673,7 +625,7 @@ bool Connection::openBlend(const ProjectPath& path, bool force) {
}
if (!force && path == m_loadedBlend)
return true;
_writeStr(fmt::format(FMT_STRING("OPEN \"{}\""), path.getAbsolutePathUTF8()));
_writeStr(fmt::format(FMT_STRING("OPEN \"{}\""), path.getAbsolutePath()));
if (_isFinished()) {
m_loadedBlend = path;
_writeStr("GETTYPE");
@@ -711,7 +663,7 @@ bool Connection::saveBlend() {
void Connection::deleteBlend() {
if (m_loadedBlend) {
hecl::Unlink(m_loadedBlend.getAbsolutePath().data());
BlenderLog.report(logvisor::Info, FMT_STRING(_SYS_STR("Deleted '{}'")), m_loadedBlend.getAbsolutePath());
BlenderLog.report(logvisor::Info, FMT_STRING("Deleted '{}'"), m_loadedBlend.getAbsolutePath());
m_loadedBlend = ProjectPath();
}
}
@@ -1203,8 +1155,7 @@ MapUniverse::World::World(Connection& conn) {
color.read(conn);
std::string path = conn._readStdString();
if (!path.empty()) {
hecl::SystemStringConv sysPath(path);
worldPath.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), sysPath.sys_str());
worldPath.assign(conn.getBlendPath().getProject().getProjectWorkingPath(), path);
}
}
@@ -1350,7 +1301,7 @@ std::vector<std::string> DataStream::getLightList() {
std::pair<atVec3f, atVec3f> DataStream::getMeshAABB() {
if (m_parent->m_loadedType != BlendType::Mesh && m_parent->m_loadedType != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a MESH or ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a MESH or ACTOR blend"),
m_parent->m_loadedBlend.getAbsolutePath());
m_parent->_writeStr("MESHAABB");
@@ -1368,7 +1319,7 @@ const char* DataStream::MeshOutputModeString(HMDLTopology topology) {
Mesh DataStream::compileMesh(HMDLTopology topology, int skinSlotCount) {
if (m_parent->getBlendType() != BlendType::Mesh)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a MESH blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a MESH blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("MESHCOMPILE");
@@ -1379,7 +1330,7 @@ Mesh DataStream::compileMesh(HMDLTopology topology, int skinSlotCount) {
Mesh DataStream::compileMesh(std::string_view name, HMDLTopology topology, int skinSlotCount, bool useLuv) {
if (m_parent->getBlendType() != BlendType::Area)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an AREA blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an AREA blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("MESHCOMPILENAME {} {}"), name, int(useLuv)));
@@ -1390,7 +1341,7 @@ Mesh DataStream::compileMesh(std::string_view name, HMDLTopology topology, int s
ColMesh DataStream::compileColMesh(std::string_view name) {
if (m_parent->getBlendType() != BlendType::Area)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an AREA blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an AREA blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("MESHCOMPILENAMECOLLISION {}"), name));
@@ -1401,7 +1352,7 @@ ColMesh DataStream::compileColMesh(std::string_view name) {
std::vector<ColMesh> DataStream::compileColMeshes() {
if (m_parent->getBlendType() != BlendType::ColMesh)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a CMESH blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a CMESH blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("MESHCOMPILECOLLISIONALL");
@@ -1414,7 +1365,7 @@ std::vector<ColMesh> DataStream::compileColMeshes() {
std::vector<Light> DataStream::compileLights() {
if (m_parent->getBlendType() != BlendType::Area)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an AREA blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an AREA blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("LIGHTCOMPILEALL");
@@ -1427,7 +1378,7 @@ std::vector<Light> DataStream::compileLights() {
PathMesh DataStream::compilePathMesh() {
if (m_parent->getBlendType() != BlendType::PathMesh)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a PATH blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a PATH blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("MESHCOMPILEPATH");
@@ -1438,7 +1389,7 @@ PathMesh DataStream::compilePathMesh() {
std::vector<uint8_t> DataStream::compileGuiFrame(int version) {
if (m_parent->getBlendType() != BlendType::Frame)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a FRAME blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a FRAME blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("FRAMECOMPILE {}"), version));
@@ -1449,13 +1400,12 @@ std::vector<uint8_t> DataStream::compileGuiFrame(int version) {
if (readStr == "FRAMEDONE")
break;
SystemStringConv absolute(readStr);
auto& proj = m_parent->getBlendPath().getProject();
SystemString relative;
if (PathRelative(absolute.c_str()))
relative = absolute.sys_str();
std::string relative;
if (PathRelative(readStr.c_str()))
relative = readStr;
else
relative = proj.getProjectRootPath().getProjectRelativeFromAbsolute(absolute.sys_str());
relative = proj.getProjectRootPath().getProjectRelativeFromAbsolute(readStr);
hecl::ProjectPath path(proj.getProjectWorkingPath(), relative);
m_parent->_writeStr(fmt::format(FMT_STRING("{:08X}"), path.parsedHash32()));
@@ -1478,7 +1428,7 @@ std::vector<ProjectPath> DataStream::getTextures() {
Actor DataStream::compileActor() {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("ACTORCOMPILE");
@@ -1489,7 +1439,7 @@ Actor DataStream::compileActor() {
Actor DataStream::compileActorCharacterOnly() {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("ACTORCOMPILECHARACTERONLY");
@@ -1500,7 +1450,7 @@ Actor DataStream::compileActorCharacterOnly() {
Armature DataStream::compileArmature() {
if (m_parent->getBlendType() != BlendType::Armature)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ARMATURE blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ARMATURE blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("ARMATURECOMPILE");
@@ -1511,7 +1461,7 @@ Armature DataStream::compileArmature() {
Action DataStream::compileActionChannelsOnly(std::string_view name) {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("ACTIONCOMPILECHANNELSONLY {}"), name));
@@ -1522,7 +1472,7 @@ Action DataStream::compileActionChannelsOnly(std::string_view name) {
World DataStream::compileWorld() {
if (m_parent->getBlendType() != BlendType::World)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an WORLD blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an WORLD blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("WORLDCOMPILE");
@@ -1533,7 +1483,7 @@ World DataStream::compileWorld() {
std::vector<std::pair<std::string, std::string>> DataStream::getSubtypeNames() {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("GETSUBTYPENAMES");
@@ -1551,7 +1501,7 @@ std::vector<std::pair<std::string, std::string>> DataStream::getSubtypeNames() {
std::vector<std::pair<std::string, std::string>> DataStream::getActionNames() {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("GETACTIONNAMES");
@@ -1569,7 +1519,7 @@ std::vector<std::pair<std::string, std::string>> DataStream::getActionNames() {
std::vector<std::pair<std::string, std::string>> DataStream::getSubtypeOverlayNames(std::string_view name) {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("GETSUBTYPEOVERLAYNAMES {}"), name));
@@ -1587,7 +1537,7 @@ std::vector<std::pair<std::string, std::string>> DataStream::getSubtypeOverlayNa
std::vector<std::pair<std::string, std::string>> DataStream::getAttachmentNames() {
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("GETATTACHMENTNAMES");
@@ -1608,7 +1558,7 @@ std::unordered_map<std::string, Matrix3f> DataStream::getBoneMatrices(std::strin
return {};
if (m_parent->getBlendType() != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an ACTOR blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an ACTOR blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("GETBONEMATRICES {}"), name));
@@ -1643,7 +1593,7 @@ bool DataStream::renderPvs(std::string_view path, const atVec3f& location) {
return false;
if (m_parent->getBlendType() != BlendType::Area)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an AREA blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an AREA blend"),
m_parent->getBlendPath().getAbsolutePath());
athena::simd_floats f(location.simd);
@@ -1658,7 +1608,7 @@ bool DataStream::renderPvsLight(std::string_view path, std::string_view lightNam
return false;
if (m_parent->getBlendType() != BlendType::Area)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not an AREA blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not an AREA blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr(fmt::format(FMT_STRING("RENDERPVSLIGHT {} {}"), path, lightName));
@@ -1669,7 +1619,7 @@ bool DataStream::renderPvsLight(std::string_view path, std::string_view lightNam
MapArea DataStream::compileMapArea() {
if (m_parent->getBlendType() != BlendType::MapArea)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a MAPAREA blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a MAPAREA blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("MAPAREACOMPILE");
@@ -1680,7 +1630,7 @@ MapArea DataStream::compileMapArea() {
MapUniverse DataStream::compileMapUniverse() {
if (m_parent->getBlendType() != BlendType::MapUniverse)
BlenderLog.report(logvisor::Fatal, FMT_STRING(_SYS_STR("{} is not a MAPUNIVERSE blend")),
BlenderLog.report(logvisor::Fatal, FMT_STRING("{} is not a MAPUNIVERSE blend"),
m_parent->getBlendPath().getAbsolutePath());
m_parent->_writeStr("MAPUNIVERSECOMPILE");

View File

@@ -0,0 +1,144 @@
#include "hecl/Blender/FindBlender.hpp"
#include "hecl/SteamFinder.hpp"
#include "hecl/hecl.hpp"
namespace hecl::blender {
#ifdef __APPLE__
#define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender"
#else
#define DEFAULT_BLENDER_BIN "blender"
#endif
static const std::regex regBlenderVersion(R"(Blender (\d+)\.(\d+)(?:\.(\d+))?)",
std::regex::ECMAScript | std::regex::optimize);
static bool RegFileExists(const char* path) {
if (!path)
return false;
hecl::Sstat theStat;
return !hecl::Stat(path, &theStat) && S_ISREG(theStat.st_mode);
}
std::optional<std::string> FindBlender(int& major, int& minor) {
major = 0;
minor = 0;
/* User-specified blender path */
#if _WIN32
auto blenderBin = GetEnv("BLENDER_BIN");
#else
const char* cblenderBin = getenv("BLENDER_BIN");
std::optional<std::string> blenderBin{};
if (cblenderBin != nullptr) {
blenderBin = cblenderBin;
}
#endif
/* Steam blender */
std::string steamBlender;
/* Child process of blender */
#if _WIN32
if (!blenderBin || !RegFileExists(blenderBin->c_str())) {
/* Environment not set; try steam */
steamBlender = hecl::FindCommonSteamApp("Blender");
if (steamBlender.size()) {
steamBlender += "\\blender.exe";
blenderBin = steamBlender.c_str();
}
if (!RegFileExists(blenderBin->c_str())) {
/* No steam; try default */
wchar_t wProgFiles[256];
if (GetEnvironmentVariableW(L"ProgramFiles", wProgFiles, 256)) {
auto progFiles = nowide::narrow(wProgFiles);
for (size_t major = MaxBlenderMajorSearch; major >= MinBlenderMajorSearch; --major) {
bool found = false;
for (size_t minor = MaxBlenderMinorSearch; minor >= MinBlenderMinorSearch; --minor) {
std::string blenderBinBuf = fmt::format(FMT_STRING("{}\\Blender Foundation\\Blender {}.{}\\blender.exe"),
progFiles, major, minor);
if (RegFileExists(blenderBinBuf.c_str())) {
blenderBin = std::move(blenderBinBuf);
found = true;
break;
}
}
if (found) {
break;
}
}
}
}
}
#else
if (!RegFileExists(blenderBin)) {
/* Try steam */
steamBlender = hecl::FindCommonSteamApp("Blender");
if (steamBlender.size()) {
#ifdef __APPLE__
steamBlender += "/blender.app/Contents/MacOS/blender";
#else
steamBlender += "/blender";
#endif
blenderBin = steamBlender.c_str();
if (!RegFileExists(blenderBin)) {
blenderBin = DEFAULT_BLENDER_BIN;
if (!RegFileExists(blenderBin)) {
blenderBin = nullptr;
}
}
} else {
blenderBin = DEFAULT_BLENDER_BIN;
if (!RegFileExists(blenderBin)) {
blenderBin = nullptr;
}
}
}
#endif
if (!blenderBin)
return {};
#if _WIN32
const nowide::wstackstring wblenderBin(blenderBin.value());
DWORD handle = 0;
DWORD infoSize = GetFileVersionInfoSizeW(wblenderBin.get(), &handle);
if (infoSize != NULL) {
auto* infoData = new char[infoSize];
if (GetFileVersionInfoW(wblenderBin.get(), handle, infoSize, infoData)) {
UINT size = 0;
LPVOID lpBuffer = nullptr;
if (VerQueryValueW(infoData, L"\\", &lpBuffer, &size) && size != 0u) {
auto* verInfo = static_cast<VS_FIXEDFILEINFO*>(lpBuffer);
if (verInfo->dwSignature == 0xfeef04bd) {
major = static_cast<int>((verInfo->dwFileVersionMS >> 16) & 0xffff);
minor = static_cast<int>((verInfo->dwFileVersionMS >> 0 & 0xffff) * 10 +
(verInfo->dwFileVersionLS >> 16 & 0xffff));
}
}
}
delete[] infoData;
}
#else
std::string command = std::string("\"") + blenderBin + "\" --version";
FILE* fp = popen(command.c_str(), "r");
char versionBuf[256];
size_t rdSize = fread(versionBuf, 1, 255, fp);
versionBuf[rdSize] = '\0';
pclose(fp);
std::cmatch match;
if (std::regex_search(versionBuf, match, regBlenderVersion)) {
major = atoi(match[1].str().c_str());
minor = atoi(match[2].str().c_str());
}
#endif
return blenderBin;
}
} // namespace hecl::blender

View File

@@ -69,7 +69,7 @@ void SDNARead::enumerate(const std::function<bool(const FileBlock& block, athena
}
}
SDNARead::SDNARead(SystemStringView path) {
SDNARead::SDNARead(std::string_view path) {
athena::io::FileReader r(path);
if (r.hasError())
return;
@@ -134,7 +134,7 @@ SDNARead::SDNARead(SystemStringView path) {
});
}
BlendType GetBlendType(SystemStringView path) {
BlendType GetBlendType(std::string_view path) {
SDNARead r(path);
if (!r)
return BlendType::None;

View File

@@ -35,7 +35,6 @@ set(HECL_HEADERS
../include/hecl/Database.hpp
../include/hecl/Runtime.hpp
../include/hecl/ClientProcess.hpp
../include/hecl/SystemChar.hpp
../include/hecl/BitVector.hpp
../include/hecl/MathExtras.hpp
../include/hecl/UniformBufferPool.hpp
@@ -63,27 +62,32 @@ if(UNIX)
endif()
add_library(hecl-full
${FRONTEND_SOURCES}
${RUNTIME_SOURCES}
${BLENDER_SOURCES}
${COMMON_SOURCES}
${HECL_HEADERS}
${PLAT_SRCS}
Pipeline.cpp)
${FRONTEND_SOURCES}
${RUNTIME_SOURCES}
${BLENDER_SOURCES}
${COMMON_SOURCES}
${HECL_HEADERS}
${PLAT_SRCS}
Pipeline.cpp)
target_include_directories(hecl-full PUBLIC ../include)
target_link_libraries(hecl-full PUBLIC ${HECL_APPLICATION_REPS_TARGETS_LIST}
hecl-blender-addon boo athena-core logvisor)
hecl-blender-addon boo athena-core logvisor)
target_atdna(hecl-full atdna_HMDLMeta_full.cpp ../include/hecl/HMDLMeta.hpp)
target_atdna(hecl-full atdna_CVar_full.cpp ../include/hecl/CVar.hpp)
target_atdna(hecl-full atdna_SDNARead_full.cpp ../include/hecl/Blender/SDNARead.hpp)
add_library(hecl-light
${RUNTIME_SOURCES}
${COMMON_SOURCES}
${HECL_HEADERS}
${PLAT_SRCS})
${RUNTIME_SOURCES}
${COMMON_SOURCES}
${HECL_HEADERS}
${PLAT_SRCS}
${FIND_BLENDER_SOURCES})
target_include_directories(hecl-light PUBLIC ../include)
target_link_libraries(hecl-light PUBLIC ${HECL_APPLICATION_REPS_TARGETS_LIST} boo athena-core logvisor)
if (WIN32)
# For FindBlender
target_link_libraries(hecl-light PUBLIC Version)
endif ()
target_atdna(hecl-light atdna_HMDLMeta_light.cpp ../include/hecl/HMDLMeta.hpp)
target_atdna(hecl-light atdna_CVar_light.cpp ../include/hecl/CVar.hpp)

View File

@@ -259,18 +259,6 @@ std::string CVar::toLiteral(bool* isValid) const {
return m_value;
}
std::wstring CVar::toWideLiteral(bool* isValid) const {
if (m_type != EType::Literal && (com_developer && com_developer->toBoolean())) {
if (isValid != nullptr)
*isValid = false;
} else if (isValid != nullptr) {
*isValid = true;
}
// Even if it's not a literal, it's still safe to return
return hecl::UTF8ToWide(m_value);
}
bool CVar::fromVec2f(const atVec2f& val) {
if (!safeToModify(EType::Vec2f))
return false;
@@ -398,15 +386,6 @@ bool CVar::fromLiteral(std::string_view val) {
return true;
}
bool CVar::fromLiteral(std::wstring_view val) {
if (!safeToModify(EType::Literal))
return false;
m_value.assign(hecl::WideToUTF8(val));
setModified();
return true;
}
bool CVar::fromLiteralToType(std::string_view val) {
if (!safeToModify(m_type) || !isValidInput(val))
return false;
@@ -415,8 +394,6 @@ bool CVar::fromLiteralToType(std::string_view val) {
return true;
}
bool CVar::fromLiteralToType(std::wstring_view val) { return fromLiteralToType(hecl::WideToUTF8(val)); }
bool CVar::isModified() const { return True(m_flags & EFlags::Modified); }
bool CVar::modificationRequiresRestart() const { return True(m_flags & EFlags::ModifyRestart); }
@@ -523,8 +500,6 @@ bool CVar::isValidInput(std::string_view input) const {
return false;
}
bool CVar::isValidInput(std::wstring_view input) const { return isValidInput(hecl::WideToUTF8(input)); }
bool CVar::safeToModify(EType type) const {
// Are we NoDevelper?
if (isNoDeveloper())

View File

@@ -111,18 +111,13 @@ void CVarManager::deserialize(CVar* cvar) {
}
/* We were either unable to find a deferred value or got an invalid value */
#if _WIN32
hecl::SystemString filename =
hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toWideLiteral();
#else
hecl::SystemString filename =
hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toLiteral();
#endif
std::string filename =
std::string(m_store.getStoreRoot()) + '/' + com_configfile->toLiteral();
hecl::Sstat st;
if (m_useBinary) {
CVarContainer container;
filename += _SYS_STR(".bin");
filename += ".bin";
if (hecl::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
return;
athena::io::FileReader reader(filename);
@@ -144,7 +139,7 @@ void CVarManager::deserialize(CVar* cvar) {
}
}
} else {
filename += _SYS_STR(".yaml");
filename += ".yaml";
if (hecl::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
return;
athena::io::FileReader reader(filename);
@@ -170,13 +165,8 @@ void CVarManager::deserialize(CVar* cvar) {
}
void CVarManager::serialize() {
#if _WIN32
hecl::SystemString filename =
hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toWideLiteral();
#else
hecl::SystemString filename =
hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toLiteral();
#endif
std::string filename =
std::string(m_store.getStoreRoot()) + '/' + com_configfile->toLiteral();
if (m_useBinary) {
CVarContainer container;
@@ -189,12 +179,12 @@ void CVarManager::serialize() {
}
container.cvarCount = atUint32(container.cvars.size());
filename += _SYS_STR(".bin");
filename += ".bin";
athena::io::FileWriter writer(filename);
if (writer.isOpen())
container.write(writer);
} else {
filename += _SYS_STR(".yaml");
filename += ".yaml";
athena::io::FileReader r(filename);
athena::io::YAMLDocWriter docWriter(r.isOpen() ? &r : nullptr);
@@ -297,21 +287,20 @@ bool CVarManager::restartRequired() const {
});
}
void CVarManager::parseCommandLine(const std::vector<SystemString>& args) {
void CVarManager::parseCommandLine(const std::vector<std::string>& args) {
bool oldDeveloper = suppressDeveloper();
std::string developerName(com_developer->name());
athena::utility::tolower(developerName);
for (const SystemString& arg : args) {
if (arg[0] != _SYS_STR('+')) {
for (const std::string& arg : args) {
if (arg[0] != '+') {
continue;
}
const std::string tmp(SystemUTF8Conv(arg).str());
std::smatch matches;
std::string cvarName;
std::string cvarValue;
if (std::regex_match(tmp, matches, cmdLineRegex)) {
if (std::regex_match(arg, matches, cmdLineRegex)) {
std::vector<std::string> realMatches;
for (auto match : matches) {
if (match.matched) {

View File

@@ -26,7 +26,7 @@ ThreadLocalPtr<ClientProcess::Worker> ClientProcess::ThreadWorker;
int CpuCountOverride = 0;
void SetCpuCountOverride(int argc, const SystemChar** argv) {
void SetCpuCountOverride(int argc, char** argv) {
bool threadArg = false;
for (int i = 1; i < argc; ++i) {
if (threadArg) {
@@ -35,7 +35,7 @@ void SetCpuCountOverride(int argc, const SystemChar** argv) {
return;
}
}
if (!hecl::StrNCmp(argv[i], _SYS_STR("-j"), 2)) {
if (!hecl::StrNCmp(argv[i], "-j", 2)) {
if (int count = int(hecl::StrToUl(argv[i] + 2, nullptr, 0))) {
CpuCountOverride = count;
return;
@@ -65,7 +65,7 @@ static int GetCPUCount() {
void ClientProcess::BufferTransaction::run(blender::Token& btok) {
athena::io::FileReader r(m_path.getAbsolutePath(), 32 * 1024, false);
if (r.hasError()) {
CP_Log.report(logvisor::Fatal, FMT_STRING(_SYS_STR("unable to background-buffer '{}'")), m_path.getAbsolutePath());
CP_Log.report(logvisor::Fatal, FMT_STRING("unable to background-buffer '{}'"), m_path.getAbsolutePath());
return;
}
if (m_offset)
@@ -175,30 +175,30 @@ bool ClientProcess::syncCook(const hecl::ProjectPath& path, Database::IDataSpec*
if (specEnt) {
hecl::ProjectPath cooked = path.getCookedPath(*specEnt);
if (fast)
cooked = cooked.getWithExtension(_SYS_STR(".fast"));
cooked = cooked.getWithExtension(".fast");
cooked.makeDirChain(false);
if (force || cooked.getPathType() == ProjectPath::Type::None || path.getModtime() > cooked.getModtime()) {
if (m_progPrinter) {
hecl::SystemString str;
std::string str;
if (path.getAuxInfo().empty())
str = fmt::format(FMT_STRING(_SYS_STR("Cooking {}")), path.getRelativePath());
str = fmt::format(FMT_STRING("Cooking {}"), path.getRelativePath());
else
str = fmt::format(FMT_STRING(_SYS_STR("Cooking {}|{}")), path.getRelativePath(), path.getAuxInfo());
str = fmt::format(FMT_STRING("Cooking {}|{}"), path.getRelativePath(), path.getAuxInfo());
m_progPrinter->print(str, std::nullopt, -1.f, hecl::ClientProcess::GetThreadWorkerIdx());
m_progPrinter->flush();
} else {
if (path.getAuxInfo().empty())
LogModule.report(logvisor::Info, FMT_STRING(_SYS_STR("Cooking {}")), path.getRelativePath());
LogModule.report(logvisor::Info, FMT_STRING("Cooking {}"), path.getRelativePath());
else
LogModule.report(logvisor::Info, FMT_STRING(_SYS_STR("Cooking {}|{}")), path.getRelativePath(), path.getAuxInfo());
LogModule.report(logvisor::Info, FMT_STRING("Cooking {}|{}"), path.getRelativePath(), path.getAuxInfo());
}
spec->doCook(path, cooked, false, btok, [](const SystemChar*) {});
spec->doCook(path, cooked, false, btok, [](const char*) {});
if (m_progPrinter) {
hecl::SystemString str;
std::string str;
if (path.getAuxInfo().empty())
str = fmt::format(FMT_STRING(_SYS_STR("Cooked {}")), path.getRelativePath());
str = fmt::format(FMT_STRING("Cooked {}"), path.getRelativePath());
else
str = fmt::format(FMT_STRING(_SYS_STR("Cooked {}|{}")), path.getRelativePath(), path.getAuxInfo());
str = fmt::format(FMT_STRING("Cooked {}|{}"), path.getRelativePath(), path.getAuxInfo());
m_progPrinter->print(str, std::nullopt, -1.f, hecl::ClientProcess::GetThreadWorkerIdx());
m_progPrinter->flush();
}

View File

@@ -378,16 +378,6 @@ void Console::LogVisorAdapter::report(const char* modName, logvisor::Level sever
}
}
void Console::LogVisorAdapter::report(const char* modName, logvisor::Level severity,
fmt::wstring_view format, fmt::wformat_args args) {
auto tmp = fmt::vformat(format, args);
std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n');
for (const std::string& line : lines) {
auto v = fmt::format(FMT_STRING("[{}] {}"), modName, line);
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
}
}
void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level severity, const char* file,
unsigned linenum, fmt::string_view format, fmt::format_args args) {
auto tmp = fmt::vformat(format, args);
@@ -395,16 +385,6 @@ void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
}
void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level severity, const char* file,
unsigned linenum, fmt::wstring_view format, fmt::wformat_args args) {
auto tmp = fmt::vformat(format, args);
std::vector<std::string> lines = athena::utility::split(athena::utility::wideToUtf8(tmp), '\n');
for (const std::string& line : lines) {
auto v = fmt::format(FMT_STRING("[{}] {} {}:{}"), modName, line, file, linenum);
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
}
}
void Console::dumpLog() {
for (const auto& l : m_log) {
switch (l.second) {

View File

@@ -38,20 +38,20 @@ void MultiProgressPrinter::ThreadStat::print(const TermInfo& tinfo) const {
if (submessageLen) {
if (messageLen > half - submessageLen - 1)
fmt::print(FMT_STRING(_SYS_STR(" {:.{}}... {} ")), m_message, half - submessageLen - 4, m_submessage);
fmt::print(FMT_STRING(" {:.{}}... {} "), m_message, half - submessageLen - 4, m_submessage);
else {
fmt::print(FMT_STRING(_SYS_STR(" {}")), m_message);
fmt::print(FMT_STRING(" {}"), m_message);
for (int i = half - messageLen - submessageLen - 1; i >= 0; --i)
fmt::print(FMT_STRING(_SYS_STR(" ")));
fmt::print(FMT_STRING(_SYS_STR("{} ")), m_submessage);
fmt::print(FMT_STRING(" "));
fmt::print(FMT_STRING("{} "), m_submessage);
}
} else {
if (messageLen > half)
fmt::print(FMT_STRING(_SYS_STR(" {:.{}}... ")), m_message, half - 3);
fmt::print(FMT_STRING(" {:.{}}... "), m_message, half - 3);
else {
fmt::print(FMT_STRING(_SYS_STR(" {}")), m_message);
fmt::print(FMT_STRING(" {}"), m_message);
for (int i = half - messageLen; i >= 0; --i)
fmt::print(FMT_STRING(_SYS_STR(" ")));
fmt::print(FMT_STRING(" "));
}
}
@@ -62,22 +62,22 @@ void MultiProgressPrinter::ThreadStat::print(const TermInfo& tinfo) const {
int rem = nblocks - filled;
if (tinfo.xtermColor) {
fmt::print(FMT_STRING(_SYS_STR("" BOLD "{:3d}% [")), iFactor);
fmt::print(FMT_STRING("" BOLD "{:3d}% ["), iFactor);
for (int b = 0; b < filled; ++b)
fmt::print(FMT_STRING(_SYS_STR("#")));
fmt::print(FMT_STRING("#"));
for (int b = 0; b < rem; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("]" NORMAL "")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("]" NORMAL ""));
} else {
#if _WIN32
SetConsoleTextAttribute(tinfo.console, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
#endif
fmt::print(FMT_STRING(_SYS_STR("{:3d}% [")), iFactor);
fmt::print(FMT_STRING("{:3d}% ["), iFactor);
for (int b = 0; b < filled; ++b)
fmt::print(FMT_STRING(_SYS_STR("#")));
fmt::print(FMT_STRING("#"));
for (int b = 0; b < rem; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("]")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("]"));
#if _WIN32
SetConsoleTextAttribute(tinfo.console, FOREGROUND_WHITE);
#endif
@@ -100,24 +100,24 @@ void MultiProgressPrinter::DrawIndeterminateBar() {
int rem = blocks - pre - 1;
if (m_termInfo.xtermColor) {
fmt::print(FMT_STRING(_SYS_STR("" BOLD " [")));
fmt::print(FMT_STRING("" BOLD " ["));
for (int b = 0; b < pre; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("#")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("#"));
for (int b = 0; b < rem; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("]" NORMAL "")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("]" NORMAL ""));
} else {
#if _WIN32
SetConsoleTextAttribute(m_termInfo.console, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
#endif
fmt::print(FMT_STRING(_SYS_STR(" [")));
fmt::print(FMT_STRING(" ["));
for (int b = 0; b < pre; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("#")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("#"));
for (int b = 0; b < rem; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("]")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("]"));
#if _WIN32
SetConsoleTextAttribute(m_termInfo.console, FOREGROUND_WHITE);
#endif
@@ -127,7 +127,7 @@ void MultiProgressPrinter::DrawIndeterminateBar() {
void MultiProgressPrinter::MoveCursorUp(int n) {
if (n) {
if (m_termInfo.xtermColor) {
fmt::print(FMT_STRING(_SYS_STR("" PREV_LINE "")), n);
fmt::print(FMT_STRING("" PREV_LINE ""), n);
}
#if _WIN32
else {
@@ -139,7 +139,7 @@ void MultiProgressPrinter::MoveCursorUp(int n) {
}
#endif
} else {
fmt::print(FMT_STRING(_SYS_STR("\r")));
fmt::print(FMT_STRING("\r"));
}
}
@@ -157,7 +157,7 @@ void MultiProgressPrinter::DoPrint() {
SetConsoleCursorInfo(m_termInfo.console, &cursorInfo);
#endif
if (m_termInfo.xtermColor)
fmt::print(FMT_STRING(_SYS_STR("" HIDE_CURSOR "")));
fmt::print(FMT_STRING("" HIDE_CURSOR ""));
if (m_dirty) {
m_termInfo.width = (hecl::GuiMode ? 120 : std::max(80, hecl::ConsoleWidth(&m_termInfo.truncate)));
@@ -168,7 +168,7 @@ void MultiProgressPrinter::DoPrint() {
for (const ThreadStat& stat : m_threadStats) {
if (stat.m_active) {
stat.print(m_termInfo);
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING("\n"));
++m_curThreadLines;
}
}
@@ -179,7 +179,7 @@ void MultiProgressPrinter::DoPrint() {
#endif
) {
DrawIndeterminateBar();
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING("\n"));
++m_curProgLines;
} else if (m_mainFactor >= 0.f) {
float factor = std::max(0.0f, std::min(1.0f, m_mainFactor));
@@ -191,34 +191,34 @@ void MultiProgressPrinter::DoPrint() {
int rem = blocks - filled;
if (m_termInfo.xtermColor) {
fmt::print(FMT_STRING(_SYS_STR("" BOLD " {:3d}% [")), iFactor);
fmt::print(FMT_STRING("" BOLD " {:3d}% ["), iFactor);
for (int b = 0; b < filled; ++b)
fmt::print(FMT_STRING(_SYS_STR("#")));
fmt::print(FMT_STRING("#"));
for (int b = 0; b < rem; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("]" NORMAL "")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("]" NORMAL ""));
} else {
#if _WIN32
SetConsoleTextAttribute(m_termInfo.console, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
#endif
fmt::print(FMT_STRING(_SYS_STR(" {:3d}% [")), iFactor);
fmt::print(FMT_STRING(" {:3d}% ["), iFactor);
for (int b = 0; b < filled; ++b)
fmt::print(FMT_STRING(_SYS_STR("#")));
fmt::print(FMT_STRING("#"));
for (int b = 0; b < rem; ++b)
fmt::print(FMT_STRING(_SYS_STR("-")));
fmt::print(FMT_STRING(_SYS_STR("]")));
fmt::print(FMT_STRING("-"));
fmt::print(FMT_STRING("]"));
#if _WIN32
SetConsoleTextAttribute(m_termInfo.console, FOREGROUND_WHITE);
#endif
}
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING("\n"));
++m_curProgLines;
}
} else if (m_latestThread != -1) {
const ThreadStat& stat = m_threadStats[m_latestThread];
stat.print(m_termInfo);
fmt::print(FMT_STRING(_SYS_STR("\r")));
fmt::print(FMT_STRING("\r"));
}
m_dirty = false;
} else if (m_mainIndeterminate
@@ -230,12 +230,12 @@ void MultiProgressPrinter::DoPrint() {
MoveCursorUp(m_curProgLines);
m_curProgLines = 0;
DrawIndeterminateBar();
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING("\n"));
++m_curProgLines;
}
if (m_termInfo.xtermColor)
fmt::print(FMT_STRING(_SYS_STR("" SHOW_CURSOR "")));
fmt::print(FMT_STRING("" SHOW_CURSOR ""));
fflush(stdout);
#if _WIN32
@@ -286,8 +286,8 @@ MultiProgressPrinter::~MultiProgressPrinter() {
m_logThread.join();
}
void MultiProgressPrinter::print(std::optional<hecl::SystemStringView> message,
std::optional<hecl::SystemStringView> submessage,
void MultiProgressPrinter::print(std::optional<std::string_view> message,
std::optional<std::string_view> submessage,
float factor,
int threadIdx) const {
if (!m_running) {
@@ -356,7 +356,7 @@ void MultiProgressPrinter::startNewLine() const {
m_curThreadLines = 0;
m_mainFactor = -1.f;
auto logLk = logvisor::LockLog();
fmt::print(FMT_STRING(_SYS_STR("\n")));
fmt::print(FMT_STRING("\n"));
}
void MultiProgressPrinter::flush() const {

View File

@@ -15,7 +15,7 @@ class ShaderCacheZipStream : public athena::io::IStreamReader {
z_stream m_zstrm = {};
public:
explicit ShaderCacheZipStream(const hecl::SystemChar* path) : m_reader(path) {
explicit ShaderCacheZipStream(const char* path) : m_reader(path) {
if (m_reader.hasError())
return;
if (m_reader.readUint32Big() != SBIG('SHAD'))
@@ -91,7 +91,7 @@ static std::vector<boo::VertexElementDescriptor> ReadVertexFormat(ShaderCacheZip
}
template <typename P>
bool PipelineConverter<P>::loadFromFile(FactoryCtx& ctx, const hecl::SystemChar* path) {
bool PipelineConverter<P>::loadFromFile(FactoryCtx& ctx, const char* path) {
ShaderCacheZipStream r(path);
if (!r)
return false;

View File

@@ -43,8 +43,8 @@ static bool CheckNewLineAdvance(std::string::const_iterator& it) {
return false;
}
Project::ConfigFile::ConfigFile(const Project& project, SystemStringView name, SystemStringView subdir) {
m_filepath = SystemString(project.m_rootPath.getAbsolutePath()) + subdir.data() + name.data();
Project::ConfigFile::ConfigFile(const Project& project, std::string_view name, std::string_view subdir) {
m_filepath = std::string(project.m_rootPath.getAbsolutePath()) + subdir.data() + name.data();
}
std::vector<std::string>& Project::ConfigFile::lockAndRead() {
@@ -52,7 +52,7 @@ std::vector<std::string>& Project::ConfigFile::lockAndRead() {
return m_lines;
}
m_lockedFile = hecl::FopenUnique(m_filepath.c_str(), _SYS_STR("a+"), FileLockType::Write);
m_lockedFile = hecl::FopenUnique(m_filepath.c_str(), "a+", FileLockType::Write);
hecl::FSeek(m_lockedFile.get(), 0, SEEK_SET);
std::string mainString;
@@ -132,8 +132,8 @@ bool Project::ConfigFile::unlockAndCommit() {
return false;
}
const SystemString newPath = m_filepath + _SYS_STR(".part");
auto newFile = hecl::FopenUnique(newPath.c_str(), _SYS_STR("w"), FileLockType::Write);
const std::string newPath = m_filepath + ".part";
auto newFile = hecl::FopenUnique(newPath.c_str(), "w", FileLockType::Write);
bool fail = false;
for (const std::string& line : m_lines) {
if (std::fwrite(line.c_str(), 1, line.size(), newFile.get()) != line.size()) {
@@ -149,19 +149,10 @@ bool Project::ConfigFile::unlockAndCommit() {
newFile.reset();
m_lockedFile.reset();
if (fail) {
#if HECL_UCS2
_wunlink(newPath.c_str());
#else
unlink(newPath.c_str());
#endif
Unlink(newPath.c_str());
return false;
} else {
#if HECL_UCS2
//_wrename(newPath.c_str(), m_filepath.c_str());
MoveFileExW(newPath.c_str(), m_filepath.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
#else
rename(newPath.c_str(), m_filepath.c_str());
#endif
Rename(newPath.c_str(), m_filepath.c_str());
return true;
}
}
@@ -172,21 +163,21 @@ bool Project::ConfigFile::unlockAndCommit() {
Project::Project(const ProjectRootPath& rootPath)
: m_rootPath(rootPath)
, m_workRoot(*this, _SYS_STR(""))
, m_dotPath(m_workRoot, _SYS_STR(".hecl"))
, m_cookedRoot(m_dotPath, _SYS_STR("cooked"))
, m_specs(*this, _SYS_STR("specs"))
, m_paths(*this, _SYS_STR("paths"))
, m_groups(*this, _SYS_STR("groups")) {
, m_workRoot(*this, "")
, m_dotPath(m_workRoot, ".hecl")
, m_cookedRoot(m_dotPath, "cooked")
, m_specs(*this, "specs")
, m_paths(*this, "paths")
, m_groups(*this, "groups") {
/* Stat for existing project directory (must already exist) */
Sstat myStat;
if (hecl::Stat(m_rootPath.getAbsolutePath().data(), &myStat)) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("unable to stat {}")), m_rootPath.getAbsolutePath());
LogModule.report(logvisor::Error, FMT_STRING("unable to stat {}"), m_rootPath.getAbsolutePath());
return;
}
if (!S_ISDIR(myStat.st_mode)) {
LogModule.report(logvisor::Error, FMT_STRING(_SYS_STR("provided path must be a directory; '{}' isn't")),
LogModule.report(logvisor::Error, FMT_STRING("provided path must be a directory; '{}' isn't"),
m_rootPath.getAbsolutePath());
return;
}
@@ -196,8 +187,8 @@ Project::Project(const ProjectRootPath& rootPath)
m_cookedRoot.makeDir();
/* Ensure beacon is valid or created */
const ProjectPath beaconPath(m_dotPath, _SYS_STR("beacon"));
auto bf = hecl::FopenUnique(beaconPath.getAbsolutePath().data(), _SYS_STR("a+b"));
const ProjectPath beaconPath(m_dotPath, "beacon");
auto bf = hecl::FopenUnique(beaconPath.getAbsolutePath().data(), "a+b");
struct BeaconStruct {
hecl::FourCC magic;
uint32_t version;
@@ -225,14 +216,14 @@ const ProjectPath& Project::getProjectCookedPath(const DataSpecEntry& spec) cons
for (const ProjectDataSpec& sp : m_compiledSpecs)
if (&sp.spec == &spec)
return sp.cookedPath;
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Unable to find spec '{}'")), spec.m_name);
LogModule.report(logvisor::Fatal, FMT_STRING("Unable to find spec '{}'"), spec.m_name);
return m_cookedRoot;
}
bool Project::addPaths(const std::vector<ProjectPath>& paths) {
m_paths.lockAndRead();
for (const ProjectPath& path : paths)
m_paths.addLine(path.getRelativePathUTF8());
m_paths.addLine(path.getRelativePath());
return m_paths.unlockAndCommit();
}
@@ -240,7 +231,7 @@ bool Project::removePaths(const std::vector<ProjectPath>& paths, bool recursive)
std::vector<std::string>& existingPaths = m_paths.lockAndRead();
if (recursive) {
for (const ProjectPath& path : paths) {
auto recursiveBase = path.getRelativePathUTF8();
auto recursiveBase = path.getRelativePath();
for (auto it = existingPaths.begin(); it != existingPaths.end();) {
if (!(*it).compare(0, recursiveBase.size(), recursiveBase)) {
it = existingPaths.erase(it);
@@ -251,19 +242,19 @@ bool Project::removePaths(const std::vector<ProjectPath>& paths, bool recursive)
}
} else
for (const ProjectPath& path : paths)
m_paths.removeLine(path.getRelativePathUTF8());
m_paths.removeLine(path.getRelativePath());
return m_paths.unlockAndCommit();
}
bool Project::addGroup(const hecl::ProjectPath& path) {
m_groups.lockAndRead();
m_groups.addLine(path.getRelativePathUTF8());
m_groups.addLine(path.getRelativePath());
return m_groups.unlockAndCommit();
}
bool Project::removeGroup(const ProjectPath& path) {
m_groups.lockAndRead();
m_groups.removeLine(path.getRelativePathUTF8());
m_groups.removeLine(path.getRelativePath());
return m_groups.unlockAndCommit();
}
@@ -271,30 +262,26 @@ void Project::rescanDataSpecs() {
m_compiledSpecs.clear();
m_specs.lockAndRead();
for (const DataSpecEntry* spec : DATA_SPEC_REGISTRY) {
hecl::SystemString specStr(spec->m_name);
SystemUTF8Conv specUTF8(specStr);
m_compiledSpecs.push_back({*spec, ProjectPath(m_cookedRoot, hecl::SystemString(spec->m_name) + _SYS_STR(".spec")),
m_specs.checkForLine(specUTF8.str())});
m_compiledSpecs.push_back({*spec, ProjectPath(m_cookedRoot, std::string(spec->m_name) + ".spec"),
m_specs.checkForLine(spec->m_name)});
}
m_specs.unlockAndDiscard();
}
bool Project::enableDataSpecs(const std::vector<SystemString>& specs) {
bool Project::enableDataSpecs(const std::vector<std::string>& specs) {
m_specs.lockAndRead();
for (const SystemString& spec : specs) {
SystemUTF8Conv specView(spec);
m_specs.addLine(specView.str());
for (const std::string& spec : specs) {
m_specs.addLine(spec);
}
bool result = m_specs.unlockAndCommit();
rescanDataSpecs();
return result;
}
bool Project::disableDataSpecs(const std::vector<SystemString>& specs) {
bool Project::disableDataSpecs(const std::vector<std::string>& specs) {
m_specs.lockAndRead();
for (const SystemString& spec : specs) {
SystemUTF8Conv specView(spec);
m_specs.removeLine(specView.str());
for (const std::string& spec : specs) {
m_specs.removeLine(spec);
}
bool result = m_specs.unlockAndCommit();
rescanDataSpecs();
@@ -303,34 +290,34 @@ bool Project::disableDataSpecs(const std::vector<SystemString>& specs) {
class CookProgress {
const hecl::MultiProgressPrinter& m_progPrinter;
const SystemChar* m_dir = nullptr;
const SystemChar* m_file = nullptr;
const char* m_dir = nullptr;
const char* m_file = nullptr;
float m_prog = 0.f;
public:
CookProgress(const hecl::MultiProgressPrinter& progPrinter) : m_progPrinter(progPrinter) {}
void changeDir(const SystemChar* dir) {
void changeDir(const char* dir) {
m_dir = dir;
m_progPrinter.startNewLine();
}
void changeFile(const SystemChar* file, float prog) {
void changeFile(const char* file, float prog) {
m_file = file;
m_prog = prog;
}
void reportFile(const DataSpecEntry* specEnt) {
SystemString submsg(m_file);
submsg += _SYS_STR(" (");
std::string submsg(m_file);
submsg += " (";
submsg += specEnt->m_name.data();
submsg += _SYS_STR(')');
submsg += ')';
m_progPrinter.print(m_dir, submsg, m_prog);
}
void reportFile(const DataSpecEntry* specEnt, const SystemChar* extra) {
SystemString submsg(m_file);
submsg += _SYS_STR(" (");
void reportFile(const DataSpecEntry* specEnt, const char* extra) {
std::string submsg(m_file);
submsg += " (";
submsg += specEnt->m_name.data();
submsg += _SYS_STR(", ");
submsg += ", ";
submsg += extra;
submsg += _SYS_STR(')');
submsg += ')';
m_progPrinter.print(m_dir, submsg, m_prog);
}
void reportDirComplete() { m_progPrinter.print(m_dir, std::nullopt, 1.f); }
@@ -348,11 +335,11 @@ static void VisitFile(const ProjectPath& path, bool force, bool fast,
continue;
ProjectPath cooked = path.getCookedPath(*override);
if (fast)
cooked = cooked.getWithExtension(_SYS_STR(".fast"));
cooked = cooked.getWithExtension(".fast");
if (force || cooked.getPathType() == ProjectPath::Type::None || path.getModtime() > cooked.getModtime()) {
progress.reportFile(override);
spec->doCook(path, cooked, fast, hecl::blender::SharedBlenderToken,
[&](const SystemChar* extra) { progress.reportFile(override, extra); });
[&](const char* extra) { progress.reportFile(override, extra); });
}
}
}
@@ -362,17 +349,17 @@ static void VisitFile(const ProjectPath& path, bool force, bool fast,
static void VisitDirectory(const ProjectPath& dir, bool recursive, bool force, bool fast,
std::vector<std::unique_ptr<IDataSpec>>& specInsts, CookProgress& progress,
ClientProcess* cp) {
if (dir.getLastComponent().size() > 1 && dir.getLastComponent()[0] == _SYS_STR('.'))
if (dir.getLastComponent().size() > 1 && dir.getLastComponent()[0] == '.')
return;
if (hecl::ProjectPath(dir, _SYS_STR("!project.yaml")).isFile() &&
hecl::ProjectPath(dir, _SYS_STR("!pool.yaml")).isFile()) {
if (hecl::ProjectPath(dir, "!project.yaml").isFile() &&
hecl::ProjectPath(dir, "!pool.yaml").isFile()) {
/* Handle AudioGroup case */
VisitFile(dir, force, fast, specInsts, progress, cp);
return;
}
std::map<SystemString, ProjectPath> children;
std::map<std::string, ProjectPath> children;
dir.getDirChildren(children);
/* Pass 1: child file count */
@@ -458,7 +445,7 @@ bool Project::packagePath(const ProjectPath& path, const hecl::MultiProgressPrin
bool foundPC = false;
for (const ProjectDataSpec& projectSpec : m_compiledSpecs) {
if (projectSpec.active && projectSpec.spec.m_factory) {
if (hecl::StringUtils::EndsWith(projectSpec.spec.m_name, _SYS_STR("-PC"))) {
if (hecl::StringUtils::EndsWith(projectSpec.spec.m_name, "-PC")) {
foundPC = true;
specEntry = &projectSpec.spec;
} else if (!foundPC) {

View File

@@ -6,23 +6,23 @@
#include "hecl/FourCC.hpp"
namespace hecl {
static const SystemRegex regPATHCOMP(_SYS_STR("[/\\\\]*([^/\\\\]+)"), SystemRegex::ECMAScript | SystemRegex::optimize);
static const std::regex regPATHCOMP("[/\\\\]*([^/\\\\]+)", std::regex::ECMAScript | std::regex::optimize);
static SystemString CanonRelPath(SystemStringView path) {
static std::string CanonRelPath(std::string_view path) {
/* Tokenize Path */
std::vector<SystemString> comps;
hecl::SystemRegexMatch matches;
SystemString in(path);
std::vector<std::string> comps;
std::smatch matches;
std::string in(path);
SanitizePath(in);
for (; std::regex_search(in, matches, regPATHCOMP); in = matches.suffix().str()) {
hecl::SystemRegexMatch::const_reference match = matches[1];
if (match == _SYS_STR("."))
std::smatch::const_reference match = matches[1];
if (match == ".")
continue;
else if (match == _SYS_STR("..")) {
else if (match == "..") {
if (comps.empty()) {
/* Unable to resolve outside project */
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Unable to resolve outside project root in {}")), path);
return _SYS_STR(".");
LogModule.report(logvisor::Fatal, FMT_STRING("Unable to resolve outside project root in {}"), path);
return ".";
}
comps.pop_back();
continue;
@@ -33,78 +33,64 @@ static SystemString CanonRelPath(SystemStringView path) {
/* Emit relative path */
if (comps.size()) {
auto it = comps.begin();
SystemString retval = *it;
std::string retval = *it;
for (++it; it != comps.end(); ++it) {
if ((*it).size()) {
retval += _SYS_STR('/');
retval += '/';
retval += *it;
}
}
return retval;
}
return _SYS_STR(".");
return ".";
}
static SystemString CanonRelPath(SystemStringView path, const ProjectRootPath& projectRoot) {
static std::string CanonRelPath(std::string_view path, const ProjectRootPath& projectRoot) {
/* Absolute paths not allowed; attempt to make project-relative */
if (IsAbsolute(path))
return CanonRelPath(projectRoot.getProjectRelativeFromAbsolute(path));
return CanonRelPath(path);
}
void ProjectPath::assign(Database::Project& project, SystemStringView path) {
void ProjectPath::assign(Database::Project& project, std::string_view path) {
m_proj = &project;
SystemString usePath;
size_t pipeFind = path.rfind(_SYS_STR('|'));
if (pipeFind != SystemString::npos) {
std::string usePath;
size_t pipeFind = path.rfind('|');
if (pipeFind != std::string::npos) {
m_auxInfo.assign(path.cbegin() + pipeFind + 1, path.cend());
usePath.assign(path.cbegin(), path.cbegin() + pipeFind);
} else
usePath = path;
m_relPath = CanonRelPath(usePath, project.getProjectRootPath());
m_absPath = SystemString(project.getProjectRootPath().getAbsolutePath()) + _SYS_STR('/') + m_relPath;
m_absPath = std::string(project.getProjectRootPath().getAbsolutePath()) + '/' + m_relPath;
SanitizePath(m_relPath);
SanitizePath(m_absPath);
ComputeHash();
}
#if HECL_UCS2
void ProjectPath::assign(Database::Project& project, std::string_view path) {
std::wstring wpath = UTF8ToWide(path);
assign(project, wpath);
}
#endif
void ProjectPath::assign(const ProjectPath& parentPath, SystemStringView path) {
void ProjectPath::assign(const ProjectPath& parentPath, std::string_view path) {
m_proj = parentPath.m_proj;
SystemString usePath;
size_t pipeFind = path.rfind(_SYS_STR('|'));
if (pipeFind != SystemString::npos) {
std::string usePath;
size_t pipeFind = path.rfind('|');
if (pipeFind != std::string::npos) {
m_auxInfo.assign(path.cbegin() + pipeFind + 1, path.cend());
usePath.assign(path.cbegin(), path.cbegin() + pipeFind);
} else
usePath = path;
m_relPath = CanonRelPath(parentPath.m_relPath + _SYS_STR('/') + usePath);
m_absPath = SystemString(m_proj->getProjectRootPath().getAbsolutePath()) + _SYS_STR('/') + m_relPath;
m_relPath = CanonRelPath(parentPath.m_relPath + '/' + usePath);
m_absPath = std::string(m_proj->getProjectRootPath().getAbsolutePath()) + '/' + m_relPath;
SanitizePath(m_relPath);
SanitizePath(m_absPath);
ComputeHash();
}
#if HECL_UCS2
void ProjectPath::assign(const ProjectPath& parentPath, std::string_view path) {
std::wstring wpath = UTF8ToWide(path);
assign(parentPath, wpath);
}
#endif
ProjectPath ProjectPath::getWithExtension(const SystemChar* ext, bool replace) const {
ProjectPath ProjectPath::getWithExtension(const char* ext, bool replace) const {
ProjectPath pp(*this);
if (replace) {
auto relIt = pp.m_relPath.end();
@@ -113,11 +99,11 @@ ProjectPath ProjectPath::getWithExtension(const SystemChar* ext, bool replace) c
auto absIt = pp.m_absPath.end();
if (absIt != pp.m_absPath.begin())
--absIt;
while (relIt != pp.m_relPath.begin() && *relIt != _SYS_STR('.') && *relIt != _SYS_STR('/')) {
while (relIt != pp.m_relPath.begin() && *relIt != '.' && *relIt != '/') {
--relIt;
--absIt;
}
if (*relIt == _SYS_STR('.') && relIt != pp.m_relPath.begin()) {
if (*relIt == '.' && relIt != pp.m_relPath.begin()) {
pp.m_relPath.resize(relIt - pp.m_relPath.begin());
pp.m_absPath.resize(absIt - pp.m_absPath.begin());
}
@@ -136,7 +122,7 @@ ProjectPath ProjectPath::getCookedPath(const Database::DataSpecEntry& spec) cons
ProjectPath ret(m_proj->getProjectCookedPath(spec), woExt.getRelativePath());
if (getAuxInfo().size())
return ret.getWithExtension((SystemString(_SYS_STR(".")) + getAuxInfo().data()).c_str());
return ret.getWithExtension((std::string(".") + getAuxInfo().data()).c_str());
else
return ret;
}
@@ -144,7 +130,7 @@ ProjectPath ProjectPath::getCookedPath(const Database::DataSpecEntry& spec) cons
ProjectPath::Type ProjectPath::getPathType() const {
if (m_absPath.empty())
return Type::None;
if (m_absPath.find(_SYS_STR('*')) != SystemString::npos)
if (m_absPath.find('*') != std::string::npos)
return Type::Glob;
Sstat theStat;
if (hecl::Stat(m_absPath.c_str(), &theStat))
@@ -159,7 +145,7 @@ ProjectPath::Type ProjectPath::getPathType() const {
Time ProjectPath::getModtime() const {
Sstat theStat;
time_t latestTime = 0;
if (m_absPath.find(_SYS_STR('*')) != SystemString::npos) {
if (m_absPath.find('*') != std::string::npos) {
std::vector<ProjectPath> globResults;
getGlobResults(globResults);
for (ProjectPath& path : globResults) {
@@ -184,21 +170,21 @@ Time ProjectPath::getModtime() const {
return Time(latestTime);
}
}
LogModule.report(logvisor::Fatal, FMT_STRING(_SYS_STR("invalid path type for computing modtime in '{}'")), m_absPath);
LogModule.report(logvisor::Fatal, FMT_STRING("invalid path type for computing modtime in '{}'"), m_absPath);
return Time();
}
static void _recursiveGlob(Database::Project& proj, std::vector<ProjectPath>& outPaths, const SystemString& remPath,
const SystemString& itStr, bool needSlash) {
SystemRegexMatch matches;
static void _recursiveGlob(Database::Project& proj, std::vector<ProjectPath>& outPaths, const std::string& remPath,
const std::string& itStr, bool needSlash) {
std::smatch matches;
if (!std::regex_search(remPath, matches, regPATHCOMP))
return;
const SystemString& comp = matches[1];
if (comp.find(_SYS_STR('*')) == SystemString::npos) {
SystemString nextItStr = itStr;
const std::string& comp = matches[1];
if (comp.find('*') == std::string::npos) {
std::string nextItStr = itStr;
if (needSlash)
nextItStr += _SYS_STR('/');
nextItStr += '/';
nextItStr += comp;
hecl::Sstat theStat;
@@ -213,12 +199,12 @@ static void _recursiveGlob(Database::Project& proj, std::vector<ProjectPath>& ou
}
/* Compile component into regex */
SystemRegex regComp(comp, SystemRegex::ECMAScript);
std::regex regComp(comp, std::regex::ECMAScript);
hecl::DirectoryEnumerator de(itStr, hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
for (const hecl::DirectoryEnumerator::Entry& ent : de) {
if (std::regex_match(ent.m_name, regComp)) {
SystemString nextItStr = itStr;
std::string nextItStr = itStr;
if (needSlash)
nextItStr += '/';
nextItStr += ent.m_name;
@@ -235,7 +221,7 @@ static void _recursiveGlob(Database::Project& proj, std::vector<ProjectPath>& ou
}
}
void ProjectPath::getDirChildren(std::map<SystemString, ProjectPath>& outPaths) const {
void ProjectPath::getDirChildren(std::map<std::string, ProjectPath>& outPaths) const {
hecl::DirectoryEnumerator de(m_absPath, hecl::DirectoryEnumerator::Mode::DirsThenFilesSorted, false, false, true);
for (const hecl::DirectoryEnumerator::Entry& ent : de)
outPaths[ent.m_name] = ProjectPath(*this, ent.m_name);
@@ -247,7 +233,7 @@ hecl::DirectoryEnumerator ProjectPath::enumerateDir() const {
void ProjectPath::getGlobResults(std::vector<ProjectPath>& outPaths) const {
auto rootPath = m_proj->getProjectRootPath().getAbsolutePath();
_recursiveGlob(*m_proj, outPaths, m_relPath, rootPath.data(), rootPath.back() != _SYS_STR('/'));
_recursiveGlob(*m_proj, outPaths, m_relPath, rootPath.data(), rootPath.back() != '/');
}
template <typename T>
@@ -265,18 +251,18 @@ static bool RegexSearchLast(const T& str, std::match_results<typename T::const_i
return true;
}
static const hecl::SystemRegex regParsedHash32(_SYS_STR(R"(_([0-9a-fA-F]{8}))"),
static const std::regex regParsedHash32(R"(_([0-9a-fA-F]{8}))",
std::regex::ECMAScript | std::regex::optimize);
uint32_t ProjectPath::parsedHash32() const {
if (!m_auxInfo.empty()) {
hecl::SystemRegexMatch match;
std::smatch match;
if (RegexSearchLast(m_auxInfo, match, regParsedHash32)) {
auto hexStr = match[1].str();
if (auto val = hecl::StrToUl(hexStr.c_str(), nullptr, 16))
return val;
}
} else {
hecl::SystemViewRegexMatch match;
std::match_results<std::string_view::const_iterator> match;
if (RegexSearchLast(getLastComponent(), match, regParsedHash32)) {
auto hexStr = match[1].str();
if (auto val = hecl::StrToUl(hexStr.c_str(), nullptr, 16))
@@ -286,17 +272,17 @@ uint32_t ProjectPath::parsedHash32() const {
return hash().val32();
}
ProjectRootPath SearchForProject(SystemStringView path) {
ProjectRootPath SearchForProject(std::string_view path) {
ProjectRootPath testRoot(path);
auto begin = testRoot.getAbsolutePath().begin();
auto end = testRoot.getAbsolutePath().end();
while (begin != end) {
SystemString testPath(begin, end);
SystemString testIndexPath = testPath + _SYS_STR("/.hecl/beacon");
std::string testPath(begin, end);
std::string testIndexPath = testPath + "/.hecl/beacon";
Sstat theStat;
if (!hecl::Stat(testIndexPath.c_str(), &theStat)) {
if (S_ISREG(theStat.st_mode)) {
const auto fp = hecl::FopenUnique(testIndexPath.c_str(), _SYS_STR("rb"));
const auto fp = hecl::FopenUnique(testIndexPath.c_str(), "rb");
if (fp == nullptr) {
continue;
}
@@ -316,7 +302,7 @@ ProjectRootPath SearchForProject(SystemStringView path) {
}
}
while (begin != end && *(end - 1) != _SYS_STR('/') && *(end - 1) != _SYS_STR('\\'))
while (begin != end && *(end - 1) != '/' && *(end - 1) != '\\')
--end;
if (begin != end)
--end;
@@ -324,19 +310,19 @@ ProjectRootPath SearchForProject(SystemStringView path) {
return ProjectRootPath();
}
ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut) {
ProjectRootPath SearchForProject(std::string_view path, std::string& subpathOut) {
const ProjectRootPath testRoot(path);
auto begin = testRoot.getAbsolutePath().begin();
auto end = testRoot.getAbsolutePath().end();
while (begin != end) {
SystemString testPath(begin, end);
SystemString testIndexPath = testPath + _SYS_STR("/.hecl/beacon");
std::string testPath(begin, end);
std::string testIndexPath = testPath + "/.hecl/beacon";
Sstat theStat;
if (!hecl::Stat(testIndexPath.c_str(), &theStat)) {
if (S_ISREG(theStat.st_mode)) {
const auto fp = hecl::FopenUnique(testIndexPath.c_str(), _SYS_STR("rb"));
const auto fp = hecl::FopenUnique(testIndexPath.c_str(), "rb");
if (fp == nullptr) {
continue;
}
@@ -352,10 +338,10 @@ ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut
const ProjectRootPath newRootPath = ProjectRootPath(testPath);
const auto origEnd = testRoot.getAbsolutePath().end();
while (end != origEnd && *end != _SYS_STR('/') && *end != _SYS_STR('\\')) {
while (end != origEnd && *end != '/' && *end != '\\') {
++end;
}
if (end != origEnd && (*end == _SYS_STR('/') || *end == _SYS_STR('\\'))) {
if (end != origEnd && (*end == '/' || *end == '\\')) {
++end;
}
@@ -364,7 +350,7 @@ ProjectRootPath SearchForProject(SystemStringView path, SystemString& subpathOut
}
}
while (begin != end && *(end - 1) != _SYS_STR('/') && *(end - 1) != _SYS_STR('\\')) {
while (begin != end && *(end - 1) != '/' && *(end - 1) != '\\') {
--end;
}
if (begin != end) {

View File

@@ -15,22 +15,22 @@ using namespace Windows::Storage;
namespace hecl::Runtime {
static logvisor::Module Log("FileStoreManager");
FileStoreManager::FileStoreManager(SystemStringView domain) : m_domain(domain) {
FileStoreManager::FileStoreManager(std::string_view domain) : m_domain(domain) {
#if _WIN32
#if !WINDOWS_STORE
WCHAR home[MAX_PATH];
if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, home)))
Log.report(logvisor::Fatal, FMT_STRING(_SYS_STR("unable to locate profile for file store")));
Log.report(logvisor::Fatal, FMT_STRING("unable to locate profile for file store"));
SystemString path(home);
std::string path = nowide::narrow(home);
#else
StorageFolder ^ cacheFolder = ApplicationData::Current->LocalCacheFolder;
SystemString path(cacheFolder->Path->Data());
std::string path(cacheFolder->Path->Data());
#endif
path += _SYS_STR("/.heclrun");
path += "/.heclrun";
hecl::MakeDir(path.c_str());
path += _SYS_STR('/');
path += '/';
path += domain.data();
hecl::MakeDir(path.c_str());

View File

@@ -2,7 +2,7 @@
#include "hecl/hecl.hpp"
#ifdef WIN32
#include <winreg.h>
#define PATH_SEP L'\\'
#define PATH_SEP '\\'
#else
#define PATH_SEP '/'
#endif
@@ -12,25 +12,25 @@ namespace hecl {
/* Used to extract alternate steam install directories from libraryfolders.vdf */
static const std::regex regSteamPath(R"(^\s+\"[0-9]+\"\s+\"(.*)\")", std::regex::ECMAScript | std::regex::optimize);
hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name) {
hecl::SystemString steamInstallDir;
std::string FindCommonSteamApp(const char* name) {
std::string steamInstallDir;
hecl::Sstat theStat;
#ifdef WIN32
#if !WINDOWS_STORE
HKEY hkey;
hecl::SystemChar _steamInstallDir[MAX_PATH] = {0};
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _SYS_STR("Software\\Valve\\Steam"), 0, KEY_QUERY_VALUE, &hkey) !=
wchar_t _steamInstallDir[MAX_PATH] = {0};
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Valve\\Steam", 0, KEY_QUERY_VALUE, &hkey) !=
ERROR_SUCCESS) {
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _SYS_STR("Software\\Valve\\Steam"), 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY,
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Valve\\Steam", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY,
&hkey) != ERROR_SUCCESS)
return {};
}
DWORD size = MAX_PATH;
if (RegQueryValueEx(hkey, _SYS_STR("InstallPath"), nullptr, nullptr, (LPBYTE)_steamInstallDir, &size) ==
if (RegQueryValueEx(hkey, L"InstallPath", nullptr, nullptr, (LPBYTE)_steamInstallDir, &size) ==
ERROR_SUCCESS)
steamInstallDir = _steamInstallDir;
steamInstallDir = nowide::narrow(_steamInstallDir);
RegCloseKey(hkey);
if (steamInstallDir.empty())
@@ -57,18 +57,18 @@ hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name) {
#endif
const hecl::SystemString appPath = hecl::SystemString(_SYS_STR("common")) + PATH_SEP + name;
const std::string appPath = std::string("common") + PATH_SEP + name;
/* Try main steam install directory first */
const hecl::SystemString steamAppsMain = steamInstallDir + PATH_SEP + _SYS_STR("steamapps");
const hecl::SystemString mainAppPath = steamAppsMain + PATH_SEP + appPath;
const std::string steamAppsMain = steamInstallDir + PATH_SEP + "steamapps";
const std::string mainAppPath = steamAppsMain + PATH_SEP + appPath;
if (!hecl::Stat(mainAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode)) {
return mainAppPath;
}
/* Iterate alternate steam install dirs */
const hecl::SystemString libraryFoldersVdfPath = steamAppsMain + PATH_SEP + _SYS_STR("libraryfolders.vdf");
auto fp = hecl::FopenUnique(libraryFoldersVdfPath.c_str(), _SYS_STR("r"));
const std::string libraryFoldersVdfPath = steamAppsMain + PATH_SEP + "libraryfolders.vdf";
auto fp = hecl::FopenUnique(libraryFoldersVdfPath.c_str(), "r");
if (fp == nullptr) {
return {};
}
@@ -88,9 +88,8 @@ hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name) {
const auto end = fileBuf.cend();
while (std::regex_search(begin, end, dirMatch, regSteamPath)) {
const std::string match = dirMatch[1].str();
const hecl::SystemStringConv otherInstallDir(match);
const auto otherAppPath =
hecl::SystemString(otherInstallDir.sys_str()) + PATH_SEP + _SYS_STR("steamapps") + PATH_SEP + appPath;
std::string(match.c_str()) + PATH_SEP + "steamapps" + PATH_SEP + appPath;
if (!hecl::Stat(otherAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode)) {
return otherAppPath;

View File

@@ -4,21 +4,6 @@
namespace hecl {
static logvisor::Module Log("hecl-wsconv");
std::string WideToUTF8(std::wstring_view src) {
std::string retval;
retval.reserve(src.length());
for (wchar_t ch : src) {
utf8proc_uint8_t mb[4];
utf8proc_ssize_t c = utf8proc_encode_char(utf8proc_int32_t(ch), mb);
if (c < 0) {
Log.report(logvisor::Warning, FMT_STRING("invalid UTF-8 character while encoding"));
return retval;
}
retval.append(reinterpret_cast<char*>(mb), c);
}
return retval;
}
std::string Char16ToUTF8(std::u16string_view src) {
std::string retval;
retval.reserve(src.length());
@@ -34,23 +19,6 @@ std::string Char16ToUTF8(std::u16string_view src) {
return retval;
}
std::wstring UTF8ToWide(std::string_view src) {
std::wstring retval;
retval.reserve(src.length());
const utf8proc_uint8_t* buf = reinterpret_cast<const utf8proc_uint8_t*>(src.data());
while (*buf) {
utf8proc_int32_t wc;
utf8proc_ssize_t len = utf8proc_iterate(buf, -1, &wc);
if (len < 0) {
Log.report(logvisor::Warning, FMT_STRING("invalid UTF-8 character while decoding"));
return retval;
}
buf += len;
retval += wchar_t(wc);
}
return retval;
}
std::u16string UTF8ToChar16(std::string_view src) {
std::u16string retval;
retval.reserve(src.length());

View File

@@ -28,6 +28,7 @@
#include <sys/wait.h>
#endif
#include <ranges>
#include <logvisor/logvisor.hpp>
using namespace std::literals;
@@ -66,44 +67,14 @@ void SanitizePath(std::string& path) {
path.pop_back();
}
constexpr std::wstring_view WIllegals = L"<>?\""sv;
void SanitizePath(std::wstring& path) {
if (path.empty())
return;
path.erase(std::remove(path.begin(), path.end(), L'\n'), path.end());
path.erase(std::remove(path.begin(), path.end(), L'\r'), path.end());
std::wstring::iterator p1 = path.begin();
bool ic = false;
std::transform(path.begin(), path.end(), path.begin(), [&](const wchar_t a) -> wchar_t {
++p1;
if (WIllegals.find_first_of(a) != std::wstring::npos) {
ic = false;
return L'_';
}
if (ic) {
ic = false;
return a;
}
if (a == L'\\' && (p1 == path.end() || *p1 != L'\\')) {
ic = true;
return L'/';
}
return a;
});
while (path.back() == L'/')
path.pop_back();
}
SystemString GetcwdStr() {
std::string GetcwdStr() {
/* http://stackoverflow.com/a/2869667 */
// const size_t ChunkSize=255;
// const int MaxChunks=10240; // 2550 KiBs of current path are more than enough
SystemChar stackBuffer[255]; // Stack buffer for the "normal" case
char stackBuffer[255]; // Stack buffer for the "normal" case
if (Getcwd(stackBuffer, int(std::size(stackBuffer))) != nullptr) {
return SystemString(stackBuffer);
return std::string(stackBuffer);
}
if (errno != ERANGE) {
// It's not ERANGE, so we don't know how to handle it
@@ -115,9 +86,9 @@ SystemString GetcwdStr() {
// With boost use scoped_ptr; in C++0x, use unique_ptr
// If you want to be less C++ but more efficient you may want to use realloc
const int bufSize = 255 * chunks;
std::unique_ptr<SystemChar[]> cwd(new SystemChar[bufSize]);
std::unique_ptr<char[]> cwd(new char[bufSize]);
if (Getcwd(cwd.get(), bufSize) != nullptr) {
return SystemString(cwd.get());
return std::string(cwd.get());
}
if (errno != ERANGE) {
// It's not ERANGE, so we don't know how to handle it
@@ -125,8 +96,9 @@ SystemString GetcwdStr() {
// Of course you may choose a different error reporting method
}
}
LogModule.report(logvisor::Fatal, FMT_STRING("Cannot determine the current path; the path is apparently unreasonably long"));
return SystemString();
LogModule.report(logvisor::Fatal,
FMT_STRING("Cannot determine the current path; the path is apparently unreasonably long"));
return std::string();
}
static std::mutex PathsMutex;
@@ -160,7 +132,7 @@ void ResourceLock::ClearThreadRes() {
}
bool IsPathPNG(const hecl::ProjectPath& path) {
const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), _SYS_STR("rb"));
const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), "rb");
if (fp == nullptr) {
return false;
}
@@ -176,10 +148,10 @@ bool IsPathPNG(const hecl::ProjectPath& path) {
bool IsPathBlend(const hecl::ProjectPath& path) {
const auto lastCompExt = path.getLastComponentExt();
if (lastCompExt.empty() || lastCompExt != _SYS_STR("blend"))
if (lastCompExt.empty() || lastCompExt != "blend")
return false;
const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), _SYS_STR("rb"));
const auto fp = hecl::FopenUnique(path.getAbsolutePath().data(), "rb");
if (fp == nullptr) {
return false;
}
@@ -195,132 +167,162 @@ bool IsPathBlend(const hecl::ProjectPath& path) {
bool IsPathYAML(const hecl::ProjectPath& path) {
auto lastComp = path.getLastComponent();
if (lastComp == _SYS_STR("!catalog.yaml") ||
lastComp == _SYS_STR("!memoryid.yaml") ||
lastComp == _SYS_STR("!memoryrelays.yaml"))
if (lastComp == "!catalog.yaml" || lastComp == "!memoryid.yaml" || lastComp == "!memoryrelays.yaml")
return false; /* !catalog.yaml, !memoryid.yaml, !memoryrelays.yaml are exempt from general use */
auto lastCompExt = path.getLastComponentExt();
if (lastCompExt.empty())
return false;
return lastCompExt == _SYS_STR("yaml") || lastCompExt == _SYS_STR("yml");
return lastCompExt == "yaml" || lastCompExt == "yml";
}
hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool sizeSort, bool reverse,
hecl::DirectoryEnumerator::DirectoryEnumerator(std::string_view path, Mode mode, bool sizeSort, bool reverse,
bool noHidden) {
hecl::Sstat theStat;
if (hecl::Stat(path.data(), &theStat) || !S_ISDIR(theStat.st_mode))
Sstat theStat;
if (Stat(path.data(), &theStat) || !S_ISDIR(theStat.st_mode)) {
return;
}
#if _WIN32
hecl::SystemString wc(path);
wc += _SYS_STR("/*");
std::wstring wc = nowide::widen(path);
wc += L"/*";
WIN32_FIND_DATAW d;
HANDLE dir = FindFirstFileW(wc.c_str(), &d);
if (dir == INVALID_HANDLE_VALUE)
if (dir == INVALID_HANDLE_VALUE) {
return;
}
switch (mode) {
case Mode::Native:
do {
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
}
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) {
continue;
hecl::SystemString fp(path);
fp += _SYS_STR('/');
fp += d.cFileName;
hecl::Sstat st;
if (hecl::Stat(fp.c_str(), &st))
}
std::string fileName = nowide::narrow(d.cFileName);
std::string fp(path);
fp += '/';
fp += fileName;
Sstat st;
if (Stat(fp.c_str(), &st))
continue;
size_t sz = 0;
bool isDir = false;
if (S_ISDIR(st.st_mode))
if (S_ISDIR(st.st_mode)) {
isDir = true;
else if (S_ISREG(st.st_mode))
} else if (S_ISREG(st.st_mode)) {
sz = st.st_size;
else
} else {
continue;
}
m_entries.emplace_back(fp, d.cFileName, sz, isDir);
m_entries.emplace_back(fp, fileName, sz, isDir);
} while (FindNextFileW(dir, &d));
break;
case Mode::DirsThenFilesSorted:
case Mode::DirsSorted: {
std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort;
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
do {
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
}
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) {
continue;
hecl::SystemString fp(path);
fp += _SYS_STR('/');
fp += d.cFileName;
hecl::Sstat st;
if (hecl::Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
}
std::string fileName = nowide::narrow(d.cFileName);
std::string fp(path);
fp += '/';
fp += fileName;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode)) {
continue;
sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, 0, true)));
}
sort.emplace(fileName, Entry{fp, fileName, 0, true});
} while (FindNextFileW(dir, &d));
if (reverse)
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
m_entries.reserve(sort.size());
if (reverse) {
for (auto& it : std::ranges::reverse_view(sort)) {
m_entries.emplace_back(std::move(it.second));
}
} else {
for (auto& e : sort) {
m_entries.emplace_back(std::move(e.second));
}
}
if (mode == Mode::DirsSorted)
if (mode == Mode::DirsSorted) {
break;
}
FindClose(dir);
dir = FindFirstFileW(wc.c_str(), &d);
}
case Mode::FilesSorted: {
if (mode == Mode::FilesSorted)
if (mode == Mode::FilesSorted) {
m_entries.clear();
}
if (sizeSort) {
std::multimap<size_t, Entry> sort;
do {
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
}
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) {
continue;
hecl::SystemString fp(path);
fp += _SYS_STR('/');
fp += d.cFileName;
hecl::Sstat st;
if (hecl::Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
}
std::string fileName = nowide::narrow(d.cFileName);
std::string fp(path);
fp += '/';
fp += fileName;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode)) {
continue;
sort.emplace(std::make_pair(st.st_size, Entry(std::move(fp), d.cFileName, st.st_size, false)));
}
sort.emplace(st.st_size, Entry{fp, fileName, static_cast<size_t>(st.st_size), false});
} while (FindNextFileW(dir, &d));
if (reverse)
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
m_entries.reserve(m_entries.size() + sort.size());
if (reverse) {
for (auto& it : std::ranges::reverse_view(sort)) {
m_entries.emplace_back(std::move(it.second));
}
} else {
for (auto& e : sort) {
m_entries.emplace_back(std::move(e.second));
}
}
} else {
std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort;
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
do {
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
if (!wcscmp(d.cFileName, L".") || !wcscmp(d.cFileName, L"..")) {
continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
}
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) {
continue;
hecl::SystemString fp(path);
fp += _SYS_STR('/');
fp += d.cFileName;
hecl::Sstat st;
if (hecl::Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
}
std::string fileName = nowide::narrow(d.cFileName);
std::string fp(path);
fp += '/';
fp += fileName;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode)) {
continue;
sort.emplace(std::make_pair(d.cFileName, Entry(std::move(fp), d.cFileName, st.st_size, false)));
}
sort.emplace(fileName, Entry{fp, fileName, static_cast<size_t>(st.st_size), false});
} while (FindNextFileW(dir, &d));
if (reverse)
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
m_entries.reserve(m_entries.size() + sort.size());
if (reverse) {
for (auto& e : std::ranges::reverse_view(sort)) {
m_entries.emplace_back(std::move(e.second));
}
} else {
for (auto& e : sort) {
m_entries.emplace_back(std::move(e.second));
}
}
}
break;
@@ -341,7 +343,7 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
continue;
if (noHidden && d->d_name[0] == '.')
continue;
hecl::SystemString fp(path);
std::string fp(path);
fp += '/';
fp += d->d_name;
hecl::Sstat st;
@@ -362,13 +364,13 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
break;
case Mode::DirsThenFilesSorted:
case Mode::DirsSorted: {
std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort;
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
while ((d = readdir(dir))) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
if (noHidden && d->d_name[0] == '.')
continue;
hecl::SystemString fp(path);
std::string fp(path);
fp += '/';
fp += d->d_name;
hecl::Sstat st;
@@ -400,7 +402,7 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
continue;
if (noHidden && d->d_name[0] == '.')
continue;
hecl::SystemString fp(path);
std::string fp(path);
fp += '/';
fp += d->d_name;
hecl::Sstat st;
@@ -416,13 +418,13 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
} else {
std::map<hecl::SystemString, Entry, CaseInsensitiveCompare> sort;
std::map<std::string, Entry, CaseInsensitiveCompare> sort;
while ((d = readdir(dir))) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
if (noHidden && d->d_name[0] == '.')
continue;
hecl::SystemString fp(path);
std::string fp(path);
fp += '/';
fp += d->d_name;
hecl::Sstat st;
@@ -447,159 +449,24 @@ hecl::DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode,
#endif
}
static std::pair<hecl::SystemString, std::string> NameFromPath(hecl::SystemStringView path) {
hecl::SystemUTF8Conv utf8(path);
if (utf8.str().size() == 1 && utf8.str()[0] == '/')
return {hecl::SystemString(path), "/"};
size_t lastSlash = utf8.str().rfind('/');
static std::pair<std::string, std::string> NameFromPath(std::string_view path) {
if (path.size() == 1 && path[0] == '/')
return {std::string(path), "/"};
size_t lastSlash = path.rfind('/');
if (lastSlash != std::string::npos)
return {hecl::SystemString(path), std::string(utf8.str().cbegin() + lastSlash + 1, utf8.str().cend())};
return {std::string(path), std::string(path.cbegin() + lastSlash + 1, path.cend())};
else
return {hecl::SystemString(path), std::string(utf8.str())};
return {std::string(path), std::string(path)};
}
std::vector<std::pair<hecl::SystemString, std::string>> GetSystemLocations() {
std::vector<std::pair<hecl::SystemString, std::string>> ret;
#ifdef WIN32
#if !WINDOWS_STORE
/* Add the drive names to the listing (as queried by blender) */
{
constexpr uint32_t FILE_MAXDIR = 768;
wchar_t wline[FILE_MAXDIR];
const uint32_t tmp = GetLogicalDrives();
for (uint32_t i = 0; i < 26; i++) {
if ((tmp >> i) & 1) {
wline[0] = L'A' + i;
wline[1] = L':';
wline[2] = L'/';
wline[3] = L'\0';
wchar_t* name = nullptr;
/* Flee from horrible win querying hover floppy drives! */
if (i > 1) {
/* Try to get volume label as well... */
if (GetVolumeInformationW(wline, wline + 4, FILE_MAXDIR - 4, nullptr, nullptr, nullptr, nullptr, 0)) {
const size_t labelLen = std::wcslen(wline + 4);
_snwprintf(wline + 4 + labelLen, FILE_MAXDIR - 4 - labelLen, L" (%.2s)", wline);
name = wline + 4;
}
}
wline[2] = L'\0';
if (name == nullptr) {
ret.push_back(NameFromPath(wline));
} else {
ret.emplace_back(wline, hecl::WideToUTF8(name));
}
}
}
/* Adding Desktop and My Documents */
SystemString wpath;
SHGetSpecialFolderPathW(nullptr, wline, CSIDL_PERSONAL, 0);
wpath.assign(wline);
SanitizePath(wpath);
ret.push_back(NameFromPath(wpath));
SHGetSpecialFolderPathW(nullptr, wline, CSIDL_DESKTOPDIRECTORY, 0);
wpath.assign(wline);
SanitizePath(wpath);
ret.push_back(NameFromPath(wpath));
}
#endif
#else
#ifdef __APPLE__
{
hecl::Sstat theStat;
const char* home = getenv("HOME");
if (home) {
ret.push_back(NameFromPath(home));
std::string desktop(home);
desktop += "/Desktop";
if (!hecl::Stat(desktop.c_str(), &theStat))
ret.push_back(NameFromPath(desktop));
}
/* Get mounted volumes better method OSX 10.6 and higher, see: */
/*https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html*/
/* we get all volumes sorted including network and do not relay on user-defined finder visibility, less confusing */
CFURLRef cfURL = nullptr;
CFURLEnumeratorResult result = kCFURLEnumeratorSuccess;
CFURLEnumeratorRef volEnum =
CFURLEnumeratorCreateForMountedVolumes(nullptr, kCFURLEnumeratorSkipInvisibles, nullptr);
while (result != kCFURLEnumeratorEnd) {
char defPath[1024];
result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, nullptr);
if (result != kCFURLEnumeratorSuccess) {
continue;
}
CFURLGetFileSystemRepresentation(cfURL, false, reinterpret_cast<UInt8*>(defPath), std::size(defPath));
ret.push_back(NameFromPath(defPath));
}
CFRelease(volEnum);
}
#else
/* unix */
{
hecl::Sstat theStat;
const char* home = getenv("HOME");
if (home) {
ret.push_back(NameFromPath(home));
std::string desktop(home);
desktop += "/Desktop";
if (!hecl::Stat(desktop.c_str(), &theStat))
ret.push_back(NameFromPath(desktop));
}
{
bool found = false;
#ifdef __linux__
/* Loop over mount points */
struct mntent* mnt;
FILE* fp = setmntent(MOUNTED, "r");
if (fp) {
while ((mnt = getmntent(fp))) {
if (strlen(mnt->mnt_fsname) < 4 || strncmp(mnt->mnt_fsname, "/dev", 4))
continue;
std::string mntStr(mnt->mnt_dir);
if (mntStr.size() > 1 && mntStr.back() == '/')
mntStr.pop_back();
ret.push_back(NameFromPath(mntStr));
found = true;
}
endmntent(fp);
}
#endif
/* Fallback */
if (!found)
ret.push_back(NameFromPath("/"));
}
}
#endif
#endif
return ret;
}
std::wstring Char16ToWide(std::u16string_view src) { return std::wstring(src.begin(), src.end()); }
/* recursive mkdir */
#if _WIN32
int RecursiveMakeDir(const SystemChar* dir) {
SystemChar tmp[1024];
int RecursiveMakeDir(const char* dir) {
char tmp[1024];
/* copy path */
std::wcsncpy(tmp, dir, std::size(tmp));
const size_t len = std::wcslen(tmp);
std::strncpy(tmp, dir, std::size(tmp));
const size_t len = std::strlen(tmp);
if (len >= std::size(tmp)) {
return -1;
}
@@ -610,7 +477,7 @@ int RecursiveMakeDir(const SystemChar* dir) {
}
/* recursive mkdir */
SystemChar* p = nullptr;
char* p = nullptr;
Sstat sb;
for (p = tmp + 1; *p; p++) {
if (*p == '/' || *p == '\\') {
@@ -618,7 +485,8 @@ int RecursiveMakeDir(const SystemChar* dir) {
/* test path */
if (Stat(tmp, &sb) != 0) {
/* path does not exist - create directory */
if (!CreateDirectoryW(tmp, nullptr)) {
const nowide::wstackstring wtmp(tmp);
if (!CreateDirectoryW(wtmp.get(), nullptr)) {
return -1;
}
} else if (!S_ISDIR(sb.st_mode)) {
@@ -631,7 +499,8 @@ int RecursiveMakeDir(const SystemChar* dir) {
/* test path */
if (Stat(tmp, &sb) != 0) {
/* path does not exist - create directory */
if (!CreateDirectoryW(tmp, nullptr)) {
const nowide::wstackstring wtmp(tmp);
if (!CreateDirectoryW(wtmp.get(), nullptr)) {
return -1;
}
} else if (!S_ISDIR(sb.st_mode)) {
@@ -641,8 +510,8 @@ int RecursiveMakeDir(const SystemChar* dir) {
return 0;
}
#else
int RecursiveMakeDir(const SystemChar* dir) {
SystemChar tmp[1024];
int RecursiveMakeDir(const char* dir) {
char tmp[1024];
/* copy path */
std::memset(tmp, 0, std::size(tmp));
@@ -658,7 +527,7 @@ int RecursiveMakeDir(const SystemChar* dir) {
}
/* recursive mkdir */
SystemChar* p = nullptr;
char* p = nullptr;
Sstat sb;
for (p = tmp + 1; *p; p++) {
if (*p == '/') {
@@ -690,25 +559,27 @@ int RecursiveMakeDir(const SystemChar* dir) {
}
#endif
const SystemChar* GetTmpDir() {
std::string GetTmpDir() {
#ifdef _WIN32
#if WINDOWS_STORE
const wchar_t* TMPDIR = nullptr;
#else
const wchar_t* TMPDIR = _wgetenv(L"TEMP");
if (!TMPDIR)
TMPDIR = L"\\Temp";
auto TMPDIR = GetEnv("TEMP");
if (!TMPDIR) {
return "\\Temp";
}
return std::move(TMPDIR.value());
#endif
#else
const char* TMPDIR = getenv("TMPDIR");
if (!TMPDIR)
TMPDIR = "/tmp";
#endif
return TMPDIR;
#endif
}
#if !WINDOWS_STORE
int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
int RunProcess(const char* path, const char* const args[]) {
#ifdef _WIN32
SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE};
HANDLE consoleOutReadTmp = INVALID_HANDLE_VALUE;
@@ -741,12 +612,12 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
CloseHandle(consoleOutReadTmp);
hecl::SystemString cmdLine;
const SystemChar* const* arg = &args[1];
std::wstring cmdLine;
const char* const* arg = &args[1];
while (*arg) {
cmdLine += _SYS_STR(" \"");
cmdLine += *arg++;
cmdLine += _SYS_STR('"');
cmdLine += L" \"";
cmdLine += nowide::widen(*arg++);
cmdLine += L'"';
}
STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
@@ -758,12 +629,14 @@ int RunProcess(const SystemChar* path, const SystemChar* const args[]) {
sinfo.hStdOutput = consoleOutWrite;
PROCESS_INFORMATION pinfo = {};
if (!CreateProcessW(path, cmdLine.data(), nullptr, nullptr, TRUE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &sinfo,
&pinfo)) {
const nowide::wstackstring wpath(path);
if (!CreateProcessW(wpath.get(), cmdLine.data(), nullptr, nullptr, TRUE, NORMAL_PRIORITY_CLASS, nullptr, nullptr,
&sinfo, &pinfo)) {
LPWSTR messageBuffer = nullptr;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
LogModule.report(logvisor::Error, FMT_STRING(L"unable to launch process from {}: {}"), path, messageBuffer);
LogModule.report(logvisor::Error, FMT_STRING("unable to launch process from {}: {}"), path,
nowide::narrow(messageBuffer));
LocalFree(messageBuffer);
CloseHandle(nulHandle);

View File

@@ -4,6 +4,7 @@
#include "glslang/Public/ShaderLang.h"
#include "hecl/hecl.hpp"
#include <sstream>
#include <nowide/args.hpp>
static logvisor::Module Log("shaderc");
@@ -32,12 +33,12 @@ static bool FindBestD3DCompile() {
}
return false;
}
int wmain(int argc, const hecl::SystemChar** argv)
#else
int main(int argc, const hecl::SystemChar** argv)
#endif
{
int main(int argc, char** argv) {
#if _WIN32
nowide::args _(argc, argv);
#endif
logvisor::RegisterConsoleLogger();
logvisor::RegisterStandardExceptions();
@@ -53,7 +54,7 @@ int main(int argc, const hecl::SystemChar** argv)
return 0;
}
hecl::SystemString outPath;
std::string outPath;
hecl::shaderc::Compiler c;
for (int i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
@@ -68,7 +69,7 @@ int main(int argc, const hecl::SystemChar** argv)
return 1;
}
} else if (argv[i][1] == 'D') {
const hecl::SystemChar* define;
const char* define;
if (argv[i][2]) {
define = &argv[i][2];
} else if (i + 1 < argc) {
@@ -78,14 +79,12 @@ int main(int argc, const hecl::SystemChar** argv)
Log.report(logvisor::Error, FMT_STRING("Invalid -D argument"));
return 1;
}
hecl::SystemUTF8Conv conv(define);
const char* defineU8 = conv.c_str();
if (const char* equals = strchr(defineU8, '='))
c.addDefine(std::string(defineU8, equals - defineU8), equals + 1);
if (const char* equals = strchr(define, '='))
c.addDefine(std::string(define, equals - define), equals + 1);
else
c.addDefine(defineU8, "");
c.addDefine(define, "");
} else {
Log.report(logvisor::Error, FMT_STRING(_SYS_STR("Unrecognized flag option '{:c}'")), argv[i][1]);
Log.report(logvisor::Error, FMT_STRING("Unrecognized flag option '{:c}'"), argv[i][1]);
return 1;
}
} else {
@@ -98,9 +97,9 @@ int main(int argc, const hecl::SystemChar** argv)
return 1;
}
hecl::SystemStringView baseName;
auto slashPos = outPath.find_last_of(_SYS_STR("/\\"));
if (slashPos != hecl::SystemString::npos)
std::string_view baseName;
auto slashPos = outPath.find_last_of("/\\");
if (slashPos != std::string::npos)
baseName = outPath.data() + slashPos + 1;
else
baseName = outPath;
@@ -110,16 +109,15 @@ int main(int argc, const hecl::SystemChar** argv)
return 1;
}
hecl::SystemUTF8Conv conv(baseName);
std::pair<std::stringstream, std::stringstream> ret;
if (!c.compile(conv.str(), ret))
if (!c.compile(baseName, ret))
return 1;
{
hecl::SystemString headerPath = outPath + _SYS_STR(".hpp");
std::string headerPath = outPath + ".hpp";
athena::io::FileWriter w(headerPath);
if (w.hasError()) {
Log.report(logvisor::Error, FMT_STRING(_SYS_STR("Error opening '{}' for writing")), headerPath);
Log.report(logvisor::Error, FMT_STRING("Error opening '{}' for writing"), headerPath);
return 1;
}
std::string header = ret.first.str();
@@ -127,10 +125,10 @@ int main(int argc, const hecl::SystemChar** argv)
}
{
hecl::SystemString impPath = outPath + _SYS_STR(".cpp");
std::string impPath = outPath + ".cpp";
athena::io::FileWriter w(impPath);
if (w.hasError()) {
Log.report(logvisor::Error, FMT_STRING(_SYS_STR("Error opening '{}' for writing")), impPath);
Log.report(logvisor::Error, FMT_STRING("Error opening '{}' for writing"), impPath);
return 1;
}
std::string source = ret.second.str();

View File

@@ -28,7 +28,7 @@ static const char* StageNames[] = {
"hecl::PipelineStage::Evaluation"
};
const std::string* Compiler::getFileContents(SystemStringView path) {
const std::string* Compiler::getFileContents(std::string_view path) {
// TODO: Heterogeneous lookup when C++20 available
auto search = m_fileContents.find(path.data());
if (search == m_fileContents.end()) {
@@ -42,7 +42,7 @@ const std::string* Compiler::getFileContents(SystemStringView path) {
return &search->second;
}
void Compiler::addInputFile(SystemStringView file) {
void Compiler::addInputFile(std::string_view file) {
if (std::find(m_inputFiles.begin(), m_inputFiles.end(), file) == m_inputFiles.end())
m_inputFiles.emplace_back(file);
}
@@ -207,25 +207,25 @@ static const std::regex regGeometry(R"(#\s*geometry\s+(.*))", RegexFlags);
static const std::regex regControl(R"(#\s*control\s+(.*))", RegexFlags);
static const std::regex regEvaluation(R"(#\s*evaluation\s+(.*))", RegexFlags);
bool Compiler::includeFile(SystemStringView file, std::string& out, int depth) {
bool Compiler::includeFile(std::string_view file, std::string& out, int depth) {
if (depth > 32) {
Log.report(logvisor::Error, FMT_STRING(_SYS_STR("Too many levels of includes (>32) at '{}'")), file);
Log.report(logvisor::Error, FMT_STRING("Too many levels of includes (>32) at '{}'"), file);
return false;
}
const std::string* data = getFileContents(file);
if (!data) {
Log.report(logvisor::Error, FMT_STRING(_SYS_STR("Unable to access '{}'")), file);
Log.report(logvisor::Error, FMT_STRING("Unable to access '{}'"), file);
return false;
}
const std::string& sdata = *data;
SystemString directory;
auto slashPos = file.find_last_of(_SYS_STR("/\\"));
if (slashPos != SystemString::npos)
directory = SystemString(file.data(), slashPos);
std::string directory;
auto slashPos = file.find_last_of("/\\");
if (slashPos != std::string::npos)
directory = std::string(file.data(), slashPos);
else
directory = _SYS_STR(".");
directory = ".";
auto begin = sdata.cbegin();
auto end = sdata.cend();
@@ -241,14 +241,13 @@ bool Compiler::includeFile(SystemStringView file, std::string& out, int depth) {
if (std::regex_search(begin, nextBegin, subMatch, regInclude)) {
std::string path = subMatch[1].str();
if (path.empty()) {
Log.report(logvisor::Error, FMT_STRING(_SYS_STR("Empty path provided to include in '{}'")), file);
Log.report(logvisor::Error, FMT_STRING("Empty path provided to include in '{}'"), file);
return false;
}
hecl::SystemString pathStr(hecl::SystemStringConv(path).sys_str());
if (!hecl::IsAbsolute(pathStr))
pathStr = directory + _SYS_STR('/') + pathStr;
if (!includeFile(pathStr, out, depth + 1))
if (!hecl::IsAbsolute(path))
path = directory + '/' + path;
if (!includeFile(path, out, depth + 1))
return false;
} else {
out.insert(out.end(), begin, nextBegin);
@@ -442,7 +441,7 @@ constexpr void SemanticOut(std::stringstream& out,
attr.second);
}
bool Compiler::compileFile(SystemStringView file, std::string_view baseName,
bool Compiler::compileFile(std::string_view file, std::string_view baseName,
std::pair<std::stringstream, std::stringstream>& out) {
std::string includesPass;
if (!includeFile(file, includesPass))

View File

@@ -1,5 +1,4 @@
#pragma once
#include "hecl/SystemChar.hpp"
#include <string>
#include <vector>
#include <unordered_map>
@@ -9,9 +8,9 @@ namespace hecl::shaderc {
class Compiler {
enum class StageType { Vertex, Fragment, Geometry, Control, Evaluation };
std::vector<SystemString> m_inputFiles;
std::unordered_map<SystemString, std::string> m_fileContents;
const std::string* getFileContents(SystemStringView path);
std::vector<std::string> m_inputFiles;
std::unordered_map<std::string, std::string> m_fileContents;
const std::string* getFileContents(std::string_view path);
std::unordered_map<std::string, std::string> m_defines;
template <typename Action, typename P>
static bool StageAction(StageType type, const std::string& name, const std::string& basename,
@@ -19,12 +18,12 @@ class Compiler {
template <typename Action>
static bool StageAction(const std::string& platforms, StageType type, const std::string& name,
const std::string& basename, const std::string& stage, std::stringstream& implOut);
bool includeFile(SystemStringView file, std::string& out, int depth = 0);
bool compileFile(SystemStringView file, std::string_view baseName,
bool includeFile(std::string_view file, std::string& out, int depth = 0);
bool compileFile(std::string_view file, std::string_view baseName,
std::pair<std::stringstream, std::stringstream>& out);
public:
void addInputFile(SystemStringView file);
void addInputFile(std::string_view file);
void addDefine(std::string_view var, std::string_view val);
bool compile(std::string_view baseName, std::pair<std::stringstream, std::stringstream>& out);
};