/*
* $Id$
*
* Copyright (c) 2004-2005 by the TeXlapse Team.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package net.sourceforge.texlipse.builder;
import java.io.File;
import java.util.StringTokenizer;
import net.sourceforge.texlipse.TexlipsePlugin;
import net.sourceforge.texlipse.properties.TexlipseProperties;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
/**
* Run the external bibtex command.
*
* @author Kimmo Karlsson
*/
public class BibtexRunner extends AbstractProgramRunner {
/**
* Create a new bibtex program runner
*/
public BibtexRunner() {
super();
}
/**
* @return bibtex program name in windows
*/
protected String getWindowsProgramName() {
return "bibtex.exe";
}
/**
* @return bibtex program name in unix systems
*/
protected String getUnixProgramName() {
return "bibtex";
}
/**
* @return bibtex program description
*/
public String getDescription() {
return "Bibtex program";
}
protected String[] getQueryString() {
return new String[] {"Please type input file name (no extension)--"};
}
/**
* @param resource the project's main file to build
* @return arguments for the bibtex program when building the given resource
*/
public String getArguments(IResource resource) {
String args = super.getArguments(resource);
//Bibtex stops if there is a fileextension, so remove it
String name = resource.getName();
String baseName = name.substring(0, name.lastIndexOf('.'));
int bPos = args.indexOf(baseName + "." + getInputFormat());
if (bPos >= 0) {
args = args.substring(0, bPos + baseName.length()) +
args.substring(bPos + baseName.length() + 1 + getInputFormat().length());
}
return args;
// String args = "";
// Seems unnecessary now, but we need more testing
// String os = System.getProperty("os.name").toLowerCase();
// if (os.indexOf("windows") >= 0) {
// args = getIncludeDirArguments(resource.getProject());
// }
/* String name = resource.getName();
String baseName = name.substring(0, name.lastIndexOf('.'));
//return args + baseName;
return baseName;*/
}
/**
* Find out the real locations of the needed bib files.
* @return the directories containing needed bib files as arguments
*/
private String getIncludeDirArguments(IResource project) {
String[] bibs = (String[]) TexlipseProperties.getSessionProperty(project, TexlipseProperties.BIBFILE_PROPERTY);
if (bibs == null) {
return " ";
}
String bibDirs = TexlipsePlugin.getDefault().getPreferenceStore().getString(TexlipseProperties.BIB_DIR);
if (bibDirs == null) {
bibDirs = "";
}
Boolean biblatexMode = (Boolean) TexlipseProperties.getSessionProperty(project,
TexlipseProperties.SESSION_BIBLATEXMODE_PROPERTY);
// TODO useless? shouldn't be such a project property
String aDir = TexlipseProperties.getProjectProperty(project, TexlipseProperties.BIBFILE_PROPERTY);
if (aDir == null) {
aDir = "";
}
String pDir = project.getLocation().toOSString();
String[] dirs = (bibDirs + aDir + File.pathSeparatorChar + pDir).split(File.pathSeparator);
if (dirs == null) {
dirs = new String[0];
}
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bibs.length; i++) {
for (int j = 0; j < dirs.length; j++) {
String bibPath;
if (biblatexMode == null) {
bibPath = dirs[j] + bibs[i] + ".bib";
}
else {
bibPath = dirs[j] + bibs[i];
}
File b = new File(bibPath);
if (b.exists()) {
sb.append(" -include-dir=");
sb.append(dirs[j]);
}
}
}
sb.append(' ');
return sb.toString();
}
public String getInputFormat() {
return TexlipseProperties.INPUT_FORMAT_BIB;
}
public String getOutputFormat() {
return TexlipseProperties.OUTPUT_FORMAT_AUX;
}
/**
* Parse the output of the BibTeX program.
*
* @param origResource the input tex file that was processed
* @param output the output of the external program
* @return true, if error messages were found in the output, false otherwise
*/
protected boolean parseErrors(IResource origResource, String output) {
IProject project = origResource.getProject();
IContainer sourceDir = TexlipseProperties.getProjectSourceDir(project);
if (sourceDir == null) {
sourceDir = project;
}
//Initialize bibResource with origResource so that all errors are at least
//displayed even if no valid bib file was found
IResource bibResource = origResource;
boolean errorsFound = false;
StringTokenizer st = new StringTokenizer(output, "\r\n");
while (st.hasMoreTokens()) {
String line = st.nextToken();
if (line.indexOf("I was expecting a ") == 0) {
parseErrorLine(sourceDir, line);
errorsFound = true;
} else if (line.startsWith("You're missing a field name")) {
parseErrorLine(sourceDir, line);
errorsFound = true;
} else if (line.startsWith("Warning--")) {
String message = line.substring(9);
Integer lineNumber = null;
String nextLine = st.nextToken();
// see if additional info is available about the warning
if (nextLine.startsWith("--line ")) {
int index = nextLine.indexOf(" of file ");
try {
lineNumber = new Integer(nextLine.substring(7, index));
} catch (NumberFormatException e) {
}
String fileName = nextLine.substring(index + 9);
IResource resource = sourceDir.findMember(fileName);
createMarker(resource, lineNumber, message, IMarker.SEVERITY_WARNING);
} else if (nextLine.startsWith("Warning--")) {
// if followed by another warning, this is the endlist with no info
createMarker(bibResource, lineNumber, message, IMarker.SEVERITY_WARNING);
createMarker(bibResource, lineNumber, nextLine.substring(9), IMarker.SEVERITY_WARNING);
} else {
// list of warnings ended
createMarker(bibResource, lineNumber, message, IMarker.SEVERITY_WARNING);
}
} else if (line.startsWith("Database file ")) {
String bibName = line.substring(line.indexOf(':')+2);
bibResource = sourceDir.findMember(bibName);
if (bibResource == null) {
//Could happen if bibName is not part of project (kpathsea)
bibResource = origResource;
}
} else if (line.startsWith("I couldn't open database file ")) {
String bibName = line.substring(line.indexOf("file")+5);
// TODO Add marker to main file, but we should really find the offending
// \bibliography command in the main file and add it to the right line.
String srcFile = TexlipseProperties.getProjectProperty(project,
TexlipseProperties.MAINFILE_PROPERTY);
IResource mainFileResource = sourceDir.findMember(srcFile);
createMarker(mainFileResource, new Integer(0), "Could not open bibtex database file " + bibName);
return true; // errors found, and no use in parsing the rest of the file
}
}
return errorsFound;
}
/**
* Parse a Bibtex error message from the given line.
* Create also an error marker to the right place.
*
* @param sourceDir directory containing project's source files
* @param line the error message line
*/
private void parseErrorLine(IContainer sourceDir, String line) {
int index = line.indexOf("---line ");
int index2 = line.indexOf(" of file ", index);
String lineNumberString = line.substring(index+8, index2);
Integer lineNumber = null;
try {
int num = Integer.parseInt(lineNumberString);
lineNumber = new Integer(num);
} catch (NumberFormatException e) {
}
String fileName = line.substring(index2+9);
IResource resource = sourceDir.findMember(fileName);
String error = line.substring(0, index);
createMarker(resource, lineNumber, error);
}
}