// file : libbuild2/functions-string.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file #include #include using namespace std; namespace build2 { static size_t find_index (const strings& vs, value&& v, optional&& fs) { bool ic (false); if (fs) { for (name& f: *fs) { string s (convert (move (f))); if (s == "icase") ic = true; else throw invalid_argument ("invalid flag '" + s + '\''); } } auto i (find_if (vs.begin (), vs.end (), [ic, y = convert (move (v))] (const string& x) { return (ic ? icasecmp (x, y) : x.compare (y)) == 0; })); return i != vs.end () ? i - vs.begin () : vs.size (); }; void string_functions (function_map& m) { function_family f (m, "string"); // Note that we must handle NULL values (relied upon by the parser // to provide conversion semantics consistent with untyped values). // f["string"] += [](string* s) { return s != nullptr ? move (*s) : string (); }; // Compare ASCII strings ignoring case and returning the boolean value. // f["icasecmp"] += [](string x, string y) { return icasecmp (x, y) == 0; }; f["icasecmp"] += [](string x, names y) { return icasecmp (x, convert (move (y))) == 0; }; f["icasecmp"] += [](names x, string y) { return icasecmp (convert (move (x)), y) == 0; }; f[".icasecmp"] += [](names x, names y) { return icasecmp (convert (move (x)), convert (move (y))) == 0; }; // Trim. // f["trim"] += [](string s) { return trim (move (s)); }; f[".trim"] += [](names s) { return names {name (trim (convert (move (s))))}; }; // Convert ASCII strings into lower/upper case. // f["lcase"] += [](string s) { return lcase (move (s)); }; f[".lcase"] += [](names s) { return names {name (lcase (convert (move (s))))}; }; f["ucase"] += [](string s) { return ucase (move (s)); }; f[".ucase"] += [](names s) { return names {name (ucase (convert (move (s))))}; }; // $size() // // Return the number of elements in the sequence. // f["size"] += [] (strings v) {return v.size ();}; // $size() // // Return the number of characters (bytes) in the string. // f["size"] += [] (string v) {return v.size ();}; // $sort( [, ]) // // Sort strings in ascending order. // // The following flags are supported: // // icase - sort ignoring case // // dedup - in addition to sorting also remove duplicates // f["sort"] += [](strings v, optional fs) { bool ic (false); bool dd (false); if (fs) { for (name& f: *fs) { string s (convert (move (f))); if (s == "icase") ic = true; else if (s == "dedup") dd = true; else throw invalid_argument ("invalid flag '" + s + '\''); } } sort (v.begin (), v.end (), [ic] (const string& x, const string& y) { return (ic ? icasecmp (x, y) : x.compare (y)) < 0; }); if (dd) v.erase (unique (v.begin(), v.end(), [ic] (const string& x, const string& y) { return (ic ? icasecmp (x, y) : x.compare (y)) == 0; }), v.end ()); return v; }; // $find(, [, ]) // // Return true if the string sequence contains the specified string. // // The following flags are supported: // // icase - compare ignoring case // // See also $regex.find_{match,search}(). // f["find"] += [](strings vs, value v, optional fs) { return find_index (vs, move (v), move (fs)) != vs.size (); }; // $find_index(, [, ]) // // Return the index of the first element in the string sequence that // is equal to the specified string or $size() if none is // found. // // The following flags are supported: // // icase - compare ignoring case // f["find_index"] += [](strings vs, value v, optional fs) { return find_index (vs, move (v), move (fs)); }; // String-specific overloads from builtins. // function_family b (m, "builtin"); // Note that we must handle NULL values (relied upon by the parser to // provide concatenation semantics consistent with untyped values). // b[".concat"] += [](string* l, string* r) { return l != nullptr ? r != nullptr ? move (*l += *r) : move (*l) : r != nullptr ? move (*r) : string (); }; b[".concat"] += [](string* l, names* ur) { string r (ur != nullptr ? convert (move (*ur)) : string ()); return l != nullptr ? move (*l += r) : move (r); }; b[".concat"] += [](names* ul, string* r) { string l (ul != nullptr ? convert (move (*ul)) : string ()); return r != nullptr ? move (l += *r) : move (l); }; } }