2009-02-15 20:53:21 -05:00
|
|
|
! Copyright (C) 2004, 2009 Slava Pestov, Doug Coleman.
|
2008-12-14 21:03:00 -05:00
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
2020-01-03 17:30:00 -05:00
|
|
|
USING: accessors assocs combinators io.backend kernel math
|
|
|
|
math.order namespaces sequences splitting strings system ;
|
2008-12-14 21:03:00 -05:00
|
|
|
IN: io.pathnames
|
|
|
|
|
|
|
|
SYMBOL: current-directory
|
|
|
|
|
|
|
|
: path-separator? ( ch -- ? ) os windows? "/\\" "/" ? member? ;
|
|
|
|
|
|
|
|
: path-separator ( -- string ) os windows? "\\" "/" ? ;
|
|
|
|
|
2009-10-16 06:48:37 -04:00
|
|
|
: trim-tail-separators ( string -- string' )
|
2009-01-29 23:19:07 -05:00
|
|
|
[ path-separator? ] trim-tail ;
|
2008-12-14 21:03:00 -05:00
|
|
|
|
2009-10-16 06:48:37 -04:00
|
|
|
: trim-head-separators ( string -- string' )
|
2009-01-29 23:19:07 -05:00
|
|
|
[ path-separator? ] trim-head ;
|
2008-12-14 21:03:00 -05:00
|
|
|
|
|
|
|
: last-path-separator ( path -- n ? )
|
2009-05-01 20:58:24 -04:00
|
|
|
[ length 1 - ] keep [ path-separator? ] find-last-from ;
|
2008-12-14 21:03:00 -05:00
|
|
|
|
|
|
|
HOOK: root-directory? io-backend ( path -- ? )
|
|
|
|
|
|
|
|
M: object root-directory? ( path -- ? )
|
|
|
|
[ f ] [ [ path-separator? ] all? ] if-empty ;
|
|
|
|
|
|
|
|
ERROR: no-parent-directory path ;
|
|
|
|
|
|
|
|
: parent-directory ( path -- parent )
|
|
|
|
dup root-directory? [
|
2009-01-29 23:19:07 -05:00
|
|
|
trim-tail-separators
|
2008-12-14 21:03:00 -05:00
|
|
|
dup last-path-separator [
|
2009-05-01 20:58:24 -04:00
|
|
|
1 + cut
|
2008-12-14 21:03:00 -05:00
|
|
|
] [
|
|
|
|
drop "." swap
|
|
|
|
] if
|
|
|
|
{ "" "." ".." } member? [
|
2015-08-13 19:13:05 -04:00
|
|
|
no-parent-directory
|
2008-12-14 21:03:00 -05:00
|
|
|
] when
|
|
|
|
] unless ;
|
|
|
|
|
|
|
|
<PRIVATE
|
|
|
|
|
|
|
|
: head-path-separator? ( path1 ? -- ?' )
|
|
|
|
[
|
|
|
|
[ t ] [ first path-separator? ] if-empty
|
|
|
|
] [
|
|
|
|
drop f
|
|
|
|
] if ;
|
|
|
|
|
|
|
|
: head.? ( path -- ? ) "." ?head head-path-separator? ;
|
|
|
|
|
|
|
|
: head..? ( path -- ? ) ".." ?head head-path-separator? ;
|
|
|
|
|
|
|
|
: append-path-empty ( path1 path2 -- path' )
|
|
|
|
{
|
|
|
|
{ [ dup head.? ] [
|
2009-01-29 23:19:07 -05:00
|
|
|
rest trim-head-separators append-path-empty
|
2008-12-14 21:03:00 -05:00
|
|
|
] }
|
2015-08-13 19:13:05 -04:00
|
|
|
{ [ dup head..? ] [ drop no-parent-directory ] }
|
2008-12-14 21:03:00 -05:00
|
|
|
[ nip ]
|
|
|
|
} cond ;
|
|
|
|
|
2020-01-03 17:30:00 -05:00
|
|
|
: windows-absolute-path? ( path -- ? )
|
2008-12-14 21:03:00 -05:00
|
|
|
{
|
|
|
|
{ [ dup "\\\\?\\" head? ] [ t ] }
|
|
|
|
{ [ dup length 2 < ] [ f ] }
|
|
|
|
{ [ dup second CHAR: : = ] [ t ] }
|
|
|
|
[ f ]
|
2020-01-03 17:30:00 -05:00
|
|
|
} cond nip ;
|
2008-12-14 21:03:00 -05:00
|
|
|
|
2009-02-15 20:53:21 -05:00
|
|
|
: special-path? ( path -- rest ? )
|
|
|
|
{
|
|
|
|
{ [ "resource:" ?head ] [ t ] }
|
|
|
|
{ [ "vocab:" ?head ] [ t ] }
|
|
|
|
[ f ]
|
|
|
|
} cond ;
|
|
|
|
|
2010-09-04 23:16:57 -04:00
|
|
|
PRIVATE>
|
|
|
|
|
2008-12-14 21:03:00 -05:00
|
|
|
: absolute-path? ( path -- ? )
|
|
|
|
{
|
2020-01-03 17:30:00 -05:00
|
|
|
{ [ dup empty? ] [ drop f ] }
|
|
|
|
{ [ dup special-path? nip ] [ drop t ] }
|
2008-12-14 21:03:00 -05:00
|
|
|
{ [ os windows? ] [ windows-absolute-path? ] }
|
2020-01-03 17:30:00 -05:00
|
|
|
{ [ dup first path-separator? ] [ drop t ] }
|
|
|
|
[ drop f ]
|
|
|
|
} cond ;
|
2008-12-14 21:03:00 -05:00
|
|
|
|
2010-09-05 01:40:47 -04:00
|
|
|
: append-relative-path ( path1 path2 -- path )
|
2010-09-04 23:16:57 -04:00
|
|
|
[ trim-tail-separators ]
|
2016-08-23 12:54:16 -04:00
|
|
|
[ trim-head-separators ] bi* "/" glue ;
|
2010-02-17 19:06:30 -05:00
|
|
|
|
2009-10-16 06:48:37 -04:00
|
|
|
: append-path ( path1 path2 -- path )
|
2008-12-14 21:03:00 -05:00
|
|
|
{
|
|
|
|
{ [ over empty? ] [ append-path-empty ] }
|
|
|
|
{ [ dup empty? ] [ drop ] }
|
2009-01-29 23:19:07 -05:00
|
|
|
{ [ over trim-tail-separators "." = ] [ nip ] }
|
2008-12-14 21:03:00 -05:00
|
|
|
{ [ dup absolute-path? ] [ nip ] }
|
2009-01-29 23:19:07 -05:00
|
|
|
{ [ dup head.? ] [ rest trim-head-separators append-path ] }
|
2008-12-14 21:03:00 -05:00
|
|
|
{ [ dup head..? ] [
|
2009-01-29 23:19:07 -05:00
|
|
|
2 tail trim-head-separators
|
2008-12-14 21:03:00 -05:00
|
|
|
[ parent-directory ] dip append-path
|
|
|
|
] }
|
|
|
|
{ [ over absolute-path? over first path-separator? and ] [
|
|
|
|
[ 2 head ] dip append
|
|
|
|
] }
|
2010-09-05 01:40:47 -04:00
|
|
|
[ append-relative-path ]
|
2008-12-14 21:03:00 -05:00
|
|
|
} cond ;
|
|
|
|
|
2009-10-16 06:48:37 -04:00
|
|
|
: prepend-path ( path1 path2 -- path )
|
2008-12-14 21:03:00 -05:00
|
|
|
swap append-path ; inline
|
|
|
|
|
2018-07-04 19:29:17 -04:00
|
|
|
: 3append-path ( path chunk1 chunk2 -- path' )
|
|
|
|
[ append-path ] dip append-path ; inline
|
|
|
|
|
2008-12-14 21:03:00 -05:00
|
|
|
: file-name ( path -- string )
|
|
|
|
dup root-directory? [
|
2009-01-29 23:19:07 -05:00
|
|
|
trim-tail-separators
|
2009-05-01 20:58:24 -04:00
|
|
|
dup last-path-separator [ 1 + tail ] [
|
2009-02-15 20:53:21 -05:00
|
|
|
drop special-path? [ file-name ] when
|
2008-12-14 21:03:00 -05:00
|
|
|
] if
|
|
|
|
] unless ;
|
|
|
|
|
2009-07-30 21:58:32 -04:00
|
|
|
: file-stem ( path -- stem )
|
|
|
|
file-name "." split1-last drop ;
|
|
|
|
|
|
|
|
: file-extension ( path -- extension )
|
2009-02-18 14:33:55 -05:00
|
|
|
file-name "." split1-last nip ;
|
|
|
|
|
|
|
|
: path-components ( path -- seq )
|
|
|
|
normalize-path path-separator split harvest ;
|
|
|
|
|
2009-10-28 18:25:50 -04:00
|
|
|
HOOK: resolve-symlinks os ( path -- path' )
|
2009-02-18 14:33:55 -05:00
|
|
|
|
2009-10-28 18:25:50 -04:00
|
|
|
M: object resolve-symlinks normalize-path ;
|
2008-12-14 21:03:00 -05:00
|
|
|
|
|
|
|
: resource-path ( path -- newpath )
|
|
|
|
"resource-path" get prepend-path ;
|
|
|
|
|
2011-12-21 11:35:05 -05:00
|
|
|
HOOK: home io-backend ( -- dir )
|
|
|
|
|
|
|
|
M: object home "" resource-path ;
|
|
|
|
|
2009-02-15 20:53:21 -05:00
|
|
|
GENERIC: vocab-path ( path -- newpath )
|
|
|
|
|
2009-10-28 18:25:50 -04:00
|
|
|
GENERIC: absolute-path ( path -- path' )
|
2008-12-14 21:03:00 -05:00
|
|
|
|
2009-10-28 18:25:50 -04:00
|
|
|
M: string absolute-path
|
2008-12-14 21:03:00 -05:00
|
|
|
"resource:" ?head [
|
2009-01-29 23:19:07 -05:00
|
|
|
trim-head-separators resource-path
|
2009-10-28 18:25:50 -04:00
|
|
|
absolute-path
|
2008-12-14 21:03:00 -05:00
|
|
|
] [
|
2009-02-15 20:53:21 -05:00
|
|
|
"vocab:" ?head [
|
|
|
|
trim-head-separators vocab-path
|
2009-10-28 18:25:50 -04:00
|
|
|
absolute-path
|
2009-02-15 20:53:21 -05:00
|
|
|
] [
|
2012-01-10 21:25:53 -05:00
|
|
|
"~" ?head [
|
2011-12-21 11:35:05 -05:00
|
|
|
trim-head-separators home prepend-path
|
|
|
|
absolute-path
|
2012-10-22 21:09:58 -04:00
|
|
|
] [
|
2009-02-15 20:53:21 -05:00
|
|
|
current-directory get prepend-path
|
2012-10-22 21:09:58 -04:00
|
|
|
] if ] if
|
2008-12-14 21:03:00 -05:00
|
|
|
] if ;
|
|
|
|
|
|
|
|
M: object normalize-path ( path -- path' )
|
2009-10-28 18:25:50 -04:00
|
|
|
absolute-path ;
|
2008-12-14 21:03:00 -05:00
|
|
|
|
2018-07-07 12:59:59 -04:00
|
|
|
: root-path* ( path -- path' )
|
|
|
|
dup absolute-path? [
|
|
|
|
dup [ path-separator? ] find
|
|
|
|
drop 1 + head
|
|
|
|
] when ;
|
|
|
|
|
|
|
|
HOOK: root-path os ( path -- path' )
|
|
|
|
|
|
|
|
M: object root-path root-path* ;
|
|
|
|
|
|
|
|
: relative-path* ( path -- relative-path )
|
|
|
|
dup absolute-path? [
|
|
|
|
dup [ path-separator? ] find
|
|
|
|
drop 1 + tail
|
|
|
|
] when ;
|
|
|
|
|
|
|
|
HOOK: relative-path os ( path -- path' )
|
|
|
|
|
|
|
|
M: object relative-path relative-path* ;
|
|
|
|
|
|
|
|
: canonicalize-path* ( path -- path' )
|
|
|
|
[
|
|
|
|
relative-path
|
|
|
|
[ path-separator? ] split-when
|
|
|
|
[ { "." "" } member? ] reject
|
|
|
|
V{ } clone [
|
|
|
|
dup ".." = [
|
|
|
|
over empty?
|
|
|
|
[ over push ]
|
|
|
|
[ over ?last ".." = [ over push ] [ drop dup pop* ] if ] if
|
|
|
|
] [
|
|
|
|
over push
|
|
|
|
] if
|
|
|
|
] reduce
|
|
|
|
] keep dup absolute-path? [
|
|
|
|
[
|
|
|
|
[ ".." = ] trim-head
|
|
|
|
path-separator join
|
|
|
|
] dip root-path prepend-path
|
|
|
|
] [
|
|
|
|
drop path-separator join [ "." ] when-empty
|
|
|
|
] if ;
|
|
|
|
|
|
|
|
HOOK: canonicalize-path io-backend ( path -- path' )
|
|
|
|
|
|
|
|
M: object canonicalize-path canonicalize-path* ;
|
|
|
|
|
2020-01-03 17:30:00 -05:00
|
|
|
HOOK: canonicalize-drive io-backend ( path -- path' )
|
|
|
|
|
|
|
|
M: object canonicalize-drive ;
|
|
|
|
|
|
|
|
HOOK: canonicalize-path-full io-backend ( path -- path' )
|
|
|
|
|
|
|
|
M: object canonicalize-path-full canonicalize-path canonicalize-drive ;
|
|
|
|
|
|
|
|
: >windows-path ( path -- path' ) H{ { CHAR: / CHAR: \\ } } substitute ;
|
|
|
|
|
2008-12-14 21:03:00 -05:00
|
|
|
TUPLE: pathname string ;
|
|
|
|
|
|
|
|
C: <pathname> pathname
|
|
|
|
|
2009-10-28 18:25:50 -04:00
|
|
|
M: pathname absolute-path string>> absolute-path ;
|
2008-12-14 21:03:00 -05:00
|
|
|
|
2018-07-07 12:59:59 -04:00
|
|
|
M: pathname <=> [ string>> ] compare ;
|