+/* $Id$
+
+This file is part of gldbg
+Copyright © 2009 Mikko Rasa, Mikkosoft Productions
+Distributed under the GPL
+*/
+
+#include <cstdlib>
+#include <cerrno>
+#include <cstring>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <msp/core/except.h>
+#include <msp/fs/dir.h>
+#include <msp/io/print.h>
+#include <msp/strings/lexicalcast.h>
+#include "gldbg.h"
+#include "glprint.h"
+
+using namespace std;
+using namespace Msp;
+
+Application::RegApp<GlDbg> GlDbg::reg;
+
+GlDbg::GlDbg(int argc, char **argv):
+ pid(0),
+ sock_fd(-1),
+ glprint(glprint_new(0, 16384))
+{
+ libdir = FS::get_sys_lib_dir(argv[0], "gldbg");
+ args.assign(argv+1, argv+argc);
+}
+
+int GlDbg::main()
+{
+ catch_signal(SIGINT);
+ launch();
+
+ Application::main();
+}
+
+void GlDbg::tick()
+{
+ int status;
+ int ret = waitpid(pid, &status, WNOHANG);
+ if(ret==pid)
+ {
+ if(WIFEXITED(status) || WIFSIGNALED(status))
+ {
+ IO::print("Target process exited\n");
+ exit(0);
+ }
+ }
+
+ pollfd pfd = { sock_fd, POLLIN, 0 };
+ ret = poll(&pfd, 1, -1);
+ if(ret>0)
+ {
+ char rbuf[1024];
+ ret = read(sock_fd, rbuf, 1024);
+ if(ret>0)
+ {
+ buffer.append(rbuf, ret);
+ while(buffer.size()>buf_offset)
+ {
+ int ret = gldecoder_decode(glprint, buffer.data()+buf_offset, buffer.size()-buf_offset);
+ if(ret<0)
+ break;
+ buf_offset += ret;
+ IO::print("%s\n", glprint_get_buffer(glprint));
+ }
+ if(buf_offset>8192)
+ {
+ buffer.erase(0, buf_offset);
+ buf_offset=0;
+ }
+ }
+ }
+}
+
+void GlDbg::launch()
+{
+ int fds[2];
+ socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+ sock_fd = fds[0];
+
+ pid = fork();
+ if(pid==0)
+ {
+ string fd_str = lexical_cast(fds[1]);
+ setenv("LD_PRELOAD", (libdir/"glwrap.so").str().c_str(), true);
+ setenv("GLWRAP_FD", fd_str.c_str(), true);
+ close(fds[0]);
+ std::vector<char *> argv(args.size()+1);
+ for(unsigned i=0; i<args.size(); ++i)
+ argv[i] = strdup(args[i].c_str());
+ argv[args.size()] = 0;
+ execvp(argv[0], &argv[0]);
+ ::exit(127);
+ }
+ else if(pid>0)
+ {
+ close(fds[1]);
+ }
+ else
+ {
+ throw SystemError("Could not launch process", errno);
+ }
+}