Ian Jauslin
summaryrefslogtreecommitdiff
path: root/bin/BBlog
diff options
context:
space:
mode:
Diffstat (limited to 'bin/BBlog')
-rwxr-xr-xbin/BBlog437
1 files changed, 437 insertions, 0 deletions
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
+