1999-09-27 18:44:28 +00:00
|
|
|
|
/* This file is part of
|
|
|
|
|
* ======================================================
|
|
|
|
|
*
|
|
|
|
|
* LyX, The Document Processor
|
1999-10-02 16:21:10 +00:00
|
|
|
|
* Copyright 1995 Matthias Ettrich
|
|
|
|
|
* Copyright 1995-1999 The LyX Team.
|
1999-09-27 18:44:28 +00:00
|
|
|
|
*
|
1999-10-02 16:21:10 +00:00
|
|
|
|
* This file is Copyright 1996-1999
|
1999-09-27 18:44:28 +00:00
|
|
|
|
* Lars Gullik Bj<EFBFBD>nnes
|
|
|
|
|
*
|
1999-10-02 16:21:10 +00:00
|
|
|
|
* ======================================================
|
1999-09-27 18:44:28 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstdlib>
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
|
|
|
|
#ifdef __GNUG__
|
|
|
|
|
#pragma implementation
|
|
|
|
|
#endif
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
#include "support/filetools.h"
|
1999-09-27 18:44:28 +00:00
|
|
|
|
#include "LaTeX.h"
|
|
|
|
|
#include "lyxlex.h"
|
1999-10-02 16:21:10 +00:00
|
|
|
|
#include "support/FileInfo.h"
|
1999-09-27 18:44:28 +00:00
|
|
|
|
#include "error.h"
|
1999-10-02 16:21:10 +00:00
|
|
|
|
#include "support/lyxlib.h"
|
|
|
|
|
#include "support/syscall.h"
|
|
|
|
|
#include "support/syscontr.h"
|
1999-09-27 18:44:28 +00:00
|
|
|
|
#include "pathstack.h"
|
|
|
|
|
#include "bufferlist.h"
|
|
|
|
|
#include "minibuffer.h"
|
|
|
|
|
#include "gettext.h"
|
|
|
|
|
|
|
|
|
|
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"}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// This should perhaps be placed in LyXLex
|
|
|
|
|
static
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string readLine(FILE *file)
|
1999-09-27 18:44:28 +00:00
|
|
|
|
{
|
|
|
|
|
if (feof(file))
|
1999-10-02 16:21:10 +00:00
|
|
|
|
return string();
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
char s[512];
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
s[i] = fgetc(file);
|
|
|
|
|
i++;
|
|
|
|
|
} while (!feof(file) && s[i-1] != '\n' && i<510);
|
|
|
|
|
s[i] = '\0';
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string tmp;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
if (i == 1 && feof(file))
|
|
|
|
|
;
|
|
|
|
|
else
|
|
|
|
|
tmp = s;
|
|
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* CLASS TEXERRORS
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// I did not leave this inlined because DEC cxx does not like
|
|
|
|
|
// variables declarations in inlined code (JMarc)
|
|
|
|
|
TeXErrors::~TeXErrors()
|
|
|
|
|
{
|
|
|
|
|
Error *tmp;
|
|
|
|
|
while (errors) {
|
|
|
|
|
tmp = errors->next_error;
|
|
|
|
|
delete errors;
|
|
|
|
|
errors = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TeXErrors::scanError(LyXLex &lex)
|
|
|
|
|
{
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string token = lex.GetString();
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// Sometimes the error string goes over more than one
|
|
|
|
|
// line, and we need to get them all.
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string errstr;
|
|
|
|
|
string tmp = frontStrip(readLine(lex.getFile()));
|
1999-09-27 18:44:28 +00:00
|
|
|
|
if (tmp == "\n" || tmp.empty()) {
|
1999-10-02 16:21:10 +00:00
|
|
|
|
tmp = frontStrip(readLine(lex.getFile()));
|
|
|
|
|
if (contains(tmp, "See the LaTeX manual")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
do {
|
|
|
|
|
tmp = readLine(lex.getFile());
|
1999-10-02 16:21:10 +00:00
|
|
|
|
} while (!tmp.empty() && !contains(tmp, "..."));
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
1999-10-02 16:21:10 +00:00
|
|
|
|
tmp = frontStrip(readLine(lex.getFile()));
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
while ((tmp != "\n" || !contains(errstr, "l."))
|
|
|
|
|
&& !prefixIs(tmp, "! ")
|
|
|
|
|
&& !contains(tmp, "(job aborted")
|
1999-09-27 18:44:28 +00:00
|
|
|
|
&& !tmp.empty()) {
|
|
|
|
|
errstr += tmp;
|
1999-10-02 16:21:10 +00:00
|
|
|
|
tmp = frontStrip(readLine(lex.getFile()));
|
1999-09-27 18:44:28 +00:00
|
|
|
|
}
|
|
|
|
|
lyxerr.debug("tmp: " + errstr);
|
|
|
|
|
int line = 0;
|
|
|
|
|
// unfortunately the error line is not always given
|
|
|
|
|
// by "l.###" in the beginning of the error string
|
|
|
|
|
// therefore we must search for "l.###" in the error
|
|
|
|
|
// msg.
|
1999-10-02 16:21:10 +00:00
|
|
|
|
if (contains(errstr, "l.")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// We make a const copy to make [] fast. (Asger)
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string const es = errstr;
|
|
|
|
|
for (string::size_type i = 2; i < es.length(); ++i) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
if (es[i-2] == 'l' && es[i-1] == '.' &&
|
|
|
|
|
(es[i] >= '0' && es[i]<= '9')) {
|
|
|
|
|
line = atoi(es.c_str() + i);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
insertError(line, token, errstr);
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
if (prefixIs(tmp, "! ")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
scanError(lex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
bool TeXErrors::getFirstError(int *line, string *text)
|
1999-09-27 18:44:28 +00:00
|
|
|
|
{
|
|
|
|
|
next_error = errors;
|
|
|
|
|
if (next_error) {
|
|
|
|
|
*line = next_error->error_in_line;
|
|
|
|
|
*text = next_error->error_desc + "\n" + next_error->error_text;
|
|
|
|
|
next_error = next_error->next_error;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
bool TeXErrors::getNextError(int *line, string *text)
|
1999-09-27 18:44:28 +00:00
|
|
|
|
{
|
|
|
|
|
if (next_error) {
|
|
|
|
|
*line = next_error->error_in_line;
|
|
|
|
|
*text = next_error->error_desc + "\n" + next_error->error_text;
|
|
|
|
|
next_error = next_error->next_error;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
void TeXErrors::insertError(int line, string const &error_desc,
|
|
|
|
|
string const &error_text)
|
1999-09-27 18:44:28 +00:00
|
|
|
|
{
|
|
|
|
|
Error *newerr = new Error(line, error_desc, error_text);
|
|
|
|
|
if (errors) {
|
|
|
|
|
Error *tmperr = errors;
|
|
|
|
|
while (tmperr->next_error) tmperr = tmperr->next_error;
|
|
|
|
|
tmperr->next_error = newerr;
|
|
|
|
|
} else {
|
|
|
|
|
errors = newerr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TeXErrors::printErrors()
|
|
|
|
|
{
|
|
|
|
|
lyxerr.print("Printing errors.");
|
|
|
|
|
if (errors) {
|
|
|
|
|
Error *tmperr = errors;
|
|
|
|
|
do {
|
1999-10-02 16:21:10 +00:00
|
|
|
|
lyxerr.print(string("Error in line ")
|
|
|
|
|
+ tostr(tmperr->error_in_line)
|
1999-09-27 18:44:28 +00:00
|
|
|
|
+ ": " + tmperr->error_desc
|
|
|
|
|
+ '\n' + tmperr->error_text);
|
|
|
|
|
//%d: %s\n%s\n", tmperr->error_in_line,
|
|
|
|
|
// tmperr->error_desc.c_str(),
|
|
|
|
|
// tmperr->error_text.c_str());
|
|
|
|
|
tmperr = tmperr->next_error;
|
|
|
|
|
} while (tmperr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TeXErrors::printWarnings()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TeXErrors::printStatus()
|
|
|
|
|
{
|
|
|
|
|
lyxerr.print("Error struct:");
|
1999-10-02 16:21:10 +00:00
|
|
|
|
lyxerr.print(string(" status: ") + tostr(status));
|
|
|
|
|
lyxerr.print(string(" no err: ") + tostr(number_of_errors));
|
1999-09-27 18:44:28 +00:00
|
|
|
|
if (status == LaTeX::NO_ERRORS) lyxerr.print("NO_ERRORS");
|
|
|
|
|
if (status & LaTeX::NO_LOGFILE) lyxerr.print("NO_LOGFILE");
|
|
|
|
|
if (status & LaTeX::NO_OUTPUT) lyxerr.print("NO_OUTPUT");
|
|
|
|
|
if (status & LaTeX::UNDEF_REF) lyxerr. print("UNDEF_REF");
|
|
|
|
|
if (status & LaTeX::RERUN) lyxerr. print("RERUN");
|
|
|
|
|
if (status & LaTeX::TEX_ERROR) lyxerr.print("TEX_ERROR");
|
|
|
|
|
if (status & LaTeX::TEX_WARNING) lyxerr.print("TEX_WARNING");
|
|
|
|
|
if (status & LaTeX::NO_FILE) lyxerr.print("NO_FILE");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* CLASS LaTeX
|
|
|
|
|
*/
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
LaTeX::LaTeX(string const & latex, string const & f, string const & p)
|
1999-09-27 18:44:28 +00:00
|
|
|
|
: cmd(latex), file(f), path(p)
|
|
|
|
|
{
|
|
|
|
|
tex_files = NO_FILES;
|
|
|
|
|
file_count = sizeof(all_files) / sizeof(texfile_struct);
|
|
|
|
|
num_errors = 0;
|
|
|
|
|
depfile = file + ".dep";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int LaTeX::run(TeXErrors &terr, MiniBuffer *minib)
|
|
|
|
|
// We know that this function will only be run if the lyx buffer
|
|
|
|
|
// has been changed. We also know that a newly written .tex file
|
|
|
|
|
// is always different from the previous one because of the date
|
|
|
|
|
// in it. However it seems safe to run latex (at least) on time each
|
|
|
|
|
// time the .tex file changes.
|
|
|
|
|
{
|
|
|
|
|
int scanres = LaTeX::NO_ERRORS;
|
|
|
|
|
unsigned int count = 0; // number of times run
|
|
|
|
|
num_errors = 0; // just to make sure.
|
|
|
|
|
const unsigned int MAX_RUN = 6;
|
|
|
|
|
DepTable head; // empty head
|
|
|
|
|
bool rerun = false; // rerun requested
|
|
|
|
|
|
|
|
|
|
// The class LaTeX does not know the temp path.
|
|
|
|
|
bufferlist.updateIncludedTeXfiles(GetCWD());
|
|
|
|
|
|
|
|
|
|
// Never write the depfile if an error was encountered.
|
|
|
|
|
|
|
|
|
|
// 0
|
|
|
|
|
// first check if the file dependencies exist:
|
|
|
|
|
// ->If it does exist
|
|
|
|
|
// check if any of the files mentioned in it have
|
|
|
|
|
// changed (done using a checksum).
|
|
|
|
|
// -> if changed:
|
|
|
|
|
// run latex once and
|
|
|
|
|
// remake the dependency file
|
|
|
|
|
// -> if not changed:
|
|
|
|
|
// just return there is nothing to do for us.
|
|
|
|
|
// ->if it doesn't exist
|
|
|
|
|
// make it and
|
|
|
|
|
// run latex once (we need to run latex once anyway) and
|
|
|
|
|
// remake the dependency file.
|
|
|
|
|
//
|
|
|
|
|
FileInfo fi(depfile);
|
|
|
|
|
if (fi.exist()) {
|
|
|
|
|
// Read the dep file:
|
|
|
|
|
head.read(depfile);
|
|
|
|
|
// Update the checksums
|
|
|
|
|
head.update();
|
|
|
|
|
|
|
|
|
|
lyxerr.debug("Dependency file exists", Error::LATEX);
|
|
|
|
|
if (head.sumchange()) {
|
|
|
|
|
lyxerr.debug("Dependency file has changed",
|
|
|
|
|
Error::LATEX);
|
1999-10-02 16:21:10 +00:00
|
|
|
|
lyxerr.debug(string(_("Run #")) + tostr(++count),
|
1999-09-27 18:44:28 +00:00
|
|
|
|
Error::LATEX);
|
1999-10-02 16:21:10 +00:00
|
|
|
|
minib->Set(string(_("LaTeX run number ")) + tostr(count));
|
1999-09-27 18:44:28 +00:00
|
|
|
|
minib->Store();
|
|
|
|
|
this->operator()();
|
|
|
|
|
scanres = scanLogFile(terr);
|
|
|
|
|
if (scanres & LaTeX::ERRORS) return scanres; // return on error
|
|
|
|
|
} else {
|
|
|
|
|
lyxerr.debug("return no_change", Error::LATEX);
|
|
|
|
|
return LaTeX::NO_CHANGE;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
lyxerr.debug("Dependency file does not exist",
|
|
|
|
|
Error::LATEX);
|
1999-10-02 16:21:10 +00:00
|
|
|
|
lyxerr.debug(string(_("Run #")) + tostr(++count),
|
1999-09-27 18:44:28 +00:00
|
|
|
|
Error::LATEX);
|
|
|
|
|
head.insert(file, true);
|
1999-10-02 16:21:10 +00:00
|
|
|
|
minib->Set(string(_("LaTeX run number ")) + tostr(count));
|
1999-09-27 18:44:28 +00:00
|
|
|
|
minib->Store();
|
|
|
|
|
this->operator()();
|
|
|
|
|
scanres = scanLogFile(terr);
|
|
|
|
|
if (scanres & LaTeX::ERRORS) return scanres; // return on error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// update the dependencies.
|
|
|
|
|
deplog(head); // reads the latex log
|
|
|
|
|
deptex(head); // checks for latex files
|
|
|
|
|
head.update();
|
|
|
|
|
|
|
|
|
|
// 0.5
|
|
|
|
|
// At this point we must run external programs if needed.
|
|
|
|
|
// makeindex will be run if a .idx file changed or was generated.
|
|
|
|
|
// And if there were undefined citations or changes in references
|
|
|
|
|
// the .aux file is checked for signs of bibtex. Bibtex is then run
|
|
|
|
|
// if needed.
|
|
|
|
|
|
|
|
|
|
// run makeindex
|
|
|
|
|
if (head.haschanged(ChangeExtension(file, ".idx", true))) {
|
|
|
|
|
// no checks for now
|
|
|
|
|
minib->Set(_("Running MakeIndex."));
|
|
|
|
|
minib->Store();
|
|
|
|
|
rerun=runMakeIndex(ChangeExtension(file,".idx",true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// run bibtex
|
|
|
|
|
if (scanres & LaTeX::UNDEF_CIT || scanres & LaTeX::RERUN) {
|
|
|
|
|
// Here we must scan the .aux file and look for
|
|
|
|
|
// "\bibdata" and/or "\bibstyle". If one of those
|
|
|
|
|
// tags is found -> run bibtex and set rerun = true;
|
|
|
|
|
// no checks for now
|
|
|
|
|
minib->Set(_("Running BibTeX."));
|
|
|
|
|
minib->Store();
|
|
|
|
|
rerun = runBibTeX(ChangeExtension(file, ".aux", true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 1
|
|
|
|
|
// we know on this point that latex has been run once (or we just
|
|
|
|
|
// returned) and the question now is to decide if we need to run
|
|
|
|
|
// it any more. This is done by asking if any of the files in the
|
|
|
|
|
// dependency file has changed. (remember that the checksum for
|
|
|
|
|
// a given file is reported to have changed if it just was created)
|
|
|
|
|
// -> if changed or rerun == true:
|
|
|
|
|
// run latex once more and
|
|
|
|
|
// update the dependency structure
|
|
|
|
|
// -> if not changed:
|
|
|
|
|
// we does nothing at this point
|
|
|
|
|
//
|
|
|
|
|
if (rerun || head.sumchange()) {
|
|
|
|
|
rerun = false;
|
|
|
|
|
lyxerr.debug("Dep. file has changed or rerun requested",
|
|
|
|
|
Error::LATEX);
|
1999-10-02 16:21:10 +00:00
|
|
|
|
lyxerr.debug(string("Run #") + tostr(++count),
|
1999-09-27 18:44:28 +00:00
|
|
|
|
Error::LATEX);
|
1999-10-02 16:21:10 +00:00
|
|
|
|
minib->Set(string(_("LaTeX run number ")) + tostr(count));
|
1999-09-27 18:44:28 +00:00
|
|
|
|
minib->Store();
|
|
|
|
|
this->operator()();
|
|
|
|
|
scanres = scanLogFile(terr);
|
|
|
|
|
if (scanres & LaTeX::ERRORS) return scanres; // return on error
|
|
|
|
|
// update the depedencies
|
|
|
|
|
deplog(head); // reads the latex log
|
|
|
|
|
head.update();
|
|
|
|
|
} else {
|
|
|
|
|
lyxerr.debug("Dep. file has NOT changed", Error::LATEX);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 1.5
|
|
|
|
|
// The inclusion of files generated by external programs like
|
|
|
|
|
// makeindex or bibtex might have done changes to pagenumbereing,
|
|
|
|
|
// etc. And because of this we must run the external programs
|
|
|
|
|
// again to make sure everything is redone correctly.
|
|
|
|
|
// Also there should be no need to run the external programs any
|
|
|
|
|
// more after this.
|
|
|
|
|
|
|
|
|
|
// run makeindex if the <file>.idx has changed or was generated.
|
|
|
|
|
if (head.haschanged(ChangeExtension(file, ".idx", true))) {
|
|
|
|
|
// no checks for now
|
|
|
|
|
minib->Set(_("Running MakeIndex."));
|
|
|
|
|
minib->Store();
|
|
|
|
|
rerun = runMakeIndex(ChangeExtension(file, ".idx", true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2
|
|
|
|
|
// we will only run latex more if the log file asks for it.
|
|
|
|
|
// or if the sumchange() is true.
|
|
|
|
|
// -> rerun asked for:
|
|
|
|
|
// run latex and
|
|
|
|
|
// remake the dependency file
|
|
|
|
|
// goto 2 or return if max runs are reached.
|
|
|
|
|
// -> rerun not asked for:
|
|
|
|
|
// just return (fall out of bottom of func)
|
|
|
|
|
//
|
|
|
|
|
while ((head.sumchange() || rerun || (scanres & LaTeX::RERUN))
|
|
|
|
|
&& count < MAX_RUN) {
|
|
|
|
|
// Yes rerun until message goes away, or until
|
|
|
|
|
// MAX_RUNS are reached.
|
|
|
|
|
rerun = false;
|
1999-10-02 16:21:10 +00:00
|
|
|
|
lyxerr.debug(string(_("Run #")) + tostr(++count), Error::LATEX);
|
|
|
|
|
minib->Set(string(_("LaTeX run number ")) + tostr(count));
|
1999-09-27 18:44:28 +00:00
|
|
|
|
minib->Store();
|
|
|
|
|
this->operator()();
|
|
|
|
|
scanres = scanLogFile(terr);
|
|
|
|
|
if (scanres & LaTeX::ERRORS) return scanres; // return on error
|
|
|
|
|
// keep this updated
|
|
|
|
|
head.update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Write the dependencies to file.
|
|
|
|
|
head.write(depfile);
|
|
|
|
|
lyxerr.debug("Done.", Error::LATEX);
|
|
|
|
|
return scanres;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int LaTeX::operator()()
|
|
|
|
|
{
|
|
|
|
|
#ifndef __EMX__
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string tmp = cmd + ' ' + file + " > /dev/null";
|
1999-09-27 18:44:28 +00:00
|
|
|
|
#else // cmd.exe (OS/2) causes SYS0003 error at "/dev/null"
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string tmp = cmd + ' ' + file + " > nul";
|
1999-09-27 18:44:28 +00:00
|
|
|
|
#endif
|
|
|
|
|
Systemcalls one;
|
|
|
|
|
return one.Startscript(Systemcalls::System, tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
bool LaTeX::runMakeIndex(string const &file)
|
1999-09-27 18:44:28 +00:00
|
|
|
|
{
|
|
|
|
|
lyxerr.debug("idx file has been made,"
|
|
|
|
|
" running makeindex on file "
|
|
|
|
|
+ file, Error::LATEX);
|
|
|
|
|
|
|
|
|
|
// 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?)
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string tmp = "makeindex -c -q ";
|
1999-09-27 18:44:28 +00:00
|
|
|
|
tmp += file;
|
|
|
|
|
Systemcalls one;
|
|
|
|
|
one.Startscript(Systemcalls::System, tmp);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
bool LaTeX::runBibTeX(string const &file)
|
1999-09-27 18:44:28 +00:00
|
|
|
|
{
|
1999-10-02 16:21:10 +00:00
|
|
|
|
LyXLex lex(0, 0);
|
|
|
|
|
string token;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
if (!lex.setFile(file)) {
|
|
|
|
|
// unable to open .aux file
|
|
|
|
|
// return at once
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (lex.IsOK()) {
|
|
|
|
|
if (lex.EatLine())
|
|
|
|
|
token=lex.GetString();
|
|
|
|
|
else // blank line in the file being read
|
|
|
|
|
continue;
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
if (contains(token, "\\bibdata{")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// run bibtex and
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string tmp="bibtex ";
|
|
|
|
|
tmp += ChangeExtension(file, string(), true);
|
1999-09-27 18:44:28 +00:00
|
|
|
|
Systemcalls one;
|
|
|
|
|
one.Startscript(Systemcalls::System, tmp);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
// bibtex was not run.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int LaTeX::scanLogFile(TeXErrors &terr)
|
|
|
|
|
{
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string token;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
int retval = NO_ERRORS;
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
LyXLex lex(0, 0);
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string tmp = ChangeExtension(file, ".log", true);
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
|
|
|
|
if (!lex.setFile(tmp)) {
|
|
|
|
|
// unable to open file
|
|
|
|
|
// return at once
|
|
|
|
|
retval |= NO_LOGFILE;
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (lex.IsOK()) {
|
|
|
|
|
if (lex.EatLine())
|
|
|
|
|
token = lex.GetString();
|
|
|
|
|
else // blank line in the file being read
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
lyxerr.debug(token, Error::LATEX);
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
if (prefixIs(token, "LaTeX Warning:")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// Here shall we handle different
|
|
|
|
|
// types of warnings
|
|
|
|
|
retval |= LATEX_WARNING;
|
|
|
|
|
lyxerr.debug("LaTeX Warning.", Error::LATEX);
|
1999-10-02 16:21:10 +00:00
|
|
|
|
if (contains(token, "Rerun to get cross-references")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
retval |= RERUN;
|
|
|
|
|
lyxerr.debug("We should rerun.", Error::LATEX);
|
1999-10-02 16:21:10 +00:00
|
|
|
|
} else if (contains(token, "Citation")
|
|
|
|
|
&& contains(token, "on page")
|
|
|
|
|
&& contains(token, "undefined")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
retval |= UNDEF_CIT;
|
|
|
|
|
}
|
1999-10-02 16:21:10 +00:00
|
|
|
|
} else if (prefixIs(token, "Package")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// Package warnings
|
|
|
|
|
retval |= PACKAGE_WARNING;
|
1999-10-02 16:21:10 +00:00
|
|
|
|
if (contains(token, "natbib Warning:")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// Natbib warnings
|
1999-10-02 16:21:10 +00:00
|
|
|
|
if (contains(token, "Citation")
|
|
|
|
|
&& contains(token, "on page")
|
|
|
|
|
&& contains(token, "undefined")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
retval |= UNDEF_CIT;
|
|
|
|
|
}
|
1999-10-02 16:21:10 +00:00
|
|
|
|
} else if (contains(token, "Rerun LaTeX.")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// at least longtable.sty might use this.
|
|
|
|
|
retval |= RERUN;
|
|
|
|
|
}
|
1999-10-02 16:21:10 +00:00
|
|
|
|
} else if (prefixIs(token, "! LaTeX Error:")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// Here shall we handle different
|
|
|
|
|
// types of errors
|
|
|
|
|
retval |= LATEX_ERROR;
|
|
|
|
|
lyxerr.debug("LaTeX Error.", Error::LATEX);
|
|
|
|
|
// this is not correct yet
|
|
|
|
|
terr.scanError(lex);
|
|
|
|
|
num_errors++;
|
1999-10-02 16:21:10 +00:00
|
|
|
|
} else if (prefixIs(token, "! ")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// Ok, we have something that looks like a TeX Error
|
|
|
|
|
// but what do we really have.
|
|
|
|
|
|
|
|
|
|
// Just get the error description:
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string desc(token);
|
|
|
|
|
desc.erase(0, 2);
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
if (contains(desc, "Undefined control sequence")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
retval |= TEX_ERROR;
|
|
|
|
|
lyxerr.debug("TeX Error.", Error::LATEX);
|
|
|
|
|
terr.scanError(lex);
|
|
|
|
|
num_errors++;
|
|
|
|
|
} else {
|
|
|
|
|
// get the next line
|
|
|
|
|
lex.next();
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string tmp = lex.GetString();
|
|
|
|
|
if (prefixIs(tmp, "l.")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// we have a latex error
|
|
|
|
|
retval |= TEX_ERROR;
|
|
|
|
|
lyxerr.debug("TeX Error.", Error::LATEX);
|
|
|
|
|
// get the line number:
|
|
|
|
|
int line = 0;
|
|
|
|
|
sscanf(tmp.c_str(), "l.%d", &line);
|
|
|
|
|
// get the rest of the message:
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string errstr;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
lex.EatLine();
|
|
|
|
|
tmp = lex.GetString();
|
1999-10-02 16:21:10 +00:00
|
|
|
|
while ((tmp != "\n" || !contains(errstr, "l."))
|
|
|
|
|
&& !prefixIs(tmp, "! ")
|
|
|
|
|
&& !contains(tmp, "(job aborted")
|
1999-09-27 18:44:28 +00:00
|
|
|
|
&& !tmp.empty()) {
|
|
|
|
|
errstr += tmp;
|
|
|
|
|
errstr += "\n";
|
|
|
|
|
lex.EatLine();
|
|
|
|
|
tmp = lex.GetString();
|
|
|
|
|
}
|
|
|
|
|
terr.insertError(line, desc, errstr);
|
|
|
|
|
num_errors++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// information messages, TeX warnings and other
|
|
|
|
|
// warnings we have not caught earlier.
|
1999-10-02 16:21:10 +00:00
|
|
|
|
if (prefixIs(token, "Overfull ")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
retval |= TEX_WARNING;
|
1999-10-02 16:21:10 +00:00
|
|
|
|
} else if (prefixIs(token, "Underfull ")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
retval |= TEX_WARNING;
|
1999-10-02 16:21:10 +00:00
|
|
|
|
} else if (contains(token, "Rerun to get citations")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// Natbib seems to use this.
|
|
|
|
|
retval |= RERUN;
|
1999-10-02 16:21:10 +00:00
|
|
|
|
} else if (contains(token, "No pages of output")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// A dvi file was not created
|
|
|
|
|
retval |= NO_OUTPUT;
|
1999-10-02 16:21:10 +00:00
|
|
|
|
} else if (contains(token, "That makes 100 errors")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// More than 100 errors were reprted
|
|
|
|
|
retval |= TOO_MANY_ERRORS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void LaTeX::deplog(DepTable & head)
|
|
|
|
|
{
|
|
|
|
|
// This function reads the LaTeX log file end extracts all the external
|
|
|
|
|
// files used by the LaTeX run. The files are then entered into the
|
|
|
|
|
// dependency file.
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string logfile = ChangeExtension(file, ".log", true);
|
1999-09-27 18:44:28 +00:00
|
|
|
|
FilePtr in(logfile, FilePtr::read);
|
|
|
|
|
bool not_eof = true;
|
|
|
|
|
if (in()) while (not_eof) { // We were able to open the file
|
|
|
|
|
// Now we read chars until we find a '('
|
|
|
|
|
int c;
|
|
|
|
|
do {
|
|
|
|
|
c = fgetc(in());
|
|
|
|
|
} while (c != EOF && c != '(');
|
|
|
|
|
if (c == EOF) {
|
|
|
|
|
// Nothing more we can do
|
|
|
|
|
not_eof = false;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We now have c == '(', we now read the the sequence of
|
|
|
|
|
// chars until reaching EOL, or ' ' and put that into a string.
|
|
|
|
|
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string foundfile;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
c = fgetc(in());
|
|
|
|
|
while (c != '\n' && c != ' ' && c != ')') {
|
|
|
|
|
foundfile += char(c);
|
|
|
|
|
c = fgetc(in());
|
|
|
|
|
}
|
|
|
|
|
if (foundfile.empty()) continue;
|
|
|
|
|
|
|
|
|
|
lyxerr.debug("Found file: "
|
|
|
|
|
+ foundfile,
|
|
|
|
|
Error::LATEX);
|
|
|
|
|
// Ok now we found a file.
|
|
|
|
|
// Now we should make sure that
|
|
|
|
|
// this is a file that we can
|
|
|
|
|
// access through the normal
|
|
|
|
|
// paths:
|
|
|
|
|
// (1) foundfile is an
|
|
|
|
|
// absolute path and should
|
|
|
|
|
// be inserted.
|
|
|
|
|
if (AbsolutePath(foundfile)) {
|
|
|
|
|
lyxerr.debug("AbsolutePath file: "
|
|
|
|
|
+ foundfile,
|
|
|
|
|
Error::LATEX);
|
|
|
|
|
// On inital insert we want to do the update at once
|
|
|
|
|
// since this file can not be a file generated by
|
|
|
|
|
// the latex run.
|
|
|
|
|
head.insert(foundfile, true);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// (2) foundfile is in the tmpdir
|
|
|
|
|
// insert it into head
|
|
|
|
|
if (FileInfo(OnlyFilename(foundfile)).exist()) {
|
1999-10-02 16:21:10 +00:00
|
|
|
|
if (suffixIs(foundfile, ".aux")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
lyxerr.debug("We don't want "
|
|
|
|
|
+ OnlyFilename(foundfile)
|
|
|
|
|
+ " in the dep file",
|
|
|
|
|
Error::LATEX);
|
1999-10-02 16:21:10 +00:00
|
|
|
|
} else if (suffixIs(foundfile, ".tex")) {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
// This is a tex file generated by LyX
|
|
|
|
|
// and latex is not likely to change this
|
|
|
|
|
// during its runs.
|
|
|
|
|
lyxerr.debug("Tmpdir TeX file: "
|
|
|
|
|
+ OnlyFilename(foundfile),
|
|
|
|
|
Error::LATEX);
|
|
|
|
|
head.insert(foundfile, true);
|
|
|
|
|
} else {
|
|
|
|
|
lyxerr.debug("In tmpdir file:"
|
|
|
|
|
+ OnlyFilename(foundfile),
|
|
|
|
|
Error::LATEX);
|
|
|
|
|
head.insert(OnlyFilename(foundfile));
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// (3) the foundfile can be
|
|
|
|
|
// found in the same dir
|
|
|
|
|
// as the .lyx file and
|
|
|
|
|
// should be inserted.
|
|
|
|
|
PathPush(path);
|
|
|
|
|
if (FileInfo(foundfile).exist()) {
|
|
|
|
|
lyxerr.print("LyX Strange: this should actually never"
|
|
|
|
|
" happen anymore, this it should be"
|
|
|
|
|
" handled by the Absolute check.");
|
|
|
|
|
lyxerr.debug("Same Directory file: "
|
|
|
|
|
+ foundfile,
|
|
|
|
|
Error::LATEX);
|
|
|
|
|
head.insert(foundfile);
|
|
|
|
|
PathPop();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
PathPop();
|
|
|
|
|
|
|
|
|
|
lyxerr.debug("Not a file or we are unable to find it.",
|
|
|
|
|
Error::LATEX);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void LaTeX::deptex(DepTable &head)
|
|
|
|
|
{
|
|
|
|
|
int except = AUX|LOG|DVI|BBL|IND|GLO;
|
1999-10-02 16:21:10 +00:00
|
|
|
|
string tmp;
|
1999-09-27 18:44:28 +00:00
|
|
|
|
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("deptex: " + tmp, Error::LATEX);
|
|
|
|
|
if (fi.newFile(tmp).exist())
|
|
|
|
|
head.insert(tmp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|