]> git.lyx.org Git - lyx.git/blobdiff - src/support/docstring.C
* support/qstring_helpers.h: erase ucs4_to_qstring() method.
[lyx.git] / src / support / docstring.C
index b3e8a76b1eda3e502be2fa5974815c20397dfbca..89abf212991ebf5fec66865e629fb5b95f05f688 100644 (file)
 #include <config.h>
 
 #include "docstring.h"
+#include "qstring_helpers.h"
 #include "unicode.h"
 
 #include <locale>
 #include <iostream>
 
+#include <QFile>
+
 #include <boost/assert.hpp>
 
 
@@ -55,16 +58,16 @@ std::string const to_ascii(docstring const & ucs4)
 }
 
 
-void utf8_to_ucs4(std::string const & utf8, docstring & ucs4)
+IconvProcessor & utf8ToUcs4()
 {
-       // FIXME (Abdel 17/11/06): static data are evil!
-       // This function cannot be used in the final exit process on Mac because
-       // static data are already destroyed at this stage.
-       // One solution would be to instantiate the utf8 to ucs4 IconvProcessor as a 
-       // singleton inside the LyX main class to ensure that it does not get 
-       // destroyed too early.
        static IconvProcessor iconv(ucs4_codeset, "UTF-8");
+       return iconv;
+}
+
+
 
+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:
@@ -76,7 +79,7 @@ void utf8_to_ucs4(std::string const & utf8, docstring & ucs4)
        // basic_string::data() is not recognized by some old gcc version
        // so we use &(ucs4[0]) instead.
        char * outbuf = (char *)(&(ucs4[0]));
-       int bytes = iconv.convert(utf8.c_str(), n, outbuf, maxoutsize);
+       int bytes = utf8ToUcs4().convert(utf8.c_str(), n, outbuf, maxoutsize);
 
        // adjust to the real converted size
        ucs4.resize(bytes/4);
@@ -99,6 +102,44 @@ std::string const to_utf8(docstring const & ucs4)
 }
 
 
+docstring const from_local8bit(std::string const & s)
+{
+       return qstring_to_ucs4(QString::fromLocal8Bit(s.data(), s.length()));
+}
+
+
+const char* to_local8bit_failure::what() const throw()
+{
+       return "A string could not be converted from unicode to the local 8 bit encoding.";
+}
+
+
+std::string const to_local8bit(docstring const & s)
+{
+       // This conversion can fail, depending on input.
+       if (s.empty())
+               return std::string();
+       QByteArray const local = toqstr(s).toLocal8Bit();
+       if (local.size() == 0)
+               throw to_local8bit_failure();
+       return std::string(local.begin(), local.end());
+}
+
+
+docstring const from_filesystem8bit(std::string const & s)
+{
+       QByteArray const encoded(s.c_str(), s.length());
+       return qstring_to_ucs4(QFile::decodeName(encoded));
+}
+
+
+std::string const to_filesystem8bit(docstring const & s)
+{
+       QByteArray const encoded = QFile::encodeName(toqstr(s));
+       return std::string(encoded.begin(), encoded.end());
+}
+
+
 bool operator==(lyx::docstring const & l, char const * r)
 {
        int const len = l.length();
@@ -422,15 +463,69 @@ public:
        };
 
 protected:
+       iter_type
+       do_put(iter_type oit, std::ios_base & b, char_type fill, bool v) const
+       {
+               return do_put_helper(oit, b, fill, v);
+       }
+
        iter_type
        do_put(iter_type oit, std::ios_base & b, char_type fill, long v) const
+       {
+               return do_put_helper(oit, b, fill, v);
+       }
+
+       iter_type
+       do_put(iter_type oit, std::ios_base & b, char_type fill, unsigned long v) const
+       {
+               return do_put_helper(oit, b, fill, v);
+       }
+
+#ifdef _GLIBCXX_USE_LONG_LONG
+       iter_type
+       do_put(iter_type oit, std::ios_base & b, char_type fill, long long v) const
+       {
+               return do_put_helper(oit, b, fill, v);
+       }
+
+       iter_type
+       do_put(iter_type oit, std::ios_base & b, char_type fill, unsigned long long v) const
+       {
+               return do_put_helper(oit, b, fill, v);
+       }
+#endif
+
+       iter_type
+       do_put(iter_type oit, std::ios_base & b, char_type fill, double v) const
+       {
+               return do_put_helper(oit, b, fill, v);
+       }
+
+       iter_type
+       do_put(iter_type oit, std::ios_base & b, char_type fill, long double v) const
+       {
+               return do_put_helper(oit, b, fill, v);
+       }
+
+       iter_type
+       do_put(iter_type oit, std::ios_base & b, char_type fill, void const * v) const
+       {
+               return do_put_helper(oit, b, fill, v);
+       }
+
+private:
+       template <typename ValueType>
+       iter_type
+       do_put_helper(iter_type oit, std::ios_base & b, char_type fill, ValueType v) const
        {
                if (fill >= 0x80)
                        throw num_put_failure();
 
-               std::string s;
-               // 64 is large enough
-               s.resize(64);
+               std::streamsize const sz = b.width() > b.precision() ?
+                                          b.width() : b.precision();
+               // 64 is large enough, unless width or precision are bigger
+               std::streamsize const wd = (sz > 56 ? sz : 56) + 8;
+               std::string s(wd, '\0');
                string_num_put_facet f;
                std::string::const_iterator cit = s.begin();
                std::string::const_iterator end =
@@ -443,6 +538,52 @@ protected:
 };
 
 
+/// 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);
+               // We add another character, not part of the numpunct facet,
+               // in order to avoid setting the eofbit in the stream state,
+               // which would prevent any further read. The space seems a
+               // good choice here.
+               s += ' ';
+               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:
@@ -451,7 +592,8 @@ public:
                std::locale global;
                std::locale const loc1(global, new ascii_ctype_facet);
                std::locale const loc2(loc1, new ascii_num_put_facet);
-               std::locale::global(loc2);
+               std::locale const loc3(loc2, new ascii_num_get_facet);
+               std::locale::global(loc3);
        }
 };