ide: Commandline handling refactored

This commit is contained in:
Mirek Fidler 2025-11-05 10:39:56 +01:00
parent b8272ee30d
commit 29cf8728ec
12 changed files with 87 additions and 324 deletions

View file

@ -1,122 +0,0 @@
#include "CommandLineHandler.h"
#include "About.h"
#include <Draw/Draw.h>
#include <ide/Common/CommandLineOptions.h>
#include <ide/Debuggers/GdbUtils.h>
using namespace Upp;
ACommandLineHandler::ACommandLineHandler(const Vector<String>& args)
: args(clone(args))
{}
BaseCommandLineHandler::BaseCommandLineHandler(const Vector<String>& args)
: ACommandLineHandler(args)
{}
bool BaseCommandLineHandler::Handle()
{
if(HandleVersion())
return true;
if(HandleHelp())
return true;
if(HandleDebugBreakProcess())
return true;
return false;
}
bool BaseCommandLineHandler::HandleVersion() const
{
if(args.IsEmpty() || findarg(args[0], "-v", "--version") < 0)
return false;
Cout() << SplashCtrl::GenerateVersionInfo(false) << "\n";
return true;
}
bool BaseCommandLineHandler::HandleHelp() const
{
if(args.IsEmpty() || findarg(args[0], "?", "--help", "-h", "-?", "/?") < 0)
return false;
Cout() << "Usage:\n"
" theide [file..] - opens given file in editor mode (Auto detection mode).\n"
" theide [assembly] [package] - opens given package from given assembly.\n\n";
Cout() << "Common options:\n"
" -f $file - opens given file in editor mode.\n"
" -v or --version - displays information about version.\n"
" -h or --help - displays this site.\n\n";
Cout() << "Advanced options:\n"
" " << COMMAND_LINE_SCALE_OPTION << " $percent - scale interface by \"percent\" parameter.\n\n";
Cout() << "Internal options (Should not be called by the user):\n"
" " << COMMAND_LINE_GDB_DEBUG_BREAK_PROCESS_OPTION << " $pid - breaks debug process represented by \"pid\".\n";
return true;
}
bool BaseCommandLineHandler::HandleDebugBreakProcess() const
{
if(args.GetCount() < 2 || !args[0].IsEqual(COMMAND_LINE_GDB_DEBUG_BREAK_PROCESS_OPTION))
return false;
int pid = StrInt(args[1]);
if(IsNull(pid)) {
Cout() << "PID should be numeric value.\n";
return true;
}
auto utils = GdbUtilsFactory().Create();
auto error = utils->BreakRunning(pid);
if(!error.IsEmpty()) {
Cout() << error << "\n";
SetExitCode(COMMAND_LINE_GDB_DEBUG_BREAK_PROCESS_FAILURE_STATUS);
}
return true;
}
MainCommandLineHandler::MainCommandLineHandler(const Vector<String>& args)
: ACommandLineHandler(args)
{}
bool MainCommandLineHandler::Handle()
{
if(HandleManipulators())
return true;
return false;
}
bool MainCommandLineHandler::HandleManipulators()
{
if(HandleScale())
return true;
return false;
}
bool MainCommandLineHandler::HandleScale()
{
if(args.GetCount() < 2 || !args[0].IsEqual(COMMAND_LINE_SCALE_OPTION))
return false;
int scale = StrInt(args[1]);
if(IsNull(scale)) {
Cout() << "Scale should be numeric value.\n";
return true;
}
Font::SetStdFont(StdFont().Height(GetStdFontCy() * minmax(scale, 50, 400) / 100));
args.Remove(0, 2);
return false;
}

View file

@ -1,51 +0,0 @@
#ifndef _ide_Command_Line_Handler_h_
#define _ide_Command_Line_Handler_h_
#include <Core/Core.h>
// TODO: All TheIDE command line arguments should be consume in this file.
namespace Upp {
class ACommandLineHandler {
public:
ACommandLineHandler(const Vector<String>& args);
Vector<String> GetArgs() { return clone(args); }
public:
virtual bool Handle() = 0;
protected:
Vector<String> args;
};
class BaseCommandLineHandler final : public ACommandLineHandler {
public:
BaseCommandLineHandler(const Vector<String>& args);
public:
bool Handle() override;
private:
bool HandleVersion() const;
bool HandleHelp() const;
bool HandleDebugBreakProcess() const;
};
class MainCommandLineHandler final : public ACommandLineHandler {
public:
MainCommandLineHandler(const Vector<String>& args);
public:
bool Handle() override;
private:
bool HandleManipulators();
bool HandleScale();
};
}
#endif

View file

@ -1,15 +0,0 @@
#ifndef _ide_Common_CommandLineDefs_h_
#define _ide_Common_CommandLineDefs_h_
#include <Core/Core.h>
namespace Upp {
const String COMMAND_LINE_SCALE_OPTION = "--scale";
const String COMMAND_LINE_GDB_DEBUG_BREAK_PROCESS_OPTION = "--gdb_debug_break_process";
const int COMMAND_LINE_GDB_DEBUG_BREAK_PROCESS_FAILURE_STATUS = -1;
}
#endif

