1 /*
   2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #ifndef TSTRINGS_H
  27 #define TSTRINGS_H
  28 
  29 #ifdef _MSC_VER
  30 #   define TSTRINGS_WITH_WCHAR
  31 #endif
  32 
  33 #ifdef TSTRINGS_WITH_WCHAR
  34 #include <windows.h>
  35 #include <tchar.h>
  36 // Want compiler issue C4995 warnings for encounters of deprecated functions.
  37 #include <strsafe.h>
  38 #endif
  39 
  40 // STL's string header depends on deprecated functions.
  41 // We don't care about warnings from STL header, so disable them locally.
  42 #ifdef _MSC_VER
  43 #   pragma warning(push)
  44 #   pragma warning(disable:4995)
  45 #endif
  46 
  47 #include <string>
  48 #include <sstream>
  49 #include <iostream>
  50 #include <vector>
  51 
  52 #ifdef _MSC_VER
  53 #   pragma warning(pop)
  54 #endif
  55 
  56 
  57 #ifndef _T
  58 #   define _T(x) x
  59 #endif
  60 
  61 
  62 #ifdef TSTRINGS_WITH_WCHAR
  63 typedef std::wstring        tstring;
  64 typedef std::wostringstream tostringstream;
  65 typedef std::wistringstream tistringstream;
  66 typedef std::wstringstream  tstringstream;
  67 typedef std::wistream       tistream;
  68 typedef std::wostream       tostream;
  69 typedef std::wiostream      tiostream;
  70 typedef std::wios           tios;
  71 #else
  72 typedef std::string         tstring;
  73 typedef std::ostringstream  tostringstream;
  74 typedef std::istringstream  tistringstream;
  75 typedef std::stringstream   tstringstream;
  76 typedef std::istream        tistream;
  77 typedef std::ostream        tostream;
  78 typedef std::iostream       tiostream;
  79 typedef std::ios            tios;
  80 
  81 typedef const char* LPCTSTR;
  82 typedef char TCHAR;
  83 #endif
  84 
  85 // frequently used "array of tstrings" type
  86 typedef std::vector<tstring> tstring_array;
  87 
  88 namespace tstrings {
  89     tstring unsafe_format(tstring::const_pointer format, ...);
  90 
  91     enum CompareType {CASE_SENSITIVE, IGNORE_CASE};
  92     bool equals(const tstring& a, const tstring& b, const CompareType ct=CASE_SENSITIVE);
  93     bool startsWith(const tstring &str, const tstring &substr, const CompareType ct=CASE_SENSITIVE);
  94     bool endsWith(const tstring &str, const tstring &substr, const CompareType ct=CASE_SENSITIVE);
  95 
  96     enum SplitType {ST_ALL, ST_EXCEPT_EMPTY_STRING};
  97     void split(tstring_array &strVector, const tstring &str,
  98               const tstring &delimiter, const SplitType st = ST_ALL);
  99     inline tstring_array split(const tstring &str, const tstring &delimiter, const SplitType st = ST_ALL) {
 100         tstring_array result;
 101         split(result, str, delimiter, st);
 102         return result;
 103     }
 104     tstring trim(const tstring& str, const tstring& whitespace = _T(" \t"));
 105 
 106     /**
 107      * Writes sequence of values from [b, e) range into string buffer inserting
 108      * 'delimiter' after each value except of the last one.
 109      * Returns contents of string buffer.
 110      */
 111     template <class It>
 112     tstring join(It b, It e, const tstring& delimiter=tstring()) {
 113         tostringstream buf;
 114         if (b != e) {
 115             for (;;) {
 116                 buf << *b;
 117                 if (++b == e) {
 118                     break;
 119                 }
 120                 buf << delimiter;
 121             }
 122         }
 123         return buf.str();
 124     }
 125 
 126     tstring toLower(const tstring& str);
 127 
 128     tstring replace(const tstring &str, const tstring &search, const tstring &replace);
 129 }
 130 
 131 
 132 namespace tstrings {
 133     inline std::string toUtf8(const std::string& utf8str) { return utf8str; }
 134     
 135 #ifdef TSTRINGS_WITH_WCHAR
 136     // conversion to Utf8
 137     std::string toUtf8(const std::wstring& utf16str);
 138 
 139     // conversion to Utf16
 140     std::wstring toUtf16(const std::string& utf8str);
 141 
 142     inline std::wstring fromUtf8(const std::string& utf8str) { return toUtf16(utf8str); }
 143 
 144 #else
 145     inline std::string fromUtf8(const std::string& utf8str) { return utf8str; }
 146 #endif
 147 } // namespace tstrings
 148 
 149 
 150 namespace tstrings {
 151 namespace format_detail {
 152 
 153     template <class T>
 154     struct str_arg_value {
 155         const tstring value;
 156 
 157         str_arg_value(const std::string& v): value(fromUtf8(v)) {
 158         }
 159 
 160 #ifdef TSTRINGS_WITH_WCHAR
 161         str_arg_value(const std::wstring& v): value(v) {
 162         }
 163 #endif
 164 
 165         tstring::const_pointer operator () () const {
 166             return value.c_str();
 167         }
 168     };
 169 
 170     template <>
 171     struct str_arg_value<tstring> {
 172         const tstring::const_pointer value;
 173 
 174         str_arg_value(const tstring& v): value(v.c_str()) {
 175         }
 176 
 177         str_arg_value(tstring::const_pointer v): value(v) {
 178         }
 179 
 180         tstring::const_pointer operator () () const {
 181             return value;
 182         }
 183     };
 184 
 185     inline str_arg_value<std::string> arg(const std::string& v) {
 186         return v;
 187     }
 188 
 189     inline str_arg_value<std::string> arg(std::string::const_pointer v) {
 190         return (v ? v : "(null)");
 191     }
 192 
 193 #ifdef TSTRINGS_WITH_WCHAR
 194     inline str_arg_value<std::wstring> arg(const std::wstring& v) {
 195         return v;
 196     }
 197 
 198     inline str_arg_value<std::wstring> arg(std::wstring::const_pointer v) {
 199         return (v ? v : L"(null)");
 200     }
 201 #else
 202     void arg(const std::wstring&);          // Compilation error by design.
 203     void arg(std::wstring::const_pointer);  // Compilation error by design.
 204 #endif
 205 
 206     template <class T>
 207     struct arg_value {
 208         arg_value(const T v): v(v) {
 209         }
 210         T operator () () const {
 211             return v;
 212         }
 213     private:
 214         const T v;
 215     };
 216 
 217     inline arg_value<int> arg(int v) {
 218         return v;
 219     }
 220     inline arg_value<unsigned> arg(unsigned v) {
 221         return v;
 222     }
 223     inline arg_value<long> arg(long v) {
 224         return v;
 225     }
 226     inline arg_value<unsigned long> arg(unsigned long v) {
 227         return v;
 228     }
 229     inline arg_value<long long> arg(long long v) {
 230         return v;
 231     }
 232     inline arg_value<unsigned long long> arg(unsigned long long v) {
 233         return v;
 234     }
 235     inline arg_value<float> arg(float v) {
 236         return v;
 237     }
 238     inline arg_value<double> arg(double v) {
 239         return v;
 240     }
 241     inline arg_value<bool> arg(bool v) {
 242         return v;
 243     }
 244     inline arg_value<const void*> arg(const void* v) {
 245         return v;
 246     }
 247 
 248 } // namespace format_detail
 249 } // namespace tstrings
 250 
 251 
 252 namespace tstrings {
 253     template <class T, class T2, class T3, class T4, class T5, class T6, class T7>
 254     inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7) {
 255         return unsafe_format(fmt.c_str(),   format_detail::arg(v)(),
 256                                             format_detail::arg(v2)(),
 257                                             format_detail::arg(v3)(),
 258                                             format_detail::arg(v4)(),
 259                                             format_detail::arg(v5)(),
 260                                             format_detail::arg(v6)(),
 261                                             format_detail::arg(v7)());
 262     }
 263 
 264     template <class T, class T2, class T3, class T4, class T5, class T6>
 265     inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6) {
 266         return unsafe_format(fmt.c_str(),   format_detail::arg(v)(),
 267                                             format_detail::arg(v2)(),
 268                                             format_detail::arg(v3)(),
 269                                             format_detail::arg(v4)(),
 270                                             format_detail::arg(v5)(),
 271                                             format_detail::arg(v6)());
 272     }
 273 
 274     template <class T, class T2, class T3, class T4, class T5>
 275     inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3, const T4& v4, const T5& v5) {
 276         return unsafe_format(fmt.c_str(),   format_detail::arg(v)(),
 277                                             format_detail::arg(v2)(),
 278                                             format_detail::arg(v3)(),
 279                                             format_detail::arg(v4)(),
 280                                             format_detail::arg(v5)());
 281     }
 282 
 283     template <class T, class T2, class T3, class T4>
 284     inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3, const T4& v4) {
 285         return unsafe_format(fmt.c_str(),   format_detail::arg(v)(),
 286                                             format_detail::arg(v2)(),
 287                                             format_detail::arg(v3)(),
 288                                             format_detail::arg(v4)());
 289     }
 290 
 291     template <class T, class T2, class T3>
 292     inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3) {
 293         return unsafe_format(fmt.c_str(),   format_detail::arg(v)(),
 294                                             format_detail::arg(v2)(),
 295                                             format_detail::arg(v3)());
 296     }
 297 
 298     template <class T, class T2>
 299     inline tstring format(const tstring& fmt, const T& v, const T2& v2) {
 300         return unsafe_format(fmt.c_str(),   format_detail::arg(v)(),
 301                                             format_detail::arg(v2)());
 302 
 303     }
 304 
 305     template <class T>
 306     inline tstring format(const tstring& fmt, const T& v) {
 307         return unsafe_format(fmt.c_str(),   format_detail::arg(v)());
 308     }
 309 } // namespace tstrings
 310 
 311 
 312 namespace tstrings {
 313     /**
 314      * Buffer that accepts both std::wstring and std::string instances doing
 315      * encoding conversions behind the scenes. All std::string-s assumed to be
 316      * UTF8-encoded, all std::wstring-s assumed to be UTF16-encoded.
 317      */
 318     class any {
 319     public:
 320         any() {
 321         }
 322 
 323         any(std::string::const_pointer msg) {
 324             data << fromUtf8(msg);
 325         }
 326 
 327         any(const std::string& msg) {
 328             data << fromUtf8(msg);
 329         }
 330 
 331 #ifdef TSTRINGS_WITH_WCHAR
 332         any(std::wstring::const_pointer msg) {
 333             data << msg;
 334         }
 335 
 336         any(const std::wstring& msg) {
 337             data << msg;
 338         }
 339 
 340         any& operator << (const std::wstring& v) {
 341             data << v;
 342             return *this;
 343         }
 344 
 345         // need this specialization instead std::wstring::pointer,
 346         // otherwise LPWSTR is handled as abstract pointer (void*)
 347         any& operator << (LPWSTR v) {
 348             data << (v ? v : L"NULL");
 349             return *this;
 350         }
 351 
 352         // need this specialization instead std::wstring::const_pointer,
 353         // otherwise LPCWSTR is handled as abstract pointer (const void*)
 354         any& operator << (LPCWSTR v) {
 355             data << (v ? v : L"NULL");
 356             return *this;
 357         }
 358 
 359         std::wstring wstr() const {
 360             return data.str();
 361         }
 362 #endif
 363 
 364         template <class T>
 365         any& operator << (T v) {
 366             data << v;
 367             return *this;
 368         }
 369 
 370         any& operator << (tostream& (*pf)(tostream&)) {
 371             data << pf;
 372             return *this;
 373         }
 374 
 375         any& operator << (tios& (*pf)(tios&)) {
 376             data << pf;
 377             return *this;
 378         }
 379 
 380         any& operator << (std::ios_base& (*pf)(std::ios_base&)) {
 381             data << pf;
 382             return *this;
 383         }
 384 
 385         std::string str() const {
 386             return toUtf8(data.str());
 387         }
 388 
 389         tstring tstr() const {
 390             return data.str();
 391         }
 392 
 393     private:
 394         tostringstream data;
 395     };
 396 
 397     inline tstring to_tstring(const any& val) {
 398         return val.tstr();
 399     }
 400 } // namespace tstrings
 401 
 402 
 403 inline std::ostream& operator << (std::ostream& os, const tstrings::any& buf) {
 404     os << buf.str();
 405     return os;
 406 }
 407 
 408 #ifdef TSTRINGS_WITH_WCHAR
 409 inline std::wostream& operator << (std::wostream& os, const tstrings::any& buf) {
 410     os << buf.wstr();
 411     return os;
 412 }
 413 #endif
 414 
 415 #endif //TSTRINGS_H