#!/bin/bash
# equivalent of install
# Copyright (C) 2019 FARGOS Development, LLC
# $Id$
# PORTABILITY NOTE: this uses arrays to preserve the structure of each
# command line token.
# Since bash was chosen as the implementation target, native arithmetic
# expressions are used.

declare -a fileList # this will be an array

fileCount=0

dontCopyIfSame=0
doMakeDir=0
doChangeGroup=""
doChangeOwner=""
doSafeCopy=0
copySuffix=""
preserveModTimeFlag=0
verbose=0
lastArgNotDir=0
targetIsDir=1
targetName=""
doForce=0

dryRunPrefix=""

while test $# -gt 0
do
	case "${1}" in
	-h | -help | --help) 
		printf "usage: %s [-v] [-C] [-D] [-g group] [-o owner] [-p] [-S] file [...] directory\n" "${0}" >&2
		printf "   OR: %s -T [-v] [-C] [-D] [-g group] [-o owner] [-p] [-S] file1 file2\n" "${0}" >&2
		printf "   OR: %s -d [-v] [-g group] [-o owner] newDir [newDir ...]\n" "${0}" >&2
		printf "  -v = verbose\n" >&2
		printf "  -C = copy only if needed\n" >&2
		printf "  -S = safe copy - copy to intermediate\n" >&2
		printf "  -D = create directories if needed\n" >&2
		printf "  -p = preserve timestamps\n" >&2
		printf "  -T = target is file, not directory\n" >&2
		printf "  -d = treat all as directory names to be created\n" >&2
		exit 1
		;;
	--dryrun)
		dryRunPrefix="echo"
		;;
	--force)
		doForce=1
		;;
	-C)
		dontCopyIfSame=1
		;;
	-d)
		lastArgNotDir=2 # add to file list, but it is a directory
		doMakeDir=1
		;;
	-D)
		doMakeDir=$(( doMakeDir + 2 ))
		;;
	-g)
		doChangeGroup="${2}"
		shift
		;;
	-o)
		doChangeOwner="${2}"
		shift
		;;
	-p)
		preserveModTimeFlag=1
		;;
	-S)
		doSafeCopy=1
		copySuffix=".cpy"
		;;
	-t) # specify target
		if test -n "${targetName}"
		then
			printf "%s: target already specified!" "${0}" >&2
			exit 1
		fi
		targetName="${2}"
		lastArgNotDir=1
		shift
		;;
	-T)
		targetIsDir=0 # claim it is a file
		;;
	-v)
		verbose=1
		;;

	-*)
		printf "%s: unrecognized option \"%s\"\n" "${0}" "${1}" >&2
		exit 1
		;;
	*)
		# If last argument, save as target name if not all directories
		# or target not already specified
		# All directories selected by -d option
		if test $# -eq 1 -a ${lastArgNotDir} -eq 0
		then
			targetName="${1}"
		else
			fileCount=$(( ${fileCount} + 1 ))
			fileList[${fileCount}]="${1}"
		fi
		;;
	esac
	shift
done

if test ${targetIsDir} -eq 0 -a ${fileCount} -gt 1
then
	printf "%s: -T used to indicate %s is a file, but %d sources specified\n" "${0}" "${targetName:-target}" "${fileCount}" >&2
	exit 1
fi

if test ${doMakeDir} -ge 2
then # create path to target
	# if more than 1 file specified or the -D option, create path to
	# destination directory.
	if test ${targetIsDir} -eq 0
	then
		d=`dirname "${targetName}"`
	else
		d="${targetName}"
	fi
	if test ! -d "${d}"
	then
		if test ${verbose} -gt 0
		then
			echo mkdir -p "${d}"
		fi
		${dryRunPrefix} mkdir -p "${d}"
		if test ${doForce} -eq 0 -a ! -d "${d}"
		then
			printf "%s: could not create directory %s\n" "${0}" "${d}" >&2
			exit 1
		fi
		if test -n "${doChangeOwner}"
		then
			if test ${verbose} -gt 0
			then
				echo chown ${doChangeOwner} "${d}"
			fi
			${dryRunPrefix} chown ${doChangeOwner} "${d}"
		fi
		if test -n "${doChangeGroup}"
		then
			if test ${verbose} -gt 0
			then
				echo chgrp ${doChangeGroup} "${d}"
			fi
			${dryRunPrefix} chgrp ${doChangeGroup} "${d}"
		fi
	fi
fi

