#include "LyX.h"
#include "LyXRC.h"
#include "LyXVC.h"
-#include "output_docbook.h"
#include "output.h"
#include "output_latex.h"
-#include "output_xhtml.h"
+#include "output_docbook.h"
#include "output_plaintext.h"
+#include "output_xhtml.h"
#include "Paragraph.h"
#include "ParagraphParameters.h"
#include "ParIterator.h"
#include "PDFOptions.h"
#include "Session.h"
#include "SpellChecker.h"
-#include "sgml.h"
+#include "xml.h"
#include "texstream.h"
#include "TexRow.h"
#include "Text.h"
#include "support/textutils.h"
#include "support/types.h"
-#include "support/bind.h"
-
#include <algorithm>
#include <fstream>
#include <iomanip>
///
CloneList_ptr clone_list_;
+ ///
+ std::list<Buffer const *> include_list_;
private:
/// So we can force access via the accessors.
mutable Buffer const * parent_buffer;
d->old_position = params().origin;
else
d->old_position = filePath();
+
+ if (!parent())
+ clearIncludeList();
+
bool const res = text().read(lex, errorList, d->inset);
d->old_position.clear();
// This is only set once per document (in master)
if (!runparams.is_child) {
runparams.use_polyglossia = features.usePolyglossia();
+ runparams.use_hyperref = features.isRequired("hyperref");
runparams.use_CJK = features.mustProvide("CJK");
}
LYXERR(Debug::LATEX, " Buffer validation done.");
updateMacroInstances(OutputUpdate);
ExportStatus const retval =
- writeDocBookSource(ofs, fname.absFileName(), runparams, output);
+ writeDocBookSource(ofs, runparams, output);
if (retval == ExportKilled)
return ExportKilled;
}
-Buffer::ExportStatus Buffer::writeDocBookSource(odocstream & os, string const & fname,
+Buffer::ExportStatus Buffer::writeDocBookSource(odocstream & os,
OutputParams const & runparams,
OutputWhat output) const
{
LaTeXFeatures features(*this, params(), runparams);
validate(features);
+ d->bibinfo_.makeCitationLabels(*this);
d->texrow.reset();
DocumentClass const & tclass = params().documentClass();
- string const & top_element = tclass.latexname();
bool const output_preamble =
output == FullSource || output == OnlyPreamble;
bool const output_body =
output == FullSource || output == OnlyBody;
- if (output_preamble) {
- if (runparams.flavor == OutputParams::XML)
- os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
-
- // FIXME UNICODE
- os << "<!DOCTYPE " << from_ascii(top_element) << ' ';
+ XMLStream xs(os);
- // FIXME UNICODE
- if (! tclass.class_header().empty())
- os << from_ascii(tclass.class_header());
- else if (runparams.flavor == OutputParams::XML)
- os << "PUBLIC \"-//OASIS//DTD DocBook XML V4.2//EN\" "
- << "\"https://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\"";
- else
- os << " PUBLIC \"-//OASIS//DTD DocBook V4.2//EN\"";
-
- docstring preamble = params().preamble;
- if (runparams.flavor != OutputParams::XML ) {
- preamble += "<!ENTITY % output.print.png \"IGNORE\">\n";
- preamble += "<!ENTITY % output.print.pdf \"IGNORE\">\n";
- preamble += "<!ENTITY % output.print.eps \"IGNORE\">\n";
- preamble += "<!ENTITY % output.print.bmp \"IGNORE\">\n";
- }
+ if (output_preamble) {
+ // XML preamble, no doctype needed.
+ // Not using XMLStream for this, as the root tag would be in the tag stack and make troubles with the error
+ // detection mechanisms (these are called before the end tag is output, and thus interact with the canary
+ // parsep in output_docbook.cpp).
+ os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ << "<!-- This DocBook file was created by LyX " << lyx_version
+ << "\n See http://www.lyx.org/ for more information -->\n";
- string const name = runparams.nice
- ? changeExtension(absFileName(), ".sgml") : fname;
- preamble += features.getIncludedFiles(name);
- preamble += features.getLyXSGMLEntities();
+ // Directly output the root tag, based on the current type of document.
+ string languageCode = params().language->code();
+ string params = "xml:lang=\"" + languageCode + '"'
+ + " xmlns=\"http://docbook.org/ns/docbook\""
+ + " xmlns:xlink=\"http://www.w3.org/1999/xlink\""
+ + " xmlns:m=\"http://www.w3.org/1998/Math/MathML\""
+ + " xmlns:xi=\"http://www.w3.org/2001/XInclude\""
+ + " version=\"5.2\"";
- if (!preamble.empty()) {
- os << "\n [ " << preamble << " ]";
- }
- os << ">\n\n";
+ os << "<" << from_ascii(tclass.docbookroot()) << " " << from_ascii(params) << ">\n";
}
if (output_body) {
- string top = top_element;
- top += " lang=\"";
- if (runparams.flavor == OutputParams::XML)
- top += params().language->code();
- else
- top += params().language->code().substr(0, 2);
- top += '"';
-
- if (!params().options.empty()) {
- top += ' ';
- top += params().options;
- }
-
- os << "<!-- " << ((runparams.flavor == OutputParams::XML)? "XML" : "SGML")
- << " file was created by LyX " << lyx_version
- << "\n See https://www.lyx.org/ for more information -->\n";
-
params().documentClass().counters().reset();
- sgml::openTag(os, top);
- os << '\n';
- try {
- docbookParagraphs(text(), *this, os, runparams);
- }
- catch (ConversionException const &) { return ExportKilled; }
- sgml::closeTag(os, top_element);
+ // Start to output the document.
+ docbookParagraphs(text(), *this, xs, runparams);
+ }
+
+ if (output_preamble) {
+ // Close the root element.
+ os << "\n</" << from_ascii(tclass.docbookroot()) << ">";
}
return ExportSuccess;
}
os << "<title>"
<< (doctitle.empty() ?
from_ascii("LyX Document") :
- html::htmlize(doctitle, XHTMLStream::ESCAPE_ALL))
+ xml::escapeString(doctitle, XMLStream::ESCAPE_ALL))
<< "</title>\n";
docstring styles = features.getTClassHTMLPreamble();
if (!styles.empty())
os << "\n<!-- Text Class Preamble -->\n" << styles << '\n';
- styles = features.getPreambleSnippets().str;
- if (!styles.empty())
- os << "\n<!-- Preamble Snippets -->\n" << styles << '\n';
-
// we will collect CSS information in a stream, and then output it
// either here, as part of the header, or else in a separate file.
odocstringstream css;
bool const output_body_tag = (output != IncludedFile);
if (output_body_tag)
os << "<body dir=\"auto\">\n";
- XHTMLStream xs(os);
+ XMLStream xs(os);
if (output != IncludedFile)
// if we're an included file, the counters are in the master.
params().documentClass().counters().reset();
if (!features.runparams().is_child)
params().validate(features);
+ if (!parent())
+ clearIncludeList();
+
for (Paragraph const & p : paragraphs())
p.validate(features);
void Buffer::collectBibKeys(FileNameList & checkedFiles) const
{
+ if (!parent())
+ clearIncludeList();
+
for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) {
it->collectBibKeys(it, checkedFiles);
if (it->lyxCode() == BIBITEM_CODE) {
// get buffer of external file
InsetInclude const & ins =
static_cast<InsetInclude const &>(*it);
- Buffer * child = ins.getChildBuffer();
+ Buffer * child = ins.loadIfNeeded();
if (!child)
continue;
child->dispatch(func, dr);
LASSERT(from, return);
LASSERT(to, return);
- for_each(par_iterator_begin(),
- par_iterator_end(),
- bind(&Paragraph::changeLanguage, _1, params(), from, to));
+ ParIterator it = par_iterator_begin();
+ ParIterator eit = par_iterator_end();
+ for (; it != eit; ++it)
+ it->changeLanguage(params(), from, to);
}
}
-docstring const Buffer::B_(string const & l10n) const
+docstring Buffer::B_(string const & l10n) const
{
return params().B_(l10n);
}
void Buffer::setParent(Buffer const * buffer)
{
- // Avoids recursive include.
- d->setParent(buffer == this ? nullptr : buffer);
+ // We need to do some work here to avoid recursive parent structures.
+ // This is the easy case.
+ if (buffer == this) {
+ LYXERR0("Ignoring attempt to set self as parent in\n" << fileName());
+ return;
+ }
+ // Now we check parents going upward, to make sure that IF we set the
+ // parent as requested, we would not generate a recursive include.
+ set<Buffer const *> sb;
+ Buffer const * b = buffer;
+ bool found_recursion = false;
+ while (b) {
+ if (sb.find(b) != sb.end()) {
+ found_recursion = true;
+ break;
+ }
+ sb.insert(b);
+ b = b->parent();
+ }
+
+ if (found_recursion) {
+ LYXERR0("Ignoring attempt to set parent of\n" <<
+ fileName() <<
+ "\nto " <<
+ buffer->fileName() <<
+ "\nbecause that would create a recursive inclusion.");
+ return;
+ }
+
+ // We should be safe now.
+ d->setParent(buffer);
updateMacros();
}
Buffer const * Buffer::masterBuffer() const
{
- // FIXME Should be make sure we are not in some kind
- // of recursive include? A -> B -> A will crash this.
Buffer const * const pbuf = d->parent();
if (!pbuf)
return this;
InsetInclude const & incinset =
static_cast<InsetInclude const &>(*insit.inset);
macro_lock = true;
- Buffer * child = incinset.getChildBuffer();
+ Buffer * child = incinset.loadIfNeeded();
macro_lock = false;
if (!child)
continue;
// get buffer of external file
InsetInclude const & ins =
static_cast<InsetInclude const &>(*it);
- Buffer * child = ins.getChildBuffer();
+ Buffer * child = ins.loadIfNeeded();
if (!child)
continue;
child->getUsedBranches(result, true);
par.write(ods, params(), dt);
os << from_utf8(ods.str());
} else if (runparams.flavor == OutputParams::HTML) {
- XHTMLStream xs(os);
+ XMLStream xs(os);
setMathFlavor(runparams);
xhtmlParagraphs(text(), *this, xs, runparams);
} else if (runparams.flavor == OutputParams::TEXT) {
// Probably should have some routine with a signature like them.
writePlaintextParagraph(*this,
text().paragraphs()[par_begin], os, runparams, dummy);
- } else if (params().isDocBook()) {
- docbookParagraphs(text(), *this, os, runparams);
+ } else if (runparams.flavor == OutputParams::DOCBOOK5) {
+ XMLStream xs{os};
+ docbookParagraphs(text(), *this, xs, runparams);
} else {
// If we are previewing a paragraph, even if this is the
// child of some other buffer, let's cut the link here,
LaTeXFeatures features(*this, params(), runparams);
validate(features);
runparams.use_polyglossia = features.usePolyglossia();
+ runparams.use_hyperref = features.isRequired("hyperref");
// latex or literate
otexstream ots(os);
// output above
os << "% "<< _("Plain text does not have a preamble.");
} else
writePlaintextFile(*this, os, runparams);
- } else if (params().isDocBook()) {
- writeDocBookSource(os, absFileName(), runparams, output);
+ } else if (runparams.flavor == OutputParams::DOCBOOK5) {
+ writeDocBookSource(os, runparams, output);
} else {
// latex or literate
otexstream ots(os);
string & result_file) const
{
bool const update_unincluded =
- params().maintain_unincluded_children
+ params().maintain_unincluded_children != BufferParams::CM_None
&& !params().getIncludedChildren().empty();
// (1) export with all included children (omit \includeonly)
return ExportKilled;
} else if (backend_format == "lyx")
writeFile(FileName(filename));
- // Docbook backend
- else if (params().isDocBook()) {
+ // DocBook backend
+ else if (backend_format == "docbook5") {
+ runparams.flavor = OutputParams::DOCBOOK5;
runparams.nice = !put_in_tempdir;
if (makeDocBookFile(FileName(filename), runparams) == ExportKilled)
return ExportKilled;
string const ext = theFormats().extension(format);
FileName const tmp_result_file(changeExtension(filename, ext));
Converters::RetVal const retval =
- converters.convert(this, FileName(filename), tmp_result_file,
- FileName(absFileName()), backend_format, format, error_list);
+ converters.convert(this, FileName(filename), tmp_result_file,
+ FileName(absFileName()), backend_format, format,
+ error_list, Converters::none, includeall);
if (retval == Converters::KILLED)
return ExportCancel;
bool success = (retval == Converters::SUCCESS);
Buffer::ExportStatus Buffer::preview(string const & format) const
{
bool const update_unincluded =
- params().maintain_unincluded_children
+ params().maintain_unincluded_children != BufferParams::CM_None
&& !params().getIncludedChildren().empty();
return preview(format, update_unincluded);
}
// do the real work
ParIterator parit = cbuf.par_iterator_begin();
+ if (scope == UpdateMaster)
+ clearIncludeList();
updateBuffer(parit, utype);
// If this document has siblings, then update the TocBackend later. The
}
d->cite_labels_valid_ = true;
/// FIXME: Perf
+ clearIncludeList();
cbuf.tocBackend().update(true, utype);
if (scope == UpdateMaster)
cbuf.structureChanged();
}
-void Buffer::updateBuffer(ParIterator & parit, UpdateType utype) const
+void Buffer::updateBuffer(ParIterator & parit, UpdateType utype, bool const deleted) const
{
+ pushIncludedBuffer(this);
// LASSERT: Is it safe to continue here, or should we just return?
LASSERT(parit.pit() == 0, /**/);
// to resolve macros in it.
parit.text()->setMacrocontextPosition(parit);
- // Reset bibitem counter in master (#8499)
- Buffer const * const master = masterBuffer();
- if (master == this && !d->ignore_parent)
- master->params().documentClass().counters().reset(from_ascii("bibitem"));
-
depth_type maxdepth = 0;
pit_type const lastpit = parit.lastpit();
bool changed = false;
// now the insets
for (auto const & insit : parit->insetList()) {
parit.pos() = insit.pos;
- insit.inset->updateBuffer(parit, utype);
+ insit.inset->updateBuffer(parit, utype, deleted || parit->isDeleted(insit.pos));
changed |= insit.inset->isChanged();
}
// set change indicator for the inset (or the cell that the iterator
// points to, if applicable).
parit.text()->inset().isChanged(changed);
+ popIncludedBuffer();
}
}
+void Buffer::pushIncludedBuffer(Buffer const * buf) const
+{
+ masterBuffer()->d->include_list_.push_back(buf);
+ if (lyxerr.debugging(Debug::FILES)) {
+ LYXERR0("Pushed. Stack now:");
+ if (masterBuffer()->d->include_list_.empty())
+ LYXERR0("EMPTY!");
+ else
+ for (auto const & b : masterBuffer()->d->include_list_)
+ LYXERR0(b->fileName());
+ }
+}
+
+
+void Buffer::popIncludedBuffer() const
+{
+ masterBuffer()->d->include_list_.pop_back();
+ if (lyxerr.debugging(Debug::FILES)) {
+ LYXERR0("Popped. Stack now:");
+ if (masterBuffer()->d->include_list_.empty())
+ LYXERR0("EMPTY!");
+ else
+ for (auto const & b : masterBuffer()->d->include_list_)
+ LYXERR0(b->fileName());
+ }
+}
+
+
+bool Buffer::isBufferIncluded(Buffer const * buf) const
+{
+ if (!buf)
+ return false;
+ if (lyxerr.debugging(Debug::FILES)) {
+ LYXERR0("Checking for " << buf->fileName() << ". Stack now:");
+ if (masterBuffer()->d->include_list_.empty())
+ LYXERR0("EMPTY!");
+ else
+ for (auto const & b : masterBuffer()->d->include_list_)
+ LYXERR0(b->fileName());
+ }
+ list<Buffer const *> const & blist = masterBuffer()->d->include_list_;
+ return find(blist.begin(), blist.end(), buf) != blist.end();
+}
+
+
+void Buffer::clearIncludeList() const
+{
+ LYXERR(Debug::FILES, "Clearing include list for " << fileName());
+ d->include_list_.clear();
+}
+
} // namespace lyx