#include "BufferList.h"
#include "LaTeX.h"
#include "LyXRC.h"
+#include "LyX.h"
#include "DepTable.h"
#include "support/debug.h"
return bformat(_("Waiting for LaTeX run number %1$d"), count);
}
-} // anon namespace
+} // namespace
/*
* CLASS TEXERRORS
*/
LaTeX::LaTeX(string const & latex, OutputParams const & rp,
- FileName const & f, string const & p)
- : cmd(latex), file(f), path(p), runparams(rp), biber(false)
+ FileName const & f, string const & p, string const & lp,
+ bool const clean_start)
+ : cmd(latex), file(f), path(p), lpath(lp), runparams(rp), biber(false)
{
num_errors = 0;
- if (prefixIs(cmd, "pdf")) { // Do we use pdflatex ?
+ // lualatex can still produce a DVI with --output-format=dvi. However,
+ // we do not use that internally (we use the "dvilualatex" command) so
+ // it would only happen from a custom converter. Thus, it is better to
+ // guess that lualatex produces a PDF than to guess a DVI.
+ // FIXME we should base the extension on the output format, which we should
+ // get in a robust way, e.g. from the converter.
+ if (prefixIs(cmd, "pdf") || prefixIs(cmd, "lualatex") || prefixIs(cmd, "xelatex")) {
depfile = FileName(file.absFileName() + ".dep-pdf");
output_file =
FileName(changeExtension(file.absFileName(), ".pdf"));
output_file =
FileName(changeExtension(file.absFileName(), ".dvi"));
}
+ if (clean_start)
+ removeAuxiliaryFiles();
}
FileName const aux(changeExtension(file.absFileName(), ".aux"));
aux.removeFile();
+ // Also remove the .out file (e.g. hyperref bookmarks) (#9963)
+ FileName const out(changeExtension(file.absFileName(), ".out"));
+ out.removeFile();
+
// Remove the output file, which is often generated even if error
output_file.removeFile();
}
theBufferList().updateIncludedTeXfiles(FileName::getcwd().absFileName(),
runparams);
- // Never write the depfile if an error was encountered.
-
// 0
// first check if the file dependencies exist:
// ->If it does exist
/// in which case we will not need to run bibtex again.
vector<AuxInfo> bibtex_info_old;
if (!run_bibtex)
- bibtex_info_old = scanAuxFiles(aux_file);
+ bibtex_info_old = scanAuxFiles(aux_file, runparams.only_childbibs);
++count;
LYXERR(Debug::LATEX, "Run #" << count);
message(runMessage(count));
- int const exit_code = startscript();
+ int exit_code = startscript();
scanres = scanLogFile(terr);
if (scanres & ERROR_RERUN) {
LYXERR(Debug::LATEX, "Rerunning LaTeX");
- startscript();
+ terr.clearErrors();
+ exit_code = startscript();
scanres = scanLogFile(terr);
}
- vector<AuxInfo> const bibtex_info = scanAuxFiles(aux_file);
+ vector<AuxInfo> const bibtex_info = scanAuxFiles(aux_file, runparams.only_childbibs);
if (!run_bibtex && bibtex_info_old != bibtex_info)
run_bibtex = true;
} else {
LYXERR(Debug::DEPEND, "Dep. file has NOT changed");
}
-
+
// 3
// rerun bibtex?
// Complex bibliography packages such as Biblatex require
// Write the dependencies to file.
head.write(depfile);
- if (scanres & NO_OUTPUT) {
- // A previous run could have left a PDF and since
- // no PDF is created if NO_OUTPUT, we remove any
- // existing PDF and temporary files so that an
- // incorrect PDF is not displayed, which could otherwise
- // happen if View is run again because the checksum will
- // be the same so any lingering PDF will be viewed.
- removeAuxiliaryFiles();
- }
-
- if (exit_code)
+ if (exit_code) {
+ // add flag here, just before return, instead of when exit_code
+ // is defined because scanres is sometimes overwritten above
+ // (e.g. rerun)
scanres |= NONZERO_ERROR;
+ }
LYXERR(Debug::LATEX, "Done.");
+ quoteName(onlyFileName(file.toFilesystemEncoding()))
+ " > " + os::nulldev();
Systemcall one;
- return one.startscript(Systemcall::Wait, tmp, path);
+ return one.startscript(Systemcall::Wait, tmp, path, lpath);
}
{
string tmp = runparams.use_japanese ?
lyxrc.jindex_command : lyxrc.index_command;
-
+
if (!runparams.index_command.empty())
tmp = runparams.index_command;
tmp += quoteName(f);
tmp += params;
Systemcall one;
- one.startscript(Systemcall::Wait, tmp, path);
+ one.startscript(Systemcall::Wait, tmp, path, lpath);
return true;
}
tmp += " -o "
+ onlyFileName(changeExtension(file.toFilesystemEncoding(), nls));
Systemcall one;
- one.startscript(Systemcall::Wait, tmp, path);
+ one.startscript(Systemcall::Wait, tmp, path, lpath);
return true;
}
vector<AuxInfo> const
-LaTeX::scanAuxFiles(FileName const & file)
+LaTeX::scanAuxFiles(FileName const & file, bool const only_childbibs)
{
vector<AuxInfo> result;
+ // With chapterbib, we have to bibtex all children's aux files
+ // but _not_ the master's!
+ if (only_childbibs) {
+ for (string const &s: children) {
+ FileName fn =
+ makeAbsPath(s, file.onlyPath().realPath());
+ fn.changeExtension("aux");
+ if (fn.exists())
+ result.push_back(scanAuxFile(fn));
+ }
+ return result;
+ }
+
result.push_back(scanAuxFile(file));
+ // This is for bibtopic
string const basename = removeExtension(file.absFileName());
for (int i = 1; i < 1000; ++i) {
FileName const file2(basename
continue;
result = true;
- string tmp = runparams.use_japanese ?
- lyxrc.jbibtex_command : lyxrc.bibtex_command;
-
- if (!runparams.bibtex_command.empty())
- tmp = runparams.bibtex_command;
+ string 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, path);
+ one.startscript(Systemcall::Wait, tmp, path, lpath);
}
// Return whether bibtex was run
return result;
onlyFileName(changeExtension(file.absFileName(), ".log"));
LYXERR(Debug::LATEX, "Log file: " << tmp);
FileName const fn = FileName(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.
ifstream ifs(fn.toFilesystemEncoding().c_str());
bool fle_style = false;
static regex const file_line_error(".+\\.\\D+:[0-9]+: (.+)");
string child_name;
int pnest = 0;
stack <pair<string, int> > child;
+ children.clear();
string token;
while (getline(ifs, token)) {
if (regex_match(substr, sub, child_file)) {
string const name = sub.str(1);
child.push(make_pair(name, pnest));
+ children.push_back(name);
i += len;
}
} else if (token[i] == ')') {
if (contains(token, "LaTeX Error:"))
retval |= LATEX_ERROR;
- if (prefixIs(token, "! File ended while scanning")){
+ if (prefixIs(token, "! File ended while scanning")) {
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;
}
}
+ if (prefixIs(token, "! Incomplete \\if")) {
+ // bug 10666. 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;
string errstr;
int count = 0;
errstr = wait_for_error;
+ wait_for_error.clear();
do {
if (!getline(ifs, tmp))
break;
} while (!contains(tmp, "(job aborted"));
terr.insertError(0,
- from_local8bit("Emergency stop"),
+ from_ascii("Emergency stop"),
from_local8bit(errstr),
child_name);
}
} else if (contains(token, "Rerun to get citations")) {
// Natbib seems to use this.
retval |= UNDEF_CIT;
- } else if (contains(token, "No pages of output")) {
- // A dvi file was not created
+ } else if (contains(token, "No pages of output")
+ || contains(token, "no pages of output")) {
+ // No output file (e.g. the DVI or PDF) was created
retval |= NO_OUTPUT;
+ } else if (contains(token, "Error 256 (driver return code)")) {
+ // This is a xdvipdfmx driver error reported by XeTeX.
+ // We have to check whether an output PDF file was created.
+ FileName pdffile = file;
+ pdffile.changeExtension("pdf");
+ if (!pdffile.exists())
+ // No output PDF file was created (see #10076)
+ retval |= NO_OUTPUT;
} else if (contains(token, "That makes 100 errors")) {
- // More than 100 errors were reprted
+ // More than 100 errors were reported
retval |= TOO_MANY_ERRORS;
- } else if (prefixIs(token, "!pdfTeX error:")){
+ } 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_ascii("pdfTeX Error"),
+ from_local8bit(token),
+ child_name);
+ } else if (!ignore_missing_glyphs
+ && prefixIs(token, "Missing character: There is no ")
+ && !contains(token, "nullfont")) {
+ // Warning about missing glyph in selected font
+ // may be dataloss (bug 9610)
+ // but can be ignored for 'nullfont' (bug 10394).
+ // as well as for ZERO WIDTH NON-JOINER (0x200C) which is
+ // missing in many fonts and output for ligature break (bug 10727).
+ // Since this error only occurs with utf8 output, we can safely assume
+ // that the log file is utf8-encoded
+ docstring const utoken = from_utf8(token);
+ if (!contains(utoken, 0x200C)) {
+ retval |= LATEX_ERROR;
terr.insertError(0,
- from_local8bit("pdfTeX Error"),
- from_local8bit(token),
+ from_ascii("Missing glyphs!"),
+ utoken,
child_name);
+ }
+ } else if (!wait_for_error.empty()) {
+ // We collect information until we know we have an error.
+ wait_for_error += token + '\n';
}
}
}
return true;
// strip off part after last space and try again
string tmp = strippedfile;
- string const stripoff =
- rsplit(tmp, strippedfile, ' ');
+ rsplit(tmp, strippedfile, ' ');
absname.set(strippedfile);
if (insertIfExists(absname, head))
return true;
break;
// strip off part after last space and try again
string strippedfile;
- string const stripoff =
- rsplit(foundfile, strippedfile, ' ');
+ rsplit(foundfile, strippedfile, ' ');
foundfile = strippedfile;
onlyfile = onlyFileName(strippedfile);
absname = makeAbsPath(onlyfile);
return result;
}
-} // anon namespace
+} // namespace
void LaTeX::deplog(DepTable & head)