Ian Jauslin
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Jauslin <jauslin@ias.edu>2017-05-02 20:20:48 +0000
committerIan Jauslin <jauslin@ias.edu>2017-05-02 21:38:33 +0000
commit1366aa391af0ec4e6fcef3a10d8345ad2d32e340 (patch)
treeefcc637d71f5f490c15580e13f4e3bf8bd7f3a27
Initial commit
-rw-r--r--INSTALL27
-rw-r--r--LICENSE202
-rw-r--r--Makefile37
-rw-r--r--NOTICE2
-rwxr-xr-xbin/BBlog437
-rw-r--r--engines/sqlite.sh115
-rw-r--r--example/BBlog_example.tex14
-rw-r--r--example/bibliography.BBlog.tex2
-rw-r--r--example/bibliography.dbbin0 -> 2048 bytes
-rw-r--r--example/conf.BBlog5
-rw-r--r--example/ref_map.sed2
-rw-r--r--man/man1/BBlog.1198
-rw-r--r--man/man7/BBlog-sqlite.737
13 files changed, 1078 insertions, 0 deletions
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..95955be
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,27 @@
+#######################################################################
+## ##
+## Installing BBlog ##
+## ##
+#######################################################################
+
+* BBlog is a bash script, and should work on any POSIX compliant
+ system, such as GNU/Linux or OSX.
+
+* Installing:
+ Run
+ make install
+
+ The default install prefix (/usr) can be changed by changing the
+ PREFIX variable.
+
+ The location in which the BBlog engines are installed can be changed
+ by changing the ENGINEDIR variable
+ (default '$(PREFIX)/share/BBlog/engines').
+ For example
+ make install PREFIX=/usr/local ENGINEDIR=/usr/local/BBlog/engines
+
+ When, for instance, building a package, the final location of the
+ engines directory might be different from that in which the engines
+ are to be installed. For such cases, use the ENGINEDIR_TARGET
+ variable to specify the final location of the engines directory
+ (default '$(ENGINEDIR)').
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..9258955
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,37 @@
+## Copyright Ian Jauslin 2015-2017
+##
+## Licensed under the Apache License, Version 2.0 (the "License");
+## you may not use this file except in compliance with the License.
+## You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+
+# installation dirs
+PREFIX=/usr
+BINDIR=$(PREFIX)/bin
+MANDIR=$(PREFIX)/share/man
+ENGINEDIR=$(PREFIX)/share/BBlog/engines
+
+ENGINEDIR_TARGET=$(ENGINEDIR)
+
+# escape enginedir path for sed
+ENGINEDIR_SED=$(subst /,\/,$(ENGINEDIR_TARGET))
+
+all: BBlog
+
+BBlog:
+ sed -i 's/^enginedir=.*$$/enginedir=$(ENGINEDIR_SED)/' bin/BBlog
+
+install: all
+ mkdir -p $(BINDIR) $(MANDIR) $(ENGINEDIR)
+ install -Dm755 bin/* -t $(BINDIR)/
+ install -Dm644 man/man1/* -t $(MANDIR)/man1
+ install -Dm644 man/man7/* -t $(MANDIR)/man7
+ gzip $(MANDIR)/*/*
+ install -Dm644 engines/* -t $(ENGINEDIR)/
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..528486f
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,2 @@
+BBlog
+Copyright Ian Jauslin 2015-2017
diff --git a/bin/BBlog b/bin/BBlog
new file mode 100755
index 0000000..0d9e88f
--- /dev/null
+++ b/bin/BBlog
@@ -0,0 +1,437 @@
+#!/bin/bash
+
+## Copyright Ian Jauslin 2015-2017
+##
+## Licensed under the Apache License, Version 2.0 (the "License");
+## you may not use this file except in compliance with the License.
+## You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+
+# directory containing the engine files
+enginedir=/usr/share/BBlog/engines
+enginedir=/home/ian/Programs/BBlog2/engines
+
+# version
+version=2.1
+
+function print_config {
+ echo "engine: $engine"
+ echo "db: $db"
+ echo "conf: $conf"
+ echo "aux: $aux"
+ echo "format: $format"
+ echo "outbib: $outbib"
+ echo "order: $order"
+ echo "aux_cmd: $aux_cmd"
+ echo "ref_map: $ref_map"
+}
+
+# defaults
+function set_defaults {
+ engine="sqlite"
+ db=""
+ conf=""
+ aux='*.aux'
+ format='\bibitem[%citeref%]{%token%}%n%%author% - {\it %title%}, %journal%, %year%.%n%'
+ outbib=''
+ order="alphabetical"
+ aux_cmd='\\citation{'
+ ref_map=''
+}
+
+# read cli args
+function read_cli {
+
+ flag=""
+ for arg in "$@"; do
+ case "$arg" in
+ "-e" )
+ flag="engine" ;;
+ "-d" )
+ flag="db" ;;
+ "-c" )
+ flag="conf" ;;
+ "-a" )
+ flag="aux" ;;
+ "-f" )
+ flag="format" ;;
+ "-b" )
+ flag="outbib" ;;
+ "-o" )
+ flag="order" ;;
+ "-A" )
+ flag="aux_cmd" ;;
+ "-F" )
+ flag="filter" ;;
+ "-r" )
+ flag="ref_map" ;;
+ # version
+ "-v" )
+ echo "$version"; exit ;;
+ * )
+ if [ -n "$flag" ]; then
+ # treat filters differently
+ if [ "$flag" != 'filter' ]; then
+ eval "$flag='$arg'"
+ # flag the variable as set
+ eval "set_$flag=1"
+ else
+ field="${arg%%:*}"
+ value="${arg#*:}"
+ eval "filter_$field='$value'"
+ eval "set_filter_$field=1"
+ fi
+ flag=""
+ fi
+ esac
+ done
+}
+
+# read config file
+function read_config {
+ extra_entries_index=0
+
+ if [ -n "$conf" ]; then
+ [ -f "$conf" ] || { echo "error: $conf: no such file" 1>&2 ; exit -1 ; }
+ while read -r confline; do
+ flag=""
+ field="${confline%%:*}"
+ value="${confline#*:}"
+ # remove spaces
+ field=$(echo "$field" | sed -r 's/ *$//')
+ value=$(echo "$value" | sed -r 's/^ *//')
+ case "$field" in
+ "engine" )
+ flag="engine" ;;
+ "database" )
+ flag="db" ;;
+ "aux" )
+ flag="aux" ;;
+ "format" )
+ flag="format" ;;
+ "out_file" )
+ flag="outbib" ;;
+ "order" )
+ flag="order" ;;
+ "aux_cmd" )
+ flag="aux_cmd" ;;
+ "ref_map" )
+ flag="ref_map" ;;
+ "filter" )
+ # set flag to the specific filter
+ flag="filter_${value%%:*}"
+ # reset value
+ value="${value#*:}" ;;
+ "extra" )
+ extra[$extra_entries_index]="$value"
+ extra_entries_index=$((extra_entries_index+1)) ;;
+ esac
+
+ if [ -n "$flag" ]; then
+ # check it was not set on the command line
+ eval "[ -n \"\$set_$flag\" -a \"\$set_$flag\" = 1 ] || $flag='$value'"
+ fi
+ done <"$conf"
+
+ # sort extra entries
+ if [ "$extra_entries_index" -gt 0 -a "$order" = "alphabetical" ]; then
+ IFS=$'\n' extra=($(echo "${extra[*]}" | sort -k 1,1 -t :))
+ fi
+ fi
+}
+
+# check the configuration
+function check_config {
+ # check whether the engine exists
+ [ -e "$enginedir/$engine.sh" ] || { echo "error: engine $engine not found in $enginedir" 1>&2; exit -1 ; }
+
+ # check the database and aux file
+ for file in "$db" "$aux"; do
+ [[ "$file" =~ '*' || -e "$file" ]] || { echo "error: $file: no such file" 1>&2 ; exit -1 ; }
+ done
+
+ # check the $order variable
+ [ "$order" != "alphabetical" -a "$order" != "appearance" ] && { echo "error: order should be one of 'alphabetical' or 'appearance' (read $order)" 1>&2 ; exit -1 ; }
+
+ # check for ref_map
+ [ -n "$ref_map" ] && [ ! -e "$ref_map" ] && { echo "error: $ref_map: no such file" 1>&2 ; exit -1 ; }
+}
+
+function replace_format {
+ out="$1"
+
+ # replace newlines
+ out="${out//\%n\%/\\n}"
+
+ # if the ref of the entry has been mapped, fetch the old citeref
+ if [ -n "$ref_map" ]; then
+ citeref=$(inverse_map_citeref "$citeref")
+ fi
+
+ # first search for conditionals
+ # while '|' is still in $out
+ while : ; do
+ # find next '|'
+ tmp=${out#*|}
+ # save text before '|'
+ pre=${out%%|*}
+ # check whether it was found
+ [ "$tmp" = "$out" ] && break
+ # find next '|'
+ command=${tmp%%|*}
+ # save text after '|'
+ post=${tmp#*|}
+ # check whether it was found
+ [ "$command" = "$tmp" ] && { echo "error: '|'s do not match in '$1'" 1>&2 ; exit -1 ; }
+
+ # extract field
+ field="${command%%\?*}"
+ repl="${command##*\?}"
+
+ # check whether field is empty
+ val=$(eval "echo \$$field")
+ if [ -n "$val" ]; then
+ out="$pre$repl$post"
+ else
+ out="$pre$post"
+ fi
+ done
+
+ # replace '%'
+ # while '%' is still in $out
+ while : ; do
+ # find next '%'
+ tmp=${out#*%}
+ # check whether it was found
+ [ "$tmp" = "$out" ] && break
+ # find next '%'
+ command=${tmp%%%*}
+ # check whether it was found
+ [ "$command" = "$tmp" ] && { echo "error: '%'s do not match in '$1'" 1>&2 ; exit -1 ; }
+
+ # the field entry may be followed by a filter
+ field="${command%:*}"
+ # filter
+ filter="${command##*:}"
+
+ # apply filter
+ if [ -n "$filter" ]; then
+ sed_cmd=$(eval "echo \$filter_$filter")
+ replacement=$(eval "echo \$$field" | sed -r "$sed_cmd" )
+ else
+ replacement=$(eval "echo \$$field")
+ fi
+
+ out="${out//\%$command\%/$replacement}"
+ done
+
+ # finish replacing newlines
+ out="${out//\\n/%}"
+ out=$(echo "$out" | tr "%" "\n")
+ echo "$out"
+}
+
+function escape_string {
+ str="$1"
+ str="${str//\\/\\\\}"
+ str="${str//\`/\\\`}"
+ str="${str//\"/\\\"}"
+ str="${str//\$/\\\$}"
+ echo "$str"
+}
+
+# replace a citeref according to a ref_map
+function map_citeref {
+ # check whether a ref_map was specified
+ [ -z "$ref_map" ] && { echo "$1" ; return 0 ; }
+
+ oldref="$1"
+ newref=$(echo "$oldref" | sed -r -f "$ref_map")
+ echo "$newref"
+}
+
+# find the pre-image of a citeref through the ref_map
+function inverse_map_citeref {
+ # check whether a ref_map was specified
+ [ -z "$ref_map" ] && { echo "$1" ; return 0 ; }
+
+ newref="$1"
+
+ foundref=0
+ # sift through aux file
+ grep -h "$aux_cmd" $aux | while read -r ref; do
+ eval "ref=\${ref#$aux_cmd}"
+ ref="${ref%\}}"
+ # replace the ref via the ref_map
+ possibleref=$(map_citeref "$ref")
+ # check whether the ref is the right one
+ if [ "$possibleref" = "$newref" ]; then
+ echo "$ref"
+ foundref=1
+ return 1
+ fi
+ done && echo "$foundref$newref"
+}
+
+# format entries
+function format_BBlog_entries {
+ # keep track of tokens to avoid repetitions
+ token_list=""
+
+ has_there_been_a_nonempty_line_so_far=0
+
+ while read -r line; do
+ # if line has 0 size, then new entry
+ if [ -z "$line" ]; then
+ # skip if it is the first line
+ if [ $has_there_been_a_nonempty_line_so_far = 1 ]; then
+ # check whether an extra entry precedes it
+ # alphabetical order
+ if [ "$order" = "alphabetical" ]; then
+ old_token="$token"
+ old_citeref="$citeref"
+ while [[ ${#extra} -gt 0 && "${extra[0]%%:*}" < "$prauth$year" ]]; do
+ reftokval="${extra[0]#*:}"
+ citeref="${reftokval%%:*}"
+ tokval="${reftokval#*:}"
+ token="${tokval%%:*}"
+ value="${tokval#*:}"
+ # check whether token is unique
+ token=$(replace_repeated_token "$token" "$token_list")
+ # add token to list
+ token_list="$token_list;$token"
+
+ replace_format "$value"
+
+ IFS=$'\n' extra=($(echo "${extra[*]:1}"))
+ done
+ token="$old_token"
+ citeref="$old_citeref"
+
+ # check whether token is unique
+ token=$(replace_repeated_token "$token" "$token_list")
+ # add token to list
+ token_list="$token_list;$token"
+
+ replace_format "$format"
+
+ # appearance order
+ else
+ foundit=0
+ if [ ${#extra} -gt 0 ]; then
+ for entry in "${extra[@]}"; do
+ ref="${entry#*:}"
+ ref="${ref%%:*}"
+ if [ "$ref" = "$citeref" ]; then
+ old_token="$token"
+ old_citeref="$citeref"
+
+ citeref="$ref"
+ token="${entry#*:*:}"
+ value="${token#*:}"
+ token="${token%%:*}"
+ # check whether token is unique
+ token=$(replace_repeated_token "$token" "$token_list")
+ # add token to list
+ token_list="$token_list;$token"
+
+ replace_format "$value"
+
+ token="$old_token"
+ citeref="$old_citeref"
+ foundit=1
+ break
+ fi
+ done
+ fi
+
+ if [ $foundit = 0 ]; then
+ # check whether token is unique
+ token=$(replace_repeated_token "$token" "$token_list")
+ # add token to list
+ token_list="$token_list;$token"
+
+ replace_format "$format"
+ fi
+ fi
+ fi
+ has_there_been_a_nonempty_line_so_far=0
+ else
+ eval "$line"
+ has_there_been_a_nonempty_line_so_far=1
+ fi
+ done
+
+ # add remaining extra entries (only for alphabetical order)
+ if [ "$order" = "alphabetical" ]; then
+ while [ ${#extra} -gt 0 ]; do
+ reftokval="${extra[0]#*:}"
+ citeref="${reftokval%%:*}"
+ tokval="${reftokval#*:}"
+ token="${tokval%%:*}"
+ value="${tokval#*:}"
+ # check whether token is unique
+ token=$(replace_repeated_token "$token" "$token_list")
+ # add token to list
+ token_list="$token_list;$token"
+
+ replace_format "$value"
+ IFS=$'\n' extra=($(echo "${extra[*]:1}"))
+ done
+ fi
+}
+
+# replace a token that already exists
+function replace_repeated_token {
+ token="$1"
+ list="$2"
+
+ out="$token"
+ i=0
+ while $(echo "$token_list;" | grep -q ";$out;"); do
+ i=$((i+1))
+ out="$token"$(alpha_number $i)
+ done
+
+ echo "$out"
+}
+
+# convert an integer to base 26
+function alpha_number {
+ num="$1"
+ rem="$num"
+ out=""
+ letters=(a b c d e f g h i j k l m n o p q r s t u v w x y z)
+ while [ "$rem" -gt 0 ]; do
+ digit=$((rem-26*(rem/26)))
+ out="${letters[$digit]}$out"
+ rem=$(((rem-digit)/26))
+ done
+
+ echo "$out"
+}
+
+
+set_defaults
+read_cli "$@"
+read_config
+check_config
+source "$enginedir/$engine.sh"
+
+# check whether to order by alphabetical order or appearance
+[ "$order" = "alphabetical" ] && fetch_cmd=fetch_BBlog_entries_alpha || fetch_cmd=fetch_BBlog_entries_appearance
+
+# fetch entries
+if [ -n "$outbib" ]; then
+ "$fetch_cmd" | format_BBlog_entries > "$outbib"
+else
+ "$fetch_cmd" | format_BBlog_entries
+fi
+
diff --git a/engines/sqlite.sh b/engines/sqlite.sh
new file mode 100644
index 0000000..c14f30c
--- /dev/null
+++ b/engines/sqlite.sh
@@ -0,0 +1,115 @@
+base_SQL="SELECT title,author,journal,year,token,doi,arxiv,citeref,prauth FROM bibliography"
+base_SQL_noprauth="SELECT title,author,journal,year,token,doi,arxiv,citeref FROM bibliography"
+
+# add quotes
+function SQL_addquotes {
+ while read -r line; do
+ # add quotes and escape string
+ if [ -n "$line" ]; then
+ line=$(escape_string "$line")
+ line="${line/%=/= }"
+ line="${line/ = /=\"}"
+ line="${line/%/\"}"
+ fi
+ echo "$line"
+ done
+}
+
+# SQL command for alphabetical ordering
+function generate_SQL_alpha {
+ echo -n "$base_SQL WHERE citeref='"
+
+ # whether there is a citeref
+ exists_citeref=0
+
+ # sift through aux file
+ grep -h "$aux_cmd" $aux | while read -r citeref; do
+ eval "citeref=\${citeref#$aux_cmd}"
+ citeref="${citeref%\}}"
+
+ # replace the citeref with a ref_map if there is any
+ if [ -n "$ref_map" ]; then
+ citeref=$(map_citeref "$citeref")
+ fi
+
+ # Only query the db if there is no matching extra entry
+ foundit=0
+ if [ ${#extra} -gt 0 ]; then
+ for entry in "${extra[@]}"; do
+ ref="${entry#*:*:}"
+ ref="${ref%%:*}"
+ if [ "$ref" = "$citeref" ]; then
+ foundit=1
+ break
+ fi
+ done
+ fi
+
+ if [ "$foundit" = 0 ]; then
+ echo -n "$citeref' OR citeref='"
+ exists_citeref=1
+ fi
+ done
+
+ # if there are no citerefs close '
+ [ $exists_citeref = 0 ] && echo -n "'"
+}
+
+# fetch entries by alphabetical order
+function fetch_BBlog_entries_alpha {
+ SQL="$(generate_SQL_alpha)"
+ SQL="${SQL% OR citeref=\'} ORDER BY prauth,year"
+ sqlite3 -line "$db" "$SQL" | SQL_addquotes
+ # add an empty line
+ echo ""
+}
+
+# fetch entries by order of appearance
+function fetch_BBlog_entries_appearance {
+ # keep track of citerefs to avoid repetitions
+ citeref_list=""
+
+ # sift through aux file
+ grep -h "$aux_cmd" $aux | while read -r citeref; do
+ eval "citeref=\${citeref#$aux_cmd}"
+ citeref="${citeref%\}}"
+
+ # replace the citeref with a ref_map if there is any
+ if [ -n "$ref_map" ]; then
+ citeref=$(map_citeref "$citeref")
+ fi
+
+ # check whether the reference was already cited
+ citeref_list="$citeref_list;"
+ if $(echo "$citeref_list" | grep -q ";$citeref;"); then
+ # remove trailing ';'
+ citeref_list="${citeref_list%;}"
+ else
+ citeref_list="$citeref_list$citeref"
+
+ # Only query the db if there is no matching extra entry
+ foundit=0
+ if [ ${#extra} -gt 0 ]; then
+ for entry in "${extra[@]}"; do
+ ref="${entry#*:}"
+ ref="${ref%%:*}"
+ if [ "$ref" = "$citeref" ]; then
+ foundit=1
+ break
+ fi
+ done
+ fi
+
+ if [ "$foundit" = 0 ]; then
+ SQL="$base_SQL_noprauth WHERE citeref='$citeref'"
+ sqlite3 -line "$db" "$SQL" | SQL_addquotes
+ else
+ echo "citeref=$citeref"
+ fi
+
+ # add an empty line
+ echo ""
+ fi
+ done
+}
+
diff --git a/example/BBlog_example.tex b/example/BBlog_example.tex
new file mode 100644
index 0000000..69c4e1b
--- /dev/null
+++ b/example/BBlog_example.tex
@@ -0,0 +1,14 @@
+\documentclass{article}
+
+\begin{document}
+\noindent References can be cited by referencing their {\tt citeref}: \cite{Do99}.
+\bigskip
+
+\noindent The bibliography can be loaded by including the file generated by {\tt BBlog}:
+
+\begin{thebibliography}{MM99}
+\IfFileExists{bibliography.BBlog.tex}{\input{bibliography.BBlog.tex}}{}
+\end{thebibliography}
+
+\end{document}
+
diff --git a/example/bibliography.BBlog.tex b/example/bibliography.BBlog.tex
new file mode 100644
index 0000000..f2dc448
--- /dev/null
+++ b/example/bibliography.BBlog.tex
@@ -0,0 +1,2 @@
+\bibitem[]{}
+{\bf } - {\it }, , .
diff --git a/example/bibliography.db b/example/bibliography.db
new file mode 100644
index 0000000..807512c
--- /dev/null
+++ b/example/bibliography.db
Binary files differ
diff --git a/example/conf.BBlog b/example/conf.BBlog
new file mode 100644
index 0000000..509a5ed
--- /dev/null
+++ b/example/conf.BBlog
@@ -0,0 +1,5 @@
+database: bibliography.db
+format: \bibitem[%citeref%]{%token%}%n%{\bf %author:auth%} - {\it %title%}, %journal%, %year%.%n%
+out_file: bibliography.BBlog.tex
+filter:auth: s/([A-Z])[^ ]* /\1. /g; s/ ([^ ]*) /\1 /g; s/_/ /g;
+ref_map: ref_map.sed
diff --git a/example/ref_map.sed b/example/ref_map.sed
new file mode 100644
index 0000000..0d7e650
--- /dev/null
+++ b/example/ref_map.sed
@@ -0,0 +1,2 @@
+s/^Do99$/Doe99/
+
diff --git a/man/man1/BBlog.1 b/man/man1/BBlog.1
new file mode 100644
index 0000000..24620e6
--- /dev/null
+++ b/man/man1/BBlog.1
@@ -0,0 +1,198 @@
+.Dt BBLOG 2.1
+.Os
+.Sh NAME
+.Nm BBlog
+.Nd LaTeX bibliography parser
+.Sh SYNOPSIS
+.Nm
+.Bk -words
+.Op Fl c Ar conf_file
+.Op Fl d Ar database_file
+.Op Fl e Ar engine
+.Op Fl a Ar aux_file
+.Op Fl A Ar aux_command
+.Op Fl f Ar format
+.Op Fl F Ar filter_name:filter
+.Op Fl r Ar ref_map
+.Op Fl o Ar order
+.Op Fl b Ar output
+.Ek
+.Pp
+.Nm
+.Bk -words
+.Fl v
+.Ek
+.Sh DESCRIPTION
+.Nm
+generates bibliographies for LaTeX documents.
+.Pp
+.Nm
+reads a list of bibliography items from a LaTeX .aux file read from a file or from stdin if no input file is specified.
+.Pp
+The bibliography is output to a file or to stdout if no output file is specified.
+.Pp
+The bibliography entries are contained in a database.
+.Nm
+is bundled with several engines" for reading the following types of databases:
+.Bl -bullet
+.It
+.Sy sqlite :
+sqlite3 databases (see
+.Sx BBlog-sqlite Ns (7))
+.El
+.Pp
+.Sh COMMAND-LINE OPTIONS
+.Bl -tag -width Ds
+.It Fl c Ar conf_file
+Configuration file (default: '').
+.It Fl d Ar database_file
+Database (default: '').
+.It Fl e Ar engine
+The engine to use to read the database (default: 'sqlite').
+.It Fl a Ar aux_file
+LaTeX .aux file, supports bash globbing (default: '*.aux').
+.It Fl A Ar aux_command
+In the .aux file, each entry should be written as the argument of a LaTeX command, specified through this option (default: '\\citation{').
+.It Fl f Ar format
+Format of the bibliography entries (default: '\\bibitem[%citeref%]{%token%}%n%%author% - {\it %title%}, %journal%, %year%.%n%').
+.It Fl F Ar filter_name:filter
+Define a filter (this option can be specified more than once). Filters can be used in the format string in order to automatically change database entries (see FILTERS).
+.It Fl r Ar ref_map
+A ref_map is a file containing a sequence of
+.Sx sed Ns (1)
+commands which is used to translate the document citerefs into database citerefs (see REF_MAP).
+.It Fl o Ar order
+Order in which to display the entries, either 'alphabetical' (order by author) or 'appearance' (in order of citation in text) (default: 'alphabetical')
+.It Fl b Ar output
+Output file (default: stdout)
+.It Fl v
+Print version and exit.
+.El
+.Sh CONFIGURATION FILE
+The options described above can also be specified in a configuration file. The options specified on the command line have precedence over those given in the configuration file. The configuration file is a list of key/value pairs, in the following format:
+.D1 key: value
+The possible keys are
+.Bl -bullet -offset Ds
+.It
+.Sy database
+.It
+.Sy engine
+.It
+.Sy aux
+.It
+.Sy aux_cmd
+.It
+.Sy format
+.It
+.Sy filter
+.It
+.Sy ref_map
+.It
+.Sy order
+.It
+.Sy out_file
+.It
+.Sy extra
+.El
+.Pp
+In addition to the command-line options, extra bibliography entries can be provided in the conf file. This is done through the 'extra' key. The value of 'extra' should be of the form
+.Pp
+.D1 order_tag:citeref:token:content
+.Pp
+where
+.Bl -tag -width Ds
+.It Sx order_tag
+a string that is compared with the 'prauth' of other entries to determine where the extra entry should be placed: e.g. in 'alphabetical' mode, if 'order_tag' is "Doe1996" and there are two other entries with prauth "Doe1990" and "Fred1967", then the extra entry will be placed between "Doe1990" and "Fred1967". If the ordering mode is "appearance", then this entry is ignored.
+.It Sx citeref
+the citeref for the extra entry.
+.It Sx token
+the token for the extra entry. If the token appears in another entry, then the appropriate steps are taken to make it unique (see TOKEN REPETITIONS).
+.It Sx content
+the text to be printed to the bibliography, which may contain the '%token%' and '%citeref%' macros (see FORMAT). Since the token may be replaced if it is a duplicate, it is safer to use the '%token%' macro rather than writing it explicitly in 'content'.
+.El
+.Sh ENGINE
+An engine is shell script that defines functions to read a database. These functions take a list of references as an input, and, for each reference, return a collection of key/value pairs. The format string (see FORMAT) can reference the keys in order to construct the entry from the associated values.
+.Pp
+One of the entries must be the citeref of the entry and its key must be 'citeref' (or else the ref_map will not work).
+.Pp
+A more thorough discussion of the format of engines and instructions on writing custom engines is provided below in the CUSTOM ENGINES section.
+.Sh FORMAT
+The format string specifies how the entries of the bibliography should be typeset. It is a string of characters, in which database entries can be inserted by writing the appropriate key, sandwiched between '%' characters. For instance '%title%' is replaced by the value associated to the 'title' key.
+.Pp
+In addition, a filter can be added to any key, for instance '%title:tfilter%' is replaced by the value associated to the 'title' key after going through the filter 'tfilter' defined in the 'filter' entry (see FILTER).
+.Pp
+The format string can also contain conditional statements, in the format '|field?text|'. When a conditional statement is encountered,
+.Nm
+checks whether the field is non-empty, and replaces it with 'text' if it is, while it ignores 'text' if the field is empty. For example, '|link?\\url{%link%}|' is expanded to '\\url{%link%}' if '%link%' is non empty, and is ignored if '%link%' is empty.
+.Pp
+.Sx Warning :
+Conditional statements cannot be nested.
+.Pp
+Newline characters can be inserted using '%n%'. For every reference, the format string is read, '%' characters are replaced by the appropriate database entry, and the output is written to the output file.
+.Pp
+Note that the format string may not contain newline characters.
+.Sh FILTER
+Filters can be used to automatically format database entries to suit the style of a particular document. For example, if the names of the authors is given as 'first_name last_name' in the database, but the desired format only retains the first initial of the first_name, then a filter that maps 'first_name last_name' to 'first_initial last_name' can be used.
+.Pp
+Each filter must be given a name, which can be referenced inside '%...%' commands. When the filter is defined, its name is specified by
+.D1 filter:name_of_the_filter: expression_of_the_filter
+.Pp
+The expression of a filter is a
+.Sx sed Ns (1)
+script. Note that the
+.Sx sed Ns (1)
+command is called with the '-r' option, so extended regexps should be used.
+.Pp
+The following line defines a filter, 'authfilter', that maps a 'first_name middle_name last_name,...' entry to a 'first_initial.middle_initial. last_name,...' entry:
+.Pp
+.D1 filter:authfilter: s/([A-Z])[^, ]* /\1. /g; s/ ([^ ,]*),/_\1,_/g; s/ ([^ ,]*)$/_\1/g; s/ //g; s/_/ /g;
+.Pp
+This filter can then be used by setting the format to
+.Pp
+.D1 %author:authfilter% - {\it %title%}, %journal%, %year%.%n%
+.Pp
+.Sh REF_MAP
+Ref_maps can be useful when the citerefs in the LaTeX document are different from those in the database (e.g. when writing papers in collaboration with someone who uses a different convention for their citerefs). In order to automatically translate the citerefs in the document to ones the database can read, a
+.Sx sed Ns (1)
+script that performs the translation can be specified. This
+.Sx sed Ns (1)
+script is called a 'ref_map'.
+.Pp
+For example, to translate 'doe11' to 'Do11', use
+.D1 s/^doe11$/Do11/
+.Pp
+Since ref_maps are
+.Sx sed Ns (1)
+scripts, they can use regexps. Note that the '-r' command line switch is used, so extended regexps should be used.
+.Pp
+.Sh CUSTOM ENGINES
+(See the sqlite.sh engine for an example). Custom engines are shell scripts that define two functions:
+.Bl -bullet -offset Ds
+.It
+fetch_BBlog_entries_alpha
+.It
+fetch_BBlog_entries_appearance
+.El
+.Pp
+which read the .aux file, and output a list of key/value pairs for each reference, respectively in alphabetical order and in order of appearance in the document.
+.Pp
+In addition, if a ref_map is specified, then the citeref should be translated accordingly before being passed to the database. The 'map_citeref' function should be used to handle the translation.
+.Pp
+The output of each function should be written to stdout. For each reference, a list of key/value pairs in the format 'key="value"' should be printed, with no empty lines. Different references must be separated by a single empty line.
+.Pp
+Each key/value entry should be formatted as a bash variable assignment, in particular special characters should be escaped and quotes should be used where needed. A function to escape some common special characters is provided, and can be called by passing the input string to the stdin of 'escape_string'.
+.Pp
+Engines are stored in /usr/share/BBlog/engines/ by default (the path can be changed through the 'enginedir' variable, which can also be set when installing
+.Nm
+using its Makefile, through the ENGINEDIR variable).
+.Sh TOKEN REPETITIONS
+If multiple references that share the same token are cited within the same document, then
+.Nm
+automatically adds a letter (from 'b' to 'z') at the end of non-unique tokens, in order of appearance.
+.Sh AUTHORS
+.Nm
+was written by Ian Jauslin.
+.Sh COPYRIGHT
+copyright Ian Jauslin 2015-2017
+.Sh SEE ALSO
+.Sx BBlog-sqlite Ns (7)
diff --git a/man/man7/BBlog-sqlite.7 b/man/man7/BBlog-sqlite.7
new file mode 100644
index 0000000..cfac0f9
--- /dev/null
+++ b/man/man7/BBlog-sqlite.7
@@ -0,0 +1,37 @@
+.Dt BBLOG-sqlite
+.Os
+.Sh DESCRIPTION
+BBlog sqlite engine.
+.Pp
+This engine reads sqlite3 databases and generates bibliographies using
+.Sx BBlog Ns (1) .
+.Pp
+The database must contain a table named 'bibliography' with (at least) the following columns:
+.Bl -tag -width Ds -offset Ds
+.It title
+title of the item
+.It author
+author(s)
+.It journal
+journal information, including its name, volume, number and page, or if the item is a book, editor information
+.It year
+publication year
+.It doi
+DOI number
+.It arxiv
+arXiv number
+.It token
+symbol printed in the document by the LaTeX '\\cite' command
+.It citeref
+label of the reference
+.It prauth
+bibliography entries are ordered alphabetically with respect to this entry
+label of the reference
+.El
+.Sh AUTHORS
+The sqlite BBlog engine was written by Ian Jauslin.
+.Sh COPYRIGHT
+copyright Ian Jauslin 2015-2017
+.Sh SEE ALSO
+.Sx BBlog Ns (1) ,
+.Sx sqlite3 Ns (1)