/*
Copyright (C) 2004 R. Nagel
All programs in this directory and
subdirectories are published under the GNU General Public License as
described below.
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.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
Further information about the GNU GPL is available at:
http://www.gnu.org/copyleft/gpl.ja.html
*/
/**
* <p>Title: Latex Aux to Bibtex</p>
*
* <p>Description: generates a sub-database which contains only bibtex entries
* from input aux file</p>
*
* <p>Copyright: Copyright (c) 2004</p>
*
* <p>Company: </p>
*
* @version 1.0
* @author r.nagel
*
* @todo Redesign of dialog structure for an assitent like feeling....
* Now - the unknown bibtex entries cannot inserted into the reference
* database without closing the dialog.
*/
// created by : r.nagel 23.08.2004
//
// modified : - 11.04.2005
// handling \\@input{file.aux} tag in aux files (nested aux files)
package net.sf.jabref.wizard.auximport ;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sf.jabref.BibtexDatabase;
import net.sf.jabref.BibtexEntry;
import net.sf.jabref.KeyCollisionException;
import net.sf.jabref.Util;
public class AuxSubGenerator
{
private HashSet<String> mySet ; // all unique bibtex keys in aux file
private Vector<String> notFoundList ; // all not solved bibtex keys
private BibtexDatabase db ; // reference database
private BibtexDatabase auxDB ; // contains only the bibtex keys who found in aux file
private int nestedAuxCounter ; // counts the nested aux files
private int crossreferencedEntriesCount = 0; // counts entries pulled in due to crossref
public AuxSubGenerator(BibtexDatabase refDBase)
{
mySet = new HashSet<String>(20) ;
notFoundList = new Vector<String>() ;
db = refDBase ;
}
public final void setReferenceDatabase(BibtexDatabase newRefDB)
{
db = newRefDB ;
}
/**
* parseAuxFile
* read the Aux file and fill up some intern data structures.
* Nested aux files (latex \\include) supported!
*
* @param filename String : Path to LatexAuxFile
* @return boolean, true = no error occurs
*/
// found at comp.text.tex
// > Can anyone tell be the information held within a .aux file? Is there a
// > specific format to this file?
//
// I don't think there is a particular format. Every package, class
// or document can write to the aux file. The aux file consists of LaTeX macros
// and is read at the \begin{document} and again at the \end{document}.
//
// It usually contains information about existing labels
// \\newlabel{sec:Intro}{{1}{1}}
// and citations
// \citation{hiri:conv:1993}
// and macros to write information to other files (like toc, lof or lot files)
// \@writefile{toc}{\contentsline {section}{\numberline
// {1}Intro}{1}}
// but as I said, there can be a lot more
// aux file :
//
// \\citation{x} x = used reference of bibtex library entry
//
// \\@input{x} x = nested aux file
//
// the \\bibdata{x} directive contains information about the
// bibtex library file -> x = name of bib file
//
// \\bibcite{x}{y}
// x is a label for an item and y is the index in bibliography
public final boolean parseAuxFile(String filename)
{
// regular expressions
Pattern pattern ;
Matcher matcher ;
// while condition
boolean weiter = false ;
// return value -> default: no error
boolean back = true ;
// fileopen status
boolean loopFileOpen = false ;
// the important tag
pattern = Pattern.compile( "\\\\citation\\{.+\\}" ) ;
// input-file-buffer
BufferedReader br = null ;
// filelist, used for nested aux files
Vector<String> fileList = new Vector<String>(5) ;
fileList.add( filename );
// get the file path
File dummy = new File( filename ) ;
String path = dummy.getParent() ;
if (path != null)
path = path + File.separator ;
else
path = "" ;
nestedAuxCounter = -1 ; // count only the nested reads
// index of current file in list
int fileIndex = 0 ;
while (fileIndex < fileList.size())
{
String fName = fileList.elementAt( fileIndex ) ;
try
{
// System.out.println("read #"+fName +"#") ;
br = new BufferedReader( new FileReader( fName ) ) ;
weiter = true ;
loopFileOpen = true ;
}
catch ( FileNotFoundException fnfe )
{
System.out.println( "Cannot locate input file! " + fnfe.getMessage() ) ;
// System.exit( 0 ) ;
back = false ;
weiter = false ;
loopFileOpen = false ;
}
while ( weiter )
{
String line ;
try
{
if (br == null)
throw new IOException();
line = br.readLine() ;
}
catch ( IOException ioe )
{
line = null ;
weiter = false ;
}
if ( line != null )
{
matcher = pattern.matcher( line ) ;
while ( matcher.find() )
{
// extract the bibtex-key(s) XXX from \citation{XXX} string
int len = matcher.end() - matcher.start() ;
if ( len > 11 )
{
String str = matcher.group().substring( matcher.start() + 10,
matcher.end() - 1 ) ;
// could be an comma separated list of keys
String keys[] = str.split( "," ) ;
if ( keys != null )
{
int keyCount = keys.length ;
for ( int t = 0 ; t < keyCount ; t++ )
{
String dummyStr = keys[t] ;
if ( dummyStr != null )
{
// delete all unnecessary blanks and save key into an set
mySet.add( dummyStr.trim() ) ;
// System.out.println("found " +str +" in AUX") ;
}
}
}
}
}
// try to find a nested aux file
int index = line.indexOf( "\\@input{" ) ;
if ( index >= 0 )
{
int start = index + 8 ;
int end = line.indexOf( "}", start ) ;
if ( end > start )
{
String str = path + line.substring( index + 8, end ) ;
// if filename already in filelist
if (!fileList.contains( str ) )
{
fileList.add(str); // insert file into filelist
}
}
}
} // line != null
else weiter = false ;
} // end of while
if ( loopFileOpen ) // only close, if open sucessful
{
try
{
if (br != null)
br.close() ;
nestedAuxCounter++ ;
}
catch ( IOException ioe )
{}
}
fileIndex++ ; // load next file
}
return back ;
}
/**
* resolveTags
* Try to find an equivalent bibtex entry into reference database for all keys
* (found in aux file). This methode will fill up some intern data structures.....
*/
public final void resolveTags()
{
auxDB = new BibtexDatabase() ;
notFoundList.clear();
Iterator<String> it = mySet.iterator() ;
// forall bibtex keys (found in aux-file) try to find an equivalent
// entry into reference database
while (it.hasNext())
{
String str = it.next() ;
BibtexEntry entry = db.getEntryByKey(str);
if (entry == null)
{
notFoundList.add(str) ;
} else
{
insertEntry(auxDB, entry);
// Check if the entry we just found references another entry which
// we don't already have in our list of entries to include. If so,
// pull in that entry as well:
String crossref = entry.getField("crossref");
if ((crossref != null) && (!mySet.contains(crossref))) {
BibtexEntry refEntry = db.getEntryByKey(crossref);
/**
* [ 1717849 ] Patch for aux import by Kai Eckert
*/
if (refEntry == null) {
notFoundList.add(crossref);
} else {
insertEntry(auxDB, refEntry);
crossreferencedEntriesCount++;
}
}
}
}
}
/**
* Insert a clone of the given entry. The clone is given a new unique ID.
* @param auxDB The database to insert into.
* @param entry The entry to insert a copy of.
*/
private void insertEntry(BibtexDatabase auxDB, BibtexEntry entry) {
try {
BibtexEntry clonedEntry = (BibtexEntry)entry.clone();
clonedEntry.setId(Util.createNeutralId());
auxDB.insertEntry(clonedEntry);
} catch (KeyCollisionException e) {
e.printStackTrace();
}
}
/**
* generate
* Shortcut methode for easy generation.
*
* @param auxFileName String
* @param bibDB BibtexDatabase - reference database
* @return Vector - contains all not resolved bibtex entries
*/
public final Vector<String> generate(String auxFileName, BibtexDatabase bibDB)
{
setReferenceDatabase(bibDB);
parseAuxFile(auxFileName) ;
resolveTags();
return notFoundList ;
}
public BibtexDatabase getGeneratedDatabase()
{
if (auxDB == null)
auxDB = new BibtexDatabase() ;
return auxDB ;
}
public final int getFoundKeysInAux()
{
return mySet.size() ;
}
public final int getResolvedKeysCount()
{
return auxDB.getEntryCount() - crossreferencedEntriesCount;
}
public final int getNotResolvedKeysCount()
{
return notFoundList.size() ;
}
/**
* Query the number of extra entries pulled in due to crossrefs from other
* entries.
* @return The number of additional entries pulled in due to crossref
*/
public final int getCrossreferencedEntriesCount()
{
return crossreferencedEntriesCount;
}
/** reset all used datastructures */
public final void clear()
{
mySet.clear() ;
notFoundList.clear();
crossreferencedEntriesCount = 0;
// db = null ; ???
}
/** returns a vector off all not resolved bibtex entries found in auxfile */
public Vector<String> getNotFoundList()
{
return notFoundList ;
}
/** returns the number of nested aux files, read by the last call of
* generate method */
public int getNestedAuxCounter()
{
return this.nestedAuxCounter ;
}
}