Macro: relpaths

Back to the Main Page. | # relpaths | Download the M4 Source.

Synopsis

  `adl_COMPUTE_RELATIVE_PATHS(PATH_LIST)`

Version

  1.1 (2001/07/26) adl @ ac-archive-0.5.39

Author

  Alexandre Duret-Lutz <duret_g@epita.fr>

Description

  PATH_LIST is a space-separated list of colon-separated triplets of the form 'FROM:TO:RESULT'. This function iterates over these triplets and set $RESULT to the relative path from $FROM to $TO. Note that $FROM and $TO needs to be absolute filenames for this macro to success.

  For instance,

  `first=/usr/local/bin`
  `second=/usr/local/share`
  `adl_COMPUTE_RELATIVE_PATHS([first:second:fs second:first:sf])`
  `# $fs is set to ../share`
  `# $sf is set to ../bin`

  $FROM and $TO are both eval'ed recursively and normalized, this means that you can call this macro with autoconf's dirnames like `prefix' or `datadir'. For example:

  `adl_COMPUTE_RELATIVE_PATHS([bindir:datadir:bin_to_data])`

  adl_COMPUTE_RELATIVE_PATHS should also works with DOS filenames.

  You may want to use this macro in order to make your package relocatable. Instead of hardcoding $datadir into your programs just encode $bin_to_data and try to determine $bindir at run-time.

  This macro requires adl_NORMALIZE_PATH.

