/*
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
*/
// created by : r.nagel 27.10.2004
//
// function : check all bibtex items and report errors, inconsistencies,
// warnings, hints and ....
//
// todo : find equal authors: e.g.: D. Knuth = Donald Knuth = Donald E. Knuth
// and try to give all items an identically look
//
// modified :
package net.sf.jabref.wizard.integrity ;
import java.util.Vector;
import net.sf.jabref.BibtexDatabase;
import net.sf.jabref.BibtexEntry;
public class IntegrityCheck
{
private Vector<IntegrityMessage> messages ;
public IntegrityCheck()
{
messages = new Vector<IntegrityMessage>() ;
}
public Vector<IntegrityMessage> checkBibtexDatabase(BibtexDatabase base) {
messages.clear();
if (base != null) {
for (BibtexEntry entry : base.getEntries()) {
checkSingleEntry(entry);
}
}
return new Vector<IntegrityMessage>(messages);
}
public Vector<IntegrityMessage> checkBibtexEntry(BibtexEntry entry) {
messages.clear();
checkSingleEntry(entry);
return new Vector<IntegrityMessage>(messages);
}
public void checkSingleEntry(BibtexEntry entry)
{
if (entry == null)
return ;
Object data = entry.getField("author") ;
if (data != null)
authorNameCheck( data.toString(), "author", entry) ;
data = entry.getField("editor") ;
if (data != null)
authorNameCheck( data.toString(), "editor", entry) ;
data = entry.getField("title") ;
if (data != null)
titleCheck( data.toString(), "title", entry) ;
data = entry.getField("year") ;
if (data != null)
yearCheck( data.toString(), "year", entry) ;
}
/** fills the class Vector (of IntegrityMessage Objects) which did inform about
* failures, hints....
* The Authors or Editors field could be invalid -> try to detect it!
* Knuth, Donald E. and Kurt Cobain and A. Einstein = N,NNaNNaNN
*/
private void authorNameCheck(String names, String fieldName, BibtexEntry entry)
{
// try to extract the structure of author tag
// N = name, ","= seperator, "a" = and
StringBuffer structure = new StringBuffer() ;
int len = names.length() ;
int mode = -1 ;
for (int t = 0 ; t < len ; t++)
{
char ch = names.charAt(t) ;
switch (ch)
{
case ',' :
if (mode == 5) // "and"
structure.append('a') ;
else
structure.append('N') ;
structure.append(',') ;
mode = 0 ;
break ;
case ' ' :
if (mode == 5) // "and"
structure.append('a') ;
else
if (mode != 0)
structure.append('N') ;
mode = -1 ; // blank processed
break ;
case 'a' :
if (mode == -1)
mode = 2 ;
break ;
case 'n' :
if (mode == 2)
mode = 3 ;
break ;
case 'd' :
if (mode == 3)
mode = 5 ;
break ;
default :
mode = 1 ;
}
}
if (mode == 5) // "and"
structure.append('a') ;
else
if (mode != 0)
structure.append('N') ;
// Check
len = structure.length() ;
if (len > 0)
{
if (structure.charAt(0) != 'N') // must start by name
{
messages.add( new IntegrityMessage( IntegrityMessage.NAME_START_WARNING,
entry, fieldName, null)) ;
// back.add("beginning of " +fieldName +" field");
}
if (structure.charAt( structure.length() -1) != 'N') // end without seperator
{
messages.add( new IntegrityMessage( IntegrityMessage.NAME_END_WARNING,
entry, fieldName, null)) ;
// back.add("bad end (" +fieldName +" field)");
}
/*if (structure.indexOf("NN,NN") > -1)
{
messages.add( new IntegrityMessage( IntegrityMessage.NAME_SEMANTIC_WARNING,
entry, fieldName, null)) ;
// back.add("something could be wrong in " +fieldName +" field") ;
} */
}
// messages.add( new IntegrityMessage( IntegrityMessage.NAME_END_WARNING,
// entry, fieldName, null)) ;
}
private void titleCheck(String title, String fieldName, BibtexEntry entry)
{
int len = title.length() ;
int mode = 0 ;
int upLowCounter = 0 ;
// boolean lastWasSpace = false ;
for (int t = 0 ; t < len ; t++)
{
char ch = title.charAt( t ) ;
switch (ch)
{
case '}' : // end of Sequence
if (mode == 0)
{
// closing brace '}' without an opening
messages.add( new IntegrityMessage( IntegrityMessage.UNEXPECTED_CLOSING_BRACE_FAILURE,
entry, fieldName, null)) ;
}
else // mode == 1
{
mode-- ;
// lastWasSpace = true ;
}
break ;
case '{' : // open {
mode++ ;
break ;
case ' ' :
// lastWasSpace = true ;
break ;
default :
if (mode == 0) // out of {}
{
if ( Character.isUpperCase(ch) && (t > 1))
{
upLowCounter++ ;
}
}
}
}
if (upLowCounter > 0)
{
/*
Morten Alver (2006.10.10):
Disabling this warning because we have a feature for automatically adding
braces when saving, which makes this warning misleading. It could be modified
to suggest to use this feature if not enabled, and not give a warning if the
feature is enabled.
messages.add( new IntegrityMessage( IntegrityMessage.UPPER_AND_LOWER_HINT,
entry, fieldName, null)) ;*/
}
}
/** Checks, if the number String contains a four digit year */
private void yearCheck(String number, String fieldName, BibtexEntry entry)
{
int len = number.length() ;
int digitCounter = 0 ;
boolean fourDigitsBlock = false ;
boolean containsFourDigits = false ;
for (int t = 0 ; t < len ; t++)
{
char ch = number.charAt( t ) ;
if ( Character.isDigit(ch))
{
digitCounter++ ;
if (digitCounter == 4)
fourDigitsBlock = true ;
else
fourDigitsBlock = false ;
} else
{
if (fourDigitsBlock)
containsFourDigits = true ;
digitCounter = 0 ;
}
}
if ((!containsFourDigits) && (!fourDigitsBlock))
{
messages.add( new IntegrityMessage( IntegrityMessage.FOUR_DIGITS_HINT,
entry, fieldName, null)) ;
}
}
}