]> git.lyx.org Git - lyx.git/blobdiff - src/LaTeX.cpp
Partial fox for bug #6622: Display \utilde on screen correctly.
[lyx.git] / src / LaTeX.cpp
index f4d98155aad65f0bbcbbe0c628aa26f01e6e36f1..1596ba1e8298e3c9611eb366710e27c37c481711 100644 (file)
 #include "support/Systemcall.h"
 #include "support/os.h"
 
-#include <boost/regex.hpp>
+#include "support/regex.h"
 
 #include <fstream>
+#include <stack>
 
-using boost::regex;
-using boost::smatch;
 
 using namespace std;
 using namespace lyx::support;
@@ -66,9 +65,10 @@ docstring runMessage(unsigned int count)
  */
 
 void TeXErrors::insertError(int line, docstring const & error_desc,
-                           docstring const & error_text)
+                           docstring const & error_text,
+                           string const & child_name)
 {
-       Error newerr(line, error_desc, error_text);
+       Error newerr(line, error_desc, error_text, child_name);
        errors.push_back(newerr);
 }
 
@@ -124,6 +124,10 @@ void LaTeX::deleteFilesOnError() const
        FileName const bbl(changeExtension(file.absFileName(), ".bbl"));
        bbl.removeFile();
 
+       // biber file
+       FileName const bcf(changeExtension(file.absFileName(), ".bcf"));
+       bcf.removeFile();
+
        // makeindex file
        FileName const ind(changeExtension(file.absFileName(), ".ind"));
        ind.removeFile();
@@ -271,6 +275,12 @@ int LaTeX::run(TeXErrors & terr)
        if (head.haschanged(glofile))
                rerun |= runMakeIndexNomencl(file, ".glo", ".gls");
 
+       // check if we're using biber instead of bibtex
+       // biber writes no info to the aux file, so we just check
+       // if a bcf file exists (and if it was updated)
+       FileName const bcffile(changeExtension(file.absFileName(), ".bcf"));
+       bool const biber = head.exist(bcffile);
+
        // run bibtex
        // if (scanres & UNDEF_CIT || scanres & RERUN || run_bibtex)
        if (scanres & UNDEF_CIT || run_bibtex) {
@@ -280,13 +290,21 @@ int LaTeX::run(TeXErrors & terr)
                // no checks for now
                LYXERR(Debug::LATEX, "Running BibTeX.");
                message(_("Running BibTeX."));
-               updateBibtexDependencies(head, bibtex_info);
-               rerun |= runBibTeX(bibtex_info, runparams);
+               updateBibtexDependencies(head, bibtex_info, biber);
+               rerun |= runBibTeX(bibtex_info, runparams, biber);
+               if (biber) {
+                       // since biber writes no info to the aux file, we have
+                       // to parse the blg file (which only exists after biber
+                       // was first issued)
+                       FileName const blgfile(changeExtension(file.absFileName(), ".blg"));
+                       if (blgfile.exists())
+                               scanBlgFile(head);
+               }
        } else if (!had_depfile) {
                /// If we run pdflatex on the file after running latex on it,
                /// then we do not need to run bibtex, but we do need to
                /// insert the .bib and .bst files into the .dep-pdf file.
-               updateBibtexDependencies(head, bibtex_info);
+               updateBibtexDependencies(head, bibtex_info, biber);
        }
 
        // 2
@@ -332,8 +350,8 @@ int LaTeX::run(TeXErrors & terr)
                // no checks for now
                LYXERR(Debug::LATEX, "Running BibTeX.");
                message(_("Running BibTeX."));
-               updateBibtexDependencies(head, bibtex_info);
-               rerun |= runBibTeX(bibtex_info, runparams);
+               updateBibtexDependencies(head, bibtex_info, biber);
+               rerun |= runBibTeX(bibtex_info, runparams, biber);
        }
 
        // 4
@@ -532,7 +550,8 @@ void LaTeX::scanAuxFile(FileName const & file, AuxInfo & aux_info)
 
 
 void LaTeX::updateBibtexDependencies(DepTable & dep,
-                                    vector<AuxInfo> const & bibtex_info)
+                                    vector<AuxInfo> const & bibtex_info,
+                                    bool biber)
 {
        // Since a run of Bibtex mandates more latex runs it is ok to
        // remove all ".bib" and ".bst" files.
@@ -556,16 +575,22 @@ void LaTeX::updateBibtexDependencies(DepTable & dep,
                                dep.insert(file, true);
                }
        }
