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