[gnote] Add sharp::Process class



commit ed91480abb7148ebbbbcc817d6e087959a6fd13e
Author: Aurimas Äernius <aurisc4 gmail com>
Date:   Sun Jun 17 20:32:08 2012 +0300

    Add sharp::Process class

 src/Makefile.am       |    1 +
 src/sharp/process.cpp |  252 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/sharp/process.hpp |  101 ++++++++++++++++++++
 3 files changed, 354 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 7db47b8..e52107b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -104,6 +104,7 @@ libgnote_la_SOURCES = \
 	sharp/map.hpp \
 	sharp/modulefactory.hpp \
 	sharp/modulemanager.hpp sharp/modulemanager.cpp \
+	sharp/process.hpp sharp/process.cpp \
 	sharp/propertyeditor.hpp sharp/propertyeditor.cpp \
 	sharp/streamreader.hpp sharp/streamreader.cpp \
 	sharp/streamwriter.hpp sharp/streamwriter.cpp \
diff --git a/src/sharp/process.cpp b/src/sharp/process.cpp
new file mode 100644
index 0000000..9632084
--- /dev/null
+++ b/src/sharp/process.cpp
@@ -0,0 +1,252 @@
+/*
+ * gnote
+ *
+ * Copyright (C) 2012 Aurimas Cernius
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <cerrno>
+#include <cstdlib>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+
+#include "debug.hpp"
+#include "process.hpp"
+
+
+namespace sharp {
+
+Process::Process()
+  : m_exit_code(-1)
+  , m_pid(-1)
+  , m_stdout(0)
+  , m_stderr(0)
+{
+}
+
+void Process::start()
+{
+  if(m_file_name == "") {
+    return;
+  }
+  int stdo[2];
+  int stde[2];
+  if(m_redirect_stdout) {
+    pipe(stdo);
+  }
+  if(m_redirect_stderr) {
+    pipe(stde);
+  }
+  m_pid = fork();
+  if(m_pid == 0) {
+    redirect_output(m_redirect_stdout, 1, stdo);
+    redirect_output(m_redirect_stderr, 2, stde);
+    char **argv = (char**) std::malloc((m_args.size() + 2) * sizeof(char*));
+    argv[0] = strdup(m_file_name.c_str());
+    argv[m_args.size() + 1] = NULL;
+    for(unsigned i = 0; i < m_args.size(); ++i) {
+      argv[i+1] = strdup(m_args[i].c_str());
+    }
+    execv(m_file_name.c_str(), argv);
+    LOG_OUT("execv() failed: %s", execv_error(errno));
+    _exit(1);
+  }
+  else {
+    if(m_redirect_stdout) {
+      close(stdo[1]);
+      m_stdout = stdo[0];
+    }
+    if(m_redirect_stdout) {
+      close(stde[1]);
+      m_stderr = stde[0];
+    }
+  }
+}
+
+void Process::redirect_output(bool redirect, int fileno, int *pipedes)
+{
+  if(redirect) {
+    close(fileno);
+    dup2(pipedes[1], fileno);
+    close(pipedes[1]);
+    fcntl(fileno, F_SETFL, O_NONBLOCK);
+  }
+  else {
+    close(pipedes[1]);
+    close(fileno);
+  }
+  close(pipedes[0]);
+}
+
+void Process::wait_for_exit()
+{
+  if(m_pid < 0) {
+    return;
+  }
+  int status = -1;
+  waitpid(m_pid, &status, 0);
+  if(WIFEXITED(status)) {
+    m_exit_code = WEXITSTATUS(status);
+  }
+}
+
+bool Process::wait_for_exit(unsigned)
+{
+  // TODO: make timeout work
+  wait_for_exit();
+  return true;
+}
+
+bool Process::standard_output_eof()
+{
+  return eof(m_stdout_stream, m_stdout);
+}
+
+std::string Process::standard_output_read_line()
+{
+  return read_line(m_stdout_stream, m_stdout);
+}
+
+bool Process::standard_error_eof()
+{
+  return eof(m_stderr_stream, m_stderr);
+}
+
+std::string Process::standard_error_read_line()
+{
+  return read_line(m_stderr_stream, m_stderr);
+}
+
+bool Process::eof(std::stringstream & stream, int & m_file)
+{
+  if(m_file == 0 && stream.tellg() < 0) {
+    return true;
+  }
+
+  if(m_file) {
+    perform_read(stream, m_file);
+  }
+  return !m_file && stream.tellg() < 0;
+}
+
+std::string Process::read_line(std::stringstream & stream, int & m_file)
+{
+  while(m_file && !line_available(stream)) {
+    if(!perform_read(stream, m_file)) {
+      break;
+    }
+  }
+
+  std::string line;
+  std::getline(stream, line);
+  return line;
+}
+
+bool Process::line_available(std::stringstream & stream)
+{
+  if(stream.tellg() < 0) {
+    return false;
+  }
+
+  std::string contents = stream.str();
+  if(contents.size() <= unsigned(stream.tellg())) {
+    return false;
+  }
+
+  return contents.substr(stream.tellg()).find('\n') != std::string::npos;
+}
+
+bool Process::perform_read(std::stringstream & stream, int & m_file)
+{
+  while(true) {
+    char buf[255];
+    int read_count = read(m_file, buf, sizeof(buf));
+    if(read_count < 0) {
+      return false;
+    }
+    else if(read_count == 0) {
+      if(errno == EAGAIN) {
+        int status;
+        waitpid(m_pid, &status, WNOHANG);
+        if(WIFEXITED(status) || WIFSIGNALED(status)) {
+          close(m_file);
+          m_file = 0;
+          m_exit_code = WEXITSTATUS(status);
+          return false;
+        }
+	continue;
+      }
+      else {
+	close(m_file);
+	m_file = 0;
+        return false;
+      }
+    }
+    else {
+      stream.write(buf, read_count);
+      break;
+    }
+  }
+  return true;
+}
+
+const char *Process::execv_error(int error)
+{
+  switch(error) {
+  case EACCES:
+    return "EACCES";
+  case EPERM:
+    return "EPERM";
+  case E2BIG:
+    return "E2BIG";
+  case ENOEXEC:
+    return "ENOEXEC";
+  case EFAULT:
+    return "EFAULT";
+  case ENAMETOOLONG:
+    return "ENAMETOOLONG";
+  case ENOENT:
+    return "ENOENT";
+  case ENOMEM:
+    return "ENOMEM";
+  case ENOTDIR:
+    return "ENOTDIR";
+  case ELOOP:
+    return "ELOOP";
+  case ETXTBSY:
+    return "ETXTBSY";
+  case EIO:
+    return "EIO";
+  case ENFILE:
+    return "ENFILE";
+  case EMFILE:
+    return "EMFILE";
+  case EINVAL:
+    return "EINVAL";
+  case EISDIR:
+    return "EISDIR";
+  case ELIBBAD:
+    return "ELIBBAD";
+  default:
+    return "Unknown";
+  }
+}
+
+
+}
+
diff --git a/src/sharp/process.hpp b/src/sharp/process.hpp
new file mode 100644
index 0000000..4d5b2f4
--- /dev/null
+++ b/src/sharp/process.hpp
@@ -0,0 +1,101 @@
+/*
+ * gnote
+ *
+ * Copyright (C) 2012 Aurimas Cernius
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _SHARP_PROCESS_HPP_
+#define _SHARP_PROCESS_HPP_
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+
+namespace sharp {
+
+class Process
+{
+public:
+  Process();
+  void start();
+  void wait_for_exit();
+  bool wait_for_exit(unsigned timeout);
+  bool standard_output_eof();
+  std::string standard_output_read_line();
+  bool standard_error_eof();
+  std::string standard_error_read_line();
+  int exit_code() const
+    {
+      return m_exit_code;
+    }
+  std::string file_name() const
+    {
+      return m_file_name;
+    }
+  void file_name(const std::string & fname)
+    {
+      m_file_name = fname;
+    }
+  std::vector<std::string> arguments() const
+    {
+      return m_args;
+    }
+  void arguments(const std::vector<std::string> & args)
+    {
+      m_args = args;
+    }
+  bool redirect_standard_output() const
+    {
+      return m_redirect_stdout;
+    }
+  void redirect_standard_output(bool redirect)
+    {
+      m_redirect_stdout = redirect;
+    }
+  bool redirect_standard_error() const
+    {
+      return m_redirect_stderr;
+    }
+  void redirect_standard_error(bool redirect)
+    {
+      m_redirect_stderr = redirect;
+    }
+private:
+  static const char *execv_error(int error);
+  static void redirect_output(bool redirect, int fileno, int *pipedes);
+
+  bool eof(std::stringstream & stream, int & m_file);
+  std::string read_line(std::stringstream & stream, int & m_file);
+  bool line_available(std::stringstream & stream);
+  bool perform_read(std::stringstream & stream, int & m_file);
+
+  int m_exit_code;
+  std::string m_file_name;
+  std::vector<std::string> m_args;
+  bool m_redirect_stdout;
+  bool m_redirect_stderr;
+  int m_pid;
+  int m_stdout;
+  std::stringstream m_stdout_stream;
+  int m_stderr;
+  std::stringstream m_stderr_stream;
+};
+
+}
+
+#endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]