Browse Source

breaking classes into files ala PSR4

pull/81/head
Chris 8 years ago
parent
commit
ab10bb500e
  1. 161
      src/BibDBBuilder.php
  2. 368
      src/Definitions.php
  3. 27
      src/ParserDelegate.php
  4. 235
      src/StateBasedBibtexParser.php
  5. 19
      src/StringEntry.php
  6. 40
      src/XMLPrettyPrinter.php
  7. 467
      src/bibtexbrowser.php

161
src/BibDBBuilder.php

@ -0,0 +1,161 @@
<?PHP
namespace Monperrus\BibtexBrowser;
/** builds arrays of BibEntry objects from a bibtex file.
usage:
<pre>
$empty_array = array();
$db = new BibDBBuilder(); // see also factory method createBibDBBuilder
$db->build('bibacid-utf8.bib'); // parses bib file
print_r($db->builtdb);// an associated array key -> BibEntry objects
print_r($db->stringdb);// an associated array key -> strings representing @string
</pre>
notes:
method build can be used several times, bibtex entries are accumulated in the builder
*/
class BibDBBuilder extends ParserDelegate {
/** A hashtable from keys to bib entries (BibEntry). */
var $builtdb = array();
/** A hashtable of constant strings */
var $stringdb = array();
var $filename;
var $currentEntry;
function build($bibfilename, $handle = NULL) {
$this->filename = $bibfilename;
if ($handle == NULL) {
$handle = fopen($bibfilename, "r");
}
if (!$handle) die ('cannot open '.$bibfilename);
$parser = new StateBasedBibtexParser($this);
$parser->parse($handle);
fclose($handle);
//print_r(array_keys($this->builtdb));
//print_r($this->builtdb);
}
function getBuiltDb() {
//print_r($this->builtdb);
return $this->builtdb;
}
function beginFile() {
}
function endFile() {
// resolving crossrefs
// we are careful with PHP 4 semantics
foreach (array_keys($this->builtdb) as $key) {
$bib = $this->builtdb[$key];
if ($bib->hasField('crossref')) {
if (isset($this->builtdb[$bib->getField('crossref')])) {
$crossrefEntry = $this->builtdb[$bib->getField('crossref')];
$bib->crossref = $crossrefEntry;
foreach($crossrefEntry->getFields() as $k => $v) {
// copying the fields of the cross ref
// only if they don't exist yet
if (!$bib->hasField($k)) {
$bib->setField($k,$v);
}
}
}
}
}
//print_r($this->builtdb);
}
function setEntryField($fieldkey,$entryvalue) {
$fieldkey=trim($fieldkey);
// support for Bibtex concatenation
// see http://newton.ex.ac.uk/tex/pack/bibtex/btxdoc/node3.html
// (?<! is a negative look-behind assertion, see http://www.php.net/manual/en/regexp.reference.assertions.php
$entryvalue_array=preg_split('/(?<!\\\\)#/', $entryvalue);
foreach ($entryvalue_array as $k=>$v) {
// spaces are allowed when using # and they are not taken into account
// however # is not itself replaced by a space
// warning: @strings are not case sensitive
// see http://newton.ex.ac.uk/tex/pack/bibtex/btxdoc/node3.html
$stringKey=strtolower(trim($v));
if (isset($this->stringdb[$stringKey]))
{
// this field will be formated later by xtrim and latex2html
$entryvalue_array[$k]=$this->stringdb[$stringKey]->value;
// we keep a trace of this replacement
// so as to produce correct bibtex snippets
$this->currentEntry->constants[$stringKey]=$this->stringdb[$stringKey]->value;
}
}
$entryvalue=implode('',$entryvalue_array);
$this->currentEntry->setField($fieldkey,$entryvalue);
}
function setEntryType($entrytype) {
$this->currentEntry->setType($entrytype);
}
function setEntryKey($entrykey) {
//echo "new entry:".$entrykey."\n";
$this->currentEntry->setKey($entrykey);
}
function beginEntry() {
$this->currentEntry = createBibEntry();
$this->currentEntry->setFile($this->filename);
}
function endEntry($entrysource) {
// we add a timestamp
$this->currentEntry->timestamp();
// we add a key if there is no key
if (!$this->currentEntry->hasField(Q_KEY) && $this->currentEntry->getType()!='string') {
$this->currentEntry->setField(Q_KEY,md5($entrysource));
}
// we set the fulltext
$this->currentEntry->text = $entrysource;
// we format the author names in a special field
// to enable search
if ($this->currentEntry->hasField('author')) {
$this->currentEntry->setField(Q_INNER_AUTHOR,$this->currentEntry->getFormattedAuthorsString());
foreach($this->currentEntry->getCanonicalAuthors() as $author) {
$homepage_key = $this->currentEntry->getHomePageKey($author);
if (isset($this->stringdb[$homepage_key])) {
$this->currentEntry->homepages[$homepage_key] = $this->stringdb[$homepage_key]->value;
}
}
}
// ignoring jabref comments
if (($this->currentEntry->getType()=='comment')) {
/* do nothing for jabref comments */
}
// we add it to the string database
else if ($this->currentEntry->getType()=='string') {
foreach($this->currentEntry->fields as $k => $v) {
$k!=Q_INNER_TYPE and $this->stringdb[$k] = new StringEntry($k,$v,$this->filename);
}
}
// we add it to the database
else {
$this->builtdb[$this->currentEntry->getKey()] = $this->currentEntry;
}
}
} // end class BibDBBuilder

368
src/Definitions.php

