diff --git a/uppsrc/Core/LocalProcess.cpp b/uppsrc/Core/LocalProcess.cpp index 44a11d17a..ac1a118d2 100644 --- a/uppsrc/Core/LocalProcess.cpp +++ b/uppsrc/Core/LocalProcess.cpp @@ -134,25 +134,27 @@ bool LocalProcess::DoStart(const char *command, bool spliterr, const char *envpt p++; else { args.Add(cmd_out); - while(*p && (byte)*p > ' ') - if(*p == '\\') { + while(*p && (byte)*p > ' ') { + int c = *p; + if(c == '\\') { if(*++p) *cmd_out++ = *p++; } - else if(*p == '\"') { + else if(c == '\"' || c == '\'') { p++; - while(*p && *p != '\"') + while(*p && *p != c) if(*p == '\\') { if(*++p) *cmd_out++ = *p++; } else *cmd_out++ = *p++; - if(*p == '\"') + if(*p == c) p++; } else *cmd_out++ = *p++; + } *cmd_out++ = '\0'; } diff --git a/uppsrc/Core/LocalProcess.h b/uppsrc/Core/LocalProcess.h index 5c72795ec..c48244564 100644 --- a/uppsrc/Core/LocalProcess.h +++ b/uppsrc/Core/LocalProcess.h @@ -62,6 +62,10 @@ public: bool Start(const char *cmdline, const char *envptr = NULL) { return DoStart(cmdline, false, envptr); } bool Start2(const char *cmdline, const char *envptr = NULL) { return DoStart(cmdline, true, envptr); } +#ifdef PLATFORM_POSIX + int GetPid() const { return pid; } +#endif + LocalProcess& ConvertCharset(bool b = true) { convertcharset = b; return *this; } LocalProcess& NoConvertCharset() { return ConvertCharset(false); } diff --git a/uppsrc/ide/Debug.cpp b/uppsrc/ide/Debug.cpp index a9be71230..f682a51e7 100644 --- a/uppsrc/ide/Debug.cpp +++ b/uppsrc/ide/Debug.cpp @@ -154,8 +154,8 @@ void Ide::BuildAndExtDebugFile() BuildAndDebug0(editfile); } -One GdbCreate(One host, const String& exefile, const String& cmdline); -One Gdb_MI2Create(One host, const String& exefile, const String& cmdline); +One GdbCreate(One host, const String& exefile, const String& cmdline, bool console); +One Gdb_MI2Create(One host, const String& exefile, const String& cmdline, bool console); #ifdef PLATFORM_WIN32 One CdbCreate(One host, const String& exefile, const String& cmdline); One PdbCreate(One host, const String& exefile, const String& cmdline); @@ -175,19 +175,22 @@ void Ide::BuildAndDebug(bool runto) host->ChDir(Nvl(rundir, GetFileFolder(target))); HideBottom(); editor.Disable(); + + bool console = FindIndex(SplitFlags(mainconfigparam, true), "GUI") < 0 || forceconsole; + #ifdef COMPILER_MSC if(builder == "GCC") if(gdbSelector) - debugger = Gdb_MI2Create(host, target, runarg); + debugger = Gdb_MI2Create(host, target, runarg, console); else - debugger = GdbCreate(host, target, runarg); + debugger = GdbCreate(host, target, runarg, console); else debugger = PdbCreate(host, target, runarg); #else if(gdbSelector) - debugger = Gdb_MI2Create(host, target, runarg); + debugger = Gdb_MI2Create(host, target, runarg, console); else - debugger = GdbCreate(host, target, runarg); + debugger = GdbCreate(host, target, runarg, console); #endif if(!debugger) return; debuglock = 0; diff --git a/uppsrc/ide/Debuggers/Dbg.cpp b/uppsrc/ide/Debuggers/Dbg.cpp index 11c8158ed..455522425 100644 --- a/uppsrc/ide/Debuggers/Dbg.cpp +++ b/uppsrc/ide/Debuggers/Dbg.cpp @@ -117,6 +117,8 @@ String Dbg::Cmd(const char *command) GuiSleep(sleep); Ctrl::ProcessEvents(); sleep = min(20, sleep + max(1, 3 * sleep / 2)); + if(TTYQuit()) + Stop(); } Unlock(); #ifdef _DEBUG @@ -141,6 +143,8 @@ String Dbg::FastCmd(const char *command) String s; // if(!lock) Sleep(0); + if(TTYQuit()) + Stop(); if(!dbg->Read(s)) { LLOG(result); PutVerbose(result); @@ -231,5 +235,4 @@ Dbg::Dbg() quickwatch.Icon(DbgImg::QuickWatch()); Transparent(); -// log.Open(ConfigFile("debug.log")); } diff --git a/uppsrc/ide/Debuggers/Debuggers.h b/uppsrc/ide/Debuggers/Debuggers.h index a35847ef0..1725aabcd 100644 --- a/uppsrc/ide/Debuggers/Debuggers.h +++ b/uppsrc/ide/Debuggers/Debuggers.h @@ -14,6 +14,14 @@ typedef uintptr_t adr_t; +#ifdef PLATFORM_POSIX +String CreateDebugTTY(); +void KillDebugTTY(); +bool TTYQuit(); +#endif + +String GdbCommand(bool console); + class DbgDisas : public Ctrl { public: virtual void Paint(Draw& w); @@ -162,11 +170,16 @@ struct Gdb : Dbg { void CopyStack(); void CopyDisas(); - bool Create(One host, const String& exefile, const String& cmdline); + bool Create(One host, const String& exefile, const String& cmdline, bool console); + + // Period check for killed console + TimeCallback periodic; + void Periodic(); typedef Gdb CLASSNAME; virtual ~Gdb(); + Gdb(); }; #include "Gdb_MI2.h" diff --git a/uppsrc/ide/Debuggers/Debuggers.upp b/uppsrc/ide/Debuggers/Debuggers.upp index ee7c9ce70..a66841845 100644 --- a/uppsrc/ide/Debuggers/Debuggers.upp +++ b/uppsrc/ide/Debuggers/Debuggers.upp @@ -6,11 +6,12 @@ uses HexView; file - MIValue.h, - MIValue.cpp, Debuggers.h, Debuggers.iml, Gdb.lay, + MIValue.h, + MIValue.cpp, + Terminal.cpp, Disas.cpp, Dbg.cpp, Gdb.cpp, diff --git a/uppsrc/ide/Debuggers/Gdb.cpp b/uppsrc/ide/Debuggers/Gdb.cpp index 48f0f0082..c339d8dc4 100644 --- a/uppsrc/ide/Debuggers/Gdb.cpp +++ b/uppsrc/ide/Debuggers/Gdb.cpp @@ -551,10 +551,10 @@ bool Gdb::Key(dword key, int count) return Ctrl::Key(key, count); } -bool Gdb::Create(One _host, const String& exefile, const String& cmdline) +bool Gdb::Create(One _host, const String& exefile, const String& cmdline, bool console) { host = _host; - dbg = host->StartProcess("gdb " + GetHostPath(exefile)); + dbg = host->StartProcess(GdbCommand(console) + GetHostPath(exefile)); if(!dbg) { Exclamation("Error invoking gdb !"); return false; @@ -593,12 +593,24 @@ Gdb::~Gdb() { IdeRemoveBottom(*this); IdeRemoveRight(disas); + KillDebugTTY(); } -One GdbCreate(One host, const String& exefile, const String& cmdline) +void Gdb::Periodic() +{ + if(TTYQuit()) + Stop(); +} + +Gdb::Gdb() +{ + periodic.Set(-50, THISBACK(Periodic)); +} + +One GdbCreate(One host, const String& exefile, const String& cmdline, bool console) { Gdb *dbg = new Gdb; - if(!dbg->Create(host, exefile, cmdline)) { + if(!dbg->Create(host, exefile, cmdline, console)) { delete dbg; return NULL; } diff --git a/uppsrc/ide/Debuggers/Gdb_MI2.cpp b/uppsrc/ide/Debuggers/Gdb_MI2.cpp index 7c029eb16..c98748a46 100644 --- a/uppsrc/ide/Debuggers/Gdb_MI2.cpp +++ b/uppsrc/ide/Debuggers/Gdb_MI2.cpp @@ -218,6 +218,12 @@ bool Gdb_MI2::Tip(const String& exp, CodeEditor::MouseTip& mt) // CONSTRUCTOR / DESTRUCTOR ///////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Gdb_MI2::Periodic() +{ + if(TTYQuit()) + Stop(); +} + Gdb_MI2::Gdb_MI2() { CtrlLayout(regs); @@ -319,12 +325,15 @@ Gdb_MI2::Gdb_MI2() started = false; stopped = false; + + periodic.Set(-50, THISBACK(Periodic)); } Gdb_MI2::~Gdb_MI2() { IdeRemoveBottom(*this); IdeRemoveRight(disas); + KillDebugTTY(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1716,10 +1725,10 @@ void Gdb_MI2::ExplorerMenu(Bar& bar) ////////////////////////////////////////////////////////////////////////////////////////////////////// // create GDB process and initializes it -bool Gdb_MI2::Create(One _host, const String& exefile, const String& cmdline) +bool Gdb_MI2::Create(One _host, const String& exefile, const String& cmdline, bool console) { host = _host; - dbg = host->StartProcess("gdb " + GetHostPath(exefile) + " --interpreter=mi -q"); + dbg = host->StartProcess(GdbCommand(console) + GetHostPath(exefile) + " --interpreter=mi -q"); if(!dbg) { Exclamation(t_("Error invoking gdb !")); return false; @@ -1776,10 +1785,10 @@ bool Gdb_MI2::Create(One _host, const String& exefile, const String& cmdli return true; } -One Gdb_MI2Create(One host, const String& exefile, const String& cmdline) +One Gdb_MI2Create(One host, const String& exefile, const String& cmdline, bool console) { Gdb_MI2 *dbg = new Gdb_MI2; - if(!dbg->Create(host, exefile, cmdline)) + if(!dbg->Create(host, exefile, cmdline, console)) { delete dbg; return NULL; diff --git a/uppsrc/ide/Debuggers/Gdb_MI2.h b/uppsrc/ide/Debuggers/Gdb_MI2.h index 8b64bdd94..9fd7d44a8 100644 --- a/uppsrc/ide/Debuggers/Gdb_MI2.h +++ b/uppsrc/ide/Debuggers/Gdb_MI2.h @@ -212,6 +212,10 @@ class Gdb_MI2 : public Debugger, public ParentCtrl // lock/unlock debugger controls void Lock(); void Unlock(); + + // Period check for killed console + TimeCallback periodic; + void Periodic(); String GetHostPath(const String& path) { return host->GetHostPath(path); } String GetLocalPath(const String& path) { return host->GetLocalPath(path); } @@ -233,7 +237,7 @@ class Gdb_MI2 : public Debugger, public ParentCtrl virtual bool Tip(const String& exp, CodeEditor::MouseTip& mt); // create GDB process and initializes it - bool Create(One _host, const String& exefile, const String& cmdline); + bool Create(One _host, const String& exefile, const String& cmdline, bool console); Gdb_MI2(); virtual ~Gdb_MI2(); diff --git a/uppsrc/ide/Debuggers/Terminal.cpp b/uppsrc/ide/Debuggers/Terminal.cpp new file mode 100644 index 000000000..b84fa19c3 --- /dev/null +++ b/uppsrc/ide/Debuggers/Terminal.cpp @@ -0,0 +1,93 @@ +#include "Debuggers.h" + +#ifdef PLATFORM_POSIX + +void Do_ps(VectorMap& pids, Index& ttys, const String& cmd) +{ + pids.Clear(); + ttys.Clear(); + Vector ps = Split(Sys(cmd), '\n'); + for(int i = 1; i < ps.GetCount(); i++) { + Vector ss = Split(ps[i], ' '); + if(ss.GetCount() >= 2) { + if(IsDigit(*ss[0]) && IsAlNum(*ss[1])) { + pids.Add(ss[1], ss[0]); + ttys.FindAdd(ss[1]); + } + } + } +} + +static VectorMap sPid; +static String sTTY; + +String CreateDebugTTY() +{ // The method is far from ideal and reliable, but should work most of time + sTTY.Clear(); + + Index tty0, tty; + Do_ps(sPid, tty0, "ps -A"); + + IGNORE_RESULT(chdir(GetHomeDirectory())); + + static const char *term[] = { + "/usr/bin/mate-terminal -e 'tail -f /dev/null'", + "/usr/bin/gnome-terminal -e 'tail -f /dev/null'", + "/usr/bin/konsole -e 'tail -f /dev/null'", + "/usr/bin/xterm -e 'tail -f /dev/null'", + }; + + for(int i = 0; i < __countof(term); i++) { + if(FileExists(Split(term[i], ' ')[0])) { + LocalProcess(term[i]).Detach(); + for(int i = 0; i < 10; i++) { // Wait for the new TTY to appear + Do_ps(sPid, tty, "ps -A"); + for(int i = 0; i < tty.GetCount(); i++) + if(tty0.Find(tty[i]) < 0) { + sTTY = tty[i]; + return "/dev/" + sTTY; + } + Sleep(200); + } + } + } + return Null; +} + +void KillDebugTTY() +{ + Index tty; + Do_ps(sPid, tty, "ps -A"); + if(sTTY.GetCount()) + for(int q = sPid.Find(sTTY); q >= 0; q = sPid.FindNext(q)) { + Sys("kill -9 " + sPid[q]); + } + sTTY.Clear(); +} + +bool TTYQuit() +{ + if(sTTY.GetCount()) { + int fd = open("/dev/" + sTTY, O_RDWR | O_NONBLOCK); + if(fd < 0) + return true; + close(fd); + return false; + } + return false; +} + +String GdbCommand(bool console) +{ + String gdb = "gdb "; +#ifdef PLATFORM_POSIX + if(console) { + String tty = CreateDebugTTY(); + if(tty.GetCount()) + gdb << "-tty=" << tty << ' '; + } +#endif + return gdb; +} + +#endif