path.c: refactor relative_path(), not only strip prefix

Original design of relative_path() is simple, just strip the prefix
(*base) from the absolute path (*abs).

In most cases, we need a real relative path, such as: ../foo,
../../bar.  That's why there is another reimplementation
(path_relative()) in quote.c.

Borrow some codes from path_relative() in quote.c to refactor
relative_path() in path.c, so that it could return real relative
path, and user can reuse this function without reimplementing
his/her own.  The function path_relative() in quote.c will be
substituted, and I would use the new relative_path() function when
implementing the interactive git-clean later.

Different results for relative_path() before and after this refactor:

    abs path  base path  relative (original)  relative (refactor)
    ========  =========  ===================  ===================
    /a/b      /a/b       .                    ./
    /a/b/     /a/b       .                    ./
    /a        /a/b/      /a                   ../
    /         /a/b/      /                    ../../
    /a/c      /a/b/      /a/c                 ../c
    /x/y      /a/b/      /x/y                 ../../x/y

    a/b/      a/b/       .                    ./
    a/b/      a/b        .                    ./
    a         a/b        a                    ../
    x/y       a/b/       x/y                  ../../x/y
    a/c       a/b        a/c                  ../c

    (empty)   (null)     (empty)              ./
    (empty)   (empty)    (empty)              ./
    (empty)   /a/b       (empty)              ./
    (null)    (null)     (null)               ./
    (null)    (empty)    (null)               ./
    (null)    /a/b       (segfault)           ./

You may notice that return value "." has been changed to "./".
It is because:

 * Function quote_path_relative() in quote.c will show the relative
   path as "./" if abs(in) and base(prefix) are the same.

 * Function relative_path() is called only once (in setup.c), and
   it will be OK for the return value as "./" instead of ".".

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jiang Xin
2013-06-25 23:53:43 +08:00
committed by Junio C Hamano
parent 203439b284
commit e02ca72f70
5 changed files with 111 additions and 51 deletions

View File

@ -191,33 +191,30 @@ test_expect_success SYMLINKS 'real path works on symlinks' '
relative_path /a/b/c/ /a/b/ c/
relative_path /a/b/c/ /a/b c/
relative_path /a//b//c/ //a/b// c/ POSIX
relative_path /a/b /a/b .
relative_path /a/b/ /a/b .
relative_path /a /a/b /a POSIX
relative_path / /a/b/ / POSIX
relative_path /a/c /a/b/ /a/c POSIX
relative_path /a/c /a/b /a/c POSIX
relative_path /x/y /a/b/ /x/y POSIX
relative_path /a/b /a/b ./
relative_path /a/b/ /a/b ./
relative_path /a /a/b ../
relative_path / /a/b/ ../../
relative_path /a/c /a/b/ ../c
relative_path /a/c /a/b ../c
relative_path /x/y /a/b/ ../../x/y
relative_path /a/b "<empty>" /a/b POSIX
relative_path /a/b "<null>" /a/b POSIX
relative_path a/b/c/ a/b/ c/
relative_path a/b/c/ a/b c/
relative_path a/b//c a//b c
relative_path a/b/ a/b/ .
relative_path a/b/ a/b .
relative_path a a/b a # TODO: should be: ..
relative_path x/y a/b x/y # TODO: should be: ../../x/y
relative_path a/c a/b a/c # TODO: should be: ../c
relative_path a/b/ a/b/ ./
relative_path a/b/ a/b ./
relative_path a a/b ../
relative_path x/y a/b ../../x/y
relative_path a/c a/b ../c
relative_path a/b "<empty>" a/b
relative_path a/b "<null>" a/b
relative_path "<empty>" /a/b "(empty)"
relative_path "<empty>" "<empty>" "(empty)"
relative_path "<empty>" "<null>" "(empty)"
relative_path "<null>" "<empty>" "(null)"
relative_path "<null>" "<null>" "(null)"
test_expect_failure 'relative path: <null> /a/b => segfault' '
test-path-utils relative_path "<null>" "/a/b"
'
relative_path "<empty>" /a/b ./
relative_path "<empty>" "<empty>" ./
relative_path "<empty>" "<null>" ./
relative_path "<null>" "<empty>" ./
relative_path "<null>" "<null>" ./
relative_path "<null>" /a/b ./
test_done