diff options
Diffstat (limited to 'build2/utility.hxx')
-rw-r--r-- | build2/utility.hxx | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/build2/utility.hxx b/build2/utility.hxx new file mode 100644 index 0000000..5f5aa1d --- /dev/null +++ b/build2/utility.hxx @@ -0,0 +1,436 @@ +// file : build2/utility.hxx -*- C++ -*- +// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BUILD2_UTILITY_HXX +#define BUILD2_UTILITY_HXX + +#include <tuple> // make_tuple() +#include <memory> // make_shared() +#include <string> // to_string() +#include <utility> // move(), forward(), declval(), make_pair() +#include <cassert> // assert() +#include <iterator> // make_move_iterator() +#include <algorithm> // * +#include <functional> // ref(), cref() + +#include <libbutl/ft/lang.hxx> + +#include <libbutl/utility.hxx> // combine_hash(), reverse_iterate(), case*(), + // etc + +#include <unordered_set> + +#include <build2/types.hxx> +#include <build2/b-options.hxx> +#include <build2/version.hxx> + +namespace build2 +{ + using std::move; + using std::forward; + using std::declval; + + using std::ref; + using std::cref; + + using std::make_pair; + using std::make_tuple; + using std::make_shared; + using std::make_move_iterator; + using std::to_string; + using std::stoul; + using std::stoull; + + // <libbutl/utility.hxx> + // + using butl::reverse_iterate; + using butl::compare_c_string; + using butl::compare_pointer_target; + //using butl::hash_pointer_target; + using butl::combine_hash; + using butl::casecmp; + using butl::case_compare_string; + using butl::case_compare_c_string; + using butl::lcase; + using butl::alpha; + using butl::alnum; + using butl::digit; + + using butl::exception_guard; + using butl::make_exception_guard; + + using butl::throw_generic_error; + + // Basic string utilities. + // + + // Trim leading/trailing whitespacec, including '\r'. + // + string& + trim (string&); + + // Find the beginning and end poistions of the next word. Return the size + // of the word or 0 and set b = e = n if there are no more words. For + // example: + // + // for (size_t b (0), e (0); next_word (s, b, e); ) + // { + // string w (s, b, e - b); + // } + // + // Or: + // + // for (size_t b (0), e (0), n; n = next_word (s, b, e, ' ', ','); ) + // { + // string w (s, b, n); + // } + // + // The second version examines up to the n'th character in the string. + // + size_t + next_word (const string&, size_t& b, size_t& e, + char d1 = ' ', char d2 = '\0'); + + size_t + next_word (const string&, size_t n, size_t& b, size_t& e, + char d1 = ' ', char d2 = '\0'); + + // Command line options. + // + extern options ops; + + // Build system driver process path (argv0.initial is argv[0]). + // + extern process_path argv0; + + // Build system driver version and check. + // + extern const standard_version build_version; + + class location; + + void + check_build_version (const standard_version_constraint&, const location&); + + // Work/home directories (must be initialized in main()) and relative path + // calculation. + // + extern dir_path work; + extern dir_path home; + + // By default this points to work. Setting this to something else should + // only be done in tightly controlled, non-concurrent situations (e.g., + // state dump). If it is empty, then relative() below returns the original + // path. + // + extern const dir_path* relative_base; + + // If possible and beneficial, translate an absolute, normalized path into + // relative to the relative_base directory, which is normally work. Note + // that if the passed path is the same as relative_base, then this function + // returns empty path. + // + template <typename K> + basic_path<char, K> + relative (const basic_path<char, K>&); + + // In addition to calling relative(), this function also uses shorter + // notations such as '~/'. For directories the result includes the trailing + // slash. If the path is the same as base, returns "./" if current is true + // and empty string otherwise. + // + string + diag_relative (const path&, bool current = true); + + // Basic process utilities. + // + + // Start a process with the specified arguments printing the command at + // verbosity level 3 and higher. Redirect STDOUT to a pipe. If error is + // false, then redirecting STDERR to STDOUT (this can be used to suppress + // diagnostics from the child process). Issue diagnostics and throw failed + // in case of an error. + // + process_path + run_search (const char*& args0); + + process_path + run_search (const path&, bool init, const dir_path& fallback = dir_path ()); + + process + run_start (const process_path&, const char* args[], bool error); + + inline process + run_start (const char* args[], bool error) + { + return run_start (run_search (args[0]), args, error); + } + + bool + run_finish (const char* args[], bool error, process&, const string&); + + // Start the process as above and then call the specified function on each + // trimmed line of the output until it returns a non-empty object T (tested + // with T::empty()) which is then returned to the caller. + // + // The predicate can move the value out of the passed string but, if error + // is false, only in case of a "content match" (so that any diagnostics + // lines are left intact). + // + // If ignore_exit is true, then the program's exist status is ignored (if it + // is false and the program exits with the non-zero status, then an empty T + // instance is returned). + // + // If checksum is not NULL, then feed it the content of each tripped line + // (including those that come after the callback returns non-empty object). + // + template <typename T, typename F> + T + run (const process_path&, + const char* args[], + F&&, + bool error = true, + bool ignore_exit = false, + sha256* checksum = nullptr); + + template <typename T, typename F> + inline T + run (const char* args[], + F&& f, + bool error = true, + bool ignore_exit = false, + sha256* checksum = nullptr) + { + return run<T> ( + run_search ( + args[0]), args, forward<F> (f), error, ignore_exit, checksum); + } + + // run <prog> + // + template <typename T, typename F> + inline T + run (const path& prog, + F&& f, + bool error = true, + bool ignore_exit = false, + sha256* checksum = nullptr) + { + const char* args[] = {prog.string ().c_str (), nullptr}; + return run<T> (args, forward<F> (f), error, ignore_exit, checksum); + } + + template <typename T, typename F> + inline T + run (const process_path& pp, + F&& f, + bool error = true, + bool ignore_exit = false, + sha256* checksum = nullptr) + { + const char* args[] = {pp.recall_string (), nullptr}; + return run<T> (pp, args, forward<F> (f), error, ignore_exit, checksum); + } + + // run <prog> <arg> + // + template <typename T, typename F> + inline T + run (const path& prog, + const char* arg, + F&& f, + bool error = true, + bool ignore_exit = false, + sha256* checksum = nullptr) + { + const char* args[] = {prog.string ().c_str (), arg, nullptr}; + return run<T> (args, forward<F> (f), error, ignore_exit, checksum); + } + + template <typename T, typename F> + inline T + run (const process_path& pp, + const char* arg, + F&& f, + bool error = true, + bool ignore_exit = false, + sha256* checksum = nullptr) + { + const char* args[] = {pp.recall_string (), arg, nullptr}; + return run<T> (pp, args, forward<F> (f), error, ignore_exit, checksum); + } + + // Empty string and path. + // + extern const std::string empty_string; + extern const path empty_path; + extern const dir_path empty_dir_path; + + // Append all the values from a variable to the C-string list. T is either + // target or scope. The variable is expected to be of type strings. + // + struct variable; + + template <typename T> + void + append_options (cstrings&, T&, const variable&); + + template <typename T> + void + append_options (cstrings&, T&, const char*); + + template <typename T> + void + append_options (strings&, T&, const variable&); + + template <typename T> + void + append_options (strings&, T&, const char*); + + template <typename T> + void + hash_options (sha256&, T&, const variable&); + + template <typename T> + void + hash_options (sha256&, T&, const char*); + + // As above but from the strings value directly. + // + class value; + struct lookup; + + void + append_options (cstrings&, const lookup&); + + void + append_options (strings&, const lookup&); + + void + hash_options (sha256&, const lookup&); + + void + append_options (cstrings&, const strings&); + + void + append_options (strings&, const strings&); + + void + hash_options (sha256&, const strings&); + + // Check if a specified option is present in the variable or value. T is + // either target or scope. + // + template <typename T> + bool + find_option (const char* option, + T&, + const variable&, + bool ignore_case = false); + + template <typename T> + bool + find_option (const char* option, + T&, + const char* variable, + bool ignore_case = false); + + bool + find_option (const char* option, const lookup&, bool ignore_case = false); + + bool + find_option (const char* option, const strings&, bool ignore_case = false); + + bool + find_option (const char* option, const cstrings&, bool ignore_case = false); + + // As above but look for several options. + // + template <typename T> + bool + find_options (initializer_list<const char*>, + T&, + const variable&, + bool = false); + + template <typename T> + bool + find_options (initializer_list<const char*>, T&, const char*, bool = false); + + bool + find_options (initializer_list<const char*>, const lookup&, bool = false); + + bool + find_options (initializer_list<const char*>, const strings&, bool = false); + + bool + find_options (initializer_list<const char*>, const cstrings&, bool = false); + + // As above but look for an option that has the specified prefix. + // + template <typename T> + bool + find_option_prefix (const char* prefix, T&, const variable&, bool = false); + + template <typename T> + bool + find_option_prefix (const char* prefix, T&, const char*, bool = false); + + bool + find_option_prefix (const char* prefix, const lookup&, bool = false); + + bool + find_option_prefix (const char* prefix, const strings&, bool = false); + + bool + find_option_prefix (const char* prefix, const cstrings&, bool = false); + + // As above but look for several option prefixes. + // + template <typename T> + bool + find_option_prefixes (initializer_list<const char*>, + T&, + const variable&, + bool = false); + + template <typename T> + bool + find_option_prefixes (initializer_list<const char*>, + T&, + const char*, + bool = false); + + bool + find_option_prefixes (initializer_list<const char*>, + const lookup&, bool = false); + + bool + find_option_prefixes (initializer_list<const char*>, + const strings&, + bool = false); + + bool + find_option_prefixes (initializer_list<const char*>, + const cstrings&, + bool = false); + + // Apply the specified substitution (stem) to a '*'-pattern. If pattern + // is NULL, then return the stem itself. Assume the pattern is valid, + // i.e., contains a single '*' character. + // + string + apply_pattern (const char* stem, const string* pattern); + + // Initialize build2 global state (verbosity, home/work directories, etc). + // Should be called early in main() once. + // + void + init (const char* argv0, uint16_t verbosity); +} + +#include <build2/utility.ixx> +#include <build2/utility.txx> + +#endif // BUILD2_UTILITY_HXX |