/***************************************************************************
begin : Die Sep 16 2003
copyright : ( C ) 2003 by Jeroen Wijnhout
email : wijnhout @ science . uva . nl
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/***************************************************************************
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// 2007-03-12 dani
// - use KileDocument::Extensions
# include "latexoutputfilter.h"
# include <tqfile.h>
# include <tqregexp.h>
# include <tqfileinfo.h>
# include "kiledebug.h"
# include <ktextedit.h>
# include <tdelocale.h>
# include "kiletool_enums.h"
using namespace std ;
LatexOutputFilter : : LatexOutputFilter ( LatexOutputInfoArray * LatexOutputInfoArray , KileDocument : : Extensions * extensions ) :
m_nErrors ( 0 ) ,
m_nWarnings ( 0 ) ,
m_nBadBoxes ( 0 ) ,
m_InfoList ( LatexOutputInfoArray ) ,
m_extensions ( extensions )
{
}
LatexOutputFilter : : ~ LatexOutputFilter ( )
{
}
bool LatexOutputFilter : : OnPreCreate ( )
{
m_nErrors = 0 ;
m_nWarnings = 0 ;
m_nBadBoxes = 0 ;
return true ;
}
bool LatexOutputFilter : : fileExists ( const TQString & name )
{
static TQFileInfo fi ;
if ( name [ 0 ] = = ' / ' )
{
fi . setFile ( name ) ;
if ( fi . exists ( ) & & ! fi . isDir ( ) ) return true ;
else return false ;
}
fi . setFile ( path ( ) + ' / ' + name ) ;
if ( fi . exists ( ) & & ! fi . isDir ( ) ) return true ;
fi . setFile ( path ( ) + ' / ' + name + m_extensions - > latexDocumentDefault ( ) ) ;
if ( fi . exists ( ) & & ! fi . isDir ( ) ) return true ;
// try to determine the LaTeX source file
TQStringList extlist = TQStringList : : split ( " " , m_extensions - > latexDocuments ( ) ) ;
for ( TQStringList : : Iterator it = extlist . begin ( ) ; it ! = extlist . end ( ) ; + + it )
{
fi . setFile ( path ( ) + ' / ' + name + ( * it ) ) ;
if ( fi . exists ( ) & & ! fi . isDir ( ) )
return true ;
}
return false ;
}
// There are basically two ways to detect the current file TeX is processing:
// 1) Use \Input (i.c.w. srctex.sty or srcltx.sty) and \include exclusively. This will
// cause (La)TeX to print the line ":<+ filename" in the log file when opening a file,
// ":<-" when closing a file. Filenames pushed on the stack in this mode are marked
// as reliable.
//
// 2) Since people will probably also use the \input command, we also have to be
// to detect the old-fashioned way. TeX prints '(filename' when opening a file and a ')'
// when closing one. It is impossible to detect this with 100% certainty (TeX prints many messages
// and even text (a context) from the TeX source file, there could be unbalanced parentheses),
// so we use a heuristic algorithm. In heuristic mode a ')' will only be considered as a signal that
// TeX is closing a file if the top of the stack is not marked as "reliable".
// Also, when scanning for a TeX error linenumber (which sometimes causes a context to be printed
// to the log-file), updateFileStack is not called, helping not to pick up unbalanced parentheses
// from the context.
void LatexOutputFilter : : updateFileStack ( const TQString & strLine , short & dwCookie )
{
//KILE_DEBUG() << "==LatexOutputFilter::updateFileStack()================" << endl;
static TQString strPartialFileName ;
switch ( dwCookie )
{
//we're looking for a filename
case Start : case FileNameHeuristic :
//TeX is opening a file
if ( strLine . startsWith ( " :<+ " ) )
{
// KILE_DEBUG() << "filename detected" << endl;
//grab the filename, it might be a partial name (i.e. continued on the next line)
strPartialFileName = strLine . mid ( 4 ) . stripWhiteSpace ( ) ;
//change the cookie so we remember we aren't sure the filename is complete
dwCookie = FileName ;
}
//TeX closed a file
else if ( strLine . startsWith ( " :<- " ) )
{
// KILE_DEBUG() << "\tpopping : " << m_stackFile.top().file() << endl;
m_stackFile . pop ( ) ;
dwCookie = Start ;
}
else
//fallback to the heuristic detection of filenames
updateFileStackHeuristic ( strLine , dwCookie ) ;
break ;
case FileName :
//The partial filename was followed by '(', this means that TeX is signalling it is
//opening the file. We are sure the filename is complete now. Don't call updateFileStackHeuristic
//since we don't want the filename on the stack twice.
if ( strLine . startsWith ( " ( " ) | | strLine . startsWith ( " \\ openout " ) )
{
//push the filename on the stack and mark it as 'reliable'
m_stackFile . push ( LOFStackItem ( strPartialFileName , true ) ) ;
// KILE_DEBUG() << "\tpushed : " << strPartialFileName << endl;
strPartialFileName = TQString ( ) ;
dwCookie = Start ;
}
//The partial filename was followed by an TeX error, meaning the file doesn't exist.
//Don't push it on the stack, instead try to detect the error.
else if ( strLine . startsWith ( " ! " ) )
{
// KILE_DEBUG() << "oops!" << endl;
dwCookie = Start ;
strPartialFileName = TQString ( ) ;
detectError ( strLine , dwCookie ) ;
}
else if ( strLine . startsWith ( " No file " ) )
{
// KILE_DEBUG() << "No file: " << strLine << endl;
dwCookie = Start ;
strPartialFileName = TQString ( ) ;
detectWarning ( strLine , dwCookie ) ;
}
//Partial filename still isn't complete.
else
{
// KILE_DEBUG() << "\tpartial file name, adding" << endl;
strPartialFileName = strPartialFileName + strLine . stripWhiteSpace ( ) ;
}
break ;
default : break ;
}
}
void LatexOutputFilter : : updateFileStackHeuristic ( const TQString & strLine , short & dwCookie )
{
//KILE_DEBUG() << "==LatexOutputFilter::updateFileStackHeuristic()================" << endl;
static TQString strPartialFileName ;
bool expectFileName = ( dwCookie = = FileNameHeuristic ) ;
int index = 0 ;
// handle special case (bug fix for 101810)
if ( expectFileName & & strLine [ 0 ] = = ' ) ' ) {
m_stackFile . push ( LOFStackItem ( strPartialFileName ) ) ;
expectFileName = false ;
dwCookie = Start ;
}
//scan for parentheses and grab filenames
for ( unsigned int i = 0 ; i < strLine . length ( ) ; + + i ) {
//We're expecting a filename. If a filename really ends at this position one of the following must be true:
// 1) Next character is a space (indicating the end of a filename (yes, there can't spaces in the
// path, this is a TeX limitation).
// 2) We're at the end of the line, the filename is probably continued on the next line.
// 3) The TeX was closed already, signalled by the ')'.
if ( expectFileName & & ( i + 1 = = strLine . length ( ) | | strLine [ i + 1 ] . isSpace ( ) | | strLine [ i + 1 ] = = ' ) ' ) ) {
//update the partial filename
strPartialFileName = strPartialFileName + strLine . mid ( index , i - index + 1 ) ;
//FIXME: improve these heuristics
if ( strLine [ i + 1 ] . isSpace ( ) | | ( ( i < 78 ) & & ( i + 1 = = strLine . length ( ) ) ) | |
strLine [ i + 1 ] = = ' ) ' | |
fileExists ( strPartialFileName ) ) {
m_stackFile . push ( LOFStackItem ( strPartialFileName ) ) ;
// KILE_DEBUG() << "\tpushed (i = " << i << " length = " << strLine.length() << "): " << strPartialFileName << endl;
expectFileName = false ;
dwCookie = Start ;
}
//Guess the filename is continued on the next line.
else if ( i + 1 = = strLine . length ( ) ) {
// KILE_DEBUG() << "\tFilename spans more than one line." << endl;
dwCookie = FileNameHeuristic ;
}
//bail out
else {
dwCookie = Start ;
strPartialFileName = TQString ( ) ;
expectFileName = false ;
}
}
//TeX is opening a file
else if ( strLine [ i ] = = ' ( ' ) {
//we need to extract the filename
expectFileName = true ;
strPartialFileName = TQString ( ) ;
dwCookie = Start ;
//this is were the filename is supposed to start
index = i + 1 ;
}
//TeX is closing a file
else if ( strLine [ i ] = = ' ) ' ) {
// KILE_DEBUG() << "\tpopping : " << m_stackFile.top().file() << endl;
//If this filename was pushed on the stack by the reliable ":<+-" method, don't pop
//a ":<-" will follow. This helps in preventing unbalanced ')' from popping filenames
//from the stack too soon.
if ( ! m_stackFile . top ( ) . reliable ( ) )
m_stackFile . pop ( ) ;
else
KILE_DEBUG ( ) < < " \t \t oh no, forget about it! " < < endl ;
}
}
}
void LatexOutputFilter : : flushCurrentItem ( )
{
//KILE_DEBUG() << "==LatexOutputFilter::flushCurrentItem()================" << endl;
int nItemType = m_currentItem . type ( ) ;
while ( ( ! fileExists ( m_stackFile . top ( ) . file ( ) ) ) & & ( m_stackFile . count ( ) > 1 ) )
m_stackFile . pop ( ) ;
m_currentItem . setSource ( m_stackFile . top ( ) . file ( ) ) ;
switch ( nItemType )
{
case itmError :
+ + m_nErrors ;
m_InfoList - > push_back ( m_currentItem ) ;
//KILE_DEBUG() << "Flushing Error in" << m_currentItem.source() << "@" << m_currentItem.sourceLine() << " reported in line " << m_currentItem.outputLine() << endl;
break ;
case itmWarning :
+ + m_nWarnings ;
m_InfoList - > push_back ( m_currentItem ) ;
//KILE_DEBUG() << "Flushing Warning in " << m_currentItem.source() << "@" << m_currentItem.sourceLine() << " reported in line " << m_currentItem.outputLine() << endl;
break ;
case itmBadBox :
+ + m_nBadBoxes ;
m_InfoList - > push_back ( m_currentItem ) ;
//KILE_DEBUG() << "Flushing BadBox in " << m_currentItem.source() << "@" << m_currentItem.sourceLine() << " reported in line " << m_currentItem.outputLine() << endl;
break ;
default : break ;
}
m_currentItem . Clear ( ) ;
}
bool LatexOutputFilter : : detectError ( const TQString & strLine , short & dwCookie )
{
//KILE_DEBUG() << "==LatexOutputFilter::detectError(" << strLine.length() << ")================" << endl;
bool found = false , flush = false ;
static TQRegExp reLaTeXError ( " ^! LaTeX Error: (.*) $ " , false) ;
static TQRegExp rePDFLaTeXError ( " ^Error: pdflatex (.*) $ " , false) ;
static TQRegExp reTeXError ( " ^! (.*) \ \ . $ " ) ;
static TQRegExp reLineNumber ( " ^l \\ .([0-9]+) ( . * ) " ) ;
switch ( dwCookie )
{
case Start :
if ( reLaTeXError . search ( strLine ) ! = - 1 )
{
//KILE_DEBUG() << "\tError : " << reLaTeXError.cap(1) << endl;
m_currentItem . setMessage ( reLaTeXError . cap ( 1 ) ) ;
found = true ;
}
else if ( rePDFLaTeXError . search ( strLine ) ! = - 1 )
{
//KILE_DEBUG() << "\tError : " << rePDFLaTeXError.cap(1) << endl;
m_currentItem . setMessage ( rePDFLaTeXError . cap ( 1 ) ) ;
found = true ;
}
else if ( reTeXError . search ( strLine ) ! = - 1 )
{
//KILE_DEBUG() << "\tError : " << reTeXError.cap(1) << endl;
m_currentItem . setMessage ( reTeXError . cap ( 1 ) ) ;
found = true ;
}
if ( found )
{
dwCookie = strLine . endsWith ( " . " ) ? LineNumber : Error ;
m_currentItem . setOutputLine ( GetCurrentOutputLine ( ) ) ;
}
break ;
case Error :
//KILE_DEBUG() << "\tError (cont'd): " << strLine << endl;
if ( strLine . endsWith ( " . " ) )
{
dwCookie = LineNumber ;
m_currentItem . setMessage ( m_currentItem . message ( ) + strLine ) ;
}
else if ( GetCurrentOutputLine ( ) - m_currentItem . outputLine ( ) > 3 )
{
kdWarning ( ) < < " \t BAILING OUT: error description spans more than three lines " < < endl ;
dwCookie = Start ;
flush = true ;
}
break ;
case LineNumber :
//KILE_DEBUG() << "\tLineNumber " << endl;
if ( reLineNumber . search ( strLine ) ! = - 1 )
{
dwCookie = Start ;
flush = true ;
//KILE_DEBUG() << "\tline number: " << reLineNumber.cap(1) << endl;
m_currentItem . setSourceLine ( reLineNumber . cap ( 1 ) . toInt ( ) ) ;
m_currentItem . setMessage ( m_currentItem . message ( ) + reLineNumber . cap ( 2 ) ) ;
}
else if ( GetCurrentOutputLine ( ) - m_currentItem . outputLine ( ) > 10 )
{
dwCookie = Start ;
flush = true ;
kdWarning ( ) < < " \t BAILING OUT: did not detect a TeX line number for an error " < < endl ;
m_currentItem . setSourceLine ( 0 ) ;
}
break ;
default : break ;
}
if ( found )
{
m_currentItem . setType ( itmError ) ;
m_currentItem . setOutputLine ( GetCurrentOutputLine ( ) ) ;
}
if ( flush ) flushCurrentItem ( ) ;
return found ;
}
bool LatexOutputFilter : : detectWarning ( const TQString & strLine , short & dwCookie )
{
//KILE_DEBUG() << "==LatexOutputFilter::detectWarning(" << strLine.length() << ")================" << endl;
bool found = false , flush = false ;
TQString warning ;
static TQRegExp reLaTeXWarning ( " ^(((! ) ? ( La | pdf ) TeX ) | Package | Class ) . * Warning . * : ( . * ) " , false) ;
static TQRegExp reNoFile ( " No file (.*) " ) ;
static TQRegExp reNoAsyFile ( " File .* does not exist. " ) ; // FIXME can be removed when http://sourceforge.net/tracker/index.php?func=detail&aid=1772022&group_id=120000&atid=685683 has promoted to the users
switch ( dwCookie )
{
//detect the beginning of a warning
case Start :
if ( reLaTeXWarning . search ( strLine ) ! = - 1 )
{
warning = reLaTeXWarning . cap ( 5 ) ;
//KILE_DEBUG() << "\tWarning found: " << warning << endl;
found = true ;
dwCookie = Start ;
m_currentItem . setMessage ( warning ) ;
m_currentItem . setOutputLine ( GetCurrentOutputLine ( ) ) ;
//do we expect a line number?
flush = detectLaTeXLineNumber ( warning , dwCookie , strLine . length ( ) ) ;
}
else if ( reNoFile . search ( strLine ) ! = - 1 )
{
found = true ;
flush = true ;
m_currentItem . setSourceLine ( 0 ) ;
m_currentItem . setMessage ( reNoFile . cap ( 0 ) ) ;
m_currentItem . setOutputLine ( GetCurrentOutputLine ( ) ) ;
}
else if ( reNoAsyFile . search ( strLine ) ! = - 1 )
{
found = true ;
flush = true ;
m_currentItem . setSourceLine ( 0 ) ;
m_currentItem . setMessage ( reNoAsyFile . cap ( 0 ) ) ;
m_currentItem . setOutputLine ( GetCurrentOutputLine ( ) ) ;
}
break ;
//warning spans multiple lines, detect the end
case Warning :
warning = m_currentItem . message ( ) + strLine ;
//KILE_DEBUG() << "'\tWarning (cont'd) : " << warning << endl;
flush = detectLaTeXLineNumber ( warning , dwCookie , strLine . length ( ) ) ;
m_currentItem . setMessage ( warning ) ;
break ;
default : break ;
}
if ( found )
{
m_currentItem . setType ( itmWarning ) ;
m_currentItem . setOutputLine ( GetCurrentOutputLine ( ) ) ;
}
if ( flush ) flushCurrentItem ( ) ;
return found ;
}
bool LatexOutputFilter : : detectLaTeXLineNumber ( TQString & warning , short & dwCookie , int len )
{
//KILE_DEBUG() << "==LatexOutputFilter::detectLaTeXLineNumber(" << warning.length() << ")================" << endl;
static TQRegExp reLaTeXLineNumber ( " (.*) on input line ( [ 0 - 9 ] + ) \ \ . $ " , false) ;
static TQRegExp reInternationalLaTeXLineNumber ( " (.*) ( [ 0 - 9 ] + ) \ \ . $ " , false) ;
if ( ( reLaTeXLineNumber . search ( warning ) ! = - 1 ) | | ( reInternationalLaTeXLineNumber . search ( warning ) ! = - 1 ) )
{
//KILE_DEBUG() << "een" << endl;
m_currentItem . setSourceLine ( reLaTeXLineNumber . cap ( 2 ) . toInt ( ) ) ;
warning + = reLaTeXLineNumber . cap ( 1 ) ;
dwCookie = Start ;
return true ;
}
else if ( warning . endsWith ( " . " ) )
{
//KILE_DEBUG() << "twee" << endl;
m_currentItem . setSourceLine ( 0 ) ;
dwCookie = Start ;
return true ;
}
//bailing out, did not find a line number
else if ( ( GetCurrentOutputLine ( ) - m_currentItem . outputLine ( ) > 4 ) | | ( len = = 0 ) )
{
//KILE_DEBUG() << "drie current " << GetCurrentOutputLine() << " " << m_currentItem.outputLine() << " len " << len << endl;
m_currentItem . setSourceLine ( 0 ) ;
dwCookie = Start ;
return true ;
}
//error message is continued on the other line
else
{
//KILE_DEBUG() << "vier" << endl;
dwCookie = Warning ;
return false ;
}
}
bool LatexOutputFilter : : detectBadBox ( const TQString & strLine , short & dwCookie )
{
//KILE_DEBUG() << "==LatexOutputFilter::detectBadBox(" << strLine.length() << ")================" << endl;
bool found = false , flush = false ;
TQString badbox ;
static TQRegExp reBadBox ( " ^(Over|Under) ( full \ \ \ \ [ hv ] box . * ) " , false) ;
switch ( dwCookie )
{
case Start :
if ( reBadBox . search ( strLine ) ! = - 1 )
{
found = true ;
dwCookie = Start ;
badbox = strLine ;
flush = detectBadBoxLineNumber ( badbox , dwCookie , strLine . length ( ) ) ;
m_currentItem . setMessage ( badbox ) ;
}
break ;
case BadBox :
badbox = m_currentItem . message ( ) + strLine ;
flush = detectBadBoxLineNumber ( badbox , dwCookie , strLine . length ( ) ) ;
m_currentItem . setMessage ( badbox ) ;
break ;
default : break ;
}
if ( found )
{
m_currentItem . setType ( itmBadBox ) ;
m_currentItem . setOutputLine ( GetCurrentOutputLine ( ) ) ;
}
if ( flush ) flushCurrentItem ( ) ;
return found ;
}
bool LatexOutputFilter : : detectBadBoxLineNumber ( TQString & strLine , short & dwCookie , int len )
{
//KILE_DEBUG() << "==LatexOutputFilter::detectBadBoxLineNumber(" << strLine.length() << ")================" << endl;
static TQRegExp reBadBoxLines ( " (.*) at lines ( [ 0 - 9 ] + ) - - ( [ 0 - 9 ] + ) " , false) ;
static TQRegExp reBadBoxLine ( " (.*) at line ( [ 0 - 9 ] + ) " , false) ;
//Use the following only, if you know how to get the source line for it.
// This is not simple, as TeX is not reporting it.
static TQRegExp reBadBoxOutput ( " (.*) has occurred while \ \ output is active ^ " , false) ;
if ( reBadBoxLines . search ( strLine ) ! = - 1 )
{
dwCookie = Start ;
strLine = reBadBoxLines . cap ( 1 ) ;
int n1 = reBadBoxLines . cap ( 2 ) . toInt ( ) ;
int n2 = reBadBoxLines . cap ( 3 ) . toInt ( ) ;
m_currentItem . setSourceLine ( n1 < n2 ? n1 : n2 ) ;
return true ;
}
else if ( reBadBoxLine . search ( strLine ) ! = - 1 )
{
dwCookie = Start ;
strLine = reBadBoxLine . cap ( 1 ) ;
m_currentItem . setSourceLine ( reBadBoxLine . cap ( 2 ) . toInt ( ) ) ;
//KILE_DEBUG() << "\tBadBox@" << reBadBoxLine.cap(2) << "." << endl;
return true ;
}
else if ( reBadBoxOutput . search ( strLine ) ! = - 1 )
{
dwCookie = Start ;
strLine = reBadBoxLines . cap ( 1 ) ;
m_currentItem . setSourceLine ( 0 ) ;
return true ;
}
//bailing out, did not find a line number
else if ( ( GetCurrentOutputLine ( ) - m_currentItem . outputLine ( ) > 3 ) | | ( len = = 0 ) )
{
dwCookie = Start ;
m_currentItem . setSourceLine ( 0 ) ;
return true ;
}
else
{
dwCookie = BadBox ;
}
return false ;
}
short LatexOutputFilter : : parseLine ( const TQString & strLine , short dwCookie )
{
//KILE_DEBUG() << "==LatexOutputFilter::parseLine(" << strLine.length() << ")================" << endl;
switch ( dwCookie )
{
case Start :
if ( ! ( detectBadBox ( strLine , dwCookie ) | | detectWarning ( strLine , dwCookie ) | | detectError ( strLine , dwCookie ) ) )
updateFileStack ( strLine , dwCookie ) ;
break ;
case Warning :
detectWarning ( strLine , dwCookie ) ;
break ;
case Error : case LineNumber :
detectError ( strLine , dwCookie ) ;
break ;
case BadBox :
detectBadBox ( strLine , dwCookie ) ;
break ;
case FileName : case FileNameHeuristic :
updateFileStack ( strLine , dwCookie ) ;
break ;
default : dwCookie = Start ; break ;
}
return dwCookie ;
}
// split old Run() into three parts
// - Run() : parse the logfile
// - updateInfoLists() : needed by QuickPreview
// - sendProblems() : emit signals
//
// dani 18.02.2005
bool LatexOutputFilter : : Run ( const TQString & logfile )
{
m_InfoList - > clear ( ) ;
m_nErrors = m_nWarnings = m_nBadBoxes = m_nParens = 0 ;
m_stackFile . clear ( ) ;
m_stackFile . push ( LOFStackItem ( TQFileInfo ( source ( ) ) . fileName ( ) , true ) ) ;
return OutputFilter : : Run ( logfile ) ;
}
void LatexOutputFilter : : updateInfoLists ( const TQString & texfilename , int selrow , int docrow )
{
// get a short name for the original tex file
TQString filename = " ./ " + TQFileInfo ( texfilename ) . fileName ( ) ;
setSource ( texfilename ) ;
//print detailed error info
for ( unsigned int i = 0 ; i < m_InfoList - > count ( ) ; + + i ) {
// perhaps correct filename and line number in OutputInfo
OutputInfo * info = & ( * m_InfoList ) [ i ] ;
info - > setSource ( filename ) ;
int linenumber = selrow + info - > sourceLine ( ) - docrow ;
if ( linenumber < 0 )
linenumber = 0 ;
info - > setSourceLine ( linenumber ) ;
}
}
void LatexOutputFilter : : sendProblems ( )
{
TQString Message ;
int type ;
//print detailed error info
for ( unsigned int i = 0 ; i < m_InfoList - > count ( ) ; + + i ) {
Message = TQString ( " %1:%2:%3 " ) . arg ( ( * m_InfoList ) [ i ] . source ( ) ) . arg ( ( * m_InfoList ) [ i ] . sourceLine ( ) ) . arg ( ( * m_InfoList ) [ i ] . message ( ) ) ;
switch ( ( * m_InfoList ) [ i ] . type ( ) )
{
case LatexOutputInfo : : itmBadBox : type = KileTool : : ProblemBadBox ; break ;
case LatexOutputInfo : : itmError : type = KileTool : : ProblemError ; break ;
case LatexOutputInfo : : itmWarning : type = KileTool : : ProblemWarning ; break ;
default : type = KileTool : : Info ; break ;
}
emit ( problem ( type , Message ) ) ;
}
}
/** Return number of errors etc. found in log-file. */
void LatexOutputFilter : : getErrorCount ( int * errors , int * warnings , int * badboxes )
{
* errors = m_nErrors ;
* warnings = m_nWarnings ;
* badboxes = m_nBadBoxes ;
}