#!/bin/sh

# Optional addons (I didn't require them to be present, but it helped):
# - permissions, ownership

verbose=0
gzip=0


filter_in() {
  if [ "$gzip" != "0" ]; then
    gzip
  else
    cat
  fi
}

filter_out() {
  if [ "$gzip" != "0" ]; then
    gunzip
  else
    cat
  fi
}


append() {
  # Trivial :-)
  [ "$verbose" != "0" ] && echo "$1" >&2
  uuencode "$1" <"$1"
}

create() {
  tarfile="$1"; shift
  for filename; do
    if [ -d "$filename" ]; then
      # A directory, add all _files_ inside
      find "$filename" -type f | while read subfilename; do
        append "$subfilename"
      done
    elif [ -f "$filename" ]; then
      append "$filename"
    else
      echo "Only regular files and directories supported, skipping '$filename'" >&2
    fi
  done | filter_in >"$tarfile"
}


extract() {
  tarfile="$1"; shift
  # We assume non-broken archive
  rm -f /tmp/$$.uudecoding
  >/tmp/$$.uudecoding

  filter_out <"$tarfile" | while read -r line; do
    if echo "$line" | grep -q "^begin"; then
      filename="$(echo "$line" | cut -d ' ' -f 3-)"
      [ "$verbose" != "0" ] && echo "$filename" >&2
      # Reset the file
      echo "$line" >/tmp/$$.uudecoding
      continue

    elif [ "$line" = "end" ]; then
      echo "end" >>/tmp/$$.uudecoding
      # Create leading directories
      # dirname is not on slides... :/
      dirname="$(echo "$filename" | sed 's#/[^/]*##')"
      if [ "$dirname" != "$filename" ]; then
        mkdir -p "$dirname"
      fi
      uudecode </tmp/$$.uudecoding

    else
      # inside of the uuencoded file...
      echo "$line" >>/tmp/$$.uudecoding
    fi
  done
  rm /tmp/$$.uudecoding
}


list() {
  tarfile="$1"; shift
  filter_out <"$tarfile" | while read begin foo filename; do
    if [ "$begin" != "begin" ]; then
      continue
    fi
    echo "$filename"
  done
}



while [ "$1" ]; do
  switch="$1"
  shift
  case $switch in
    -v) verbose=1;;
    -z) gzip=1;;
    -c) if [ $# -lt 2 ]; then echo "Invalid number of arguments" >&2; exit 1; fi
        create "$@"; exit 0;;
    -x) if [ $# -ne 1 ]; then echo "Invalid number of arguments" >&2; exit 1; fi
        extract "$@"; exit 0;;
    -t) if [ $# -ne 1 ]; then echo "Invalid number of arguments" >&2; exit 1; fi
        list "$@"; exit 0;;
    *) echo "Usage: tar [-v] [-z] {-c tarfile files... | -x tarfile | -t tarfile}" >&2
        exit 0;;
  esac
done
