#include "unicode.h"
#include <locale>
+#include <iostream>
#include <boost/assert.hpp>
namespace lyx {
+
docstring const from_ascii(char const * ascii)
{
docstring s;
}
+void utf8_to_ucs4(std::string const & utf8, docstring & ucs4)
+{
+ size_t n = utf8.size();
+ // as utf8 is a multi-byte encoding, there would be at most
+ // n characters:
+ ucs4.resize(n);
+ if (n == 0)
+ return;
+
+ int maxoutsize = n * 4;
+ // basic_string::data() is not recognized by some old gcc version
+ // so we use &(ucs4[0]) instead.
+ char * outbuf = (char *)(&(ucs4[0]));
+ int bytes = utf8ToUcs4().convert(utf8.c_str(), n, outbuf, maxoutsize);
+
+ // adjust to the real converted size
+ ucs4.resize(bytes/4);
+}
+
+
docstring const from_utf8(std::string const & utf8)
{
- std::vector<lyx::char_type> const ucs4 =
- utf8_to_ucs4(utf8.data(), utf8.size());
- return docstring(ucs4.begin(), ucs4.end());
+ docstring ucs4;
+ utf8_to_ucs4(utf8, ucs4);
+ return ucs4;
}
return std::string(utf8.begin(), utf8.end());
}
-}
-
bool operator==(lyx::docstring const & l, char const * r)
{
}
-lyx::docstring operator+=(lyx::docstring & l, char const * r)
+lyx::docstring & operator+=(lyx::docstring & l, char const * r)
{
for (char const * c = r; *c; ++c) {
BOOST_ASSERT(static_cast<unsigned char>(*c) < 0x80);
}
-lyx::docstring operator+=(lyx::docstring & l, char r)
+lyx::docstring & operator+=(lyx::docstring & l, char r)
{
BOOST_ASSERT(static_cast<unsigned char>(r) < 0x80);
l.push_back(r);
return l;
}
+} // namespace lyx
#if (!defined(HAVE_WCHAR_T) || SIZEOF_WCHAR_T != 4) && defined(__GNUC__)
};
+class num_put_failure : public std::bad_cast {
+public:
+ num_put_failure() throw() : std::bad_cast() {}
+ virtual ~num_put_failure() throw() {}
+ virtual const char* what() const throw()
+ {
+ return "The num_put locale facet does only support ASCII characters on this platform.";
+ }
+};
+
+
/// ctype facet for UCS4 characters. The implementation does only support pure
/// ASCII, since we do not need anything else for now.
/// The code is partly stolen from std::ctype<wchar_t> from gcc.
};
-/// class to add our ascii_ctype_facet to the global locale
+/// Facet for outputting numbers to odocstreams as ascii.
+/// Here we simply need defining the virtual do_put functions.
+class ascii_num_put_facet : public std::num_put<lyx::char_type, std::ostreambuf_iterator<lyx::char_type, std::char_traits<lyx::char_type> > >
+{
+ typedef std::ostreambuf_iterator<lyx::char_type, std::char_traits<lyx::char_type> > iter_type;
+public:
+ ascii_num_put_facet(size_t refs = 0) : std::num_put<lyx::char_type, iter_type>(refs) {}
+
+ /// Facet for converting numbers to ascii strings.
+ class string_num_put_facet : public std::num_put<char, std::basic_string<char>::iterator>
+ {
+ public:
+ string_num_put_facet() : std::num_put<char, std::basic_string<char>::iterator>(1) {}
+ };
+
+protected:
+ iter_type
+ do_put(iter_type oit, std::ios_base & b, char_type fill, long v) const
+ {
+ if (fill >= 0x80)
+ throw num_put_failure();
+
+ std::string s;
+ // 64 is large enough
+ s.resize(64);
+ string_num_put_facet f;
+ std::string::const_iterator cit = s.begin();
+ std::string::const_iterator end =
+ f.put(s.begin(), b, fill, v);
+ for (; cit != end; ++cit, ++oit)
+ *oit = *cit;
+
+ return oit;
+ }
+};
+
+
+/// Facet for inputting ascii representations of numbers from idocstreams.
+/// Here we simply need defining the virtual do_get functions.
+class ascii_num_get_facet : public std::num_get<lyx::char_type, std::istreambuf_iterator<lyx::char_type, std::char_traits<lyx::char_type> > >
+{
+ typedef std::istreambuf_iterator<lyx::char_type, std::char_traits<lyx::char_type> > iter_type;
+public:
+ ascii_num_get_facet(size_t refs = 0) : std::num_get<lyx::char_type, iter_type>(refs) {}
+
+ /// Facet for converting ascii representation of numbers to a value.
+ class string_num_get_facet : public std::num_get<char, std::basic_string<char>::iterator>
+ {
+ public:
+ string_num_get_facet() : std::num_get<char, std::basic_string<char>::iterator>(1) {}
+ };
+
+private:
+ bool isNumpunct(lyx::char_type const c) const
+ {
+ /// Only account for the standard numpunct "C" locale facet.
+ return c < 0x80 && (c == '-' || c == '+' || isdigit(c)
+ || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')
+ || c == 'x' || c == 'X');
+ }
+
+protected:
+ iter_type
+ do_get(iter_type iit, iter_type eit, std::ios_base & b,
+ std::ios_base::iostate & err, long & v) const
+ {
+ std::string s;
+ s.reserve(64);
+ for (; iit != eit && isNumpunct(*iit); ++iit)
+ s += static_cast<char>(*iit);
+ string_num_get_facet f;
+ f.get(s.begin(), s.end(), b, err, v);
+
+ return iit;
+ }
+};
+
+
+/// class to add our facets to the global locale
class locale_initializer {
public:
locale_initializer()
{
std::locale global;
- std::locale const loc(global, new ascii_ctype_facet);
- std::locale::global(loc);
+ std::locale const loc1(global, new ascii_ctype_facet);
+ std::locale const loc2(loc1, new ascii_num_put_facet);
+ std::locale const loc3(loc2, new ascii_num_get_facet);
+ std::locale::global(loc3);
}
};
namespace {
-/// make sure that our ascii_ctype_facet gets used
+/// make sure that our facets get used
static locale_initializer initializer;
}