diff options
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/BBlog | 437 |
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 + |