]> git.lyx.org Git - lyx.git/blobdiff - src/buffer.C
cleanup some debug messages
[lyx.git] / src / buffer.C
index 4a7de29cb7d8a012bf1c50b53017dc4cda2ce57a..429907f18ac17076db2828ad70f51d5e4f806cce 100644 (file)
@@ -13,6 +13,7 @@
 #include "buffer.h"
 
 #include "author.h"
+#include "BranchList.h"
 #include "buffer_funcs.h"
 #include "bufferlist.h"
 #include "bufferparams.h"
 
 #include "graphics/Previews.h"
 
-#include "support/FileInfo.h"
+#include "support/lyxalgo.h"
 #include "support/filetools.h"
-#include "support/gzstream.h"
+#include "support/fs_extras.h"
+#ifdef USE_COMPRESSION
+# include "support/gzstream.h"
+#endif
 #include "support/lyxlib.h"
 #include "support/os.h"
 #include "support/path.h"
 #include "support/convert.h"
 
 #include <boost/bind.hpp>
+#include <boost/filesystem/operations.hpp>
 
-#include <utime.h>
+#if defined (HAVE_UTIME_H)
+# include <utime.h>
+#elif defined (HAVE_SYS_UTIME_H)
+# include <sys/utime.h>
+#endif
 
 #include <iomanip>
 #include <stack>
 #include <sstream>
+#include <fstream>
 
 
 using lyx::pos_type;
@@ -90,12 +100,10 @@ using lyx::support::ChangeExtension;
 using lyx::support::cmd_ret;
 using lyx::support::createBufferTmpDir;
 using lyx::support::destroyDir;
-using lyx::support::FileInfo;
-using lyx::support::FileInfo;
 using lyx::support::getFormatFromContents;
 using lyx::support::IsDirWriteable;
-using lyx::support::IsFileWriteable;
 using lyx::support::LibFileSearch;
+using lyx::support::latex_path;
 using lyx::support::ltrim;
 using lyx::support::MakeAbsPath;
 using lyx::support::MakeDisplayPath;
@@ -108,12 +116,12 @@ using lyx::support::removeAutosaveFile;
 using lyx::support::rename;
 using lyx::support::RunCommand;
 using lyx::support::split;
-using lyx::support::strToInt;
 using lyx::support::subst;
 using lyx::support::tempName;
 using lyx::support::trim;
 
 namespace os = lyx::support::os;
+namespace fs = boost::filesystem;
 
 using std::endl;
 using std::for_each;
@@ -136,7 +144,7 @@ extern BufferList bufferlist;
 
 namespace {
 
-int const LYX_FORMAT = 239;
+int const LYX_FORMAT = 245;
 
 } // namespace anon
 
@@ -197,6 +205,7 @@ Buffer::Impl::Impl(Buffer & parent, string const & file, bool readonly_)
          filename(file), filepath(OnlyPath(file)), file_fully_loaded(false),
                inset(params)
 {
+       inset.setAutoBreakRows(true);
        lyxvc.buffer(&parent);
        temppath = createBufferTmpDir();
        // FIXME: And now do something if temppath == string(), because we
@@ -205,8 +214,8 @@ Buffer::Impl::Impl(Buffer & parent, string const & file, bool readonly_)
 }
 
 
-Buffer::Buffer(string const & file, bool ronly)
-       : pimpl_(new Impl(*this, file, ronly))
+Buffer::Buffer(string const & file, bool readonly)
+       : pimpl_(new Impl(*this, file, readonly))
 {
        lyxerr[Debug::INFO] << "Buffer::Buffer()" << endl;
 }
@@ -220,7 +229,7 @@ Buffer::~Buffer()
 
        closing();
 