@ -2,188 +2,194 @@
namespace Monperrus\BibtexBrowser;
// the encoding of your bibtex file
@define('BIBTEX_INPUT_ENCODING','UTF-8');//@define('BIBTEX_INPUT_ENCODING','iso-8859-1');//define('BIBTEX_INPUT_ENCODING','windows-1252');
// the encoding of the HTML output
@define('OUTPUT_ENCODING','UTF-8');
// print a warning if deprecated variable is used
if (defined('ENCODING')) {
class Definitions
{
public function __construct()
{
// the encoding of your bibtex file
@define('BIBTEX_INPUT_ENCODING','UTF-8');//@define('BIBTEX_INPUT_ENCODING','iso-8859-1');//define('BIBTEX_INPUT_ENCODING','windows-1252');
// the encoding of the HTML output
@define('OUTPUT_ENCODING','UTF-8');
// print a warning if deprecated variable is used
if (defined('ENCODING')) {
echo 'ENCODING has been replaced by BIBTEX_INPUT_ENCODING and OUTPUT_ENCODING';
}
}
// number of bib items per page
// we use the same parameter 'num' as Google
@define('PAGE_SIZE',isset($_GET['num'])?(preg_match('/^\d+$/',$_GET['num'])?$_GET['num']:10000):14);
// number of bib items per page
// we use the same parameter 'num' as Google
@define('PAGE_SIZE',isset($_GET['num'])?(preg_match('/^\d+$/',$_GET['num'])?$_GET['num']:10000):14);
// bibtexbrowser uses a small piece of Javascript to improve the user experience
// see http://en.wikipedia.org/wiki/Progressive_enhancement
// if you don't like it, you can be disable it by adding in bibtexbrowser.local.php
// @define('BIBTEXBROWSER_USE_PROGRESSIVE_ENHANCEMENT',false);
@define('BIBTEXBROWSER_USE_PROGRESSIVE_ENHANCEMENT',true);
@define('BIBLIOGRAPHYSTYLE','DefaultBibliographyStyle');// this is the name of a function
@define('BIBLIOGRAPHYSECTIONS','DefaultBibliographySections');// this is the name of a function
@define('BIBLIOGRAPHYTITLE','DefaultBibliographyTitle');// this is the name of a function
// bibtexbrowser uses a small piece of Javascript to improve the user experience
// see http://en.wikipedia.org/wiki/Progressive_enhancement
// if you don't like it, you can be disable it by adding in bibtexbrowser.local.php
// @define('BIBTEXBROWSER_USE_PROGRESSIVE_ENHANCEMENT',false);
@define('BIBTEXBROWSER_USE_PROGRESSIVE_ENHANCEMENT',true);
@define('BIBLIOGRAPHYSTYLE','DefaultBibliographyStyle');// this is the name of a function
@define('BIBLIOGRAPHYSECTIONS','DefaultBibliographySections');// this is the name of a function
@define('BIBLIOGRAPHYTITLE','DefaultBibliographyTitle');// this is the name of a function
// shall we load MathJax to render math in $…$ in HTML?
@define('BIBTEXBROWSER_RENDER_MATH', true);
@define('MATHJAX_URI', '//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML.js');
// the default jquery URI
@define('JQUERY_URI', '//code.jquery.com/jquery-1.5.1.min.js');
// can we load bibtex files on external servers?
@define('BIBTEXBROWSER_LOCAL_BIB_ONLY', true);
// the default view in {SimpleDisplay,AcademicDisplay,RSSDisplay,BibtexDisplay}
@define('BIBTEXBROWSER_DEFAULT_DISPLAY','SimpleDisplay');
// the default template
@define('BIBTEXBROWSER_DEFAULT_TEMPLATE','HTMLTemplate');
// the target frame of menu links
@define('BIBTEXBROWSER_MENU_TARGET','main'); // might be define('BIBTEXBROWSER_MENU_TARGET','_self'); in bibtexbrowser.local.php
@define('ABBRV_TYPE','index');// may be year/x-abbrv/key/none/index/keys-index
// are robots allowed to crawl and index bibtexbrowser generated pages?
@define('BIBTEXBROWSER_ROBOTS_NOINDEX',false);
//the default view in the "main" (right hand side) frame
@define('BIBTEXBROWSER_DEFAULT_FRAME','year=latest'); // year=latest,all and all valid bibtexbrowser queries
// Wrapper to use when we are included by another script
@define('BIBTEXBROWSER_EMBEDDED_WRAPPER', 'NoWrapper');
// Main class to use
@define('BIBTEXBROWSER_MAIN', 'Dispatcher');
// default order functions
// Contract Returns < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.
// can be @define('ORDER_FUNCTION','compare_bib_entry_by_title');
// can be @define('ORDER_FUNCTION','compare_bib_entry_by_bibtex_order');
@define('ORDER_FUNCTION','compare_bib_entry_by_year');
@define('ORDER_FUNCTION_FINE','compare_bib_entry_by_month');
// only displaying the n newest entries
@define('BIBTEXBROWSER_NEWEST',5);
@define('BIBTEXBROWSER_NO_DEFAULT', false);
// BIBTEXBROWSER_LINK_STYLE defines which function to use to display the links of a bibtex entry
@define('BIBTEXBROWSER_LINK_STYLE','bib2links_default'); // can be 'nothing' (a function that does nothing)
// do we add [bibtex] links ?
@define('BIBTEXBROWSER_BIBTEX_LINKS',true);
// do we add [pdf] links ?
@define('BIBTEXBROWSER_PDF_LINKS',true);
// do we add [doi] links ?
@define('BIBTEXBROWSER_DOI_LINKS',true);
// do we add [gsid] links (Google Scholar)?
@define('BIBTEXBROWSER_GSID_LINKS',true);
// should pdf, doi, url, gsid links be opened in a new window?
@define('BIBTEXBROWSER_LINKS_TARGET','_self');// can be _blank (new window), _top (with frames)
// should authors be linked to [none/homepage/resultpage]
// none: nothing
// their homepage if defined as @strings
// their publication lists according to this bibtex
@define('BIBTEXBROWSER_AUTHOR_LINKS','homepage');
// BIBTEXBROWSER_LAYOUT defines the HTML rendering layout of the produced HTML
// may be table/list/ordered_list/definition/none (for <table>, <ol>, <dl>, nothing resp.).
// for list/ordered_list, the abbrevations are not taken into account (see ABBRV_TYPE)
// for ordered_list, the index is given by HTML directly (in increasing order)
@define('BIBTEXBROWSER_LAYOUT','table');
// should the original bibtex be displayed or a reconstructed one with filtering
// values: original/reconstructed
// warning, with reconstructed, the latex markup for accents/diacritics is lost
@define('BIBTEXBROWSER_BIBTEX_VIEW','original');
// a list of fields that will not be shown in the bibtex view if BIBTEXBROWSER_BIBTEX_VIEW=reconstructed
@define('BIBTEXBROWSER_BIBTEX_VIEW_FILTEREDOUT','comment|note|file');
// should Latex macros be executed (e.g. \'e -> é
@define('BIBTEXBROWSER_USE_LATEX2HTML',true);
// Which is the first html <hN> level that should be used in embedded mode?
@define('BIBTEXBROWSER_HTMLHEADINGLEVEL', 2);
@define('BIBTEXBROWSER_ACADEMIC_TOC', false);
@define('BIBTEXBROWSER_DEBUG',false);
// how to print authors names?
// default => as in the bibtex file
// USE_COMMA_AS_NAME_SEPARATOR_IN_OUTPUT = true => "Meyer, Herbert"
// USE_INITIALS_FOR_NAMES = true => "Meyer H"
// USE_FIRST_THEN_LAST => Herbert Meyer
@define('USE_COMMA_AS_NAME_SEPARATOR_IN_OUTPUT',false);// output authors in a comma separated form, e.g. "Meyer, H"?
@define('USE_INITIALS_FOR_NAMES',false); // use only initials for all first names?
@define('USE_FIRST_THEN_LAST',false); // use only initials for all first names?
@define('FORCE_NAMELIST_SEPARATOR', ''); // if non-empty, use this to separate multiple names regardless of USE_COMMA_AS_NAME_SEPARATOR_IN_OUTPUT
@define('LAST_AUTHOR_SEPARATOR',' and ');
@define('TYPES_SIZE',10); // number of entry types per table
@define('YEAR_SIZE',20); // number of years per table
@define('AUTHORS_SIZE',30); // number of authors per table
@define('TAGS_SIZE',30); // number of keywords per table
@define('READLINE_LIMIT',1024);
@define('Q_YEAR', 'year');
@define('Q_YEAR_PAGE', 'year_page');
@define('Q_YEAR_INPRESS', 'in press');
@define('Q_YEAR_ACCEPTED', 'accepted');
@define('Q_YEAR_SUBMITTED', 'submitted');
@define('Q_FILE', 'bib');
@define('Q_AUTHOR', 'author');
@define('Q_AUTHOR_PAGE', 'author_page');
@define('Q_TAG', 'keywords');
@define('Q_TAG_PAGE', 'keywords_page');
@define('Q_TYPE', 'type');// used for queries
@define('Q_TYPE_PAGE', 'type_page');
@define('Q_ALL', 'all');
@define('Q_ENTRY', 'entry');
@define('Q_KEY', 'key');
@define('Q_KEYS', 'keys'); // filter entries using a url-encoded, JSON-encoded array of bibtex keys
@define('Q_SEARCH', 'search');
@define('Q_EXCLUDE', 'exclude');
@define('Q_RESULT', 'result');
@define('Q_ACADEMIC', 'academic');
@define('Q_DB', 'bibdb');
@define('Q_LATEST', 'latest');
@define('Q_RANGE', 'range');
@define('AUTHOR', 'author');
@define('EDITOR', 'editor');
@define('SCHOOL', 'school');
@define('TITLE', 'title');
@define('BOOKTITLE', 'booktitle');
@define('YEAR', 'year');
@define('BUFFERSIZE',100000);
@define('MULTIPLE_BIB_SEPARATOR',';');
@define('METADATA_GS',true);
@define('METADATA_DC',true);
@define('METADATA_OPENGRAPH',true);
@define('METADATA_EPRINTS',false);
// define sort order for special values in 'year' field
// highest number is sorted first
// don't exceed 0 though, since the values are added to PHP_INT_MAX
@define('ORDER_YEAR_INPRESS', -0);
@define('ORDER_YEAR_ACCEPTED', -1);
@define('ORDER_YEAR_SUBMITTED', -2);
@define('ORDER_YEAR_OTHERNONINT', -3);
// in embedded mode, we still need a URL for displaying bibtex entries alone
// this is usually resolved to bibtexbrowser.php
// but can be overridden in bibtexbrowser.local.php
// for instance with @define('BIBTEXBROWSER_URL',''); // links to the current page with ?
//@define('BIBTEXBROWSER_URL',basename(__FILE__));
@define('BIBTEXBROWSER_URL',parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
// *************** END CONFIGURATION
define('Q_INNER_AUTHOR', '_author');// internally used for representing the author
define('Q_INNER_TYPE', 'x-bibtex-type');// used for representing the type of the bibtex entry internally
@define('Q_INNER_KEYS_INDEX', '_keys-index');// used for storing indices in $_GET[Q_KEYS] array
// shall we load MathJax to render math in $…$ in HTML?
@define('BIBTEXBROWSER_RENDER_MATH', true);
@define('MATHJAX_URI', '//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML.js');
// the default jquery URI
@define('JQUERY_URI', '//code.jquery.com/jquery-1.5.1.min.js');
// can we load bibtex files on external servers?
@define('BIBTEXBROWSER_LOCAL_BIB_ONLY', true);
// the default view in {SimpleDisplay,AcademicDisplay,RSSDisplay,BibtexDisplay}
@define('BIBTEXBROWSER_DEFAULT_DISPLAY','SimpleDisplay');
// the default template
@define('BIBTEXBROWSER_DEFAULT_TEMPLATE','HTMLTemplate');
// the target frame of menu links
@define('BIBTEXBROWSER_MENU_TARGET','main'); // might be define('BIBTEXBROWSER_MENU_TARGET','_self'); in bibtexbrowser.local.php
@define('ABBRV_TYPE','index');// may be year/x-abbrv/key/none/index/keys-index
// are robots allowed to crawl and index bibtexbrowser generated pages?
@define('BIBTEXBROWSER_ROBOTS_NOINDEX',false);
//the default view in the "main" (right hand side) frame
@define('BIBTEXBROWSER_DEFAULT_FRAME','year=latest'); // year=latest,all and all valid bibtexbrowser queries
// Wrapper to use when we are included by another script
@define('BIBTEXBROWSER_EMBEDDED_WRAPPER', 'NoWrapper');
// Main class to use
@define('BIBTEXBROWSER_MAIN', 'Dispatcher');
// default order functions
// Contract Returns < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.
// can be @define('ORDER_FUNCTION','compare_bib_entry_by_title');
// can be @define('ORDER_FUNCTION','compare_bib_entry_by_bibtex_order');
@define('ORDER_FUNCTION','compare_bib_entry_by_year');
@define('ORDER_FUNCTION_FINE','compare_bib_entry_by_month');
// only displaying the n newest entries
@define('BIBTEXBROWSER_NEWEST',5);
@define('BIBTEXBROWSER_NO_DEFAULT', false);
// BIBTEXBROWSER_LINK_STYLE defines which function to use to display the links of a bibtex entry
@define('BIBTEXBROWSER_LINK_STYLE','bib2links_default'); // can be 'nothing' (a function that does nothing)
// do we add [bibtex] links ?
@define('BIBTEXBROWSER_BIBTEX_LINKS',true);
// do we add [pdf] links ?
@define('BIBTEXBROWSER_PDF_LINKS',true);
// do we add [doi] links ?
@define('BIBTEXBROWSER_DOI_LINKS',true);
// do we add [gsid] links (Google Scholar)?
@define('BIBTEXBROWSER_GSID_LINKS',true);
// should pdf, doi, url, gsid links be opened in a new window?
@define('BIBTEXBROWSER_LINKS_TARGET','_self');// can be _blank (new window), _top (with frames)
// should authors be linked to [none/homepage/resultpage]
// none: nothing
// their homepage if defined as @strings
// their publication lists according to this bibtex
@define('BIBTEXBROWSER_AUTHOR_LINKS','homepage');
// BIBTEXBROWSER_LAYOUT defines the HTML rendering layout of the produced HTML
// may be table/list/ordered_list/definition/none (for <table>, <ol>, <dl>, nothing resp.).
// for list/ordered_list, the abbrevations are not taken into account (see ABBRV_TYPE)
// for ordered_list, the index is given by HTML directly (in increasing order)
@define('BIBTEXBROWSER_LAYOUT','table');
// should the original bibtex be displayed or a reconstructed one with filtering
// values: original/reconstructed
// warning, with reconstructed, the latex markup for accents/diacritics is lost
@define('BIBTEXBROWSER_BIBTEX_VIEW','original');
// a list of fields that will not be shown in the bibtex view if BIBTEXBROWSER_BIBTEX_VIEW=reconstructed
@define('BIBTEXBROWSER_BIBTEX_VIEW_FILTEREDOUT','comment|note|file');
// should Latex macros be executed (e.g. \'e -> é
@define('BIBTEXBROWSER_USE_LATEX2HTML',true);
// Which is the first html <hN> level that should be used in embedded mode?
@define('BIBTEXBROWSER_HTMLHEADINGLEVEL', 2);
@define('BIBTEXBROWSER_ACADEMIC_TOC', false);
@define('BIBTEXBROWSER_DEBUG',false);
// how to print authors names?
// default => as in the bibtex file
// USE_COMMA_AS_NAME_SEPARATOR_IN_OUTPUT = true => "Meyer, Herbert"
// USE_INITIALS_FOR_NAMES = true => "Meyer H"
// USE_FIRST_THEN_LAST => Herbert Meyer
@define('USE_COMMA_AS_NAME_SEPARATOR_IN_OUTPUT',false);// output authors in a comma separated form, e.g. "Meyer, H"?
@define('USE_INITIALS_FOR_NAMES',false); // use only initials for all first names?
@define('USE_FIRST_THEN_LAST',false); // use only initials for all first names?
@define('FORCE_NAMELIST_SEPARATOR', ''); // if non-empty, use this to separate multiple names regardless of USE_COMMA_AS_NAME_SEPARATOR_IN_OUTPUT
@define('LAST_AUTHOR_SEPARATOR',' and ');
@define('TYPES_SIZE',10); // number of entry types per table
@define('YEAR_SIZE',20); // number of years per table
@define('AUTHORS_SIZE',30); // number of authors per table
@define('TAGS_SIZE',30); // number of keywords per table
@define('READLINE_LIMIT',1024);
@define('Q_YEAR', 'year');
@define('Q_YEAR_PAGE', 'year_page');
@define('Q_YEAR_INPRESS', 'in press');
@define('Q_YEAR_ACCEPTED', 'accepted');
@define('Q_YEAR_SUBMITTED', 'submitted');
@define('Q_FILE', 'bib');
@define('Q_AUTHOR', 'author');
@define('Q_AUTHOR_PAGE', 'author_page');
@define('Q_TAG', 'keywords');
@define('Q_TAG_PAGE', 'keywords_page');
@define('Q_TYPE', 'type');// used for queries
@define('Q_TYPE_PAGE', 'type_page');
@define('Q_ALL', 'all');
@define('Q_ENTRY', 'entry');
@define('Q_KEY', 'key');
@define('Q_KEYS', 'keys'); // filter entries using a url-encoded, JSON-encoded array of bibtex keys
@define('Q_SEARCH', 'search');
@define('Q_EXCLUDE', 'exclude');
@define('Q_RESULT', 'result');
@define('Q_ACADEMIC', 'academic');
@define('Q_DB', 'bibdb');
@define('Q_LATEST', 'latest');
@define('Q_RANGE', 'range');
@define('AUTHOR', 'author');
@define('EDITOR', 'editor');
@define('SCHOOL', 'school');
@define('TITLE', 'title');
@define('BOOKTITLE', 'booktitle');
@define('YEAR', 'year');
@define('BUFFERSIZE',100000);
@define('MULTIPLE_BIB_SEPARATOR',';');
@define('METADATA_GS',true);
@define('METADATA_DC',true);
@define('METADATA_OPENGRAPH',true);
@define('METADATA_EPRINTS',false);
// define sort order for special values in 'year' field
// highest number is sorted first
// don't exceed 0 though, since the values are added to PHP_INT_MAX
@define('ORDER_YEAR_INPRESS', -0);
@define('ORDER_YEAR_ACCEPTED', -1);
@define('ORDER_YEAR_SUBMITTED', -2);
@define('ORDER_YEAR_OTHERNONINT', -3);
// in embedded mode, we still need a URL for displaying bibtex entries alone
// this is usually resolved to bibtexbrowser.php
// but can be overridden in bibtexbrowser.local.php
// for instance with @define('BIBTEXBROWSER_URL',''); // links to the current page with ?
//@define('BIBTEXBROWSER_URL',basename(__FILE__));
@define('BIBTEXBROWSER_URL',parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
// *************** END CONFIGURATION
define('Q_INNER_AUTHOR', '_author');// internally used for representing the author
define('Q_INNER_TYPE', 'x-bibtex-type');// used for representing the type of the bibtex entry internally
@define('Q_INNER_KEYS_INDEX', '_keys-index');// used for storing indices in $_GET[Q_KEYS] array
}
}

27
src/ParserDelegate.php

@ -0,0 +1,27 @@
<?PHP
namespace Monperrus\BibtexBrowser;
/** a default empty implementation of a delegate for StateBasedBibtexParser */
class ParserDelegate {
function beginFile() {}
function endFile() {}
function setEntryField($finalkey,$entryvalue) {}
function setEntryType($entrytype) {}
function setEntryKey($entrykey) {}
function beginEntry() {}
function endEntry($entrysource) {}
/** called for each sub parts of type {part} of a field value
* for now, only CURLYTOP and CURLYONE events
*/
function entryValuePart($key, $value, $type) {}
} // end class ParserDelegate

235
src/StateBasedBibtexParser.php

@ -0,0 +1,235 @@
<?PHP
namespace Monperrus\BibtexBrowser;
class StateBasedBibtexParser
{
var $delegate;
public function __construct($delegate) {
$this->delegate = $delegate;
}
public function parse($handle) {
if (gettype($handle) == 'string') { throw new Exception('oops'); }
$delegate = $this->delegate;
// STATE DEFINITIONS
@define('NOTHING',1);
@define('GETTYPE',2);
@define('GETKEY',3);
@define('GETVALUE',4);
@define('GETVALUEDELIMITEDBYQUOTES',5);
@define('GETVALUEDELIMITEDBYQUOTES_ESCAPED',6);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS',7);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_ESCAPED',8);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL',9);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL_ESCAPED',10);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL',11);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL_ESCAPED',12);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL',13);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL_ESCAPED',14);
$state=NOTHING;
$entrytype='';
$entrykey='';
$entryvalue='';
$fieldvaluepart='';
$finalkey='';
$entrysource='';
// metastate
$isinentry = false;
$delegate->beginFile();
// if you encounter this error "Allowed memory size of xxxxx bytes exhausted"
// then decrease the size of the temp buffer below
$bufsize=BUFFERSIZE;
while (!feof($handle)) {
$sread=fread($handle,$bufsize);
//foreach(str_split($sread) as $s) {
for ( $i=0; $i < strlen( $sread ); $i++) { $s=$sread[$i];
if ($isinentry) $entrysource.=$s;
if ($state==NOTHING) {
// this is the beginning of an entry
if ($s=='@') {
$delegate->beginEntry();
$state = GETTYPE;
$isinentry = true;
$entrysource='@';
}
}
else if ($state==GETTYPE) {
// this is the beginning of a key
if ($s=='{') {
$state = GETKEY;
$delegate->setEntryType($entrytype);
$entrytype='';
}
else $entrytype=$entrytype.$s;
}
else if ($state==GETKEY) {
// now we get the value
if ($s=='=') {
$state = GETVALUE;
$fieldvaluepart='';
$finalkey=$entrykey;
$entrykey='';
}
// oups we only have the key :-) anyway
else if ($s=='}') {
$state = NOTHING;$isinentry = false;$delegate->endEntry($entrysource);
$entrykey='';
}
// OK now we look for values
else if ($s==',') {
$state=GETKEY;
$delegate->setEntryKey($entrykey);
$entrykey='';}
else { $entrykey=$entrykey.$s; }
}
// we just got a =, we can now receive the value, but we don't now whether the value
// is delimited by curly brackets, double quotes or nothing
else if ($state==GETVALUE) {
// the value is delimited by double quotes
if ($s=='"') {
$state = GETVALUEDELIMITEDBYQUOTES;
}
// the value is delimited by curly brackets
else if ($s=='{') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS;
}
// the end of the key and no value found: it is the bibtex key e.g. \cite{Descartes1637}
else if ($s==',') {
$state = GETKEY;
$delegate->setEntryField($finalkey,$entryvalue);
$entryvalue=''; // resetting the value buffer
}
// this is the end of the value AND of the entry
else if ($s=='}') {
$state = NOTHING;
$delegate->setEntryField($finalkey,$entryvalue);
$isinentry = false;$delegate->endEntry($entrysource);
$entryvalue=''; // resetting the value buffer
}
else if ($s==' ' || $s=="\t" || $s=="\n" || $s=="\r" ) {
// blank characters are not taken into account when values are not in quotes or curly brackets
}
else {
$entryvalue=$entryvalue.$s;
}
}
/* GETVALUEDELIMITEDBYCURLYBRACKETS* handle entries delimited by curly brackets and the possible nested curly brackets */
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS) {
if ($s=='\\') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_ESCAPED;
$entryvalue=$entryvalue.$s;}
else if ($s=='{') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL;
$entryvalue=$entryvalue.$s;
$delegate->entryValuePart($finalkey,$fieldvaluepart,'CURLYTOP');
$fieldvaluepart='';
}
else if ($s=='}') { // end entry
$state = GETVALUE;
$delegate->entryValuePart($finalkey,$fieldvaluepart,'CURLYTOP');
}
else {
$entryvalue=$entryvalue.$s;
$fieldvaluepart=$fieldvaluepart.$s;
}
}
// handle anti-slashed brackets
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_ESCAPED) {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS;
$entryvalue=$entryvalue.$s;
}
// in first level of curly bracket
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL) {
if ($s=='\\') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL_ESCAPED;
$entryvalue=$entryvalue.$s;}
else if ($s=='{') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL;$entryvalue=$entryvalue.$s;}
else if ($s=='}') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS;
$delegate->entryValuePart($finalkey,$fieldvaluepart,'CURLYONE');
$fieldvaluepart='';
$entryvalue=$entryvalue.$s;
}
else {
$entryvalue=$entryvalue.$s;
$fieldvaluepart=$fieldvaluepart.$s;
}
}
// handle anti-slashed brackets
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL_ESCAPED) {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL;
$entryvalue=$entryvalue.$s;
}
// in second level of curly bracket
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL) {
if ($s=='\\') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL_ESCAPED;
$entryvalue=$entryvalue.$s;}
else if ($s=='{') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL;$entryvalue=$entryvalue.$s;}
else if ($s=='}') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL;$entryvalue=$entryvalue.$s;}
else { $entryvalue=$entryvalue.$s;}
}
// handle anti-slashed brackets
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL_ESCAPED) {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL;
$entryvalue=$entryvalue.$s;
}
// in third level of curly bracket
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL) {
if ($s=='\\') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL_ESCAPED;
$entryvalue=$entryvalue.$s;}
else if ($s=='}') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL;$entryvalue=$entryvalue.$s;}
else { $entryvalue=$entryvalue.$s;}
}
// handle anti-slashed brackets
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL_ESCAPED) {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL;
$entryvalue=$entryvalue.$s;
}
/* handles entries delimited by double quotes */
else if ($state==GETVALUEDELIMITEDBYQUOTES) {
if ($s=='\\') {
$state = GETVALUEDELIMITEDBYQUOTES_ESCAPED;
$entryvalue=$entryvalue.$s;}
else if ($s=='"') {
$state = GETVALUE;
}
else { $entryvalue=$entryvalue.$s;}
}
// handle anti-double quotes
else if ($state==GETVALUEDELIMITEDBYQUOTES_ESCAPED) {
$state = GETVALUEDELIMITEDBYQUOTES;
$entryvalue=$entryvalue.$s;
}
} // end for
} // end while
$delegate->endFile();
//$d = $this->delegate;print_r($d);
} // end function
} // end class

