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,
  93             const CompareType ct=CASE_SENSITIVE);
  94     bool startsWith(const tstring &str, const tstring &substr,
  95             const CompareType ct=CASE_SENSITIVE);
  96     bool endsWith(const tstring &str, const tstring &substr,
  97             const CompareType ct=CASE_SENSITIVE);
  98 
  99     enum SplitType {ST_ALL, ST_EXCEPT_EMPTY_STRING};
 100     void split(tstring_array &strVector, const tstring &str,
 101             const tstring &delimiter, const SplitType st = ST_ALL);
 102     inline tstring_array split(const tstring &str, const tstring &delimiter,
 103             const SplitType st = ST_ALL) {
 104         tstring_array result;
 105         split(result, str, delimiter, st);
 106         return result;
 107     }
 108     tstring trim(const tstring& str, const tstring& whitespace = _T(" \t"));
 109 
 110     /**
 111      * Writes sequence of values from [b, e) range into string buffer inserting
 112      * 'delimiter' after each value except of the last one.
 113      * Returns contents of string buffer.
 114      */
 115     template <class It>
 116     tstring join(It b, It e, const tstring& delimiter=tstring()) {
 117         tostringstream buf;
 118         if (b != e) {
 119             for (;;) {
 120                 buf << *b;
 121                 if (++b == e) {
 122                     break;
 123                 }
 124                 buf << delimiter;
 125             }
 126         }
 127         return buf.str();
 128     }
 129 
 130     tstring toLower(const tstring& str);
 131 
 132     tstring replace(const tstring &str, const tstring &search,
 133             const tstring &replace);
 134 }
 135 
 136 
 137 namespace tstrings {
 138     inline std::string toUtf8(const std::string& utf8str) {
 139         return utf8str;
 140     }
 141 
 142 #ifdef TSTRINGS_WITH_WCHAR
 143     // conversion to Utf8
 144     std::string toUtf8(const std::wstring& utf16str);
 145 
 146     // conversion to Utf16
 147     std::wstring toUtf16(const std::string& utf8str);
 148 
 149     inline std::wstring fromUtf8(const std::string& utf8str) {
 150         return toUtf16(utf8str);
 151     }
 152 
 153 #else
 154     inline std::string fromUtf8(const std::string& utf8str) {
 155         return utf8str;
 156     }
 157 #endif
 158 } // namespace tstrings
 159 
 160 
 161 namespace tstrings {
 162 namespace format_detail {
 163 
 164     template <class T>
 165     struct str_arg_value {
 166         const tstring value;
 167 
 168         str_arg_value(const std::string& v): value(fromUtf8(v)) {
 169         }
 170 
 171 #ifdef TSTRINGS_WITH_WCHAR
 172         str_arg_value(const std::wstring& v): value(v) {
 173         }
 174 #endif
 175 
 176         tstring::const_pointer operator () () const {
 177             return value.c_str();
 178         }
 179     };
 180 
 181     template <>
 182     struct str_arg_value<tstring> {
 183         const tstring::const_pointer value;
 184 
 185         str_arg_value(const tstring& v): value(v.c_str()) {
 186         }
 187 
 188         str_arg_value(tstring::const_pointer v): value(v) {
 189         }
 190 
 191         tstring::const_pointer operator () () const {
 192             return value;
 193         }
 194     };
 195 
 196     inline str_arg_value<std::string> arg(const std::string& v) {
 197         return v;
 198     }
 199 
 200     inline str_arg_value<std::string> arg(std::string::const_pointer v) {
 201         return (v ? v : "(null)");
 202     }
 203 
 204 #ifdef TSTRINGS_WITH_WCHAR
 205     inline str_arg_value<std::wstring> arg(const std::wstring& v) {
 206         return v;
 207     }
 208 
 209     inline str_arg_value<std::wstring> arg(std::wstring::const_pointer v) {
 210         return (v ? v : L"(null)");
 211     }
 212 #else
 213     void arg(const std::wstring&);          // Compilation error by design.
 214     void arg(std::wstring::const_pointer);  // Compilation error by design.
 215 #endif
 216 
 217     template <class T>
 218     struct arg_value {
 219         arg_value(const T v): v(v) {
 220         }
 221         T operator () () const {
 222             return v;
 223         }
 224     private:
 225         const T v;
 226     };
 227 
 228     inline arg_value<int> arg(int v) {
 229         return v;
 230     }
 231     inline arg_value<unsigned> arg(unsigned v) {
 232         return v;
 233     }
 234     inline arg_value<long> arg(long v) {
 235         return v;
 236     }
 237     inline arg_value<unsigned long> arg(unsigned long v) {
 238         return v;
 239     }
 240     inline arg_value<long long> arg(long long v) {
 241         return v;
 242     }
 243     inline arg_value<unsigned long long> arg(unsigned long long v) {
 244         return v;
 245     }
 246     inline arg_value<float> arg(float v) {
 247         return v;
 248     }
 249     inline arg_value<double> arg(double v) {
 250         return v;
 251     }
 252     inline arg_value<bool> arg(bool v) {
 253         return v;
 254     }
 255     inline arg_value<const void*> arg(const void* v) {
 256         return v;
 257     }
 258 
 259 } // namespace format_detail
 260 } // namespace tstrings
 261 
 262 
 263 namespace tstrings {
 264     template <class T, class T2, class T3, class T4, class T5, class T6, class T7>
 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, const T7& v7) {
 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                                             format_detail::arg(v7)());
 273     }
 274 
 275     template <class T, class T2, class T3, class T4, class T5, class T6>
 276     inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6) {
 277         return unsafe_format(fmt.c_str(),   format_detail::arg(v)(),
 278                                             format_detail::arg(v2)(),
 279                                             format_detail::arg(v3)(),
 280                                             format_detail::arg(v4)(),
 281                                             format_detail::arg(v5)(),
 282                                             format_detail::arg(v6)());
 283     }
 284 
 285     template <class T, class T2, class T3, class T4, class T5>
 286     inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3, const T4& v4, const T5& v5) {
 287         return unsafe_format(fmt.c_str(),   format_detail::arg(v)(),
 288                                             format_detail::arg(v2)(),
 289                                             format_detail::arg(v3)(),
 290                                             format_detail::arg(v4)(),
 291                                             format_detail::arg(v5)());
 292     }
 293 
 294     template <class T, class T2, class T3, class T4>
 295     inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3, const T4& v4) {
 296         return unsafe_format(fmt.c_str(),   format_detail::arg(v)(),
 297                                             format_detail::arg(v2)(),
 298                                             format_detail::arg(v3)(),
 299                                             format_detail::arg(v4)());
 300     }
 301 
 302     template <class T, class T2, class T3>
 303     inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3) {
 304         return unsafe_format(fmt.c_str(),   format_detail::arg(v)(),
 305                                             format_detail::arg(v2)(),
 306                                             format_detail::arg(v3)());
 307     }
 308 
 309     template <class T, class T2>
 310     inline tstring format(const tstring& fmt, const T& v, const T2& v2) {
 311         return unsafe_format(fmt.c_str(),   format_detail::arg(v)(),
 312                                             format_detail::arg(v2)());
 313 
 314     }
 315 
 316     template <class T>
 317     inline tstring format(const tstring& fmt, const T& v) {
 318         return unsafe_format(fmt.c_str(),   format_detail::arg(v)());
 319     }
 320 } // namespace tstrings
 321 
 322 
 323 namespace tstrings {
 324     /**
 325      * Buffer that accepts both std::wstring and std::string instances doing
 326      * encoding conversions behind the scenes. All std::string-s assumed to be
 327      * UTF8-encoded, all std::wstring-s assumed to be UTF16-encoded.
 328      */
 329     class any {
 330     public:
 331         any() {
 332         }
 333 
 334         any(std::string::const_pointer msg) {
 335             data << fromUtf8(msg);
 336         }
 337 
 338         any(const std::string& msg) {
 339             data << fromUtf8(msg);
 340         }
 341 
 342 #ifdef TSTRINGS_WITH_WCHAR
 343         any(std::wstring::const_pointer msg) {
 344             data << msg;
 345         }
 346 
 347         any(const std::wstring& msg) {
 348             data << msg;
 349         }
 350 
 351         any& operator << (const std::wstring& v) {
 352             data << v;
 353             return *this;
 354         }
 355 
 356         // need this specialization instead std::wstring::pointer,
 357         // otherwise LPWSTR is handled as abstract pointer (void*)
 358         any& operator << (LPWSTR v) {
 359             data << (v ? v : L"NULL");
 360             return *this;
 361         }
 362 
 363         // need this specialization instead std::wstring::const_pointer,
 364         // otherwise LPCWSTR is handled as abstract pointer (const void*)
 365         any& operator << (LPCWSTR v) {
 366             data << (v ? v : L"NULL");
 367             return *this;
 368         }
 369 
 370         std::wstring wstr() const {
 371             return data.str();
 372         }
 373 #endif
 374 
 375         template <class T>
 376         any& operator << (T v) {
 377             data << v;
 378             return *this;
 379         }
 380 
 381         any& operator << (tostream& (*pf)(tostream&)) {
 382             data << pf;
 383             return *this;
 384         }
 385 
 386         any& operator << (tios& (*pf)(tios&)) {
 387             data << pf;
 388             return *this;
 389         }
 390 
 391         any& operator << (std::ios_base& (*pf)(std::ios_base&)) {
 392             data << pf;
 393             return *this;
 394         }
 395 
 396         std::string str() const {
 397             return toUtf8(data.str());
 398         }
 399 
 400         tstring tstr() const {
 401             return data.str();
 402         }
 403 
 404     private:
 405         tostringstream data;
 406     };
 407 
 408     inline tstring to_tstring(const any& val) {
 409         return val.tstr();
 410     }
 411 } // namespace tstrings
 412 
 413 
 414 inline std::ostream& operator << (std::ostream& os, const tstrings::any& buf) {
 415     os << buf.str();
 416     return os;
 417 }
 418 
 419 #ifdef TSTRINGS_WITH_WCHAR
 420 inline std::wostream& operator << (std::wostream& os, const tstrings::any& buf) {
 421     os << buf.wstr();
 422     return os;
 423 }
 424 #endif
 425 
 426 #endif //TSTRINGS_H