X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fsupport%2Fdocstream.cpp;h=04b57045b24d2fed98bea7c4bb1aa52359512deb;hb=41a8994da902031a743373c1c57d028b7c900797;hp=def45c4d3b87ba9eb9629f1987a283a212ab2388;hpb=0cac034d10abf9185772c308d1a58f39853c3a54;p=lyx.git diff --git a/src/support/docstream.cpp b/src/support/docstream.cpp index def45c4d3b..04b57045b2 100644 --- a/src/support/docstream.cpp +++ b/src/support/docstream.cpp @@ -24,13 +24,28 @@ using namespace std; using lyx::ucs4_codeset; -using lyx::support::contains; -using lyx::support::split; #if defined(_MSC_VER) && (_MSC_VER >= 1600) std::locale::id numpunct::id; -#endif + +namespace std { +// Implementation of numpunct defined in numpunct_lyx_char_type.h +typedef basic_string string_type; + +string_type numpunct::truename() const +{ + return lyx::from_ascii(numpunct::truename()); +} + +string_type numpunct::falsename() const +{ + return lyx::from_ascii(numpunct::falsename()); +} + +} // namespace std + +#endif // _MSC_VER >= 1600 namespace { @@ -73,6 +88,7 @@ public: } else out_cd_ = (iconv_t)(-1); } + string const & encoding() const { return encoding_; } protected: virtual ~iconv_codecvt_facet() { @@ -265,7 +281,7 @@ private: inbytesleft, to, outbytesleft); if (converted == (size_t)(-1)) { switch(errno) { - case 0: + case 0: // As strange as it may seem, this // does happen on windows when parsing // comments with accented chars in @@ -291,7 +307,7 @@ private: string encoding_; }; -} // namespace anon +} // namespace namespace lyx { @@ -318,6 +334,12 @@ ifdocstream::ifdocstream() : base() } +ifdocstream::ifdocstream(SetEnc const & enc) : base() +{ + setEncoding(*this, enc.encoding, in); +} + + ifdocstream::ifdocstream(const char* s, ios_base::openmode mode, string const & encoding) : base() @@ -333,6 +355,12 @@ ofdocstream::ofdocstream(): base() } +ofdocstream::ofdocstream(SetEnc const & enc) : base() +{ + setEncoding(*this, enc.encoding, out); +} + + ofdocstream::ofdocstream(const char* s, ios_base::openmode mode, string const & encoding) : base() @@ -360,37 +388,51 @@ odocstream & operator<<(odocstream & os, SetEnc e) if (has_facet(os.rdbuf()->getloc())) { // This stream must be a file stream, since we never imbue // any other stream with a locale having a iconv_codecvt_facet. + iconv_codecvt_facet const & facet = + use_facet(os.rdbuf()->getloc()); + + // FIXME Changing the codecvt facet of an open file is allowed, + // but unsafe for facets that use internal state (see the thread + // "iostreams: Does imbue() need to be called before open()?" + // in comp.std.c++. + // Currently it seems to work with gcc and MSVC, but not with + // clang on OS X. + // Avoid imbueing with the same encoding again if possible. + if (facet.encoding() == e.encoding) + return os; + // Flush the stream so that all pending output is written // with the old encoding. os.flush(); + locale locale(os.rdbuf()->getloc(), new iconv_codecvt_facet(e.encoding, ios_base::out)); - // FIXME Does changing the codecvt facet of an open file - // stream always work? It does with gcc 4.1, but I have read - // somewhere that it does not with MSVC. - // What does the standard say? os.imbue(locale); } return os; } -//CHECKME: I just copied the code above, and have no idea whether it -//is correct... (JMarc) idocstream & operator<<(idocstream & is, SetEnc e) { if (has_facet(is.rdbuf()->getloc())) { // This stream must be a file stream, since we never imbue // any other stream with a locale having a iconv_codecvt_facet. - // Flush the stream so that all pending output is written - // with the old encoding. - //is.flush(); + iconv_codecvt_facet const & facet = + use_facet(is.rdbuf()->getloc()); + + // FIXME Changing the codecvt facet of an open file is allowed, + // but unsafe for facets that use internal state (see the thread + // "iostreams: Does imbue() need to be called before open()?" + // in comp.std.c++. + // Currently it seems to work with gcc and MSVC, but not with + // clang on OS X. + // Avoid imbueing with the same encoding again if possible. + if (facet.encoding() == e.encoding) + return is; + locale locale(is.rdbuf()->getloc(), new iconv_codecvt_facet(e.encoding, ios_base::in)); - // FIXME Does changing the codecvt facet of an open file - // stream always work? It does with gcc 4.1, but I have read - // somewhere that it does not with MSVC. - // What does the standard say? is.imbue(locale); } return is; @@ -405,220 +447,8 @@ odocstream & operator<<(odocstream & os, char c) } #endif +} // namespace lyx -void otexstream::put(char_type const & c) -{ - if (protectspace_) { - if (!canbreakline_ && c == ' ') - os_ << "{}"; - protectspace_ = false; - } - os_.put(c); - lastchar_ = c; - if (c == '\n') { - texrow_.newline(); - canbreakline_ = false; - } else - canbreakline_ = true; -} - - -BreakLine breakln; -SafeBreakLine safebreakln; - - -otexstream & operator<<(otexstream & ots, BreakLine) -{ - if (ots.canBreakLine()) { - ots.os().put('\n'); - ots.lastChar('\n'); - ots.canBreakLine(false); - ots.texrow().newline(); - } - ots.protectSpace(false); - return ots; -} - - -otexstream & operator<<(otexstream & ots, SafeBreakLine) -{ - if (ots.canBreakLine()) { - ots.os() << "%\n"; - ots.lastChar('\n'); - ots.canBreakLine(false); - ots.texrow().newline(); - } - ots.protectSpace(false); - return ots; -} - - -otexstream & operator<<(otexstream & ots, odocstream_manip pf) -{ - ots.os() << pf; - if (pf == static_cast(endl)) { - ots.lastChar('\n'); - ots.texrow().newline(); - } - return ots; -} - - -otexstream & operator<<(otexstream & ots, docstring const & s) -{ - size_t const len = s.length(); - - // Check whether there's something to output - if (len == 0) - return ots; - - if (ots.protectSpace()) { - if (!ots.canBreakLine() && s[0] == ' ') - ots.os() << "{}"; - ots.protectSpace(false); - } - - if (contains(s, 0xF0000)) { - // Some encoding changes for the underlying stream are embedded - // in the docstring. The encoding names to be used are enclosed - // between the code points 0xF0000 and 0xF0001, the first two - // characters of plane 15, which is a Private Use Area whose - // codepoints don't have any associated glyph. - docstring s1; - docstring s2 = split(s, s1, 0xF0000); - while (true) { - if (!s1.empty()) - ots.os() << s1; - if (s2.empty()) - break; - docstring enc; - docstring const s3 = split(s2, enc, 0xF0001); - if (!contains(s2, 0xF0001)) - s2 = split(enc, s1, 0xF0000); - else { - ots.os() << setEncoding(to_ascii(enc)); - s2 = split(s3, s1, 0xF0000); - } - } - } else - ots.os() << s; - - ots.lastChar(s[len - 1]); - ots.texrow().newlines(count(s.begin(), s.end(), '\n')); - ots.canBreakLine(s[len - 1] != '\n'); - return ots; -} - - -otexstream & operator<<(otexstream & ots, string const & s) -{ - ots << s.c_str(); - return ots; -} - - -namespace { - -int findToken(char const * s, char const * search_token) -{ - char const * token = strstr(s, search_token); - if (token) - return token - s; - return -1; -} - -} // namespace anon - - -otexstream & operator<<(otexstream & ots, char const * s) -{ - size_t const len = strlen(s); - - // Check whether there's something to output - if (len == 0) - return ots; - - if (ots.protectSpace()) { - if (!ots.canBreakLine() && s[0] == ' ') - ots.os() << "{}"; - ots.protectSpace(false); - } - - char const * start_token = "\xf3\xb0\x80\x80"; - char const * end_token = "\xf3\xb0\x80\x81"; - - int i = findToken(s, start_token); - - if (i >= 0) { - // Some encoding changes for the underlying stream are embedded - // in the string. The encoding names to be used are enclosed - // between the code points 0xF0000 and xF0001 (0xf3b08080 and - // 0xf3b08081 in utf8 encoding). This codepoints belong to the - // plane 15 Private Use Area and have no associated glyph. - string s1(s, i); - char const * s2 = s + i + 4; - while (true) { - if (!s1.empty()) - ots.os() << s1; - if (s2[0] == '\0') - break; - i = findToken(s2, end_token); - if (i >= 0) { - ots.os() << setEncoding(string(s2, i)); - s2 += i + 4; - } - i = findToken(s2, start_token); - if (i >= 0) { - s1 = string(s2, i); - s2 += i + 4; - } else { - s1 = s2; - s2 += strlen(s2); - } - } - } else - ots.os() << s; - - ots.lastChar(s[len - 1]); - ots.texrow().newlines(count(s, s + len, '\n')); - ots.canBreakLine(s[len - 1] != '\n'); - return ots; -} - - -otexstream & operator<<(otexstream & ots, char c) -{ - if (ots.protectSpace()) { - if (!ots.canBreakLine() && c == ' ') - ots.os() << "{}"; - ots.protectSpace(false); - } - ots.os() << c; - ots.lastChar(c); - if (c == '\n') - ots.texrow().newline(); - ots.canBreakLine(c != '\n'); - return ots; -} - - -template -otexstream & operator<<(otexstream & ots, Type value) -{ - ots.os() << value; - ots.lastChar(0); - ots.canBreakLine(true); - ots.protectSpace(false); - return ots; -} - -template otexstream & operator<< (otexstream & os, SetEnc); -template otexstream & operator<< (otexstream &, double); -template otexstream & operator<< (otexstream &, int); -template otexstream & operator<< (otexstream &, unsigned int); -template otexstream & operator<< (otexstream &, unsigned long); - -} #if ! defined(USE_WCHAR_T) && defined(__GNUC__) // We get undefined references to these virtual methods. This looks like @@ -665,17 +495,6 @@ bool codecvt::do_always_noconv() const throw() return true; } -#if __GNUC__ == 3 && __GNUC_MINOR__ < 4 - -template<> -int codecvt::do_length( - mbstate_t const &, const char *, const char *, size_t) const -{ - return 1; -} - -#else - template<> int codecvt::do_length( mbstate_t &, const char *, const char *, size_t) const @@ -683,8 +502,6 @@ int codecvt::do_length( return 1; } -#endif - template<> int codecvt::do_max_length() const throw() {