3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author Jürgen Spitzmüller
13 * Full author contact details are available in file CREDITS.
18 #include "bufferlist.h"
25 #include "support/filetools.h"
26 #include "support/convert.h"
27 #include "support/lstrings.h"
28 #include "support/lyxlib.h"
29 #include "support/systemcall.h"
30 #include "support/os.h"
32 #include <boost/filesystem/operations.hpp>
33 #include <boost/regex.hpp>
40 using support::absolutePath;
41 using support::bformat;
42 using support::changeExtension;
43 using support::contains;
44 using support::FileName;
45 using support::findtexfile;
46 using support::getcwd;
47 using support::makeAbsPath;
48 using support::onlyFilename;
49 using support::prefixIs;
50 using support::quoteName;
51 using support::removeExtension;
53 using support::rsplit;
56 using support::suffixIs;
57 using support::Systemcall;
58 using support::unlink;
61 namespace os = support::os;
62 namespace fs = boost::filesystem;
68 #ifndef CXX_GLOBAL_CSTD
79 // TODO: in no particular order
80 // - get rid of the call to
81 // BufferList::updateIncludedTeXfiles, this should either
82 // be done before calling LaTeX::funcs or in a completely
84 // - the makeindex style files should be taken care of with
85 // the dependency mechanism.
86 // - makeindex commandline options should be supported
87 // - somewhere support viewing of bibtex and makeindex log files.
88 // - we should perhaps also scan the bibtex log file
92 docstring runMessage(unsigned int count)
94 return bformat(_("Waiting for LaTeX run number %1$d"), count);
103 void TeXErrors::insertError(int line, docstring const & error_desc,
104 docstring const & error_text)
106 Error newerr(line, error_desc, error_text);
107 errors.push_back(newerr);
111 bool operator==(Aux_Info const & a, Aux_Info const & o)
113 return a.aux_file == o.aux_file &&
114 a.citations == o.citations &&
115 a.databases == o.databases &&
116 a.styles == o.styles;
120 bool operator!=(Aux_Info const & a, Aux_Info const & o)
130 LaTeX::LaTeX(string const & latex, OutputParams const & rp,
132 : cmd(latex), file(f), runparams(rp)
135 if (prefixIs(cmd, "pdf")) { // Do we use pdflatex ?
136 depfile = FileName(file.absFilename() + ".dep-pdf");
138 FileName(changeExtension(file.absFilename(), ".pdf"));
140 depfile = FileName(file.absFilename() + ".dep");
142 FileName(changeExtension(file.absFilename(), ".dvi"));
147 void LaTeX::deleteFilesOnError() const
149 // currently just a dummy function.
151 // What files do we have to delete?
153 // This will at least make latex do all the runs
156 // but the reason for the error might be in a generated file...
159 FileName const bbl(changeExtension(file.absFilename(), ".bbl"));
163 FileName const ind(changeExtension(file.absFilename(), ".ind"));
167 FileName const nls(changeExtension(file.absFilename(), ".nls"));
170 // Also remove the aux file
171 FileName const aux(changeExtension(file.absFilename(), ".aux"));
176 int LaTeX::run(TeXErrors & terr)
177 // We know that this function will only be run if the lyx buffer
178 // has been changed. We also know that a newly written .tex file
179 // is always different from the previous one because of the date
180 // in it. However it seems safe to run latex (at least) on time
181 // each time the .tex file changes.
183 int scanres = NO_ERRORS;
184 unsigned int count = 0; // number of times run
185 num_errors = 0; // just to make sure.
186 unsigned int const MAX_RUN = 6;
187 DepTable head; // empty head
188 bool rerun = false; // rerun requested
190 // The class LaTeX does not know the temp path.
191 theBufferList().updateIncludedTeXfiles(getcwd().absFilename(),
194 // Never write the depfile if an error was encountered.
197 // first check if the file dependencies exist:
198 // ->If it does exist
199 // check if any of the files mentioned in it have
200 // changed (done using a checksum).
202 // run latex once and
203 // remake the dependency file
204 // -> if not changed:
205 // just return there is nothing to do for us.
206 // ->if it doesn't exist
208 // run latex once (we need to run latex once anyway) and
209 // remake the dependency file.
212 bool had_depfile = fs::exists(depfile.toFilesystemEncoding());
213 bool run_bibtex = false;
214 FileName const aux_file(changeExtension(file.absFilename(), "aux"));
217 lyxerr[Debug::DEPEND] << "Dependency file exists" << endl;
218 // Read the dep file:
219 had_depfile = head.read(depfile);
223 // Update the checksums
225 // Can't just check if anything has changed because it might
226 // have aborted on error last time... in which cas we need
227 // to re-run latex and collect the error messages
228 // (even if they are the same).
229 if (!fs::exists(output_file.toFilesystemEncoding())) {
230 lyxerr[Debug::DEPEND]
231 << "re-running LaTeX because output file doesn't exist."
233 } else if (!head.sumchange()) {
234 lyxerr[Debug::DEPEND] << "return no_change" << endl;
237 lyxerr[Debug::DEPEND]
238 << "Dependency file has changed" << endl;
241 if (head.extchanged(".bib") || head.extchanged(".bst"))
244 lyxerr[Debug::DEPEND]
245 << "Dependency file does not exist, or has wrong format"
248 /// We scan the aux file even when had_depfile = false,
249 /// because we can run pdflatex on the file after running latex on it,
250 /// in which case we will not need to run bibtex again.
251 vector<Aux_Info> bibtex_info_old;
253 bibtex_info_old = scanAuxFiles(aux_file);
256 lyxerr[Debug::LATEX] << "Run #" << count << endl;
257 message(runMessage(count));
260 scanres = scanLogFile(terr);
261 if (scanres & ERROR_RERUN) {
262 lyxerr[Debug::LATEX] << "Rerunning LaTeX" << endl;
264 scanres = scanLogFile(terr);
267 if (scanres & ERRORS) {
268 deleteFilesOnError();
269 return scanres; // return on error
272 vector<Aux_Info> const bibtex_info = scanAuxFiles(aux_file);
273 if (!run_bibtex && bibtex_info_old != bibtex_info)
276 // update the dependencies.
277 deplog(head); // reads the latex log
281 // At this point we must run external programs if needed.
282 // makeindex will be run if a .idx file changed or was generated.
283 // And if there were undefined citations or changes in references
284 // the .aux file is checked for signs of bibtex. Bibtex is then run
287 // memoir (at least) writes an empty *idx file in the first place.
288 // A second latex run is needed.
289 FileName const idxfile(changeExtension(file.absFilename(), ".idx"));
290 rerun = fs::exists(idxfile.toFilesystemEncoding()) &&
291 fs::is_empty(idxfile.toFilesystemEncoding());
294 if (head.haschanged(idxfile)) {
296 lyxerr[Debug::LATEX] << "Running MakeIndex." << endl;
297 message(_("Running MakeIndex."));
298 // onlyFilename() is needed for cygwin
299 rerun |= runMakeIndex(onlyFilename(idxfile.absFilename()),
302 if (head.haschanged(FileName(changeExtension(file.absFilename(), ".nlo")))) {
304 << "Running MakeIndex for nomencl."
306 message(_("Running MakeIndex for nomencl."));
307 // onlyFilename() is needed for cygwin
308 string const nomenclstr = " -s nomencl.ist -o "
309 + onlyFilename(changeExtension(
310 file.toFilesystemEncoding(), ".nls"));
311 rerun |= runMakeIndex(onlyFilename(changeExtension(
312 file.absFilename(), ".nlo")),
318 // if (scanres & UNDEF_CIT || scanres & RERUN || run_bibtex)
319 if (scanres & UNDEF_CIT || run_bibtex) {
320 // Here we must scan the .aux file and look for
321 // "\bibdata" and/or "\bibstyle". If one of those
322 // tags is found -> run bibtex and set rerun = true;
324 lyxerr[Debug::LATEX] << "Running BibTeX." << endl;
325 message(_("Running BibTeX."));
326 updateBibtexDependencies(head, bibtex_info);
327 rerun |= runBibTeX(bibtex_info);
328 } else if (!had_depfile) {
329 /// If we run pdflatex on the file after running latex on it,
330 /// then we do not need to run bibtex, but we do need to
331 /// insert the .bib and .bst files into the .dep-pdf file.
332 updateBibtexDependencies(head, bibtex_info);
336 // we know on this point that latex has been run once (or we just
337 // returned) and the question now is to decide if we need to run
338 // it any more. This is done by asking if any of the files in the
339 // dependency file has changed. (remember that the checksum for
340 // a given file is reported to have changed if it just was created)
341 // -> if changed or rerun == true:
342 // run latex once more and
343 // update the dependency structure
344 // -> if not changed:
345 // we does nothing at this point
347 if (rerun || head.sumchange()) {
350 lyxerr[Debug::DEPEND]
351 << "Dep. file has changed or rerun requested"
354 << "Run #" << count << endl;
355 message(runMessage(count));
357 scanres = scanLogFile(terr);
358 if (scanres & ERRORS) {
359 deleteFilesOnError();
360 return scanres; // return on error
363 // update the depedencies
364 deplog(head); // reads the latex log
367 lyxerr[Debug::DEPEND]
368 << "Dep. file has NOT changed"
373 // The inclusion of files generated by external programs like
374 // makeindex or bibtex might have done changes to pagenumbering,
375 // etc. And because of this we must run the external programs
376 // again to make sure everything is redone correctly.
377 // Also there should be no need to run the external programs any
380 // run makeindex if the <file>.idx has changed or was generated.
381 if (head.haschanged(FileName(changeExtension(file.absFilename(), ".idx")))) {
383 lyxerr[Debug::LATEX] << "Running MakeIndex." << endl;
384 message(_("Running MakeIndex."));
385 // onlyFilename() is needed for cygwin
386 rerun = runMakeIndex(onlyFilename(changeExtension(
387 file.absFilename(), ".idx")), runparams);
390 // I am not pretty sure if need this twice.
391 if (head.haschanged(FileName(changeExtension(file.absFilename(), ".nlo")))) {
393 << "Running MakeIndex for nomencl."
395 message(_("Running MakeIndex for nomencl."));
396 // onlyFilename() is needed for cygwin
397 string nomenclstr = " -s nomencl.ist -o "
398 + onlyFilename(changeExtension(
399 file.toFilesystemEncoding(), ".nls"));
400 rerun |= runMakeIndex(onlyFilename(changeExtension(
401 file.absFilename(), ".nlo")),
407 // we will only run latex more if the log file asks for it.
408 // or if the sumchange() is true.
409 // -> rerun asked for:
411 // remake the dependency file
412 // goto 2 or return if max runs are reached.
413 // -> rerun not asked for:
414 // just return (fall out of bottom of func)
416 while ((head.sumchange() || rerun || (scanres & RERUN))
417 && count < MAX_RUN) {
418 // Yes rerun until message goes away, or until
419 // MAX_RUNS are reached.
422 lyxerr[Debug::LATEX] << "Run #" << count << endl;
423 message(runMessage(count));
425 scanres = scanLogFile(terr);
426 if (scanres & ERRORS) {
427 deleteFilesOnError();
428 return scanres; // return on error
435 // Write the dependencies to file.
437 lyxerr[Debug::LATEX] << "Done." << endl;
442 int LaTeX::startscript()
444 // onlyFilename() is needed for cygwin
445 string tmp = cmd + ' '
446 + quoteName(onlyFilename(file.toFilesystemEncoding()))
447 + " > " + os::nulldev();
449 return one.startscript(Systemcall::Wait, tmp);
453 bool LaTeX::runMakeIndex(string const & f, OutputParams const & runparams,
454 string const & params)
457 << "idx file has been made, running makeindex on file "
459 string tmp = lyxrc.index_command + ' ';
461 tmp = subst(tmp, "$$lang", runparams.document_language);
465 one.startscript(Systemcall::Wait, tmp);
470 vector<Aux_Info> const
471 LaTeX::scanAuxFiles(FileName const & file)
473 vector<Aux_Info> result;
475 result.push_back(scanAuxFile(file));
477 string const basename = removeExtension(file.absFilename());
478 for (int i = 1; i < 1000; ++i) {
479 FileName const file2(basename
480 + '.' + convert<string>(i)
482 if (!fs::exists(file2.toFilesystemEncoding()))
484 result.push_back(scanAuxFile(file2));
490 Aux_Info const LaTeX::scanAuxFile(FileName const & file)
493 result.aux_file = file;
494 scanAuxFile(file, result);
499 void LaTeX::scanAuxFile(FileName const & file, Aux_Info & aux_info)
501 lyxerr[Debug::LATEX] << "Scanning aux file: " << file << endl;
503 ifstream ifs(file.toFilesystemEncoding().c_str());
505 static regex const reg1("\\\\citation\\{([^}]+)\\}");
506 static regex const reg2("\\\\bibdata\\{([^}]+)\\}");
507 static regex const reg3("\\\\bibstyle\\{([^}]+)\\}");
508 static regex const reg4("\\\\@input\\{([^}]+)\\}");
510 while (getline(ifs, token)) {
511 token = rtrim(token, "\r");
513 // FIXME UNICODE: We assume that citation keys and filenames
514 // in the aux file are in the file system encoding.
515 token = to_utf8(from_filesystem8bit(token));
516 if (regex_match(token, sub, reg1)) {
517 string data = sub.str(1);
518 while (!data.empty()) {
520 data = split(data, citation, ',');
521 lyxerr[Debug::LATEX] << "Citation: "
523 aux_info.citations.insert(citation);
525 } else if (regex_match(token, sub, reg2)) {
526 string data = sub.str(1);
527 // data is now all the bib files separated by ','
528 // get them one by one and pass them to the helper
529 while (!data.empty()) {
531 data = split(data, database, ',');
532 database = changeExtension(database, "bib");
533 lyxerr[Debug::LATEX] << "BibTeX database: `"
534 << database << '\'' << endl;
535 aux_info.databases.insert(database);
537 } else if (regex_match(token, sub, reg3)) {
538 string style = sub.str(1);
539 // token is now the style file
540 // pass it to the helper
541 style = changeExtension(style, "bst");
542 lyxerr[Debug::LATEX] << "BibTeX style: `"
543 << style << '\'' << endl;
544 aux_info.styles.insert(style);
545 } else if (regex_match(token, sub, reg4)) {
546 string const file2 = sub.str(1);
547 scanAuxFile(makeAbsPath(file2), aux_info);
553 void LaTeX::updateBibtexDependencies(DepTable & dep,
554 vector<Aux_Info> const & bibtex_info)
556 // Since a run of Bibtex mandates more latex runs it is ok to
557 // remove all ".bib" and ".bst" files.
558 dep.remove_files_with_extension(".bib");
559 dep.remove_files_with_extension(".bst");
560 //string aux = OnlyFilename(ChangeExtension(file, ".aux"));
562 for (vector<Aux_Info>::const_iterator it = bibtex_info.begin();
563 it != bibtex_info.end(); ++it) {
564 for (set<string>::const_iterator it2 = it->databases.begin();
565 it2 != it->databases.end(); ++it2) {
566 FileName const file = findtexfile(*it2, "bib");
568 dep.insert(file, true);
571 for (set<string>::const_iterator it2 = it->styles.begin();
572 it2 != it->styles.end(); ++it2) {
573 FileName const file = findtexfile(*it2, "bst");
575 dep.insert(file, true);
581 bool LaTeX::runBibTeX(vector<Aux_Info> const & bibtex_info)
584 for (vector<Aux_Info>::const_iterator it = bibtex_info.begin();
585 it != bibtex_info.end(); ++it) {
586 if (it->databases.empty())
590 string tmp = lyxrc.bibtex_command + " ";
591 // onlyFilename() is needed for cygwin
592 tmp += quoteName(onlyFilename(removeExtension(
593 it->aux_file.absFilename())));
595 one.startscript(Systemcall::Wait, tmp);
597 // Return whether bibtex was run
602 int LaTeX::scanLogFile(TeXErrors & terr)
606 int retval = NO_ERRORS;
608 onlyFilename(changeExtension(file.absFilename(), ".log"));
609 lyxerr[Debug::LATEX] << "Log file: " << tmp << endl;
610 FileName const fn = FileName(makeAbsPath(tmp));
611 ifstream ifs(fn.toFilesystemEncoding().c_str());
614 while (getline(ifs, token)) {
615 // MikTeX sometimes inserts \0 in the log file. They can't be
616 // removed directly with the existing string utility
617 // functions, so convert them first to \r, and remove all
618 // \r's afterwards, since we need to remove them anyway.
619 token = subst(token, '\0', '\r');
620 token = subst(token, "\r", "");
622 lyxerr[Debug::LATEX] << "Log line: " << token << endl;
627 if (prefixIs(token, "LaTeX Warning:") ||
628 prefixIs(token, "! pdfTeX warning")) {
629 // Here shall we handle different
631 retval |= LATEX_WARNING;
632 lyxerr[Debug::LATEX] << "LaTeX Warning." << endl;
633 if (contains(token, "Rerun to get cross-references")) {
636 << "We should rerun." << endl;
637 } else if (contains(token, "Citation")
638 && contains(token, "on page")
639 && contains(token, "undefined")) {
642 } else if (prefixIs(token, "Package")) {
644 retval |= PACKAGE_WARNING;
645 if (contains(token, "natbib Warning:")) {
647 if (contains(token, "Citation")
648 && contains(token, "on page")
649 && contains(token, "undefined")) {
652 } else if (contains(token, "run BibTeX")) {
654 } else if (contains(token, "Rerun LaTeX") ||
655 contains(token, "Rerun to get")) {
656 // at least longtable.sty and bibtopic.sty
659 << "We should rerun." << endl;
662 } else if (token[0] == '(') {
663 if (contains(token, "Rerun LaTeX") ||
664 contains(token, "Rerun to get")) {
667 << "We should rerun." << endl;
670 } else if (prefixIs(token, "! ")) {
671 // Ok, we have something that looks like a TeX Error
672 // but what do we really have.
674 // Just get the error description:
675 string desc(token, 2);
676 if (contains(token, "LaTeX Error:"))
677 retval |= LATEX_ERROR;
682 if (!getline(ifs, tmp))
686 } while (!prefixIs(tmp, "l."));
687 if (prefixIs(tmp, "l.")) {
688 // we have a latex error
691 "Package babel Error: You haven't defined the language"))
692 retval |= ERROR_RERUN;
693 // get the line number:
695 sscanf(tmp.c_str(), "l.%d", &line);
696 // get the rest of the message:
697 string errstr(tmp, tmp.find(' '));
700 while (!contains(errstr, "l.")
702 && !prefixIs(tmp, "! ")
703 && !contains(tmp, "(job aborted")) {
709 << "line: " << line << '\n'
710 << "Desc: " << desc << '\n'
711 << "Text: " << errstr << endl;
712 if (line == last_line)
718 if (line_count <= 5) {
720 // We have no idea what the encoding of
722 // It seems that the output from the
723 // latex compiler itself is pure ASCII,
724 // but it can include bits from the
725 // document, so whatever encoding we
726 // assume here it can be wrong.
727 terr.insertError(line,
728 from_local8bit(desc),
729 from_local8bit(errstr));
734 // information messages, TeX warnings and other
735 // warnings we have not caught earlier.
736 if (prefixIs(token, "Overfull ")) {
737 retval |= TEX_WARNING;
738 } else if (prefixIs(token, "Underfull ")) {
739 retval |= TEX_WARNING;
740 } else if (contains(token, "Rerun to get citations")) {
741 // Natbib seems to use this.
743 } else if (contains(token, "No pages of output")) {
744 // A dvi file was not created
746 } else if (contains(token, "That makes 100 errors")) {
747 // More than 100 errors were reprted
748 retval |= TOO_MANY_ERRORS;
752 lyxerr[Debug::LATEX] << "Log line: " << token << endl;
759 bool insertIfExists(FileName const & absname, DepTable & head)
761 fs::path const path = absname.toFilesystemEncoding();
762 if (fs::exists(path) && !fs::is_directory(path)) {
763 head.insert(absname, true);
770 bool handleFoundFile(string const & ff, DepTable & head)
772 // convert from native os path to unix path
773 string foundfile = os::internal_path(trim(ff));
775 lyxerr[Debug::DEPEND] << "Found file: " << foundfile << endl;
777 // Ok now we found a file.
778 // Now we should make sure that this is a file that we can
779 // access through the normal paths.
780 // We will not try any fancy search methods to
783 // (1) foundfile is an
784 // absolute path and should
786 if (absolutePath(foundfile)) {
787 lyxerr[Debug::DEPEND] << "AbsolutePath file: "
788 << foundfile << endl;
789 // On initial insert we want to do the update at once
790 // since this file cannot be a file generated by
792 FileName absname(foundfile);
793 if (!insertIfExists(absname, head)) {
795 string strippedfile = foundfile;
796 while (contains(strippedfile, " ")) {
797 // strip off part after last space and try again
798 string tmp = strippedfile;
799 string const stripoff =
800 rsplit(tmp, strippedfile, ' ');
801 absname.set(strippedfile);
802 if (insertIfExists(absname, head))
808 string onlyfile = onlyFilename(foundfile);
809 FileName absname(makeAbsPath(onlyfile));
812 while (contains(foundfile, " ")) {
813 if (fs::exists(absname.toFilesystemEncoding()))
817 // strip off part after last space and try again
819 string const stripoff =
820 rsplit(foundfile, strippedfile, ' ');
821 foundfile = strippedfile;
822 onlyfile = onlyFilename(strippedfile);
823 absname = makeAbsPath(onlyfile);
827 // (2) foundfile is in the tmpdir
828 // insert it into head
829 fs::path const path = absname.toFilesystemEncoding();
830 if (fs::exists(path) && !fs::is_directory(path)) {
831 static regex unwanted("^.*\\.(aux|log|dvi|bbl|ind|glo)$");
832 if (regex_match(onlyfile, unwanted)) {
833 lyxerr[Debug::DEPEND]
836 << " in the dep file"
838 } else if (suffixIs(onlyfile, ".tex")) {
839 // This is a tex file generated by LyX
840 // and latex is not likely to change this
842 lyxerr[Debug::DEPEND]
843 << "Tmpdir TeX file: "
846 head.insert(absname, true);
848 lyxerr[Debug::DEPEND]
852 head.insert(absname);
856 lyxerr[Debug::DEPEND]
857 << "Not a file or we are unable to find it."
864 bool checkLineBreak(string const & ff, DepTable & head)
866 if (contains(ff, '.'))
867 // if we have a dot, we let handleFoundFile decide
868 return handleFoundFile(ff, head);
870 // else, we suspect a line break
877 void LaTeX::deplog(DepTable & head)
879 // This function reads the LaTeX log file end extracts all the
880 // external files used by the LaTeX run. The files are then
881 // entered into the dependency file.
883 string const logfile =
884 onlyFilename(changeExtension(file.absFilename(), ".log"));
886 static regex reg1("File: (.+).*");
887 static regex reg2("No file (.+)(.).*");
888 static regex reg3("\\\\openout[0-9]+.*=.*`(.+)(..).*");
889 // If an index should be created, MikTex does not write a line like
890 // \openout# = 'sample.idx'.
891 // but instead only a line like this into the log:
892 // Writing index file sample.idx
893 static regex reg4("Writing index file (.+).*");
894 // files also can be enclosed in <...>
895 static regex reg5("<([^>]+)(.).*");
896 static regex regnomencl("Writing nomenclature file (.+).*");
897 // If a toc should be created, MikTex does not write a line like
898 // \openout# = `sample.toc'.
899 // but only a line like this into the log:
901 // This line is also written by tetex.
902 // This line is not present if no toc should be created.
903 static regex miktexTocReg("\\\\tf@toc=\\\\write.*");
904 static regex reg6(".*\\([^)]+.*");
906 FileName const fn(makeAbsPath(logfile));
907 ifstream ifs(fn.toFilesystemEncoding().c_str());
910 // Ok, the scanning of files here is not sufficient.
911 // Sometimes files are named by "File: xxx" only
912 // So I think we should use some regexps to find files instead.
913 // Note: all file names and paths might contains spaces.
914 bool found_file = false;
917 // MikTeX sometimes inserts \0 in the log file. They can't be
918 // removed directly with the existing string utility
919 // functions, so convert them first to \r, and remove all
920 // \r's afterwards, since we need to remove them anyway.
921 token = subst(token, '\0', '\r');
922 token = subst(token, "\r", "");
923 if (token.empty() || token == ")") {
928 // Sometimes, filenames are broken across lines.
929 // We care for that and save suspicious lines.
930 // Here we exclude some cases where we are sure
931 // that there is no continued filename
932 if (!lastline.empty()) {
933 static regex package_info("Package \\w+ Info: .*");
934 static regex package_warning("Package \\w+ Warning: .*");
935 if (prefixIs(token, "File:") || prefixIs(token, "(Font)")
936 || prefixIs(token, "Package:")
937 || prefixIs(token, "Language:")
938 || prefixIs(token, "LaTeX Info:")
939 || prefixIs(token, "LaTeX Font Info:")
940 || prefixIs(token, "\\openout[")
941 || prefixIs(token, "))")
942 || regex_match(token, package_info)
943 || regex_match(token, package_warning))
947 if (!lastline.empty())
948 // probably a continued filename from last line
949 token = lastline + token;
950 if (token.length() > 255) {
951 // string too long. Cut off.
952 int r = token.length() - 250;
953 string ntoken = token.substr(r, token.length());
959 // FIXME UNICODE: We assume that the file names in the log
960 // file are in the file system encoding.
961 token = to_utf8(from_filesystem8bit(token));
963 // (1) "File: file.ext"
964 if (regex_match(token, sub, reg1)) {
966 found_file = checkLineBreak(sub.str(1), head);
968 if (suffixIs(token, ")"))
969 // no line break for sure
970 // pretend we've been succesfully searching
972 // (2) "No file file.ext"
973 } else if (regex_match(token, sub, reg2)) {
974 // file names must contains a dot, line ends with dot
975 if (contains(sub.str(1), '.') && sub.str(2) == ".")
976 found_file = handleFoundFile(sub.str(1), head);
978 // we suspect a line break
980 // (3) "\openout<nr> = `file.ext'."
981 } else if (regex_match(token, sub, reg3)) {
982 // search for closing '. at the end of the line
983 if (sub.str(2) == "\'.")
984 found_file = handleFoundFile(sub.str(1), head);
986 // probable line break
988 // (4) "Writing index file file.ext"
989 } else if (regex_match(token, sub, reg4))
991 found_file = checkLineBreak(sub.str(1), head);
993 else if (regex_match(token, sub, reg5)) {
994 // search for closing '>' and dot ('*.*>') at the eol
995 if (contains(sub.str(1), '.') && sub.str(2) == ">")
996 found_file = handleFoundFile(sub.str(1), head);
998 // probable line break
1000 // (6) "Writing nomenclature file file.ext"
1001 } else if (regex_match(token, sub, regnomencl))
1003 found_file = checkLineBreak(sub.str(1), head);
1004 // (7) "\tf@toc=\write<nr>" (for MikTeX)
1005 else if (regex_match(token, sub, miktexTocReg))
1006 found_file = handleFoundFile(onlyFilename(changeExtension(
1007 file.absFilename(), ".toc")), head);
1009 // not found, but we won't check further
1010 // pretend we've been succesfully searching
1014 // note that we can have several of these on one line
1015 // this must be queried separated, because of
1016 // cases such as "File: file.ext (type eps)"
1017 // where "File: file.ext" would be skipped
1018 if (regex_match(token, sub, reg6)) {
1019 // search for strings in (...)
1020 static regex reg6_1("\\(([^()]+)(.).*");
1022 string::const_iterator first = token.begin();
1023 string::const_iterator end = token.end();
1025 while (regex_search(first, end, what, reg6_1)) {
1026 // if we have a dot, try to handle as file
1027 if (contains(what.str(1), '.')) {
1028 first = what[0].second;
1029 if (what.str(2) == ")") {
1030 handleFoundFile(what.str(1), head);
1031 // since we had a closing bracket,
1032 // do not investigate further
1035 // if we have no closing bracket,
1036 // try to handle as file nevertheless
1037 found_file = handleFoundFile(
1038 what.str(1) + what.str(2), head);
1040 // if we do not have a dot, check if the line has
1041 // a closing bracket (else, we suspect a line break)
1042 else if (what.str(2) != ")") {
1043 first = what[0].second;
1046 // we have a closing bracket, so the content
1047 // is not a file name.
1048 // no need to investigate further
1049 // pretend we've been succesfully searching
1050 first = what[0].second;
1057 // probable linebreak:
1061 // no linebreak: reset
1062 lastline = string();
1065 // Make sure that the main .tex file is in the dependency file.
1066 head.insert(file, true);