2015-01-09 20:07:59 +00:00
|
|
|
/**
|
|
|
|
* \file texstream.cpp
|
|
|
|
* This file is part of LyX, the document processor.
|
|
|
|
* Licence details can be found in the file COPYING.
|
|
|
|
*
|
|
|
|
* \author Enrico Forestieri
|
|
|
|
*
|
|
|
|
* Full author contact details are available in file CREDITS.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "texstream.h"
|
2016-06-19 02:39:38 +00:00
|
|
|
|
|
|
|
#include "TexRow.h"
|
|
|
|
|
2015-01-09 20:07:59 +00:00
|
|
|
#include "support/lstrings.h"
|
|
|
|
#include "support/unicode.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cerrno>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstring>
|
|
|
|
#include <iconv.h>
|
|
|
|
#include <locale>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
using lyx::support::contains;
|
|
|
|
using lyx::support::split;
|
|
|
|
|
|
|
|
|
|
|
|
namespace lyx {
|
|
|
|
|
2015-10-13 22:51:50 +00:00
|
|
|
|
2016-09-04 02:02:47 +00:00
|
|
|
otexrowstream::otexrowstream(odocstream & os)
|
|
|
|
: os_(os), texrow_(make_unique<TexRow>())
|
2016-06-19 02:39:38 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
otexrowstream::~otexrowstream() = default;
|
|
|
|
|
|
|
|
|
2016-07-04 02:43:22 +00:00
|
|
|
unique_ptr<TexRow> otexrowstream::releaseTexRow()
|
2016-06-19 02:39:38 +00:00
|
|
|
{
|
|
|
|
auto p = make_unique<TexRow>();
|
|
|
|
swap(texrow_, p);
|
2016-07-04 02:43:22 +00:00
|
|
|
return p;
|
2016-06-19 02:39:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-07 03:02:40 +00:00
|
|
|
void otexrowstream::put(char_type const & c)
|
|
|
|
{
|
|
|
|
os_.put(c);
|
|
|
|
if (c == '\n')
|
2016-06-19 02:39:38 +00:00
|
|
|
texrow_->newline();
|
2015-10-07 03:02:40 +00:00
|
|
|
}
|
|
|
|
|
2015-10-13 22:51:50 +00:00
|
|
|
|
2015-01-09 20:07:59 +00:00
|
|
|
void otexstream::put(char_type const & c)
|
|
|
|
{
|
2016-12-12 14:55:28 +00:00
|
|
|
bool isprotected = false;
|
2015-01-09 20:07:59 +00:00
|
|
|
if (protectspace_) {
|
2016-12-12 14:55:28 +00:00
|
|
|
if (!canbreakline_ && c == ' ') {
|
2015-10-07 03:02:40 +00:00
|
|
|
os() << "{}";
|
2016-12-12 14:55:28 +00:00
|
|
|
isprotected = true;
|
|
|
|
}
|
2015-01-09 20:07:59 +00:00
|
|
|
protectspace_ = false;
|
|
|
|
}
|
2016-12-12 14:55:28 +00:00
|
|
|
if (terminate_command_) {
|
2016-12-12 16:00:20 +00:00
|
|
|
if ((c == ' ' || c == '\0' || c == '\n') && !isprotected)
|
|
|
|
// A space or line break follows. Terminate with brackets.
|
2016-12-12 14:55:28 +00:00
|
|
|
os() << "{}";
|
|
|
|
else if (c != '\\' && c != '{' && c != '}')
|
|
|
|
// Non-terminating character follows. Terminate with space.
|
|
|
|
os() << " ";
|
|
|
|
terminate_command_ = false;
|
|
|
|
}
|
2015-10-07 03:02:40 +00:00
|
|
|
otexrowstream::put(c);
|
2015-01-09 20:07:59 +00:00
|
|
|
lastChar(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-04 02:21:19 +00:00
|
|
|
size_t otexstringstream::length()
|
|
|
|
{
|
|
|
|
auto pos = ods_.tellp();
|
|
|
|
return (pos >= 0) ? size_t(pos) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TexString otexstringstream::release()
|
|
|
|
{
|
2022-10-21 12:11:36 +00:00
|
|
|
TexString ts(ods_.str(), std::move(texrow()));
|
2016-09-25 10:38:53 +00:00
|
|
|
// reset this
|
|
|
|
texrow() = TexRow();
|
2016-09-22 23:42:57 +00:00
|
|
|
ods_.clear();
|
|
|
|
ods_.str(docstring());
|
2016-09-04 02:21:19 +00:00
|
|
|
return ts;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-09 20:07:59 +00:00
|
|
|
BreakLine breakln;
|
|
|
|
SafeBreakLine safebreakln;
|
2016-12-12 14:55:28 +00:00
|
|
|
TerminateCommand termcmd;
|
2015-01-09 20:07:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
otexstream & operator<<(otexstream & ots, BreakLine)
|
|
|
|
{
|
|
|
|
if (ots.canBreakLine()) {
|
2016-12-12 16:00:20 +00:00
|
|
|
if (ots.terminateCommand())
|
|
|
|
ots << "{}";
|
2015-10-07 03:02:40 +00:00
|
|
|
ots.otexrowstream::put('\n');
|
2015-01-09 20:07:59 +00:00
|
|
|
ots.lastChar('\n');
|
|
|
|
}
|
|
|
|
ots.protectSpace(false);
|
2016-12-12 14:55:28 +00:00
|
|
|
ots.terminateCommand(false);
|
2015-01-09 20:07:59 +00:00
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
otexstream & operator<<(otexstream & ots, SafeBreakLine)
|
|
|
|
{
|
2015-10-07 03:02:40 +00:00
|
|
|
otexrowstream & otrs = ots;
|
2015-01-09 20:07:59 +00:00
|
|
|
if (ots.canBreakLine()) {
|
2016-12-12 16:00:20 +00:00
|
|
|
if (ots.terminateCommand())
|
2016-12-18 12:13:19 +00:00
|
|
|
otrs << "{}";
|
2015-10-07 03:02:40 +00:00
|
|
|
otrs << "%\n";
|
2015-01-09 20:07:59 +00:00
|
|
|
ots.lastChar('\n');
|
|
|
|
}
|
|
|
|
ots.protectSpace(false);
|
2016-12-12 14:55:28 +00:00
|
|
|
ots.terminateCommand(false);
|
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
otexstream & operator<<(otexstream & ots, TerminateCommand)
|
|
|
|
{
|
|
|
|
ots.terminateCommand(true);
|
2015-01-09 20:07:59 +00:00
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-07 03:02:40 +00:00
|
|
|
otexrowstream & operator<<(otexrowstream & ots, odocstream_manip pf)
|
2015-01-09 20:07:59 +00:00
|
|
|
{
|
|
|
|
ots.os() << pf;
|
|
|
|
if (pf == static_cast<odocstream_manip>(endl)) {
|
|
|
|
ots.texrow().newline();
|
|
|
|
}
|
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
2016-09-04 02:21:19 +00:00
|
|
|
|
2015-10-07 03:02:40 +00:00
|
|
|
otexstream & operator<<(otexstream & ots, odocstream_manip pf)
|
|
|
|
{
|
|
|
|
otexrowstream & otrs = ots;
|
|
|
|
otrs << pf;
|
|
|
|
if (pf == static_cast<odocstream_manip>(endl)) {
|
|
|
|
ots.lastChar('\n');
|
|
|
|
}
|
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-04 02:21:19 +00:00
|
|
|
otexrowstream & operator<<(otexrowstream & ots, TexString ts)
|
|
|
|
{
|
|
|
|
ts.validate();
|
2022-10-21 12:11:36 +00:00
|
|
|
ots.os() << std::move(ts.str);
|
|
|
|
ots.texrow().append(std::move(ts.texrow));
|
2016-09-04 02:21:19 +00:00
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
otexstream & operator<<(otexstream & ots, TexString ts)
|
|
|
|
{
|
|
|
|
size_t const len = ts.str.length();
|
|
|
|
// Check whether there is something to output
|
|
|
|
if (len == 0)
|
|
|
|
return ots;
|
|
|
|
|
|
|
|
otexrowstream & otrs = ots;
|
2016-12-12 14:55:28 +00:00
|
|
|
bool isprotected = false;
|
2016-12-18 12:13:19 +00:00
|
|
|
char_type const c = ts.str[0];
|
2016-09-04 02:21:19 +00:00
|
|
|
if (ots.protectSpace()) {
|
2016-12-12 14:55:28 +00:00
|
|
|
if (!ots.canBreakLine() && c == ' ') {
|
2016-09-04 02:21:19 +00:00
|
|
|
otrs << "{}";
|
2016-12-12 14:55:28 +00:00
|
|
|
isprotected = true;
|
|
|
|
}
|
2016-09-04 02:21:19 +00:00
|
|
|
ots.protectSpace(false);
|
|
|
|
}
|
2016-12-12 14:55:28 +00:00
|
|
|
if (ots.terminateCommand()) {
|
2016-12-12 16:00:20 +00:00
|
|
|
if ((c == ' ' || c == '\0' || c == '\n') && !isprotected)
|
|
|
|
// A space or line break follows. Terminate with brackets.
|
2016-12-12 14:55:28 +00:00
|
|
|
otrs << "{}";
|
|
|
|
else if (c != '\\' && c != '{' && c != '}')
|
|
|
|
// Non-terminating character follows. Terminate with space.
|
|
|
|
otrs << " ";
|
|
|
|
ots.terminateCommand(false);
|
|
|
|
}
|
2016-09-04 02:21:19 +00:00
|
|
|
|
|
|
|
if (len > 1)
|
|
|
|
ots.canBreakLine(ts.str[len - 2] != '\n');
|
|
|
|
ots.lastChar(ts.str[len - 1]);
|
|
|
|
|
2022-10-21 12:11:36 +00:00
|
|
|
otrs << std::move(ts);
|
2016-09-04 02:21:19 +00:00
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-07 03:02:40 +00:00
|
|
|
otexrowstream & operator<<(otexrowstream & ots, docstring const & s)
|
|
|
|
{
|
|
|
|
ots.os() << s;
|
|
|
|
ots.texrow().newlines(count(s.begin(), s.end(), '\n'));
|
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
2015-01-09 20:07:59 +00:00
|
|
|
|
|
|
|
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;
|
2015-10-07 03:02:40 +00:00
|
|
|
otexrowstream & otrs = ots;
|
2016-12-12 14:55:28 +00:00
|
|
|
bool isprotected = false;
|
2016-12-18 12:13:19 +00:00
|
|
|
char_type const c = s[0];
|
2015-01-09 20:07:59 +00:00
|
|
|
if (ots.protectSpace()) {
|
2016-12-12 14:55:28 +00:00
|
|
|
if (!ots.canBreakLine() && c == ' ') {
|
2015-10-07 03:02:40 +00:00
|
|
|
otrs << "{}";
|
2016-12-12 14:55:28 +00:00
|
|
|
isprotected = true;
|
|
|
|
}
|
2015-01-09 20:07:59 +00:00
|
|
|
ots.protectSpace(false);
|
|
|
|
}
|
2016-12-12 14:55:28 +00:00
|
|
|
if (ots.terminateCommand()) {
|
2016-12-12 16:00:20 +00:00
|
|
|
if ((c == ' ' || c == '\0' || c == '\n') && !isprotected)
|
|
|
|
// A space or line break follows. Terminate with brackets.
|
2016-12-12 14:55:28 +00:00
|
|
|
otrs << "{}";
|
|
|
|
else if (c != '\\' && c != '{' && c != '}')
|
|
|
|
// Non-terminating character follows. Terminate with space.
|
|
|
|
otrs << " ";
|
|
|
|
ots.terminateCommand(false);
|
|
|
|
}
|
2015-01-09 20:07:59 +00:00
|
|
|
|
|
|
|
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())
|
2015-10-07 03:02:40 +00:00
|
|
|
otrs << s1;
|
2015-01-09 20:07:59 +00:00
|
|
|
if (s2.empty())
|
|
|
|
break;
|
|
|
|
docstring enc;
|
|
|
|
docstring const s3 = split(s2, enc, 0xF0001);
|
|
|
|
if (!contains(s2, 0xF0001))
|
|
|
|
s2 = split(enc, s1, 0xF0000);
|
|
|
|
else {
|
2015-10-07 03:02:40 +00:00
|
|
|
otrs << setEncoding(to_ascii(enc));
|
2015-01-09 20:07:59 +00:00
|
|
|
s2 = split(s3, s1, 0xF0000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else
|
2015-10-07 03:02:40 +00:00
|
|
|
otrs << s;
|
2015-01-09 20:07:59 +00:00
|
|
|
|
|
|
|
if (len > 1)
|
|
|
|
ots.canBreakLine(s[len - 2] != '\n');
|
|
|
|
ots.lastChar(s[len - 1]);
|
2015-10-07 03:02:40 +00:00
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
otexrowstream & operator<<(otexrowstream & ots, string const & s)
|
|
|
|
{
|
|
|
|
ots << from_utf8(s);
|
2015-01-09 20:07:59 +00:00
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
otexstream & operator<<(otexstream & ots, string const & s)
|
|
|
|
{
|
|
|
|
ots << from_utf8(s);
|
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-07 03:02:40 +00:00
|
|
|
otexrowstream & operator<<(otexrowstream & ots, char const * s)
|
|
|
|
{
|
|
|
|
ots << from_utf8(s);
|
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-09 20:07:59 +00:00
|
|
|
otexstream & operator<<(otexstream & ots, char const * s)
|
|
|
|
{
|
|
|
|
ots << from_utf8(s);
|
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-07 03:02:40 +00:00
|
|
|
otexrowstream & operator<<(otexrowstream & ots, char c)
|
|
|
|
{
|
|
|
|
ots.put(c);
|
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-09 20:07:59 +00:00
|
|
|
otexstream & operator<<(otexstream & ots, char c)
|
|
|
|
{
|
2015-10-07 03:02:40 +00:00
|
|
|
ots.put(c);
|
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Type>
|
|
|
|
otexrowstream & operator<<(otexrowstream & ots, Type value)
|
|
|
|
{
|
|
|
|
ots.os() << value;
|
2015-01-09 20:07:59 +00:00
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
2015-10-07 03:02:40 +00:00
|
|
|
template otexrowstream & operator<< <SetEnc>(otexrowstream & os, SetEnc);
|
|
|
|
template otexrowstream & operator<< <double>(otexrowstream &, double);
|
|
|
|
template otexrowstream & operator<< <int>(otexrowstream &, int);
|
|
|
|
template otexrowstream & operator<< <unsigned int>(otexrowstream &,
|
|
|
|
unsigned int);
|
|
|
|
template otexrowstream & operator<< <unsigned long>(otexrowstream &,
|
|
|
|
unsigned long);
|
|
|
|
|
2019-03-21 13:05:50 +00:00
|
|
|
#ifdef HAVE_LONG_LONG_INT
|
2016-05-05 11:05:12 +00:00
|
|
|
template otexrowstream & operator<< <unsigned long long>(otexrowstream &,
|
|
|
|
unsigned long long);
|
|
|
|
#endif
|
|
|
|
|
2015-01-09 20:07:59 +00:00
|
|
|
|
|
|
|
template <typename Type>
|
|
|
|
otexstream & operator<<(otexstream & ots, Type value)
|
|
|
|
{
|
|
|
|
ots.os() << value;
|
|
|
|
ots.lastChar(0);
|
|
|
|
ots.protectSpace(false);
|
2016-12-12 14:55:28 +00:00
|
|
|
ots.terminateCommand(false);
|
2015-01-09 20:07:59 +00:00
|
|
|
return ots;
|
|
|
|
}
|
|
|
|
|
|
|
|
template otexstream & operator<< <SetEnc>(otexstream & os, SetEnc);
|
|
|
|
template otexstream & operator<< <double>(otexstream &, double);
|
|
|
|
template otexstream & operator<< <int>(otexstream &, int);
|
|
|
|
template otexstream & operator<< <unsigned int>(otexstream &, unsigned int);
|
|
|
|
template otexstream & operator<< <unsigned long>(otexstream &, unsigned long);
|
2019-03-21 13:05:50 +00:00
|
|
|
#ifdef HAVE_LONG_LONG_INT
|
2016-05-05 11:05:12 +00:00
|
|
|
template otexstream & operator<< <unsigned long long>(otexstream &, unsigned long long);
|
|
|
|
#endif
|
2015-01-09 20:07:59 +00:00
|
|
|
|
2017-07-23 11:11:54 +00:00
|
|
|
} // namespace lyx
|