#!/bin/zsh
# there is no posix stat(1) and the implementations are riddled with locale-speciffic stuff
# better use sane version from zsh

setopt extendedglob globdots
zmodload zsh/stat

typeset -A ftypes hardlinks s
ftypes=(  # convert hex type to mnemonic character
	C  s  # socket
	c  s
	A  l  # symbolic link
	a  l
	8  f  # regular file
	6  b  # block device
	4  d  # directory
	2  u  # character device
	1  p  # FIFO
)

delim=''

statement() {
	# start on new line for multiline statements - more readable
	if [[ -n delim && $1 == *$'\n'* ]]; then
		delim=$'\n'
	fi
	printf '%s%s' $delim ${1//$'\n'/$'\n\t'}
	delim=${2:-$'\t'}
}

statement_end() {
	printf '\n'
	delim=''
}

ROOT=${${${ROOT:-$PWD}:A}%/}
: ${compact:=1}
: ${print_m:=1}
: ${print_o:=1}
: ${print_c:=1}
if (($+commands[file])) && (($+commands[base64])); then
	: ${print_b:=1}
else
	: ${print_b:=0}
	if (($+commands[file])) && (($+commands[xxd])); then
		: ${print_x:=1}
	fi
fi
: ${print_x:=0}
: ${max_bin_size:=}

fnames=( )
for arg in "${@:-$ROOT}"; do
	fnames+=( $arg:a )
	[[ -d $arg ]] && fnames+=( $arg:a/**/* )
done

for fname in $fnames; do
	if ! [[ $fname == $ROOT || $fname == $ROOT/* ]]; then
		printf "skipping out-of-root file: %s\n" "$fname" >&2
		continue
	fi
	relname=${${fname#$ROOT}#/}
	zstat -LH s $fname || continue
	ftype=$(( [##16] $s[mode] >> 12 ))
	fmode=$(( [##8] $s[mode] & 8#7777 ))
	t=$ftypes[$ftype]

	(($compact)) || printf '\n'

	if [[ $relname == *$'\t'* || $relname == *$'\n'* ]]; then
		statement $'P\t'$relname $'\t'
	else
		if (($compact)); then
			statement /$relname
		else
			statement /$relname $'\n'
		fi
	fi

	if [[ $t != d && $s[nlink] -gt 1 ]]; then
		id=$s[device]:$s[inode]
		if (($+hardlinks[$id])); then
			statement $'H\t'$hardlinks[$id] $'\n'
			continue
		else
			hardlinks[$id]=./$relname
		fi
	fi

	if [[ $t == [bu] ]]; then
		statement $t$(( $s[rdev] >> 8 )):$(( $s[rdev] & 255 ))
	elif [[ $t == l ]]; then
		statement $'l\t'$s[link] $'\t'
	elif [[ $t == f ]]; then
		if (($print_c)); then
			if (($s[size])) && (($print_b + $print_x)) && \
					[[ $(file -bi $fname) != text/* ]]; then
				if [[ -n $max_bin_size && $s[size] -gt $max_bin_size ]]; then
					statement s$'\tSHA512:'${"$(sha512sum < $fname)"%% *}
				elif (($print_x)); then
					statement X$'\t'"$(xxd $fname)" $'\n'
				else
					statement B$'\t'"$(base64 <$fname)" $'\n'
				fi
			else
				IFS= read -r -d '' content <$fname
				flags=''
				if [[ $content == *$'\n' ]]; then
					content=${content%$'\n'}
					if [[ $content == *$'\n' ]]; then
						# force appending newline
						flags+=n
					fi
				else
					flags+=N
				fi
				if ! (($compact)) || [[ $content == *$'\t'* || $content == *$'\n'* ]]; then
					statement C$flags$'\t'$content $'\n'
				else
					statement c$flags$'\t'$content
				fi
			fi
		else
			statement f
		fi
	else
		statement $t
	fi
	(($print_o)) && statement o$s[uid]:$s[gid]
	(($print_m)) && statement m$fmode
	statement_end
done

# while getopts omcaOMC o
# do	case "$o" in
# 	([?])
# 		print >&2 "Usage: $(basename "$0") [-omcaOMC] [dir [...]]"
# 		exit 1;;
# 	esac
# done

# find "${@:-$PWD}" -exec stat -c '%F	%U:%G	%a	%h:%i:%d	%t:%T	%n' '{}' + | awk '
# BEGIN {
# 	FS="\t"
# }

# /\t/
# '