metaforce/hecl/driver/main.cpp

310 lines
8.2 KiB
C++
Raw Normal View History

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