metaforce/hecl/driver/main.cpp

317 lines
8.3 KiB
C++
Raw Normal View History

2015-07-22 19:14:50 +00:00
#if _WIN32
2015-10-12 04:38:49 +00:00
#ifndef NOMINMAX
#define NOMINMAX
#endif
2017-11-06 06:56:17 +00:00
#define WIN_PAUSE 0
2015-08-31 03:36:24 +00:00
#include <objbase.h>
2015-07-22 19:14:50 +00:00
#endif
2015-08-31 03:36:24 +00:00
#include <clocale>
2017-12-29 07:56:31 +00:00
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cstdarg>
2015-08-16 23:01:35 +00:00
#include <signal.h>
2015-05-20 05:22:32 +00:00
#include <regex>
2015-05-26 04:42:20 +00:00
#include <list>
2016-03-04 23:02:44 +00:00
#include "hecl/Database.hpp"
2017-12-29 07:56:31 +00:00
#include "hecl/Blender/Connection.hpp"
2016-03-04 23:02:44 +00:00
#include "logvisor/logvisor.hpp"
2015-07-05 06:27:24 +00:00
2016-09-25 01:57:43 +00:00
logvisor::Module LogModule("hecl::Driver");
2015-05-17 04:55:29 +00:00
2015-06-10 02:40:03 +00:00
#include "ToolBase.hpp"
#include "ToolInit.hpp"
#include "ToolSpec.hpp"
2015-06-12 09:08:49 +00:00
#include "ToolExtract.hpp"
2015-06-10 02:40:03 +00:00
#include "ToolCook.hpp"
#include "ToolPackage.hpp"
2018-04-15 06:04:08 +00:00
#include "ToolImage.hpp"
2015-06-10 02:40:03 +00:00
#include "ToolHelp.hpp"
2015-05-15 22:39:43 +00:00
2015-07-25 23:01:02 +00:00
/* Static reference to dataspec additions
* (used by MSVC to definitively link DataSpecs) */
#include "DataSpecRegistry.hpp"
2015-07-22 19:14:50 +00:00
2015-05-26 04:42:20 +00:00
bool XTERM_COLOR = false;
2015-06-11 09:41:10 +00:00
/*
2015-06-10 02:40:03 +00:00
#define HECL_GIT 1234567
#define HECL_GIT_S "1234567"
#define HECL_BRANCH master
#define HECL_BRANCH_S "master"
2015-06-11 09:41:10 +00:00
*/
2015-06-10 02:40:03 +00:00
2015-05-20 05:22:32 +00:00
/* Main usage message */
2018-12-08 05:18:42 +00:00
static void printHelp(const hecl::SystemChar* pname) {
if (XTERM_COLOR)
2019-07-20 04:22:58 +00:00
fmt::print(fmt(_SYS_STR("" BOLD "HECL" NORMAL "")));
2018-12-08 05:18:42 +00:00
else
2019-07-20 04:22:58 +00:00
fmt::print(fmt(_SYS_STR("HECL")));
2018-04-15 06:04:08 +00:00
#if HECL_HAS_NOD
2018-12-08 05:18:42 +00:00
#define TOOL_LIST "extract|init|cook|package|image|help"
2018-04-15 06:04:08 +00:00
#else
2018-12-08 05:18:42 +00:00
#define TOOL_LIST "extract|init|cook|package|help"
2018-04-15 06:04:08 +00:00
#endif
2015-05-20 05:22:32 +00:00
#if HECL_GIT
2019-07-20 04:22:58 +00:00
fmt::print(fmt(_SYS_STR(" Commit " HECL_GIT_S " " HECL_BRANCH_S "\nUsage: {} " TOOL_LIST "\n")), pname);
2015-05-20 05:22:32 +00:00
#elif HECL_VER
2019-07-20 04:22:58 +00:00
fmt::print(fmt(_SYS_STR(" Version " HECL_VER_S "\nUsage: {} " TOOL_LIST "\n")), pname);
2015-05-20 05:22:32 +00:00
#else
2019-07-20 04:22:58 +00:00
fmt::print(fmt(_SYS_STR("\nUsage: {} " TOOL_LIST "\n")), pname);
2015-05-20 05:22:32 +00:00
#endif
}
/* Regex patterns */
2018-12-08 05:18:42 +00:00
static const hecl::SystemRegex regOPEN(_SYS_STR("-o([^\"]*|\\S*)"), std::regex::ECMAScript | std::regex::optimize);
static ToolBase* ToolPtr = nullptr;
2015-08-16 23:01:35 +00:00
/* SIGINT will gracefully close blender connections and delete blends in progress */
2018-12-08 05:18:42 +00:00
static void SIGINTHandler(int sig) {
if (ToolPtr)
ToolPtr->cancel();
hecl::blender::Connection::Shutdown();
logvisor::KillProcessTree();
exit(1);
2015-08-16 23:01:35 +00:00
}
2016-03-04 23:02:44 +00:00
static logvisor::Module AthenaLog("Athena");
2019-07-20 04:22:58 +00:00
static void AthenaExc(athena::error::Level level, const char* file, const char*, int line,
fmt::string_view fmt, fmt::format_args args) {
AthenaLog.vreport(logvisor::Level(level), fmt, args);
2015-07-26 02:52:02 +00:00
}
2017-02-24 08:27:07 +00:00
static hecl::SystemChar cwdbuf[1024];
hecl::SystemString ExeDir;
2016-06-17 20:44:49 +00:00
#if _WIN32
2015-06-10 02:40:03 +00:00
int wmain(int argc, const wchar_t** argv)
#else
2018-05-25 06:34:58 +00:00
/* SIGWINCH should do nothing */
static void SIGWINCHHandler(int sig) {}
int main(int argc, const char** argv)
2015-06-10 02:40:03 +00:00
#endif
{
2018-12-08 05:18:42 +00:00
if (argc > 1 && !hecl::StrCmp(argv[1], _SYS_STR("--dlpackage"))) {
2019-07-20 04:22:58 +00:00
fmt::print(fmt("{}\n"), HECL_DLPACKAGE);
2018-12-08 05:18:42 +00:00
return 100;
}
2018-01-02 00:58:13 +00:00
2015-08-31 03:36:24 +00:00
#if _WIN32
2018-12-08 05:18:42 +00:00
CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
2015-08-31 03:36:24 +00:00
#else
2018-12-08 05:18:42 +00:00
std::setlocale(LC_ALL, "en-US.UTF-8");
2015-08-31 03:36:24 +00:00
#endif
2016-03-24 02:51:57 +00:00
2018-12-08 05:18:42 +00:00
/* Xterm check */
2015-09-02 22:00:05 +00:00
#if _WIN32
2018-12-08 05:18:42 +00:00
const char* conemuANSI = getenv("ConEmuANSI");
if (conemuANSI && !strcmp(conemuANSI, "ON"))
XTERM_COLOR = true;
2015-09-02 22:00:05 +00:00
#else
2018-12-08 05:18:42 +00:00
const char* term = getenv("TERM");
if (term && !strncmp(term, "xterm", 5))
XTERM_COLOR = true;
signal(SIGWINCH, SIGWINCHHandler);
2015-09-02 22:00:05 +00:00
#endif
2018-12-08 05:18:42 +00:00
signal(SIGINT, SIGINTHandler);
2015-08-16 23:01:35 +00:00
2018-12-08 05:18:42 +00:00
logvisor::RegisterStandardExceptions();
logvisor::RegisterConsoleLogger();
atSetExceptionHandler(AthenaExc);
2018-12-08 05:18:42 +00:00
/* Basic usage check */
if (argc == 1) {
printHelp(argv[0]);
2015-07-22 19:14:50 +00:00
#if WIN_PAUSE
2018-12-08 05:18:42 +00:00
system("PAUSE");
2015-07-22 19:14:50 +00:00
#endif
2018-12-08 05:18:42 +00:00
return 0;
} else if (argc == 0) {
printHelp(_SYS_STR("hecl"));
2015-07-22 19:14:50 +00:00
#if WIN_PAUSE
2018-12-08 05:18:42 +00:00
system("PAUSE");
2015-07-22 19:14:50 +00:00
#endif
2018-12-08 05:18:42 +00:00
return 0;
}
/* Prepare DataSpecs */
HECLRegisterDataSpecs();
/* Assemble common tool pass info */
ToolPassInfo info;
info.pname = argv[0];
if (hecl::Getcwd(cwdbuf, 1024)) {
info.cwd = cwdbuf;
if (info.cwd.size() && info.cwd.back() != _SYS_STR('/') && info.cwd.back() != _SYS_STR('\\'))
#if _WIN32
2018-12-08 05:18:42 +00:00
info.cwd += _SYS_STR('\\');
#else
2018-12-08 05:18:42 +00:00
info.cwd += _SYS_STR('/');
#endif
2017-02-24 08:27:07 +00:00
2018-12-08 05:18:42 +00:00
if (hecl::PathRelative(argv[0]))
ExeDir = hecl::SystemString(cwdbuf) + _SYS_STR('/');
hecl::SystemString Argv0(argv[0]);
hecl::SystemString::size_type lastIdx = Argv0.find_last_of(_SYS_STR("/\\"));
if (lastIdx != hecl::SystemString::npos)
ExeDir.insert(ExeDir.end(), Argv0.begin(), Argv0.begin() + lastIdx);
}
/* Concatenate args */
std::vector<hecl::SystemString> args;
args.reserve(argc - 2);
for (int i = 2; i < argc; ++i)
args.push_back(hecl::SystemString(argv[i]));
if (!args.empty()) {
/* Extract output argument */
for (auto it = args.cbegin(); it != args.cend();) {
const hecl::SystemString& arg = *it;
hecl::SystemRegexMatch oMatch;
if (std::regex_search(arg, oMatch, regOPEN)) {
const hecl::SystemString& token = oMatch[1].str();
if (token.size()) {
if (info.output.empty())
info.output = oMatch[1].str();
it = args.erase(it);
} else {
it = args.erase(it);
if (it == args.end())
break;
if (info.output.empty())
info.output = *it;
it = args.erase(it);
2015-05-20 05:22:32 +00:00
}
2018-12-08 05:18:42 +00:00
continue;
}
++it;
}
2015-05-20 05:22:32 +00:00
2018-12-08 05:18:42 +00:00
/* Iterate flags */
2019-02-04 00:01:12 +00:00
bool threadArg = false;
2018-12-08 05:18:42 +00:00
for (auto it = args.cbegin(); it != args.cend();) {
const hecl::SystemString& arg = *it;
2019-02-04 00:01:12 +00:00
if (threadArg) {
threadArg = false;
hecl::CpuCountOverride = int(hecl::StrToUl(arg.c_str(), nullptr, 0));
it = args.erase(it);
continue;
}
2018-12-08 05:18:42 +00:00
if (arg.size() < 2 || arg[0] != _SYS_STR('-') || arg[1] == _SYS_STR('-')) {
++it;
continue;
}
for (auto chit = arg.cbegin() + 1; chit != arg.cend(); ++chit) {
if (*chit == _SYS_STR('v'))
++info.verbosityLevel;
else if (*chit == _SYS_STR('f'))
info.force = true;
else if (*chit == _SYS_STR('y'))
info.yes = true;
else if (*chit == _SYS_STR('g'))
info.gui = true;
2019-02-04 00:01:12 +00:00
else if (*chit == _SYS_STR('j')) {
++chit;
if (*chit)
hecl::CpuCountOverride = int(hecl::StrToUl(&*chit, nullptr, 0));
else
threadArg = true;
break;
}
2018-12-08 05:18:42 +00:00
else
info.flags.push_back(*chit);
}
2015-05-20 05:22:32 +00:00
2018-12-08 05:18:42 +00:00
it = args.erase(it);
2015-05-20 05:22:32 +00:00
}
2018-12-08 05:18:42 +00:00
/* Gather remaining args */
info.args.reserve(args.size());
for (const hecl::SystemString& arg : args)
info.args.push_back(arg);
}
/* Attempt to find hecl project */
hecl::ProjectRootPath rootPath = hecl::SearchForProject(info.cwd);
std::unique_ptr<hecl::Database::Project> project;
if (rootPath) {
size_t ErrorRef = logvisor::ErrorCount;
hecl::Database::Project* newProj = new hecl::Database::Project(rootPath);
if (logvisor::ErrorCount > ErrorRef) {
2015-07-22 19:14:50 +00:00
#if WIN_PAUSE
2018-12-08 05:18:42 +00:00
system("PAUSE");
2015-07-22 19:14:50 +00:00
#endif
2018-12-08 05:18:42 +00:00
delete newProj;
return 1;
2015-06-11 04:55:06 +00:00
}
2018-12-08 05:18:42 +00:00
project.reset(newProj);
info.project = newProj;
}
/* Construct selected tool */
hecl::SystemString toolName(argv[1]);
hecl::ToLower(toolName);
std::unique_ptr<ToolBase> tool;
size_t ErrorRef = logvisor::ErrorCount;
if (toolName == _SYS_STR("init"))
tool.reset(new ToolInit(info));
else if (toolName == _SYS_STR("spec"))
tool.reset(new ToolSpec(info));
else if (toolName == _SYS_STR("extract"))
tool.reset(new ToolExtract(info));
else if (toolName == _SYS_STR("cook"))
tool.reset(new ToolCook(info));
else if (toolName == _SYS_STR("package") || toolName == _SYS_STR("pack"))
tool.reset(new ToolPackage(info));
2018-04-15 06:04:08 +00:00
#if HECL_HAS_NOD
2018-12-08 05:18:42 +00:00
else if (toolName == _SYS_STR("image"))
tool.reset(new ToolImage(info));
2018-04-15 06:04:08 +00:00
#endif
2018-12-08 05:18:42 +00:00
else if (toolName == _SYS_STR("help"))
tool.reset(new ToolHelp(info));
else {
FILE* fp = hecl::Fopen(argv[1], _SYS_STR("rb"));
if (!fp)
2019-07-20 04:22:58 +00:00
LogModule.report(logvisor::Error, fmt(_SYS_STR("unrecognized tool '{}'")), toolName);
2018-12-08 05:18:42 +00:00
else {
/* Shortcut-case: implicit extract */
fclose(fp);
info.args.insert(info.args.begin(), argv[1]);
tool.reset(new ToolExtract(info));
}
2018-12-08 05:18:42 +00:00
}
2018-12-08 05:18:42 +00:00
if (logvisor::ErrorCount > ErrorRef) {
2015-07-22 19:14:50 +00:00
#if WIN_PAUSE
2018-12-08 05:18:42 +00:00
system("PAUSE");
2015-07-16 02:03:38 +00:00
#endif
2018-12-08 05:18:42 +00:00
return 1;
}
if (info.verbosityLevel)
2019-07-20 04:22:58 +00:00
LogModule.report(logvisor::Info, fmt(_SYS_STR("Constructed tool '{}' {}\n")), tool->toolName(), info.verbosityLevel);
2018-12-08 05:18:42 +00:00
/* Run tool */
ErrorRef = logvisor::ErrorCount;
ToolPtr = tool.get();
int retval = tool->run();
ToolPtr = nullptr;
if (logvisor::ErrorCount > ErrorRef) {
hecl::blender::Connection::Shutdown();
2015-07-22 19:14:50 +00:00
#if WIN_PAUSE
2018-12-08 05:18:42 +00:00
system("PAUSE");
2015-07-16 02:03:38 +00:00
#endif
2018-12-08 05:18:42 +00:00
return 1;
}
2018-12-08 05:18:42 +00:00
hecl::blender::Connection::Shutdown();
2015-07-22 19:14:50 +00:00
#if WIN_PAUSE
2018-12-08 05:18:42 +00:00
system("PAUSE");
2015-07-22 19:14:50 +00:00
#endif
2018-12-08 05:18:42 +00:00
return retval;
2015-05-15 22:39:43 +00:00
}