X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FLaTeX.cpp;h=917d129424613286280d9ee64061b6bcf40aa2b6;hb=6f7b39f84299660586b0485713d9672279ebe226;hp=be9465495417c17b22e5904a0d0ad5e1b7af897c;hpb=05c7c65d9345c4cd88b9c34b8e30beb96a268963;p=features.git diff --git a/src/LaTeX.cpp b/src/LaTeX.cpp index be94654954..917d129424 100644 --- a/src/LaTeX.cpp +++ b/src/LaTeX.cpp @@ -15,16 +15,19 @@ #include +#include "LaTeX.h" + #include "Buffer.h" #include "BufferList.h" #include "BufferParams.h" -#include "LaTeX.h" #include "LyXRC.h" #include "LyX.h" #include "DepTable.h" #include "Encoding.h" +#include "Language.h" #include "support/debug.h" +#include "support/docstring.h" #include "support/convert.h" #include "support/FileName.h" #include "support/filetools.h" @@ -33,9 +36,8 @@ #include "support/Systemcall.h" #include "support/os.h" -#include "support/regex.h" - #include +#include #include @@ -133,6 +135,7 @@ LaTeX::LaTeX(string const & latex, OutputParams const & rp, void LaTeX::removeAuxiliaryFiles() const { + LYXERR(Debug::OUTFILE, "Removing auxiliary files"); // Note that we do not always call this function when there is an error. // For example, if there is an error but an output file is produced we // still would like to output (export/view) the file. @@ -238,7 +241,7 @@ int LaTeX::run(TeXErrors & terr) // Also remove all children which are included Buffer const * buf = theBufferList().getBufferFromTmp(file.absFileName()); if (buf && buf->params().maintain_unincluded_children == BufferParams::CM_Mostly) { - for (auto const incfile : buf->params().getIncludedChildren()) { + for (auto const & incfile : buf->params().getIncludedChildren()) { string const incm = DocFileName(changeExtension(makeAbsPath(incfile, path) .absFileName(), ".tex")).mangledFileName(); @@ -277,20 +280,20 @@ int LaTeX::run(TeXErrors & terr) bibtex_info_old = scanAuxFiles(aux_file, runparams.only_childbibs); ++count; - LYXERR(Debug::LATEX, "Run #" << count); + LYXERR(Debug::OUTFILE, "Run #" << count); message(runMessage(count)); int exit_code = startscript(); - if (exit_code == Systemcall::KILLED) - return Systemcall::KILLED; + if (exit_code == Systemcall::KILLED || exit_code == Systemcall::TIMEOUT) + return exit_code; scanres = scanLogFile(terr); if (scanres & ERROR_RERUN) { - LYXERR(Debug::LATEX, "Rerunning LaTeX"); + LYXERR(Debug::OUTFILE, "Rerunning LaTeX"); terr.clearErrors(); exit_code = startscript(); - if (exit_code == Systemcall::KILLED) - return Systemcall::KILLED; + if (exit_code == Systemcall::KILLED || exit_code == Systemcall::TIMEOUT) + return exit_code; scanres = scanLogFile(terr); } @@ -303,63 +306,14 @@ int LaTeX::run(TeXErrors & terr) head.update(); // 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 - // the .aux file is checked for signs of bibtex. Bibtex is then run - // if needed. - - // 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 = idxfile.exists() && idxfile.isFileEmpty(); - - // run makeindex - if (head.haschanged(idxfile)) { - // no checks for now - LYXERR(Debug::LATEX, "Running MakeIndex."); - message(_("Running Index Processor.")); - // onlyFileName() is needed for cygwin - int const ret = - runMakeIndex(onlyFileName(idxfile.absFileName()), runparams); - if (ret == Systemcall::KILLED) - return Systemcall::KILLED; - FileName const ilgfile(changeExtension(file.absFileName(), ".ilg")); - if (ilgfile.exists()) - iscanres = scanIlgFile(terr); - rerun = true; - } - - FileName const nlofile(changeExtension(file.absFileName(), ".nlo")); - // If all nomencl entries are removed, nomencl writes an empty nlo file. - // DepTable::hasChanged() returns false in this case, since it does not - // distinguish empty files from non-existing files. This is why we need - // the extra checks here (to trigger a rerun). Cf. discussions in #8905. - // FIXME: Sort out the real problem in DepTable. - if (head.haschanged(nlofile) || (nlofile.exists() && nlofile.isFileEmpty())) { - int const ret = runMakeIndexNomencl(file, ".nlo", ".nls"); - if (ret == Systemcall::KILLED) - return Systemcall::KILLED; - rerun = true; - } - - FileName const glofile(changeExtension(file.absFileName(), ".glo")); - if (head.haschanged(glofile)) { - int const ret = runMakeIndexNomencl(file, ".glo", ".gls"); - if (ret) - return ret; - rerun = true; - } - - - // check if we're using biber instead of bibtex + // At this point we must run the bibliography processor if needed. + // First, 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) + // if a bcf file exists (and if it was updated). FileName const bcffile(changeExtension(file.absFileName(), ".bcf")); biber |= head.exist(bcffile); - // run bibtex - // if (scanres & UNDEF_CIT || scanres & RERUN || run_bibtex) + // If (scanres & UNDEF_CIT || scanres & RERUN || run_bibtex) // We do not run bibtex/biber on an "includeall" call (whose purpose is // to set up/maintain counters and references for includeonly) since // (1) bibliographic references will be updated on the subsequent includeonly run @@ -370,13 +324,13 @@ 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."); - message(_("Running BibTeX.")); + LYXERR(Debug::OUTFILE, "Running Bibliography Processor."); + message(_("Running Bibliography Processor.")); updateBibtexDependencies(head, bibtex_info); int exit_code; rerun |= runBibTeX(bibtex_info, runparams, exit_code); - if (exit_code == Systemcall::KILLED) - return Systemcall::KILLED; + if (exit_code == Systemcall::KILLED || exit_code == Systemcall::TIMEOUT) + return exit_code; FileName const blgfile(changeExtension(file.absFileName(), ".blg")); if (blgfile.exists()) bscanres = scanBlgFile(head, terr); @@ -388,7 +342,7 @@ int LaTeX::run(TeXErrors & terr) } // 2 - // we know on this point that latex has been run once (or we just + // 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 // dependency file has changed. (remember that the checksum for @@ -403,11 +357,11 @@ int LaTeX::run(TeXErrors & terr) rerun = false; ++count; LYXERR(Debug::DEPEND, "Dep. file has changed or rerun requested"); - LYXERR(Debug::LATEX, "Run #" << count); + LYXERR(Debug::OUTFILE, "Run #" << count); message(runMessage(count)); int exit_code = startscript(); - if (exit_code == Systemcall::KILLED) - return Systemcall::KILLED; + if (exit_code == Systemcall::KILLED || exit_code == Systemcall::TIMEOUT) + return exit_code; scanres = scanLogFile(terr); // update the depedencies @@ -418,7 +372,7 @@ int LaTeX::run(TeXErrors & terr) } // 3 - // rerun bibtex? + // Rerun bibliography processor? // Complex bibliography packages such as Biblatex require // an additional bibtex cycle sometimes. // We do not run bibtex/biber on an "includeall" call (whose purpose is @@ -431,50 +385,87 @@ 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."); - message(_("Running BibTeX.")); + LYXERR(Debug::OUTFILE, "Re-Running Bibliography Processor."); + message(_("Re-Running Bibliography Processor.")); updateBibtexDependencies(head, bibtex_info); int exit_code; rerun |= runBibTeX(bibtex_info, runparams, exit_code); - if (exit_code == Systemcall::KILLED) - return Systemcall::KILLED; + if (exit_code == Systemcall::KILLED || exit_code == Systemcall::TIMEOUT) + return exit_code; FileName const blgfile(changeExtension(file.absFileName(), ".blg")); if (blgfile.exists()) bscanres = scanBlgFile(head, terr); } // 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. - // Also there should be no need to run the external programs any - // more after this. - - // run makeindex if the .idx has changed or was generated. - if (head.haschanged(idxfile)) { + // After the bibliography was processed, we need more passes of LaTeX + // in order to resolve the citations. We need to do this before the index + // is being generated (since we need the correct pagination, see #2696). + // Also, memoir (at least) writes an empty *idx file in the first place. + // A further latex run is needed in that case as well. + FileName const idxfile(changeExtension(file.absFileName(), ".idx")); + if (run_bibtex || (idxfile.exists() && idxfile.isFileEmpty())) { + while ((head.sumchange() || rerun || (scanres & RERUN)) + && count < MAX_RUN) { + // Yes rerun until message goes away, or until + // MAX_RUNS are reached. + rerun = false; + ++count; + LYXERR(Debug::OUTFILE, "Run #" << count); + message(runMessage(count)); + startscript(); + scanres = scanLogFile(terr); + + // keep this updated + head.update(); + } + } + + // 5 + // Now that we have final pagination, run the index and nomencl processors + if (idxfile.exists()) { // no checks for now - LYXERR(Debug::LATEX, "Running MakeIndex."); + LYXERR(Debug::OUTFILE, "Running Index Processor."); message(_("Running Index Processor.")); // onlyFileName() is needed for cygwin - int const ret = runMakeIndex(onlyFileName(changeExtension( - file.absFileName(), ".idx")), runparams); - if (ret == Systemcall::KILLED) - return Systemcall::KILLED; + int const ret = + runMakeIndex(onlyFileName(idxfile.absFileName()), runparams); + if (ret == Systemcall::KILLED || ret == Systemcall::TIMEOUT) + return ret; + else if (ret != Systemcall::OK) { + iscanres |= INDEX_ERROR; + terr.insertError(0, + _("Index Processor Error"), + _("The index processor did not run successfully. " + "Please check the output of View > Messages Pane!")); + } FileName const ilgfile(changeExtension(file.absFileName(), ".ilg")); if (ilgfile.exists()) iscanres = scanIlgFile(terr); rerun = true; } + FileName const nlofile(changeExtension(file.absFileName(), ".nlo")); + // If all nomencl entries are removed, nomencl writes an empty nlo file. + // DepTable::hasChanged() returns false in this case, since it does not + // distinguish empty files from non-existing files. This is why we need + // the extra checks here (to trigger a rerun). Cf. discussions in #8905. + // FIXME: Sort out the real problem in DepTable. + if (head.haschanged(nlofile) || (nlofile.exists() && nlofile.isFileEmpty())) { + int const ret = runMakeIndexNomencl(file, ".nlo", ".nls"); + if (ret == Systemcall::KILLED || ret == Systemcall::TIMEOUT) + return ret; + rerun = true; + } + FileName const glofile(changeExtension(file.absFileName(), ".glo")); + if (head.haschanged(glofile)) { + int const ret = runMakeIndexNomencl(file, ".glo", ".gls"); + if (ret) + return ret; + rerun = true; + } - // MSVC complains that bool |= int is unsafe. Not sure why. - if (head.haschanged(nlofile)) - rerun |= (runMakeIndexNomencl(file, ".nlo", ".nls") != 0); - if (head.haschanged(glofile)) - rerun |= (runMakeIndexNomencl(file, ".glo", ".gls") != 0); - - // 5 - // we will only run latex more if the log file asks for it. + // 6 + // We will re-run latex if the log file asks for it, // or if the sumchange() is true. // -> rerun asked for: // run latex and @@ -489,7 +480,7 @@ int LaTeX::run(TeXErrors & terr) // MAX_RUNS are reached. rerun = false; ++count; - LYXERR(Debug::LATEX, "Run #" << count); + LYXERR(Debug::OUTFILE, "Run #" << count); message(runMessage(count)); startscript(); scanres = scanLogFile(terr); @@ -508,7 +499,7 @@ int LaTeX::run(TeXErrors & terr) scanres |= NONZERO_ERROR; } - LYXERR(Debug::LATEX, "Done."); + LYXERR(Debug::OUTFILE, "Done."); if (bscanres & ERRORS) return bscanres; // return on error @@ -541,13 +532,15 @@ int LaTeX::runMakeIndex(string const & f, OutputParams const & rp, if (!rp.index_command.empty()) tmp = rp.index_command; + + Language const * doc_lang = languages.getLanguage(rp.document_language); if (contains(tmp, "$$x")) { // This adds appropriate [te]xindy options // such as language and codepage (for the // main document language/encoding) as well // as input markup (latex or xelatex) - string xdyopts = rp.xindy_language; + string xdyopts = doc_lang ? doc_lang->xindy() : string(); if (!xdyopts.empty()) xdyopts = "-L " + xdyopts; if (rp.isFullUnicode() && rp.encoding->package() == Encoding::none) { @@ -576,14 +569,17 @@ int LaTeX::runMakeIndex(string const & f, OutputParams const & rp, tmp = subst(tmp, "$$b", removeExtension(f)); } - LYXERR(Debug::LATEX, + LYXERR(Debug::OUTFILE, "idx file has been made, running index processor (" << tmp << ") on file " << f); - tmp = subst(tmp, "$$lang", rp.document_language); + if (doc_lang) { + tmp = subst(tmp, "$$lang", doc_lang->babel()); + tmp = subst(tmp, "$$lcode", doc_lang->code()); + } if (rp.use_indices) { tmp = lyxrc.splitindex_command + " -m " + quoteName(tmp); - LYXERR(Debug::LATEX, + LYXERR(Debug::OUTFILE, "Multiple indices. Using splitindex command: " << tmp); } tmp += ' '; @@ -599,8 +595,8 @@ int LaTeX::runMakeIndex(string const & f, OutputParams const & rp, int LaTeX::runMakeIndexNomencl(FileName const & fname, string const & nlo, string const & nls) { - LYXERR(Debug::LATEX, "Running MakeIndex for nomencl."); - message(_("Running MakeIndex for nomencl.")); + LYXERR(Debug::OUTFILE, "Running Nomenclature Processor."); + message(_("Running Nomenclature Processor.")); string tmp = lyxrc.nomencl_command + ' '; // onlyFileName() is needed for cygwin tmp += quoteName(onlyFileName(changeExtension(fname.absFileName(), nlo))); @@ -658,7 +654,7 @@ AuxInfo const LaTeX::scanAuxFile(FileName const & fname) void LaTeX::scanAuxFile(FileName const & fname, AuxInfo & aux_info) { - LYXERR(Debug::LATEX, "Scanning aux file: " << fname); + LYXERR(Debug::OUTFILE, "Scanning aux file: " << fname); ifstream ifs(fname.toFilesystemEncoding().c_str()); string token; @@ -678,7 +674,7 @@ void LaTeX::scanAuxFile(FileName const & fname, AuxInfo & aux_info) while (!data.empty()) { string citation; data = split(data, citation, ','); - LYXERR(Debug::LATEX, "Citation: " << citation); + LYXERR(Debug::OUTFILE, "Citation: " << citation); aux_info.citations.insert(citation); } } else if (regex_match(token, sub, reg2)) { @@ -689,7 +685,7 @@ void LaTeX::scanAuxFile(FileName const & fname, AuxInfo & aux_info) string database; data = split(data, database, ','); database = changeExtension(database, "bib"); - LYXERR(Debug::LATEX, "BibTeX database: `" << database << '\''); + LYXERR(Debug::OUTFILE, "BibTeX database: `" << database << '\''); aux_info.databases.insert(database); } } else if (regex_match(token, sub, reg3)) { @@ -697,7 +693,7 @@ void LaTeX::scanAuxFile(FileName const & fname, AuxInfo & aux_info) // token is now the style file // pass it to the helper style = changeExtension(style, "bst"); - LYXERR(Debug::LATEX, "BibTeX style: `" << style << '\''); + LYXERR(Debug::OUTFILE, "BibTeX style: `" << style << '\''); aux_info.styles.insert(style); } else if (regex_match(token, sub, reg4)) { string const file2 = sub.str(1); @@ -760,7 +756,7 @@ bool LaTeX::runBibTeX(vector const & bibtex_info, it->aux_file.absFileName()))); Systemcall one; Systemcall::Starttype const starttype = - allow_cancel ? Systemcall::WaitLoop : Systemcall::Wait; + allow_cancel ? Systemcall::WaitLoop : Systemcall::Wait; exit_code = one.startscript(starttype, tmp, path, lpath, true); if (exit_code) { return result; @@ -786,8 +782,8 @@ int LaTeX::scanLogFile(TeXErrors & terr) int retval = NO_ERRORS; string tmp = onlyFileName(changeExtension(file.absFileName(), ".log")); - LYXERR(Debug::LATEX, "Log file: " << tmp); - FileName const fn = FileName(makeAbsPath(tmp)); + LYXERR(Debug::OUTFILE, "Log file: " << tmp); + FileName const fn = makeAbsPath(tmp); // FIXME we should use an ifdocstream here and a docstring for token // below. The encoding of the log file depends on the _output_ (font) // encoding of the TeX file (T1, TU etc.). See #10728. @@ -817,7 +813,7 @@ int LaTeX::scanLogFile(TeXErrors & terr) token = subst(token, "\r", ""); smatch sub; - LYXERR(Debug::LATEX, "Log line: " << token); + LYXERR(Debug::OUTFILE, "Log line: " << token); if (token.empty()) continue; @@ -873,24 +869,24 @@ int LaTeX::scanLogFile(TeXErrors & terr) // Here shall we handle different // types of warnings retval |= LATEX_WARNING; - LYXERR(Debug::LATEX, "LaTeX Warning."); + LYXERR(Debug::OUTFILE, "LaTeX Warning."); if (contains(token, "Rerun to get cross-references")) { retval |= RERUN; - LYXERR(Debug::LATEX, "We should rerun."); + LYXERR(Debug::OUTFILE, "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."); + LYXERR(Debug::OUTFILE, "Force rerun."); // package etaremune } else if (contains(token, "Etaremune labels have changed")) { retval |= ERROR_RERUN; - LYXERR(Debug::LATEX, "Force rerun."); + LYXERR(Debug::OUTFILE, "Force rerun."); // package enotez } else if (contains(token, "Endnotes may have changed. Rerun")) { retval |= RERUN; - LYXERR(Debug::LATEX, "We should rerun."); + LYXERR(Debug::OUTFILE, "We should rerun."); //"Citation `cit' on page X undefined on input line X." } else if (!runparams.includeall && contains(token, "Citation") //&& contains(token, "on input line") //often split to newline @@ -972,20 +968,20 @@ int LaTeX::scanLogFile(TeXErrors & terr) contains(token, "Rerun to get")) { // at least longtable.sty and bibtopic.sty // might use this. - LYXERR(Debug::LATEX, "We should rerun."); + LYXERR(Debug::OUTFILE, "We should rerun."); retval |= RERUN; } } else if (prefixIs(token, "LETTRE WARNING:")) { if (contains(token, "veuillez recompiler")) { // lettre.cls - LYXERR(Debug::LATEX, "We should rerun."); + LYXERR(Debug::OUTFILE, "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."); + LYXERR(Debug::OUTFILE, "We should rerun."); retval |= RERUN; } } else if (prefixIs(token, "! ") @@ -1008,7 +1004,7 @@ int LaTeX::scanLogFile(TeXErrors & terr) 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."); + LYXERR(Debug::OUTFILE, "Force rerun."); } else { // bug 6445. At this point its not clear we finish with error. wait_for_error = desc; @@ -1025,7 +1021,7 @@ int LaTeX::scanLogFile(TeXErrors & terr) 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."); + LYXERR(Debug::OUTFILE, "Force rerun."); } if (!wait_for_error.empty() && prefixIs(token, "! Emergency stop.")){ @@ -1105,8 +1101,8 @@ int LaTeX::scanLogFile(TeXErrors & terr) if (preamble_error) // Add a note that the error is to be found in preamble errstr += "\n" + to_utf8(_("(NOTE: The erroneous command is in the preamble)")); - LYXERR(Debug::LATEX, "line: " << line << '\n' - << "Desc: " << desc << '\n' << "Text: " << errstr); + LYXERR(Debug::OUTFILE, "line: " << line << '\n' + << "Desc: " << desc << '\n' << "Text: " << errstr); if (line == last_line) ++line_count; else { @@ -1186,7 +1182,7 @@ int LaTeX::scanLogFile(TeXErrors & terr) } } } - LYXERR(Debug::LATEX, "Log line: " << token); + LYXERR(Debug::OUTFILE, "Log line: " << token); return retval; } @@ -1564,7 +1560,7 @@ void LaTeX::deplog(DepTable & head) int LaTeX::scanBlgFile(DepTable & dep, TeXErrors & terr) { FileName const blg_file(changeExtension(file.absFileName(), "blg")); - LYXERR(Debug::LATEX, "Scanning blg file: " << blg_file); + LYXERR(Debug::OUTFILE, "Scanning blg file: " << blg_file); ifstream ifs(blg_file.toFilesystemEncoding().c_str()); string token; @@ -1587,7 +1583,7 @@ int LaTeX::scanBlgFile(DepTable & dep, TeXErrors & terr) if (regex_match(token, sub, reg1)) { string data = sub.str(3); if (!data.empty()) { - LYXERR(Debug::LATEX, "Found bib file: " << data); + LYXERR(Debug::OUTFILE, "Found bib file: " << data); handleFoundFile(data, dep); } } @@ -1619,10 +1615,9 @@ int LaTeX::scanBlgFile(DepTable & dep, TeXErrors & terr) } else if (regex_match(token, sub, biberError)) { retval |= BIBTEX_ERROR; string errstr = N_("Biber error: ") + sub.str(2); - string msg = token; terr.insertError(0, from_local8bit(errstr), - from_local8bit(msg)); + from_local8bit(token)); } prevtoken = token; } @@ -1633,7 +1628,7 @@ int LaTeX::scanBlgFile(DepTable & dep, TeXErrors & terr) int LaTeX::scanIlgFile(TeXErrors & terr) { FileName const ilg_file(changeExtension(file.absFileName(), "ilg")); - LYXERR(Debug::LATEX, "Scanning ilg file: " << ilg_file); + LYXERR(Debug::OUTFILE, "Scanning ilg file: " << ilg_file); ifstream ifs(ilg_file.toFilesystemEncoding().c_str()); string token; @@ -1642,7 +1637,6 @@ int LaTeX::scanIlgFile(TeXErrors & terr) string prevtoken; while (getline(ifs, token)) { token = rtrim(token, "\r"); - smatch sub; if (prefixIs(token, "!! ")) prevtoken = token; else if (!prevtoken.empty()) { @@ -1657,10 +1651,9 @@ int LaTeX::scanIlgFile(TeXErrors & terr) } else if (prefixIs(token, "ERROR: ")) { retval |= BIBTEX_ERROR; string errstr = N_("Xindy error: ") + token.substr(6); - string msg = token; terr.insertError(0, from_local8bit(errstr), - from_local8bit(msg)); + from_local8bit(token)); } } return retval;