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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; }
|
||||
};
|
||||
|
||||
@@ -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; }
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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); }
|
||||
|
||||
13
hecl/include/hecl/Blender/FindBlender.hpp
Normal file
13
hecl/include/hecl/Blender/FindBlender.hpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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; }
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
@@ -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");
|
||||
|
||||
144
hecl/lib/Blender/FindBlender.cpp
Normal file
144
hecl/lib/Blender/FindBlender.cpp
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user