forked from gnustep/tools-make
-
Notifications
You must be signed in to change notification settings - Fork 1
/
relative_path.sh
executable file
·225 lines (200 loc) · 6.81 KB
/
relative_path.sh
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#!/bin/sh
# relative_path.sh
#
# Copyright (C) 2001 - 2007 Free Software Foundation, Inc.
#
# Author: Nicola Pero <[email protected]>
# Date: April 2001, January 2007
#
# This file is part of the GNUstep Makefile Package.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# You should have received a copy of the GNU General Public
# License along with this library; see the file COPYING.
# If not, write to the Free Software Foundation,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# This script gets two paths as argument - and outputs a relative path
# which, when appended to the first one, gives the second one ... more
# precisely, the path of minimum length with this property.
#
# A third optional parameter controls the type of output; if it's set
# to 'strict' it outputs "strict" relative paths that always start
# with the exact sequence of characters './'. If set to 'short' it
# outputs "short" relative paths that might start with './' or with
# '../'. Here are examples:
#
# strict: ./
# short: ./
#
# strict: ./../System
# short: ../System
#
# strict: ./System
# short: ./System
#
# Inside shell scripts (eg, in framework.make) we use the 'short' mode
# because it prevents ugly unnecessary path fragments to get into all
# paths. Inside the configuration system we traditionally use the
# 'strict' mode because NSPathUtilities detects relative paths by
# checking that they start with './'. The 'short' mode might
# become the one used for the configuration system in the future if
# NSPathUtilities learns to detect that '../' also starts a relative
# path.
#
# If no this parameter is provided, 'strict' is assumed for backwards
# compatibility (even if gnustep-make v1 used to default to 'short').
# This might change in the future, so if you are depending on a
# specific behaviour, it's important that you specify the type of
# output you want.
#
# <NB: the paths must be absolute.>
#
# for example,
#
# $GNUSTEP_MAKEFILES/print_relative_path.sh /usr/GNUstep/Local /usr/GNUstep/System short
#
# returns ../System (and not ../../GNUstep/System which is not the minimum).
#
# This is needed by `ln -s' to properly create symlinks between
# directories which are related ... but we don't know how. We only
# need this for frameworks, which are particularly complex and
# delicate. For example, to create the link
#
# /usr/GNUstep/System/Library/Libraries/ix86/linux-gnu/gnu-gnu-gnu/libnicola.so
# --> ../../../../Frameworks/nicola.framework/Versions/Current/ix86/linux-gnu/gnu-gnu-gnu/libnicola.so
#
# (and where the paths are actually computed by make variables which
# might depend on variables in user makefiles outside our control, so
# it's not obvious what the relationship is between the two paths, and
# you only have the absolute paths) we do -
#
# cd /usr/GNUstep/System/Library/Libraries/ix86/linux-gnu/gnu-gnu-gnu/
# $(LN_S) `$(RELATIVE_PATH_SCRIPT) /usr/GNUstep/System/Frameworks/nicola.framework/Versions/Current/ix86/linux-gnu/gnu-gnu-gnu/libnicola.so /usr/GNUstep/System/Library/Libraries/ix86/linux-gnu/gnu-gnu-gnu/ short` libnicola.so
#
# which creates the link. We need to use the minimum path because
# that is the most relocatable possible path. I consider all this a
# trick and a hack and recommend to use libraries and bundles instead
# of frameworks, since libraries and bundles are much more portable
# and stable, anyway here we are.
#
# This script is also used to create relative paths in the
# configuration system for cases where the location of things is
# relative to the location of something (eg, base library).
# Unfortunately in that case because of limitations in gnustep-base's
# NSPathUtilities, we have to always output a './' at the beginning of
# the result so that gnustep-base recognizes the result as a relative
# path. This means we use the 'strict' output in that case.
# mode=strict means we always need to start our output with './'.
# mode=short means we always start our output with '../' or './'.
mode=strict
if [ "$#" != 2 ]; then
if [ "$#" != 3 ]; then
exit 1
else
mode="$3"
fi
fi
a="$1";
b="$2";
if [ "$a" = "" ]; then
exit 1
fi
if [ "$b" = "" ]; then
exit 1
fi
#
# Our first argument is a path like /xxx/yyy/zzz/ccc/ttt
# Our second argument is a path like /xxx/yyy/kkk/nnn/ppp
#
# Step zero is normalizing the paths by removing any /./ component
# inside the given paths (these components can occur for example when
# enable-flattened is used).
tmp_IFS="$IFS"
IFS=/
# Normalize a by removing any '.' path component.
normalized_a=""
for component in $a; do
if [ -n "$component" ]; then
if [ "$component" != "." ]; then
normalized_a="$normalized_a/$component"
fi
fi
done
a="$normalized_a"
# Normalize b by removing any '.' path component.
normalized_b=""
for component in $b; do
if [ -n "$component" ]; then
if [ "$component" != "." ]; then
normalized_b="$normalized_b/$component"
fi
fi
done
b="$normalized_b"
IFS="$tmp_IFS"
# Step one: we first want to remove the common root -- we want to get
# into having /zzz/ccc/tt and /kkk/nnn/ppp.
# We first try to match as much as possible between the first and the second
# So we loop on the fields in the second. The common root must not contain
# empty path components (/./) for this to work, but we have already filtered
# those out at step zero.
tmp_IFS="$IFS"
IFS=/
partial_b=""
partial_match=""
for component in $b; do
if [ -n "$component" ]; then
partial_b="$partial_b/$component"
case "$a" in
"$partial_b"*) partial_match="$partial_b";;
*) break;;
esac
fi
done
IFS="$tmp_IFS"
if [ "$partial_match" != "" ]; then
# Now partial_match is the substring which matches (/xxx/yyy/) in the
# example. Remove it from both a and b.
a=`echo $a | sed -e "s#$partial_match##"`
b=`echo $b | sed -e "s#$partial_match##"`
fi
# Ok - now ready to build the result
result="."
# Special note - if a is now empty, the second directory was a
# subdirectory of the first; we will end up outputting ./$b
# Now add as many ../ as there are components in a
tmp_IFS="$IFS"
IFS=/
for component in $a; do
if [ -n "$component" -a "$component" != "." ]; then
if [ "$mode" = "strict" ]; then
# In strict mode, ./../../xxx is required
result="$result/.."
else
# In short mode, it's not, we prefer ../../xxx
if [ "$result" = "." ]; then
result=".."
else
result="$result/.."
fi
fi
fi
done
IFS="$tmp_IFS"
# Then, append b
if [ -n "$result" ]; then
result="$result$b"
else
result="$b"
fi
if [ "$mode" = "strict" ]; then
# Make sure the result always starts with './' in strict mode
if [ "$result" = "." ]; then
result="./"
fi
fi
echo "$result"