#!/bin/bash
LLenMax=${LINELEN:-37}
awk -W version 2>&1 | grep -q GNU && AWKOPTS='-n'

declare -A ExitCodes=(
  [E_Ok]=0
  [E_Usage]=3
  [E_NotFound]=4
  [E_InvHeader]=5
  [E_CkXexCr]=6
  [E_BadData]=7
)

function PrintErr {
  printf '%s\n' "$1" >&2
  return $2
}

function usage {
  return $(PrintErr "usage: ${0##*/} [-f] filename [-n routine] [-l <max length>]" ${ExitCodes[E_Usage]})
}

function Print {
  EchoL=${#1}
  if [ $((LLen+EchoL)) -gt ${LLenMax} ]; then
    S='\n%s'
    LLen=${EchoL}
  else
    S='%s'
    LLen=$((LLen+EchoL))
  fi
  printf "${S}" "$1"
}

[ "$1" ] || exit $(usage)

while [ "$1" ]; do
  while getopts :f:n:l: OPTOPT; do
    case ${OPTOPT} in
      'f') FName="${OPTARG}" ;;
      'n') RName="${OPTARG}" ;;
      'l') LLenMax="${OPTARG}" ;;
      *) exit $(usage);
    esac
  done
  shift $((OPTIND-1))
  [ "$1" ] \
    && FName="$1"
  shift
  OPTIND=1
done

CkXEX="$(chkxex -det "${FName}" 2> /dev/null)"
[ $? -eq 6 ] \
  && exit $(PrintErr 'chkxex has crushed.' ${ExitCodes[E_CkXexCr]})
[[ "${CkXEX}" =~ ^"File '${FName}' not found"\.$ ]] \
  && exit $(PrintErr "${CkXEX}" ${ExitCodes[E_NotFound]})
[[ "${CkXEX}" =~ ^'Invalid file header'\.$ ]] \
  && exit $(PrintErr "${CkXEX}" ${ExitCodes[E_InvHeader]})

Table=($(awk ${AWKOPTS} '/RELOC MAIN BYTE$/ {sub("\\$", "", $6); printf("%d\n", "0x"$6)} /^[[:space:]]*\(#[[:xdigit:]][[:xdigit:]]:/ {FS="[$)]"; $0=$0; $2=sprintf("%d", "0x"$2); print $2" "(sprintf("%d", "0x"$4)-$2+65536)%65536}' <<< "${CkXEX}"))
LLen=1
TIdx=1
Count=0

test "${RName}" \
  && printf '%s\n' "${RName}"
echo -n '['
while read Byte; do
  if [ "x${Count}" = "x${Table[TIdx]}" ]; then
    read Byte
    Count=$((Count+1))
    Byte="*+${Table[TIdx+1]}"
    TIdx=$((TIdx+2))
  fi

  if [[ "${Byte}" =~ ^[[:xdigit:]]{2}$ ]]; then
    if [[ "${Prev}" =~ ^[[:xdigit:]]{2}$ ]]; then
      if [ "${Byte}" = '00' ]; then
        Echo="\$${Prev#0}"
        Prev="${Byte}"
      else
        Echo="\$${Byte#0}${Prev}"
        Prev=''
      fi
    else
      Echo="${Prev}"
      Prev="${Byte}"
    fi
  elif [[ "${Byte}" =~ ^\*\+[[:digit:]]{1,5}$ ]]; then
    [[ "${Prev}" =~ ^[[:xdigit:]]{2}$ ]] \
      && Echo="\$${Prev#0}" \
      || Echo="${Prev}"
    Prev="${Byte}"
  else
    exit $(PrintErr 'Bad data' ${ExitCodes[E_BadData]})
  fi
  Print "${Echo}"
  Echo=''
  Count=$((Count+1))
done < <(xxd -l ${Table[0]} -s 8 -ps -u "$FName" | fold -b2)
[ ${Prev} ] \
  && Print "${Prev}]" \
  || Print ']'
echo
exit ${ExitCodes[E_Ok]}