-       if (!temppath().empty() && destroyDir(temppath()) != 0) {
+       if (!temppath().empty() && !destroyDir(temppath())) {
                Alert::warning(_("Could not remove temporary directory"),
                        bformat(_("Could not remove the temporary directory %1$s"), temppath()));
        }
@@ -346,11 +355,8 @@ pair<Buffer::LogType, string> const Buffer::getLogName() const
 
        // If no Latex log or Build log is newer, show Build log
 
-       FileInfo const f_fi(fname);
-       FileInfo const b_fi(bname);
-
-       if (b_fi.exist() &&
-           (!f_fi.exist() || f_fi.getModificationTime() < b_fi.getModificationTime())) {
+       if (fs::exists(bname) &&
+           (!fs::exists(fname) || fs::last_write_time(fname) < fs::last_write_time(bname))) {
                lyxerr[Debug::FILES] << "Log name calculated as: " << bname << endl;
                return make_pair(Buffer::buildlog, bname);
        }
@@ -372,7 +378,7 @@ void Buffer::setFileName(string const & newfile)
 {
        pimpl_->filename = MakeAbsPath(newfile);
        pimpl_->filepath = OnlyPath(pimpl_->filename);
-       setReadonly(IsFileWriteable(pimpl_->filename) == 0);
+       setReadonly(fs::is_readonly(pimpl_->filename));
        updateTitles();
 }
 
@@ -396,6 +402,20 @@ int Buffer::readHeader(LyXLex & lex)
        int line = -1;
        int begin_header_line = -1;
 
+       // Initialize parameters that may be/go lacking in header:
+       params().branchlist().clear();
+       params().options.erase();
+       params().float_placement.erase();
+       params().paperwidth.erase();
+       params().paperheight.erase();
+       params().leftmargin.erase();
+       params().rightmargin.erase();
+       params().topmargin.erase();
+       params().bottommargin.erase();
+       params().headheight.erase();
+       params().headsep.erase();
+       params().footskip.erase();
+
        while (lex.isOK()) {
                lex.next();
                string const token = lex.getString();
@@ -412,7 +432,7 @@ int Buffer::readHeader(LyXLex & lex)
                        continue;
                }
 
-               lyxerr[Debug::PARSER] << "Handling header token: `"
+               lyxerr[Debug::PARSER] << "Handling document header token: `"
                                      << token << '\'' << endl;
 
                string unknown = params().readToken(lex, token);
@@ -425,14 +445,14 @@ int Buffer::readHeader(LyXLex & lex)
                                                           "%1$s %2$s\n"),
                                                         token,
                                                         lex.getString());
-                               error(ErrorItem(_("Header error"), s,
+                               error(ErrorItem(_("Document header error"), s,
                                                -1, 0, 0));
                        }
                }
        }
        if (begin_header_line) {
                string const s = _("\\begin_header is missing");
-               error(ErrorItem(_("Header error"), s, -1, 0, 0));
+               error(ErrorItem(_("Document header error"), s, -1, 0, 0));
        }
        return unknown_tokens;
 }
@@ -447,50 +467,46 @@ bool Buffer::readDocument(LyXLex & lex)
        string const token = lex.getString();
        if (token != "\\begin_document") {
                string const s = _("\\begin_document is missing");
-               error(ErrorItem(_("Header error"), s, -1, 0, 0));
+               error(ErrorItem(_("Document header error"), s, -1, 0, 0));
        }
 
