1 /**
2  * \file LaTeX.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alfredo Braunstein
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Angus Leeming
10  * \author Dekel Tsur
11  * \author Jürgen Spitzmüller
12  *
13  * Full author contact details are available in file CREDITS.
14  */
15 
16 #include <config.h>
17 
18 #include "BufferList.h"
19 #include "LaTeX.h"
20 #include "LyXRC.h"
21 #include "LyX.h"
22 #include "DepTable.h"
23 
24 #include "support/debug.h"
25 #include "support/convert.h"
26 #include "support/FileName.h"
27 #include "support/filetools.h"
28 #include "support/gettext.h"
29 #include "support/lstrings.h"
30 #include "support/Systemcall.h"
31 #include "support/os.h"
32 
33 #include "support/regex.h"
34 
35 #include <fstream>
36 #include <stack>
37 
38 
39 using namespace std;
40 using namespace lyx::support;
41 
42 namespace lyx {
43 
44 namespace os = support::os;
45 
46 // TODO: in no particular order
47 // - get rid of the call to
48 //   BufferList::updateIncludedTeXfiles, this should either
49 //   be done before calling LaTeX::funcs or in a completely
50 //   different way.
51 // - the makeindex style files should be taken care of with
52 //   the dependency mechanism.
53 
54 namespace {
55 
runMessage(unsigned int count)56 docstring runMessage(unsigned int count)
57 {
58 	return bformat(_("Waiting for LaTeX run number %1$d"), count);
59 }
60 
61 } // namespace
62 
63 /*
64  * CLASS TEXERRORS
65  */
66 
insertError(int line,docstring const & error_desc,docstring const & error_text,string const & child_name)67 void TeXErrors::insertError(int line, docstring const & error_desc,
68 			    docstring const & error_text,
69 			    string const & child_name)
70 {
71 	Error newerr(line, error_desc, error_text, child_name);
72 	errors.push_back(newerr);
73 }
74 
75 
operator ==(AuxInfo const & a,AuxInfo const & o)76 bool operator==(AuxInfo const & a, AuxInfo const & o)
77 {
78 	return a.aux_file == o.aux_file
79 		&& a.citations == o.citations
80 		&& a.databases == o.databases
81 		&& a.styles == o.styles;
82 }
83 
84 
operator !=(AuxInfo const & a,AuxInfo const & o)85 bool operator!=(AuxInfo const & a, AuxInfo const & o)
86 {
87 	return !(a == o);
88 }
89 
90 
91 /*
92  * CLASS LaTeX
93  */
94 
LaTeX(string const & latex,OutputParams const & rp,FileName const & f,string const & p,string const & lp,bool const clean_start)95 LaTeX::LaTeX(string const & latex, OutputParams const & rp,
96 	     FileName const & f, string const & p, string const & lp,
97 	     bool const clean_start)
98 	: cmd(latex), file(f), path(p), lpath(lp), runparams(rp), biber(false)
99 {
100 	num_errors = 0;
101 	// lualatex can still produce a DVI with --output-format=dvi. However,
102 	// we do not use that internally (we use the "dvilualatex" command) so
103 	// it would only happen from a custom converter. Thus, it is better to
104 	// guess that lualatex produces a PDF than to guess a DVI.
105 	// FIXME we should base the extension on the output format, which we should
106 	// get in a robust way, e.g. from the converter.
107 	if (prefixIs(cmd, "pdf") || prefixIs(cmd, "lualatex") || prefixIs(cmd, "xelatex")) {
108 		depfile = FileName(file.absFileName() + ".dep-pdf");
109 		output_file =
110 			FileName(changeExtension(file.absFileName(), ".pdf"));
111 	} else {
112 		depfile = FileName(file.absFileName() + ".dep");
113 		output_file =
114 			FileName(changeExtension(file.absFileName(), ".dvi"));
115 	}
116 	if (clean_start)
117 		removeAuxiliaryFiles();
118 }
119 
120 
removeAuxiliaryFiles() const121 void LaTeX::removeAuxiliaryFiles() const
122 {
123 	// Note that we do not always call this function when there is an error.
124 	// For example, if there is an error but an output file is produced we
125 	// still would like to output (export/view) the file.
126 
127 	// What files do we have to delete?
128 
129 	// This will at least make latex do all the runs
130 	depfile.removeFile();
131 
132 	// but the reason for the error might be in a generated file...
133 
134 	// bibtex file
135 	FileName const bbl(changeExtension(file.absFileName(), ".bbl"));
136 	bbl.removeFile();
137 
138 	// biber file
139 	FileName const bcf(changeExtension(file.absFileName(), ".bcf"));
140 	bcf.removeFile();
141 
142 	// makeindex file
143 	FileName const ind(changeExtension(file.absFileName(), ".ind"));
144 	ind.removeFile();
145 
146 	// nomencl file
147 	FileName const nls(changeExtension(file.absFileName(), ".nls"));
148 	nls.removeFile();
149 
150 	// nomencl file (old version of the package)
151 	FileName const gls(changeExtension(file.absFileName(), ".gls"));
152 	gls.removeFile();
153 
154 	// Also remove the aux file
155 	FileName const aux(changeExtension(file.absFileName(), ".aux"));
156 	aux.removeFile();
157 
158 	// Also remove the .out file (e.g. hyperref bookmarks) (#9963)
159 	FileName const out(changeExtension(file.absFileName(), ".out"));
160 	out.removeFile();
161 
162 	// Remove the output file, which is often generated even if error
163 	output_file.removeFile();
164 }
165 
166 
run(TeXErrors & terr)167 int LaTeX::run(TeXErrors & terr)
168 	// We know that this function will only be run if the lyx buffer
169 	// has been changed. We also know that a newly written .tex file
170 	// is always different from the previous one because of the date
171 	// in it. However it seems safe to run latex (at least) one time
172 	// each time the .tex file changes.
173 {
174 	int scanres = NO_ERRORS;
175 	int bscanres = NO_ERRORS;
176 	unsigned int count = 0; // number of times run
177 	num_errors = 0; // just to make sure.
178 	unsigned int const MAX_RUN = 6;
179 	DepTable head; // empty head
180 	bool rerun = false; // rerun requested
181 
182 	// The class LaTeX does not know the temp path.
183 	theBufferList().updateIncludedTeXfiles(FileName::getcwd().absFileName(),
184 		runparams);
185 
186 	// 0
187 	// first check if the file dependencies exist:
188 	//     ->If it does exist
189 	//             check if any of the files mentioned in it have
190 	//             changed (done using a checksum).
191 	//                 -> if changed:
192 	//                        run latex once and
193 	//                        remake the dependency file
194 	//                 -> if not changed:
195 	//                        just return there is nothing to do for us.
196 	//     ->if it doesn't exist
197 	//             make it and
198 	//             run latex once (we need to run latex once anyway) and
199 	//             remake the dependency file.
200 	//
201 
202 	bool had_depfile = depfile.exists();
203 	bool run_bibtex = false;
204 	FileName const aux_file(changeExtension(file.absFileName(), ".aux"));
205 
206 	if (had_depfile) {
207 		LYXERR(Debug::DEPEND, "Dependency file exists");
208 		// Read the dep file:
209 		had_depfile = head.read(depfile);
210 	}
211 
212 	if (had_depfile) {
213 		// Update the checksums
214 		head.update();
215 		// Can't just check if anything has changed because it might
216 		// have aborted on error last time... in which cas we need
217 		// to re-run latex and collect the error messages
218 		// (even if they are the same).
219 		if (!output_file.exists()) {
220 			LYXERR(Debug::DEPEND,
221 				"re-running LaTeX because output file doesn't exist.");
222 		} else if (!head.sumchange()) {
223 			LYXERR(Debug::DEPEND, "return no_change");
224 			return NO_CHANGE;
225 		} else {
226 			LYXERR(Debug::DEPEND, "Dependency file has changed");
227 		}
228 
229 		if (head.extchanged(".bib") || head.extchanged(".bst"))
230 			run_bibtex = true;
231 	} else
232 		LYXERR(Debug::DEPEND,
233 			"Dependency file does not exist, or has wrong format");
234 
235 	/// We scan the aux file even when had_depfile = false,
236 	/// because we can run pdflatex on the file after running latex on it,
237 	/// in which case we will not need to run bibtex again.
238 	vector<AuxInfo> bibtex_info_old;
239 	if (!run_bibtex)
240 		bibtex_info_old = scanAuxFiles(aux_file, runparams.only_childbibs);
241 
242 	++count;
243 	LYXERR(Debug::LATEX, "Run #" << count);
244 	message(runMessage(count));
245 
246 	int exit_code = startscript();
247 
248 	scanres = scanLogFile(terr);
249 	if (scanres & ERROR_RERUN) {
250 		LYXERR(Debug::LATEX, "Rerunning LaTeX");
251 		terr.clearErrors();
252 		exit_code = startscript();
253 		scanres = scanLogFile(terr);
254 	}
255 
256 	vector<AuxInfo> const bibtex_info = scanAuxFiles(aux_file, runparams.only_childbibs);
257 	if (!run_bibtex && bibtex_info_old != bibtex_info)
258 		run_bibtex = true;
259 
260 	// update the dependencies.
261 	deplog(head); // reads the latex log
262 	head.update();
263 
264 	// 1
265 	// At this point we must run external programs if needed.
266 	// makeindex will be run if a .idx file changed or was generated.
267 	// And if there were undefined citations or changes in references
268 	// the .aux file is checked for signs of bibtex. Bibtex is then run
269 	// if needed.
270 
271 	// memoir (at least) writes an empty *idx file in the first place.
272 	// A second latex run is needed.
273 	FileName const idxfile(changeExtension(file.absFileName(), ".idx"));
274 	rerun = idxfile.exists() && idxfile.isFileEmpty();
275 
276 	// run makeindex
277 	if (head.haschanged(idxfile)) {
278 		// no checks for now
279 		LYXERR(Debug::LATEX, "Running MakeIndex.");
280 		message(_("Running Index Processor."));
281 		// onlyFileName() is needed for cygwin
282 		rerun |= runMakeIndex(onlyFileName(idxfile.absFileName()),
283 				runparams);
284 	}
285 	FileName const nlofile(changeExtension(file.absFileName(), ".nlo"));
286 	// If all nomencl entries are removed, nomencl writes an empty nlo file.
287 	// DepTable::hasChanged() returns false in this case, since it does not
288 	// distinguish empty files from non-existing files. This is why we need
289 	// the extra checks here (to trigger a rerun). Cf. discussions in #8905.
290 	// FIXME: Sort out the real problem in DepTable.
291 	if (head.haschanged(nlofile) || (nlofile.exists() && nlofile.isFileEmpty()))
292 		rerun |= runMakeIndexNomencl(file, ".nlo", ".nls");
293 	FileName const glofile(changeExtension(file.absFileName(), ".glo"));
294 	if (head.haschanged(glofile))
295 		rerun |= runMakeIndexNomencl(file, ".glo", ".gls");
296 
297 	// check if we're using biber instead of bibtex
298 	// biber writes no info to the aux file, so we just check
299 	// if a bcf file exists (and if it was updated)
300 	FileName const bcffile(changeExtension(file.absFileName(), ".bcf"));
301 	biber |= head.exist(bcffile);
302 
303 	// run bibtex
304 	// if (scanres & UNDEF_CIT || scanres & RERUN || run_bibtex)
305 	if (scanres & UNDEF_CIT || run_bibtex) {
306 		// Here we must scan the .aux file and look for
307 		// "\bibdata" and/or "\bibstyle". If one of those
308 		// tags is found -> run bibtex and set rerun = true;
309 		// no checks for now
310 		LYXERR(Debug::LATEX, "Running BibTeX.");
311 		message(_("Running BibTeX."));
312 		updateBibtexDependencies(head, bibtex_info);
313 		rerun |= runBibTeX(bibtex_info, runparams);
314 		FileName const blgfile(changeExtension(file.absFileName(), ".blg"));
315 		if (blgfile.exists())
316 			bscanres = scanBlgFile(head, terr);
317 	} else if (!had_depfile) {
318 		/// If we run pdflatex on the file after running latex on it,
319 		/// then we do not need to run bibtex, but we do need to
320 		/// insert the .bib and .bst files into the .dep-pdf file.
321 		updateBibtexDependencies(head, bibtex_info);
322 	}
323 
324 	// 2
325 	// we know on this point that latex has been run once (or we just
326 	// returned) and the question now is to decide if we need to run
327 	// it any more. This is done by asking if any of the files in the
328 	// dependency file has changed. (remember that the checksum for
329 	// a given file is reported to have changed if it just was created)
330 	//     -> if changed or rerun == true:
331 	//             run latex once more and
332 	//             update the dependency structure
333 	//     -> if not changed:
334 	//             we do nothing at this point
335 	//
336 	if (rerun || head.sumchange()) {
337 		rerun = false;
338 		++count;
339 		LYXERR(Debug::DEPEND, "Dep. file has changed or rerun requested");
340 		LYXERR(Debug::LATEX, "Run #" << count);
341 		message(runMessage(count));
342 		startscript();
343 		scanres = scanLogFile(terr);
344 
345 		// update the depedencies
346 		deplog(head); // reads the latex log
347 		head.update();
348 	} else {
349 		LYXERR(Debug::DEPEND, "Dep. file has NOT changed");
350 	}
351 
352 	// 3
353 	// rerun bibtex?
354 	// Complex bibliography packages such as Biblatex require
355 	// an additional bibtex cycle sometimes.
356 	if (scanres & UNDEF_CIT) {
357 		// Here we must scan the .aux file and look for
358 		// "\bibdata" and/or "\bibstyle". If one of those
359 		// tags is found -> run bibtex and set rerun = true;
360 		// no checks for now
361 		LYXERR(Debug::LATEX, "Running BibTeX.");
362 		message(_("Running BibTeX."));
363 		updateBibtexDependencies(head, bibtex_info);
364 		rerun |= runBibTeX(bibtex_info, runparams);
365 		FileName const blgfile(changeExtension(file.absFileName(), ".blg"));
366 		if (blgfile.exists())
367 			bscanres = scanBlgFile(head, terr);
368 	}
369 
370 	// 4
371 	// The inclusion of files generated by external programs such as
372 	// makeindex or bibtex might have done changes to pagenumbering,
373 	// etc. And because of this we must run the external programs
374 	// again to make sure everything is redone correctly.
375 	// Also there should be no need to run the external programs any
376 	// more after this.
377 
378 	// run makeindex if the <file>.idx has changed or was generated.
379 	if (head.haschanged(idxfile)) {
380 		// no checks for now
381 		LYXERR(Debug::LATEX, "Running MakeIndex.");
382 		message(_("Running Index Processor."));
383 		// onlyFileName() is needed for cygwin
384 		rerun = runMakeIndex(onlyFileName(changeExtension(
385 				file.absFileName(), ".idx")), runparams);
386 	}
387 
388 	// I am not pretty sure if need this twice.
389 	if (head.haschanged(nlofile))
390 		rerun |= runMakeIndexNomencl(file, ".nlo", ".nls");
391 	if (head.haschanged(glofile))
392 		rerun |= runMakeIndexNomencl(file, ".glo", ".gls");
393 
394 	// 5
395 	// we will only run latex more if the log file asks for it.
396 	// or if the sumchange() is true.
397 	//     -> rerun asked for:
398 	//             run latex and
399 	//             remake the dependency file
400 	//             goto 2 or return if max runs are reached.
401 	//     -> rerun not asked for:
402 	//             just return (fall out of bottom of func)
403 	//
404 	while ((head.sumchange() || rerun || (scanres & RERUN))
405 	       && count < MAX_RUN) {
406 		// Yes rerun until message goes away, or until
407 		// MAX_RUNS are reached.
408 		rerun = false;
409 		++count;
410 		LYXERR(Debug::LATEX, "Run #" << count);
411 		message(runMessage(count));
412 		startscript();
413 		scanres = scanLogFile(terr);
414 
415 		// keep this updated
416 		head.update();
417 	}
418 
419 	// Write the dependencies to file.
420 	head.write(depfile);
421 
422 	if (exit_code) {
423 		// add flag here, just before return, instead of when exit_code
424 		// is defined because scanres is sometimes overwritten above
425 		// (e.g. rerun)
426 		scanres |= NONZERO_ERROR;
427 	}
428 
429 	LYXERR(Debug::LATEX, "Done.");
430 
431 	if (bscanres & ERRORS)
432 		return bscanres; // return on error
433 
434 	return scanres;
435 }
436 
437 
startscript()438 int LaTeX::startscript()
439 {
440 	// onlyFileName() is needed for cygwin
441 	string tmp = cmd + ' '
442 		     + quoteName(onlyFileName(file.toFilesystemEncoding()))
443 		     + " > " + os::nulldev();
444 	Systemcall one;
445 	return one.startscript(Systemcall::Wait, tmp, path, lpath);
446 }
447 
448 
runMakeIndex(string const & f,OutputParams const & runparams,string const & params)449 bool LaTeX::runMakeIndex(string const & f, OutputParams const & runparams,
450 			 string const & params)
451 {
452 	string tmp = runparams.use_japanese ?
453 		lyxrc.jindex_command : lyxrc.index_command;
454 
455 	if (!runparams.index_command.empty())
456 		tmp = runparams.index_command;
457 
458 	LYXERR(Debug::LATEX,
459 		"idx file has been made, running index processor ("
460 		<< tmp << ") on file " << f);
461 
462 	tmp = subst(tmp, "$$lang", runparams.document_language);
463 	if (runparams.use_indices) {
464 		tmp = lyxrc.splitindex_command + " -m " + quoteName(tmp);
465 		LYXERR(Debug::LATEX,
466 		"Multiple indices. Using splitindex command: " << tmp);
467 	}
468 	tmp += ' ';
469 	tmp += quoteName(f);
470 	tmp += params;
471 	Systemcall one;
472 	one.startscript(Systemcall::Wait, tmp, path, lpath);
473 	return true;
474 }
475 
476 
runMakeIndexNomencl(FileName const & file,string const & nlo,string const & nls)477 bool LaTeX::runMakeIndexNomencl(FileName const & file,
478 		string const & nlo, string const & nls)
479 {
480 	LYXERR(Debug::LATEX, "Running MakeIndex for nomencl.");
481 	message(_("Running MakeIndex for nomencl."));
482 	string tmp = lyxrc.nomencl_command + ' ';
483 	// onlyFileName() is needed for cygwin
484 	tmp += quoteName(onlyFileName(changeExtension(file.absFileName(), nlo)));
485 	tmp += " -o "
486 		+ onlyFileName(changeExtension(file.toFilesystemEncoding(), nls));
487 	Systemcall one;
488 	one.startscript(Systemcall::Wait, tmp, path, lpath);
489 	return true;
490 }
491 
492 
493 vector<AuxInfo> const
scanAuxFiles(FileName const & file,bool const only_childbibs)494 LaTeX::scanAuxFiles(FileName const & file, bool const only_childbibs)
495 {
496 	vector<AuxInfo> result;
497 
498 	// With chapterbib, we have to bibtex all children's aux files
499 	// but _not_ the master's!
500 	if (only_childbibs) {
501 		for (string const &s: children) {
502 			FileName fn =
503 				makeAbsPath(s, file.onlyPath().realPath());
504 			fn.changeExtension("aux");
505 			if (fn.exists())
506 				result.push_back(scanAuxFile(fn));
507 		}
508 		return result;
509 	}
510 
511 	result.push_back(scanAuxFile(file));
512 
513 	// This is for bibtopic
514 	string const basename = removeExtension(file.absFileName());
515 	for (int i = 1; i < 1000; ++i) {
516 		FileName const file2(basename
517 			+ '.' + convert<string>(i)
518 			+ ".aux");
519 		if (!file2.exists())
520 			break;
521 		result.push_back(scanAuxFile(file2));
522 	}
523 	return result;
524 }
525 
526 
scanAuxFile(FileName const & file)527 AuxInfo const LaTeX::scanAuxFile(FileName const & file)
528 {
529 	AuxInfo result;
530 	result.aux_file = file;
531 	scanAuxFile(file, result);
532 	return result;
533 }
534 
535 
scanAuxFile(FileName const & file,AuxInfo & aux_info)536 void LaTeX::scanAuxFile(FileName const & file, AuxInfo & aux_info)
537 {
538 	LYXERR(Debug::LATEX, "Scanning aux file: " << file);
539 
540 	ifstream ifs(file.toFilesystemEncoding().c_str());
541 	string token;
542 	static regex const reg1("\\\\citation\\{([^}]+)\\}");
543 	static regex const reg2("\\\\bibdata\\{([^}]+)\\}");
544 	static regex const reg3("\\\\bibstyle\\{([^}]+)\\}");
545 	static regex const reg4("\\\\@input\\{([^}]+)\\}");
546 
547 	while (getline(ifs, token)) {
548 		token = rtrim(token, "\r");
549 		smatch sub;
550 		// FIXME UNICODE: We assume that citation keys and filenames
551 		// in the aux file are in the file system encoding.
552 		token = to_utf8(from_filesystem8bit(token));
553 		if (regex_match(token, sub, reg1)) {
554 			string data = sub.str(1);
555 			while (!data.empty()) {
556 				string citation;
557 				data = split(data, citation, ',');
558 				LYXERR(Debug::LATEX, "Citation: " << citation);
559 				aux_info.citations.insert(citation);
560 			}
561 		} else if (regex_match(token, sub, reg2)) {
562 			string data = sub.str(1);
563 			// data is now all the bib files separated by ','
564 			// get them one by one and pass them to the helper
565 			while (!data.empty()) {
566 				string database;
567 				data = split(data, database, ',');
568 				database = changeExtension(database, "bib");
569 				LYXERR(Debug::LATEX, "BibTeX database: `" << database << '\'');
570 				aux_info.databases.insert(database);
571 			}
572 		} else if (regex_match(token, sub, reg3)) {
573 			string style = sub.str(1);
574 			// token is now the style file
575 			// pass it to the helper
576 			style = changeExtension(style, "bst");
577 			LYXERR(Debug::LATEX, "BibTeX style: `" << style << '\'');
578 			aux_info.styles.insert(style);
579 		} else if (regex_match(token, sub, reg4)) {
580 			string const file2 = sub.str(1);
581 			scanAuxFile(makeAbsPath(file2), aux_info);
582 		}
583 	}
584 }
585 
586 
updateBibtexDependencies(DepTable & dep,vector<AuxInfo> const & bibtex_info)587 void LaTeX::updateBibtexDependencies(DepTable & dep,
588 				     vector<AuxInfo> const & bibtex_info)
589 {
590 	// Since a run of Bibtex mandates more latex runs it is ok to
591 	// remove all ".bib" and ".bst" files.
592 	dep.remove_files_with_extension(".bib");
593 	dep.remove_files_with_extension(".bst");
594 	//string aux = OnlyFileName(ChangeExtension(file, ".aux"));
595 
596 	for (vector<AuxInfo>::const_iterator it = bibtex_info.begin();
597 	     it != bibtex_info.end(); ++it) {
598 		for (set<string>::const_iterator it2 = it->databases.begin();
599 		     it2 != it->databases.end(); ++it2) {
600 			FileName const file = findtexfile(*it2, "bib");
601 			if (!file.empty())
602 				dep.insert(file, true);
603 		}
604 
605 		for (set<string>::const_iterator it2 = it->styles.begin();
606 		     it2 != it->styles.end(); ++it2) {
607 			FileName const file = findtexfile(*it2, "bst");
608 			if (!file.empty())
609 				dep.insert(file, true);
610 		}
611 	}
612 
613 	// biber writes nothing into the aux file.
614 	// Instead, we have to scan the blg file
615 	if (biber) {
616 		TeXErrors terr;
617 		scanBlgFile(dep, terr);
618 	}
619 }
620 
621 
runBibTeX(vector<AuxInfo> const & bibtex_info,OutputParams const & runparams)622 bool LaTeX::runBibTeX(vector<AuxInfo> const & bibtex_info,
623 		      OutputParams const & runparams)
624 {
625 	bool result = false;
626 	for (vector<AuxInfo>::const_iterator it = bibtex_info.begin();
627 	     it != bibtex_info.end(); ++it) {
628 		if (!biber && it->databases.empty())
629 			continue;
630 		result = true;
631 
632 		string tmp = runparams.bibtex_command;
633 		tmp += " ";
634 		// onlyFileName() is needed for cygwin
635 		tmp += quoteName(onlyFileName(removeExtension(
636 				it->aux_file.absFileName())));
637 		Systemcall one;
638 		one.startscript(Systemcall::Wait, tmp, path, lpath);
639 	}
640 	// Return whether bibtex was run
641 	return result;
642 }
643 
644 
scanLogFile(TeXErrors & terr)645 int LaTeX::scanLogFile(TeXErrors & terr)
646 {
647 	int last_line = -1;
648 	int line_count = 1;
649 	int retval = NO_ERRORS;
650 	string tmp =
651 		onlyFileName(changeExtension(file.absFileName(), ".log"));
652 	LYXERR(Debug::LATEX, "Log file: " << tmp);
653 	FileName const fn = FileName(makeAbsPath(tmp));
654 	// FIXME we should use an ifdocstream here and a docstring for token
655 	// below. The encoding of the log file depends on the _output_ (font)
656 	// encoding of the TeX file (T1, TU etc.). See #10728.
657 	ifstream ifs(fn.toFilesystemEncoding().c_str());
658 	bool fle_style = false;
659 	static regex const file_line_error(".+\\.\\D+:[0-9]+: (.+)");
660 	static regex const child_file("[^0-9]*([0-9]+[A-Za-z]*_.+\\.tex).*");
661 	// Flag for 'File ended while scanning' message.
662 	// We need to wait for subsequent processing.
663 	string wait_for_error;
664 	string child_name;
665 	int pnest = 0;
666 	stack <pair<string, int> > child;
667 	children.clear();
668 
669 	string token;
670 	while (getline(ifs, token)) {
671 		// MikTeX sometimes inserts \0 in the log file. They can't be
672 		// removed directly with the existing string utility
673 		// functions, so convert them first to \r, and remove all
674 		// \r's afterwards, since we need to remove them anyway.
675 		token = subst(token, '\0', '\r');
676 		token = subst(token, "\r", "");
677 		smatch sub;
678 
679 		LYXERR(Debug::LATEX, "Log line: " << token);
680 
681 		if (token.empty())
682 			continue;
683 
684 		// Track child documents
685 		for (size_t i = 0; i < token.length(); ++i) {
686 			if (token[i] == '(') {
687 				++pnest;
688 				size_t j = token.find('(', i + 1);
689 				size_t len = j == string::npos
690 						? token.substr(i + 1).length()
691 						: j - i - 1;
692 				string const substr = token.substr(i + 1, len);
693 				if (regex_match(substr, sub, child_file)) {
694 					string const name = sub.str(1);
695 					// Sometimes also masters have a name that matches
696 					// (if their name starts with a number and _)
697 					if (name != file.onlyFileName()) {
698 						child.push(make_pair(name, pnest));
699 						children.push_back(name);
700 					}
701 					i += len;
702 				}
703 			} else if (token[i] == ')') {
704 				if (!child.empty()
705 				    && child.top().second == pnest)
706 					child.pop();
707 				--pnest;
708 			}
709 		}
710 		child_name = child.empty() ? empty_string() : child.top().first;
711 
712 		if (contains(token, "file:line:error style messages enabled"))
713 			fle_style = true;
714 
715 		if (prefixIs(token, "LaTeX Warning:") ||
716 		    prefixIs(token, "! pdfTeX warning")) {
717 			// Here shall we handle different
718 			// types of warnings
719 			retval |= LATEX_WARNING;
720 			LYXERR(Debug::LATEX, "LaTeX Warning.");
721 			if (contains(token, "Rerun to get cross-references")) {
722 				retval |= RERUN;
723 				LYXERR(Debug::LATEX, "We should rerun.");
724 			// package clefval needs 2 latex runs before bibtex
725 			} else if (contains(token, "Value of")
726 				   && contains(token, "on page")
727 				   && contains(token, "undefined")) {
728 				retval |= ERROR_RERUN;
729 				LYXERR(Debug::LATEX, "Force rerun.");
730 			// package etaremune
731 			} else if (contains(token, "Etaremune labels have changed")) {
732 				retval |= ERROR_RERUN;
733 				LYXERR(Debug::LATEX, "Force rerun.");
734 			} else if (contains(token, "Citation")
735 				   && contains(token, "on page")
736 				   && contains(token, "undefined")) {
737 				retval |= UNDEF_CIT;
738 			} else if (contains(token, "Citation")
739 				   && contains(token, "on input line")
740 				   && contains(token, "undefined")) {
741 				retval |= UNDEF_CIT;
742 			}
743 		} else if (prefixIs(token, "Package")) {
744 			// Package warnings
745 			retval |= PACKAGE_WARNING;
746 			if (contains(token, "natbib Warning:")) {
747 				// Natbib warnings
748 				if (contains(token, "Citation")
749 				    && contains(token, "on page")
750 				    && contains(token, "undefined")) {
751 					retval |= UNDEF_CIT;
752 				}
753 			} else if (contains(token, "run BibTeX")) {
754 				retval |= UNDEF_CIT;
755 			} else if (contains(token, "run Biber")) {
756 				retval |= UNDEF_CIT;
757 				biber = true;
758 			} else if (contains(token, "Rerun LaTeX") ||
759 				   contains(token, "Please rerun LaTeX") ||
760 				   contains(token, "Rerun to get")) {
761 				// at least longtable.sty and bibtopic.sty
762 				// might use this.
763 				LYXERR(Debug::LATEX, "We should rerun.");
764 				retval |= RERUN;
765 			}
766 		} else if (prefixIs(token, "LETTRE WARNING:")) {
767 			if (contains(token, "veuillez recompiler")) {
768 				// lettre.cls
769 				LYXERR(Debug::LATEX, "We should rerun.");
770 				retval |= RERUN;
771 			}
772 		} else if (token[0] == '(') {
773 			if (contains(token, "Rerun LaTeX") ||
774 			    contains(token, "Rerun to get")) {
775 				// Used by natbib
776 				LYXERR(Debug::LATEX, "We should rerun.");
777 				retval |= RERUN;
778 			}
779 		} else if (prefixIs(token, "! ")
780 			    || (fle_style
781 				&& regex_match(token, sub, file_line_error)
782 				&& !contains(token, "pdfTeX warning"))) {
783 			   // Ok, we have something that looks like a TeX Error
784 			   // but what do we really have.
785 
786 			// Just get the error description:
787 			string desc;
788 			if (prefixIs(token, "! "))
789 				desc = string(token, 2);
790 			else if (fle_style)
791 				desc = sub.str();
792 			if (contains(token, "LaTeX Error:"))
793 				retval |= LATEX_ERROR;
794 
795 			if (prefixIs(token, "! File ended while scanning")) {
796 				if (prefixIs(token, "! File ended while scanning use of \\Hy@setref@link.")){
797 					// bug 7344. We must rerun LaTeX if hyperref has been toggled.
798 					retval |= ERROR_RERUN;
799 					LYXERR(Debug::LATEX, "Force rerun.");
800 				} else {
801 					// bug 6445. At this point its not clear we finish with error.
802 					wait_for_error = desc;
803 					continue;
804 				}
805 			}
806 
807 			if (prefixIs(token, "! Incomplete \\if")) {
808 				// bug 10666. At this point its not clear we finish with error.
809 				wait_for_error = desc;
810 				continue;
811 			}
812 
813 			if (prefixIs(token, "! Paragraph ended before \\Hy@setref@link was complete.")){
814 					// bug 7344. We must rerun LaTeX if hyperref has been toggled.
815 					retval |= ERROR_RERUN;
816 					LYXERR(Debug::LATEX, "Force rerun.");
817 			}
818 
819 			if (!wait_for_error.empty() && prefixIs(token, "! Emergency stop.")){
820 				retval |= LATEX_ERROR;
821 				string errstr;
822 				int count = 0;
823 				errstr = wait_for_error;
824 				wait_for_error.clear();
825 				do {
826 					if (!getline(ifs, tmp))
827 						break;
828 					tmp = rtrim(tmp, "\r");
829 					errstr += "\n" + tmp;
830 					if (++count > 5)
831 						break;
832 				} while (!contains(tmp, "(job aborted"));
833 
834 				terr.insertError(0,
835 						 from_ascii("Emergency stop"),
836 						 from_local8bit(errstr),
837 						 child_name);
838 			}
839 
840 			// get the next line
841 			string tmp;
842 			int count = 0;
843 			do {
844 				if (!getline(ifs, tmp))
845 					break;
846 				tmp = rtrim(tmp, "\r");
847 				// 15 is somewhat arbitrarily chosen, based on practice.
848 				// We used 10 for 14 years and increased it to 15 when we
849 				// saw one case.
850 				if (++count > 15)
851 					break;
852 			} while (!prefixIs(tmp, "l."));
853 			if (prefixIs(tmp, "l.")) {
854 				// we have a latex error
855 				retval |=  TEX_ERROR;
856 				if (contains(desc,
857 					"Package babel Error: You haven't defined the language")
858 				    || contains(desc,
859 					"Package babel Error: You haven't loaded the option")
860 				    || contains(desc,
861 					"Package babel Error: Unknown language"))
862 					retval |= ERROR_RERUN;
863 				// get the line number:
864 				int line = 0;
865 				sscanf(tmp.c_str(), "l.%d", &line);
866 				// get the rest of the message:
867 				string errstr(tmp, tmp.find(' '));
868 				errstr += '\n';
869 				getline(ifs, tmp);
870 				tmp = rtrim(tmp, "\r");
871 				while (!contains(errstr, "l.")
872 				       && !tmp.empty()
873 				       && !prefixIs(tmp, "! ")
874 				       && !contains(tmp, "(job aborted")) {
875 					errstr += tmp;
876 					errstr += "\n";
877 					getline(ifs, tmp);
878 					tmp = rtrim(tmp, "\r");
879 				}
880 				LYXERR(Debug::LATEX, "line: " << line << '\n'
881 					<< "Desc: " << desc << '\n' << "Text: " << errstr);
882 				if (line == last_line)
883 					++line_count;
884 				else {
885 					line_count = 1;
886 					last_line = line;
887 				}
888 				if (line_count <= 5) {
889 					// FIXME UNICODE
890 					// We have no idea what the encoding of
891 					// the log file is.
892 					// It seems that the output from the
893 					// latex compiler itself is pure ASCII,
894 					// but it can include bits from the
895 					// document, so whatever encoding we
896 					// assume here it can be wrong.
897 					terr.insertError(line,
898 							 from_local8bit(desc),
899 							 from_local8bit(errstr),
900 							 child_name);
901 					++num_errors;
902 				}
903 			}
904 		} else {
905 			// information messages, TeX warnings and other
906 			// warnings we have not caught earlier.
907 			if (prefixIs(token, "Overfull ")) {
908 				retval |= TEX_WARNING;
909 			} else if (prefixIs(token, "Underfull ")) {
910 				retval |= TEX_WARNING;
911 			} else if (contains(token, "Rerun to get citations")) {
912 				// Natbib seems to use this.
913 				retval |= UNDEF_CIT;
914 			} else if (contains(token, "No pages of output")
915 				|| contains(token, "no pages of output")) {
916 				// No output file (e.g. the DVI or PDF) was created
917 				retval |= NO_OUTPUT;
918 			} else if (contains(token, "Error 256 (driver return code)")) {
919 				// This is a xdvipdfmx driver error reported by XeTeX.
920 				// We have to check whether an output PDF file was created.
921 				FileName pdffile = file;
922 				pdffile.changeExtension("pdf");
923 				if (!pdffile.exists())
924 					// No output PDF file was created (see #10076)
925 					retval |= NO_OUTPUT;
926 			} else if (contains(token, "That makes 100 errors")) {
927 				// More than 100 errors were reported
928 				retval |= TOO_MANY_ERRORS;
929 			} else if (prefixIs(token, "!pdfTeX error:")) {
930 				// otherwise we dont catch e.g.:
931 				// !pdfTeX error: pdflatex (file feyn10): Font feyn10 at 600 not found
932 				retval |= ERRORS;
933 				terr.insertError(0,
934 						 from_ascii("pdfTeX Error"),
935 						 from_local8bit(token),
936 						 child_name);
937 			} else if (!ignore_missing_glyphs
938 				   && prefixIs(token, "Missing character: There is no ")
939 				   && !contains(token, "nullfont")) {
940 				// Warning about missing glyph in selected font
941 				// may be dataloss (bug 9610)
942 				// but can be ignored for 'nullfont' (bug 10394).
943 				// as well as for ZERO WIDTH NON-JOINER (0x200C) which is
944 				// missing in many fonts and output for ligature break (bug 10727).
945 				// Since this error only occurs with utf8 output, we can safely assume
946 				// that the log file is utf8-encoded
947 				docstring const utoken = from_utf8(token);
948 				if (!contains(utoken, 0x200C)) {
949 					retval |= LATEX_ERROR;
950 					terr.insertError(0,
951 							 from_ascii("Missing glyphs!"),
952 							 utoken,
953 							 child_name);
954 				}
955 			} else if (!wait_for_error.empty()) {
956 				// We collect information until we know we have an error.
957 				wait_for_error += token + '\n';
958 			}
959 		}
960 	}
961 	LYXERR(Debug::LATEX, "Log line: " << token);
962 	return retval;
963 }
964 
965 
966 namespace {
967 
insertIfExists(FileName const & absname,DepTable & head)968 bool insertIfExists(FileName const & absname, DepTable & head)
969 {
970 	if (absname.exists() && !absname.isDirectory()) {
971 		head.insert(absname, true);
972 		return true;
973 	}
974 	return false;
975 }
976 
977 
handleFoundFile(string const & ff,DepTable & head)978 bool handleFoundFile(string const & ff, DepTable & head)
979 {
980 	// convert from native os path to unix path
981 	string foundfile = os::internal_path(trim(ff));
982 
983 	LYXERR(Debug::DEPEND, "Found file: " << foundfile);
984 
985 	// Ok now we found a file.
986 	// Now we should make sure that this is a file that we can
987 	// access through the normal paths.
988 	// We will not try any fancy search methods to
989 	// find the file.
990 
991 	// (1) foundfile is an
992 	//     absolute path and should
993 	//     be inserted.
994 	FileName absname;
995 	if (FileName::isAbsolute(foundfile)) {
996 		LYXERR(Debug::DEPEND, "AbsolutePath file: " << foundfile);
997 		// On initial insert we want to do the update at once
998 		// since this file cannot be a file generated by
999 		// the latex run.
1000 		absname.set(foundfile);
1001 		if (!insertIfExists(absname, head)) {
1002 			// check for spaces
1003 			string strippedfile = foundfile;
1004 			while (contains(strippedfile, " ")) {
1005 				// files with spaces are often enclosed in quotation
1006 				// marks; those have to be removed
1007 				string unquoted = subst(strippedfile, "\"", "");
1008 				absname.set(unquoted);
1009 				if (insertIfExists(absname, head))
1010 					return true;
1011 				// strip off part after last space and try again
1012 				string tmp = strippedfile;
1013 				rsplit(tmp, strippedfile, ' ');
1014 				absname.set(strippedfile);
1015 				if (insertIfExists(absname, head))
1016 					return true;
1017 			}
1018 		}
1019 	}
1020 
1021 	string onlyfile = onlyFileName(foundfile);
1022 	absname = makeAbsPath(onlyfile);
1023 
1024 	// check for spaces
1025 	while (contains(foundfile, ' ')) {
1026 		if (absname.exists())
1027 			// everything o.k.
1028 			break;
1029 		else {
1030 			// files with spaces are often enclosed in quotation
1031 			// marks; those have to be removed
1032 			string unquoted = subst(foundfile, "\"", "");
1033 			absname = makeAbsPath(unquoted);
1034 			if (absname.exists())
1035 				break;
1036 			// strip off part after last space and try again
1037 			string strippedfile;
1038 			rsplit(foundfile, strippedfile, ' ');
1039 			foundfile = strippedfile;
1040 			onlyfile = onlyFileName(strippedfile);
1041 			absname = makeAbsPath(onlyfile);
1042 		}
1043 	}
1044 
1045 	// (2) foundfile is in the tmpdir
1046 	//     insert it into head
1047 	if (absname.exists() && !absname.isDirectory()) {
1048 		// FIXME: This regex contained glo, but glo is used by the old
1049 		// version of nomencl.sty. Do we need to put it back?
1050 		static regex const unwanted("^.*\\.(aux|log|dvi|bbl|ind)$");
1051 		if (regex_match(onlyfile, unwanted)) {
1052 			LYXERR(Debug::DEPEND, "We don't want " << onlyfile
1053 				<< " in the dep file");
1054 		} else if (suffixIs(onlyfile, ".tex")) {
1055 			// This is a tex file generated by LyX
1056 			// and latex is not likely to change this
1057 			// during its runs.
1058 			LYXERR(Debug::DEPEND, "Tmpdir TeX file: " << onlyfile);
1059 			head.insert(absname, true);
1060 		} else {
1061 			LYXERR(Debug::DEPEND, "In tmpdir file:" << onlyfile);
1062 			head.insert(absname);
1063 		}
1064 		return true;
1065 	} else {
1066 		LYXERR(Debug::DEPEND, "Not a file or we are unable to find it.");
1067 		return false;
1068 	}
1069 }
1070 
1071 
completeFilename(string const & ff,DepTable & head)1072 bool completeFilename(string const & ff, DepTable & head)
1073 {
1074 	// If we do not find a dot, we suspect
1075 	// a fragmental file name
1076 	if (!contains(ff, '.'))
1077 		return false;
1078 
1079 	// if we have a dot, we let handleFoundFile decide
1080 	return handleFoundFile(ff, head);
1081 }
1082 
1083 
iterateLine(string const & token,regex const & reg,string const & opening,string const & closing,int fragment_pos,DepTable & head)1084 int iterateLine(string const & token, regex const & reg, string const & opening,
1085 		string const & closing, int fragment_pos, DepTable & head)
1086 {
1087 	smatch what;
1088 	string::const_iterator first = token.begin();
1089 	string::const_iterator end = token.end();
1090 	bool fragment = false;
1091 	string last_match;
1092 
1093 	while (regex_search(first, end, what, reg)) {
1094 		// if we have a dot, try to handle as file
1095 		if (contains(what.str(1), '.')) {
1096 			first = what[0].second;
1097 			if (what.str(2) == closing) {
1098 				handleFoundFile(what.str(1), head);
1099 				// since we had a closing bracket,
1100 				// do not investigate further
1101 				fragment = false;
1102 			} else if (what.str(2) == opening) {
1103 				// if we have another opening bracket,
1104 				// we might have a nested file chain
1105 				// as is (file.ext (subfile.ext))
1106 				fragment = !handleFoundFile(rtrim(what.str(1)), head);
1107 				// decrease first position by one in order to
1108 				// consider the opening delimiter on next iteration
1109 				if (first > token.begin())
1110 					--first;
1111 			} else
1112 				// if we have no closing bracket,
1113 				// try to handle as file nevertheless
1114 				fragment = !handleFoundFile(
1115 					what.str(1) + what.str(2), head);
1116 		}
1117 		// if we do not have a dot, check if the line has
1118 		// a closing bracket (else, we suspect a line break)
1119 		else if (what.str(2) != closing) {
1120 			first = what[0].second;
1121 			fragment = true;
1122 		} else {
1123 			// we have a closing bracket, so the content
1124 			// is not a file name.
1125 			// no need to investigate further
1126 			first = what[0].second;
1127 			fragment = false;
1128 		}
1129 		last_match = what.str(1);
1130 	}
1131 
1132 	// We need to consider the result from previous line iterations:
1133 	// We might not find a fragment here, but another one might follow
1134 	// E.g.: (filename.ext) <filenam
1135 	// Vice versa, we consider the search completed if a real match
1136 	// follows a potential fragment from a previous iteration.
1137 	// E.g. <some text we considered a fragment (filename.ext)
1138 	// result = -1 means we did not find a fragment!
1139 	int result = -1;
1140 	int last_match_pos = -1;
1141 	if (!last_match.empty() && token.find(last_match) != string::npos)
1142 		last_match_pos = int(token.find(last_match));
1143 	if (fragment) {
1144 		if (last_match_pos > fragment_pos)
1145 			result = last_match_pos;
1146 		else
1147 			result = fragment_pos;
1148 	} else
1149 		if (last_match_pos < fragment_pos)
1150 			result = fragment_pos;
1151 
1152 	return result;
1153 }
1154 
1155 } // namespace
1156 
1157 
deplog(DepTable & head)1158 void LaTeX::deplog(DepTable & head)
1159 {
1160 	// This function reads the LaTeX log file end extracts all the
1161 	// external files used by the LaTeX run. The files are then
1162 	// entered into the dependency file.
1163 
1164 	string const logfile =
1165 		onlyFileName(changeExtension(file.absFileName(), ".log"));
1166 
1167 	static regex const reg1("File: (.+).*");
1168 	static regex const reg2("No file (.+)(.).*");
1169 	static regex const reg3a("\\\\openout[0-9]+.*=.*`(.+)(..).*");
1170 	// LuaTeX has a slightly different output
1171 	static regex const reg3b("\\\\openout[0-9]+.*=\\s*(.+)");
1172 	// If an index should be created, MikTex does not write a line like
1173 	//    \openout# = 'sample.idx'.
1174 	// but instead only a line like this into the log:
1175 	//   Writing index file sample.idx
1176 	static regex const reg4("Writing index file (.+).*");
1177 	static regex const regoldnomencl("Writing glossary file (.+).*");
1178 	static regex const regnomencl(".*Writing nomenclature file (.+).*");
1179 	// If a toc should be created, MikTex does not write a line like
1180 	//    \openout# = `sample.toc'.
1181 	// but only a line like this into the log:
1182 	//    \tf@toc=\write#
1183 	// This line is also written by tetex.
1184 	// This line is not present if no toc should be created.
1185 	static regex const miktexTocReg("\\\\tf@toc=\\\\write.*");
1186 	// file names can be enclosed in <...> (anywhere on the line)
1187 	static regex const reg5(".*<[^>]+.*");
1188 	// and also (...) anywhere on the line
1189 	static regex const reg6(".*\\([^)]+.*");
1190 
1191 	FileName const fn = makeAbsPath(logfile);
1192 	ifstream ifs(fn.toFilesystemEncoding().c_str());
1193 	string lastline;
1194 	while (ifs) {
1195 		// Ok, the scanning of files here is not sufficient.
1196 		// Sometimes files are named by "File: xxx" only
1197 		// Therefore we use some regexps to find files instead.
1198 		// Note: all file names and paths might contains spaces.
1199 		// Also, file names might be broken across lines. Therefore
1200 		// we mark (potential) fragments and merge those lines.
1201 		bool fragment = false;
1202 		string token;
1203 		getline(ifs, token);
1204 		// MikTeX sometimes inserts \0 in the log file. They can't be
1205 		// removed directly with the existing string utility
1206 		// functions, so convert them first to \r, and remove all
1207 		// \r's afterwards, since we need to remove them anyway.
1208 		token = subst(token, '\0', '\r');
1209 		token = subst(token, "\r", "");
1210 		if (token.empty() || token == ")") {
1211 			lastline = string();
1212 			continue;
1213 		}
1214 
1215 		// FIXME UNICODE: We assume that the file names in the log
1216 		// file are in the file system encoding.
1217 		token = to_utf8(from_filesystem8bit(token));
1218 
1219 		// Sometimes, filenames are broken across lines.
1220 		// We care for that and save suspicious lines.
1221 		// Here we exclude some cases where we are sure
1222 		// that there is no continued filename
1223 		if (!lastline.empty()) {
1224 			static regex const package_info("Package \\w+ Info: .*");
1225 			static regex const package_warning("Package \\w+ Warning: .*");
1226 			if (prefixIs(token, "File:") || prefixIs(token, "(Font)")
1227 			    || prefixIs(token, "Package:")
1228 			    || prefixIs(token, "Language:")
1229 			    || prefixIs(token, "LaTeX Info:")
1230 			    || prefixIs(token, "LaTeX Font Info:")
1231 			    || prefixIs(token, "\\openout[")
1232 			    || prefixIs(token, "))")
1233 			    || regex_match(token, package_info)
1234 			    || regex_match(token, package_warning))
1235 				lastline = string();
1236 		}
1237 
1238 		if (!lastline.empty())
1239 			// probably a continued filename from last line
1240 			token = lastline + token;
1241 		if (token.length() > 255) {
1242 			// string too long. Cut off.
1243 			token.erase(0, token.length() - 251);
1244 		}
1245 
1246 		smatch sub;
1247 
1248 		// (1) "File: file.ext"
1249 		if (regex_match(token, sub, reg1)) {
1250 			// is this a fragmental file name?
1251 			fragment = !completeFilename(sub.str(1), head);
1252 			// However, ...
1253 			if (suffixIs(token, ")"))
1254 				// no fragment for sure
1255 				fragment = false;
1256 		// (2) "No file file.ext"
1257 		} else if (regex_match(token, sub, reg2)) {
1258 			// file names must contains a dot, line ends with dot
1259 			if (contains(sub.str(1), '.') && sub.str(2) == ".")
1260 				fragment = !handleFoundFile(sub.str(1), head);
1261 			else
1262 				// we suspect a line break
1263 				fragment = true;
1264 		// (3)(a) "\openout<nr> = `file.ext'."
1265 		} else if (regex_match(token, sub, reg3a)) {
1266 			// search for closing '. at the end of the line
1267 			if (sub.str(2) == "\'.")
1268 				fragment = !handleFoundFile(sub.str(1), head);
1269 			else
1270 				// potential fragment
1271 				fragment = true;
1272 		// (3)(b) "\openout<nr> = file.ext" (LuaTeX)
1273 		} else if (regex_match(token, sub, reg3b)) {
1274 			// file names must contains a dot
1275 			if (contains(sub.str(1), '.'))
1276 				fragment = !handleFoundFile(sub.str(1), head);
1277 			else
1278 				// potential fragment
1279 				fragment = true;
1280 		// (4) "Writing index file file.ext"
1281 		} else if (regex_match(token, sub, reg4))
1282 			// fragmential file name?
1283 			fragment = !completeFilename(sub.str(1), head);
1284 		// (5) "Writing nomenclature file file.ext"
1285 		else if (regex_match(token, sub, regnomencl) ||
1286 			   regex_match(token, sub, regoldnomencl))
1287 			// fragmental file name?
1288 			fragment= !completeFilename(sub.str(1), head);
1289 		// (6) "\tf@toc=\write<nr>" (for MikTeX)
1290 		else if (regex_match(token, sub, miktexTocReg))
1291 			fragment = !handleFoundFile(onlyFileName(changeExtension(
1292 						file.absFileName(), ".toc")), head);
1293 		else
1294 			// not found, but we won't check further
1295 			fragment = false;
1296 
1297 		int fragment_pos = -1;
1298 		// (7) "<file.ext>"
1299 		// We can have several of these on one line
1300 		// (and in addition to those above)
1301 		if (regex_match(token, sub, reg5)) {
1302 			// search for strings in <...>
1303 			static regex const reg5_1("<([^>]+)(.)");
1304 			fragment_pos = iterateLine(token, reg5_1, "<", ">",
1305 						   fragment_pos, head);
1306 			fragment = (fragment_pos != -1);
1307 		}
1308 
1309 		// (8) "(file.ext)"
1310 		// We can have several of these on one line
1311 		// this must be queried separated, because of
1312 		// cases such as "File: file.ext (type eps)"
1313 		// where "File: file.ext" would be skipped
1314 		if (regex_match(token, sub, reg6)) {
1315 			// search for strings in (...)
1316 			static regex const reg6_1("\\(([^()]+)(.)");
1317 			fragment_pos = iterateLine(token, reg6_1, "(", ")",
1318 						   fragment_pos, head);
1319 			fragment = (fragment_pos != -1);
1320 		}
1321 
1322 		if (fragment)
1323 			// probable linebreak within file name:
1324 			// save this line
1325 			lastline = token;
1326 		else
1327 			// no linebreak: reset
1328 			lastline = string();
1329 	}
1330 
1331 	// Make sure that the main .tex file is in the dependency file.
1332 	head.insert(file, true);
1333 }
1334 
1335 
scanBlgFile(DepTable & dep,TeXErrors & terr)1336 int LaTeX::scanBlgFile(DepTable & dep, TeXErrors & terr)
1337 {
1338 	FileName const blg_file(changeExtension(file.absFileName(), "blg"));
1339 	LYXERR(Debug::LATEX, "Scanning blg file: " << blg_file);
1340 
1341 	ifstream ifs(blg_file.toFilesystemEncoding().c_str());
1342 	string token;
1343 	static regex const reg1(".*Found (bibtex|BibTeX) data (file|source) '([^']+).*");
1344 	static regex const bibtexError("^(.*---line [0-9]+ of file).*$");
1345 	static regex const bibtexError2("^(.*---while reading file).*$");
1346 	static regex const bibtexError3("(A bad cross reference---).*");
1347 	static regex const bibtexError4("(Sorry---you've exceeded BibTeX's).*");
1348 	static regex const bibtexError5("\\*Please notify the BibTeX maintainer\\*");
1349 	static regex const biberError("^.*> (FATAL|ERROR) - (.*)$");
1350 	int retval = NO_ERRORS;
1351 
1352 	string prevtoken;
1353 	while (getline(ifs, token)) {
1354 		token = rtrim(token, "\r");
1355 		smatch sub;
1356 		// FIXME UNICODE: We assume that citation keys and filenames
1357 		// in the aux file are in the file system encoding.
1358 		token = to_utf8(from_filesystem8bit(token));
1359 		if (regex_match(token, sub, reg1)) {
1360 			string data = sub.str(3);
1361 			if (!data.empty()) {
1362 				LYXERR(Debug::LATEX, "Found bib file: " << data);
1363 				handleFoundFile(data, dep);
1364 			}
1365 		}
1366 		else if (regex_match(token, sub, bibtexError)
1367 			 || regex_match(token, sub, bibtexError2)
1368 			 || regex_match(token, sub, bibtexError4)
1369 			 || regex_match(token, sub, bibtexError5)) {
1370 			retval |= BIBTEX_ERROR;
1371 			string errstr = N_("BibTeX error: ") + token;
1372 			string message;
1373 			if ((prefixIs(token, "while executing---line")
1374 			     || prefixIs(token, "---line ")
1375 			     || prefixIs(token, "*Please notify the BibTeX"))
1376 			    && !prevtoken.empty()) {
1377 				errstr = N_("BibTeX error: ") + prevtoken;
1378 				message = prevtoken + '\n';
1379 			}
1380 			message += token;
1381 			terr.insertError(0,
1382 					 from_local8bit(errstr),
1383 					 from_local8bit(message));
1384 		} else if (regex_match(prevtoken, sub, bibtexError3)) {
1385 			retval |= BIBTEX_ERROR;
1386 			string errstr = N_("BibTeX error: ") + prevtoken;
1387 			string message = prevtoken + '\n' + token;
1388 			terr.insertError(0,
1389 					 from_local8bit(errstr),
1390 					 from_local8bit(message));
1391 		} else if (regex_match(token, sub, biberError)) {
1392 			retval |= BIBTEX_ERROR;
1393 			string errstr = N_("Biber error: ") + sub.str(2);
1394 			string message = token;
1395 			terr.insertError(0,
1396 					 from_local8bit(errstr),
1397 					 from_local8bit(message));
1398 		}
1399 		prevtoken = token;
1400 	}
1401 	return retval;
1402 }
1403 
1404 
1405 } // namespace lyx
1406