]> git.lyx.org Git - lyx.git/blobdiff - src/support/docstring.C
hopefully fix tex2lyx linking.
[lyx.git] / src / support / docstring.C
index ceffbc3832a2a0079352b9a8c0a511ddea71d41a..7ee1923df9909c87f31ca9e8caf36e2895f63462 100644 (file)
 #include "unicode.h"
 
 #include <locale>
+#include <iostream>
 
 #include <boost/assert.hpp>
 
 
 namespace lyx {
 
+
 docstring const from_ascii(char const * ascii)
 {
        docstring s;
@@ -53,11 +55,31 @@ std::string const to_ascii(docstring const & ucs4)
 }
 
 
+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;
 }
 
 
@@ -68,8 +90,6 @@ std::string const to_utf8(docstring const & ucs4)
        return std::string(utf8.begin(), utf8.end());
 }
 
-}
-
 
 bool operator==(lyx::docstring const & l, char const * r)
 {
@@ -122,7 +142,7 @@ lyx::docstring operator+(char l, lyx::docstring 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);
@@ -132,13 +152,14 @@ lyx::docstring operator+=(lyx::docstring & l, char const * r)
 }
 
 
-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__)
 
@@ -186,6 +207,17 @@ public:
 };
 
 
+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.
@@ -366,21 +398,101 @@ protected:
 };
 
 
-/// 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.resize(64);
+               for (int i = 0; iit != eit && isNumpunct(*iit); ++i, ++iit)
+                       s[i] = 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;
 
 }