#include "cangjie/Macro/InvokeUtil.h"
#include "cangjie/Macro/MacroEvaluation.h"
#include <algorithm>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
#ifdef __WIN32
#include <windows.h>
#else
#include <csignal>
#ifdef __ohos__
#include <signal.h>
#else
#include <sys/signal.h>
#endif
#include <sys/stat.h>
#endif
using namespace Cangjie;
namespace {
#if defined(__linux__) || defined(__APPLE__)
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
const size_t ARGS_NUM = 6;
#endif
#else
const size_t ARGS_NUM = 5;
#endif
const size_t IDX_OF_READ_HANDLE = 1;
const size_t IDX_OF_WRITE_HANDLE = 2;
const size_t IDX_OF_ENABLE_PARA = 3;
const size_t IDX_OF_CJC_FOLDER = 4;
const size_t IDX_OF_PPID = 5;
#if defined(__linux__) || defined(__APPLE__)
const unsigned int CHECK_INTERVAL = 2;
static void MonitoringParentProcess(pid_t pid)
{
while (true) {
sleep(CHECK_INTERVAL);
if (kill(pid, 0) != 0) {
perror("parent process not exits");
[[maybe_unused]] std::lock_guard lg(MacroProcMsger::GetInstance().mutex);
MacroProcMsger::GetInstance().CloseClientResource();
RuntimeInit::GetInstance().CloseRuntime();
exit(1);
}
}
}
#endif
bool IsNumber(const std::string& str)
{
for (char c : str) {
if (!std::isdigit(c)) {
return false;
}
}
return true;
}
bool IsArgsValid(const std::vector<std::string>& args)
{
if (args.size() != ARGS_NUM) {
Errorln(
"Macro srv: Incorrect number of args, " + std::to_string(args.size()) + " : " + std::to_string(ARGS_NUM));
return false;
}
if (!IsNumber(args[IDX_OF_READ_HANDLE])) {
Errorln("Macro srv: Arg of read handle is not number");
return false;
}
if (!IsNumber(args[IDX_OF_WRITE_HANDLE])) {
Errorln("Macro srv: Arg of write handle is not number");
return false;
}
if (args.size() > IDX_OF_PPID && !IsNumber(args[IDX_OF_PPID])) {
Errorln("Macro srv: Arg of ppid is not number");
return false;
}
if (args[IDX_OF_CJC_FOLDER].empty()) {
Errorln("Macro srv: Arg of cjc folder is empty");
return false;
}
return true;
}
#ifdef __WIN32
bool CheckPipe(HANDLE read, HANDLE write)
{
if (GetNamedPipeInfo(read, nullptr, nullptr, nullptr, nullptr) == FALSE) {
Errorln("Macro srv: Read handle is not available");
return false;
}
if (GetNamedPipeInfo(write, nullptr, nullptr, nullptr, nullptr) == FALSE) {
CloseHandle(read);
Errorln("Macro srv: Write handle is not available");
return false;
}
return true;
}
#else
bool IsPipe(int fd)
{
struct stat status;
fstat(fd, &status);
return S_ISFIFO(status.st_mode);
}
bool CheckPipe(int read, int write)
{
if (!IsPipe(read)) {
Errorln("Macro srv: Read pipe is not available");
return false;
}
if (!IsPipe(write)) {
close(read);
Errorln("Macro srv: Write pipe is not available");
return false;
}
return true;
}
#endif
}
int main(int argc, const char* argv[], [[maybe_unused]] const char** envp)
{
auto args = Utils::StringifyArgumentVector(argc, argv);
if (!IsArgsValid(args)) {
return -1;
}
#ifdef _WIN32
HANDLE hRead = reinterpret_cast<HANDLE>(atoi(args[IDX_OF_READ_HANDLE].c_str()));
HANDLE hWrite = reinterpret_cast<HANDLE>(atoi(args[IDX_OF_WRITE_HANDLE].c_str()));
#else
int hRead = stoi(args[IDX_OF_READ_HANDLE]);
int hWrite = stoi(args[IDX_OF_WRITE_HANDLE]);
int ppid = stoi(args[IDX_OF_PPID]);
std::thread w(MonitoringParentProcess, ppid);
w.detach();
#endif
if (!CheckPipe(hRead, hWrite)) {
return -1;
}
GlobalOptions gpt;
std::string cjcFolder = args[IDX_OF_CJC_FOLDER];
if (cjcFolder.back() == '"') {
cjcFolder.back() = '\\';
}
gpt.executablePath = cjcFolder;
gpt.enableParallelMacro = args[IDX_OF_ENABLE_PARA] == "1" ? true : false;
DiagnosticEngine diag;
CompilerInvocation compilerInvocation;
compilerInvocation.globalOptions = gpt;
CompilerInstance ci(compilerInvocation, diag);
MacroCollector macroCollector;
MacroEvaluation evaluator(&ci, ¯oCollector, false);
{
[[maybe_unused]] std::lock_guard lg(MacroProcMsger::GetInstance().mutex);
MacroProcMsger::GetInstance().SetSrvPipeHandle(hRead, hWrite);
}
#ifdef CANGJIE_CODEGEN_CJNATIVE_BACKEND
RuntimeInit::GetInstance().InitRuntime(
ci.invocation.GetRuntimeLibPath(), ci.invocation.globalOptions.environment.allVariables);
#endif
evaluator.ExecuteEvalSrvTask();
RuntimeInit::GetInstance().CloseRuntime();
#ifdef _WIN32
CloseHandle(hRead);
CloseHandle(hWrite);
#else
[[maybe_unused]] std::lock_guard lg(MacroProcMsger::GetInstance().mutex);
MacroProcMsger::GetInstance().CloseClientResource();
#endif
_exit(0);
}