lyx_mirror/src/support/docstream.cpp

513 lines
14 KiB
C++
Raw Normal View History

/**
Rename files in src/support, step one. src/support/package.h src/support/Package.h Package src/support/package.C.in src/support/Package.C.in Package src/support/path.h src/support/Path.h Path src/support/fs_extras.h src/support/fs_extras.h NOCLASSES src/support/RandomAccessList.h src/support/RandomAccessList.h RandomAccessList src/support/lyxmanip.h src/support/lyxmanip.h NOCLASSES src/support/rename.C src/support/rename.cpp NOCLASSES src/support/abort.C src/support/abort.cpp NOCLASSES src/support/lyxlib.h src/support/lyxlib.h NOCLASSES src/support/ExceptionMessage.h src/support/ExceptionMessage.h ExceptionMessage src/support/copy.C src/support/copy.cpp NOCLASSES src/support/limited_stack.h src/support/limited_stack.h limited_stack src/support/filefilterlist.C src/support/FileFilterList.cpp ['FileFilterList', 'Filter'] src/support/cow_ptr.h src/support/cow_ptr.h cow_ptr src/support/os_unix.C src/support/os_unix.cpp NOCLASSES src/support/socktools.h src/support/socktools.h NOCLASSES src/support/forkedcontr.h src/support/ForkedcallsController.h ForkedcallsController src/support/os.h src/support/os.h NOCLASSES src/support/FileMonitor.h src/support/FileMonitor.h FileMonitor src/support/copied_ptr.h src/support/copied_ptr.h copied_ptr src/support/translator.h src/support/Translator.h Translator src/support/filetools.C src/support/filetools.cpp NOCLASSES src/support/unlink.C src/support/unlink.cpp NOCLASSES src/support/os_win32.C src/support/os_win32.cpp GetFolderPath src/support/lstrings.C src/support/lstrings.cpp NOCLASSES src/support/qstring_helpers.C src/support/qstring_helpers.cpp NOCLASSES src/support/getcwd.C src/support/getcwd.cpp NOCLASSES src/support/systemcall.C src/support/Systemcall.cpp Systemcall src/support/lyxalgo.h src/support/lyxalgo.h NOCLASSES src/support/filefilterlist.h src/support/FileFilterList.h ['FileFilterList', 'Filter'] src/support/unicode.C src/support/unicode.cpp IconvProcessor src/support/userinfo.C src/support/userinfo.cpp NOCLASSES src/support/lyxtime.C src/support/lyxtime.cpp NOCLASSES src/support/kill.C src/support/kill.cpp NOCLASSES src/support/docstring.C src/support/docstring.cpp to_local8bit_failure src/support/os_cygwin.C src/support/os_cygwin.cpp NOCLASSES src/support/lyxsum.C src/support/lyxsum.cpp NOCLASSES src/support/environment.C src/support/environment.cpp NOCLASSES src/support/filetools.h src/support/filetools.h NOCLASSES src/support/textutils.C src/support/textutils.cpp NOCLASSES src/support/mkdir.C src/support/mkdir.cpp NOCLASSES src/support/forkedcall.C src/support/Forkedcall.cpp ['ForkedProcess', 'Forkedcall'] src/support/tempname.C src/support/tempname.cpp NOCLASSES src/support/os_win32.h src/support/os_win32.h GetFolderPath src/support/types.h src/support/types.h NOCLASSES src/support/lstrings.h src/support/lstrings.h NOCLASSES src/support/forkedcallqueue.C src/support/ForkedCallQueue.cpp ForkedCallQueue src/support/qstring_helpers.h src/support/qstring_helpers.h NOCLASSES src/support/convert.C src/support/convert.cpp NOCLASSES src/support/filename.C src/support/FileName.cpp ['FileName', 'DocFileName'] src/support/tests/convert.C src/support/tests/convert.cpp NOCLASSES src/support/tests/filetools.C src/support/tests/filetools.cpp NOCLASSES src/support/tests/lstrings.C src/support/tests/lstrings.cpp NOCLASSES src/support/tests/boost.C src/support/tests/boost.cpp NOCLASSES src/support/docstream.C src/support/docstream.cpp ['iconv_codecvt_facet_exception', 'idocfstream', 'odocfstream'] src/support/std_istream.h src/support/std_istream.h NOCLASSES src/support/systemcall.h src/support/Systemcall.h Systemcall src/support/chdir.C src/support/chdir.cpp NOCLASSES src/support/std_ostream.h src/support/std_ostream.h NOCLASSES src/support/unicode.h src/support/unicode.h IconvProcessor src/support/path.C src/support/Path.cpp Path src/support/fs_extras.C src/support/fs_extras.cpp NOCLASSES src/support/userinfo.h src/support/userinfo.h NOCLASSES src/support/lyxtime.h src/support/lyxtime.h NOCLASSES src/support/docstring.h src/support/docstring.h to_local8bit_failure src/support/debugstream.h src/support/debugstream.h basic_debugstream src/support/environment.h src/support/environment.h NOCLASSES src/support/textutils.h src/support/textutils.h NOCLASSES src/support/forkedcall.h src/support/Forkedcall.h ['ForkedProcess', 'Forkedcall'] src/support/socktools.C src/support/socktools.cpp NOCLASSES src/support/forkedcallqueue.h src/support/ForkedCallQueue.h ForkedCallQueue src/support/forkedcontr.C src/support/ForkedcallsController.cpp ForkedcallsController src/support/os.C src/support/os.cpp NOCLASSES src/support/convert.h src/support/convert.h NOCLASSES src/support/filename.h src/support/FileName.h ['FileName', 'DocFileName'] src/support/docstream.h src/support/docstream.h ['iconv_codecvt_facet_exception', 'idocfstream', 'odocfstream'] src/support/FileMonitor.C src/support/FileMonitor.cpp FileMonitor git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@18024 a592a061-630c-0410-9148-cb99ea01b6c8
2007-04-26 05:12:52 +00:00
* \file docstream.cpp
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Georg Baum
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include "support/docstream.h"
#include "support/lstrings.h"
#include "support/unicode.h"
Introduce a wrapper class for odocstream to help ensuring that no blank lines may be inadvertently output. This is achieved by using two special iomanip-like variables (breakln and safebreakln) in the lyx:: namespace. When they are inserted in the stream, a newline is output only if not already at the beginning of a line. The difference between breakln and safebreakln is that, if needed, the former outputs '\n' and the latter "%\n". In future, the new class will also be used for counting the number of newlines issued. Even if the infractrure for doing that is already in place, the counting is essentially still done the old way. There are still places in the code where the functionality of the class could be used, most probably. ATM, it is used for InsetTabular, InsetListings, InsetFloat, and InsetText. The Comment and GreyedOut insets required a special treatment and a new InsetLayout parameter (Display) has been introduced. The default for Display is "true", meaning that the corresponding latex environment is of "display" type, i.e., it stands on its own, whereas "false" means that the contents appear inline with the text. The latter is the case for both Comment and GreyedOut insets. Mostly, the only visible effects on latex exports should be the disappearing of some redundant % chars and the appearing/disappearing of null {} latex groups after a comment or lyxgreyedout environments (they are related to the presence or absence of a space immediately after those environments), as well as the fact that math environments are now started on their own lines. As a last thing, only the latex code between \begin{document} and \end{document} goes through the new class, the preamble being directly output through odocstream, as usual. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
#include <algorithm>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <iconv.h>
#include <locale>
using namespace std;
using lyx::ucs4_codeset;
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
std::locale::id numpunct<lyx::char_type>::id;
namespace std {
// Implementation of numpunct<lyx::char_type> defined in numpunct_lyx_char_type.h
typedef basic_string<lyx::char_type> string_type;
string_type numpunct<lyx::char_type>::truename() const
{
return lyx::from_ascii(numpunct<char>::truename());
}
string_type numpunct<lyx::char_type>::falsename() const
{
return lyx::from_ascii(numpunct<char>::falsename());
}
} // namespace std
#endif // _MSC_VER >= 1600
namespace {
// We use C IO throughout this file, because the facets might be used with
// lyxerr in the future.
/// codecvt facet for conversion of UCS4 (internal representation) to UTF8
/// (external representation) or vice versa
class iconv_codecvt_facet : public codecvt<lyx::char_type, char, mbstate_t>
{
typedef codecvt<lyx::char_type, char, mbstate_t> base;
public:
/// Constructor. You have to specify with \p inout whether you want
/// to use this facet only for input, only for output or for both.
explicit iconv_codecvt_facet(string const & encoding = "UTF-8",
ios_base::openmode inout = ios_base::in | ios_base::out,
size_t refs = 0)
: base(refs), encoding_(encoding)
{
if (inout & ios_base::in) {
in_cd_ = iconv_open(ucs4_codeset, encoding.c_str());
if (in_cd_ == (iconv_t)(-1)) {
fprintf(stderr, "Error %d returned from iconv_open(in_cd_): %s\n",
errno, strerror(errno));
fflush(stderr);
throw lyx::iconv_codecvt_facet_exception();
}
} else
in_cd_ = (iconv_t)(-1);
if (inout & ios_base::out) {
out_cd_ = iconv_open(encoding.c_str(), ucs4_codeset);
if (out_cd_ == (iconv_t)(-1)) {
fprintf(stderr, "Error %d returned from iconv_open(out_cd_): %s\n",
errno, strerror(errno));
fflush(stderr);
throw lyx::iconv_codecvt_facet_exception();
}
} else
out_cd_ = (iconv_t)(-1);
}
string const & encoding() const { return encoding_; }
protected:
virtual ~iconv_codecvt_facet()
{
if (in_cd_ != (iconv_t)(-1))
if (iconv_close(in_cd_) == -1) {
fprintf(stderr, "Error %d returned from iconv_close(in_cd_): %s\n",
errno, strerror(errno));
fflush(stderr);
}
if (out_cd_ != (iconv_t)(-1))
if (iconv_close(out_cd_) == -1) {
fprintf(stderr, "Error %d returned from iconv_close(out_cd_): %s\n",
errno, strerror(errno));
fflush(stderr);
}
}
virtual result do_out(state_type &, intern_type const * from,
intern_type const * from_end, intern_type const *& from_next,
extern_type * to, extern_type * to_end,
extern_type *& to_next) const
{
#define WORKAROUND_ICONV_BUG 1
#if WORKAROUND_ICONV_BUG
// Due to a bug in some iconv versions, when the last char
// in the buffer is a wide char and the output encoding is
// ISO-2022-JP and we are going to switch to another encoding,
// the appropriate escape sequence for changing the character
// set is not output (see bugs 5216, 5280, and also 5489).
// As a workaround, we append a nul char in order to force
// a switch to ASCII, and then remove it from output after
// the conversion.
intern_type * from_new = 0;
intern_type const * from_old = from;
size_t extra = 0;
if (*(from_end - 1) >= 0x80 && encoding_ == "ISO-2022-JP") {
size_t len = from_end - from;
from_new = new intern_type[len + 1];
memcpy(from_new, from, len * sizeof(intern_type));
from_new[len] = 0;
from_end = from_new + len + 1;
from = from_new;
extra = 1;
}
#endif
size_t inbytesleft = (from_end - from) * sizeof(intern_type);
size_t outbytesleft = (to_end - to) * sizeof(extern_type);
#if WORKAROUND_ICONV_BUG
outbytesleft += extra * sizeof(extern_type);
#endif
from_next = from;
to_next = to;
result const retval = do_iconv(out_cd_,
reinterpret_cast<char const **>(&from_next),
&inbytesleft, &to_next, &outbytesleft);
#if WORKAROUND_ICONV_BUG
// Remove from output the nul char that we inserted at the end
// of the input buffer in order to circumvent an iconv bug.
if (from_new) {
--to_next;
--from_next;
from_next = from_old + (from_next - from);
from = from_old;
delete[] from_new;
}
#endif
if (retval == base::error) {
fprintf(stderr,
"Error %d returned from iconv when converting from %s to %s: %s\n",
errno, ucs4_codeset, encoding_.c_str(),
strerror(errno));
fputs("Converted input:", stderr);
for (intern_type const * i = from; i < from_next; ++i) {
unsigned int const c = *i;
fprintf(stderr, " 0x%04x", c);
}
unsigned int const c = *from_next;
fprintf(stderr, "\nStopped at: 0x%04x\n", c);
fputs("Unconverted input:", stderr);
for (intern_type const * i = from_next + 1; i < from_end; ++i) {
unsigned int const c = *i;
fprintf(stderr, " 0x%04x", c);
}
fputs("\nConverted output:", stderr);
for (extern_type const * i = to; i < to_next; ++i) {
// extern_type may be signed, avoid output of
// something like 0xffffffc2
unsigned int const c =
*reinterpret_cast<unsigned char const *>(i);
fprintf(stderr, " 0x%02x", c);
}
fputc('\n', stderr);
fflush(stderr);
}
return retval;
}
virtual result do_unshift(state_type &, extern_type * to,
extern_type *, extern_type *& to_next) const
{
// utf8 does not use shifting
to_next = to;
return base::noconv;
}
virtual result do_in(state_type &,
extern_type const * from, extern_type const * from_end,
extern_type const *& from_next,
intern_type * to, intern_type * to_end,
intern_type *& to_next) const
{
size_t inbytesleft = (from_end - from) * sizeof(extern_type);
size_t outbytesleft = (to_end - to) * sizeof(intern_type);
from_next = from;
to_next = to;
result const retval = do_iconv(in_cd_, &from_next, &inbytesleft,
reinterpret_cast<char **>(&to_next),
&outbytesleft);
if (retval == base::error) {
fprintf(stderr,
"Error %d returned from iconv when converting from %s to %s: %s\n",
errno, encoding_.c_str(), ucs4_codeset,
strerror(errno));
fputs("Converted input:", stderr);
for (extern_type const * i = from; i < from_next; ++i) {
// extern_type may be signed, avoid output of
// something like 0xffffffc2
unsigned int const c =
*reinterpret_cast<unsigned char const *>(i);
fprintf(stderr, " 0x%02x", c);
}
unsigned int const c =
*reinterpret_cast<unsigned char const *>(from_next);
fprintf(stderr, "\nStopped at: 0x%02x\n", c);
fputs("Unconverted input:", stderr);
for (extern_type const * i = from_next + 1; i < from_end; ++i) {
unsigned int const c =
*reinterpret_cast<unsigned char const *>(i);
fprintf(stderr, " 0x%02x", c);
}
fputs("\nConverted output:", stderr);
for (intern_type const * i = to; i < to_next; ++i) {
unsigned int const c = *i;
fprintf(stderr, " 0x%02x", c);
}
fputc('\n', stderr);
fflush(stderr);
}
return retval;
}
virtual int do_encoding() const throw()
{
return 0;
}
virtual bool do_always_noconv() const throw()
{
return false;
}
virtual int do_length(state_type & /*state*/, extern_type const * from,
extern_type const * end, size_t max) const
{
// The docs are a bit unclear about this method.
// It seems that we should calculate the actual length of the
// converted sequence, but that would not make sense, since
// once could just do the conversion directly.
// Therefore we just return the number of unconverted
// characters, since that is the best guess we can do.
#if 0
intern_type * to = new intern_type[max];
intern_type * to_end = to + max;
intern_type * to_next = to;
extern_type const * from_next = from;
do_in(state, from, end, from_next, to, to_end, to_next);
delete[] to;
return to_next - to;
#else
size_t const length = end - from;
return min(length, max);
#endif
}
virtual int do_max_length() const throw()
{
return lyx::max_encoded_bytes(encoding_);
}
private:
/// Do the actual conversion. The interface is equivalent to that of
/// iconv() (but const correct).
inline base::result do_iconv(iconv_t cd, char const ** from,
size_t * inbytesleft, char ** to, size_t * outbytesleft) const
{
char const * const to_start = *to;
size_t converted = iconv(cd, const_cast<char ICONV_CONST **>(from),
inbytesleft, to, outbytesleft);
if (converted == (size_t)(-1)) {
switch(errno) {
case 0:
// As strange as it may seem, this
// does happen on windows when parsing
// comments with accented chars in
// tex2lyx. See the following thread
// for details
// http://thread.gmane.org/gmane.editors.lyx.devel/117636
break;
case EINVAL:
case E2BIG:
return base::partial;
case EILSEQ:
default:
return base::error;
}
}
if (*to == to_start)
return base::noconv;
return base::ok;
}
iconv_t in_cd_;
iconv_t out_cd_;
/// The narrow encoding
string encoding_;
};
} // namespace anon
namespace lyx {
template<class Ios>
void setEncoding(Ios & ios, string const & encoding, ios_base::openmode mode)
{
// We must imbue the stream before openening the file
locale global;
locale locale(global, new iconv_codecvt_facet(encoding, mode));
ios.imbue(locale);
}
const char * iconv_codecvt_facet_exception::what() const throw()
{
return "iconv problem in iconv_codecvt_facet initialization";
}
ifdocstream::ifdocstream() : base()
{
setEncoding(*this, "UTF-8", in);
}
ifdocstream::ifdocstream(SetEnc const & enc) : base()
{
setEncoding(*this, enc.encoding, in);
}
ifdocstream::ifdocstream(const char* s, ios_base::openmode mode,
string const & encoding)
: base()
{
setEncoding(*this, encoding, in);
open(s, mode);
}
ofdocstream::ofdocstream(): base()
{
setEncoding(*this, "UTF-8", out);
}
ofdocstream::ofdocstream(SetEnc const & enc) : base()
{
setEncoding(*this, enc.encoding, out);
}
ofdocstream::ofdocstream(const char* s, ios_base::openmode mode,
string const & encoding)
: base()
{
setEncoding(*this, encoding, out);
open(s, mode);
}
Make the output of \inputencoding commands (and the change of output encodings) more fine grained: From paragraph level to individual character level. The inputenc package supports that since at least 2000. * src/insets/insetbase.h (latex): Document the differences between output to a string stream and a file stream * src/buffer.h (writeLaTeXSource): ditto * src/output_latex.h (latexParagraphs): ditto (switchEncoding): new function to change the encoding of a stream (and output \inputencoding commands) * src/paragraph_pimpl.C (Paragraph::Pimpl::simpleTeXSpecialC): Adjust to latexWriteEndChanges changes * src/support/docstream.[Ch] (setEncoding, operator<<): New stream modifier that changes the encoding of file streams * src/lyxfont.[Ch] (LyXFont::latexWriteStartChanges): Change stream encoding if needed (LyXFont::latexWriteEndChanges): Change stream encoding if needed * src/lyxfont.h (public:): * src/paragraph.C (Paragraph::simpleTeXOnePar): Adjust to latexWriteStartChanges and latexWriteEndChanges changes (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): * src/output_latex.C (TeXOnePar): Remove the ugly hack to for wencoding changes and use switchEncoding instead. A nice side effect is that the old hack would not work if the main language encoding is latin1 and a character would be mapped to a cedilla in the "fake ucs4" encoding, because iconv refuses to convert such a character to latin1, although it exists in latin1 (it wants to attach it to a base character). git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16633 a592a061-630c-0410-9148-cb99ea01b6c8
2007-01-09 19:25:40 +00:00
void ofdocstream::reset(string const & encoding)
{
setEncoding(*this, encoding, out);
}
Make the output of \inputencoding commands (and the change of output encodings) more fine grained: From paragraph level to individual character level. The inputenc package supports that since at least 2000. * src/insets/insetbase.h (latex): Document the differences between output to a string stream and a file stream * src/buffer.h (writeLaTeXSource): ditto * src/output_latex.h (latexParagraphs): ditto (switchEncoding): new function to change the encoding of a stream (and output \inputencoding commands) * src/paragraph_pimpl.C (Paragraph::Pimpl::simpleTeXSpecialC): Adjust to latexWriteEndChanges changes * src/support/docstream.[Ch] (setEncoding, operator<<): New stream modifier that changes the encoding of file streams * src/lyxfont.[Ch] (LyXFont::latexWriteStartChanges): Change stream encoding if needed (LyXFont::latexWriteEndChanges): Change stream encoding if needed * src/lyxfont.h (public:): * src/paragraph.C (Paragraph::simpleTeXOnePar): Adjust to latexWriteStartChanges and latexWriteEndChanges changes (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): * src/output_latex.C (TeXOnePar): Remove the ugly hack to for wencoding changes and use switchEncoding instead. A nice side effect is that the old hack would not work if the main language encoding is latin1 and a character would be mapped to a cedilla in the "fake ucs4" encoding, because iconv refuses to convert such a character to latin1, although it exists in latin1 (it wants to attach it to a base character). git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16633 a592a061-630c-0410-9148-cb99ea01b6c8
2007-01-09 19:25:40 +00:00
SetEnc setEncoding(string const & encoding)
{
return SetEnc(encoding);
}
odocstream & operator<<(odocstream & os, SetEnc e)
{
if (has_facet<iconv_codecvt_facet>(os.rdbuf()->getloc())) {
Make the output of \inputencoding commands (and the change of output encodings) more fine grained: From paragraph level to individual character level. The inputenc package supports that since at least 2000. * src/insets/insetbase.h (latex): Document the differences between output to a string stream and a file stream * src/buffer.h (writeLaTeXSource): ditto * src/output_latex.h (latexParagraphs): ditto (switchEncoding): new function to change the encoding of a stream (and output \inputencoding commands) * src/paragraph_pimpl.C (Paragraph::Pimpl::simpleTeXSpecialC): Adjust to latexWriteEndChanges changes * src/support/docstream.[Ch] (setEncoding, operator<<): New stream modifier that changes the encoding of file streams * src/lyxfont.[Ch] (LyXFont::latexWriteStartChanges): Change stream encoding if needed (LyXFont::latexWriteEndChanges): Change stream encoding if needed * src/lyxfont.h (public:): * src/paragraph.C (Paragraph::simpleTeXOnePar): Adjust to latexWriteStartChanges and latexWriteEndChanges changes (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): * src/output_latex.C (TeXOnePar): Remove the ugly hack to for wencoding changes and use switchEncoding instead. A nice side effect is that the old hack would not work if the main language encoding is latin1 and a character would be mapped to a cedilla in the "fake ucs4" encoding, because iconv refuses to convert such a character to latin1, although it exists in latin1 (it wants to attach it to a base character). git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16633 a592a061-630c-0410-9148-cb99ea01b6c8
2007-01-09 19:25:40 +00:00
// 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<iconv_codecvt_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;
Make the output of \inputencoding commands (and the change of output encodings) more fine grained: From paragraph level to individual character level. The inputenc package supports that since at least 2000. * src/insets/insetbase.h (latex): Document the differences between output to a string stream and a file stream * src/buffer.h (writeLaTeXSource): ditto * src/output_latex.h (latexParagraphs): ditto (switchEncoding): new function to change the encoding of a stream (and output \inputencoding commands) * src/paragraph_pimpl.C (Paragraph::Pimpl::simpleTeXSpecialC): Adjust to latexWriteEndChanges changes * src/support/docstream.[Ch] (setEncoding, operator<<): New stream modifier that changes the encoding of file streams * src/lyxfont.[Ch] (LyXFont::latexWriteStartChanges): Change stream encoding if needed (LyXFont::latexWriteEndChanges): Change stream encoding if needed * src/lyxfont.h (public:): * src/paragraph.C (Paragraph::simpleTeXOnePar): Adjust to latexWriteStartChanges and latexWriteEndChanges changes (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): * src/output_latex.C (TeXOnePar): Remove the ugly hack to for wencoding changes and use switchEncoding instead. A nice side effect is that the old hack would not work if the main language encoding is latin1 and a character would be mapped to a cedilla in the "fake ucs4" encoding, because iconv refuses to convert such a character to latin1, although it exists in latin1 (it wants to attach it to a base character). git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16633 a592a061-630c-0410-9148-cb99ea01b6c8
2007-01-09 19:25:40 +00:00
// 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));
Make the output of \inputencoding commands (and the change of output encodings) more fine grained: From paragraph level to individual character level. The inputenc package supports that since at least 2000. * src/insets/insetbase.h (latex): Document the differences between output to a string stream and a file stream * src/buffer.h (writeLaTeXSource): ditto * src/output_latex.h (latexParagraphs): ditto (switchEncoding): new function to change the encoding of a stream (and output \inputencoding commands) * src/paragraph_pimpl.C (Paragraph::Pimpl::simpleTeXSpecialC): Adjust to latexWriteEndChanges changes * src/support/docstream.[Ch] (setEncoding, operator<<): New stream modifier that changes the encoding of file streams * src/lyxfont.[Ch] (LyXFont::latexWriteStartChanges): Change stream encoding if needed (LyXFont::latexWriteEndChanges): Change stream encoding if needed * src/lyxfont.h (public:): * src/paragraph.C (Paragraph::simpleTeXOnePar): Adjust to latexWriteStartChanges and latexWriteEndChanges changes (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): (bool Paragraph::simpleTeXOnePar): * src/output_latex.C (TeXOnePar): Remove the ugly hack to for wencoding changes and use switchEncoding instead. A nice side effect is that the old hack would not work if the main language encoding is latin1 and a character would be mapped to a cedilla in the "fake ucs4" encoding, because iconv refuses to convert such a character to latin1, although it exists in latin1 (it wants to attach it to a base character). git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16633 a592a061-630c-0410-9148-cb99ea01b6c8
2007-01-09 19:25:40 +00:00
os.imbue(locale);
}
return os;
}
idocstream & operator<<(idocstream & is, SetEnc e)
{
if (has_facet<iconv_codecvt_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.
iconv_codecvt_facet const & facet =
use_facet<iconv_codecvt_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));
is.imbue(locale);
}
return is;
}
#if ! defined(USE_WCHAR_T)
odocstream & operator<<(odocstream & os, char c)
{
os.put(c);
return os;
}
#endif
Introduce a wrapper class for odocstream to help ensuring that no blank lines may be inadvertently output. This is achieved by using two special iomanip-like variables (breakln and safebreakln) in the lyx:: namespace. When they are inserted in the stream, a newline is output only if not already at the beginning of a line. The difference between breakln and safebreakln is that, if needed, the former outputs '\n' and the latter "%\n". In future, the new class will also be used for counting the number of newlines issued. Even if the infractrure for doing that is already in place, the counting is essentially still done the old way. There are still places in the code where the functionality of the class could be used, most probably. ATM, it is used for InsetTabular, InsetListings, InsetFloat, and InsetText. The Comment and GreyedOut insets required a special treatment and a new InsetLayout parameter (Display) has been introduced. The default for Display is "true", meaning that the corresponding latex environment is of "display" type, i.e., it stands on its own, whereas "false" means that the contents appear inline with the text. The latter is the case for both Comment and GreyedOut insets. Mostly, the only visible effects on latex exports should be the disappearing of some redundant % chars and the appearing/disappearing of null {} latex groups after a comment or lyxgreyedout environments (they are related to the presence or absence of a space immediately after those environments), as well as the fact that math environments are now started on their own lines. As a last thing, only the latex code between \begin{document} and \end{document} goes through the new class, the preamble being directly output through odocstream, as usual. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
}
#if ! defined(USE_WCHAR_T) && defined(__GNUC__)
// We get undefined references to these virtual methods. This looks like
// a bug in gcc. The implementation here does not do anything useful, since
// it is overriden in iconv_codecvt_facet.
namespace std {
template<> codecvt<lyx::char_type, char, mbstate_t>::result
codecvt<lyx::char_type, char, mbstate_t>::do_out(
mbstate_t &, const lyx::char_type *, const lyx::char_type *,
const lyx::char_type *&, char *, char *, char *&) const
{
return error;
}
template<> codecvt<lyx::char_type, char, mbstate_t>::result
codecvt<lyx::char_type, char, mbstate_t>::do_unshift(
mbstate_t &, char *, char *, char *&) const
{
return error;
}
template<> codecvt<lyx::char_type, char, mbstate_t>::result
codecvt<lyx::char_type, char, mbstate_t>::do_in(
mbstate_t &, const char *, const char *, const char *&,
lyx::char_type *, lyx::char_type *, lyx::char_type *&) const
{
return error;
}
template<>
int codecvt<lyx::char_type, char, mbstate_t>::do_encoding() const throw()
{
return 0;
}
template<>
bool codecvt<lyx::char_type, char, mbstate_t>::do_always_noconv() const throw()
{
return true;
}
template<>
int codecvt<lyx::char_type, char, mbstate_t>::do_length(
mbstate_t &, const char *, const char *, size_t) const
{
return 1;
}
template<>
int codecvt<lyx::char_type, char, mbstate_t>::do_max_length() const throw()
{
return 4;
}
} // namespace std
#endif