19
src/StringEntry.php

@ -0,0 +1,19 @@
<?PHP
namespace Monperrus\BibtexBrowser;
/** represents @string{k=v} */
class StringEntry
{
public function __construct($key, $value, $filename)
{
$this->name=$key;
$this->value=$value;
$this->filename=$filename;
}
public function toString()
{
return '@string{'.$this->name.'={'.$this->value.'}}';
}
} // end class StringEntry

40
src/XMLPrettyPrinter.php

@ -0,0 +1,40 @@
<?PHP
namespace Monperrus\BibtexBrowser;
/** is a possible delegate for StateBasedBibParser.
usage:
see snippet of [[#StateBasedBibParser]]
*/
class XMLPrettyPrinter extends ParserDelegate
{
public function beginFile() {
header('Content-type: text/xml;');
print '<?xml version="1.0" encoding="'.OUTPUT_ENCODING.'"?>';
print '<bibfile>';
}
public function endFile() {
print '</bibfile>';
}
public function setEntryField($finalkey,$entryvalue) {
print "<data>\n<key>".$finalkey."</key>\n<value>".$entryvalue."</value>\n</data>\n";
}
public function setEntryType($entrytype) {
print '<type>'.$entrytype.'</type>';
}
public function setEntryKey($entrykey) {
print '<keyonly>'.$entrykey.'</keyonly>';
}
public function beginEntry() {
print "<entry>\n";
}
public function endEntry($entrysource) {
print "</entry>\n";
}
} // end class XMLPrettyPrinter