n=1
while test ${n} -le ${fileCount}
do
	src="${fileList[${n}]}"
	if test ${doMakeDir} -eq 1
	then # treat all as directories
		if test ! -d "${src}"
		then
			if test ${verbose} -gt 0
			then
				echo mkdir -p "${src}"
			fi
			${dryRunPrefix} mkdir -p "${src}"
			if test ! -d "${src}"
			then
				printf "%s: could not create directory %s\n" "${0}" "${src}" >&2
				if test ${doForce} -eq 0
				then
					exit 1
				fi
			fi
		fi
		destTarget="${src}"
		mustDoCopy=2
	else # do copy of a file to targetName
		if test ! -r "${src}"
		then
			printf "%s: cannot access %s\n" "${0}" "${src}" >&2
			if test ${doForce} -eq 0
			then
				exit 1
			fi
		fi
		srcBase=`basename "${src}"`
		if test ${targetIsDir} -eq 0
		then
			destTarget="${targetName}"
		else
			destTarget="${targetName}/${srcBase}"
		fi
		mustDoCopy=1 # assume copy must be done
		l1="x" # clear, don't want to redo if not needed
		c1="x"
		if test ${dontCopyIfSame} -ne 0 -a -r "${destTarget}"
		then
			l1=`ls -l "${src}" | awk '{ print $5; }'`
			l2=`ls -l "${destTarget}" | awk '{ print $5; }'`
			if test "${l1}" = "${l2}"
			then
				c1=`cksum "${src}" | awk '{ print $1; }'`
				c2=`cksum "${destTarget}" | awk '{ print $1; }'`
				if test "${c1}" = "${c2}"
				then
					mustDoCopy=0
					if test ${verbose} -ne 0
					then
						printf "%s: Not copying %s as content is identical to %s\n" "${0}" "${src}" "${destTarget}"
					fi
				fi
			fi
		fi
		if test ${mustDoCopy} -eq 1
		then
			if test ${verbose} -gt 0
			then
				echo cp ${src} ${destTarget}${copySuffix}
			fi
			${dryRunPrefix} cp -f "${src}" "${destTarget}${copySuffix}"
			if test ${preserveModTimeFlag} -eq 1
			then
				if test ${verbose} -gt 0
				then
					echo touch -c -r "${src}" "${destTarget}${copySuffix}"
				fi
				${dryRunPrefix} touch -c -r "${src}" "${destTarget}${copySuffix}"
			fi
			if test -n "${copySuffix}"
			then # safe copy mode in use, verify
				if test "${l1}" = "x"
				then # not yet determined
					l1=`ls -l "${src}" | awk '{ print $5; }'`
				fi
				l3=`ls -l "${destTarget}${copySuffix}" | awk '{ print $5; }'`
				if test "${l1}" != "${l3}"
				then
					printf "%s: copy failed of %s sourceLen=%s dest %s destLen=%s\n" "${0}" "${src}" "${l1}" "${destTarget}${copySuffix}" "${l3:-NONE}" >&2
					if test ${doForce} -eq 0
					then
						exit 1
					fi
				fi
				if test "${c1}" = "x"
				then
					c1=`cksum "${src}" | awk '{ print $1; }'`
				fi
				c3=`cksum "${destTarget}${copySuffix}" | awk '{ print $1; }'`
				if test "${c1}" != "${c3}"
				then
					printf "%s: copy failed of %s to %s as content did not match\n" "${0}" "${src}" "${destTarget}${copySuffix}" >&2
					if test ${doForce} -eq 0
					then
						exit 1
					fi
				fi
			fi
		fi
	fi
	if test ${mustDoCopy} -eq 1
	then
		if test -n "${doChangeOwner}"
		then
			if test ${verbose} -gt 0
			then
				echo chown ${doChangeOwner} "${destTarget}${copySuffix}"
			fi
			${dryRunPrefix} chown ${doChangeOwner} "${destTarget}${copySuffix}"
		fi
		if test -n "${doChangeGroup}"
		then
			if test ${verbose} -gt 0
			then
				echo chgrp ${doChangeGroup} "${destTarget}${copySuffix}"
			fi
			${dryRunPrefix} chgrp ${doChangeGroup} "${destTarget}${copySuffix}"
		fi
	fi
	# if copied and using copySuffix, rename to final result
	if test ${mustDoCopy} -eq 1 -a -n "${copySuffix}"
	then
		if test ${verbose} -gt 0
		then
			echo mv ${destTarget}${copySuffix} ${destTarget}
		fi
		${dryRunPrefix} mv -f "${destTarget}${copySuffix}" "${destTarget}"
	fi

	n=$(( n + 1 ))
done
exit 0
