#!/bin/sh
unalias -a
export fname
die() {
	printf '%s\n' "$*"
	exit 1
}

flags() {
	case "$1" in (*'!'*) f_bang=true;; (*) f_bang=false;; esac
	case "$1" in (*p*) f_p=true;; (*) f_p=false;; esac
	case "$1" in (*f*) f_f=true;; (*) f_f=false;; esac
	case "$1" in (*r*) f_r=true;; (*) f_r=false;; esac
	case "$1" in (*n*) f_n=true;; (*) f_n=false;; esac
	case "$1" in (*N*) f_N=true;; (*) f_N=false;; esac
	case "$1" in (*a*) f_a=true;; (*) f_a=false;; esac
	case "$1" in (*i*) f_i=true;; (*) f_i=false;; esac
	case "$1" in (*o*) f_o=true;; (*) f_o=false;; esac
}


print_flags() {
	$f_bang && printf '!'
	$f_p && printf p
	$f_f && printf f
	$f_r && printf r
	$f_n && printf n
	$f_N && printf N
	$f_a && printf a
	$f_i && printf i
	$f_o && printf o
}

# TODO: search $PATH
if ! test -x /bin/readlink -o -x /usr/bin/readlink; then
	# Hackity hack. If you know of better way, let me know.
	if test -x /bin/rsync -o -x /usr/bin/rsync; then
		readlink() {
			rsync -l8 --list-only "$1" | sed 's|^.* ->||'
		}
	else
		readlink() {
			ls -ld "$1" | sed 's|^.* ->||'
		}
	fi
fi

: ${check_only:=false}

req() {
	if ! "check_$@"; then
		if $check_only; then
			die "check failed on '$fname': $* ($(print_flags))"
		else
			"do_$@" || die "action failed on '$fname': $* ($(print_flags))"
			check_only=true
			req "$@"
			check_only=false
		fi
	fi
}


check_p() {
	test -d "$(dirname "$fname")"
}

do_p() {
	mkdir -p "$(dirname "$fname")" || exit $?
}


check_type_or_missing() {
	test '!' -e "$fname" -o "-$1" "$fname"
}

do_type_or_missing() {
	if $f_r; then
		if $f_f; then
			rm -rf "$fname" || exit $?
		else
			rm -r "$fname" || exit $?
		fi
	elif test -d "$fname"; then
		rmdir "$fname"
	else
		if $f_f; then
			rm -f "$fname" || exit $?
		else
			rm "$fname" || exit $?
		fi
	fi
}


do_l() {
	if test -L "$fname"; then
		rm "$fname"
	elif test -e "$fname"; then
		die "already present but not a symbolic link: $fname"
	fi
	ln -s "$1" "$fname" || exit $?
}

check_l() {
	if $f_p; then
		req p
	fi
	if $f_bang; then
		req type_or_missing L
	fi
	test -L "$fname" && test x"$(readlink "$fname")" = x"$1"
}

l() {
	req l "$@"
}


check_r() {
	! test -e "$fname" -o -L "$fname"
}

do_r() {
	do_type_or_missing
}

r() {
	req r "$@"
}


check_m() {
	test -e "$fname" -o -L "$fname" && \
		test 0 -lt $(find "$fname" -prune -perm "$1" | wc -l)
}

do_m() {
	chmod "$1" "$fname"
}

m() {
	req m "$@"
}


check_o() {
	test -e "$fname" -o -L "$fname" || return 1
	case "$1" in
		(*:*) test 0 -lt $( \
				find "$fname" -prune -user "${1%:*}" -group "${1#*:}" | wc -l \
				)
			return $?;;
		(*) test 0 -lt $(find "$fname" -prune -user "$1" | wc -l)
			return $?;;
	esac
}

do_o() {
	chown "$1" "$fname"
}

o() {
	req o "$@"
}


check_f() {
	if test -f "$fname"; then
		return 0
	fi
	if $f_p; then
		req p
	fi
	if $f_bang; then
		req type_or_missing f
	elif test -e "$fname" -o -L "$fname"; then
		die "already present but not a file: $fname"
	fi
	return 1
}

do_f() {
	touch "$fname"
}

f() {
	req f "$@"
}


check_d() {
	if test -d "$fname"; then
		return 0
	fi
	if $f_bang; then
		req type_or_missing d
	elif test -e "$fname" -o -L "$fname"; then
		die "already present but not a directory: $fname"
	fi
	return 1
}

do_d() {
	if $f_p; then
		mkdir -p "$fname"
	else
		mkdir "$fname"
	fi
}

d() {
	req d "$@"
}


check_c() {
	req f
	"$@" | cmp -s - "$fname"
}

do_c() {
	"$@" > "$fname"
}

c() {
	req c "$@"
}