+
+       // biber writes nothing into the aux file.
+       // Instead, we have to scan the blg file
+       if (biber) {
+               scanBlgFile(dep);
+       }
 }
 
 
 bool LaTeX::runBibTeX(vector<AuxInfo> const & bibtex_info,
-                     OutputParams const & runparams)
+                     OutputParams const & runparams, bool biber)
 {
        bool result = false;
        for (vector<AuxInfo>::const_iterator it = bibtex_info.begin();
             it != bibtex_info.end(); ++it) {
-               if (it->databases.empty())
+               if (!biber && it->databases.empty())
                        continue;
                result = true;
 
@@ -598,9 +623,13 @@ int LaTeX::scanLogFile(TeXErrors & terr)
        ifstream ifs(fn.toFilesystemEncoding().c_str());
        bool fle_style = false;
        static regex file_line_error(".+\\.\\D+:[0-9]+: (.+)");
+       static regex child_file(".*([0-9]+[A-Za-z]*_.+\\.tex).*");
        // Flag for 'File ended while scanning' message.
        // We need to wait for subsequent processing.
        string wait_for_error;
+       string child_name;
+       int pnest = 0;
+       stack <pair<string, int> > child;
 
        string token;
        while (getline(ifs, token)) {
@@ -617,6 +646,29 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                if (token.empty())
                        continue;
 
+               // Track child documents
+               for (size_t i = 0; i < token.length(); ++i) {
+                       if (token[i] == '(') {
+                               ++pnest;
+                               size_t j = token.find('(', i + 1);
+                               size_t len = j == string::npos
+                                               ? token.substr(i + 1).length()
+                                               : j - i - 1;
+                               if (regex_match(token.substr(i + 1, len),
+                                                       sub, child_file)) {
+                                       string const name = sub.str(1);
+                                       child.push(make_pair(name, pnest));
+                                       i += len;
+                               }
+                       } else if (token[i] == ')') {
+                               if (!child.empty()
+                                   && child.top().second == pnest)
+                                       child.pop();
+                               --pnest;
+                       }
+               }
+               child_name = child.empty() ? empty_string() : child.top().first;
+
                if (contains(token, "file:line:error style messages enabled"))
                        fle_style = true;
 
@@ -635,6 +687,10 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                                   && contains(token, "undefined")) {
                                retval |= ERROR_RERUN;
                                LYXERR(Debug::LATEX, "Force rerun.");
+                       // package etaremune
+                       } else if (contains(token, "Etaremune labels have changed")) {
+                               retval |= ERROR_RERUN;
+                               LYXERR(Debug::LATEX, "Force rerun.");
                        } else if (contains(token, "Citation")
                                   && contains(token, "on page")
                                   && contains(token, "undefined")) {
@@ -653,6 +709,7 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                        } else if (contains(token, "run BibTeX")) {
                                retval |= UNDEF_CIT;
                        } else if (contains(token, "Rerun LaTeX") ||
+                                  contains(token, "Please rerun LaTeX") ||
                                   contains(token, "Rerun to get")) {
                                // at least longtable.sty and bibtopic.sty
                                // might use this.
@@ -688,11 +745,24 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                        if (contains(token, "LaTeX Error:"))
                                retval |= LATEX_ERROR;
 
-                       // bug 6445. At this point its not clear we finish with error.
                        if (prefixIs(token, "! File ended while scanning")){
-                               wait_for_error = desc;
-                               continue;
+                               if (prefixIs(token, "! File ended while scanning use of \\Hy@setref@link.")){
+                                       // bug 7344. We must rerun LaTeX if hyperref has been toggled.
+                                       retval |= ERROR_RERUN;
+                                       LYXERR(Debug::LATEX, "Force rerun.");
+                               } else {
+                                       // bug 6445. At this point its not clear we finish with error.
+                                       wait_for_error = desc;
+                                       continue;
+                               }
                        }
+
+                       if (prefixIs(token, "! Paragraph ended before \\Hy@setref@link was complete.")){
+                                       // bug 7344. We must rerun LaTeX if hyperref has been toggled.
+                                       retval |= ERROR_RERUN;
+                                       LYXERR(Debug::LATEX, "Force rerun.");
+                       }
+
                        if (!wait_for_error.empty() && prefixIs(token, "! Emergency stop.")){
                                retval |= LATEX_ERROR;
                                string errstr;
@@ -701,6 +771,7 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                                do {
                                        if (!getline(ifs, tmp))
                                                break;
+                                       tmp = rtrim(tmp, "\r");
                                        errstr += "\n" + tmp;
                                        if (++count > 5)
                                                break;
@@ -708,7 +779,8 @@ int LaTeX::scanLogFile(TeXErrors & terr)
 
                                terr.insertError(0,
                                                 from_local8bit("Emergency stop"),
-                                                from_local8bit(errstr));
+                                                from_local8bit(errstr),
+                                                child_name);
                        }
 
                        // get the next line
@@ -717,6 +789,7 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                        do {
                                if (!getline(ifs, tmp))
                                        break;
+                               tmp = rtrim(tmp, "\r");
                                if (++count > 10)
                                        break;
                        } while (!prefixIs(tmp, "l."));
@@ -735,6 +808,7 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                                string errstr(tmp, tmp.find(' '));
                                errstr += '\n';
                                getline(ifs, tmp);
+                               tmp = rtrim(tmp, "\r");
                                while (!contains(errstr, "l.")
                                       && !tmp.empty()
                                       && !prefixIs(tmp, "! ")
@@ -742,6 +816,7 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                                        errstr += tmp;
                                        errstr += "\n";
                                        getline(ifs, tmp);
+                                       tmp = rtrim(tmp, "\r");
                                }
                                LYXERR(Debug::LATEX, "line: " << line << '\n'
                                        << "Desc: " << desc << '\n' << "Text: " << errstr);
@@ -762,7 +837,8 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                                        // assume here it can be wrong.
                                        terr.insertError(line,
                                                         from_local8bit(desc),
-                                                        from_local8bit(errstr));
+                                                        from_local8bit(errstr),
+                                                        child_name);
                                        ++num_errors;
                                }
                        }