467
src/bibtexbrowser.php

@ -15,6 +15,12 @@ License, or (at your option) any later version.
*/
use Monperrus\BibtexBrowser\StateBasedBibtexParser;
use Monperrus\BibtexBrowser\ParserDelegate;
use Monperrus\BibtexBrowser\XMLPrettyPrinter;
use Monperrus\BibtexBrowser\StringEntry;
use Monperrus\BibtexBrowser\BibDBBuilder;
// it is be possible to include( 'bibtexbrowser.php' ); several times in the same script
// added on Wednesday, June 01 2011, bug found by Carlos Bras
if (!defined('BIBTEXBROWSER')) {
@ -483,471 +489,10 @@ notes:
- It has no dependencies, it can be used outside of bibtexbrowser
- The delegate is expected to have some methods, see classes BibDBBuilder and XMLPrettyPrinter
*/
class StateBasedBibtexParser {
var $delegate;
function __construct($delegate) {
$this->delegate = $delegate;
}
function parse($handle) {
if (gettype($handle) == 'string') { throw new Exception('oops'); }
$delegate = $this->delegate;
// STATE DEFINITIONS
@define('NOTHING',1);
@define('GETTYPE',2);
@define('GETKEY',3);
@define('GETVALUE',4);
@define('GETVALUEDELIMITEDBYQUOTES',5);
@define('GETVALUEDELIMITEDBYQUOTES_ESCAPED',6);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS',7);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_ESCAPED',8);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL',9);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL_ESCAPED',10);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL',11);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL_ESCAPED',12);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL',13);
@define('GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL_ESCAPED',14);
$state=NOTHING;
$entrytype='';
$entrykey='';
$entryvalue='';
$fieldvaluepart='';
$finalkey='';
$entrysource='';
// metastate
$isinentry = false;
$delegate->beginFile();
// if you encounter this error "Allowed memory size of xxxxx bytes exhausted"
// then decrease the size of the temp buffer below
$bufsize=BUFFERSIZE;
while (!feof($handle)) {
$sread=fread($handle,$bufsize);
//foreach(str_split($sread) as $s) {
for ( $i=0; $i < strlen( $sread ); $i++) { $s=$sread[$i];
if ($isinentry) $entrysource.=$s;
if ($state==NOTHING) {
// this is the beginning of an entry
if ($s=='@') {
$delegate->beginEntry();
$state = GETTYPE;
$isinentry = true;
$entrysource='@';
}
}
else if ($state==GETTYPE) {
// this is the beginning of a key
if ($s=='{') {
$state = GETKEY;
$delegate->setEntryType($entrytype);
$entrytype='';
}
else $entrytype=$entrytype.$s;
}
else if ($state==GETKEY) {
// now we get the value
if ($s=='=') {
$state = GETVALUE;
$fieldvaluepart='';
$finalkey=$entrykey;
$entrykey='';
}
// oups we only have the key :-) anyway
else if ($s=='}') {
$state = NOTHING;$isinentry = false;$delegate->endEntry($entrysource);
$entrykey='';
}
// OK now we look for values
else if ($s==',') {
$state=GETKEY;
$delegate->setEntryKey($entrykey);
$entrykey='';}
else { $entrykey=$entrykey.$s; }
}
// we just got a =, we can now receive the value, but we don't now whether the value
// is delimited by curly brackets, double quotes or nothing
else if ($state==GETVALUE) {
// the value is delimited by double quotes
if ($s=='"') {
$state = GETVALUEDELIMITEDBYQUOTES;
}
// the value is delimited by curly brackets
else if ($s=='{') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS;
}
// the end of the key and no value found: it is the bibtex key e.g. \cite{Descartes1637}
else if ($s==',') {
$state = GETKEY;
$delegate->setEntryField($finalkey,$entryvalue);
$entryvalue=''; // resetting the value buffer
}
// this is the end of the value AND of the entry
else if ($s=='}') {
$state = NOTHING;
$delegate->setEntryField($finalkey,$entryvalue);
$isinentry = false;$delegate->endEntry($entrysource);
$entryvalue=''; // resetting the value buffer
}
else if ($s==' ' || $s=="\t" || $s=="\n" || $s=="\r" ) {
// blank characters are not taken into account when values are not in quotes or curly brackets
}
else {
$entryvalue=$entryvalue.$s;
}
}
/* GETVALUEDELIMITEDBYCURLYBRACKETS* handle entries delimited by curly brackets and the possible nested curly brackets */
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS) {
if ($s=='\\') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_ESCAPED;
$entryvalue=$entryvalue.$s;}
else if ($s=='{') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL;
$entryvalue=$entryvalue.$s;
$delegate->entryValuePart($finalkey,$fieldvaluepart,'CURLYTOP');
$fieldvaluepart='';
}
else if ($s=='}') { // end entry
$state = GETVALUE;
$delegate->entryValuePart($finalkey,$fieldvaluepart,'CURLYTOP');
}
else {
$entryvalue=$entryvalue.$s;
$fieldvaluepart=$fieldvaluepart.$s;
}
}
// handle anti-slashed brackets
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_ESCAPED) {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS;
$entryvalue=$entryvalue.$s;
}
// in first level of curly bracket
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL) {
if ($s=='\\') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL_ESCAPED;
$entryvalue=$entryvalue.$s;}
else if ($s=='{') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL;$entryvalue=$entryvalue.$s;}
else if ($s=='}') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS;
$delegate->entryValuePart($finalkey,$fieldvaluepart,'CURLYONE');
$fieldvaluepart='';
$entryvalue=$entryvalue.$s;
}
else {
$entryvalue=$entryvalue.$s;
$fieldvaluepart=$fieldvaluepart.$s;
}
}
// handle anti-slashed brackets
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL_ESCAPED) {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL;
$entryvalue=$entryvalue.$s;
}
// in second level of curly bracket
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL) {
if ($s=='\\') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL_ESCAPED;
$entryvalue=$entryvalue.$s;}
else if ($s=='{') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL;$entryvalue=$entryvalue.$s;}
else if ($s=='}') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL;$entryvalue=$entryvalue.$s;}
else { $entryvalue=$entryvalue.$s;}
}
// handle anti-slashed brackets
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL_ESCAPED) {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL;
$entryvalue=$entryvalue.$s;
}
// in third level of curly bracket
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL) {
if ($s=='\\') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL_ESCAPED;
$entryvalue=$entryvalue.$s;}
else if ($s=='}') {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL;$entryvalue=$entryvalue.$s;}
else { $entryvalue=$entryvalue.$s;}
}
// handle anti-slashed brackets
else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL_ESCAPED) {
$state = GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL;
$entryvalue=$entryvalue.$s;
}
/* handles entries delimited by double quotes */
else if ($state==GETVALUEDELIMITEDBYQUOTES) {
if ($s=='\\') {
$state = GETVALUEDELIMITEDBYQUOTES_ESCAPED;
$entryvalue=$entryvalue.$s;}
else if ($s=='"') {
$state = GETVALUE;
}
else { $entryvalue=$entryvalue.$s;}
}
// handle anti-double quotes
else if ($state==GETVALUEDELIMITEDBYQUOTES_ESCAPED) {
$state = GETVALUEDELIMITEDBYQUOTES;
$entryvalue=$entryvalue.$s;
}
} // end for
} // end while
$delegate->endFile();
//$d = $this->delegate;print_r($d);
} // end function
} // end class
/** a default empty implementation of a delegate for StateBasedBibtexParser */
class ParserDelegate {
function beginFile() {}
function endFile() {}
function setEntryField($finalkey,$entryvalue) {}
function setEntryType($entrytype) {}
function setEntryKey($entrykey) {}
function beginEntry() {}
function endEntry($entrysource) {}
/** called for each sub parts of type {part} of a field value
* for now, only CURLYTOP and CURLYONE events
*/
function entryValuePart($key, $value, $type) {}
} // end class ParserDelegate
/** is a possible delegate for StateBasedBibParser.
usage:
see snippet of [[#StateBasedBibParser]]
*/
class XMLPrettyPrinter extends ParserDelegate {
function beginFile() {
header('Content-type: text/xml;');
print '<?xml version="1.0" encoding="'.OUTPUT_ENCODING.'"?>';
print '<bibfile>';
}
function endFile() {
print '</bibfile>';
}
function setEntryField($finalkey,$entryvalue) {
print "<data>\n<key>".$finalkey."</key>\n<value>".$entryvalue."</value>\n</data>\n";
}
function setEntryType($entrytype) {
print '<type>'.$entrytype.'</type>';
}
function setEntryKey($entrykey) {
print '<keyonly>'.$entrykey.'</keyonly>';
}
function beginEntry() {
print "<entry>\n";
}
function endEntry($entrysource) {
print "</entry>\n";
}
} // end class XMLPrettyPrinter
/** represents @string{k=v} */
class StringEntry {
function __construct($k, $v, $filename) {
$this->name=$k;
$this->value=$v;
$this->filename=$filename;
}
function toString() {
return '@string{'.$this->name.'={'.$this->value.'}}';
}
} // end class StringEntry
/** builds arrays of BibEntry objects from a bibtex file.
usage:
<pre>
$empty_array = array();
$db = new BibDBBuilder(); // see also factory method createBibDBBuilder
$db->build('bibacid-utf8.bib'); // parses bib file
print_r($db->builtdb);// an associated array key -> BibEntry objects
print_r($db->stringdb);// an associated array key -> strings representing @string
</pre>
notes:
method build can be used several times, bibtex entries are accumulated in the builder
*/
class BibDBBuilder extends ParserDelegate {
/** A hashtable from keys to bib entries (BibEntry). */
var $builtdb = array();
/** A hashtable of constant strings */
var $stringdb = array();
var $filename;
var $currentEntry;
function build($bibfilename, $handle = NULL) {
$this->filename = $bibfilename;
if ($handle == NULL) {
$handle = fopen($bibfilename, "r");
}
if (!$handle) die ('cannot open '.$bibfilename);
$parser = new StateBasedBibtexParser($this);
$parser->parse($handle);
fclose($handle);
//print_r(array_keys($this->builtdb));
//print_r($this->builtdb);
}
function getBuiltDb() {
//print_r($this->builtdb);
return $this->builtdb;
}
function beginFile() {
}
function endFile() {
// resolving crossrefs
// we are careful with PHP 4 semantics
foreach (array_keys($this->builtdb) as $key) {
$bib = $this->builtdb[$key];
if ($bib->hasField('crossref')) {
if (isset($this->builtdb[$bib->getField('crossref')])) {
$crossrefEntry = $this->builtdb[$bib->getField('crossref')];
$bib->crossref = $crossrefEntry;
foreach($crossrefEntry->getFields() as $k => $v) {
// copying the fields of the cross ref
// only if they don't exist yet
if (!$bib->hasField($k)) {
$bib->setField($k,$v);
}
}
}
}
}
//print_r($this->builtdb);
}
function setEntryField($fieldkey,$entryvalue) {
$fieldkey=trim($fieldkey);
// support for Bibtex concatenation
// see http://newton.ex.ac.uk/tex/pack/bibtex/btxdoc/node3.html
// (?<! is a negative look-behind assertion, see http://www.php.net/manual/en/regexp.reference.assertions.php
$entryvalue_array=preg_split('/(?<!\\\\)#/', $entryvalue);
foreach ($entryvalue_array as $k=>$v) {
// spaces are allowed when using # and they are not taken into account
// however # is not itself replaced by a space
// warning: @strings are not case sensitive
// see http://newton.ex.ac.uk/tex/pack/bibtex/btxdoc/node3.html
$stringKey=strtolower(trim($v));
if (isset($this->stringdb[$stringKey]))
{
// this field will be formated later by xtrim and latex2html
$entryvalue_array[$k]=$this->stringdb[$stringKey]->value;
// we keep a trace of this replacement
// so as to produce correct bibtex snippets
$this->currentEntry->constants[$stringKey]=$this->stringdb[$stringKey]->value;
}
}
$entryvalue=implode('',$entryvalue_array);
$this->currentEntry->setField($fieldkey,$entryvalue);
}
function setEntryType($entrytype) {
$this->currentEntry->setType($entrytype);
}
function setEntryKey($entrykey) {
//echo "new entry:".$entrykey."\n";
$this->currentEntry->setKey($entrykey);
}
function beginEntry() {
$this->currentEntry = createBibEntry();
$this->currentEntry->setFile($this->filename);
}
function endEntry($entrysource) {
// we add a timestamp
$this->currentEntry->timestamp();
// we add a key if there is no key
if (!$this->currentEntry->hasField(Q_KEY) && $this->currentEntry->getType()!='string') {
$this->currentEntry->setField(Q_KEY,md5($entrysource));
}
// we set the fulltext
$this->currentEntry->text = $entrysource;
// we format the author names in a special field
// to enable search
if ($this->currentEntry->hasField('author')) {
$this->currentEntry->setField(Q_INNER_AUTHOR,$this->currentEntry->getFormattedAuthorsString());
foreach($this->currentEntry->getCanonicalAuthors() as $author) {
$homepage_key = $this->currentEntry->getHomePageKey($author);
if (isset($this->stringdb[$homepage_key])) {
$this->currentEntry->homepages[$homepage_key] = $this->stringdb[$homepage_key]->value;
}
}
}
// ignoring jabref comments
if (($this->currentEntry->getType()=='comment')) {
/* do nothing for jabref comments */
}
// we add it to the string database
else if ($this->currentEntry->getType()=='string') {
foreach($this->currentEntry->fields as $k => $v) {
$k!=Q_INNER_TYPE and $this->stringdb[$k] = new StringEntry($k,$v,$this->filename);
}
}
// we add it to the database
else {
$this->builtdb[$this->currentEntry->getKey()] = $this->currentEntry;
}
}
} // end class BibDBBuilder

Loading…
Cancel
Save