diff options
-rw-r--r-- | libbutl/process-io.cxx | 81 | ||||
-rw-r--r-- | libbutl/process-io.hxx | 30 | ||||
-rw-r--r-- | libbutl/process.cxx | 84 | ||||
-rw-r--r-- | libbutl/process.hxx | 43 | ||||
-rw-r--r-- | libbutl/process.ixx | 28 | ||||
-rw-r--r-- | tests/process/driver.cxx | 14 |
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"); } } } |