summaryrefslogtreecommitdiff
path: root/contrib/relpath.sh
blob: 1b329fc04a78e9c273d0c29bbe194c745a703c7f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#!/bin/sh

if [ "$1" = "--help" -o $# -ne 2 -o -f "$1" ]; then
    echo Usage: relpath.sh FROM TO
    echo Print the relative path from FROM to TO
    echo FROM must be a directory, but need not exist
    exit 0
fi

from="${1%%/}"
to="${2%%/}"

# The parent directory of a pathname, handling ..
parent() {
    name=$(basename "$1")
    path=$(dirname "$1")
    top=$(basename "$path")
    if [ "$top" = ".." ]; then
	path=$(parent "$path")
    fi
    if [ "$name" = ".." ]; then
	path=$(parent "$path")
    fi
    echo $path
}

# Canonicalize a directory that contains '..'.
canonicalize() {
    path=$1
    suffix=
    while ! [ -d "$path" ]; do
	name=$(basename "$path")
	path=$(parent "$path")
	suffix="/$name$suffix"
    done
    if [ -d "$path" ]; then
	echo $(cd "$path"; pwd)$suffix
    else
	echo $1
    fi
}

case "$to$from" in
    *..* )
	from=$(canonicalize "$from")
	to=$(canonicalize "$to")
	;;
esac
case "$to$from" in
    *..* )
	echo unable to canonicalize .. >&2
	exit 1
	;;
esac

back=
while [ "${to#$from}" = "$to" ]; do
    #echo $from too long
    from=$(dirname $from);
    back=../$back

    if [ "$from" = / ] && [ "${to#/}" = "$to" ]; then
	echo no common ancestor between $1 and $2 >&2
	exit 1
    elif [ "$from" = . ]; then
	echo no common ancestor between $1 and $2 >&2
	exit 1
    fi
done

to=${to#$from}
to=${to##/}
back=${back%%/}

if [ -n "$to" ] && [ -n "$back" ]; then
    echo $back/$to
elif [ -n "$back$to" ]; then
    echo $back$to
else
    echo .
fi