/* This file is part of
- * ======================================================
+ * ======================================================
*
* LyX, The Document Processor
* Copyright 1995 Matthias Ettrich
- * Copyright 1995-1999 The LyX Team.
+ * Copyright 1995-2000 The LyX Team.
*
- * This file is Copyright 1996-1999
+ * This file is Copyright 1996-2000
* Lars Gullik Bjønnes
*
- * ======================================================
+ * ======================================================
*/
#include <config.h>
#ifdef __GNUG__
#pragma implementation
#endif
+#include <fstream>
#include "support/filetools.h"
#include "LaTeX.h"
#include "support/syscall.h"
#include "support/syscontr.h"
#include "support/path.h"
+#include "support/LRegex.h"
+#include "support/LSubstring.h"
#include "bufferlist.h"
#include "minibuffer.h"
#include "gettext.h"
-using std::make_pair;
+using std::ifstream;
+using std::getline;
+using std::endl;
// TODO: in no particular order
// - get rid of the extern BufferList and the call to
extern BufferList bufferlist;
-struct texfile_struct {
- LaTeX::TEX_FILES file;
- char const *extension;
-};
-
-static
-const texfile_struct all_files[] = {
- { LaTeX::AUX, ".aux"},
- { LaTeX::BBL, ".bbl"},
- { LaTeX::DVI, ".dvi"},
- { LaTeX::GLO, ".glo"},
- { LaTeX::IDX, ".idx"},
- { LaTeX::IND, ".ind"},
- { LaTeX::LOF, ".lof"},
- { LaTeX::LOA, ".loa"},
- { LaTeX::LOG, ".log"},
- { LaTeX::LOT, ".lot"},
- { LaTeX::TOC, ".toc"},
- { LaTeX::LTX, ".ltx"},
- { LaTeX::TEX, ".tex"}
-};
-
-
/*
* CLASS TEXERRORS
*/
LaTeX::LaTeX(string const & latex, string const & f, string const & p)
: cmd(latex), file(f), path(p)
{
- tex_files = NO_FILES;
- file_count = sizeof(all_files) / sizeof(texfile_struct);
num_errors = 0;
depfile = file + ".dep";
+ if (prefixIs(cmd, "pdf")) // Do we use pdflatex ?
+ depfile += "-pdf";
+}
+
+
+void LaTeX::deleteFilesOnError() const
+{
+ // currently just a dummy function.
+
+ // What files do we have to delete?
+
+ // This will at least make latex do all the runs
+ ::unlink(depfile.c_str());
+
+ // but the reason for the error might be in a generated file...
+
+ string ofname = OnlyFilename(file);
+
+ // bibtex file
+ string bbl = ChangeExtension(ofname, ".bbl");
+ ::unlink(bbl.c_str());
+
+ // makeindex file
+ string ind = ChangeExtension(ofname, ".ind");
+ ::unlink(ind.c_str());
+
+ // Also remove the aux file
+ string aux = ChangeExtension(ofname, ".aux");
+ ::unlink(aux.c_str());
}
// Update the checksums
head.update();
- lyxerr[Debug::LATEX] << "Dependency file exists" << endl;
+ lyxerr[Debug::DEPEND] << "Dependency file exists" << endl;
if (head.sumchange()) {
++count;
- if (head.extchanged(".bib")
- || head.extchanged(".bst")) run_bibtex = true;
+ lyxerr[Debug::DEPEND]
+ << "Dependency file has changed" << endl;
lyxerr[Debug::LATEX]
- << "Dependency file has changed\n"
<< "Run #" << count << endl;
minib->Set(string(_("LaTeX run number ")) + tostr(count));
minib->Store();
this->operator()();
scanres = scanLogFile(terr);
- if (scanres & LaTeX::ERRORS) return scanres; // return on error
+ if (scanres & LaTeX::ERRORS) {
+ deleteFilesOnError();
+ return scanres; // return on error
+ }
+
+ run_bibtex = scanAux(head);
+ if (run_bibtex)
+ lyxerr[Debug::DEPEND]
+ << "Bibtex demands rerun" << endl;
} else {
- lyxerr[Debug::LATEX] << "return no_change" << endl;
+ lyxerr[Debug::DEPEND] << "return no_change" << endl;
return LaTeX::NO_CHANGE;
}
} else {
++count;
- lyxerr[Debug::LATEX] << "Dependency file does not exist\n"
- << "Run #" << count << endl;
+ lyxerr[Debug::DEPEND]
+ << "Dependency file does not exist" << endl;
+
+ lyxerr[Debug::LATEX]
+ << "Run #" << count << endl;
head.insert(file, true);
minib->Set(string(_("LaTeX run number ")) + tostr(count));
minib->Store();
this->operator()();
scanres = scanLogFile(terr);
- if (scanres & LaTeX::ERRORS) return scanres; // return on error
+ if (scanres & LaTeX::ERRORS) {
+ deleteFilesOnError();
+ return scanres; // return on error
+ }
+
}
// update the dependencies.
deplog(head); // reads the latex log
- deptex(head); // checks for latex files
head.update();
// 0.5
// if needed.
// run makeindex
- if (head.haschanged(ChangeExtension(file, ".idx", true))) {
+ if (head.haschanged(OnlyFilename(ChangeExtension(file, ".idx")))) {
// no checks for now
lyxerr[Debug::LATEX] << "Running MakeIndex." << endl;
minib->Set(_("Running MakeIndex."));
minib->Store();
- rerun=runMakeIndex(ChangeExtension(file,".idx",true));
+ rerun = runMakeIndex(OnlyFilename(ChangeExtension(file, ".idx")));
}
// run bibtex
lyxerr[Debug::LATEX] << "Running BibTeX." << endl;
minib->Set(_("Running BibTeX."));
minib->Store();
- rerun = runBibTeX(ChangeExtension(file, ".aux", true), head);
+ rerun = runBibTeX(OnlyFilename(ChangeExtension(file, ".aux")),
+ head);
}
// 1
if (rerun || head.sumchange()) {
rerun = false;
++count;
+ lyxerr[Debug::DEPEND]
+ << "Dep. file has changed or rerun requested" << endl;
lyxerr[Debug::LATEX]
- << "Dep. file has changed or rerun requested\n"
<< "Run #" << count << endl;
minib->Set(string(_("LaTeX run number ")) + tostr(count));
minib->Store();
this->operator()();
scanres = scanLogFile(terr);
- if (scanres & LaTeX::ERRORS) return scanres; // return on error
+ if (scanres & LaTeX::ERRORS) {
+ deleteFilesOnError();
+ return scanres; // return on error
+ }
+
// update the depedencies
deplog(head); // reads the latex log
head.update();
} else {
- lyxerr[Debug::LATEX] << "Dep. file has NOT changed" << endl;
+ lyxerr[Debug::DEPEND] << "Dep. file has NOT changed" << endl;
}
// 1.5
// more after this.
// run makeindex if the <file>.idx has changed or was generated.
- if (head.haschanged(ChangeExtension(file, ".idx", true))) {
+ if (head.haschanged(OnlyFilename(ChangeExtension(file, ".idx")))) {
// no checks for now
lyxerr[Debug::LATEX] << "Running MakeIndex." << endl;
minib->Set(_("Running MakeIndex."));
minib->Store();
- rerun = runMakeIndex(ChangeExtension(file, ".idx", true));
+ rerun = runMakeIndex(OnlyFilename(ChangeExtension(file, ".idx")));
}
// 2
minib->Store();
this->operator()();
scanres = scanLogFile(terr);
- if (scanres & LaTeX::ERRORS) return scanres; // return on error
+ if (scanres & LaTeX::ERRORS) {
+ deleteFilesOnError();
+ return scanres; // return on error
+ }
+
// keep this updated
head.update();
}
int LaTeX::operator()()
{
#ifndef __EMX__
- string tmp = cmd + ' ' + file + " > /dev/null";
+ string tmp = cmd + ' ' + QuoteName(file) + " > /dev/null";
#else // cmd.exe (OS/2) causes SYS0003 error at "/dev/null"
string tmp = cmd + ' ' + file + " > nul";
#endif
}
-bool LaTeX::runMakeIndex(string const &file)
+bool LaTeX::runMakeIndex(string const & f)
{
lyxerr[Debug::LATEX] << "idx file has been made,"
" running makeindex on file "
- << file << endl;
+ << f << endl;
// It should be possible to set the switches for makeindex
// sorting style and such. It would also be very convenient
// to be able to make style files from within LyX. This has
// to come for a later time. (0.13 perhaps?)
string tmp = "makeindex -c -q ";
- tmp += file;
+ tmp += f;
Systemcalls one;
one.startscript(Systemcalls::System, tmp);
return true;
}
-typedef pair<int, string> cmdret;
-static cmdret do_popen(string const & cmd)
-{
- // One question is if we should use popen or
- // create our own popen based on fork,exec,pipe
- // of course the best would be to have a
- // pstream (process stream), with the
- // variants ipstream, opstream and
- FILE * inf = popen(cmd.c_str(), "r");
- string ret;
- int c = fgetc(inf);
- while (c != EOF) {
- ret += static_cast<char>(c);
- c = fgetc(inf);
- }
- int pret = pclose(inf);
- return make_pair(pret, ret);
-}
-
-
-static string findtexfile(string const & fil, string const & format)
+bool LaTeX::scanAux(DepTable & dep)
{
- // If fil is a file with absolute path we just return it
- if (AbsolutePath(fil)) return fil;
-
- // Check in the current dir.
- if (FileInfo(OnlyFilename(fil)).exist())
- return OnlyFilename(fil);
+ // if any of the bib file has changed we don't have to
+ // check the .aux file.
+ if (dep.extchanged(".bib")
+ || dep.extchanged(".bst")) return true;
- // No we try to find it using kpsewhich.
- string kpsecmd = "kpsewhich --format=" + format + " " + fil;
- cmdret c = do_popen(kpsecmd);
-
- lyxerr << "kpse status = " << c.first << "\n"
- << "kpse result = `" << strip(c.second, '\n') << "'" << endl;
- return c.first == 0 ? strip(c.second, '\n') : string();
+ string aux = OnlyFilename(ChangeExtension(file, ".aux"));
+ ifstream ifs(aux.c_str());
+ string token;
+ LRegex reg1("\\\\bibdata\\{([^}]+)\\}");
+ LRegex reg2("\\\\bibstyle\\{([^}]+)\\}");
+ while (getline(ifs, token)) {
+ if (reg1.exact_match(token)) {
+ LRegex::SubMatches sub = reg1.exec(token);
+ string data = LSubstring(token, sub[1].first,
+ sub[1].second);
+ string::size_type b;
+ do {
+ b = data.find_first_of(',', 0);
+ string l;
+ if (b == string::npos)
+ l = data;
+ else {
+ l = data.substr( 0, b - 0);
+ data.erase(0, b + 1);
+ }
+ string full_l =
+ findtexfile(
+ ChangeExtension(l, "bib"), "bib");
+ if (!full_l.empty()) {
+ if (!dep.exist(full_l))
+ return true;
+ }
+ } while (b != string::npos);
+ } else if (reg2.exact_match(token)) {
+ LRegex::SubMatches sub = reg2.exec(token);
+ string style = LSubstring(token, sub[1].first,
+ sub[1].second);
+ // token is now the style file
+ // pass it to the helper
+ string full_l =
+ findtexfile(
+ ChangeExtension(style, "bst"),
+ "bst");
+ if (!full_l.empty()) {
+ if (!dep.exist(full_l))
+ return true;
+ }
+ }
+ }
+ return false;
}
-bool LaTeX::runBibTeX(string const & file, DepTable & dep)
+bool LaTeX::runBibTeX(string const & f, DepTable & dep)
{
- ifstream ifs(file.c_str());
+ // Since a run of Bibtex mandates more latex runs it is ok to
+ // remove all ".bib" and ".bst" files, it is also required to
+ // discover style and database changes.
+ dep.remove_files_with_extension(".bib");
+ dep.remove_files_with_extension(".bst");
+ ifstream ifs(f.c_str());
string token;
bool using_bibtex = false;
+ LRegex reg1("\\\\bibdata\\{([^}]+)\\}");
+ LRegex reg2("\\\\bibstyle\\{([^}]+)\\}");
while (getline(ifs, token)) {
- if (contains(token, "\\bibdata{")) {
+ if (reg1.exact_match(token)) {
using_bibtex = true;
- string::size_type a = token.find("\\bibdata{") + 9;
- string::size_type b = token.find_first_of("}", a);
- string data = token.substr(a, b - a);
+ LRegex::SubMatches const & sub = reg1.exec(token);
+ string data = LSubstring(token, sub[1].first,
+ sub[1].second);
// data is now all the bib files separated by ','
// get them one by one and pass them to the helper
+ string::size_type b;
do {
b = data.find_first_of(',', 0);
string l;
l = data.substr(0, b - 0);
data.erase(0, b + 1);
}
- string full_l =
+ string full_l =
findtexfile(
- ChangeExtension(l,"bib",false),
+ ChangeExtension(l, "bib"),
"bib");
- lyxerr << "data = `"
- << full_l << "'" << endl;
+ lyxerr[Debug::LATEX] << "Bibtex database: `"
+ << full_l << "'" << endl;
if (!full_l.empty()) {
// add full_l to the dep file.
dep.insert(full_l, true);
}
} while (b != string::npos);
- } else if (contains(token, "\\bibstyle{")) {
+ } else if (reg2.exact_match(token)) {
using_bibtex = true;
- string::size_type a = token.find("\\bibstyle{") + 10;
- string::size_type b = token.find_first_of("}", a);
- string style = token.substr(a, b - a);
+ LRegex::SubMatches const & sub = reg2.exec(token);
+ string style = LSubstring(token, sub[1].first,
+ sub[1].second);
// token is now the style file
// pass it to the helper
- string full_l =
+ string full_l =
findtexfile(
- ChangeExtension(style, "bst", false),
+ ChangeExtension(style, "bst"),
"bst");
- lyxerr << "style = `"
- << full_l << "'" << endl;
+ lyxerr[Debug::LATEX] << "Bibtex style: `"
+ << full_l << "'" << endl;
if (!full_l.empty()) {
// add full_l to the dep file.
dep.insert(full_l, true);
}
if (using_bibtex) {
// run bibtex and
- string tmp= "bibtex ";
- tmp += ChangeExtension(file, string(), true);
+ string tmp = "bibtex ";
+ tmp += OnlyFilename(ChangeExtension(file, string()));
Systemcalls one;
one.startscript(Systemcalls::System, tmp);
return true;
int LaTeX::scanLogFile(TeXErrors & terr)
{
+ int last_line = -1;
+ int line_count = 1;
int retval = NO_ERRORS;
- string tmp = ChangeExtension(file, ".log", true);
+ string tmp = OnlyFilename(ChangeExtension(file, ".log"));
lyxerr[Debug::LATEX] << "Log file: " << tmp << endl;
ifstream ifs(tmp.c_str());
retval |= LATEX_ERROR;
// get the next line
string tmp;
- getline(ifs, tmp);
+ int count = 0;
+ do {
+ if (!getline(ifs, tmp))
+ break;
+ if (++count > 10)
+ break;
+ } while (!prefixIs(tmp, "l."));
if (prefixIs(tmp, "l.")) {
// we have a latex error
retval |= TEX_ERROR;
<< "line: " << line << '\n'
<< "Desc: " << desc << '\n'
<< "Text: " << errstr << endl;
- terr.insertError(line, desc, errstr);
- num_errors++;
+ if (line == last_line)
+ ++line_count;
+ else {
+ line_count = 1;
+ last_line = line;
+ }
+ if (line_count <= 5) {
+ terr.insertError(line, desc, errstr);
+ ++num_errors;
+ }
}
} else {
// information messages, TeX warnings and other
// files used by the LaTeX run. The files are then entered into the
// dependency file.
- string logfile = ChangeExtension(file, ".log", true);
+ string logfile = OnlyFilename(ChangeExtension(file, ".log"));
+
+ LRegex reg1(")* *\\(([^ ]+).*");
+ LRegex reg2("File: ([^ ]+).*");
+ LRegex reg3("No file ([^ ]+)\\..*");
+ LRegex reg4("\\\\openout[0-9]+.*=.*`([^ ]+)'\\..*");
+ LRegex unwanted("^.*\\.(aux|log|dvi|bbl|ind|glo)$");
ifstream ifs(logfile.c_str());
while (ifs) {
- // Now we read chars until we find a '('
- char c = 0;
- while(ifs.get(c)) {
- if (c == '(') break;
- };
- if (!ifs) break;
-
- // We now have c == '(', we now read the the sequence of
- // chars until reaching EOL, ' ' or ')' and put that
- // into a string.
+ // Ok, the scanning of files here is not sufficient.
+ // Sometimes files are named by "File: xxx" only
+ // So I think we should use some regexps to find files instead.
+ // "(\([^ ]+\)" should match the "(file " variant
+ // "File: \([^ ]+\)" should match the "File: file" variant
string foundfile;
- while (ifs.get(c)) {
- if (c == '\n' || c == ' ' || c == ')')
- break;
- foundfile += c;
+ string token;
+ getline(ifs, token);
+ if (token.empty()) continue;
+
+ if (reg1.exact_match(token)) {
+ LRegex::SubMatches const & sub = reg1.exec(token);
+ foundfile = LSubstring(token, sub[1].first,
+ sub[1].second);
+ } else if (reg2.exact_match(token)) {
+ LRegex::SubMatches const & sub = reg2.exec(token);
+ foundfile = LSubstring(token, sub[1].first,
+ sub[1].second);
+ } else if (reg3.exact_match(token)) {
+ LRegex::SubMatches const & sub = reg3.exec(token);
+ foundfile = LSubstring(token, sub[1].first,
+ sub[1].second);
+ } else if (reg4.exact_match(token)) {
+ LRegex::SubMatches const & sub = reg4.exec(token);
+ foundfile = LSubstring(token, sub[1].first,
+ sub[1].second);
+ } else {
+ continue;
}
- lyxerr[Debug::LATEX] << "Found file: "
- << foundfile << endl;
+
+ lyxerr[Debug::DEPEND] << "Found file: "
+ << foundfile << endl;
// Ok now we found a file.
- // Now we should make sure that
- // this is a file that we can
- // access through the normal
- // paths:
+ // Now we should make sure that this is a file that we can
+ // access through the normal paths.
+ // We will not try any fance search methods to
+ // find the file.
+
// (1) foundfile is an
// absolute path and should
// be inserted.
if (AbsolutePath(foundfile)) {
- lyxerr[Debug::LATEX] << "AbsolutePath file: "
- << foundfile << endl;
+ lyxerr[Debug::DEPEND] << "AbsolutePath file: "
+ << foundfile << endl;
// On inital insert we want to do the update at once
// since this file can not be a file generated by
// the latex run.
// (2) foundfile is in the tmpdir
// insert it into head
if (FileInfo(OnlyFilename(foundfile)).exist()) {
- if (suffixIs(foundfile, ".aux")) {
- lyxerr[Debug::LATEX] << "We don't want "
- << OnlyFilename(foundfile)
- << " in the dep file"
- << endl;
+ if (unwanted.exact_match(foundfile)) {
+ lyxerr[Debug::DEPEND]
+ << "We don't want "
+ << OnlyFilename(foundfile)
+ << " in the dep file"
+ << endl;
} else if (suffixIs(foundfile, ".tex")) {
// This is a tex file generated by LyX
// and latex is not likely to change this
// during its runs.
- lyxerr[Debug::LATEX] << "Tmpdir TeX file: "
- << OnlyFilename(foundfile)
- << endl;
+ lyxerr[Debug::DEPEND]
+ << "Tmpdir TeX file: "
+ << OnlyFilename(foundfile)
+ << endl;
head.insert(foundfile, true);
} else {
- lyxerr[Debug::LATEX] << "In tmpdir file:"
- << OnlyFilename(foundfile)
- << endl;
+ lyxerr[Debug::DEPEND]
+ << "In tmpdir file:"
+ << OnlyFilename(foundfile)
+ << endl;
head.insert(OnlyFilename(foundfile));
}
continue;
}
- lyxerr[Debug::LATEX]
+ lyxerr[Debug::DEPEND]
<< "Not a file or we are unable to find it."
<< endl;
}
}
-
-
-void LaTeX::deptex(DepTable & head)
-{
- int except = AUX|LOG|DVI|BBL|IND|GLO;
- string tmp;
- FileInfo fi;
- for (int i = 0; i < file_count; ++i) {
- if (!(all_files[i].file & except)) {
- tmp = ChangeExtension(file,
- all_files[i].extension,
- true);
- lyxerr[Debug::LATEX] << "deptex: " << tmp << endl;
- if (fi.newFile(tmp).exist())
- head.insert(tmp);
- }
- }
-}