/** * Updates the stack that determines which file we are currently * parsing, so that errors can be annotated in the correct file. * * @param logLine A line from latex' output containing which file we are in */ private void updateParsedFile(String logLine, TexCompiler.Job job) { if (logLine.IndexOf('(') == -1 && logLine.IndexOf(')') == -1) { return; } for (int i = 0; i < logLine.Length; i++) { if (logLine[i] == '(') { int j; for (j = i + 1; j < logLine.Length && isAllowedinName(logLine[j]); j++) { ; } parsingStack.Push(logLine.Substring(i, j - i).Trim()); i = j - 1; } else if (logLine[i] == ')' && !(parsingStack.Count == 0)) { parsingStack.Pop(); } else if (logLine[i] == ')' && !alreadyShowError) { alreadyShowError = true; // There was a parsing error, this is very rare string err = "Error while parsing the LaTeX output. " + "Please consult the console output"; MainWindow.AddStatusLine(err, true); addProblemMarker(err, "file", 0, Severity.ERROR, job); } } }
public bool parseOutput(TexCompiler.Job job) { //if WholeOutput is not complete, ignore it. However, this should NEVER happen. if (!WholeOutput.Contains("Transcript written on")) { WholeOutput = ""; return(true); } //take WholeOutput and use each line as token StringTokenizer st = new StringTokenizer(WholeOutput, Environment.NewLine); //reset all variables (actually most of them could be local variables...) parseNewOutput(); Regex LATEXERROR = new Regex("^! LaTeX Error: (.*)$"); Regex LATEXCERROR = new Regex("^(.+?\\.\\w{3}):(\\d+): (.+)$"); Regex TEXERROR = new Regex("^!\\s+(.*)$"); Regex FULLBOX = new Regex("^(?:Over|Under)full \\\\[hv]box .* at lines? (\\d+)-?-?(\\d+)?"); Regex WARNING = new Regex("^.+[Ww]arning.*: (.*)$"); Regex ATLINE = new Regex("^l\\.(\\d+)(.*)$"); Regex ATLINE2 = new Regex(".* line (\\d+).*"); Regex NOBIBFILE = new Regex("^No file .+\\.bbl\\.$"); Regex NOTOCFILE = new Regex("^No file .+\\.toc\\.$"); String line = ""; while (st.hasMoreTokens()) { line = st.nextToken(); #region Skipped /* //This is assumed to be performed before adding lines to WholeOutput by calling addLine() * //Add more lines if line length is a multiple of 79 and * //it does not end with ... * while (!line.endsWith("...") && st.hasMoreTokens() * && line.length() % MAX_LINE_LENGTH == 0) * { * line = line + st.nextToken(); * } */ #endregion //not sure what this is good for line = line.Replace(" {2,}", " ").Trim(); Match m = LATEXCERROR.Match(line); if (m.Success) { //C-Style LaTeX error addProblemMarker(m.Groups[3].Value, m.Groups[1].Value, Convert.ToInt32(m.Groups[2]), Severity.ERROR, job); //Maybe parsingStack is empty... if (parsingStack.Count == 0) { //Add the file to the stack parsingStack.Push("(" + m.Groups[1]); } continue; } m = TEXERROR.Match(line); if (m.Success && line.IndexOf("warning", StringComparison.InvariantCultureIgnoreCase) == -1) { if (hasProblem) { // We have a not reported problem addProblemMarker(error, occurance, linenr, severity, job); linenr = -1; } hasProblem = true; errorsFound = true; severity = Severity.ERROR; occurance = determineSourceFile(); Match m2 = LATEXERROR.Match(line); if (m2.Success) { // LaTex error error = m2.Groups[1].Value;; String part2 = st.nextToken().Trim(); if (part2 != "" && Char.IsLower(part2[0])) { error += ' ' + part2; } updateParsedFile(part2, job); continue; } if (line.StartsWith("! Undefined control sequence.")) { // Undefined Control Sequence error = "Undefined control sequence: "; continue; } m2 = WARNING.Match(line); if (m2.Success) { severity = Severity.WARNING; } error = m.Groups[1].Value; continue; } m = WARNING.Match(line); if (m.Success) { if (hasProblem) { // We have a not reported problem addProblemMarker(error, occurance, linenr, severity, job); linenr = -1; hasProblem = false; } if (line.IndexOf("Label(s) may have changed.") > -1) { // prepare to re-run latex /*TexlipseProperties.setSessionProperty(resource.getProject(), * TexlipseProperties.SESSION_LATEX_RERUN, "true");*/ MainWindow.AddStatusLine("SHOULD RERUN LATEX.", true); continue; } else if (line.IndexOf("There were undefined") > -1) { if (citeNotfound) { // prepare to run bibtex /*TexlipseProperties.setSessionProperty(resource.getProject(), * TexlipseProperties.SESSION_BIBTEX_RERUN, "true");*/ MainWindow.AddStatusLine("SHOULD RERUN BIBTEX.", true); } continue; } // Ignore undefined references or citations because they are // found by the parser if (line.IndexOf("Warning: Reference `") > -1) { continue; } if (line.IndexOf("Warning: Citation `") > -1) { citeNotfound = true; continue; } severity = Severity.WARNING; occurance = determineSourceFile(); hasProblem = true; if (line.StartsWith("LaTeX Warning: ") || line.IndexOf("pdfTeX warning") != -1) { error = m.Groups[1].Value; //Try to get the line number Match pm = ATLINE2.Match(line); if (pm.Success) { linenr = Convert.ToInt32(pm.Groups[1].Value); } String nextLine = st.nextToken().Replace(" {2,}", " "); pm = ATLINE2.Match(nextLine); if (pm.Success) { linenr = Convert.ToInt32(pm.Groups[1].Value); } updateParsedFile(nextLine, job); error += nextLine; if (linenr != -1) { addProblemMarker(line, occurance, linenr, severity, job); hasProblem = false; linenr = -1; } continue; } else { error = m.Groups[1].Value; //Try to get the line number Match pm = ATLINE2.Match(line); if (pm.Success) { linenr = Convert.ToInt32((pm.Groups[1].Value)); } continue; } } m = FULLBOX.Match(line); if (m.Success) { if (hasProblem) { // We have a not reported problem addProblemMarker(error, occurance, linenr, severity, job); linenr = -1; hasProblem = false; } severity = Severity.WARNING; occurance = determineSourceFile(); error = line; linenr = Convert.ToInt32(m.Groups[1].Value); addProblemMarker(line, occurance, linenr, severity, job); hasProblem = false; linenr = -1; continue; } m = NOBIBFILE.Match(line); if (m.Success) { // prepare to run bibtex MainWindow.AddStatusLine("SHOULD RUN BIBTEX.", true); continue; } m = NOTOCFILE.Match(line); if (m.Success) { // prepare to re-run latex MainWindow.AddStatusLine("SHOULD RERUN LATEX.", true); continue; } m = ATLINE.Match(line); if (hasProblem && m.Success) { linenr = Convert.ToInt32(m.Groups[1].Value); String part2 = st.nextToken(); int index = line.IndexOf(' '); if (index > -1) { error += " " + line.Substring(index).Trim() + " (followed by: " + part2.Trim() + ")"; addProblemMarker(error, occurance, linenr, severity, job); linenr = -1; hasProblem = false; continue; } } m = ATLINE2.Match(line); if (hasProblem && m.Success) { linenr = Convert.ToInt32(m.Groups[1].Value); addProblemMarker(error, occurance, linenr, severity, job); linenr = -1; hasProblem = false; continue; } updateParsedFile(line, job); } if (hasProblem) { // We have a not reported problem // do not add "==> Fatal error blabla " to error list (is not an error) //addProblemMarker(error, occurance, linenr, severity); //hasProblem = false; } return(errorsFound); }
/// <summary> /// Private function that is called for each found problem in output of pdflatex when /// calling parseOutput(). addProblemMarker() fits the arguments into addProblemEventArgs /// so that addProblemEventHandler addProblem can be triggered. /// </summary> private void addProblemMarker(String error, String causingSourceFile, int linenr, Severity severity, TexCompiler.Job job) { if (OnTexError != null) { TexError e = new TexError(); e.error = error; e.causingSourceFile = causingSourceFile; e.linenr = linenr; if (job != null) { if (e.causingSourceFile == null) { e.inincludefile = true; } else { e.inincludefile = (String.Compare(e.causingSourceFile.Trim(), System.IO.Path.GetFullPath(job.path), true) != 0); } if (!e.inincludefile && linenr > 0) { e.linenr = job.TempFileLineToEditorLine(e.linenr); } if (!e.inincludefile) { //trim preview file ending. e.causingSourceFile = e.SourceFileName.Substring(0, (e.SourceFileName.Length - Helper.GetPreviewFilename().Length - Helper.GetPreviewFilenameExt().Length)); } } e.pos = -1; e.severity = severity; OnTexError(this, e, job); } }