@@ -788,7 +864,8 @@ int LaTeX::scanLogFile(TeXErrors & terr)
                                retval |= ERRORS;
                                        terr.insertError(0,
                                                         from_local8bit("pdfTeX Error"),
-                                                        from_local8bit(token));
+                                                        from_local8bit(token),
+                                                        child_name);
                        }
                }
        }
@@ -952,7 +1029,7 @@ void LaTeX::deplog(DepTable & head)
        string lastline;
        while (ifs) {
                // Ok, the scanning of files here is not sufficient.
-               // Sometimes files are named by "File: xxx" only
+               // Sometimes files are named by "File:� xxx" only
                // So I think we should use some regexps to find files instead.
                // Note: all file names and paths might contains spaces.
                bool found_file = false;
@@ -1009,7 +1086,7 @@ void LaTeX::deplog(DepTable & head)
                        // However, ...
                        if (suffixIs(token, ")"))
                                // no line break for sure
-                               // pretend we've been succesfully searching
+                               // pretend we've been successfully searching
                                found_file = true;
                // (2) "No file file.ext"
                } else if (regex_match(token, sub, reg2)) {
@@ -1050,7 +1127,7 @@ void LaTeX::deplog(DepTable & head)
                                                file.absFileName(), ".toc")), head);
                else
                        // not found, but we won't check further
-                       // pretend we've been succesfully searching
+                       // pretend we've been successfully searching
                        found_file = true;
 
                // (8) "(file.ext"
@@ -1089,7 +1166,7 @@ void LaTeX::deplog(DepTable & head)
                                        // we have a closing bracket, so the content
                                        // is not a file name.
                                        // no need to investigate further
-                                       // pretend we've been succesfully searching
+                                       // pretend we've been successfully searching
                                        first = what[0].second;
                                        found_file = true;
                                }
@@ -1110,4 +1187,30 @@ void LaTeX::deplog(DepTable & head)
 }
 
 
+void LaTeX::scanBlgFile(DepTable & dep)
+{
+       FileName const blg_file(changeExtension(file.absFileName(), "blg"));
+       LYXERR(Debug::LATEX, "Scanning blg file: " << blg_file);
+
+       ifstream ifs(blg_file.toFilesystemEncoding().c_str());
+       string token;
+       static regex const reg1(".*Found bibtex data file '([^']+).*");
+
+       while (getline(ifs, token)) {
+               token = rtrim(token, "\r");
+               smatch sub;
+               // FIXME UNICODE: We assume that citation keys and filenames
+               // in the aux file are in the file system encoding.
+               token = to_utf8(from_filesystem8bit(token));
+               if (regex_match(token, sub, reg1)) {
+                       string data = sub.str(1);
+                       if (!data.empty()) {
+                               LYXERR(Debug::LATEX, "Found bib file: " << data);
+                               handleFoundFile(data, dep);
+                       }
+               }
+       } 
+}
+
+
 } // namespace lyx