-       if (paragraphs().empty()) {
-               readHeader(lex);
-               if (!params().getLyXTextClass().load()) {
-                       string theclass = params().getLyXTextClass().name();
-                       Alert::error(_("Can't load document class"), bformat(
-                                       "Using the default document class, because the "
-                                       " class %1$s could not be loaded.", theclass));
-                       params().textclass = 0;
-               }
-       } else {
-               // We don't want to adopt the parameters from the
-               // document we insert, so read them into a temporary buffer
-               // and then discard it
+       // we are reading in a brand new document
+       BOOST_ASSERT(paragraphs().empty());
 
-               Buffer tmpbuf("", false);
-               tmpbuf.readHeader(lex);
+       readHeader(lex);
+       if (!params().getLyXTextClass().load()) {
+               string theclass = params().getLyXTextClass().name();
+               Alert::error(_("Can't load document class"), bformat(
+                                    "Using the default document class, because the "
+                                    " class %1$s could not be loaded.", theclass));
+               params().textclass = 0;
        }
 
-       return text().read(*this, lex);
+       bool const res = text().read(*this, lex);
+       for_each(text().paragraphs().begin(),
+                text().paragraphs().end(),
+                bind(&Paragraph::setInsetOwner, _1, &inset()));
+       return res;
 }
 
 
 // needed to insert the selection
 void Buffer::insertStringAsLines(ParagraphList & pars,
-       pit_type & par, pos_type & pos,
+       pit_type & pit, pos_type & pos,
        LyXFont const & fn, string const & str, bool autobreakrows)
 {
-       LyXLayout_ptr const & layout = pars[par].layout();
-
        LyXFont font = fn;
 
-       pars[par].checkInsertChar(font);
        // insert the string, don't insert doublespace
        bool space_inserted = true;
        for (string::const_iterator cit = str.begin();
            cit != str.end(); ++cit) {
+               Paragraph & par = pars[pit];
                if (*cit == '\n') {
-                       if (autobreakrows && (!pars[par].empty() || pars[par].allowEmpty())) {
-                               breakParagraph(params(), paragraphs(), par, pos,
-                                              layout->isEnvironment());
-                               ++par;
+                       if (autobreakrows && (!par.empty() || par.allowEmpty())) {
+                               breakParagraph(params(), pars, pit, pos,
+                                              par.layout()->isEnvironment());
+                               ++pit;
                                pos = 0;
                                space_inserted = true;
                        } else {
@@ -498,18 +514,18 @@ void Buffer::insertStringAsLines(ParagraphList & pars,
                        }
                        // do not insert consecutive spaces if !free_spacing
                } else if ((*cit == ' ' || *cit == '\t') &&
-                          space_inserted && !pars[par].isFreeSpacing()) {
+                          space_inserted && !par.isFreeSpacing()) {
                        continue;
                } else if (*cit == '\t') {
-                       if (!pars[par].isFreeSpacing()) {
+                       if (!par.isFreeSpacing()) {
                                // tabs are like spaces here
-                               pars[par].insertChar(pos, ' ', font);
+                               par.insertChar(pos, ' ', font);
                                ++pos;
                                space_inserted = true;
                        } else {
                                const pos_type n = 8 - pos % 8;
                                for (pos_type i = 0; i < n; ++i) {
-                                       pars[par].insertChar(pos, ' ', font);
+                                       par.insertChar(pos, ' ', font);
                                        ++pos;
                                }
                                space_inserted = true;
@@ -519,7 +535,7 @@ void Buffer::insertStringAsLines(ParagraphList & pars,
                        continue;
                } else {
                        // just insert the character
-                       pars[par].insertChar(pos, *cit, font);
+                       par.insertChar(pos, *cit, font);
                        ++pos;
                        space_inserted = (*cit == ' ');
                }
@@ -538,7 +554,9 @@ bool Buffer::readFile(string const & filename)
 
        // remove dummy empty par
        paragraphs().clear();
-       bool ret = readFile(filename, paragraphs().size());
+       LyXLex lex(0, 0);
+       lex.setFile(filename);
+       bool ret = readFile(lex, filename);
 
        // After we have read a file, we must ensure that the buffer
        // language is set and used in the gui.
@@ -549,14 +567,6 @@ bool Buffer::readFile(string const & filename)
 }
 
 
-bool Buffer::readFile(string const & filename, pit_type const pit)
-{
-       LyXLex lex(0, 0);
-       lex.setFile(filename);
-       return readFile(lex, filename, pit);
-}
-
-
 bool Buffer::fully_loaded() const
 {
        return pimpl_->file_fully_loaded;
@@ -569,7 +579,7 @@ void Buffer::fully_loaded(bool const value)
 }
 
 
-bool Buffer::readFile(LyXLex & lex, string const & filename, pit_type const pit)
+bool Buffer::readFile(LyXLex & lex, string const & filename)
 {
        BOOST_ASSERT(!filename.empty());
 
@@ -606,7 +616,7 @@ bool Buffer::readFile(LyXLex & lex, string const & filename, pit_type const pit)
        //lyxerr << "           dot found at " << dot << endl;
        if (dot != string::npos)
                        tmp_format.erase(dot, 1);
-       int file_format = strToInt(tmp_format);
+       int const file_format = convert<int>(tmp_format);
        //lyxerr << "format: " << file_format << endl;
 
        if (file_format != LYX_FORMAT) {
@@ -620,9 +630,8 @@ bool Buffer::readFile(LyXLex & lex, string const & filename, pit_type const pit)
                                              filename));
                        return false;
                }
-               string command =
-                       "python " + LibFileSearch("lyx2lyx", "lyx2lyx");
-               if (command.empty()) {
+               string const lyx2lyx = LibFileSearch("lyx2lyx", "lyx2lyx");
+               if (lyx2lyx.empty()) {
                        Alert::error(_("Conversion script not found"),
                                     bformat(_("%1$s is from an earlier"
                                               " version of LyX, but the"
@@ -631,14 +640,18 @@ bool Buffer::readFile(LyXLex & lex, string const & filename, pit_type const pit)
                                               filename));
                        return false;
                }
-               command += " -t"
-                       + convert<string>(LYX_FORMAT)
-                       + " -o " + tmpfile + ' '
-                       + QuoteName(filename);
+               ostringstream command;
+               command << "python " << QuoteName(lyx2lyx)
+                       << " -t " << convert<string>(LYX_FORMAT)
+                       << " -o " << QuoteName(tmpfile) << ' '
+                       << QuoteName(filename);
+               string const command_str = command.str();
+
                lyxerr[Debug::INFO] << "Running '"
-                                   << command << '\''
+                                   << command_str << '\''
                                    << endl;
-               cmd_ret const ret = RunCommand(command);
+
+               cmd_ret const ret = RunCommand(command_str);
                if (ret.first != 0) {
                        Alert::error(_("Conversion script failed"),
                                     bformat(_("%1$s is from an earlier version"
@@ -647,7 +660,7 @@ bool Buffer::readFile(LyXLex & lex, string const & filename, pit_type const pit)
                                              filename));
                        return false;
                } else {
-                       bool ret = readFile(tmpfile, pit);
+                       bool const ret = readFile(tmpfile);
                        // Do stuff with tmpfile name and buffer name here.
                        return ret;
                }
@@ -664,7 +677,6 @@ bool Buffer::readFile(LyXLex & lex, string const & filename, pit_type const pit)
        //lyxerr << "removing " << MacroTable::localMacros().size()
        //      << " temporary macro entries" << endl;
        //MacroTable::localMacros().clear();
-       params().setPaperStuff();
 
        pimpl_->file_fully_loaded = true;
        return true;
@@ -685,51 +697,18 @@ bool Buffer::save() const
                        s = AddName(lyxrc.backupdir_path,
                                    subst(os::internal_path(s),'/','!'));
 
-               // Rename is the wrong way of making a backup,
-               // this is the correct way.
-               /* truss cp fil fil2:
-                  lstat("LyXVC3.lyx", 0xEFFFF898)                 Err#2 ENOENT
-                  stat("LyXVC.lyx", 0xEFFFF688)                   = 0
-                  open("LyXVC.lyx", O_RDONLY)                     = 3
-                  open("LyXVC3.lyx", O_WRONLY|O_CREAT|O_TRUNC, 0600) = 4
-                  fstat(4, 0xEFFFF508)                            = 0
-                  fstat(3, 0xEFFFF508)                            = 0
-                  read(3, " # T h i s   f i l e   w".., 8192)     = 5579
-                  write(4, " # T h i s   f i l e   w".., 5579)    = 5579
-                  read(3, 0xEFFFD4A0, 8192)                       = 0
-                  close(4)                                        = 0
-                  close(3)                                        = 0
-                  chmod("LyXVC3.lyx", 0100644)                    = 0
-                  lseek(0, 0, SEEK_CUR)                           = 46440
-                  _exit(0)
-               */
-
-               // Should probably have some more error checking here.
-               // Doing it this way, also makes the inodes stay the same.
-               // This is still not a very good solution, in particular we
-               // might loose the owner of the backup.
-               FileInfo finfo(fileName());
-               if (finfo.exist()) {
-                       mode_t fmode = finfo.getMode();
-                       struct utimbuf times = {
-                               finfo.getAccessTime(),
-                               finfo.getModificationTime() };
-
-                       ifstream ifs(fileName().c_str());
-                       ofstream ofs(s.c_str(), ios::out|ios::trunc);
-                       if (ifs && ofs) {
-                               ofs << ifs.rdbuf();
-                               ifs.close();
-                               ofs.close();
-                               ::chmod(s.c_str(), fmode);
-
-                               if (::utime(s.c_str(), &times)) {
-                                       lyxerr << "utime error." << endl;
-                               }
-                       } else {
-                               lyxerr << "LyX was not able to make "
-                                       "backup copy. Beware." << endl;
-                       }
+               // It might very well be that this variant is just
+               // good enough. (Lgb)
+               // But to use this we need fs::copy_file to actually do a copy,
+               // even when the target file exists. (Lgb)
+               if (fs::exists(fileName()) && fs::is_writable(fs::path(fileName()).branch_path())) {
+                 //try {
+                   fs::copy_file(fileName(), s, false);
+                   //}
+                   //catch (fs::filesystem_error const & fe) {
+                   //lyxerr << "LyX was not able to make backup copy. Beware.\n"
+                   //     << fe.what() << endl;
+                   //}
                }
        }
 
@@ -751,21 +730,20 @@ bool Buffer::writeFile(string const & fname) const
        if (pimpl_->read_only && fname == fileName())
                return false;
 
-       FileInfo finfo(fname);
-       if (finfo.exist() && !finfo.writable())
-               return false;
-
        bool retval = false;
 
        if (params().compressed) {
-               gz::ogzstream ofs(fname.c_str());
+#ifdef USE_COMPRESSION
+               gz::ogzstream ofs(fname.c_str(), ios::out|ios::trunc);
                if (!ofs)
                        return false;
 
                retval = do_writeFile(ofs);
-
+#else
+               return false;
+#endif
        } else {
-               ofstream ofs(fname.c_str());
+               ofstream ofs(fname.c_str(), ios::out|ios::trunc);
                if (!ofs)
                        return false;
 
@@ -872,7 +850,7 @@ void Buffer::makeLaTeXFile(ostream & os,
                texrow().newline();
                texrow().newline();
        }
-       lyxerr[Debug::INFO] << "lyx header finished" << endl;
+       lyxerr[Debug::INFO] << "lyx document header finished" << endl;
        // There are a few differences between nice LaTeX and usual files:
        // usual is \batchmode and has a
        // special input@path to allow the including of figures
@@ -891,8 +869,7 @@ void Buffer::makeLaTeXFile(ostream & os,
                        texrow().newline();
                }
                if (!original_path.empty()) {
-                       string inputpath = os::external_path(original_path);
-                       subst(inputpath, "~", "\\string~");
+                       string const inputpath = latex_path(original_path);
                        os << "\\makeatletter\n"
                            << "\\def\\input@path{{"
                            << inputpath << "/}}\n"
@@ -1179,7 +1156,8 @@ void Buffer::validate(LaTeXFeatures & features) const
 {
        LyXTextClass const & tclass = params().getLyXTextClass();
 
-       if (params().tracking_changes) {
+       if (features.isAvailable("dvipost") && params().tracking_changes
+               && params().output_changes) {
                features.require("dvipost");
                features.require("color");
        }
@@ -1541,19 +1519,58 @@ void Buffer::buildMacros()
        pimpl_->macros = MacroTable::globalMacros();
 
        // Now add our own.
-       ParagraphList & pars = text().paragraphs();
+       ParagraphList const & 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();
+               InsetList const & insets = pars[i].insetlist;
+               InsetList::const_iterator it = insets.begin();
+               InsetList::const_iterator end = insets.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);
+                               MathMacroTemplate const & mac
+                                       = static_cast<MathMacroTemplate const &>(*it->inset);
                                insertMacro(mac.name(), mac.asMacroData());
                        }
                }
        }
 }
+
+
+void Buffer::saveCursor(StableDocIterator cur, StableDocIterator anc)
+{
+       cursor_ = cur;
+       anchor_ = anc;
+}
+
+
+void Buffer::changeRefsIfUnique(string const & from, string const & to)
+{
+       // Check if the label 'from' appears more than once
+       vector<string> labels;
+       getLabelList(labels);
+
+       if (lyx::count(labels.begin(), labels.end(), from) > 1)
+               return;
+
+       InsetBase::Code code = InsetBase::REF_CODE;
+
+       ParIterator it = par_iterator_begin();
+       ParIterator end = par_iterator_end();
+       for ( ; it != end; ++it) {
+               bool changed_inset = false;
+               for (InsetList::iterator it2 = it->insetlist.begin();
+                    it2 != it->insetlist.end(); ++it2) {
+                       if (it2->inset->lyxCode() == code) {
+                               InsetCommand * inset = static_cast<InsetCommand *>(it2->inset);
+                               if (inset->getContents() == from) {
+                                       inset->setContents(to);
+                                       //inset->setButtonLabel();
+                                       changed_inset = true;
+                               }
+                       }
+               }
+       }
+}
+