X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FLaTeX.cpp;h=3e8729adf13313888d9f0defdf7c85339f84e66d;hb=66ca99798bff016b0a60cb10bd2124c5c228c8b6;hp=1cbbe2a915cdef1a911c9e0d0b15a29d167c4a1d;hpb=3e3955c4f3ee3302d2e1aae643be37ee3b758512;p=lyx.git diff --git a/src/LaTeX.cpp b/src/LaTeX.cpp index 1cbbe2a915..3e8729adf1 100644 --- a/src/LaTeX.cpp +++ b/src/LaTeX.cpp @@ -4,11 +4,11 @@ * Licence details can be found in the file COPYING. * * \author Alfredo Braunstein - * \author Lars Gullik Bjønnes + * \author Lars Gullik Bjønnes * \author Jean-Marc Lasgouttes * \author Angus Leeming * \author Dekel Tsur - * \author Jürgen Spitzmüller + * \author Jürgen Spitzmüller * * Full author contact details are available in file CREDITS. */ @@ -17,64 +17,29 @@ #include "BufferList.h" #include "LaTeX.h" -#include "gettext.h" #include "LyXRC.h" -#include "debug.h" #include "DepTable.h" -#include "support/filetools.h" +#include "support/debug.h" #include "support/convert.h" +#include "support/FileName.h" +#include "support/filetools.h" +#include "support/gettext.h" #include "support/lstrings.h" -#include "support/lyxlib.h" #include "support/Systemcall.h" #include "support/os.h" -#include -#include -#include +#include "support/regex.h" #include -using boost::regex; -using boost::smatch; - -#ifndef CXX_GLOBAL_CSTD -using std::sscanf; -#endif - -using std::endl; -using std::getline; -using std::string; -using std::ifstream; -using std::set; -using std::vector; +using namespace std; +using namespace lyx::support; namespace lyx { -using support::absolutePath; -using support::bformat; -using support::changeExtension; -using support::contains; -using support::FileName; -using support::findtexfile; -using support::getcwd; -using support::makeAbsPath; -using support::onlyFilename; -using support::prefixIs; -using support::quoteName; -using support::removeExtension; -using support::rtrim; -using support::rsplit; -using support::split; -using support::subst; -using support::suffixIs; -using support::Systemcall; -using support::unlink; -using support::trim; - namespace os = support::os; -namespace fs = boost::filesystem; // TODO: in no particular order // - get rid of the call to @@ -83,8 +48,6 @@ namespace fs = boost::filesystem; // different way. // - the makeindex style files should be taken care of with // the dependency mechanism. -// - makeindex commandline options should be supported -// - somewhere support viewing of bibtex and makeindex log files. // - we should perhaps also scan the bibtex log file namespace { @@ -108,16 +71,16 @@ void TeXErrors::insertError(int line, docstring const & error_desc, } -bool operator==(Aux_Info const & a, Aux_Info const & o) +bool operator==(AuxInfo const & a, AuxInfo const & o) { - return a.aux_file == o.aux_file && - a.citations == o.citations && - a.databases == o.databases && - a.styles == o.styles; + return a.aux_file == o.aux_file + && a.citations == o.citations + && a.databases == o.databases + && a.styles == o.styles; } -bool operator!=(Aux_Info const & a, Aux_Info const & o) +bool operator!=(AuxInfo const & a, AuxInfo const & o) { return !(a == o); } @@ -133,13 +96,13 @@ LaTeX::LaTeX(string const & latex, OutputParams const & rp, { num_errors = 0; if (prefixIs(cmd, "pdf")) { // Do we use pdflatex ? - depfile = FileName(file.absFilename() + ".dep-pdf"); + depfile = FileName(file.absFileName() + ".dep-pdf"); output_file = - FileName(changeExtension(file.absFilename(), ".pdf")); + FileName(changeExtension(file.absFileName(), ".pdf")); } else { - depfile = FileName(file.absFilename() + ".dep"); + depfile = FileName(file.absFileName() + ".dep"); output_file = - FileName(changeExtension(file.absFilename(), ".dvi")); + FileName(changeExtension(file.absFileName(), ".dvi")); } } @@ -151,29 +114,33 @@ void LaTeX::deleteFilesOnError() const // What files do we have to delete? // This will at least make latex do all the runs - unlink(depfile); + depfile.removeFile(); // but the reason for the error might be in a generated file... // bibtex file - FileName const bbl(changeExtension(file.absFilename(), ".bbl")); - unlink(bbl); + 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")); - unlink(ind); + FileName const ind(changeExtension(file.absFileName(), ".ind")); + ind.removeFile(); // nomencl file - FileName const nls(changeExtension(file.absFilename(), ".nls")); - unlink(nls); + FileName const nls(changeExtension(file.absFileName(), ".nls")); + nls.removeFile(); // nomencl file (old version of the package) - FileName const gls(changeExtension(file.absFilename(), ".gls")); - unlink(gls); + FileName const gls(changeExtension(file.absFileName(), ".gls")); + gls.removeFile(); // Also remove the aux file - FileName const aux(changeExtension(file.absFilename(), ".aux")); - unlink(aux); + FileName const aux(changeExtension(file.absFileName(), ".aux")); + aux.removeFile(); } @@ -181,7 +148,7 @@ int LaTeX::run(TeXErrors & terr) // We know that this function will only be run if the lyx buffer // has been changed. We also know that a newly written .tex file // is always different from the previous one because of the date - // in it. However it seems safe to run latex (at least) on time + // in it. However it seems safe to run latex (at least) one time // each time the .tex file changes. { int scanres = NO_ERRORS; @@ -192,7 +159,7 @@ int LaTeX::run(TeXErrors & terr) bool rerun = false; // rerun requested // The class LaTeX does not know the temp path. - theBufferList().updateIncludedTeXfiles(getcwd().absFilename(), + theBufferList().updateIncludedTeXfiles(FileName::getcwd().absFileName(), runparams); // Never write the depfile if an error was encountered. @@ -213,12 +180,12 @@ int LaTeX::run(TeXErrors & terr) // remake the dependency file. // - bool had_depfile = fs::exists(depfile.toFilesystemEncoding()); + bool had_depfile = depfile.exists(); bool run_bibtex = false; - FileName const aux_file(changeExtension(file.absFilename(), "aux")); + FileName const aux_file(changeExtension(file.absFileName(), "aux")); if (had_depfile) { - LYXERR(Debug::DEPEND) << "Dependency file exists" << endl; + LYXERR(Debug::DEPEND, "Dependency file exists"); // Read the dep file: had_depfile = head.read(depfile); } @@ -230,40 +197,37 @@ int LaTeX::run(TeXErrors & terr) // have aborted on error last time... in which cas we need // to re-run latex and collect the error messages // (even if they are the same). - if (!fs::exists(output_file.toFilesystemEncoding())) { - LYXERR(Debug::DEPEND) - << "re-running LaTeX because output file doesn't exist." - << endl; + if (!output_file.exists()) { + LYXERR(Debug::DEPEND, + "re-running LaTeX because output file doesn't exist."); } else if (!head.sumchange()) { - LYXERR(Debug::DEPEND) << "return no_change" << endl; + LYXERR(Debug::DEPEND, "return no_change"); return NO_CHANGE; } else { - LYXERR(Debug::DEPEND) - << "Dependency file has changed" << endl; + LYXERR(Debug::DEPEND, "Dependency file has changed"); } if (head.extchanged(".bib") || head.extchanged(".bst")) run_bibtex = true; } else - LYXERR(Debug::DEPEND) - << "Dependency file does not exist, or has wrong format" - << endl; + LYXERR(Debug::DEPEND, + "Dependency file does not exist, or has wrong format"); /// We scan the aux file even when had_depfile = false, /// because we can run pdflatex on the file after running latex on it, /// in which case we will not need to run bibtex again. - vector bibtex_info_old; + vector bibtex_info_old; if (!run_bibtex) bibtex_info_old = scanAuxFiles(aux_file); ++count; - LYXERR(Debug::LATEX) << "Run #" << count << endl; + LYXERR(Debug::LATEX, "Run #" << count); message(runMessage(count)); startscript(); scanres = scanLogFile(terr); if (scanres & ERROR_RERUN) { - LYXERR(Debug::LATEX) << "Rerunning LaTeX" << endl; + LYXERR(Debug::LATEX, "Rerunning LaTeX"); startscript(); scanres = scanLogFile(terr); } @@ -273,7 +237,7 @@ int LaTeX::run(TeXErrors & terr) return scanres; // return on error } - vector const bibtex_info = scanAuxFiles(aux_file); + vector const bibtex_info = scanAuxFiles(aux_file); if (!run_bibtex && bibtex_info_old != bibtex_info) run_bibtex = true; @@ -281,7 +245,7 @@ int LaTeX::run(TeXErrors & terr) deplog(head); // reads the latex log head.update(); - // 0.5 + // 1 // At this point we must run external programs if needed. // makeindex will be run if a .idx file changed or was generated. // And if there were undefined citations or changes in references @@ -290,25 +254,30 @@ int LaTeX::run(TeXErrors & terr) // memoir (at least) writes an empty *idx file in the first place. // A second latex run is needed. - FileName const idxfile(changeExtension(file.absFilename(), ".idx")); - rerun = fs::exists(idxfile.toFilesystemEncoding()) && - fs::is_empty(idxfile.toFilesystemEncoding()); + FileName const idxfile(changeExtension(file.absFileName(), ".idx")); + rerun = idxfile.exists() && idxfile.isFileEmpty(); // run makeindex if (head.haschanged(idxfile)) { // no checks for now - LYXERR(Debug::LATEX) << "Running MakeIndex." << endl; - message(_("Running MakeIndex.")); - // onlyFilename() is needed for cygwin - rerun |= runMakeIndex(onlyFilename(idxfile.absFilename()), + LYXERR(Debug::LATEX, "Running MakeIndex."); + message(_("Running Index Processor.")); + // onlyFileName() is needed for cygwin + rerun |= runMakeIndex(onlyFileName(idxfile.absFileName()), runparams); } - FileName const nlofile(changeExtension(file.absFilename(), ".nlo")); + FileName const nlofile(changeExtension(file.absFileName(), ".nlo")); if (head.haschanged(nlofile)) - rerun |= runMakeIndexNomencl(file, runparams, ".nlo", ".nls"); - FileName const glofile(changeExtension(file.absFilename(), ".glo")); + rerun |= runMakeIndexNomencl(file, ".nlo", ".nls"); + FileName const glofile(changeExtension(file.absFileName(), ".glo")); if (head.haschanged(glofile)) - rerun |= runMakeIndexNomencl(file, runparams, ".glo", ".gls"); + 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) @@ -317,18 +286,26 @@ int LaTeX::run(TeXErrors & terr) // "\bibdata" and/or "\bibstyle". If one of those // tags is found -> run bibtex and set rerun = true; // no checks for now - LYXERR(Debug::LATEX) << "Running BibTeX." << endl; + LYXERR(Debug::LATEX, "Running BibTeX."); message(_("Running BibTeX.")); - updateBibtexDependencies(head, bibtex_info); - rerun |= runBibTeX(bibtex_info); + 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); } - // 1 + // 2 // we know on this point that latex has been run once (or we just // returned) and the question now is to decide if we need to run // it any more. This is done by asking if any of the files in the @@ -338,16 +315,13 @@ int LaTeX::run(TeXErrors & terr) // run latex once more and // update the dependency structure // -> if not changed: - // we does nothing at this point + // we do nothing at this point // if (rerun || head.sumchange()) { rerun = false; ++count; - LYXERR(Debug::DEPEND) - << "Dep. file has changed or rerun requested" - << endl; - LYXERR(Debug::LATEX) - << "Run #" << count << endl; + LYXERR(Debug::DEPEND, "Dep. file has changed or rerun requested"); + LYXERR(Debug::LATEX, "Run #" << count); message(runMessage(count)); startscript(); scanres = scanLogFile(terr); @@ -360,13 +334,26 @@ int LaTeX::run(TeXErrors & terr) deplog(head); // reads the latex log head.update(); } else { - LYXERR(Debug::DEPEND) - << "Dep. file has NOT changed" - << endl; + LYXERR(Debug::DEPEND, "Dep. file has NOT changed"); + } + + // 3 + // rerun bibtex? + // Complex bibliography packages such as Biblatex require + // an additional bibtex cycle sometimes. + if (scanres & UNDEF_CIT) { + // Here we must scan the .aux file and look for + // "\bibdata" and/or "\bibstyle". If one of those + // tags is found -> run bibtex and set rerun = true; + // no checks for now + LYXERR(Debug::LATEX, "Running BibTeX."); + message(_("Running BibTeX.")); + updateBibtexDependencies(head, bibtex_info, biber); + rerun |= runBibTeX(bibtex_info, runparams, biber); } - // 1.5 - // The inclusion of files generated by external programs like + // 4 + // The inclusion of files generated by external programs such as // makeindex or bibtex might have done changes to pagenumbering, // etc. And because of this we must run the external programs // again to make sure everything is redone correctly. @@ -376,20 +363,20 @@ int LaTeX::run(TeXErrors & terr) // run makeindex if the .idx has changed or was generated. if (head.haschanged(idxfile)) { // no checks for now - LYXERR(Debug::LATEX) << "Running MakeIndex." << endl; - message(_("Running MakeIndex.")); - // onlyFilename() is needed for cygwin - rerun = runMakeIndex(onlyFilename(changeExtension( - file.absFilename(), ".idx")), runparams); + LYXERR(Debug::LATEX, "Running MakeIndex."); + message(_("Running Index Processor.")); + // onlyFileName() is needed for cygwin + rerun = runMakeIndex(onlyFileName(changeExtension( + file.absFileName(), ".idx")), runparams); } // I am not pretty sure if need this twice. if (head.haschanged(nlofile)) - rerun |= runMakeIndexNomencl(file, runparams, ".nlo", ".nls"); + rerun |= runMakeIndexNomencl(file, ".nlo", ".nls"); if (head.haschanged(glofile)) - rerun |= runMakeIndexNomencl(file, runparams, ".glo", ".gls"); + rerun |= runMakeIndexNomencl(file, ".glo", ".gls"); - // 2 + // 5 // we will only run latex more if the log file asks for it. // or if the sumchange() is true. // -> rerun asked for: @@ -405,7 +392,7 @@ int LaTeX::run(TeXErrors & terr) // MAX_RUNS are reached. rerun = false; ++count; - LYXERR(Debug::LATEX) << "Run #" << count << endl; + LYXERR(Debug::LATEX, "Run #" << count); message(runMessage(count)); startscript(); scanres = scanLogFile(terr); @@ -420,16 +407,16 @@ int LaTeX::run(TeXErrors & terr) // Write the dependencies to file. head.write(depfile); - LYXERR(Debug::LATEX) << "Done." << endl; + LYXERR(Debug::LATEX, "Done."); return scanres; } int LaTeX::startscript() { - // onlyFilename() is needed for cygwin + // onlyFileName() is needed for cygwin string tmp = cmd + ' ' - + quoteName(onlyFilename(file.toFilesystemEncoding())) + + quoteName(onlyFileName(file.toFilesystemEncoding())) + " > " + os::nulldev(); Systemcall one; return one.startscript(Systemcall::Wait, tmp); @@ -439,12 +426,23 @@ int LaTeX::startscript() bool LaTeX::runMakeIndex(string const & f, OutputParams const & runparams, string const & params) { - LYXERR(Debug::LATEX) - << "idx file has been made, running makeindex on file " - << f << endl; - string tmp = lyxrc.index_command + ' '; + string tmp = runparams.use_japanese ? + lyxrc.jindex_command : lyxrc.index_command; + + if (!runparams.index_command.empty()) + tmp = runparams.index_command; + + LYXERR(Debug::LATEX, + "idx file has been made, running index processor (" + << tmp << ") on file " << f); tmp = subst(tmp, "$$lang", runparams.document_language); + if (runparams.use_indices) { + tmp = lyxrc.splitindex_command + " -m " + quoteName(tmp); + LYXERR(Debug::LATEX, + "Multiple indices. Using splitindex command: " << tmp); + } + tmp += ' '; tmp += quoteName(f); tmp += params; Systemcall one; @@ -454,33 +452,34 @@ bool LaTeX::runMakeIndex(string const & f, OutputParams const & runparams, bool LaTeX::runMakeIndexNomencl(FileName const & file, - OutputParams const & runparams, string const & nlo, string const & nls) { - LYXERR(Debug::LATEX) << "Running MakeIndex for nomencl." << endl; + LYXERR(Debug::LATEX, "Running MakeIndex for nomencl."); message(_("Running MakeIndex for nomencl.")); - // onlyFilename() is needed for cygwin - string const nomenclstr = " -s nomencl.ist -o " - + onlyFilename(changeExtension(file.toFilesystemEncoding(), nls)); - return runMakeIndex( - onlyFilename(changeExtension(file.absFilename(), nlo)), - runparams, nomenclstr); + string tmp = lyxrc.nomencl_command + ' '; + // onlyFileName() is needed for cygwin + tmp += quoteName(onlyFileName(changeExtension(file.absFileName(), nlo))); + tmp += " -o " + + onlyFileName(changeExtension(file.toFilesystemEncoding(), nls)); + Systemcall one; + one.startscript(Systemcall::Wait, tmp); + return true; } -vector const +vector const LaTeX::scanAuxFiles(FileName const & file) { - vector result; + vector result; result.push_back(scanAuxFile(file)); - string const basename = removeExtension(file.absFilename()); + string const basename = removeExtension(file.absFileName()); for (int i = 1; i < 1000; ++i) { FileName const file2(basename + '.' + convert(i) + ".aux"); - if (!fs::exists(file2.toFilesystemEncoding())) + if (!file2.exists()) break; result.push_back(scanAuxFile(file2)); } @@ -488,18 +487,18 @@ LaTeX::scanAuxFiles(FileName const & file) } -Aux_Info const LaTeX::scanAuxFile(FileName const & file) +AuxInfo const LaTeX::scanAuxFile(FileName const & file) { - Aux_Info result; + AuxInfo result; result.aux_file = file; scanAuxFile(file, result); return result; } -void LaTeX::scanAuxFile(FileName const & file, Aux_Info & aux_info) +void LaTeX::scanAuxFile(FileName const & file, AuxInfo & aux_info) { - LYXERR(Debug::LATEX) << "Scanning aux file: " << file << endl; + LYXERR(Debug::LATEX, "Scanning aux file: " << file); ifstream ifs(file.toFilesystemEncoding().c_str()); string token; @@ -519,8 +518,7 @@ void LaTeX::scanAuxFile(FileName const & file, Aux_Info & aux_info) while (!data.empty()) { string citation; data = split(data, citation, ','); - LYXERR(Debug::LATEX) << "Citation: " - << citation << endl; + LYXERR(Debug::LATEX, "Citation: " << citation); aux_info.citations.insert(citation); } } else if (regex_match(token, sub, reg2)) { @@ -531,8 +529,7 @@ void LaTeX::scanAuxFile(FileName const & file, Aux_Info & aux_info) string database; data = split(data, database, ','); database = changeExtension(database, "bib"); - LYXERR(Debug::LATEX) << "BibTeX database: `" - << database << '\'' << endl; + LYXERR(Debug::LATEX, "BibTeX database: `" << database << '\''); aux_info.databases.insert(database); } } else if (regex_match(token, sub, reg3)) { @@ -540,8 +537,7 @@ void LaTeX::scanAuxFile(FileName const & file, Aux_Info & aux_info) // token is now the style file // pass it to the helper style = changeExtension(style, "bst"); - LYXERR(Debug::LATEX) << "BibTeX style: `" - << style << '\'' << endl; + LYXERR(Debug::LATEX, "BibTeX style: `" << style << '\''); aux_info.styles.insert(style); } else if (regex_match(token, sub, reg4)) { string const file2 = sub.str(1); @@ -552,15 +548,16 @@ void LaTeX::scanAuxFile(FileName const & file, Aux_Info & aux_info) void LaTeX::updateBibtexDependencies(DepTable & dep, - vector const & bibtex_info) + vector const & bibtex_info, + bool biber) { // Since a run of Bibtex mandates more latex runs it is ok to // remove all ".bib" and ".bst" files. dep.remove_files_with_extension(".bib"); dep.remove_files_with_extension(".bst"); - //string aux = OnlyFilename(ChangeExtension(file, ".aux")); + //string aux = OnlyFileName(ChangeExtension(file, ".aux")); - for (vector::const_iterator it = bibtex_info.begin(); + for (vector::const_iterator it = bibtex_info.begin(); it != bibtex_info.end(); ++it) { for (set::const_iterator it2 = it->databases.begin(); it2 != it->databases.end(); ++it2) { @@ -576,22 +573,34 @@ 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 const & bibtex_info) +bool LaTeX::runBibTeX(vector const & bibtex_info, + OutputParams const & runparams, bool biber) { bool result = false; - for (vector::const_iterator it = bibtex_info.begin(); + for (vector::const_iterator it = bibtex_info.begin(); it != bibtex_info.end(); ++it) { - if (it->databases.empty()) + if (!biber && it->databases.empty()) continue; result = true; - string tmp = lyxrc.bibtex_command + " "; - // onlyFilename() is needed for cygwin - tmp += quoteName(onlyFilename(removeExtension( - it->aux_file.absFilename()))); + string tmp = runparams.use_japanese ? + lyxrc.jbibtex_command : lyxrc.bibtex_command; + + if (!runparams.bibtex_command.empty()) + tmp = runparams.bibtex_command; + tmp += " "; + // onlyFileName() is needed for cygwin + tmp += quoteName(onlyFileName(removeExtension( + it->aux_file.absFileName()))); Systemcall one; one.startscript(Systemcall::Wait, tmp); } @@ -606,10 +615,15 @@ int LaTeX::scanLogFile(TeXErrors & terr) int line_count = 1; int retval = NO_ERRORS; string tmp = - onlyFilename(changeExtension(file.absFilename(), ".log")); - LYXERR(Debug::LATEX) << "Log file: " << tmp << endl; + onlyFileName(changeExtension(file.absFileName(), ".log")); + LYXERR(Debug::LATEX, "Log file: " << tmp); FileName const fn = FileName(makeAbsPath(tmp)); ifstream ifs(fn.toFilesystemEncoding().c_str()); + bool fle_style = false; + static regex file_line_error(".+\\.\\D+:[0-9]+: (.+)"); + // Flag for 'File ended while scanning' message. + // We need to wait for subsequent processing. + string wait_for_error; string token; while (getline(ifs, token)) { @@ -619,22 +633,35 @@ int LaTeX::scanLogFile(TeXErrors & terr) // \r's afterwards, since we need to remove them anyway. token = subst(token, '\0', '\r'); token = subst(token, "\r", ""); + smatch sub; - LYXERR(Debug::LATEX) << "Log line: " << token << endl; + LYXERR(Debug::LATEX, "Log line: " << token); if (token.empty()) continue; + if (contains(token, "file:line:error style messages enabled")) + fle_style = true; + if (prefixIs(token, "LaTeX Warning:") || prefixIs(token, "! pdfTeX warning")) { // Here shall we handle different // types of warnings retval |= LATEX_WARNING; - LYXERR(Debug::LATEX) << "LaTeX Warning." << endl; + LYXERR(Debug::LATEX, "LaTeX Warning."); if (contains(token, "Rerun to get cross-references")) { retval |= RERUN; - LYXERR(Debug::LATEX) - << "We should rerun." << endl; + LYXERR(Debug::LATEX, "We should rerun."); + // package clefval needs 2 latex runs before bibtex + } else if (contains(token, "Value of") + && contains(token, "on page") + && 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,29 +680,65 @@ 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. - LYXERR(Debug::LATEX) - << "We should rerun." << endl; + LYXERR(Debug::LATEX, "We should rerun."); + retval |= RERUN; + } + } else if (prefixIs(token, "LETTRE WARNING:")) { + if (contains(token, "veuillez recompiler")) { + // lettre.cls + LYXERR(Debug::LATEX, "We should rerun."); retval |= RERUN; } } else if (token[0] == '(') { if (contains(token, "Rerun LaTeX") || contains(token, "Rerun to get")) { // Used by natbib - LYXERR(Debug::LATEX) - << "We should rerun." << endl; + LYXERR(Debug::LATEX, "We should rerun."); retval |= RERUN; } - } else if (prefixIs(token, "! ")) { - // Ok, we have something that looks like a TeX Error - // but what do we really have. + } else if (prefixIs(token, "! ") + || (fle_style + && regex_match(token, sub, file_line_error) + && !contains(token, "pdfTeX warning"))) { + // Ok, we have something that looks like a TeX Error + // but what do we really have. // Just get the error description: - string desc(token, 2); + string desc; + if (prefixIs(token, "! ")) + desc = string(token, 2); + else if (fle_style) + desc = sub.str(); 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 (!wait_for_error.empty() && prefixIs(token, "! Emergency stop.")){ + retval |= LATEX_ERROR; + string errstr; + int count = 0; + errstr = wait_for_error; + do { + if (!getline(ifs, tmp)) + break; + errstr += "\n" + tmp; + if (++count > 5) + break; + } while (!contains(tmp, "(job aborted")); + + terr.insertError(0, + from_local8bit("Emergency stop"), + from_local8bit(errstr)); + } + // get the next line string tmp; int count = 0; @@ -689,7 +752,9 @@ int LaTeX::scanLogFile(TeXErrors & terr) // we have a latex error retval |= TEX_ERROR; if (contains(desc, - "Package babel Error: You haven't defined the language")) + "Package babel Error: You haven't defined the language") || + contains(desc, + "Package babel Error: You haven't loaded the option")) retval |= ERROR_RERUN; // get the line number: int line = 0; @@ -706,10 +771,8 @@ int LaTeX::scanLogFile(TeXErrors & terr) errstr += "\n"; getline(ifs, tmp); } - LYXERR(Debug::LATEX) - << "line: " << line << '\n' - << "Desc: " << desc << '\n' - << "Text: " << errstr << endl; + LYXERR(Debug::LATEX, "line: " << line << '\n' + << "Desc: " << desc << '\n' << "Text: " << errstr); if (line == last_line) ++line_count; else { @@ -747,41 +810,26 @@ int LaTeX::scanLogFile(TeXErrors & terr) } else if (contains(token, "That makes 100 errors")) { // More than 100 errors were reprted retval |= TOO_MANY_ERRORS; + } else if (prefixIs(token, "!pdfTeX error:")){ + // otherwise we dont catch e.g.: + // !pdfTeX error: pdflatex (file feyn10): Font feyn10 at 600 not found + retval |= ERRORS; + terr.insertError(0, + from_local8bit("pdfTeX Error"), + from_local8bit(token)); } } } - LYXERR(Debug::LATEX) << "Log line: " << token << endl; + LYXERR(Debug::LATEX, "Log line: " << token); return retval; } namespace { -/** - * Wrapper around fs::exists that can handle invalid file names. - * In theory we could test with fs::native whether a filename is valid - * before calling fs::exists, but in practice it is unusable: On windows it - * does not allow spaces, and on unix it does not allow absolute file names. - * This function has the disadvantage that it catches also other errors than - * invalid names, but for dependency checking we can live with that. - */ -bool exists(FileName const & possible_name) { - try { - return fs::exists(possible_name.toFilesystemEncoding()); - } - catch (fs::filesystem_error const & fe) { - LYXERR(Debug::DEPEND) << "Got error `" << fe.what() - << "' while checking whether file `" << possible_name - << "' exists." << endl; - return false; - } -} - - bool insertIfExists(FileName const & absname, DepTable & head) { - if (exists(absname) && - !fs::is_directory(absname.toFilesystemEncoding())) { + if (absname.exists() && !absname.isDirectory()) { head.insert(absname, true); return true; } @@ -794,7 +842,7 @@ bool handleFoundFile(string const & ff, DepTable & head) // convert from native os path to unix path string foundfile = os::internal_path(trim(ff)); - LYXERR(Debug::DEPEND) << "Found file: " << foundfile << endl; + LYXERR(Debug::DEPEND, "Found file: " << foundfile); // Ok now we found a file. // Now we should make sure that this is a file that we can @@ -805,13 +853,13 @@ bool handleFoundFile(string const & ff, DepTable & head) // (1) foundfile is an // absolute path and should // be inserted. - if (absolutePath(foundfile)) { - LYXERR(Debug::DEPEND) << "AbsolutePath file: " - << foundfile << endl; + FileName absname; + if (FileName::isAbsolute(foundfile)) { + LYXERR(Debug::DEPEND, "AbsolutePath file: " << foundfile); // On initial insert we want to do the update at once // since this file cannot be a file generated by // the latex run. - FileName absname(foundfile); + absname.set(foundfile); if (!insertIfExists(absname, head)) { // check for spaces string strippedfile = foundfile; @@ -833,12 +881,12 @@ bool handleFoundFile(string const & ff, DepTable & head) } } - string onlyfile = onlyFilename(foundfile); - FileName absname(makeAbsPath(onlyfile)); + string onlyfile = onlyFileName(foundfile); + absname = makeAbsPath(onlyfile); // check for spaces while (contains(foundfile, ' ')) { - if (exists(absname)) + if (absname.exists()) // everything o.k. break; else { @@ -846,52 +894,40 @@ bool handleFoundFile(string const & ff, DepTable & head) // marks; those have to be removed string unquoted = subst(foundfile, "\"", ""); absname = makeAbsPath(unquoted); - if (exists(absname)) + if (absname.exists()) break; // strip off part after last space and try again string strippedfile; string const stripoff = rsplit(foundfile, strippedfile, ' '); foundfile = strippedfile; - onlyfile = onlyFilename(strippedfile); + onlyfile = onlyFileName(strippedfile); absname = makeAbsPath(onlyfile); } } // (2) foundfile is in the tmpdir // insert it into head - if (exists(absname) && - !fs::is_directory(absname.toFilesystemEncoding())) { + if (absname.exists() && !absname.isDirectory()) { // FIXME: This regex contained glo, but glo is used by the old // version of nomencl.sty. Do we need to put it back? - static regex unwanted("^.*\\.(aux|log|dvi|bbl|ind)$"); + static regex const unwanted("^.*\\.(aux|log|dvi|bbl|ind)$"); if (regex_match(onlyfile, unwanted)) { - LYXERR(Debug::DEPEND) - << "We don't want " - << onlyfile - << " in the dep file" - << endl; + LYXERR(Debug::DEPEND, "We don't want " << onlyfile + << " in the dep file"); } else if (suffixIs(onlyfile, ".tex")) { // This is a tex file generated by LyX // and latex is not likely to change this // during its runs. - LYXERR(Debug::DEPEND) - << "Tmpdir TeX file: " - << onlyfile - << endl; + LYXERR(Debug::DEPEND, "Tmpdir TeX file: " << onlyfile); head.insert(absname, true); } else { - LYXERR(Debug::DEPEND) - << "In tmpdir file:" - << onlyfile - << endl; + LYXERR(Debug::DEPEND, "In tmpdir file:" << onlyfile); head.insert(absname); } return true; } else { - LYXERR(Debug::DEPEND) - << "Not a file or we are unable to find it." - << endl; + LYXERR(Debug::DEPEND, "Not a file or we are unable to find it."); return false; } } @@ -899,12 +935,11 @@ bool handleFoundFile(string const & ff, DepTable & head) bool checkLineBreak(string const & ff, DepTable & head) { - if (contains(ff, '.')) - // if we have a dot, we let handleFoundFile decide - return handleFoundFile(ff, head); - else - // else, we suspect a line break + if (!contains(ff, '.')) return false; + + // if we have a dot, we let handleFoundFile decide + return handleFoundFile(ff, head); } } // anon namespace @@ -917,35 +952,35 @@ void LaTeX::deplog(DepTable & head) // entered into the dependency file. string const logfile = - onlyFilename(changeExtension(file.absFilename(), ".log")); + onlyFileName(changeExtension(file.absFileName(), ".log")); - static regex reg1("File: (.+).*"); - static regex reg2("No file (.+)(.).*"); - static regex reg3("\\\\openout[0-9]+.*=.*`(.+)(..).*"); + static regex const reg1("File: (.+).*"); + static regex const reg2("No file (.+)(.).*"); + static regex const reg3("\\\\openout[0-9]+.*=.*`(.+)(..).*"); // If an index should be created, MikTex does not write a line like // \openout# = 'sample.idx'. // but instead only a line like this into the log: // Writing index file sample.idx - static regex reg4("Writing index file (.+).*"); + static regex const reg4("Writing index file (.+).*"); // files also can be enclosed in <...> - static regex reg5("<([^>]+)(.).*"); - static regex regoldnomencl("Writing glossary file (.+).*"); - static regex regnomencl("Writing nomenclature file (.+).*"); + static regex const reg5("<([^>]+)(.).*"); + static regex const regoldnomencl("Writing glossary file (.+).*"); + static regex const regnomencl("Writing nomenclature file (.+).*"); // If a toc should be created, MikTex does not write a line like // \openout# = `sample.toc'. // but only a line like this into the log: // \tf@toc=\write# // This line is also written by tetex. // This line is not present if no toc should be created. - static regex miktexTocReg("\\\\tf@toc=\\\\write.*"); - static regex reg6(".*\\([^)]+.*"); + static regex const miktexTocReg("\\\\tf@toc=\\\\write.*"); + static regex const reg6(".*\\([^)]+.*"); - FileName const fn(makeAbsPath(logfile)); + FileName const fn = makeAbsPath(logfile); ifstream ifs(fn.toFilesystemEncoding().c_str()); 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; @@ -967,8 +1002,8 @@ void LaTeX::deplog(DepTable & head) // Here we exclude some cases where we are sure // that there is no continued filename if (!lastline.empty()) { - static regex package_info("Package \\w+ Info: .*"); - static regex package_warning("Package \\w+ Warning: .*"); + static regex const package_info("Package \\w+ Info: .*"); + static regex const package_warning("Package \\w+ Warning: .*"); if (prefixIs(token, "File:") || prefixIs(token, "(Font)") || prefixIs(token, "Package:") || prefixIs(token, "Language:") @@ -1002,7 +1037,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)) { @@ -1039,11 +1074,11 @@ void LaTeX::deplog(DepTable & head) found_file = checkLineBreak(sub.str(1), head); // (7) "\tf@toc=\write" (for MikTeX) else if (regex_match(token, sub, miktexTocReg)) - found_file = handleFoundFile(onlyFilename(changeExtension( - file.absFilename(), ".toc")), head); + found_file = handleFoundFile(onlyFileName(changeExtension( + 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" @@ -1053,7 +1088,7 @@ void LaTeX::deplog(DepTable & head) // where "File: file.ext" would be skipped if (regex_match(token, sub, reg6)) { // search for strings in (...) - static regex reg6_1("\\(([^()]+)(.).*"); + static regex reg6_1("\\(([^()]+)(.)"); smatch what; string::const_iterator first = token.begin(); string::const_iterator end = token.end(); @@ -1082,7 +1117,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; } @@ -1103,4 +1138,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