diff options
| author | Ian Jauslin <jauslin@ias.edu> | 2017-05-02 20:20:48 +0000 | 
|---|---|---|
| committer | Ian Jauslin <jauslin@ias.edu> | 2017-05-02 21:38:33 +0000 | 
| commit | 1366aa391af0ec4e6fcef3a10d8345ad2d32e340 (patch) | |
| tree | efcc637d71f5f490c15580e13f4e3bf8bd7f3a27 /bin | |
Initial commit
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 + | 
