From df1ef68cd8e8582724ce1192bfc202e0b9aeaf0c Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Tue, 28 Sep 2021 19:24:31 +0300 Subject: Get rid of C++ modules related code and rename *.mxx files to *.hxx --- libbutl/command.hxx | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 libbutl/command.hxx (limited to 'libbutl/command.hxx') diff --git a/libbutl/command.hxx b/libbutl/command.hxx new file mode 100644 index 0000000..fb7258f --- /dev/null +++ b/libbutl/command.hxx @@ -0,0 +1,107 @@ +// file : libbutl/command.hxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#pragma once + +#include +#include +#include // size_t +#include + +#include +#include + +#include + +namespace butl +{ + // Run a process or a builtin, interpreting the command line as + // whitespace-separated, potentially quoted program path/builtin name, + // arguments, and redirects. Throw std::invalid_argument on the parsing + // error, ios::failure on the underlying OS error, process_error on the + // process running error and std::system_error on the builtin running error. + // + // To run a system utility rather than a builtin prefix its name with `^`, + // for example: + // + // ^cat --squeeze-blank file + // + // The process environment path is unused and must point to the empty + // process path. + // + // Currently only the following stdout redirects are supported: + // + // >file # Overwrite file. + // >>file # Append to file. + // + // In particular, the file descriptor cannot be specified. The file path can + // optionally be separated from '>' by whitespaces. Note that redirects are + // distinguished from arguments by the presence of leading '>' and prior to + // possible substitutions (so the redirect character cannot be the result of + // a substitution; see below). + // + // The relative redirect file paths are completed using the command + // current working directory. Note that if it is altered via the process + // environment, then the new value is used. + // + // The command line elements (program, arguments, etc) may optionally + // contain substitutions - variable names enclosed with the substitution + // symbol ('@' by default) - which are replaced with the corresponding + // variable values to produce the actual command. Variable names must not + // contain whitespaces and an attempt to substitute an unknown or a + // malformed variable is an error. Double substitution character ('@@' by + // default) is an escape sequence. + // + // If the variable map is absent, then '@' has no special meaning and is + // treated as a regular character. + // + // The callback function, if specified, is called prior to running the + // command process with the substituted command elements and including + // redirects which will be in the "canonical" form (single argument without + // space after '>'). The callback can be used, for example, for tracing the + // resulting command line, etc. + // + using command_substitution_map = std::map; + using command_callback = void (const char* const args[], std::size_t n); + + LIBBUTL_SYMEXPORT process_exit + command_run (const std::string& command, + const optional& = nullopt, + const optional& = nullopt, + char subst = '@', + const std::function& = {}); + + // Reusable substitution utility functions. + // + // Unlike command_run(), these support different opening and closing + // substitution characters (e.g., ). Note that unmatched closing + // characters are treated literally and there is no support for their + // escaping (which would only be necessary if we needed to support variable + // names containing the closing character). + + // Perform substitutions in a string. The second argument should be the + // position of the openning substitution character in the passed string. + // Throw invalid_argument for a malformed substitution or an unknown + // variable name. + // + LIBBUTL_SYMEXPORT std::string + command_substitute (const std::string&, std::size_t, + const command_substitution_map&, + char open, char close); + + // As above but using a callback instead of a map. + // + // Specifically, on success, the callback should substitute the specified + // variable in out by appending its value and returning true. On failure, + // the callback can either throw invalid_argument or return false, in which + // case the standard "unknown substitution variable ..." exception will be + // thrown. + // + using command_substitution_callback = + bool (const std::string& var, std::string& out); + + LIBBUTL_SYMEXPORT std::string + command_substitute (const std::string&, std::size_t, + const std::function&, + char open, char close); +} -- cgit v1.1