#!/bin/bash

pathOfDirPartOfExecPath() {
  if [[ -h "$1" ]] ; then
    local lsout="$(ls -l "$1")"
    local referent="${lsout#* -> }"
    pathOfDirPartOfExecPath "$referent"
  elif [[ -d "${1%/*}" ]] ; then
    echo "${1%/*}"
  else
    echo .
  fi
}
typeset -r commandDir="$(pathOfDirPartOfExecPath "$0")/"
# If $0 is a symlink, this is the invoked name, not the symlink referent name
typeset -r commandName="${0##*/}"
PATH="$commandDir:$PATH"

usage() {
    echo 1>&2 "
Usage: $commandName [ -v ] [ file ]

Unbunchs output from the \"bunch\" command into files on disk.
If a file to be extracted from the bunch differs from an existing file 
by the same name, unbunch replaces (rather than overwrites) the exsting file.

Lines before and after the bunchd file data are copied to standard output 
except for lines starting with #, so the first line of a bunch file can be
#!/usr/bin/env unbunch

Relies on \"replceifnew\" program.

Author: dave@yost.com
Last rev: 2015-06-07 make dirs for names ending in slash
"
    exit 2
}

verbose=
case "$1" in
--help) usage ;;
-v) verbose=-v ; shift
esac

rmtmp() {
  exitstatus=$? ; rm -f $tmp ; exit $exitstatus
}

tmp=,unbunch-tmp-$$
trap '
    trap - EXIT ERR
    echo 1>&2 "[$commandName killed]"
    rmtmp
' 1 2 3 4 5 6 7 8 10 11 12 13 14 15

if which gawk 2>&1 > /dev/null ; then
  gawk=gawk
elif awk --version | head -1 | grep -q GNU ; then
  gawk=awk
elif [[ -x /opt/local/bin/gawk ]] ; then
  gawk=/opt/local/bin/gawk
fi 

doit() {
  # Only gawk has the gensub function.
  $gawk '
    BEGIN {
      verbose   = "'$verbose'"
      tmpOutput = "'$tmp'"
      encounteredFirstFileHeader = 0
    }
    
    /^#!\/.*unbunch.*/ {
      if (NR == 1) next
    }
    
    /^========/ {
      encounteredFirstFileHeader = 1
      if (output != "") {
        # Replace file with tmp file contents, if different.
        close(output)
        system("replaceifnew " verbose " " filename " " output)
      }
      if ($0 ~ /======== /) {
        # Start collecting content into tmp file.
        sub("======== ", "")
        filename = $0
        if (filename ~ /\/$/) {
          system("mkdir -p " filename)
        } else {
          needNewline = 0
          output = tmpOutput
          printf("") > output
        }
      } else {
        encounteredFirstFileHeader = 0
      }
      next
    }
    
    {
      if (!encounteredFirstFileHeader) {
        # Before we encounter the first header or after the terminator line,
        #   * comment lines, starting with #, are not printed
        #   * other lines are printed to stdout
        if (!match($0, /^\s*#/))
          print $0
      } else {
        if (needNewline) {
          print "" >> output
        } else {
          needNewline = 1
        }
        line = gensub(/^(\\*)\\========( .*|)$/,"\\1========\\2", "1", $0)
        printf("%s", line) >> output
      }
      next
    }
  '
}

case "$1" in
'') doit
    ;;
*)  for x ; do
      doit < $x
    done
    ;;
esac

rmtmp
