summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/llcommon/llstring.cpp158
1 files changed, 158 insertions, 0 deletions
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 614075498c..23b12bb98d 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -31,10 +31,168 @@
#include "llfasttimer.h"
#include "llsd.h"
#include <vector>
+#include <sstream>
#if LL_WINDOWS
#include "llwin32headerslean.h"
#include <winnls.h> // for WideCharToMultiByte
+
+// From https://stackoverflow.com/a/48716488:
+// how to work around MSVC's broken implementation of std::basic_ostream<CHAR>
+// (get C2941 otherwise)
+// The problem is that the MSVC implementation doesn't generalize for
+// arbitrary CHAR.
+namespace std
+{
+
+// The std::numpunct<_Elem> template on which this specialization is based was
+// copied 2024-09-11 from xlocnum header with versions:
+// FRAMEWORK40VERSION="v4.0"
+// FRAMEWORKVERSION="v4.0.30319"
+// FRAMEWORKVERSION64="v4.0.30319"
+// UCRTVERSION="10.0.22621.0"
+// VCTOOLSVERSION="14.40.33807"
+// VISUALSTUDIOVERSION="17.0"
+// WINDOWSSDKLIBVERSION="10.0.22621.0"
+// WINDOWSSDKVERSION="10.0.22621.0"
+// Not sure which of the above versions tracks changes to xlocnum.
+template <>
+class numpunct<llwchar> : public locale::facet // facet for defining numeric punctuation text
+{
+private:
+ friend _Tidy_guard<numpunct>;
+
+public:
+ using string_type = basic_string<llwchar, char_traits<llwchar>, allocator<llwchar>>;
+ using char_type = llwchar;
+
+ static locale::id id; // unique facet id
+
+ llwchar decimal_point() const {
+ return do_decimal_point();
+ }
+
+ llwchar thousands_sep() const {
+ return do_thousands_sep();
+ }
+
+ string grouping() const {
+ return do_grouping();
+ }
+
+ string_type falsename() const {
+ return do_falsename();
+ }
+
+ string_type truename() const {
+ return do_truename();
+ }
+
+ explicit numpunct(size_t _Refs = 0) : locale::facet(_Refs) { // construct from current locale
+ _BEGIN_LOCINFO(_Lobj)
+ _Init(_Lobj);
+ if (_Kseparator == 0) {
+ _Kseparator = // NB: differs from "C" locale
+ _Maklocchr(',', static_cast<llwchar*>(nullptr), _Lobj._Getcvt());
+ }
+ _END_LOCINFO()
+ }
+
+ numpunct(const _Locinfo& _Lobj, size_t _Refs = 0, bool _Isdef = false) : locale::facet(_Refs) {
+ _Init(_Lobj, _Isdef);
+ }
+
+ static size_t _Getcat(const locale::facet** _Ppf = nullptr, const locale* _Ploc = nullptr) {
+ // return locale category mask and construct standard facet
+ if (_Ppf && !*_Ppf) {
+ *_Ppf = new numpunct<llwchar>(_Locinfo(_Ploc->_C_str()), 0, true);
+ }
+ return _X_NUMERIC;
+ }
+
+protected:
+ __CLR_OR_THIS_CALL ~numpunct() noexcept override {
+ _Tidy();
+ }
+
+ numpunct(const char* _Locname, size_t _Refs = 0, bool _Isdef = false) : locale::facet(_Refs) {
+ _BEGIN_LOCINFO(_Lobj(_Locname))
+ _Init(_Lobj, _Isdef);
+ _END_LOCINFO()
+ }
+
+ template <class _Elem2>
+ void _Getvals(_Elem2, const lconv* _Ptr, _Locinfo::_Cvtvec _Cvt) { // get values
+ _Dp = _Maklocchr(_Ptr->decimal_point[0], static_cast<_Elem2*>(nullptr), _Cvt);
+ _Kseparator = _Maklocchr(_Ptr->thousands_sep[0], static_cast<_Elem2*>(nullptr), _Cvt);
+ }
+
+ void _Getvals(wchar_t, const lconv* _Ptr, _Locinfo::_Cvtvec) { // get values
+ _Dp = static_cast<llwchar>(_Ptr->_W_decimal_point[0]);
+ _Kseparator = static_cast<llwchar>(_Ptr->_W_thousands_sep[0]);
+ }
+
+ void _Init(const _Locinfo& _Lobj, bool _Isdef = false) { // initialize from _Lobj
+ const lconv* _Ptr = _Lobj._Getlconv();
+ _Locinfo::_Cvtvec _Cvt = _Lobj._Getcvt(); // conversion information
+
+ _Grouping = nullptr;
+ _Falsename = nullptr;
+ _Truename = nullptr;
+
+ _Tidy_guard<numpunct> _Guard{this};
+ _Grouping = _Maklocstr(_Isdef ? "" : _Ptr->grouping, static_cast<char*>(nullptr), _Lobj._Getcvt());
+ _Falsename = _Maklocstr(_Lobj._Getfalse(), static_cast<llwchar*>(nullptr), _Cvt);
+ _Truename = _Maklocstr(_Lobj._Gettrue(), static_cast<llwchar*>(nullptr), _Cvt);
+ _Guard._Target = nullptr;
+
+ if (_Isdef) { // apply defaults for required facets
+ // _Grouping = _Maklocstr("", static_cast<char *>(nullptr), _Cvt);
+ _Dp = _Maklocchr('.', static_cast<llwchar*>(nullptr), _Cvt);
+ _Kseparator = _Maklocchr(',', static_cast<llwchar*>(nullptr), _Cvt);
+ } else {
+ _Getvals(llwchar{}, _Ptr, _Cvt);
+ }
+ }
+
+ virtual llwchar __CLR_OR_THIS_CALL do_decimal_point() const {
+ return _Dp;
+ }
+
+ virtual llwchar __CLR_OR_THIS_CALL do_thousands_sep() const {
+ return _Kseparator;
+ }
+
+ virtual string __CLR_OR_THIS_CALL do_grouping() const {
+ return string{_Grouping};
+ }
+
+ virtual string_type __CLR_OR_THIS_CALL do_falsename() const {
+ return string_type{_Falsename};
+ }
+
+ virtual string_type __CLR_OR_THIS_CALL do_truename() const {
+ return string_type{_Truename};
+ }
+
+private:
+ void _Tidy() noexcept { // free all storage
+ _CSTD free(const_cast<char*>(_Grouping));
+ _CSTD free(const_cast<llwchar*>(_Falsename));
+ _CSTD free(const_cast<llwchar*>(_Truename));
+ }
+
+ const char* _Grouping; // grouping string, "" for "C" locale
+ llwchar _Dp; // decimal point, '.' for "C" locale
+ llwchar _Kseparator; // thousands separator, '\0' for "C" locale
+ const llwchar* _Falsename; // name for false, "false" for "C" locale
+ const llwchar* _Truename; // name for true, "true" for "C" locale
+};
+
+locale::id numpunct<llwchar>::id;
+
+} // namespace std
+
#endif
std::string ll_safe_string(const char* in)