#!/bin/sh
### rmdups.sh  -*- Sh -*-
## Replace copies of files with hardlinks, symlinks, or remove them.

### Ivan Shmakov, 2005, 2015, 2017, 2018, 2020

## To the extent possible under law, the author(s) have dedicated
## all copyright and related and neighboring rights to this software
## to the public domain worldwide.  This software is distributed
## without any warranty.

## You should have received a copy of the CC0 Public Domain Dedication
## along with this software.  If not, see
## <http://creativecommons.org/publicdomain/zero/1.0/>.

### History:

## 0.6  2020-04-05 17:35Z
##      New -U (drop older) option.
##
## 0.5  2020-02-14 20:17:28Z
##      (sfn.gEY_lCQqY-J2Waha6l9zWnSD0tz02MPLzOpiR_4P0oI.sh)
##      Fixed: remove a duplicate when one is newer and -u is given
##      (was: when one is older.)
##
## 0.4  2018-11-21 17:05:28Z
##      (sfn.aYulqJqbEZW90KTiKxqD4K2QzP_Er3r0wKk_TgvFLTA.sh)
##      New -u (drop newer), -s (symbolic link) and -X (expunge) options.
##      New REALPATH and RM environment variables.  Use set -e.
##
## 0.3  2017-12-26 17:45:26Z
##      (sfn.tsX0rpNEsDcVxp8doYMzrPOi2awFOZ9TLnbbiib84cA.sh)
##      Get defaults for CMP and LN from the environment, and skip
##      setting IFS at all (relying on either the environment or the
##      Shell default.)  Use -- POSIX option terminator for CMP, LN.
##      Do not use (non-POSIX) -v to LN (invoke with env LN=ln\ -v
##      if the old behavior is desired.)  Use /bin/sh (was: /bin/bash.)
##
## 0.2  2015-03-06 07:56:16Z
##      (sfn.sK3eXAi75zESPpjW8ZTDlDkzNMwUgbzjHZ7hRjWuHNU.sh)
##      Skip a copy if already linked to the original file.
##
## 0.1  2005-05-31 09:51:37Z
##      (sfn.gNp5rXl4sEFAPAhzpxKJyCeEpVFp8Bg-QgYtxCV8rNU.sh)
##      Initial revision.

### Code:

set -e

: "${CMP:=cmp}"
: "${LN:=ln}"
: "${REALPATH:=realpath}"
: "${RM:=rm}"

progname=${0##*/}
if [ ${#} -gt 2 ] ; then
    printf %s\\n "Usage: ${progname} [-u] [-s|-X]" >&2
    ## .
    exit 1
fi

do_rm () {
    ## NB: remove the original from the list
    shift
    ## .
    ${RM} -- "$1"
}

do_symlink () {
    case "$2" in
        (*/*)   sym_dir=${2%/*} ;;
        (*)     sym_dir=. ;;
    esac
    sym_target=$(${REALPATH} --relative-to="$sym_dir" -- "$1")
    ## .
    ${LN} -sf -- "$sym_target" "$2"
}

drop_newer_p=
drop_older_p=
action=false
for arg ; do
    case "$arg" in
        ("")    action="${LN} -f" ;;
        (-s)    action=do_symlink ;;
        (-X)    action=do_rm ;;
        (-U)    drop_older_p=yes ;;
        (-u)    drop_newer_p=yes ;;
        (*) printf %s\\n "Usage: ${progname} [-u] [-s|-X]" >&2
            ## .
            exit 1 ;;
    esac
done

while read -r -- fn rest; do
    if ! [ -f "$fn" ]; then
	echo "$fn: is not a regular file; ignored"
	continue
    fi
    for dup in $rest; do
	if ! [ -f "$dup" ]; then
	    echo "$dup: is not a regular file; ignored"
	elif [ "$fn" -ef "$dup" ]; then
	    echo "$dup: \`$fn' is the same file already; ignored"
	elif test -z "$drop_newer_p" && [ "$fn" -ot "$dup" ]; then
	    echo "$dup: \`$fn' is older"
	elif test -z "$drop_older_p" && [ "$fn" -nt "$dup" ]; then
	    echo "$dup: \`$fn' is newer"
	elif ! ${CMP} -s -- "$fn" "$dup"; then
	    echo "$dup: content differs with \`$fn'"
	else
	    ${action} "$fn" "$dup"
	fi
    done
done

### Emacs trailer
## Local variables:
## coding: us-ascii
## fill-column: 72
## indent-tabs-mode: nil
## ispell-local-dictionary: "american"
## End:
### rmdups.sh ends here
