aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbutl/process-io.cxx81
-rw-r--r--libbutl/process-io.hxx30
-rw-r--r--libbutl/process.cxx84
-rw-r--r--libbutl/process.hxx43
-rw-r--r--libbutl/process.ixx28
-rw-r--r--tests/process/driver.cxx14
6 files changed, 167 insertions, 113 deletions
diff --git a/libbutl/process-io.cxx b/libbutl/process-io.cxx
deleted file mode 100644
index 0be3a77..0000000
--- a/libbutl/process-io.cxx
+++ /dev/null
@@ -1,81 +0,0 @@
-// file : libbutl/process-io.cxx -*- C++ -*-
-// license : MIT; see accompanying LICENSE file
-
-#include <libbutl/process-io.hxx>
-
-#include <cstring> // strchr()
-
-#include <libbutl/path-io.hxx>
-
-using namespace std;
-
-namespace butl
-{
- // process_env
- //
- ostream&
- operator<< (ostream& o, const process_env& env)
- {
- bool first (true);
- const dir_path* cwd (env.cwd);
-
- if (cwd != nullptr && !cwd->empty ())
- {
- if (cwd->string ().find (' ') != string::npos)
- o << "PWD=\"" << *cwd << '"';
- else
- o << "PWD=" << *cwd;
-
- first = false;
- }
-
- if (env.vars != nullptr)
- {
- for (const char* const* ev (env.vars); *ev != nullptr; ++ev)
- {
- if (first)
- first = false;
- else
- o << ' ';
-
- const char* v (*ev);
-
- // If there is no `=` in the string, then this is just a name
- // (variable unset) and we print it as the empty string assignment.
- //
- const char* eq (strchr (v, '='));
-
- // If there is the space character in the string, then we quote the
- // variable value, unless this is the variable name that contains the
- // space character in which case we quote the whole (potentially
- // broken) assignment.
- //
- const char* sp (strchr (v, ' '));
-
- if (eq != nullptr) // Variable assignment?
- {
- if (sp == nullptr) // No space?
- {
- o << v;
- }
- else if (eq < sp) // Space in the value?
- {
- o.write (v, eq - v + 1); // Name and '='.
- o << '"' << eq + 1 << '"'; // Quoted value.
- }
- else // Space in the name.
- o << '"' << v << '"';
- }
- else // Variable unset.
- {
- if (sp == nullptr) // No space?
- o << v << '=';
- else // Space in the name.
- o << '"' << v << "=\"";
- }
- }
- }
-
- return o;
- }
-}
diff --git a/libbutl/process-io.hxx b/libbutl/process-io.hxx
index 29d6d8b..9b1d5cc 100644
--- a/libbutl/process-io.hxx
+++ b/libbutl/process-io.hxx
@@ -7,8 +7,6 @@
#include <libbutl/process.hxx>
-#include <libbutl/export.hxx>
-
namespace butl
{
inline std::ostream&
@@ -24,27 +22,9 @@ namespace butl
return o;
}
- // Print the environment variables and the current working directory (if
- // specified) in a POSIX shell command line notation. The process path
- // itself is not printed. For example:
- //
- // LC_ALL=C
- //
- // If an environment variable is in the `name` rather than in the
- // `name=value` form, then it is considered unset. Since there is no POSIX
- // way to unset a variable on the command line, this information is printed
- // as `name=` (ambiguous with assigning an empty value but the two cases are
- // normally handled in the same way). For example:
- //
- // PATH= LC_ALL=C
- //
- // Note that since there is no POSIX way to change the current working
- // directory of a command to be executed, this information is printed in a
- // pseudo-notation by assigning to PWD (which, according POSIX, would result
- // in the undefined behavior of the cwd utility). For example:
- //
- // PWD=/tmp LC_ALL=C
- //
- LIBBUTL_SYMEXPORT std::ostream&
- operator<< (std::ostream&, const process_env&);
+ inline std::ostream&
+ operator<< (std::ostream& o, const process_env& e)
+ {
+ return to_stream (o, e);
+ }
}
diff --git a/libbutl/process.cxx b/libbutl/process.cxx
index f6c1745..38afb54 100644
--- a/libbutl/process.cxx
+++ b/libbutl/process.cxx
@@ -116,6 +116,7 @@ namespace butl
shared_mutex process_spawn_mutex; // Out of module purview.
}
+#include <libbutl/path-io.hxx>
#include <libbutl/utility.hxx> // icasecmp()
#include <libbutl/fdstream.hxx> // fdopen_null()
@@ -157,6 +158,89 @@ namespace butl
return r;
}
+ // process_env
+ //
+ std::ostream&
+ to_stream (std::ostream& o,
+ const process_env& env,
+ process_env_format f)
+ {
+ bool first (true);
+
+ if ((f & process_env_format::cwd) != process_env_format::none)
+ {
+ const dir_path* cwd (env.cwd);
+
+ if (cwd != nullptr && !cwd->empty ())
+ {
+ if (cwd->string ().find (' ') != string::npos)
+ o << "PWD=\"" << *cwd << '"';
+ else
+ o << "PWD=" << *cwd;
+
+ first = false;
+ }
+ }
+
+ if ((f & process_env_format::vars) != process_env_format::none &&
+ env.vars != nullptr)
+ {
+ for (const char* const* ev (env.vars); *ev != nullptr; ++ev)
+ {
+ if (first)
+ first = false;
+ else
+ o << ' ';
+
+ const char* v (*ev);
+
+ // If there is no `=` in the string, then this is just a name
+ // (variable unset) and we print it as the empty string assignment.
+ //
+ const char* eq (strchr (v, '='));
+
+ // If there is the space character in the string, then we quote the
+ // variable value, unless this is the variable name that contains the
+ // space character in which case we quote the whole (potentially
+ // broken) assignment.
+ //
+ const char* sp (strchr (v, ' '));
+
+ if (eq != nullptr) // Variable assignment?
+ {
+ if (sp == nullptr) // No space?
+ {
+ o << v;
+ }
+ else if (eq < sp) // Space in the value?
+ {
+ o.write (v, eq - v + 1); // Name and '='.
+ o << '"' << eq + 1 << '"'; // Quoted value.
+ }
+ else // Space in the name.
+ o << '"' << v << '"';
+ }
+ else // Variable unset.
+ {
+ if (sp == nullptr) // No space?
+ o << v << '=';
+ else // Space in the name.
+ o << '"' << v << "=\"";
+ }
+ }
+ }
+
+ if ((f & process_env_format::path) != process_env_format::none)
+ {
+ if (!first)
+ o << ' ';
+
+ o << env.path->recall_string ();
+ }
+
+ return o;
+ }
+
// process
//
static process_path
diff --git a/libbutl/process.hxx b/libbutl/process.hxx
index bbb7c89..d6028af 100644
--- a/libbutl/process.hxx
+++ b/libbutl/process.hxx
@@ -774,6 +774,49 @@ namespace butl
small_vector<const char*, 3> vars_;
};
+ // Print the environment variables, the current working directory, and the
+ // process recall path, or some subset of this information. The environment
+ // variables are printed in the POSIX shell command line notation. For
+ // example:
+ //
+ // LC_ALL=C program
+ //
+ // If an environment variable is in the `name` rather than in the
+ // `name=value` form, then it is considered unset. Since there is no POSIX
+ // way to unset a variable on the command line, this information is printed
+ // as `name=` (ambiguous with assigning an empty value but the two cases are
+ // normally handled in the same way). For example:
+ //
+ // PATH= LC_ALL=C program
+ //
+ // Since there is no POSIX way to change the current working directory of a
+ // command to be executed, this information is printed in a pseudo-notation
+ // by assigning to PWD (which, according POSIX, would result in the
+ // undefined behavior of the cwd utility). For example:
+ //
+ // PWD=/tmp LC_ALL=C program
+ //
+ enum class process_env_format: std::uint16_t
+ {
+ none = 0x00,
+ path = 0x01,
+ cwd = 0x02,
+ vars = 0x04,
+ all = path | cwd | vars
+ };
+
+ process_env_format operator& (process_env_format, process_env_format);
+ process_env_format operator| (process_env_format, process_env_format);
+ process_env_format operator&= (process_env_format&, process_env_format);
+ process_env_format operator|= (process_env_format&, process_env_format);
+
+ LIBBUTL_SYMEXPORT std::ostream&
+ to_stream (std::ostream&,
+ const process_env&,
+ process_env_format = process_env_format::all);
+
+ // Run process.
+ //
template <typename I,
typename O,
typename E,
diff --git a/libbutl/process.ixx b/libbutl/process.ixx
index e4db474..47f10d0 100644
--- a/libbutl/process.ixx
+++ b/libbutl/process.ixx
@@ -482,4 +482,32 @@ namespace butl
return *this;
}
+
+ inline process_env_format
+ operator&= (process_env_format& x, process_env_format y)
+ {
+ return x = static_cast<process_env_format> (
+ static_cast<std::uint16_t> (x) &
+ static_cast<std::uint16_t> (y));
+ }
+
+ inline process_env_format
+ operator|= (process_env_format& x, process_env_format y)
+ {
+ return x = static_cast<process_env_format> (
+ static_cast<std::uint16_t> (x) |
+ static_cast<std::uint16_t> (y));
+ }
+
+ inline process_env_format
+ operator& (process_env_format x, process_env_format y)
+ {
+ return x &= y;
+ }
+
+ inline process_env_format
+ operator| (process_env_format x, process_env_format y)
+ {
+ return x |= y;
+ }
}
diff --git a/tests/process/driver.cxx b/tests/process/driver.cxx
index 1ee5710..4fef2e0 100644
--- a/tests/process/driver.cxx
+++ b/tests/process/driver.cxx
@@ -500,31 +500,31 @@ main (int argc, const char* argv[])
auto str = [] (const process_env& env)
{
ostringstream os;
- os << env;
+ to_stream (os, env);
return os.str ();
};
- process_path p;
+ process_path p (path ("program"));
- assert (str (process_env (p)) == "");
+ assert (str (process_env (p)) == "program");
{
dir_path d ("dir");
dir_path ds ("d ir");
- assert (str (process_env (p, d)) == "PWD=dir");
- assert (str (process_env (p, ds)) == "PWD=\"d ir\"");
+ assert (str (process_env (p, d)) == "PWD=dir program");
+ assert (str (process_env (p, ds)) == "PWD=\"d ir\" program");
}
{
dir_path ed; // Empty.
const char* vars[] = {nullptr};
- assert (str (process_env (p, ed, vars)) == "");
+ assert (str (process_env (p, ed, vars)) == "program");
}
{
const char* vars[] = {"A=B", "A=B C", "A B=C", "A", "A B", nullptr};
assert (str (process_env (p, vars)) ==
- "A=B A=\"B C\" \"A B=C\" A= \"A B=\"");
+ "A=B A=\"B C\" \"A B=C\" A= \"A B=\" program");
}
}
}