]> git.lyx.org Git - features.git/blobdiff - src/buffer.C
change "support/std_sstream.h" to <sstream>
[features.git] / src / buffer.C
index 273ece0f6edc9781511a6534fc5ca76d3b30fb24..d6665c8352d1bcf3ea059cf830809a6defd79634 100644 (file)
 #include "Bullet.h"
 #include "Chktex.h"
 #include "debug.h"
+#include "encoding.h"
 #include "errorlist.h"
 #include "exporter.h"
 #include "format.h"
 #include "funcrequest.h"
 #include "gettext.h"
-#include "iterators.h"
+#include "insetiterator.h"
 #include "language.h"
 #include "LaTeX.h"
 #include "LaTeXFeatures.h"
@@ -43,7 +44,7 @@
 #include "paragraph.h"
 #include "paragraph_funcs.h"
 #include "ParagraphParameters.h"
-#include "PosIterator.h"
+#include "pariterator.h"
 #include "sgml.h"
 #include "texrow.h"
 #include "undo.h"
 #include "insets/insetinclude.h"
 #include "insets/insettext.h"
 
+#include "mathed/math_macrotemplate.h"
+#include "mathed/math_macrotable.h"
+#include "mathed/math_support.h"
+
 #include "frontends/Alert.h"
 
 #include "graphics/Previews.h"
 
 #include <boost/bind.hpp>
 
-#include "support/std_sstream.h"
+#include <utime.h>
 
 #include <iomanip>
 #include <stack>
+#include <sstream>
 
-#include <utime.h>
-
-#ifdef HAVE_LOCALE
-#endif
 
 using lyx::pos_type;
+using lyx::par_type;
 
 using lyx::support::AddName;
 using lyx::support::atoi;
@@ -119,6 +122,7 @@ using std::make_pair;
 
 using std::ifstream;
 using std::ios;
+using std::map;
 using std::ostream;
 using std::ostringstream;
 using std::ofstream;
@@ -133,7 +137,7 @@ extern BufferList bufferlist;
 
 namespace {
 
-const int LYX_FORMAT = 230;
+const int LYX_FORMAT = 235;
 
 } // namespace anon
 
@@ -182,6 +186,9 @@ struct Buffer::Impl
 
        /// our LyXText that should be wrapped in an InsetText
        InsetText inset;
+
+       ///
+       MacroTable macros;
 };
 
 
@@ -202,7 +209,6 @@ Buffer::Buffer(string const & file, bool ronly)
        : pimpl_(new Impl(*this, file, ronly))
 {
        lyxerr[Debug::INFO] << "Buffer::Buffer()" << endl;
-       lyxerr << "Buffer::Buffer()" << endl;
 }
 
 
