! Copyright (C) 2004, 2009 Slava Pestov, Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: accessors combinators io.backend kernel math math.order namespaces sequences splitting strings system ; IN: io.pathnames SYMBOL: current-directory : path-separator? ( ch -- ? ) os windows? "/\\" "/" ? member? ; : path-separator ( -- string ) os windows? "\\" "/" ? ; : trim-tail-separators ( string -- string' ) [ path-separator? ] trim-tail ; : trim-head-separators ( string -- string' ) [ path-separator? ] trim-head ; : last-path-separator ( path -- n ? ) [ length 1 - ] keep [ path-separator? ] find-last-from ; 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? [ trim-tail-separators dup last-path-separator [ 1 + cut ] [ drop "." swap ] if { "" "." ".." } member? [ no-parent-directory ] when ] unless ; : append-path ( path1 path2 -- path ) { { [ over empty? ] [ append-path-empty ] } { [ dup empty? ] [ drop ] } { [ over trim-tail-separators "." = ] [ nip ] } { [ dup absolute-path? ] [ nip ] } { [ dup head.? ] [ rest trim-head-separators append-path ] } { [ dup head..? ] [ 2 tail trim-head-separators [ parent-directory ] dip append-path ] } { [ over absolute-path? over first path-separator? and ] [ [ 2 head ] dip append ] } [ [ trim-tail-separators ] [ trim-head-separators ] bi* "/" glue ] } cond ; : prepend-path ( path1 path2 -- path ) swap append-path ; inline : file-name ( path -- string ) dup root-directory? [ trim-tail-separators dup last-path-separator [ 1 + tail ] [ drop special-path? [ file-name ] when ] if ] unless ; : file-stem ( path -- stem ) file-name "." split1-last drop ; : file-extension ( path -- extension ) file-name "." split1-last nip ; : path-components ( path -- seq ) normalize-path path-separator split harvest ; HOOK: resolve-symlinks os ( path -- path' ) M: object resolve-symlinks normalize-path ; : resource-path ( path -- newpath ) "resource-path" get prepend-path ; GENERIC: vocab-path ( path -- newpath ) GENERIC: absolute-path ( path -- path' ) M: string absolute-path "resource:" ?head [ trim-head-separators resource-path absolute-path ] [ "vocab:" ?head [ trim-head-separators vocab-path absolute-path ] [ current-directory get prepend-path ] if ] if ; M: object normalize-path ( path -- path' ) absolute-path ; TUPLE: pathname string ; C: pathname M: pathname absolute-path string>> absolute-path ; M: pathname <=> [ string>> ] compare ; HOOK: home io-backend ( -- dir ) M: object home "" resource-path ;