M4 Source Code

      AC_DEFUN([adl_COMPUTE_RELATIVE_PATHS],
      [for _lcl_i in $1; do
        _lcl_from=\[$]`echo "[$]_lcl_i" | sed 's,:.*$,,'`
        _lcl_to=\[$]`echo "[$]_lcl_i" | sed 's,^[[^:]]*:,,' | sed 's,:[[^:]]*$,,'`
        _lcl_result_var=`echo "[$]_lcl_i" | sed 's,^.*:,,'`
        adl_RECURSIVE_EVAL([[$]_lcl_from], [_lcl_from])
        adl_RECURSIVE_EVAL([[$]_lcl_to], [_lcl_to])
        _lcl_notation="$_lcl_from$_lcl_to"
        adl_NORMALIZE_PATH([_lcl_from],['/'])
        adl_NORMALIZE_PATH([_lcl_to],['/'])
        adl_COMPUTE_RELATIVE_PATH([_lcl_from], [_lcl_to], [_lcl_result_tmp])
        adl_NORMALIZE_PATH([_lcl_result_tmp],["[$]_lcl_notation"])
        eval $_lcl_result_var='[$]_lcl_result_tmp'
      done])

      ## Note:
      ## *****
      ## The following helper macros are too fragile to be used out
      ## of adl_COMPUTE_RELATIVE_PATHS (mainly because they assume that
      ## paths are normalized), that's why I'm keeping them in the same file.
      ## Still, some of them maybe worth to reuse.

      dnl adl_COMPUTE_RELATIVE_PATH(FROM, TO, RESULT)
      dnl ===========================================
      dnl Compute the relative path to go from $FROM to $TO and set the value
      dnl of $RESULT to that value.  This function work on raw filenames
      dnl (for instead it will considerate /usr//local and /usr/local as
      dnl two distinct paths), you should really use adl_COMPUTE_REALTIVE_PATHS
      dnl instead to have the paths sanitized automatically.
      dnl
      dnl For instance:
      dnl    first_dir=/somewhere/on/my/disk/bin
      dnl    second_dir=/somewhere/on/another/disk/share
      dnl    adl_COMPUTE_RELATIVE_PATH(first_dir, second_dir, first_to_second)
      dnl will set $first_to_second to '../../../another/disk/share'.
      AC_DEFUN([adl_COMPUTE_RELATIVE_PATH],
      [adl_COMPUTE_COMMON_PATH([$1], [$2], [_lcl_common_prefix])
      adl_COMPUTE_BACK_PATH([$1], [_lcl_common_prefix], [_lcl_first_rel])
      adl_COMPUTE_SUFFIX_PATH([$2], [_lcl_common_prefix], [_lcl_second_suffix])
      $3="[$]_lcl_first_rel[$]_lcl_second_suffix"])

      dnl adl_COMPUTE_COMMON_PATH(LEFT, RIGHT, RESULT)
      dnl ============================================
      dnl Compute the common path to $LEFT and $RIGHT and set the result to $RESULT.
      dnl
      dnl For instance:
      dnl    first_path=/somewhere/on/my/disk/bin
      dnl    second_path=/somewhere/on/another/disk/share
      dnl    adl_COMPUTE_COMMON_PATH(first_path, second_path, common_path)
      dnl will set $common_path to '/somewhere/on'.
      AC_DEFUN([adl_COMPUTE_COMMON_PATH],
      [$3=''
      _lcl_second_prefix_match=''
      while test "[$]_lcl_second_prefix_match" != 0; do
        _lcl_first_prefix=`expr "x[$]$1" : "x\([$]$3/*[[^/]]*\)"`
        _lcl_second_prefix_match=`expr "x[$]$2" : "x[$]_lcl_first_prefix"`
        if test "[$]_lcl_second_prefix_match" != 0; then
          if test "[$]_lcl_first_prefix" != "[$]$3"; then
            $3="[$]_lcl_first_prefix"
          else
            _lcl_second_prefix_match=0
          fi
        fi
      done])

      dnl adl_COMPUTE_SUFFIX_PATH(PATH, SUBPATH, RESULT)
      dnl ==============================================
      dnl Substrack $SUBPATH from $PATH, and set the resulting suffix
      dnl (or the empty string if $SUBPATH is not a subpath of $PATH)
      dnl to $RESULT.
      dnl
      dnl For instace:
      dnl    first_path=/somewhere/on/my/disk/bin
      dnl    second_path=/somewhere/on
      dnl    adl_COMPUTE_SUFFIX_PATH(first_path, second_path, common_path)
      dnl will set $common_path to '/my/disk/bin'.
      AC_DEFUN([adl_COMPUTE_SUFFIX_PATH],
      [$3=`expr "x[$]$1" : "x[$]$2/*\(.*\)"`])

      dnl adl_COMPUTE_BACK_PATH(PATH, SUBPATH, RESULT)
      dnl ============================================
      dnl Compute the relative path to go from $PATH to $SUBPATH, knowing that
      dnl $SUBPATH is a subpath of $PATH (any other words, only repeated '../'
      dnl should be needed to move from $PATH to $SUBPATH) and set the value
      dnl of $RESULT to that value.  If $SUBPATH is not a subpath of PATH,
      dnl set $RESULT to the empty string.
      dnl
      dnl For instance:
      dnl    first_path=/somewhere/on/my/disk/bin
      dnl    second_path=/somewhere/on
      dnl    adl_COMPUTE_BACK_PATH(first_path, second_path, back_path)
      dnl will set $back_path to '../../../'.
      AC_DEFUN([adl_COMPUTE_BACK_PATH],
      [adl_COMPUTE_SUFFIX_PATH([$1], [$2], [_lcl_first_suffix])
      $3=''
      _lcl_tmp='xxx'
      while test "[$]_lcl_tmp" != ''; do
        _lcl_tmp=`expr "x[$]_lcl_first_suffix" : "x[[^/]]*/*\(.*\)"`
        if test "[$]_lcl_first_suffix" != ''; then
           _lcl_first_suffix="[$]_lcl_tmp"
           $3="../[$]$3"
        fi
      done])

      dnl adl_RECURSIVE_EVAL(VALUE, RESULT)
      dnl =================================
      dnl Interpolate the VALUE in loop until it doesn't change,
      dnl and set the result to $RESULT.
      dnl WARNING: It's easy to get an infinite loop with some unsane input.
      AC_DEFUN([adl_RECURSIVE_EVAL],
      [_lcl_receval="$1"
      $2=`(test "x$prefix" = xNONE && prefix="$ac_default_prefix"
           test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
           _lcl_receval_old=''
           while test "[$]_lcl_receval_old" != "[$]_lcl_receval"; do
             _lcl_receval_old="[$]_lcl_receval"
             eval _lcl_receval="\"[$]_lcl_receval\""
           done
           echo "[$]_lcl_receval")`])