// file : build2/utility -*- C++ -*- // copyright : Copyright (c) 2014-2017 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #ifndef BUILD2_UTILITY #define BUILD2_UTILITY #include // make_tuple() #include // make_shared() #include // to_string() #include // move(), forward(), declval(), make_pair() #include // assert() #include // make_move_iterator() #include // * #include // ref(), cref() #include #include // combine_hash(), reverse_iterate(), casecmp(), // lcase(), etc #include #include #include 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; // // 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; // 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; // 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 basic_path relative (const basic_path&); // 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 line. // template T run (const process_path&, const char* args[], T (*) (string&), bool error = true, bool ignore_exit = false, sha256* checksum = nullptr); template inline T run (const char* args[], T (*f) (string&), bool error = true, bool ignore_exit = false, sha256* checksum = nullptr) { return run (run_search (args[0]), args, f, error, ignore_exit, checksum); } // run // template inline T run (const path& prog, T (*f) (string&), bool error = true, bool ignore_exit = false, sha256* checksum = nullptr) { const char* args[] = {prog.string ().c_str (), nullptr}; return run (args, f, error, ignore_exit, checksum); } template inline T run (const process_path& pp, T (*f) (string&), bool error = true, bool ignore_exit = false, sha256* checksum = nullptr) { const char* args[] = {pp.recall_string (), nullptr}; return run (pp, args, f, error, ignore_exit, checksum); } // run // template inline T run (const path& prog, const char* arg, T (*f) (string&), bool error = true, bool ignore_exit = false, sha256* checksum = nullptr) { const char* args[] = {prog.string ().c_str (), arg, nullptr}; return run (args, f, error, ignore_exit, checksum); } template inline T run (const process_path& pp, const char* arg, T (*f) (string&), bool error = true, bool ignore_exit = false, sha256* checksum = nullptr) { const char* args[] = {pp.recall_string (), arg, nullptr}; return run (pp, args, 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 void append_options (cstrings&, T&, const variable&); template void append_options (cstrings&, T&, const char*); template void append_options (strings&, T&, const variable&); template void append_options (strings&, T&, const char*); template void hash_options (sha256&, T&, const variable&); template 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 bool find_option (const char* option, T&, const variable&, bool ignore_case = false); template 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 bool find_options (initializer_list, T&, const variable&, bool = false); template bool find_options (initializer_list, T&, const char*, bool = false); bool find_options (initializer_list, const lookup&, bool = false); bool find_options (initializer_list, const strings&, bool = false); bool find_options (initializer_list, const cstrings&, bool = false); // As above but look for an option that has the specified prefix. // template bool find_option_prefix (const char* prefix, T&, const variable&, bool = false); template 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 bool find_option_prefixes (initializer_list, T&, const variable&, bool = false); template bool find_option_prefixes (initializer_list, T&, const char*, bool = false); bool find_option_prefixes (initializer_list, const lookup&, bool = false); bool find_option_prefixes (initializer_list, const strings&, bool = false); bool find_option_prefixes (initializer_list, 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); // Parse version string in the X.Y.Z[-{a|b}N] to a version integer in the // AABBCCDD form, where: // // AA - major version number // BB - minor version number // CC - bugfix version number // DD - alpha / beta (DD + 50) version number // // When DD is not 00, 1 is subtracted from AABBCC. For example: // // Version AABBCCDD // 2.0.0 02000000 // 2.1.0 02010000 // 2.1.1 02010100 // 2.2.0-a1 02019901 // 3.0.0-b2 02999952 // // For a version in the 1.2.3- form, it returns (AABBCC-1)01, which is the // lowest possible version in the 1.2.3 release set. For example: // // Version AABBCCDD // 2.2.0- 02019901 // 1.2.3- 01020201 // // In fact versions 1.2.3- and 1.2.3-a1 are equivalent. // // Throw invalid_argument if the passed string is not a valid version. // unsigned int to_version (const string&); // 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 #include #endif // BUILD2_UTILITY