#!/bin/bash ## Copyright Ian Jauslin 2015-2022 ## ## 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 # version version=2.1.5 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 # escape '%' in replacement replacement="${replacement//\%/::iansays:percent::}" out="${out//\%$command\%/$replacement}" done # finish replacing newlines out="${out//\\n/%}" out=$(echo "$out" | tr "%" "\n") # un-escape '%' in replacement out="${out//::iansays:percent::/\%}" 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 refs; do eval "refs=\${refs#$aux_cmd}" refs="${ref%\}}" # can be a comma separated list for ref in $(echo -n "$refs" | tr ',' '\n'); do # 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 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