]> git.lyx.org Git - lyx.git/blob - src/LaTeX.cpp
3e8729adf13313888d9f0defdf7c85339f84e66d
[lyx.git] / src / LaTeX.cpp
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 "DepTable.h"
22
23 #include "support/debug.h"
24 #include "support/convert.h"
25 #include "support/FileName.h"
26 #include "support/filetools.h"
27 #include "support/gettext.h"
28 #include "support/lstrings.h"
29 #include "support/Systemcall.h"
30 #include "support/os.h"
31
32 #include "support/regex.h"
33
34 #include <fstream>
35
36
37 using namespace std;
38 using namespace lyx::support;
39
40 namespace lyx {
41
42 namespace os = support::os;
43
44 // TODO: in no particular order
45 // - get rid of the call to
46 //   BufferList::updateIncludedTeXfiles, this should either
47 //   be done before calling LaTeX::funcs or in a completely
48 //   different way.
49 // - the makeindex style files should be taken care of with
50 //   the dependency mechanism.
51 // - we should perhaps also scan the bibtex log file
52
53 namespace {
54
55 docstring runMessage(unsigned int count)
56 {
57         return bformat(_("Waiting for LaTeX run number %1$d"), count);
58 }
59
60 } // anon namespace
61
62 /*
63  * CLASS TEXERRORS
64  */
65
66 void TeXErrors::insertError(int line, docstring const & error_desc,
67                             docstring const & error_text)
68 {
69         Error newerr(line, error_desc, error_text);
70         errors.push_back(newerr);
71 }
72
73
74 bool operator==(AuxInfo const & a, AuxInfo const & o)
75 {
76         return a.aux_file == o.aux_file
77                 && a.citations == o.citations
78                 && a.databases == o.databases
79                 && a.styles == o.styles;
80 }
81
82
83 bool operator!=(AuxInfo const & a, AuxInfo const & o)
84 {
85         return !(a == o);
86 }
87
88
89 /*
90  * CLASS LaTeX
91  */
92
93 LaTeX::LaTeX(string const & latex, OutputParams const & rp,
94              FileName const & f)
95         : cmd(latex), file(f), runparams(rp)
96 {
97         num_errors = 0;
98         if (prefixIs(cmd, "pdf")) { // Do we use pdflatex ?
99                 depfile = FileName(file.absFileName() + ".dep-pdf");
100                 output_file =
101                         FileName(changeExtension(file.absFileName(), ".pdf"));
102         } else {
103                 depfile = FileName(file.absFileName() + ".dep");
104                 output_file =
105                         FileName(changeExtension(file.absFileName(), ".dvi"));
106         }
107 }
108
109
110 void LaTeX::deleteFilesOnError() const
111 {
112         // currently just a dummy function.
113
114         // What files do we have to delete?
115
116         // This will at least make latex do all the runs
117         depfile.removeFile();
118
119         // but the reason for the error might be in a generated file...
120
121         // bibtex file
122         FileName const bbl(changeExtension(file.absFileName(), ".bbl"));
123         bbl.removeFile();
124
125         // biber file
126         FileName const bcf(changeExtension(file.absFileName(), ".bcf"));
127         bcf.removeFile();
128
129         // makeindex file
130         FileName const ind(changeExtension(file.absFileName(), ".ind"));
131         ind.removeFile();
132
133         // nomencl file
134         FileName const nls(changeExtension(file.absFileName(), ".nls"));
135         nls.removeFile();
136
137         // nomencl file (old version of the package)
138         FileName const gls(changeExtension(file.absFileName(), ".gls"));
139         gls.removeFile();
140
141         // Also remove the aux file
142         FileName const aux(changeExtension(file.absFileName(), ".aux"));
143         aux.removeFile();
144 }
145
146
147 int LaTeX::run(TeXErrors & terr)
148         // We know that this function will only be run if the lyx buffer
149         // has been changed. We also know that a newly written .tex file
150         // is always different from the previous one because of the date
151         // in it. However it seems safe to run latex (at least) one time
152         // each time the .tex file changes.
153 {
154         int scanres = NO_ERRORS;
155         unsigned int count = 0; // number of times run
156         num_errors = 0; // just to make sure.
157         unsigned int const MAX_RUN = 6;
158         DepTable head; // empty head
159         bool rerun = false; // rerun requested
160
161         // The class LaTeX does not know the temp path.
162         theBufferList().updateIncludedTeXfiles(FileName::getcwd().absFileName(),
163                 runparams);
164
165         // Never write the depfile if an error was encountered.
166
167         // 0
168         // first check if the file dependencies exist:
169         //     ->If it does exist
170         //             check if any of the files mentioned in it have
171         //             changed (done using a checksum).
172         //                 -> if changed:
173         //                        run latex once and
174         //                        remake the dependency file
175         //                 -> if not changed:
176         //                        just return there is nothing to do for us.
177         //     ->if it doesn't exist
178         //             make it and
179         //             run latex once (we need to run latex once anyway) and
180         //             remake the dependency file.
181         //
182
183         bool had_depfile = depfile.exists();
184         bool run_bibtex = false;
185         FileName const aux_file(changeExtension(file.absFileName(), "aux"));
186
187         if (had_depfile) {
188                 LYXERR(Debug::DEPEND, "Dependency file exists");
189                 // Read the dep file:
190                 had_depfile = head.read(depfile);
191         }
192
193         if (had_depfile) {
194                 // Update the checksums
195                 head.update();
196                 // Can't just check if anything has changed because it might
197                 // have aborted on error last time... in which cas we need
198                 // to re-run latex and collect the error messages
199                 // (even if they are the same).
200                 if (!output_file.exists()) {
201                         LYXERR(Debug::DEPEND,
202                                 "re-running LaTeX because output file doesn't exist.");
203                 } else if (!head.sumchange()) {
204                         LYXERR(Debug::DEPEND, "return no_change");
205                         return NO_CHANGE;
206                 } else {
207                         LYXERR(Debug::DEPEND, "Dependency file has changed");
208                 }
209
210                 if (head.extchanged(".bib") || head.extchanged(".bst"))
211                         run_bibtex = true;
212         } else
213                 LYXERR(Debug::DEPEND,
214                         "Dependency file does not exist, or has wrong format");
215
216         /// We scan the aux file even when had_depfile = false,
217         /// because we can run pdflatex on the file after running latex on it,
218         /// in which case we will not need to run bibtex again.
219         vector<AuxInfo> bibtex_info_old;
220         if (!run_bibtex)
221                 bibtex_info_old = scanAuxFiles(aux_file);
222
223         ++count;
224         LYXERR(Debug::LATEX, "Run #" << count);
225         message(runMessage(count));
226
227         startscript();
228         scanres = scanLogFile(terr);
229         if (scanres & ERROR_RERUN) {
230                 LYXERR(Debug::LATEX, "Rerunning LaTeX");
231                 startscript();
232                 scanres = scanLogFile(terr);
233         }
234
235         if (scanres & ERRORS) {
236                 deleteFilesOnError();
237                 return scanres; // return on error
238         }
239
240         vector<AuxInfo> const bibtex_info = scanAuxFiles(aux_file);
241         if (!run_bibtex && bibtex_info_old != bibtex_info)
242                 run_bibtex = true;
243
244         // update the dependencies.
245         deplog(head); // reads the latex log
246         head.update();
247
248         // 1
249         // At this point we must run external programs if needed.
250         // makeindex will be run if a .idx file changed or was generated.
251         // And if there were undefined citations or changes in references
252         // the .aux file is checked for signs of bibtex. Bibtex is then run
253         // if needed.
254
255         // memoir (at least) writes an empty *idx file in the first place.
256         // A second latex run is needed.
257         FileName const idxfile(changeExtension(file.absFileName(), ".idx"));
258         rerun = idxfile.exists() && idxfile.isFileEmpty();
259
260         // run makeindex
261         if (head.haschanged(idxfile)) {
262                 // no checks for now
263                 LYXERR(Debug::LATEX, "Running MakeIndex.");
264                 message(_("Running Index Processor."));
265                 // onlyFileName() is needed for cygwin
266                 rerun |= runMakeIndex(onlyFileName(idxfile.absFileName()),
267                                 runparams);
268         }
269         FileName const nlofile(changeExtension(file.absFileName(), ".nlo"));
270         if (head.haschanged(nlofile))
271                 rerun |= runMakeIndexNomencl(file, ".nlo", ".nls");
272         FileName const glofile(changeExtension(file.absFileName(), ".glo"));
273         if (head.haschanged(glofile))
274                 rerun |= runMakeIndexNomencl(file, ".glo", ".gls");
275
276         // check if we're using biber instead of bibtex
277         // biber writes no info to the aux file, so we just check
278         // if a bcf file exists (and if it was updated)
279         FileName const bcffile(changeExtension(file.absFileName(), ".bcf"));
280         bool const biber = head.exist(bcffile);
281
282         // run bibtex
283         // if (scanres & UNDEF_CIT || scanres & RERUN || run_bibtex)
284         if (scanres & UNDEF_CIT || run_bibtex) {
285                 // Here we must scan the .aux file and look for
286                 // "\bibdata" and/or "\bibstyle". If one of those
287                 // tags is found -> run bibtex and set rerun = true;
288                 // no checks for now
289                 LYXERR(Debug::LATEX, "Running BibTeX.");
290                 message(_("Running BibTeX."));
291                 updateBibtexDependencies(head, bibtex_info, biber);
292                 rerun |= runBibTeX(bibtex_info, runparams, biber);
293                 if (biber) {
294                         // since biber writes no info to the aux file, we have
295                         // to parse the blg file (which only exists after biber
296                         // was first issued)
297                         FileName const blgfile(changeExtension(file.absFileName(), ".blg"));
298                         if (blgfile.exists())
299                                 scanBlgFile(head);
300                 }
301         } else if (!had_depfile) {
302                 /// If we run pdflatex on the file after running latex on it,
303                 /// then we do not need to run bibtex, but we do need to
304                 /// insert the .bib and .bst files into the .dep-pdf file.
305                 updateBibtexDependencies(head, bibtex_info, biber);
306         }
307
308         // 2
309         // we know on this point that latex has been run once (or we just
310         // returned) and the question now is to decide if we need to run
311         // it any more. This is done by asking if any of the files in the
312         // dependency file has changed. (remember that the checksum for
313         // a given file is reported to have changed if it just was created)
314         //     -> if changed or rerun == true:
315         //             run latex once more and
316         //             update the dependency structure
317         //     -> if not changed:
318         //             we do nothing at this point
319         //
320         if (rerun || head.sumchange()) {
321                 rerun = false;
322                 ++count;
323                 LYXERR(Debug::DEPEND, "Dep. file has changed or rerun requested");
324                 LYXERR(Debug::LATEX, "Run #" << count);
325                 message(runMessage(count));
326                 startscript();
327                 scanres = scanLogFile(terr);
328                 if (scanres & ERRORS) {
329                         deleteFilesOnError();
330                         return scanres; // return on error
331                 }
332
333                 // update the depedencies
334                 deplog(head); // reads the latex log
335                 head.update();
336         } else {
337                 LYXERR(Debug::DEPEND, "Dep. file has NOT changed");
338         }
339         
340         // 3
341         // rerun bibtex?
342         // Complex bibliography packages such as Biblatex require
343         // an additional bibtex cycle sometimes.
344         if (scanres & UNDEF_CIT) {
345                 // Here we must scan the .aux file and look for
346                 // "\bibdata" and/or "\bibstyle". If one of those
347                 // tags is found -> run bibtex and set rerun = true;
348                 // no checks for now
349                 LYXERR(Debug::LATEX, "Running BibTeX.");
350                 message(_("Running BibTeX."));
351                 updateBibtexDependencies(head, bibtex_info, biber);
352                 rerun |= runBibTeX(bibtex_info, runparams, biber);
353         }
354
355         // 4
356         // The inclusion of files generated by external programs such as
357         // makeindex or bibtex might have done changes to pagenumbering,
358         // etc. And because of this we must run the external programs
359         // again to make sure everything is redone correctly.
360         // Also there should be no need to run the external programs any
361         // more after this.
362
363         // run makeindex if the <file>.idx has changed or was generated.
364         if (head.haschanged(idxfile)) {
365                 // no checks for now
366                 LYXERR(Debug::LATEX, "Running MakeIndex.");
367                 message(_("Running Index Processor."));
368                 // onlyFileName() is needed for cygwin
369                 rerun = runMakeIndex(onlyFileName(changeExtension(
370                                 file.absFileName(), ".idx")), runparams);
371         }
372
373         // I am not pretty sure if need this twice.
374         if (head.haschanged(nlofile))
375                 rerun |= runMakeIndexNomencl(file, ".nlo", ".nls");
376         if (head.haschanged(glofile))
377                 rerun |= runMakeIndexNomencl(file, ".glo", ".gls");
378
379         // 5
380         // we will only run latex more if the log file asks for it.
381         // or if the sumchange() is true.
382         //     -> rerun asked for:
383         //             run latex and
384         //             remake the dependency file
385         //             goto 2 or return if max runs are reached.
386         //     -> rerun not asked for:
387         //             just return (fall out of bottom of func)
388         //
389         while ((head.sumchange() || rerun || (scanres & RERUN))
390                && count < MAX_RUN) {
391                 // Yes rerun until message goes away, or until
392                 // MAX_RUNS are reached.
393                 rerun = false;
394                 ++count;
395                 LYXERR(Debug::LATEX, "Run #" << count);
396                 message(runMessage(count));
397                 startscript();
398                 scanres = scanLogFile(terr);
399                 if (scanres & ERRORS) {
400                         deleteFilesOnError();
401                         return scanres; // return on error
402                 }
403
404                 // keep this updated
405                 head.update();
406         }
407
408         // Write the dependencies to file.
409         head.write(depfile);
410         LYXERR(Debug::LATEX, "Done.");
411         return scanres;
412 }
413
414
415 int LaTeX::startscript()
416 {
417         // onlyFileName() is needed for cygwin
418         string tmp = cmd + ' '
419                      + quoteName(onlyFileName(file.toFilesystemEncoding()))
420                      + " > " + os::nulldev();
421         Systemcall one;
422         return one.startscript(Systemcall::Wait, tmp);
423 }
424
425
426 bool LaTeX::runMakeIndex(string const & f, OutputParams const & runparams,
427                          string const & params)
428 {
429         string tmp = runparams.use_japanese ?
430                 lyxrc.jindex_command : lyxrc.index_command;
431         
432         if (!runparams.index_command.empty())
433                 tmp = runparams.index_command;
434
435         LYXERR(Debug::LATEX,
436                 "idx file has been made, running index processor ("
437                 << tmp << ") on file " << f);
438
439         tmp = subst(tmp, "$$lang", runparams.document_language);
440         if (runparams.use_indices) {
441                 tmp = lyxrc.splitindex_command + " -m " + quoteName(tmp);
442                 LYXERR(Debug::LATEX,
443                 "Multiple indices. Using splitindex command: " << tmp);
444         }
445         tmp += ' ';
446         tmp += quoteName(f);
447         tmp += params;
448         Systemcall one;
449         one.startscript(Systemcall::Wait, tmp);
450         return true;
451 }
452
453
454 bool LaTeX::runMakeIndexNomencl(FileName const & file,
455                 string const & nlo, string const & nls)
456 {
457         LYXERR(Debug::LATEX, "Running MakeIndex for nomencl.");
458         message(_("Running MakeIndex for nomencl."));
459         string tmp = lyxrc.nomencl_command + ' ';
460         // onlyFileName() is needed for cygwin
461         tmp += quoteName(onlyFileName(changeExtension(file.absFileName(), nlo)));
462         tmp += " -o "
463                 + onlyFileName(changeExtension(file.toFilesystemEncoding(), nls));
464         Systemcall one;
465         one.startscript(Systemcall::Wait, tmp);
466         return true;
467 }
468
469
470 vector<AuxInfo> const
471 LaTeX::scanAuxFiles(FileName const & file)
472 {
473         vector<AuxInfo> result;
474
475         result.push_back(scanAuxFile(file));
476
477         string const basename = removeExtension(file.absFileName());
478         for (int i = 1; i < 1000; ++i) {
479                 FileName const file2(basename
480                         + '.' + convert<string>(i)
481                         + ".aux");
482                 if (!file2.exists())
483                         break;
484                 result.push_back(scanAuxFile(file2));
485         }
486         return result;
487 }
488
489
490 AuxInfo const LaTeX::scanAuxFile(FileName const & file)
491 {
492         AuxInfo result;
493         result.aux_file = file;
494         scanAuxFile(file, result);
495         return result;
496 }
497
498
499 void LaTeX::scanAuxFile(FileName const & file, AuxInfo & aux_info)
500 {
501         LYXERR(Debug::LATEX, "Scanning aux file: " << file);
502
503         ifstream ifs(file.toFilesystemEncoding().c_str());
504         string token;
505         static regex const reg1("\\\\citation\\{([^}]+)\\}");
506         static regex const reg2("\\\\bibdata\\{([^}]+)\\}");
507         static regex const reg3("\\\\bibstyle\\{([^}]+)\\}");
508         static regex const reg4("\\\\@input\\{([^}]+)\\}");
509
510         while (getline(ifs, token)) {
511                 token = rtrim(token, "\r");
512                 smatch sub;
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()) {
519                                 string citation;
520                                 data = split(data, citation, ',');
521                                 LYXERR(Debug::LATEX, "Citation: " << citation);
522                                 aux_info.citations.insert(citation);
523                         }
524                 } else if (regex_match(token, sub, reg2)) {
525                         string data = sub.str(1);
526                         // data is now all the bib files separated by ','
527                         // get them one by one and pass them to the helper
528                         while (!data.empty()) {
529                                 string database;
530                                 data = split(data, database, ',');
531                                 database = changeExtension(database, "bib");
532                                 LYXERR(Debug::LATEX, "BibTeX database: `" << database << '\'');
533                                 aux_info.databases.insert(database);
534                         }
535                 } else if (regex_match(token, sub, reg3)) {
536                         string style = sub.str(1);
537                         // token is now the style file
538                         // pass it to the helper
539                         style = changeExtension(style, "bst");
540                         LYXERR(Debug::LATEX, "BibTeX style: `" << style << '\'');
541                         aux_info.styles.insert(style);
542                 } else if (regex_match(token, sub, reg4)) {
543                         string const file2 = sub.str(1);
544                         scanAuxFile(makeAbsPath(file2), aux_info);
545                 }
546         }
547 }
548
549
550 void LaTeX::updateBibtexDependencies(DepTable & dep,
551                                      vector<AuxInfo> const & bibtex_info,
552                                      bool biber)
553 {
554         // Since a run of Bibtex mandates more latex runs it is ok to
555         // remove all ".bib" and ".bst" files.
556         dep.remove_files_with_extension(".bib");
557         dep.remove_files_with_extension(".bst");
558         //string aux = OnlyFileName(ChangeExtension(file, ".aux"));
559
560         for (vector<AuxInfo>::const_iterator it = bibtex_info.begin();
561              it != bibtex_info.end(); ++it) {
562                 for (set<string>::const_iterator it2 = it->databases.begin();
563                      it2 != it->databases.end(); ++it2) {
564                         FileName const file = findtexfile(*it2, "bib");
565                         if (!file.empty())
566                                 dep.insert(file, true);
567                 }
568
569                 for (set<string>::const_iterator it2 = it->styles.begin();
570                      it2 != it->styles.end(); ++it2) {
571                         FileName const file = findtexfile(*it2, "bst");
572                         if (!file.empty())
573                                 dep.insert(file, true);
574                 }
575         }
576
577         // biber writes nothing into the aux file.
578         // Instead, we have to scan the blg file
579         if (biber) {
580                 scanBlgFile(dep);
581         }
582 }
583
584
585 bool LaTeX::runBibTeX(vector<AuxInfo> const & bibtex_info,
586                       OutputParams const & runparams, bool biber)
587 {
588         bool result = false;
589         for (vector<AuxInfo>::const_iterator it = bibtex_info.begin();
590              it != bibtex_info.end(); ++it) {
591                 if (!biber && it->databases.empty())
592                         continue;
593                 result = true;
594
595                 string tmp = runparams.use_japanese ?
596                         lyxrc.jbibtex_command : lyxrc.bibtex_command;
597
598                 if (!runparams.bibtex_command.empty())
599                         tmp = runparams.bibtex_command;
600                 tmp += " ";
601                 // onlyFileName() is needed for cygwin
602                 tmp += quoteName(onlyFileName(removeExtension(
603                                 it->aux_file.absFileName())));
604                 Systemcall one;
605                 one.startscript(Systemcall::Wait, tmp);
606         }
607         // Return whether bibtex was run
608         return result;
609 }
610
611
612 int LaTeX::scanLogFile(TeXErrors & terr)
613 {
614         int last_line = -1;
615         int line_count = 1;
616         int retval = NO_ERRORS;
617         string tmp =
618                 onlyFileName(changeExtension(file.absFileName(), ".log"));
619         LYXERR(Debug::LATEX, "Log file: " << tmp);
620         FileName const fn = FileName(makeAbsPath(tmp));
621         ifstream ifs(fn.toFilesystemEncoding().c_str());
622         bool fle_style = false;
623         static regex file_line_error(".+\\.\\D+:[0-9]+: (.+)");
624         // Flag for 'File ended while scanning' message.
625         // We need to wait for subsequent processing.
626         string wait_for_error;
627
628         string token;
629         while (getline(ifs, token)) {
630                 // MikTeX sometimes inserts \0 in the log file. They can't be
631                 // removed directly with the existing string utility
632                 // functions, so convert them first to \r, and remove all
633                 // \r's afterwards, since we need to remove them anyway.
634                 token = subst(token, '\0', '\r');
635                 token = subst(token, "\r", "");
636                 smatch sub;
637
638                 LYXERR(Debug::LATEX, "Log line: " << token);
639
640                 if (token.empty())
641                         continue;
642
643                 if (contains(token, "file:line:error style messages enabled"))
644                         fle_style = true;
645
646                 if (prefixIs(token, "LaTeX Warning:") ||
647                     prefixIs(token, "! pdfTeX warning")) {
648                         // Here shall we handle different
649                         // types of warnings
650                         retval |= LATEX_WARNING;
651                         LYXERR(Debug::LATEX, "LaTeX Warning.");
652                         if (contains(token, "Rerun to get cross-references")) {
653                                 retval |= RERUN;
654                                 LYXERR(Debug::LATEX, "We should rerun.");
655                         // package clefval needs 2 latex runs before bibtex
656                         } else if (contains(token, "Value of")
657                                    && contains(token, "on page")
658                                    && contains(token, "undefined")) {
659                                 retval |= ERROR_RERUN;
660                                 LYXERR(Debug::LATEX, "Force rerun.");
661                         // package etaremune
662                         } else if (contains(token, "Etaremune labels have changed")) {
663                                 retval |= ERROR_RERUN;
664                                 LYXERR(Debug::LATEX, "Force rerun.");
665                         } else if (contains(token, "Citation")
666                                    && contains(token, "on page")
667                                    && contains(token, "undefined")) {
668                                 retval |= UNDEF_CIT;
669                         }
670                 } else if (prefixIs(token, "Package")) {
671                         // Package warnings
672                         retval |= PACKAGE_WARNING;
673                         if (contains(token, "natbib Warning:")) {
674                                 // Natbib warnings
675                                 if (contains(token, "Citation")
676                                     && contains(token, "on page")
677                                     && contains(token, "undefined")) {
678                                         retval |= UNDEF_CIT;
679                                 }
680                         } else if (contains(token, "run BibTeX")) {
681                                 retval |= UNDEF_CIT;
682                         } else if (contains(token, "Rerun LaTeX") ||
683                                    contains(token, "Please rerun LaTeX") ||
684                                    contains(token, "Rerun to get")) {
685                                 // at least longtable.sty and bibtopic.sty
686                                 // might use this.
687                                 LYXERR(Debug::LATEX, "We should rerun.");
688                                 retval |= RERUN;
689                         }
690                 } else if (prefixIs(token, "LETTRE WARNING:")) {
691                         if (contains(token, "veuillez recompiler")) {
692                                 // lettre.cls
693                                 LYXERR(Debug::LATEX, "We should rerun.");
694                                 retval |= RERUN;
695                         }
696                 } else if (token[0] == '(') {
697                         if (contains(token, "Rerun LaTeX") ||
698                             contains(token, "Rerun to get")) {
699                                 // Used by natbib
700                                 LYXERR(Debug::LATEX, "We should rerun.");
701                                 retval |= RERUN;
702                         }
703                 } else if (prefixIs(token, "! ")
704                             || (fle_style
705                                 && regex_match(token, sub, file_line_error)
706                                 && !contains(token, "pdfTeX warning"))) {
707                            // Ok, we have something that looks like a TeX Error
708                            // but what do we really have.
709
710                         // Just get the error description:
711                         string desc;
712                         if (prefixIs(token, "! "))
713                                 desc = string(token, 2);
714                         else if (fle_style)
715                                 desc = sub.str();
716                         if (contains(token, "LaTeX Error:"))
717                                 retval |= LATEX_ERROR;
718
719                         // bug 6445. At this point its not clear we finish with error.
720                         if (prefixIs(token, "! File ended while scanning")){
721                                 wait_for_error = desc;
722                                 continue;
723                         }
724                         if (!wait_for_error.empty() && prefixIs(token, "! Emergency stop.")){
725                                 retval |= LATEX_ERROR;
726                                 string errstr;
727                                 int count = 0;
728                                 errstr = wait_for_error;
729                                 do {
730                                         if (!getline(ifs, tmp))
731                                                 break;
732                                         errstr += "\n" + tmp;
733                                         if (++count > 5)
734                                                 break;
735                                 } while (!contains(tmp, "(job aborted"));
736
737                                 terr.insertError(0,
738                                                  from_local8bit("Emergency stop"),
739                                                  from_local8bit(errstr));
740                         }
741
742                         // get the next line
743                         string tmp;
744                         int count = 0;
745                         do {
746                                 if (!getline(ifs, tmp))
747                                         break;
748                                 if (++count > 10)
749                                         break;
750                         } while (!prefixIs(tmp, "l."));
751                         if (prefixIs(tmp, "l.")) {
752                                 // we have a latex error
753                                 retval |=  TEX_ERROR;
754                                 if (contains(desc,
755                                     "Package babel Error: You haven't defined the language") ||
756                                     contains(desc,
757                                     "Package babel Error: You haven't loaded the option"))
758                                         retval |= ERROR_RERUN;
759                                 // get the line number:
760                                 int line = 0;
761                                 sscanf(tmp.c_str(), "l.%d", &line);
762                                 // get the rest of the message:
763                                 string errstr(tmp, tmp.find(' '));
764                                 errstr += '\n';
765                                 getline(ifs, tmp);
766                                 while (!contains(errstr, "l.")
767                                        && !tmp.empty()
768                                        && !prefixIs(tmp, "! ")
769                                        && !contains(tmp, "(job aborted")) {
770                                         errstr += tmp;
771                                         errstr += "\n";
772                                         getline(ifs, tmp);
773                                 }
774                                 LYXERR(Debug::LATEX, "line: " << line << '\n'
775                                         << "Desc: " << desc << '\n' << "Text: " << errstr);
776                                 if (line == last_line)
777                                         ++line_count;
778                                 else {
779                                         line_count = 1;
780                                         last_line = line;
781                                 }
782                                 if (line_count <= 5) {
783                                         // FIXME UNICODE
784                                         // We have no idea what the encoding of
785                                         // the log file is.
786                                         // It seems that the output from the
787                                         // latex compiler itself is pure ASCII,
788                                         // but it can include bits from the
789                                         // document, so whatever encoding we
790                                         // assume here it can be wrong.
791                                         terr.insertError(line,
792                                                          from_local8bit(desc),
793                                                          from_local8bit(errstr));
794                                         ++num_errors;
795                                 }
796                         }
797                 } else {
798                         // information messages, TeX warnings and other
799                         // warnings we have not caught earlier.
800                         if (prefixIs(token, "Overfull ")) {
801                                 retval |= TEX_WARNING;
802                         } else if (prefixIs(token, "Underfull ")) {
803                                 retval |= TEX_WARNING;
804                         } else if (contains(token, "Rerun to get citations")) {
805                                 // Natbib seems to use this.
806                                 retval |= UNDEF_CIT;
807                         } else if (contains(token, "No pages of output")) {
808                                 // A dvi file was not created
809                                 retval |= NO_OUTPUT;
810                         } else if (contains(token, "That makes 100 errors")) {
811                                 // More than 100 errors were reprted
812                                 retval |= TOO_MANY_ERRORS;
813                         } else if (prefixIs(token, "!pdfTeX error:")){
814                                 // otherwise we dont catch e.g.:
815                                 // !pdfTeX error: pdflatex (file feyn10): Font feyn10 at 600 not found
816                                 retval |= ERRORS;
817                                         terr.insertError(0,
818                                                          from_local8bit("pdfTeX Error"),
819                                                          from_local8bit(token));
820                         }
821                 }
822         }
823         LYXERR(Debug::LATEX, "Log line: " << token);
824         return retval;
825 }
826
827
828 namespace {
829
830 bool insertIfExists(FileName const & absname, DepTable & head)
831 {
832         if (absname.exists() && !absname.isDirectory()) {
833                 head.insert(absname, true);
834                 return true;
835         }
836         return false;
837 }
838
839
840 bool handleFoundFile(string const & ff, DepTable & head)
841 {
842         // convert from native os path to unix path
843         string foundfile = os::internal_path(trim(ff));
844
845         LYXERR(Debug::DEPEND, "Found file: " << foundfile);
846
847         // Ok now we found a file.
848         // Now we should make sure that this is a file that we can
849         // access through the normal paths.
850         // We will not try any fancy search methods to
851         // find the file.
852
853         // (1) foundfile is an
854         //     absolute path and should
855         //     be inserted.
856         FileName absname;
857         if (FileName::isAbsolute(foundfile)) {
858                 LYXERR(Debug::DEPEND, "AbsolutePath file: " << foundfile);
859                 // On initial insert we want to do the update at once
860                 // since this file cannot be a file generated by
861                 // the latex run.
862                 absname.set(foundfile);
863                 if (!insertIfExists(absname, head)) {
864                         // check for spaces
865                         string strippedfile = foundfile;
866                         while (contains(strippedfile, " ")) {
867                                 // files with spaces are often enclosed in quotation
868                                 // marks; those have to be removed
869                                 string unquoted = subst(strippedfile, "\"", "");
870                                 absname.set(unquoted);
871                                 if (insertIfExists(absname, head))
872                                         return true;
873                                 // strip off part after last space and try again
874                                 string tmp = strippedfile;
875                                 string const stripoff =
876                                         rsplit(tmp, strippedfile, ' ');
877                                 absname.set(strippedfile);
878                                 if (insertIfExists(absname, head))
879                                         return true;
880                         }
881                 }
882         }
883
884         string onlyfile = onlyFileName(foundfile);
885         absname = makeAbsPath(onlyfile);
886
887         // check for spaces
888         while (contains(foundfile, ' ')) {
889                 if (absname.exists())
890                         // everything o.k.
891                         break;
892                 else {
893                         // files with spaces are often enclosed in quotation
894                         // marks; those have to be removed
895                         string unquoted = subst(foundfile, "\"", "");
896                         absname = makeAbsPath(unquoted);
897                         if (absname.exists())
898                                 break;
899                         // strip off part after last space and try again
900                         string strippedfile;
901                         string const stripoff =
902                                 rsplit(foundfile, strippedfile, ' ');
903                         foundfile = strippedfile;
904                         onlyfile = onlyFileName(strippedfile);
905                         absname = makeAbsPath(onlyfile);
906                 }
907         }
908
909         // (2) foundfile is in the tmpdir
910         //     insert it into head
911         if (absname.exists() && !absname.isDirectory()) {
912                 // FIXME: This regex contained glo, but glo is used by the old
913                 // version of nomencl.sty. Do we need to put it back?
914                 static regex const unwanted("^.*\\.(aux|log|dvi|bbl|ind)$");
915                 if (regex_match(onlyfile, unwanted)) {
916                         LYXERR(Debug::DEPEND, "We don't want " << onlyfile
917                                 << " in the dep file");
918                 } else if (suffixIs(onlyfile, ".tex")) {
919                         // This is a tex file generated by LyX
920                         // and latex is not likely to change this
921                         // during its runs.
922                         LYXERR(Debug::DEPEND, "Tmpdir TeX file: " << onlyfile);
923                         head.insert(absname, true);
924                 } else {
925                         LYXERR(Debug::DEPEND, "In tmpdir file:" << onlyfile);
926                         head.insert(absname);
927                 }
928                 return true;
929         } else {
930                 LYXERR(Debug::DEPEND, "Not a file or we are unable to find it.");
931                 return false;
932         }
933 }
934
935
936 bool checkLineBreak(string const & ff, DepTable & head)
937 {
938         if (!contains(ff, '.'))
939                 return false;
940
941         // if we have a dot, we let handleFoundFile decide
942         return handleFoundFile(ff, head);
943 }
944
945 } // anon namespace
946
947
948 void LaTeX::deplog(DepTable & head)
949 {
950         // This function reads the LaTeX log file end extracts all the
951         // external files used by the LaTeX run. The files are then
952         // entered into the dependency file.
953
954         string const logfile =
955                 onlyFileName(changeExtension(file.absFileName(), ".log"));
956
957         static regex const reg1("File: (.+).*");
958         static regex const reg2("No file (.+)(.).*");
959         static regex const reg3("\\\\openout[0-9]+.*=.*`(.+)(..).*");
960         // If an index should be created, MikTex does not write a line like
961         //    \openout# = 'sample.idx'.
962         // but instead only a line like this into the log:
963         //   Writing index file sample.idx
964         static regex const reg4("Writing index file (.+).*");
965         // files also can be enclosed in <...>
966         static regex const reg5("<([^>]+)(.).*");
967         static regex const regoldnomencl("Writing glossary file (.+).*");
968         static regex const regnomencl("Writing nomenclature file (.+).*");
969         // If a toc should be created, MikTex does not write a line like
970         //    \openout# = `sample.toc'.
971         // but only a line like this into the log:
972         //    \tf@toc=\write#
973         // This line is also written by tetex.
974         // This line is not present if no toc should be created.
975         static regex const miktexTocReg("\\\\tf@toc=\\\\write.*");
976         static regex const reg6(".*\\([^)]+.*");
977
978         FileName const fn = makeAbsPath(logfile);
979         ifstream ifs(fn.toFilesystemEncoding().c_str());
980         string lastline;
981         while (ifs) {
982                 // Ok, the scanning of files here is not sufficient.
983                 // Sometimes files are named by "File:� xxx" only
984                 // So I think we should use some regexps to find files instead.
985                 // Note: all file names and paths might contains spaces.
986                 bool found_file = false;
987                 string token;
988                 getline(ifs, token);
989                 // MikTeX sometimes inserts \0 in the log file. They can't be
990                 // removed directly with the existing string utility
991                 // functions, so convert them first to \r, and remove all
992                 // \r's afterwards, since we need to remove them anyway.
993                 token = subst(token, '\0', '\r');
994                 token = subst(token, "\r", "");
995                 if (token.empty() || token == ")") {
996                         lastline = string();
997                         continue;
998                 }
999
1000                 // Sometimes, filenames are broken across lines.
1001                 // We care for that and save suspicious lines.
1002                 // Here we exclude some cases where we are sure
1003                 // that there is no continued filename
1004                 if (!lastline.empty()) {
1005                         static regex const package_info("Package \\w+ Info: .*");
1006                         static regex const package_warning("Package \\w+ Warning: .*");
1007                         if (prefixIs(token, "File:") || prefixIs(token, "(Font)")
1008                             || prefixIs(token, "Package:")
1009                             || prefixIs(token, "Language:")
1010                             || prefixIs(token, "LaTeX Info:")
1011                             || prefixIs(token, "LaTeX Font Info:")
1012                             || prefixIs(token, "\\openout[")
1013                             || prefixIs(token, "))")
1014                             || regex_match(token, package_info)
1015                             || regex_match(token, package_warning))
1016                                 lastline = string();
1017                 }
1018
1019                 if (!lastline.empty())
1020                         // probably a continued filename from last line
1021                         token = lastline + token;
1022                 if (token.length() > 255) {
1023                         // string too long. Cut off.
1024                         token.erase(0, token.length() - 251);
1025                 }
1026
1027                 smatch sub;
1028
1029                 // FIXME UNICODE: We assume that the file names in the log
1030                 // file are in the file system encoding.
1031                 token = to_utf8(from_filesystem8bit(token));
1032
1033                 // (1) "File: file.ext"
1034                 if (regex_match(token, sub, reg1)) {
1035                         // check for dot
1036                         found_file = checkLineBreak(sub.str(1), head);
1037                         // However, ...
1038                         if (suffixIs(token, ")"))
1039                                 // no line break for sure
1040                                 // pretend we've been successfully searching
1041                                 found_file = true;
1042                 // (2) "No file file.ext"
1043                 } else if (regex_match(token, sub, reg2)) {
1044                         // file names must contains a dot, line ends with dot
1045                         if (contains(sub.str(1), '.') && sub.str(2) == ".")
1046                                 found_file = handleFoundFile(sub.str(1), head);
1047                         else
1048                                 // we suspect a line break
1049                                 found_file = false;
1050                 // (3) "\openout<nr> = `file.ext'."
1051                 } else if (regex_match(token, sub, reg3)) {
1052                         // search for closing '. at the end of the line
1053                         if (sub.str(2) == "\'.")
1054                                 found_file = handleFoundFile(sub.str(1), head);
1055                         else
1056                                 // probable line break
1057                                 found_file = false;
1058                 // (4) "Writing index file file.ext"
1059                 } else if (regex_match(token, sub, reg4))
1060                         // check for dot
1061                         found_file = checkLineBreak(sub.str(1), head);
1062                 // (5) "<file.ext>"
1063                 else if (regex_match(token, sub, reg5)) {
1064                         // search for closing '>' and dot ('*.*>') at the eol
1065                         if (contains(sub.str(1), '.') && sub.str(2) == ">")
1066                                 found_file = handleFoundFile(sub.str(1), head);
1067                         else
1068                                 // probable line break
1069                                 found_file = false;
1070                 // (6) "Writing nomenclature file file.ext"
1071                 } else if (regex_match(token, sub, regnomencl) ||
1072                            regex_match(token, sub, regoldnomencl))
1073                         // check for dot
1074                         found_file = checkLineBreak(sub.str(1), head);
1075                 // (7) "\tf@toc=\write<nr>" (for MikTeX)
1076                 else if (regex_match(token, sub, miktexTocReg))
1077                         found_file = handleFoundFile(onlyFileName(changeExtension(
1078                                                 file.absFileName(), ".toc")), head);
1079                 else
1080                         // not found, but we won't check further
1081                         // pretend we've been successfully searching
1082                         found_file = true;
1083
1084                 // (8) "(file.ext"
1085                 // note that we can have several of these on one line
1086                 // this must be queried separated, because of
1087                 // cases such as "File: file.ext (type eps)"
1088                 // where "File: file.ext" would be skipped
1089                 if (regex_match(token, sub, reg6)) {
1090                         // search for strings in (...)
1091                         static regex reg6_1("\\(([^()]+)(.)");
1092                         smatch what;
1093                         string::const_iterator first = token.begin();
1094                         string::const_iterator end = token.end();
1095
1096                         while (regex_search(first, end, what, reg6_1)) {
1097                                 // if we have a dot, try to handle as file
1098                                 if (contains(what.str(1), '.')) {
1099                                         first = what[0].second;
1100                                         if (what.str(2) == ")") {
1101                                                 handleFoundFile(what.str(1), head);
1102                                                 // since we had a closing bracket,
1103                                                 // do not investigate further
1104                                                 found_file = true;
1105                                         } else
1106                                                 // if we have no closing bracket,
1107                                                 // try to handle as file nevertheless
1108                                                 found_file = handleFoundFile(
1109                                                         what.str(1) + what.str(2), head);
1110                                 }
1111                                 // if we do not have a dot, check if the line has
1112                                 // a closing bracket (else, we suspect a line break)
1113                                 else if (what.str(2) != ")") {
1114                                         first = what[0].second;
1115                                         found_file = false;
1116                                 } else {
1117                                         // we have a closing bracket, so the content
1118                                         // is not a file name.
1119                                         // no need to investigate further
1120                                         // pretend we've been successfully searching
1121                                         first = what[0].second;
1122                                         found_file = true;
1123                                 }
1124                         }
1125                 }
1126
1127                 if (!found_file)
1128                         // probable linebreak:
1129                         // save this line
1130                         lastline = token;
1131                 else
1132                         // no linebreak: reset
1133                         lastline = string();
1134         }
1135
1136         // Make sure that the main .tex file is in the dependency file.
1137         head.insert(file, true);
1138 }
1139
1140
1141 void LaTeX::scanBlgFile(DepTable & dep)
1142 {
1143         FileName const blg_file(changeExtension(file.absFileName(), "blg"));
1144         LYXERR(Debug::LATEX, "Scanning blg file: " << blg_file);
1145
1146         ifstream ifs(blg_file.toFilesystemEncoding().c_str());
1147         string token;
1148         static regex const reg1(".*Found bibtex data file '([^']+).*");
1149
1150         while (getline(ifs, token)) {
1151                 token = rtrim(token, "\r");
1152                 smatch sub;
1153                 // FIXME UNICODE: We assume that citation keys and filenames
1154                 // in the aux file are in the file system encoding.
1155                 token = to_utf8(from_filesystem8bit(token));
1156                 if (regex_match(token, sub, reg1)) {
1157                         string data = sub.str(1);
1158                         if (!data.empty()) {
1159                                 LYXERR(Debug::LATEX, "Found bib file: " << data);
1160                                 handleFoundFile(data, dep);
1161                         }
1162                 }
1163         } 
1164 }
1165
1166
1167 } // namespace lyx