path.sh
Go to the documentation of this file.
1 # ============================================================================
2 # Copyright (c) 2011-2012 University of Pennsylvania
3 # Copyright (c) 2013-2016 Andreas Schuh
4 # All rights reserved.
5 #
6 # See COPYING file for license information or visit
7 # https://cmake-basis.github.io/download.html#license
8 # ============================================================================
9 
10 ##############################################################################
11 # @file os/path.sh
12 # @brief Path manipulation functions.
13 ##############################################################################
14 
15 [ "${_BASIS_OS_PATH_INCLUDED}" == 'true' ] || {
16 _BASIS_OS_PATH_INCLUDED='true'
17 
18 
19 . "`cd -P -- \`dirname -- "${BASH_SOURCE}"\` && pwd`/../config.sh" || exit 1
20 
21 
22 ## @addtogroup BasisBashUtilities
23 # @{
24 
25 
26 # ----------------------------------------------------------------------------
27 ## @brief Clean path, i.e., remove occurences of "./", duplicate slashes,...
28 #
29 # This function removes single periods (.) enclosed by slashes or backslashes,
30 # duplicate slashes (/) or backslashes (\), and further tries to reduce the
31 # number of parent directory references.
32 #
33 # For example, "../bla//.//.\bla\\\\\bla/../.." is convert to "../bla".
34 #
35 # @param [in] path Path.
36 #
37 # @return Cleaned path.
38 normpath()
39 {
40  local _basis_cp_path="$1"
41  # GNU bash, version 3.00.15(1)-release (x86_64-redhat-linux-gnu)
42  # turns the array into a single string value if local is used
43  if [ ${BASH_VERSION_MAJOR} -gt 3 ] || [ ${BASH_VERSION_MAJOR} -eq 3 -a ${BASH_VERSION_MINOR} -gt 0 ]; then
44  local _basis_cp_dirs=()
45  else
46  _basis_cp_dirs=()
47  fi
48  # split path into parts, discarding redundant slashes
49  while [ -n "${_basis_cp_path}" ]; do
50  if [ ${#_basis_cp_dirs[@]} -eq 0 ]; then
51  _basis_cp_dirs=("`basename -- "${_basis_cp_path}"`")
52  else
53  _basis_cp_dirs=("`basename -- "${_basis_cp_path}"`" "${_basis_cp_dirs[@]}")
54  fi
55  _basis_cp_path="`dirname -- "${_basis_cp_path}"`"
56  if [ "${_basis_cp_path}" == '/' ]; then
57  _basis_cp_path=''
58  fi
59  done
60  # build up path again from the beginning,
61  # discarding dots ('.') and stepping one level up for each '..'
62  local _basis_cp_i=0
63  while [ ${_basis_cp_i} -lt ${#_basis_cp_dirs[@]} ]; do
64  if [ "${_basis_cp_dirs[${_basis_cp_i}]}" != '.' ]; then
65  if [ "${_basis_cp_dirs[${_basis_cp_i}]}" == '..' ]; then
66  _basis_cp_path=`dirname -- "${_basis_cp_path}"`
67  else
68  _basis_cp_path="${_basis_cp_path}/${_basis_cp_dirs[${_basis_cp_i}]}"
69  fi
70  fi
71  let _basis_cp_i++
72  done
73  # return
74  echo -n "${_basis_cp_path}"
75 }
76 
77 # ----------------------------------------------------------------------------
78 ## @brief Get absolute path given a relative path.
79 #
80 # This function converts a relative path to an absolute path. If the given
81 # path is already absolute, this path is passed through unchanged.
82 #
83 # @param [in] path Absolute or relative path.
84 #
85 # @return Absolute path.
86 abspath()
87 {
88  local _basis_tap_base="$1"
89  local _basis_tap_path="$2"
90  if [ "${_basis_tap_base:0:1}" != '/' ]; then
91  _basis_tap_base="`pwd`/${_basis_tap_base}"
92  fi
93  if [ "${_basis_tap_path:0:1}" != '/' ]; then
94  _basis_tap_path="${_basis_tap_base}/${_basis_tap_path}"
95  fi
96  normpath "${_basis_tap_path}"
97 }
98 
99 # ----------------------------------------------------------------------------
100 ## @brief Get canonical file path.
101 #
102 # This function resolves symbolic links and returns a cleaned path.
103 #
104 # @param [in] path Path.
105 #
106 # @return Canonical file path without duplicate slashes, ".", "..",
107 # and symbolic links.
108 realpath()
109 {
110  # make path absolute and resolve '..' references
111  local _basis_grp_path=`abspath "$1"`
112  if ! [ -e "${_basis_grp_path}" ]; then echo -n "${_basis_grp_path}"; return; fi
113  # if path itself is a symbolic link, follow it
114  local _basis_grp_i=0
115  local _basis_grp_cur="${_basis_grp_path}"
116  while [ -h "${_basis_grp_cur}" ] && [ ${_basis_grp_i} -lt 100 ]; do
117  _basis_grp_dir=`dirname -- "${_basis_grp_cur}"`
118  _basis_grp_cur=`readlink -- "${_basis_grp_cur}"`
119  _basis_grp_cur=`cd "${_basis_grp_dir}" && cd $(dirname -- "${_basis_grp_cur}") && pwd`/`basename -- "${_basis_grp_cur}"`
120  let _basis_grp_i++
121  done
122  # If symbolic link could entirely be resolved in less than 100 iterations,
123  # return the obtained canonical file path. Otherwise, return the original
124  # link which could not be resolved due to some probable cycle.
125  [ ${_basis_grp_i} -ge 100 ] || _basis_grp_path="${_basis_grp_cur}"
126  # resolve symbolic links within linked path
127  _basis_grp_path=`cd -P -- $(dirname -- "${_basis_grp_path}") && pwd -P`/`basename -- "${_basis_grp_path}"`
128  # return
129  echo -n "${_basis_grp_path}"
130 }
131 
132 
133 ## @}
134 # end of Doxygen group
135 
136 
137 } # _BASIS_PATH_INCLUDED
function normpath(in path)
Clean path, i.e., remove occurences of "./", duplicate slashes,...
function realpath(in path)
Get canonical file path.
def which(command, path=None, verbose=0, exts=None)
Definition: which.py:257
cmake BASH_VERSION_MAJOR
Definition: FindBASH.cmake:12
cmake BASH_VERSION_MINOR
Definition: FindBASH.cmake:37
std::string basename(const std::string &path)
Get file name.
Definition: path.cxx:273
function abspath(in path)
Get absolute path given a relative path.
std::string dirname(const std::string &path)
Get file directory.
Definition: path.cxx:265
std::string readlink(const std::string &path)
Read value of symbolic link.
Definition: os.cxx:147