View file

@ -12,8 +12,6 @@ file
Module.cpp,
Util.cpp,
common.iml,
Defs readonly separator,
CommandLineOptions.h,
Info readonly separator,
Copying;

View file

@ -3,8 +3,6 @@
#define DR_LOG(x) // RLOG(x)
#include "GdbUtils.h"
#include <ide/Common/Common.h>
#include <HexView/HexView.h>

View file

@ -21,7 +21,6 @@ file
GdbData.cpp,
Gdb.cpp,
GdbMem.cpp,
GdbUtils.h,
GdbUtils.cpp,
PDB readonly separator,
Pdb.h,

View file

@ -448,7 +448,7 @@ void Gdb::BreakRunning()
{
Logd() << METHOD_NAME << "PID: " << pid << "\n";
auto error = gdb_utils->BreakRunning(pid);
auto error = BreakRunning(pid);
if(!error.IsEmpty()) {
Loge() << METHOD_NAME << error;
ErrorOK(error);
@ -693,7 +693,6 @@ void Gdb::SerializeSession(Stream& s)
}
Gdb::Gdb()
: gdb_utils(GdbUtilsFactory().Create())
{
auto Mem = [=](Bar& bar, ArrayCtrl& h) {
String s = h.GetKey();

View file

@ -158,6 +158,7 @@ protected:
String exception;
const int max_stack_trace_size = 400;
One<IGdbUtils> gdb_utils;
public:
static String BreakRunning(int pid);
};

View file

@ -1,80 +1,39 @@
#include "GdbUtils.h"
#include <memory>
#include <ide/Core/Logger.h>
#include <ide/Common/CommandLineOptions.h>
#include "Debuggers.h"
using namespace Upp;
One<IGdbUtils> GdbUtilsFactory::Create()
{
#if defined(PLATFORM_WIN32)
return MakeOne<GdbWindowsUtils>();
#elif defined(PLATFORM_POSIX)
return MakeOne<GdbPosixUtils>();
#endif
}
#if defined(PLATFORM_WIN32)
#define METHOD_NAME UPP_METHOD_NAME("GdbWindowsUtils")
using DeleteHandleFun = std::function<void(HANDLE)>;
static void DeleteHandle(HANDLE handle)
String Gdb::BreakRunning(int pid)
{
if (handle)
{
CloseHandle(handle);
}
}
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
String GdbWindowsUtils::BreakRunning(int pid)
{
std::unique_ptr<void, DeleteHandleFun> handle(OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid), &DeleteHandle);
if(!handle)
return String().Cat() << "Failed to open process associated with " << pid << " PID.";
if(Is64BitIde() && !Is64BitProcess(handle.get())) {
auto path = String().Cat() << GetExeFolder() << "\\" << GetExeTitle() << "32.exe";
auto cmd = String().Cat() << path << " " << COMMAND_LINE_GDB_DEBUG_BREAK_PROCESS_OPTION << " " << pid;
String out;
if(Sys(cmd, out) == COMMAND_LINE_GDB_DEBUG_BREAK_PROCESS_FAILURE_STATUS) {
Logd() << METHOD_NAME << cmd;
return String().Cat() << "Failed to interrupt process via 32-bit TheIDE. Output from command is \"" << out << "\".";
return String() << "Failed to open process associated with " << pid << " PID.";
String ret;
BOOL is_wow_64 = FALSE;
if(IsWow64Process(handle, &is_wow_64)) {
if(sizeof(void*) == 8 && is_wow_64) {
String out; // NOTE: this does not work anyway as we are not distributing theide32.exe anymore
if(Sys(GetExeFolder() << "\\" << "theide32.exe --gdb_debug_break_process=" << pid, out) < 0)
ret = "Failed to interrupt process via 32-bit TheIDE. Output from command is \"" << out << "\".";
}
return "";
}
else
ret = "Failed to check that process is under wow64 emulation layer.";
if (!DebugBreakProcess(handle.get()))
if(DebugBreakProcess(handle))
return String().Cat() << "Failed to break process associated with " << pid << " PID.";
CloseHandle(handle);
return "";
}
bool GdbWindowsUtils::Is64BitIde() const
{
return sizeof(void*) == 8;
}
bool GdbWindowsUtils::Is64BitProcess(HANDLE handle) const
{
BOOL is_wow_64 = FALSE;
if(!IsWow64Process(handle, &is_wow_64)) {
Loge() << METHOD_NAME << "Failed to check that process is under wow64 emulation layer.";
}
return !is_wow_64;
}
#undef METHOD_NAME
#elif defined(PLATFORM_POSIX)
String GdbPosixUtils::BreakRunning(int pid)
String Gdb::BreakRunning(int pid)
{
if(kill(pid, SIGINT) == -1)
return String().Cat() << "Failed to interrupt process associated with " << pid << " PID.";

View file

@ -1,42 +0,0 @@
#ifndef _ide_Debuggers_GdbUtils_h_
#define _ide_Debuggers_GdbUtils_h_
#include <Core/Core.h>
namespace Upp {
class IGdbUtils {
public:
virtual ~IGdbUtils() = default;
virtual String BreakRunning(int pid) = 0;
};
class GdbUtilsFactory final {
public:
One<IGdbUtils> Create();
};
#if defined(PLATFORM_WIN32)
class GdbWindowsUtils final : public IGdbUtils {
public: /* IGdbUtils */
virtual String BreakRunning(int pid) override;
private:
bool Is64BitIde() const;
bool Is64BitProcess(HANDLE handle) const;
};
#elif defined(PLATFORM_POSIX)
class GdbPosixUtils final : public IGdbUtils {
public: /* IGdbUtils */
virtual String BreakRunning(int pid) override;
};
#endif
}
#endif

View file

@ -73,8 +73,6 @@ file
background.cpp,
idewin.cpp,
main.cpp,
CommandLineHandler.h,
CommandLineHandler.cpp,
About.h,
BuildInfo.cpp,
About.cpp,

View file

@ -1,5 +1,4 @@
#include "ide.h"
#include "CommandLineHandler.h"
#define FUNCTION_NAME UPP_FUNCTION_NAME << "(): "
@ -108,14 +107,6 @@ void StartEditorMode(const Vector<String>& args, Ide& ide, bool& clset)
}
}
#undef GUI_APP_MAIN_HOOK
#define GUI_APP_MAIN_HOOK \
{ \
BaseCommandLineHandler cmd_handler(CommandLine()); \
if (cmd_handler.Handle()) \
return Upp::GetExitCode(); \
}
#ifdef DYNAMIC_LIBCLANG
bool TryLoadLibClang()
{
@ -230,17 +221,73 @@ void AppMain___()
SetLanguage(LNG_ENGLISH);
SetDefaultCharset(CHARSET_UTF8);
MainCommandLineHandler cmd_handler(CommandLine());
if (cmd_handler.Handle())
return;
auto arg = clone(cmd_handler.GetArgs());
bool dosplash = true;
bool debug_exe_mode = false;
bool debug_exe_mode = arg.GetCount() && arg[0] == "--debug";
Vector<String> arg = clone(CommandLine());
for(int i = 0; i < arg.GetCount();) {
String ca = arg[i];
int number = atoi(Filter(ca, CharFilterDigit));
auto Info = [](const char *s) {
#ifdef PLATFORM_POSIX
Cout() << s;
#else
PromptOK(String() << "[C0 \1" << s); // Console output does not work in Win32 GUI apps
#endif
};
if(findarg(ca, "?", "--help", "-h", "-?", "/?") >= 0) {
Info(
"Usage:\n"
" theide [file..] opens given file in editor mode (Auto detection mode).\n"
" theide [assembly] [package] opens given package from given assembly.\n\n"
"Common options:\n"
" -v or --version displays information about version.\n"
" -h or --help displays this site.\n"
" --nosplash start without showing splash window\n"
" --scale=number scales interface by number percent.\n"
#ifdef PLATFORM_POSIX
" --clangdir dir specify location of libclang.so\n"
#endif
);
return;
}
else
if(findarg(ca, "-v", "--version") >= 0) {
Info(SplashCtrl::GenerateVersionInfo(false) + "\n");
return;
}
else
if(ca == "--nosplash") {
dosplash = false;
arg.Remove(i);
}
if(ca.StartsWith("--scale=")) {
Font::SetStdFont(StdFont().Height(GetStdFontCy() * minmax(number, 50, 400) / 100));
arg.Remove(i);
}
else
if(ca.StartsWith("--gdb_debug_break_process=")) {
String error = Gdb::BreakRunning(number);
if(!error.IsEmpty()) {
Cout() << error << "\n";
SetExitCode(-1);
return;
}
}
else
if(ca == "--debug") {
debug_exe_mode = true;
arg.Remove(i);
}
else
i++;
}
SetVppLogSizeLimit(200000000);
// SetVppLogSizeLimit(2000000000); _DBG_
bool dosplash = true;
if(debug_exe_mode)
dosplash = false;
else {
@ -272,12 +319,6 @@ void AppMain___()
if(!FileExists(SearchEnginesFile()))
SearchEnginesDefaultSetup();
for(int i = 0; i < arg.GetCount(); i++)
if(arg[i] == "--nosplash") {
dosplash = false;
arg.Remove(i);
break;
}
for(int i = 0; i < arg.GetCount(); i++) {
#ifdef PLATFORM_WIN32
if(arg[i] == "!") {
@ -379,12 +420,12 @@ void AppMain___()
}
}
}
} else {
if(arg.GetCount() == 2 && IsAssembly(arg[0])) {
}
else
if(arg.GetCount() == 2 && IsAssembly(arg[0])) {
LoadVars(arg[0]);
ide.SetMain(arg[1]);
clset=true;
}
}
ide.LoadAbbr();