Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-11 10:24:30

0001 // Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
0002 // under NSF AWARD 1414736 and by the respective contributors.
0003 // All rights reserved.
0004 //
0005 // SPDX-License-Identifier: BSD-3-Clause
0006 
0007 #pragma once
0008 
0009 // IWYU pragma: private, include "CLI/CLI.hpp"
0010 
0011 // This include is only needed for IDEs to discover symbols
0012 #include "../StringTools.hpp"
0013 
0014 // [CLI11:public_includes:set]
0015 #include <cstdint>
0016 #include <string>
0017 #include <utility>
0018 #include <vector>
0019 // [CLI11:public_includes:end]
0020 
0021 namespace CLI {
0022 // [CLI11:string_tools_inl_hpp:verbatim]
0023 
0024 namespace detail {
0025 CLI11_INLINE std::vector<std::string> split(const std::string &s, char delim) {
0026     std::vector<std::string> elems;
0027     if(s.empty()) {
0028         elems.emplace_back();
0029         return elems;
0030     }
0031 
0032     std::size_t start = 0;
0033     std::size_t end = 0;
0034 
0035     while((end = s.find(delim, start)) != std::string::npos) {
0036         elems.push_back(s.substr(start, end - start));
0037         start = end + 1;
0038     }
0039     elems.push_back(s.substr(start));
0040     return elems;
0041 }
0042 
0043 CLI11_INLINE std::string &ltrim(std::string &str) {
0044     auto it = std::find_if(str.begin(), str.end(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
0045     str.erase(str.begin(), it);
0046     return str;
0047 }
0048 
0049 CLI11_INLINE std::string &ltrim(std::string &str, const std::string &filter) {
0050     auto it = std::find_if(str.begin(), str.end(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
0051     str.erase(str.begin(), it);
0052     return str;
0053 }
0054 
0055 CLI11_INLINE std::string &rtrim(std::string &str) {
0056     auto it = std::find_if(str.rbegin(), str.rend(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
0057     str.erase(it.base(), str.end());
0058     return str;
0059 }
0060 
0061 CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter) {
0062     auto it =
0063         std::find_if(str.rbegin(), str.rend(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
0064     str.erase(it.base(), str.end());
0065     return str;
0066 }
0067 
0068 CLI11_INLINE std::string &remove_quotes(std::string &str) {
0069     if(!str.empty() && (str.front() == '"' || str.front() == '\'' || str.front() == '`')) {
0070         remove_outer(str, str.front());
0071     }
0072     return str;
0073 }
0074 
0075 CLI11_INLINE std::string &remove_outer(std::string &str, char key) {
0076     if(str.length() > 1 && (str.front() == key)) {
0077         if(str.front() == str.back()) {
0078             str.pop_back();
0079             str.erase(str.begin(), str.begin() + 1);
0080         }
0081     }
0082     return str;
0083 }
0084 
0085 CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input) {
0086     std::string::size_type n = 0;
0087     while(n != std::string::npos && n < input.size()) {
0088         n = input.find_first_of("\r\n", n);
0089         if(n != std::string::npos) {
0090             input.insert(n + 1, leader);
0091             n += leader.size() + 1;
0092         }
0093     }
0094     return input;
0095 }
0096 
0097 CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid) {
0098     if(!aliases.empty()) {
0099         out << std::setw(static_cast<int>(wid)) << "     aliases: ";
0100         bool front = true;
0101         for(const auto &alias : aliases) {
0102             if(!front) {
0103                 out << ", ";
0104             } else {
0105                 front = false;
0106             }
0107             out << detail::fix_newlines("              ", alias);
0108         }
0109         out << "\n";
0110     }
0111     return out;
0112 }
0113 
0114 CLI11_INLINE bool valid_name_string(const std::string &str) {
0115     if(str.empty() || !valid_first_char(str[0])) {
0116         return false;
0117     }
0118     auto e = str.end();
0119     for(auto c = str.begin() + 1; c != e; ++c)
0120         if(!valid_later_char(*c))
0121             return false;
0122     return true;
0123 }
0124 
0125 CLI11_INLINE std::string get_group_separators() {
0126     std::string separators{"_'"};
0127 #if CLI11_HAS_RTTI != 0
0128     char group_separator = std::use_facet<std::numpunct<char>>(std::locale()).thousands_sep();
0129     separators.push_back(group_separator);
0130 #endif
0131     return separators;
0132 }
0133 
0134 CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to) {
0135 
0136     std::size_t start_pos = 0;
0137 
0138     while((start_pos = str.find(from, start_pos)) != std::string::npos) {
0139         str.replace(start_pos, from.length(), to);
0140         start_pos += to.length();
0141     }
0142 
0143     return str;
0144 }
0145 
0146 CLI11_INLINE void remove_default_flag_values(std::string &flags) {
0147     auto loc = flags.find_first_of('{', 2);
0148     while(loc != std::string::npos) {
0149         auto finish = flags.find_first_of("},", loc + 1);
0150         if((finish != std::string::npos) && (flags[finish] == '}')) {
0151             flags.erase(flags.begin() + static_cast<std::ptrdiff_t>(loc),
0152                         flags.begin() + static_cast<std::ptrdiff_t>(finish) + 1);
0153         }
0154         loc = flags.find_first_of('{', loc + 1);
0155     }
0156     flags.erase(std::remove(flags.begin(), flags.end(), '!'), flags.end());
0157 }
0158 
0159 CLI11_INLINE std::ptrdiff_t
0160 find_member(std::string name, const std::vector<std::string> &names, bool ignore_case, bool ignore_underscore) {
0161     auto it = std::end(names);
0162     if(ignore_case) {
0163         if(ignore_underscore) {
0164             name = detail::to_lower(detail::remove_underscore(name));
0165             it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
0166                 return detail::to_lower(detail::remove_underscore(local_name)) == name;
0167             });
0168         } else {
0169             name = detail::to_lower(name);
0170             it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
0171                 return detail::to_lower(local_name) == name;
0172             });
0173         }
0174 
0175     } else if(ignore_underscore) {
0176         name = detail::remove_underscore(name);
0177         it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
0178             return detail::remove_underscore(local_name) == name;
0179         });
0180     } else {
0181         it = std::find(std::begin(names), std::end(names), name);
0182     }
0183 
0184     return (it != std::end(names)) ? (it - std::begin(names)) : (-1);
0185 }
0186 
0187 CLI11_MODULE_INLINE const std::string &escapedChars() {
0188     static const std::string s{"\b\t\n\f\r\"\\"};
0189     return s;
0190 }
0191 CLI11_MODULE_INLINE const std::string &escapedCharsCode() {
0192     static const std::string s{"btnfr\"\\"};
0193     return s;
0194 }
0195 CLI11_MODULE_INLINE const std::string &bracketChars() {
0196     static const std::string s{"\"'`[(<{"};
0197     return s;
0198 }
0199 CLI11_MODULE_INLINE const std::string &matchBracketChars() {
0200     static const std::string s{"\"'`])>}"};
0201     return s;
0202 }
0203 
0204 CLI11_INLINE bool has_escapable_character(const std::string &str) {
0205     return (str.find_first_of(escapedChars()) != std::string::npos);
0206 }
0207 
0208 CLI11_INLINE std::string add_escaped_characters(const std::string &str) {
0209     std::string out;
0210     out.reserve(str.size() + 4);
0211     for(char s : str) {
0212         auto sloc = escapedChars().find_first_of(s);
0213         if(sloc != std::string::npos) {
0214             out.push_back('\\');
0215             out.push_back(escapedCharsCode()[sloc]);
0216         } else {
0217             out.push_back(s);
0218         }
0219     }
0220     return out;
0221 }
0222 
0223 CLI11_INLINE std::uint32_t hexConvert(char hc) {
0224     int hcode{0};
0225     if(hc >= '0' && hc <= '9') {
0226         hcode = (hc - '0');
0227     } else if(hc >= 'A' && hc <= 'F') {
0228         hcode = (hc - 'A' + 10);
0229     } else if(hc >= 'a' && hc <= 'f') {
0230         hcode = (hc - 'a' + 10);
0231     } else {
0232         hcode = -1;
0233     }
0234     return static_cast<uint32_t>(hcode);
0235 }
0236 
0237 CLI11_INLINE char make_char(std::uint32_t code) { return static_cast<char>(static_cast<unsigned char>(code)); }
0238 
0239 CLI11_INLINE void append_codepoint(std::string &str, std::uint32_t code) {
0240     if(code < 0x80) {  // ascii code equivalent
0241         str.push_back(static_cast<char>(code));
0242     } else if(code < 0x800) {  // \u0080 to \u07FF
0243         // 110yyyyx 10xxxxxx; 0x3f == 0b0011'1111
0244         str.push_back(make_char(0xC0 | code >> 6));
0245         str.push_back(make_char(0x80 | (code & 0x3F)));
0246     } else if(code < 0x10000) {  // U+0800...U+FFFF
0247         if(0xD800 <= code && code <= 0xDFFF) {
0248             throw std::invalid_argument("[0xD800, 0xDFFF] are not valid code points.");
0249         }
0250         // 1110yyyy 10yxxxxx 10xxxxxx
0251         str.push_back(make_char(0xE0 | code >> 12));
0252         str.push_back(make_char(0x80 | (code >> 6 & 0x3F)));
0253         str.push_back(make_char(0x80 | (code & 0x3F)));
0254     } else if(code < 0x110000) {  // U+010000 ... U+10FFFF
0255         // 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx
0256         str.push_back(make_char(0xF0 | code >> 18));
0257         str.push_back(make_char(0x80 | (code >> 12 & 0x3F)));
0258         str.push_back(make_char(0x80 | (code >> 6 & 0x3F)));
0259         str.push_back(make_char(0x80 | (code & 0x3F)));
0260     } else {  // code points above U+10FFFF are not valid
0261         throw std::invalid_argument("values above 0x10FFFF are not valid code points.");
0262     }
0263 }
0264 
0265 CLI11_INLINE std::string remove_escaped_characters(const std::string &str) {
0266 
0267     std::string out;
0268     out.reserve(str.size());
0269     for(auto loc = str.begin(); loc < str.end(); ++loc) {
0270         if(*loc == '\\') {
0271             if(str.end() - loc < 2) {
0272                 throw std::invalid_argument("invalid escape sequence " + str);
0273             }
0274             auto ecloc = escapedCharsCode().find_first_of(*(loc + 1));
0275             if(ecloc != std::string::npos) {
0276                 out.push_back(escapedChars()[ecloc]);
0277                 ++loc;
0278             } else if(*(loc + 1) == 'u') {
0279                 // must have 4 hex characters
0280                 if(str.end() - loc < 6) {
0281                     throw std::invalid_argument("unicode sequence must have 4 hex codes " + str);
0282                 }
0283                 std::uint32_t code{0};
0284                 std::uint32_t mplier{16 * 16 * 16};
0285                 for(int ii = 2; ii < 6; ++ii) {
0286                     std::uint32_t res = hexConvert(*(loc + ii));
0287                     if(res > 0x0F) {
0288                         throw std::invalid_argument("unicode sequence must have 4 hex codes " + str);
0289                     }
0290                     code += res * mplier;
0291                     mplier = mplier / 16;
0292                 }
0293                 append_codepoint(out, code);
0294                 loc += 5;
0295             } else if(*(loc + 1) == 'U') {
0296                 // must have 8 hex characters
0297                 if(str.end() - loc < 10) {
0298                     throw std::invalid_argument("unicode sequence must have 8 hex codes " + str);
0299                 }
0300                 std::uint32_t code{0};
0301                 std::uint32_t mplier{16 * 16 * 16 * 16 * 16 * 16 * 16};
0302                 for(int ii = 2; ii < 10; ++ii) {
0303                     std::uint32_t res = hexConvert(*(loc + ii));
0304                     if(res > 0x0F) {
0305                         throw std::invalid_argument("unicode sequence must have 8 hex codes " + str);
0306                     }
0307                     code += res * mplier;
0308                     mplier = mplier / 16;
0309                 }
0310                 append_codepoint(out, code);
0311                 loc += 9;
0312             } else if(*(loc + 1) == '0') {
0313                 out.push_back('\0');
0314                 ++loc;
0315             } else {
0316                 throw std::invalid_argument(std::string("unrecognized escape sequence \\") + *(loc + 1) + " in " + str);
0317             }
0318         } else {
0319             out.push_back(*loc);
0320         }
0321     }
0322     return out;
0323 }
0324 
0325 CLI11_INLINE std::size_t close_string_quote(const std::string &str, std::size_t start, char closure_char) {
0326     std::size_t loc{0};
0327     for(loc = start + 1; loc < str.size(); ++loc) {
0328         if(str[loc] == closure_char) {
0329             break;
0330         }
0331         if(str[loc] == '\\') {
0332             // skip the next character for escaped sequences
0333             ++loc;
0334         }
0335     }
0336     return loc;
0337 }
0338 
0339 CLI11_INLINE std::size_t close_literal_quote(const std::string &str, std::size_t start, char closure_char) {
0340     auto loc = str.find_first_of(closure_char, start + 1);
0341     return (loc != std::string::npos ? loc : str.size());
0342 }
0343 
0344 CLI11_INLINE std::size_t close_sequence(const std::string &str, std::size_t start, char closure_char) {
0345 
0346     auto bracket_loc = matchBracketChars().find(closure_char);
0347     switch(bracket_loc) {
0348     case 0:
0349         return close_string_quote(str, start, closure_char);
0350     case 1:
0351     case 2:
0352 #if defined(_MSC_VER) && _MSC_VER < 1920
0353     case(std::size_t)-1:
0354 #else
0355     case std::string::npos:
0356 #endif
0357         return close_literal_quote(str, start, closure_char);
0358     default:
0359         break;
0360     }
0361 
0362     std::string closures(1, closure_char);
0363     auto loc = start + 1;
0364 
0365     while(loc < str.size()) {
0366         if(str[loc] == closures.back()) {
0367             closures.pop_back();
0368             if(closures.empty()) {
0369                 return loc;
0370             }
0371         }
0372         bracket_loc = bracketChars().find(str[loc]);
0373         if(bracket_loc != std::string::npos) {
0374             switch(bracket_loc) {
0375             case 0:
0376                 loc = close_string_quote(str, loc, str[loc]);
0377                 break;
0378             case 1:
0379             case 2:
0380                 loc = close_literal_quote(str, loc, str[loc]);
0381                 break;
0382             default:
0383                 closures.push_back(matchBracketChars()[bracket_loc]);
0384                 break;
0385             }
0386         }
0387         ++loc;
0388     }
0389     if(loc > str.size()) {
0390         loc = str.size();
0391     }
0392     return loc;
0393 }
0394 
0395 CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter) {
0396 
0397     auto find_ws = [delimiter](char ch) {
0398         return (delimiter == '\0') ? std::isspace<char>(ch, std::locale()) : (ch == delimiter);
0399     };
0400     trim(str);
0401 
0402     std::vector<std::string> output;
0403     while(!str.empty()) {
0404         if(bracketChars().find_first_of(str[0]) != std::string::npos) {
0405             auto bracketLoc = bracketChars().find_first_of(str[0]);
0406             auto end = close_sequence(str, 0, matchBracketChars()[bracketLoc]);
0407             if(end >= str.size()) {
0408                 output.push_back(std::move(str));
0409                 str.clear();
0410             } else {
0411                 output.push_back(str.substr(0, end + 1));
0412                 // The character following a closing quote/bracket is normally a delimiter and is
0413                 // consumed.  If it is an ordinary character it must be retained (resume from it) so
0414                 // no characters are silently lost (e.g. `"abc"def` -> {"abc", "def"}).  However if it
0415                 // is itself a quote/bracket opening character, resuming from it would start a fresh
0416                 // (potentially unterminated) quoted sequence that could swallow later delimiters, so
0417                 // it is skipped like the original delimiter case to keep splitting well behaved.
0418                 char follow = str[end + 1];
0419                 bool skip_follow = find_ws(follow) || (bracketChars().find_first_of(follow) != std::string::npos);
0420                 auto next = skip_follow ? end + 2 : end + 1;
0421                 if(next < str.size()) {
0422                     str = str.substr(next);
0423                 } else {
0424                     str.clear();
0425                 }
0426             }
0427 
0428         } else {
0429             auto it = std::find_if(std::begin(str), std::end(str), find_ws);
0430             if(it != std::end(str)) {
0431                 std::string value = std::string(str.begin(), it);
0432                 output.push_back(value);
0433                 str = std::string(it + 1, str.end());
0434             } else {
0435                 output.push_back(str);
0436                 str.clear();
0437             }
0438         }
0439         trim(str);
0440     }
0441     return output;
0442 }
0443 
0444 CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset) {
0445     auto next = str[offset + 1];
0446     if((next == '\"') || (next == '\'') || (next == '`')) {
0447         if(offset == 0) {
0448             // nothing precedes the trigger character, so there is nothing to reinterpret
0449             return offset + 1;
0450         }
0451         auto astart = str.find_last_of("-/ \"\'`", offset - 1);
0452         if(astart != std::string::npos) {
0453             if(str[astart] == ((str[offset] == '=') ? '-' : '/'))
0454                 str[offset] = ' ';  // interpret this as a space so the split_up works properly
0455         }
0456     }
0457     return offset + 1;
0458 }
0459 
0460 CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape, bool force) {
0461     // s is our escaped output string
0462     std::string escaped_string{};
0463     // loop through all characters
0464     for(char c : string_to_escape) {
0465         // check if a given character is printable
0466         // the cast is necessary to avoid undefined behaviour
0467         if(isprint(static_cast<unsigned char>(c)) == 0) {
0468             std::stringstream stream;
0469             // if the character is not printable
0470             // we'll convert it to a hex string using a stringstream
0471             // note that since char is signed we have to cast it to unsigned first
0472             stream << std::hex << static_cast<unsigned int>(static_cast<unsigned char>(c));
0473             std::string code = stream.str();
0474             escaped_string += std::string("\\x") + (code.size() < 2 ? "0" : "") + code;
0475         } else if(c == 'x' || c == 'X') {
0476             // need to check for inadvertent binary sequences
0477             if(!escaped_string.empty() && escaped_string.back() == '\\') {
0478                 escaped_string += std::string("\\x") + (c == 'x' ? "78" : "58");
0479             } else {
0480                 escaped_string.push_back(c);
0481             }
0482 
0483         } else {
0484             escaped_string.push_back(c);
0485         }
0486     }
0487     if(escaped_string != string_to_escape || force) {
0488         auto sqLoc = escaped_string.find('\'');
0489         while(sqLoc != std::string::npos) {
0490             escaped_string[sqLoc] = '\\';
0491             escaped_string.insert(sqLoc + 1, "x27");
0492             sqLoc = escaped_string.find('\'', sqLoc + 4);
0493         }
0494         escaped_string.insert(0, "'B\"(");
0495         escaped_string.push_back(')');
0496         escaped_string.push_back('"');
0497         escaped_string.push_back('\'');
0498     }
0499     return escaped_string;
0500 }
0501 
0502 CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string) {
0503     size_t ssize = escaped_string.size();
0504     if(escaped_string.compare(0, 3, "B\"(") == 0 && escaped_string.compare(ssize - 2, 2, ")\"") == 0) {
0505         return true;
0506     }
0507     return (escaped_string.compare(0, 4, "'B\"(") == 0 && escaped_string.compare(ssize - 3, 3, ")\"'") == 0);
0508 }
0509 
0510 CLI11_INLINE std::string extract_binary_string(const std::string &escaped_string) {
0511     std::size_t start{0};
0512     std::size_t tail{0};
0513     size_t ssize = escaped_string.size();
0514     if(escaped_string.compare(0, 3, "B\"(") == 0 && escaped_string.compare(ssize - 2, 2, ")\"") == 0) {
0515         start = 3;
0516         tail = 2;
0517     } else if(escaped_string.compare(0, 4, "'B\"(") == 0 && escaped_string.compare(ssize - 3, 3, ")\"'") == 0) {
0518         start = 4;
0519         tail = 3;
0520     }
0521 
0522     if(start == 0) {
0523         return escaped_string;
0524     }
0525     std::string outstring;
0526 
0527     outstring.reserve(ssize - start - tail);
0528     std::size_t loc = start;
0529     while(loc < ssize - tail) {
0530         // ssize-2 to skip )" at the end
0531         if(escaped_string[loc] == '\\' && (escaped_string[loc + 1] == 'x' || escaped_string[loc + 1] == 'X')) {
0532             auto c1 = escaped_string[loc + 2];
0533             auto c2 = escaped_string[loc + 3];
0534 
0535             std::uint32_t res1 = hexConvert(c1);
0536             std::uint32_t res2 = hexConvert(c2);
0537             if(res1 <= 0x0F && res2 <= 0x0F) {
0538                 loc += 4;
0539                 outstring.push_back(static_cast<char>(res1 * 16 + res2));
0540                 continue;
0541             }
0542         }
0543         outstring.push_back(escaped_string[loc]);
0544         ++loc;
0545     }
0546     return outstring;
0547 }
0548 
0549 CLI11_INLINE void remove_quotes(std::vector<std::string> &args) {
0550     for(auto &arg : args) {
0551         if(arg.empty()) {
0552             continue;
0553         }
0554         if(arg.front() == '\"' && arg.back() == '\"') {
0555             remove_quotes(arg);
0556             // only remove escaped for string arguments not literal strings
0557             arg = remove_escaped_characters(arg);
0558         } else {
0559             remove_quotes(arg);
0560         }
0561     }
0562 }
0563 
0564 CLI11_INLINE void handle_secondary_array(std::string &str) {
0565     if(str.size() >= 2 && str.front() == '[' && str.back() == ']') {
0566         // handle some special array processing for arguments if it might be interpreted as a secondary array
0567         std::string tstr{"[["};
0568         for(std::size_t ii = 1; ii < str.size(); ++ii) {
0569             tstr.push_back(str[ii]);
0570             tstr.push_back(str[ii]);
0571         }
0572         str = std::move(tstr);
0573     }
0574 }
0575 
0576 CLI11_INLINE bool
0577 process_quoted_string(std::string &str, char string_char, char literal_char, bool disable_secondary_array_processing) {
0578     if(str.size() <= 1) {
0579         return false;
0580     }
0581     if(detail::is_binary_escaped_string(str)) {
0582         str = detail::extract_binary_string(str);
0583         if(!disable_secondary_array_processing)
0584             handle_secondary_array(str);
0585         return true;
0586     }
0587     if(str.front() == string_char && str.back() == string_char) {
0588         detail::remove_outer(str, string_char);
0589         if(str.find_first_of('\\') != std::string::npos) {
0590             str = detail::remove_escaped_characters(str);
0591         }
0592         if(!disable_secondary_array_processing)
0593             handle_secondary_array(str);
0594         return true;
0595     }
0596     if((str.front() == literal_char || str.front() == '`') && str.back() == str.front()) {
0597         detail::remove_outer(str, str.front());
0598         if(!disable_secondary_array_processing)
0599             handle_secondary_array(str);
0600         return true;
0601     }
0602     return false;
0603 }
0604 
0605 CLI11_INLINE std::string get_environment_value(const std::string &env_name) {
0606     std::string ename_string;
0607 
0608 #ifdef _MSC_VER
0609     // Windows version
0610     char *buffer = nullptr;
0611     std::size_t sz = 0;
0612     if(_dupenv_s(&buffer, &sz, env_name.c_str()) == 0 && buffer != nullptr) {
0613         ename_string = std::string(buffer);
0614         free(buffer);
0615     }
0616 #else
0617     // This also works on Windows, but gives a warning
0618 
0619     // MISRA static analysis need. MISRACPP2023-25_5_2-a-1
0620     const char *buffer = nullptr;
0621     buffer = std::getenv(env_name.c_str());
0622     if(buffer != nullptr) {
0623         ename_string = std::string(buffer);
0624     }
0625 #endif
0626     return ename_string;
0627 }
0628 
0629 CLI11_INLINE std::ostream &streamOutAsParagraph(std::ostream &out,
0630                                                 const std::string &text,
0631                                                 std::size_t paragraphWidth,
0632                                                 const std::string &linePrefix,
0633                                                 bool skipPrefixOnFirstLine) {
0634     std::istringstream lss(text);
0635     std::string line = "";
0636     while(std::getline(lss, line)) {
0637         std::istringstream iss(line);
0638         std::string word = "";
0639         std::size_t charsWritten = 0;
0640 
0641         if(!skipPrefixOnFirstLine)
0642             out << linePrefix;
0643         skipPrefixOnFirstLine = false;  // subsequent lines always get the prefix
0644 
0645         while(iss >> word) {
0646             if(charsWritten > 0 && (word.length() + 1 + charsWritten > paragraphWidth)) {
0647                 out << '\n' << linePrefix;
0648                 charsWritten = 0;
0649             }
0650             if(charsWritten == 0) {
0651                 out << word;
0652                 charsWritten += word.length();
0653             } else {
0654                 out << ' ' << word;
0655                 charsWritten += word.length() + 1;
0656             }
0657         }
0658 
0659         if(!lss.eof())
0660             out << '\n';
0661     }
0662     return out;
0663 }
0664 
0665 }  // namespace detail
0666 // [CLI11:string_tools_inl_hpp:end]
0667 }  // namespace CLI