@@ -426,8 +432,6 @@ int Buffer::readHeader(LyXLex & lex)
 // Returns false if "\end_document" is not read (Asger)
 bool Buffer::readBody(LyXLex & lex)
 {
-       bool the_end_read = false;
-
        if (paragraphs().empty()) {
                readHeader(lex);
                if (!params().getLyXTextClass().load()) {
@@ -446,30 +450,27 @@ bool Buffer::readBody(LyXLex & lex)
                tmpbuf.readHeader(lex);
        }
 
-       if (text().read(*this, lex))
-               the_end_read = true;
-
-       return the_end_read;
+       return text().read(*this, lex);
 }
 
 
 // needed to insert the selection
-void Buffer::insertStringAsLines(ParagraphList::iterator & par, pos_type & pos,
-                                LyXFont const & fn, string const & str)
+void Buffer::insertStringAsLines(ParagraphList & pars,
+       par_type & par, pos_type & pos,
+       LyXFont const & fn, string const & str)
 {
-       LyXLayout_ptr const & layout = par->layout();
+       LyXLayout_ptr const & layout = pars[par].layout();
 
        LyXFont font = fn;
 
-       par->checkInsertChar(font);
+       pars[par].checkInsertChar(font);
        // insert the string, don't insert doublespace
        bool space_inserted = true;
-       bool autobreakrows = !par->inInset() ||
-               static_cast<InsetText *>(par->inInset())->getAutoBreakRows();
-       for(string::const_iterator cit = str.begin();
+       bool autobreakrows = pars[par].autoBreakRows();
+       for (string::const_iterator cit = str.begin();
            cit != str.end(); ++cit) {
                if (*cit == '\n') {
-                       if (autobreakrows && (!par->empty() || par->allowEmpty())) {
+                       if (autobreakrows && (!pars[par].empty() || pars[par].allowEmpty())) {
                                breakParagraph(params(), paragraphs(), par, pos,
                                               layout->isEnvironment());
                                ++par;
@@ -480,18 +481,18 @@ void Buffer::insertStringAsLines(ParagraphList::iterator & par, pos_type & pos,
                        }
                        // do not insert consecutive spaces if !free_spacing
                } else if ((*cit == ' ' || *cit == '\t') &&
-                          space_inserted && !par->isFreeSpacing()) {
+                          space_inserted && !pars[par].isFreeSpacing()) {
                        continue;
                } else if (*cit == '\t') {
-                       if (!par->isFreeSpacing()) {
+                       if (!pars[par].isFreeSpacing()) {
                                // tabs are like spaces here
-                               par->insertChar(pos, ' ', font);
+                               pars[par].insertChar(pos, ' ', font);
                                ++pos;
                                space_inserted = true;
                        } else {
                                const pos_type n = 8 - pos % 8;
                                for (pos_type i = 0; i < n; ++i) {
-                                       par->insertChar(pos, ' ', font);
+                                       pars[par].insertChar(pos, ' ', font);
                                        ++pos;
                                }
                                space_inserted = true;
@@ -501,7 +502,7 @@ void Buffer::insertStringAsLines(ParagraphList::iterator & par, pos_type & pos,
                        continue;
                } else {
                        // just insert the character
-                       par->insertChar(pos, *cit, font);
+                       pars[par].insertChar(pos, *cit, font);
                        ++pos;
                        space_inserted = (*cit == ' ');
                }
@@ -520,7 +521,7 @@ bool Buffer::readFile(string const & filename)
 
        // remove dummy empty par
        paragraphs().clear();
-       bool ret = readFile(filename, paragraphs().end());
+       bool ret = readFile(filename, paragraphs().size());
 
        // After we have read a file, we must ensure that the buffer
        // language is set and used in the gui.
@@ -531,7 +532,7 @@ bool Buffer::readFile(string const & filename)
 }
 
 
-bool Buffer::readFile(string const & filename, ParagraphList::iterator pit)
+bool Buffer::readFile(string const & filename, par_type pit)
 {
        LyXLex lex(0, 0);
        lex.setFile(filename);
@@ -551,8 +552,7 @@ void Buffer::fully_loaded(bool value)
 }
 
 
-bool Buffer::readFile(LyXLex & lex, string const & filename,
-                     ParagraphList::iterator pit)
+bool Buffer::readFile(LyXLex & lex, string const & filename, par_type pit)
 {
        BOOST_ASSERT(!filename.empty());
 
@@ -643,9 +643,14 @@ bool Buffer::readFile(LyXLex & lex, string const & filename,
        }
 
        bool the_end = readBody(lex);
+       //lyxerr << "removing " << MacroTable::localMacros().size()
+       //      << " temporary macro entries" << endl;
+       //MacroTable::localMacros().clear();
        params().setPaperStuff();
 
+#ifdef WITH_WARNINGS
 #warning Look here!
+#endif
 #if 0
        if (token == "\\end_document")
                the_end_read = true;
@@ -656,7 +661,7 @@ bool Buffer::readFile(LyXLex & lex, string const & filename,
                                       " that it is probably corrupted."),
                                       filename));
        }
-#endif 
+#endif
        pimpl_->file_fully_loaded = true;
        return true;
 }
@@ -867,6 +872,9 @@ void Buffer::makeLaTeXFile(ostream & os,
        // input@path is set when the actual parameter
        // original_path is set. This is done for usual tex-file, but not
        // for nice-latex-file. (Matthias 250696)
+       // Note that input@path is only needed for something the user does
+       // in the preamble, included .tex files or ERT, files included by
+       // LyX work without it.
        if (output_preamble) {
                if (!runparams.nice) {
                        // code for usual, NOT nice-latex-file
@@ -905,8 +913,22 @@ void Buffer::makeLaTeXFile(ostream & os,
                texrow().newline();
        }
 
+       // if we are doing a real file with body, even if this is the
+       // child of some other buffer, let's cut the link here.
+       // This happens for example if only a child document is printed.
+       string save_parentname;
+       if (output_preamble) {
+               save_parentname = params().parentname;
+               params().parentname.erase();
+       }
+
+       // the real stuff
        latexParagraphs(*this, paragraphs(), os, texrow(), runparams);
 
+       // Restore the parenthood if needed
+       if (output_preamble)
+               params().parentname = save_parentname;
+
        // add this just in case after all the paragraphs
        os << endl;
        texrow().newline();
@@ -1045,7 +1067,18 @@ void Buffer::makeDocBookFile(string const & fname,
        string top_element = tclass.latexname();
 
        if (!only_body) {
-               ofs << subst(tclass.class_header(), "#", top_element);
+               if (runparams.flavor == OutputParams::XML)
+                       ofs << "<?xml version=\"1.0\" encoding=\""
+                           << params().language->encoding()->Name() << "\"?>\n";
+
+               ofs << "<!DOCTYPE " << top_element << " ";
+
+               if (! tclass.class_header().empty()) ofs << tclass.class_header();
+               else if (runparams.flavor == OutputParams::XML)
+                       ofs << "PUBLIC \"-//OASIS//DTD DocBook XML//EN\" "
+                           << "\"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\"";
+               else
+                       ofs << " PUBLIC \"-//OASIS//DTD DocBook V4.2//EN\"";
 
                string preamble = params().preamble;
                string const name = runparams.nice ? ChangeExtension(pimpl_->filename, ".sgml")
@@ -1061,7 +1094,10 @@ void Buffer::makeDocBookFile(string const & fname,
 
        string top = top_element;
        top += " lang=\"";
-       top += params().language->code();
+       if (runparams.flavor == OutputParams::XML)
+               top += params().language->code();
+       else
+               top += params().language->code().substr(0,2);
        top += '"';
 
        if (!params().options.empty()) {
@@ -1070,7 +1106,8 @@ void Buffer::makeDocBookFile(string const & fname,
        }
        sgml::openTag(ofs, 0, false, top);
 
-       ofs << "<!-- SGML/XML file was created by LyX " << lyx_version
+       ofs << "<!-- " << ((runparams.flavor == OutputParams::XML)? "XML" : "SGML")
+           << " file was created by LyX " << lyx_version
            << "\n  See http://www.lyx.org/ for more information -->\n";
 
        params().getLyXTextClass().counters().reset();
@@ -1174,19 +1211,18 @@ void Buffer::getLabelList(std::vector<string> & list) const
 {
        /// if this is a child document and the parent is already loaded
        /// Use the parent's list instead  [ale990407]
-       if (!params().parentname.empty()
-           && bufferlist.exists(params().parentname)) {
-               Buffer const * tmp = bufferlist.getBuffer(params().parentname);
-               if (tmp) {
-                       tmp->getLabelList(list);
-                       return;
-               }
+       Buffer const * tmp = getMasterBuffer();
+       if (!tmp) {
+               lyxerr << "getMasterBuffer() failed!" << endl;
+               BOOST_ASSERT(tmp);
        }
-
-       for (inset_iterator it = inset_const_iterator_begin();
-            it != inset_const_iterator_end(); ++it) {
-               it->getLabelList(*this, list);
+       if (tmp != this) {
+               tmp->getLabelList(list);
+               return;
        }
+
+       for (InsetIterator it = inset_iterator_begin(inset()); it; ++it)
+               it.nextInset()->getLabelList(*this, list);
 }
 
 
@@ -1196,17 +1232,14 @@ void Buffer::fillWithBibKeys(std::vector<std::pair<string, string> > & keys)
 {
        /// if this is a child document and the parent is already loaded
        /// use the parent's list instead  [ale990412]
-       if (!params().parentname.empty() &&
-           bufferlist.exists(params().parentname)) {
-               Buffer const * tmp = bufferlist.getBuffer(params().parentname);
-               if (tmp) {
-                       tmp->fillWithBibKeys(keys);
-                       return;
-               }
+       Buffer const * tmp = getMasterBuffer();
+       BOOST_ASSERT(tmp);
+       if (tmp != this) {
+               tmp->fillWithBibKeys(keys);
+               return;
        }
 
-       for (inset_iterator it = inset_const_iterator_begin();
-               it != inset_const_iterator_end(); ++it) {
+       for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) {
                if (it->lyxCode() == InsetOld::BIBTEX_CODE) {
                        InsetBibtex const & inset =
                                dynamic_cast<InsetBibtex const &>(*it);
@@ -1298,24 +1331,11 @@ bool Buffer::isMultiLingual() const
 }
 
 
-void Buffer::inset_iterator::setParagraph()
-{
-       while (pit != pend) {
-               it = pit->insetlist.begin();
-               if (it != pit->insetlist.end())
-                       return;
-               ++pit;
-       }
-}
-
-
 ParIterator Buffer::getParFromID(int id) const
 {
-#warning FIXME: const correctness! (Andre)
-       ParIterator it = const_cast<Buffer*>(this)->par_iterator_begin();
-       ParIterator end = const_cast<Buffer*>(this)->par_iterator_end();
+       ParConstIterator it = par_iterator_begin();
+       ParConstIterator end = par_iterator_end();
 
-#warning FIXME, perhaps this func should return a ParIterator? (Lgb)
        if (id < 0) {
                // John says this is called with id == -1 from undo
                lyxerr << "getParFromID(), id: " << id << endl;
@@ -1349,41 +1369,27 @@ bool Buffer::hasParWithID(int id) const
 }
 
 
-PosIterator Buffer::pos_iterator_begin()
-{
-       return PosIterator(&paragraphs(), paragraphs().begin(), 0);
-}
-
-
-PosIterator Buffer::pos_iterator_end()
-{
-       return PosIterator(&paragraphs(), paragraphs().end(), 0);
-}
-
-
 ParIterator Buffer::par_iterator_begin()
 {
-       return ParIterator(paragraphs().begin(), paragraphs());
+       return ::par_iterator_begin(inset());
 }
 
 
 ParIterator Buffer::par_iterator_end()
 {
-       return ParIterator(paragraphs().end(), paragraphs());
+       return ::par_iterator_end(inset());
 }
 
 
 ParConstIterator Buffer::par_iterator_begin() const
 {
-       ParagraphList const & pars = paragraphs();
-       return ParConstIterator(const_cast<ParagraphList&>(pars).begin(), pars);
+       return ::par_const_iterator_begin(inset());
 }
 
 
 ParConstIterator Buffer::par_iterator_end() const
 {
-       ParagraphList const & pars = paragraphs();
-       return ParConstIterator(const_cast<ParagraphList&>(pars).end(), pars);
+       return ::par_const_iterator_end(inset());
 }
 
 
@@ -1486,99 +1492,57 @@ void Buffer::setParentName(string const & name)
 }
 
 
-Buffer::inset_iterator::inset_iterator()
-       : pit(), pend()
-{}
-
-
-Buffer::inset_iterator::inset_iterator(base_type p, base_type e)
-       : pit(p), pend(e)
-{
-       setParagraph();
-}
-
-
-Buffer::inset_iterator Buffer::inset_iterator_begin()
-{
-       return inset_iterator(paragraphs().begin(), paragraphs().end());
-}
-
-
-Buffer::inset_iterator Buffer::inset_iterator_end()
-{
-       return inset_iterator(paragraphs().end(), paragraphs().end());
-}
-
-
-Buffer::inset_iterator Buffer::inset_const_iterator_begin() const
-{
-       ParagraphList & pars = const_cast<ParagraphList&>(paragraphs());
-       return inset_iterator(pars.begin(), pars.end());
-}
-
-
-Buffer::inset_iterator Buffer::inset_const_iterator_end() const
+Buffer const * Buffer::getMasterBuffer() const
 {
-       ParagraphList & pars = const_cast<ParagraphList&>(paragraphs());
-       return inset_iterator(pars.end(), pars.end());
-}
-
-
-Buffer::inset_iterator & Buffer::inset_iterator::operator++()
-{
-       if (pit != pend) {
-               ++it;
-               if (it == pit->insetlist.end()) {
-                       ++pit;
-                       setParagraph();
-               }
+       if (!params().parentname.empty()
+           && bufferlist.exists(params().parentname)) {
+               Buffer const * buf = bufferlist.getBuffer(params().parentname);
+               if (buf)
+                       return buf->getMasterBuffer();
        }
-       return *this;
-}
-
-
-Buffer::inset_iterator Buffer::inset_iterator::operator++(int)
-{
-       inset_iterator tmp = *this;
-       ++*this;
-       return tmp;
-}
-
 
-Buffer::inset_iterator::reference Buffer::inset_iterator::operator*()
-{
-       return *it->inset;
+       return this;
 }
 
 
-Buffer::inset_iterator::pointer Buffer::inset_iterator::operator->()
+MacroData const & Buffer::getMacro(std::string const & name) const
 {
-       return it->inset;
+       return pimpl_->macros.get(name);
 }
 
 
-ParagraphList::iterator Buffer::inset_iterator::getPar() const
+bool Buffer::hasMacro(string const & name) const
 {
-       return pit;
+       return pimpl_->macros.has(name);
 }
 
 
-lyx::pos_type Buffer::inset_iterator::getPos() const
+void Buffer::insertMacro(string const & name, MacroData const & data)
 {
-       return it->pos;
+       MacroTable::globalMacros().insert(name, data);
+       pimpl_->macros.insert(name, data);
 }
 
 
-bool operator==(Buffer::inset_iterator const & iter1,
-               Buffer::inset_iterator const & iter2)
+void Buffer::buildMacros()
 {
-       return iter1.pit == iter2.pit
-               && (iter1.pit == iter1.pend || iter1.it == iter2.it);
-}
+       // Start with global table.
+       pimpl_->macros = MacroTable::globalMacros();
 
-
-bool operator!=(Buffer::inset_iterator const & iter1,
-               Buffer::inset_iterator const & iter2)
-{
-       return !(iter1 == iter2);
+       // Now add our own.
+       ParagraphList & pars = text().paragraphs();
+       for (size_t i = 0, n = pars.size(); i != n; ++i) {
+               //lyxerr << "searching main par " << i
+               //      << " for macro definitions" << std::endl;
+               InsetList::iterator it = pars[i].insetlist.begin();
+               InsetList::iterator end = pars[i].insetlist.end();
+               for ( ; it != end; ++it) {
+                       //lyxerr << "found inset code " << it->inset->lyxCode() << std::endl;
+                       if (it->inset->lyxCode() == InsetBase::MATHMACRO_CODE) {
+                               MathMacroTemplate & mac
+                                       = static_cast<MathMacroTemplate &>(*it->inset);
+                               insertMacro(mac.name(), mac.asMacroData());
+                       }
+               }
+       }
 }