metaforce/hecl/driver/ToolBase.hpp

385 lines
9.7 KiB
C++
Raw Normal View History

2015-05-19 21:01:32 +00:00
#ifndef CTOOL_BASE
#define CTOOL_BASE
2015-05-20 05:22:32 +00:00
#include <string>
#include <vector>
#include <list>
2017-12-29 07:56:31 +00:00
#include <cstdio>
#include <cstring>
2015-05-20 05:22:32 +00:00
2015-07-22 19:14:50 +00:00
#ifndef _WIN32
#include <unistd.h>
2017-10-25 07:46:32 +00:00
#include <termios.h>
2017-10-30 07:29:07 +00:00
#else
#include <conio.h>
2015-07-22 19:14:50 +00:00
#endif
2016-03-04 23:02:44 +00:00
#include "hecl/Database.hpp"
#include "logvisor/logvisor.hpp"
2015-07-05 06:27:24 +00:00
2016-03-04 23:02:44 +00:00
extern logvisor::Module LogModule;
2015-06-10 02:40:03 +00:00
struct ToolPassInfo
2015-05-20 05:22:32 +00:00
{
2016-03-04 23:02:44 +00:00
hecl::SystemString pname;
hecl::SystemString cwd;
std::vector<hecl::SystemString> args;
std::vector<hecl::SystemChar> flags;
hecl::SystemString output;
hecl::Database::Project* project = nullptr;
2015-05-20 05:22:32 +00:00
unsigned verbosityLevel = 0;
bool force = false;
2016-03-24 02:51:57 +00:00
bool yes = false;
bool gui = false;
2015-05-20 05:22:32 +00:00
};
2017-10-25 07:46:32 +00:00
#define RED "\033[0;31m"
#define GREEN "\033[0;32m"
#define YELLOW "\033[0;33m"
#define BLUE "\033[0;34m"
#define MAGENTA "\033[0;35m"
#define CYAN "\033[0;36m"
#define BOLD "\033[1m"
#define NORMAL "\033[0m"
#define HIDE_CURSOR "\033[?25l"
#define SHOW_CURSOR "\033[?25h"
#define WRAP_INDENT 4
extern bool XTERM_COLOR;
2015-06-10 02:40:03 +00:00
class ToolBase
{
protected:
2015-06-10 02:40:03 +00:00
const ToolPassInfo& m_info;
2015-07-26 02:52:02 +00:00
bool m_good = false;
2017-10-25 07:46:32 +00:00
bool continuePrompt()
{
if (!m_info.yes)
{
if (XTERM_COLOR)
hecl::Printf(_S("\n" BLUE BOLD "Continue?" NORMAL " (Y/n) "));
else
hecl::Printf(_S("\nContinue? (Y/n) "));
2018-01-10 06:16:18 +00:00
fflush(stdout);
2017-10-25 07:46:32 +00:00
int ch;
#ifndef _WIN32
struct termios tioOld, tioNew;
tcgetattr(0, &tioOld);
tioNew = tioOld;
tioNew.c_lflag &= ~ICANON;
tcsetattr(0, TCSANOW, &tioNew);
while ((ch = getchar()))
#else
while ((ch = getch()))
#endif
{
if (ch == 'n' || ch == 'N')
return false;
if (ch == 'y' || ch == 'Y' || ch == '\r' || ch == '\n')
break;
}
#ifndef _WIN32
tcsetattr(0, TCSANOW, &tioOld);
#endif
}
hecl::Printf(_S("\n"));
return true;
}
public:
2015-06-10 02:40:03 +00:00
ToolBase(const ToolPassInfo& info)
2015-08-06 19:10:12 +00:00
: m_info(info)
{
2016-03-04 23:02:44 +00:00
hecl::VerbosityLevel = info.verbosityLevel;
hecl::GuiMode = info.gui;
2015-08-06 19:10:12 +00:00
}
2015-06-10 02:40:03 +00:00
virtual ~ToolBase() {}
2016-03-04 23:02:44 +00:00
virtual hecl::SystemString toolName() const=0;
2015-05-20 05:22:32 +00:00
virtual int run()=0;
2015-07-26 02:52:02 +00:00
inline operator bool() const {return m_good;}
};
2015-06-10 02:40:03 +00:00
class HelpOutput
2015-05-26 04:42:20 +00:00
{
public:
2015-06-10 02:40:03 +00:00
typedef void(*HelpFunc)(HelpOutput&);
2015-05-26 04:42:20 +00:00
private:
FILE* m_sout;
2015-06-10 02:40:03 +00:00
HelpFunc m_helpFunc;
2015-05-26 04:42:20 +00:00
int m_lineWidth;
2016-03-04 23:02:44 +00:00
hecl::SystemString m_wrapBuffer;
2015-05-26 04:42:20 +00:00
2016-03-04 23:02:44 +00:00
void _wrapBuf(hecl::SystemString& string)
2015-05-26 04:42:20 +00:00
{
int counter;
2016-03-04 23:02:44 +00:00
hecl::SystemString::iterator it = string.begin();
2015-05-26 04:42:20 +00:00
while (it != string.end())
{
2017-11-14 05:35:00 +00:00
std::ptrdiff_t v = it - string.begin();
2015-05-26 04:42:20 +00:00
/* copy string until the end of the line is reached */
for (counter=WRAP_INDENT ; counter < m_lineWidth ; ++counter)
{
2017-11-14 05:35:00 +00:00
if (it >= string.end())
return;
2015-06-10 02:40:03 +00:00
if (*it == _S('\n'))
2015-05-26 04:42:20 +00:00
{
counter = WRAP_INDENT;
++it;
}
if (counter == WRAP_INDENT)
2015-07-12 18:08:20 +00:00
{
for (int i=0 ; i<WRAP_INDENT ; ++i)
it = string.insert(it, _S(' ')) + 1;
}
2015-05-26 04:42:20 +00:00
if (it >= string.end())
return;
2015-06-10 02:40:03 +00:00
if (*it != _S('\n'))
2015-05-26 04:42:20 +00:00
++it;
}
/* check for whitespace */
if (isspace(*it))
{
2015-06-10 02:40:03 +00:00
*it = _S('\n');
2015-05-26 04:42:20 +00:00
counter = WRAP_INDENT;
++it;
}
else
{
/* check for nearest whitespace back in string */
2016-03-04 23:02:44 +00:00
for (hecl::SystemString::iterator k=it ; k!=string.begin() ; --k)
2015-05-26 04:42:20 +00:00
{
if (isspace(*k))
{
counter = WRAP_INDENT;
2017-11-14 05:35:00 +00:00
if (k - string.begin() < v)
k = string.insert(it, _S('\n'));
2015-05-26 04:42:20 +00:00
else
2015-06-10 02:40:03 +00:00
*k = _S('\n');
2015-05-26 04:42:20 +00:00
it = k + 1;
break;
}
}
}
}
}
public:
2015-06-10 02:40:03 +00:00
HelpOutput(HelpFunc helpFunc)
: m_sout(NULL), m_helpFunc(helpFunc), m_lineWidth(hecl::GuiMode ? 120 : hecl::ConsoleWidth())
2015-07-20 23:27:22 +00:00
{}
2015-05-26 04:42:20 +00:00
void go()
{
2015-06-10 02:40:03 +00:00
#if _WIN32
m_sout = stdout;
m_helpFunc(*this);
#else
2015-05-26 04:42:20 +00:00
m_sout = popen("less -R", "w");
if (m_sout)
{
m_helpFunc(*this);
pclose(m_sout);
}
else
{
m_sout = stdout;
m_helpFunc(*this);
}
2015-06-10 02:40:03 +00:00
#endif
2015-05-26 04:42:20 +00:00
}
2016-03-04 23:02:44 +00:00
void print(const hecl::SystemChar* str)
2015-05-26 04:42:20 +00:00
{
2016-03-04 23:02:44 +00:00
hecl::FPrintf(m_sout, _S("%s"), str);
2015-05-26 04:42:20 +00:00
}
2016-03-04 23:02:44 +00:00
void printBold(const hecl::SystemChar* str)
2015-05-26 04:42:20 +00:00
{
if (XTERM_COLOR)
2016-03-04 23:02:44 +00:00
hecl::FPrintf(m_sout, _S("" BOLD "%s" NORMAL ""), str);
2015-05-26 04:42:20 +00:00
else
2016-03-04 23:02:44 +00:00
hecl::FPrintf(m_sout, _S("%s"), str);
2015-05-26 04:42:20 +00:00
}
2016-03-04 23:02:44 +00:00
void secHead(const hecl::SystemChar* headName)
2015-05-26 04:42:20 +00:00
{
if (XTERM_COLOR)
2016-03-04 23:02:44 +00:00
hecl::FPrintf(m_sout, _S("" BOLD "%s" NORMAL "\n"), headName);
2015-05-26 04:42:20 +00:00
else
2016-03-04 23:02:44 +00:00
hecl::FPrintf(m_sout, _S("%s\n"), headName);
2015-05-26 04:42:20 +00:00
}
2016-03-04 23:02:44 +00:00
void optionHead(const hecl::SystemChar* flag, const hecl::SystemChar* synopsis)
2015-05-26 04:42:20 +00:00
{
if (XTERM_COLOR)
2016-03-04 23:02:44 +00:00
hecl::FPrintf(m_sout, _S("" BOLD "%s" NORMAL " (%s)\n"), flag, synopsis);
2015-05-26 04:42:20 +00:00
else
2016-03-04 23:02:44 +00:00
hecl::FPrintf(m_sout, _S("%s (%s)\n"), flag, synopsis);
2015-05-26 04:42:20 +00:00
}
void beginWrap()
{
m_wrapBuffer.clear();
}
2016-03-04 23:02:44 +00:00
void wrap(const hecl::SystemChar* str)
2015-05-26 04:42:20 +00:00
{
m_wrapBuffer += str;
}
2016-03-04 23:02:44 +00:00
void wrapBold(const hecl::SystemChar* str)
2015-05-26 04:42:20 +00:00
{
2015-06-10 02:40:03 +00:00
if (XTERM_COLOR)
m_wrapBuffer += _S("" BOLD "");
2015-05-26 04:42:20 +00:00
m_wrapBuffer += str;
2015-06-10 02:40:03 +00:00
if (XTERM_COLOR)
m_wrapBuffer += _S("" NORMAL "");
2015-05-26 04:42:20 +00:00
}
void endWrap()
{
_wrapBuf(m_wrapBuffer);
2015-06-10 02:40:03 +00:00
m_wrapBuffer += _S('\n');
2016-03-04 23:02:44 +00:00
hecl::FPrintf(m_sout, _S("%s"), m_wrapBuffer.c_str());
2015-05-26 04:42:20 +00:00
m_wrapBuffer.clear();
}
};
2016-03-04 23:02:44 +00:00
static hecl::SystemString MakePathArgAbsolute(const hecl::SystemString& arg,
const hecl::SystemString& cwd)
2015-10-02 04:06:45 +00:00
{
#if _WIN32
if (arg.size() >= 2 && iswalpha(arg[0]) && arg[1] == _S(':'))
return arg;
if (arg[0] == _S('\\') || arg[0] == _S('/'))
return arg;
return cwd + _S('\\') + arg;
#else
if (arg[0] == _S('/') || arg[0] == _S('\\'))
return arg;
2017-10-26 05:37:15 +00:00
if (cwd.back() == _S('/') || cwd.back() == _S('\\'))
return cwd + arg;
2015-10-02 04:06:45 +00:00
return cwd + _S('/') + arg;
#endif
}
2018-01-10 06:16:18 +00:00
static bool g_HasLastProgTime = false;
static std::chrono::steady_clock::time_point g_LastProgTime;
2016-03-04 23:02:44 +00:00
void ToolPrintProgress(const hecl::SystemChar* message, const hecl::SystemChar* submessage,
2015-09-30 06:23:07 +00:00
int lidx, float factor, int& lineIdx)
{
2018-01-10 06:16:18 +00:00
if (g_HasLastProgTime)
{
std::chrono::steady_clock::time_point newPoint = std::chrono::steady_clock::now();
std::chrono::milliseconds::rep delta =
std::chrono::duration_cast<std::chrono::milliseconds>(newPoint - g_LastProgTime).count();
if (delta < 50)
return;
g_LastProgTime = newPoint;
}
else
{
g_HasLastProgTime = true;
g_LastProgTime = std::chrono::steady_clock::now();
}
auto lk = logvisor::LockLog();
2015-10-04 04:35:18 +00:00
bool blocks = factor >= 0.0;
2015-09-30 06:23:07 +00:00
factor = std::max(0.0f, std::min(1.0f, factor));
int iFactor = factor * 100.0;
if (XTERM_COLOR)
2016-03-04 23:02:44 +00:00
hecl::Printf(_S("" HIDE_CURSOR ""));
2015-09-30 06:23:07 +00:00
if (lidx > lineIdx)
{
2016-03-04 23:02:44 +00:00
hecl::Printf(_S("\n "));
2015-09-30 06:23:07 +00:00
lineIdx = lidx;
}
else
2016-03-04 23:02:44 +00:00
hecl::Printf(_S(" "));
2015-09-30 06:23:07 +00:00
int width = (hecl::GuiMode ? 120 : std::max(80, hecl::ConsoleWidth()));
2015-10-04 04:35:18 +00:00
int half;
if (blocks)
half = width / 2 - 2;
else
half = width - 4;
2015-09-30 06:23:07 +00:00
if (!message)
message = _S("");
2018-01-10 06:16:18 +00:00
int messageLen = hecl::StrLen(message);
2015-09-30 06:23:07 +00:00
if (!submessage)
submessage = _S("");
2018-01-10 06:16:18 +00:00
int submessageLen = hecl::StrLen(submessage);
2015-09-30 06:23:07 +00:00
if (half - messageLen < submessageLen-2)
submessageLen = 0;
if (submessageLen)
{
if (messageLen > half-submessageLen-1)
2018-01-10 06:16:18 +00:00
hecl::Printf(_S("%.*s... %s "), half-submessageLen-4, message, submessage);
2015-09-30 06:23:07 +00:00
else
{
2016-03-04 23:02:44 +00:00
hecl::Printf(_S("%s"), message);
2015-09-30 06:23:07 +00:00
for (int i=half-messageLen-submessageLen-1 ; i>=0 ; --i)
2016-03-04 23:02:44 +00:00
hecl::Printf(_S(" "));
hecl::Printf(_S("%s "), submessage);
2015-09-30 06:23:07 +00:00
}
}
else
{
if (messageLen > half)
2016-03-04 23:02:44 +00:00
hecl::Printf(_S("%.*s... "), half-3, message);
2015-09-30 06:23:07 +00:00
else
{
2016-03-04 23:02:44 +00:00
hecl::Printf(_S("%s"), message);
2015-09-30 06:23:07 +00:00
for (int i=half-messageLen ; i>=0 ; --i)
2016-03-04 23:02:44 +00:00
hecl::Printf(_S(" "));
2015-09-30 06:23:07 +00:00
}
}
2015-10-04 04:35:18 +00:00
if (blocks)
2015-09-30 06:23:07 +00:00
{
2015-10-04 04:35:18 +00:00
if (XTERM_COLOR)
{
2018-01-10 06:16:18 +00:00
int blocks = half - 7;
int filled = blocks * factor;
int rem = blocks - filled;
2016-03-04 23:02:44 +00:00
hecl::Printf(_S("" BOLD "%3d%% ["), iFactor);
2015-10-04 04:35:18 +00:00
for (int b=0 ; b<filled ; ++b)
2016-03-04 23:02:44 +00:00
hecl::Printf(_S("#"));
2015-10-04 04:35:18 +00:00
for (int b=0 ; b<rem ; ++b)
2016-03-04 23:02:44 +00:00
hecl::Printf(_S("-"));
hecl::Printf(_S("]" NORMAL ""));
2015-10-04 04:35:18 +00:00
}
else
{
2018-01-10 06:16:18 +00:00
int blocks = half - 7;
int filled = blocks * factor;
int rem = blocks - filled;
2016-03-04 23:02:44 +00:00
hecl::Printf(_S("%3d%% ["), iFactor);
2015-10-04 04:35:18 +00:00
for (int b=0 ; b<filled ; ++b)
2016-03-04 23:02:44 +00:00
hecl::Printf(_S("#"));
2015-10-04 04:35:18 +00:00
for (int b=0 ; b<rem ; ++b)
2016-03-04 23:02:44 +00:00
hecl::Printf(_S("-"));
hecl::Printf(_S("]"));
2015-10-04 04:35:18 +00:00
}
2015-09-30 06:23:07 +00:00
}
2016-03-04 23:02:44 +00:00
hecl::Printf(_S("\r"));
2015-09-30 06:23:07 +00:00
if (XTERM_COLOR)
2016-03-04 23:02:44 +00:00
hecl::Printf(_S("" SHOW_CURSOR ""));
2015-09-30 06:23:07 +00:00
fflush(stdout);
}
2015-05-19 21:01:32 +00:00
#endif // CTOOL_BASE