diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fe258fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.dat +vendor \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 8fb8394..3fe911b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,8 @@ php: script: - curl -L -o reflectivedoc.php https://www.monperrus.net/martin/reflectivedoc.php.txt - curl -L -o gakowiki-syntax.php https://www.monperrus.net/martin/gakowiki-syntax.php.txt - - phpunit bibtexbrowser-test.php + - cp ./src/bibtexbrowser.php ./tests/ + - cp ./src/bibacid-utf8.bib ./tests/ + - phpunit tests/bibtexbrowser-test.php sudo: false diff --git a/bibtexbrowser-cli.php b/bin/bibtexbrowser-cli.php similarity index 100% rename from bibtexbrowser-cli.php rename to bin/bibtexbrowser-cli.php diff --git a/composer.json b/composer.json index 84301f5..c0281b5 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,18 @@ } ], "require": { - "php": ">=4" + "php": ">=5.3.0" + }, + "autoload": { + "psr-4": { + "Monperrus\\BibtexBrowser\\": "src/" + } + }, + "scripts": { + "serve": "@php -S localhost:29896 -t public/" + }, + "require-dev": { + "monolog/monolog": "^1.23", + "kint-php/kint": "^2.2" } } diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..59127f8 --- /dev/null +++ b/composer.lock @@ -0,0 +1,203 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "fa3a6762d454ebe3dce634e74511aae2", + "packages": [], + "packages-dev": [ + { + "name": "kint-php/kint", + "version": "2.2", + "source": { + "type": "git", + "url": "https://github.com/kint-php/kint.git", + "reference": "b091715eadaf6e1a7ef927f3e81d1004611d2aea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kint-php/kint/zipball/b091715eadaf6e1a7ef927f3e81d1004611d2aea", + "reference": "b091715eadaf6e1a7ef927f3e81d1004611d2aea", + "shasum": "" + }, + "require": { + "php": ">=5.1.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.0", + "phpunit/phpunit": "^4.0", + "symfony/finder": "^2.6" + }, + "type": "library", + "autoload": { + "files": [ + "init.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Rokas Šleinius", + "homepage": "https://github.com/raveren" + }, + { + "name": "Jonathan Vollebregt", + "homepage": "https://github.com/jnvsor" + }, + { + "name": "Contributors", + "homepage": "https://github.com/kint-php/kint/graphs/contributors" + } + ], + "description": "Kint - debugging tool for PHP developers", + "homepage": "https://kint-php.github.io/kint/", + "keywords": [ + "debug", + "kint", + "php" + ], + "time": "2017-09-06T17:46:03+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.23.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "jakub-onderka/php-parallel-lint": "0.9", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "2.3.0", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2017-06-19T01:22:40+00:00" + }, + { + "name": "psr/log", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2016-10-10T12:19:37+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=4" + }, + "platform-dev": [] +} diff --git a/bibacid-utf8.bib b/public/bibacid-utf8.bib similarity index 100% rename from bibacid-utf8.bib rename to public/bibacid-utf8.bib diff --git a/public/embed.php b/public/embed.php new file mode 100644 index 0000000..d1ba77e --- /dev/null +++ b/public/embed.php @@ -0,0 +1,25 @@ + + + + +HTML; + +$_GET['library']=1; +require_once('../src/bibtexbrowser.php'); +$db = new BibDataBase(); +$db->load('bibacid-utf8.bib'); +$query = array('year'=>'1997'); +$entries=$db->multisearch($query); +uasort($entries, 'compare_bib_entries'); +foreach ($entries as $bibentry) { + print $bibentry->toHTML()."
"; +} + +print << + +HTML; +exit; diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..8e45e1a --- /dev/null +++ b/public/index.php @@ -0,0 +1,16 @@ + "bibacid-utf8.bib", + "all" => 1, + "author" => "", + "academic" => 1 +); + +$browser = new Bibliography($config); +$browser->print(); diff --git a/src/BibDBBuilder.php b/src/BibDBBuilder.php new file mode 100644 index 0000000..3939734 --- /dev/null +++ b/src/BibDBBuilder.php @@ -0,0 +1,161 @@ + + $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 + + 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 + // (?$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 diff --git a/src/Bibliography.php b/src/Bibliography.php new file mode 100644 index 0000000..f1f9c8a --- /dev/null +++ b/src/Bibliography.php @@ -0,0 +1,26 @@ + null, + "all" => null, + "author" => null, + "library" => null, + "academic" => null); + + public function __construct($userConfig = array()) + { + // (PHP 5 >= 5.3.0, PHP 7) + // $userConfig precedent over defaultConfig; $_GET over $userConfig + $_GET = array_replace($this->defaultConfig, $userConfig, $_GET); + } + + public function print() + { + require_once "bibtexbrowser.php"; + } +} diff --git a/src/Definitions.php b/src/Definitions.php new file mode 100644 index 0000000..65d8c9d --- /dev/null +++ b/src/Definitions.php @@ -0,0 +1,195 @@ + 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 ,
    ,
    , 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 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 + } +} diff --git a/src/ParserDelegate.php b/src/ParserDelegate.php new file mode 100644 index 0000000..629af5d --- /dev/null +++ b/src/ParserDelegate.php @@ -0,0 +1,27 @@ +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 diff --git a/src/StringEntry.php b/src/StringEntry.php new file mode 100644 index 0000000..0f54186 --- /dev/null +++ b/src/StringEntry.php @@ -0,0 +1,19 @@ +name=$key; + $this->value=$value; + $this->filename=$filename; + } + + public function toString() + { + return '@string{'.$this->name.'={'.$this->value.'}}'; + } +} // end class StringEntry diff --git a/src/XMLPrettyPrinter.php b/src/XMLPrettyPrinter.php new file mode 100644 index 0000000..ce414f3 --- /dev/null +++ b/src/XMLPrettyPrinter.php @@ -0,0 +1,40 @@ +'; + print ''; + } + + public function endFile() { + print ''; + } + + public function setEntryField($finalkey,$entryvalue) { + print "\n".$finalkey."\n".$entryvalue."\n\n"; + } + + public function setEntryType($entrytype) { + print ''.$entrytype.''; + } + + public function setEntryKey($entrykey) { + print ''.$entrykey.''; + } + + public function beginEntry() { + print "\n"; + } + + public function endEntry($entrysource) { + print "\n"; + } +} // end class XMLPrettyPrinter diff --git a/src/bibacid-utf8.bib b/src/bibacid-utf8.bib new file mode 100644 index 0000000..1c04146 --- /dev/null +++ b/src/bibacid-utf8.bib @@ -0,0 +1,231 @@ + + +@string{foo="Foo"} +@string{bar=foo#" Bar"} + + +%% test the home page feature +@string{hp_J.Abounader="http://www.google.com"} + +@inproceedings{classical, + author = {J. Abounader and D. Tooj}, + title = bar, + institution = {Queen's University, Kingston, ON.}, + year = {1997} +} + +%% testing the abstract +@inproceedings{with_abstract, + author = {J. Abounader and D. Tooj}, + title = {This is with abstract}, + institution = {Queen's University, Kingston, ON.}, + year = {1997}, + abstract = {This is an abstract + on several lines} +} + + +%% using double quotes +%% also Took test the advanced search +@TECHREPORT{dquotes, + author = "J. Abounader and Tooj, D.", + title = "using double quotes ", + institution = "Queen's University, Kingston, ON.", + year = "1997" +} + + +%% using single value (year) +@TECHREPORT{singlevalue, + author = {The }, + title = {The year}, + institution = {Queen's University, Kingston, ON.}, + year = 1997 +} + + +%% no new line +@TECHREPORT{Abounader1997e, author = {J. Abounader and D. Lamb}, title = "using double quotes", institution = {Queen's University, Kingston, ON.}, year = 1997 } + + + +%% intersting: bibtex does not allow \} in brackets enclosed entries and \" in quotes enclosed entries + +%% escaped quotes +@TECHREPORT{notallowed1, + author = {J. Abounader and D. Lamb}, + title = "escaped \"quotes\"", + institution = {Queen's University, Kingston, ON.}, + year = {1997} +} + +%% escaped braces +@TECHREPORT{notallowed2, + author = {J. Abounader \} and D. Lamb}, + title = "escaped braces", + institution = {Queen's University, Kingston, ON.}, + year = {1997} +} + +@article{testsearch1, + author = {Jacob G{\"o}del}, + title = {using Banach Space}, + year = {1997} +} +@article{testsearch2, + author = {Jacob {G}{\"{o}}del}, + title = {using banach space}, + year = {1997} +} +@article{testsearch3, + author = {Jacob {G\"{o}del}}, + title = {using {Banach} Space}, + year = {1997} +} +@article{testsearch4, + author = {Jacob Gödel}, + title = {using {B}anach Space}, + year = {1997} +} +@article{testsearch5, + author = {Jacob Gödel}, + title = {using {Banach Space}}, + year = {1997} +} + + + +%% bug from Jakob Kellner +%% copied from ams.org +@article {MR1841330, + AUTHOR = {Lejay, Antoine}, + TITLE = {Homogenization of divergence-form operators with lower-order + terms in random media}, + JOURNAL = {Probab. Theory Related Fields}, + FJOURNAL = {Probability Theory and Related Fields}, + VOLUME = {120}, + YEAR = {2001}, + NUMBER = {2}, + PAGES = {255--276}, + ISSN = {0178-8051}, + CODEN = {PTRFEU}, + MRCLASS = {35B27 (31C25 35R60 60H30 60J60)}, + MRNUMBER = {MR1841330 (2002g:35023)}, +MRREVIEWER = {Jean-Fran{\c{c}}ois Clouet}, + DOI = {10.1007/PL00008783}, + URL = {http://dx.doi.org/10.1007/PL00008783}, +} + +@article{serge, + author = "Serge Bug", + title = "curly {braces} in quote", + year = 2010 +} + +@article{cediltest, + author = "Serge Bug", + title = "\ccurly \c{c}urly {\c{c}}urly ", + year = 2010 +} + + +%%%%% now testing the string concatenation +@string{str1="toto"} +@string{str2="titi"} + +@book{stgringconcat:test1, + author = {J. Abounader and D. Lamb}, + title = str1#str2, + institution = {Queen's University, Kingston, ON.}, + year = {1997} +} + +% with space +@bookchapter{stgringconcat:test2, + author = {J. Abounader and D. Lamb}, + title = str1 # str2, + institution = {Queen's University, Kingston, ON.}, + year = {1997} +} + +% with another value +@inbook{stgringconcat:test3, + author = {J. Abounader and D. Lamb}, + title = str1 # {3344}, + institution = {Queen's University, Kingston, ON.}, + year = {1997} +} + + +%% Saturday, October 09 2010 +%% taken from http://en.wikipedia.org/wiki/BibTeX +@PROCEEDINGS {conference:06, + editor = {First Editor and Second Editor}, + title = {Proceedings of the Xth Conference on XYZ}, + booktitle = {Proceedings of the Xth Conference on XYZ}, + year = {2006}, + month = oct, +} + +@INPROCEEDINGS {author:06, + title = {Some publication title}, + author = {First Author and Second Author}, + crossref = {conference:06}, + pages = {330?331}, +} + + +%% Thursday, October 28 2010 +%% two test cases for special key +@INPROCEEDINGS {author+06, + title = {Some publication title}, + author = {First Author and Second Author}, + year = {2011}, +} + +@INPROCEEDINGS { author06 , + title = {Some publication title}, + author = {First Author and Second Author}, + year = {2011}, +} + +%% testing the accented i and j +@INPROCEEDINGS {paper000, + title = {Some publication title}, + author = {F\`\irst A\`{\i}thor and S{\`\i}cond Author\`\I}, + year = {2011}, +} + +%% bug reported by Mark Hereld +@misc{mark, + title = {Bug in Urls}, + author = {Mark Hereld}, + howpublished = {\url{http://foo.com/under_score.html}}, + year = {2011}, +} + +%% handling of percentage +@misc{mark, + title = {Percentage \%}, + abstract = {Percentage \%}, + author = {MM}, + year = {2015}, +} + +% bug https://github.com/monperrus/bibtexbrowser/issues/40 +@Article{Baldwin2014Quantum, + Doi = {10.1103/PhysRevA.90.012110}, + Url = {http://link.aps.org/doi/10.1103/PhysRevA.90.012110} +} + +@article{croatiantest, + author = "Strabi{\'{c}} Strabi\'{c}", + title = "Fancy accents bug", + year = 2015 +} + +@article{kjsdf 8, + title = "Entry with + in the key", + author = "Foo Bar", + year = 2017 +} diff --git a/bibtexbrowser.php b/src/bibtexbrowser.php old mode 100755 new mode 100644 similarity index 90% rename from bibtexbrowser.php rename to src/bibtexbrowser.php index 613de6d..681d260 --- a/bibtexbrowser.php +++ b/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')) { @@ -226,7 +232,8 @@ if (defined('ENCODING')) { // 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',basename(__FILE__)); +@define('BIBTEXBROWSER_URL',''); // *************** END CONFIGURATION @@ -243,6 +250,8 @@ define('Q_INNER_TYPE', 'x-bibtex-type');// used for representing the type of the function nothing() {} + + function config_value($key) { global $CONFIGURATION; if (isset($CONFIGURATION[$key])) { return $CONFIGURATION[$key]; } @@ -325,7 +334,7 @@ function _zetDB($bibtex_filenames) { // to automate dectection of faulty links with tools such as webcheck header('HTTP/1.1 404 Not found'); // escape $bib to prevent XSS - $escapedBib = htmlEntities($bib, ENT_QUOTES); + htmlEntities($bib, ENT_QUOTES); die('the bib file '.$escapedBib.' does not exist !'); } } // end for each @@ -467,7 +476,6 @@ if (!function_exists('createMenuManager')) { function createMenuManager() { $x = new MenuManager(); return $x;} } - //////////////////////////////////////////////////////// /** is a generic parser of bibtex files. @@ -481,472 +489,11 @@ 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 ''; - print ''; - } - - - function endFile() { - print ''; - } - function setEntryField($finalkey,$entryvalue) { - print "\n".$finalkey."\n".$entryvalue."\n\n"; - } - - function setEntryType($entrytype) { - print ''.$entrytype.''; - } - - function setEntryKey($entrykey) { - print ''.$entrykey.''; - } - - function beginEntry() { - print "\n"; - } - - function endEntry($entrysource) { - print "\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: -
    -  $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
    -
    -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 - // (?$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 - @@ -1228,7 +775,7 @@ class BibEntry { // we assume that "comment" is never latex code // but instead could contain HTML code (with links using the character "~" for example) // so "comment" is not transformed too - if ($name!='url' && $name!='comment' + if ($name!='url' && $name!='comment' && !preg_match('/^hp_/',$name) // homepage links should not be transformed with latex2html ) { $value = $this->transformValue($value); @@ -4089,7 +3636,6 @@ dd { <BODY> and TITLE) usage:
    @@ -4103,6 +3649,7 @@ usage:
           getTitle()
      * $title: title of the page
      */
    +
     function HTMLTemplate($content) {
     
     // when we load a page with AJAX
    @@ -4139,20 +3686,20 @@ if (method_exists($content, 'getTitle')) {
     
     // now the CSS
     echo '';
     
     ?>
     
     
    -
    @@ -4529,7 +4076,7 @@ class Dispatcher {
           }
     
           // should call method display() on $x
    -      $fun = $this->wrapper;
    +      $fun = BIBTEXBROWSER_DEFAULT_TEMPLATE;//$this->wrapper;
           $fun($x);
     
           $this->clearQuery();
    @@ -4539,7 +4086,7 @@ class Dispatcher {
            // if some contents have already been sent, for instance if we are included
            // this means doing nothing
            if ( headers_sent() == false ) { /* to avoid sending an unnecessary frameset */
    -         header("Location: ".$_SERVER['SCRIPT_NAME']."?frameset&bib=".$_GET[Q_FILE]);
    +           header("Location: ".$_SERVER['SCRIPT_NAME']."?frameset&bib=".$_GET[Q_FILE]);
            }
          }
       }
    @@ -4666,7 +4213,8 @@ class Dispatcher {
       function menu() {
         $menu = createMenuManager();
         $menu->setDB($this->getDB());
    -    $fun = $this->wrapper;
    +    // why does //$this->wrapper; = no wrapper?
    +    $fun = BIBTEXBROWSER_DEFAULT_TEMPLATE;
         $fun($menu);
         return 'END_DISPATCH';
       }
    @@ -4757,7 +4305,7 @@ class Dispatcher {
         
     
         extract_css_classes($first_entry->toHTML());
    -    
    +
         // IEEE style
         bibtexbrowser_configure('BIBLIOGRAPHYSTYLE','JanosBibliographyStyle');
         $this->assertEquals("Foo Bar and Jane Doe, \"An Article\", In New Results, vol. 5, pp. 1-2, 2009.\n ",strip_tags($first_entry->toHTML()));
    @@ -646,7 +646,7 @@ class BTBTest extends PHPUnit_Framework_TestCase {
             ob_get_clean();
             $this->assertEquals("[2]", $btb->getEntryByKey('aKey')->getAbbrv());
             $this->assertEquals("[1]", $btb->getEntryByKey('aKey-withSlash')->getAbbrv());
    -        
    +
         }
     
         function test_identity() {
    diff --git a/bibtexbrowser-documentation.wiki b/wiki/bibtexbrowser-documentation.wiki
    similarity index 100%
    rename from bibtexbrowser-documentation.wiki
    rename to wiki/bibtexbrowser-documentation.wiki
    diff --git a/bibtexbrowser-users.wiki b/wiki/bibtexbrowser-users.wiki
    similarity index 100%
    rename from bibtexbrowser-users.wiki
    rename to wiki/bibtexbrowser-users.wiki