summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/pbd/pbd/system_exec.h22
-rw-r--r--libs/pbd/system_exec.cc113
2 files changed, 121 insertions, 14 deletions
diff --git a/libs/pbd/pbd/system_exec.h b/libs/pbd/pbd/system_exec.h
index cf8518f547..dc17ced2f6 100644
--- a/libs/pbd/pbd/system_exec.h
+++ b/libs/pbd/pbd/system_exec.h
@@ -33,6 +33,8 @@
#include <string>
#include <pthread.h>
#include <signal.h>
+#include <map>
+
#ifdef NOPBD /* outside ardour */
#include <sigc++/bind.h>
#include <sigc++/signal.h>
@@ -83,8 +85,26 @@ class SystemExec
*
*/
SystemExec (std::string c, char ** a);
+
+ /** similar to \ref SystemExec but expects a whole command line, and
+ * handles some simple escape sequences.
+ *
+ * @param command complete command-line to be executed
+ * @param subs a map of <char, std::string> listing the % substitutions to
+ * be made.
+ *
+ * creates an argv array from the given command string, splitting into
+ * parameters at spaces.
+ * "\ " is non-splitting space, "\\" (and "\" at end of command) as "\",
+ * for "%<char>", <char> is looked up in subs and the corresponding string
+ * substituted. "%%" (and "%" at end of command)
+ * returns an argv array suitable for creating a new SystemExec with
+ */
+ SystemExec (std::string command, const std::map<char, std::string> subs);
+
virtual ~SystemExec ();
+
/** fork and execute the given program
*
* @param stderr_mode select what to do with program's standard error
@@ -171,6 +191,7 @@ class SystemExec
int nicelevel; ///< process nice level - defaults to 0
void make_argp(std::string);
+ void make_argp_escaped(std::string command, const std::map<char, std::string> subs);
void make_envp();
char **argp;
@@ -187,6 +208,7 @@ class SystemExec
#else
pid_t pid;
#endif
+ void init ();
pthread_mutex_t write_lock;
int fdin; ///< file-descriptor for writing to child's STDIN. This variable is identical to pin[1] but also used as status check if the stdin pipe is open: <0 means closed.
diff --git a/libs/pbd/system_exec.cc b/libs/pbd/system_exec.cc
index d26eedad6d..f270364660 100644
--- a/libs/pbd/system_exec.cc
+++ b/libs/pbd/system_exec.cc
@@ -144,9 +144,8 @@ static int close_allv(const int except_fds[]) {
}
#endif /* not on windows */
-
-SystemExec::SystemExec (std::string c, std::string a)
- : cmd(c)
+void
+SystemExec::init ()
{
pthread_mutex_init(&write_lock, NULL);
thread_active=false;
@@ -154,12 +153,19 @@ SystemExec::SystemExec (std::string c, std::string a)
pin[1] = -1;
nicelevel = 0;
envp = NULL;
- argp = NULL;
#ifdef __WIN32__
stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE;
stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE;
stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE;
#endif
+}
+
+SystemExec::SystemExec (std::string c, std::string a)
+ : cmd(c)
+{
+ init ();
+
+ argp = NULL;
make_envp();
make_argp(a);
}
@@ -167,21 +173,100 @@ SystemExec::SystemExec (std::string c, std::string a)
SystemExec::SystemExec (std::string c, char **a)
: cmd(c) , argp(a)
{
- pthread_mutex_init(&write_lock, NULL);
- thread_active=false;
- pid = 0;
- pin[1] = -1;
- nicelevel = 0;
- envp = NULL;
+ init ();
+
#ifdef __WIN32__
- stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE;
- stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE;
- stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE;
make_wargs(a);
#endif
make_envp();
}
+SystemExec::SystemExec (std::string command, const std::map<char, std::string> subs)
+{
+ init ();
+ make_argp_escaped(command, subs);
+ cmd = argp[0];
+ // cmd = strdup(argp[0]);
+ make_envp();
+}
+
+void
+SystemExec::make_argp_escaped(std::string command, const std::map<char, std::string> subs)
+{
+
+ int inquotes = 0;
+ int n = 0;
+ size_t i = 0;
+ std::string arg = "";
+
+ argp = (char **) malloc(sizeof(char *));
+
+ for (i = 0; i < command.length(); i++) {
+ char c = command.c_str()[i];
+ if (inquotes) {
+ if (c == '"') {
+ inquotes = 0;
+ } else {
+ // still in quotes - just copy
+ arg += c;
+ }
+ } else switch (c) {
+ case '%' :
+ c = command.c_str()[++i];
+ if (c == '%' || c == '\0') {
+ // "%%", "%" at end-of-string => "%"
+ arg += '%';
+ } else {
+ // search subs for string to substitute for char
+ std::map<char, std::string>::const_iterator s = subs.find(c);
+ if (s != subs.end()) {
+ // found substitution
+ arg += s->second;
+ } else {
+ // not a valid substitution, just copy
+ arg += '%';
+ arg += c;
+ }
+ }
+ break;
+ case '\\':
+ c = command.c_str()[++i];
+ switch (c) {
+ case ' ' :
+ case '"' : arg += c; break; // "\\", "\" at end-of-string => "\"
+ case '\0':
+ case '\\': arg += '\\'; break;
+ default : arg += '\\'; arg += c; break;
+ }
+ break;
+ case '"' :
+ inquotes = 1;
+ break;
+ case ' ' :
+ case '\t':
+ if (arg.length() > 0) {
+ // if there wasn't already a space or tab, start a new parameter
+ argp = (char **) realloc(argp, (n + 2) * sizeof(char *));
+ argp[n++] = strdup (arg.c_str());
+ arg = "";
+ }
+ break;
+ default :
+ arg += c;
+ break;
+ }
+ }
+ argp[n] = NULL;
+
+ char *p = argp[0];
+ n = 0;
+ do {
+ std::cerr << "argv[" << n << "] == \"" << p << "\"" << std::endl;
+ p = argp[n++];
+ } while (p);
+
+}
+
SystemExec::~SystemExec ()
{
terminate ();
@@ -502,7 +587,7 @@ SystemExec::make_argp(std::string args) {
*cp2 = '\0';
argp[argn++] = strdup(cp1);
cp1 = cp2 + 1;
- argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
+ argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
}
}
if (cp2 != cp1) {