factor/core/io/files/files.factor

346 lines
8.4 KiB
Factor
Raw Normal View History

2008-02-21 16:22:49 -05:00
! Copyright (C) 2004, 2008 Slava Pestov, Daniel Ehrenberg.
2007-09-20 18:09:08 -04:00
! See http://factorcode.org/license.txt for BSD license.
2008-09-18 23:08:12 -04:00
USING: io.backend io.files.private io hashtables kernel
kernel.private math memory namespaces sequences strings assocs
arrays definitions system combinators splitting sbufs
continuations destructors io.encodings io.encodings.binary init
accessors math.order ;
2008-02-29 00:46:27 -05:00
IN: io.files
HOOK: (file-reader) io-backend ( path -- stream )
2007-09-20 18:09:08 -04:00
HOOK: (file-writer) io-backend ( path -- stream )
2007-09-20 18:09:08 -04:00
HOOK: (file-appender) io-backend ( path -- stream )
2007-09-20 18:09:08 -04:00
2008-02-16 17:25:45 -05:00
: <file-reader> ( path encoding -- stream )
swap normalize-path (file-reader) swap <decoder> ;
2008-02-16 17:25:45 -05:00
: <file-writer> ( path encoding -- stream )
swap normalize-path (file-writer) swap <encoder> ;
2008-02-16 17:25:45 -05:00
: <file-appender> ( path encoding -- stream )
swap normalize-path (file-appender) swap <encoder> ;
2008-02-16 17:25:45 -05:00
2008-03-25 20:50:39 -04:00
: file-lines ( path encoding -- seq )
<file-reader> lines ;
: with-file-reader ( path encoding quot -- )
>r <file-reader> r> with-input-stream ; inline
2008-03-25 20:50:39 -04:00
: file-contents ( path encoding -- str )
<file-reader> contents ;
: with-file-writer ( path encoding quot -- )
>r <file-writer> r> with-output-stream ; inline
2008-03-25 20:50:39 -04:00
: set-file-lines ( seq path encoding -- )
[ [ print ] each ] with-file-writer ;
: set-file-contents ( str path encoding -- )
[ write ] with-file-writer ;
: with-file-appender ( path encoding quot -- )
>r <file-appender> r> with-output-stream ; inline
2007-09-20 18:09:08 -04:00
2008-02-27 15:59:15 -05:00
! Pathnames
2008-04-02 19:25:33 -04:00
: path-separator? ( ch -- ? ) os windows? "/\\" "/" ? member? ;
2007-09-20 18:09:08 -04:00
2008-04-02 19:25:33 -04:00
: path-separator ( -- string ) os windows? "\\" "/" ? ;
2008-03-26 15:57:35 -04:00
2008-09-05 18:12:30 -04:00
: trim-right-separators ( str -- newstr )
[ path-separator? ] trim-right ;
2007-09-20 18:09:08 -04:00
2008-09-05 18:12:30 -04:00
: trim-left-separators ( str -- newstr )
[ path-separator? ] trim-left ;
2008-02-05 20:16:22 -05:00
2008-02-27 15:59:15 -05:00
: last-path-separator ( path -- n ? )
[ length 1- ] keep [ path-separator? ] find-last-from ;
2008-02-27 15:59:15 -05:00
HOOK: root-directory? io-backend ( path -- ? )
2007-09-20 18:09:08 -04:00
2008-03-25 20:50:39 -04:00
M: object root-directory? ( path -- ? )
2008-09-06 18:10:32 -04:00
[ f ] [ [ path-separator? ] all? ] if-empty ;
2007-09-20 18:09:08 -04:00
2008-03-20 16:00:49 -04:00
ERROR: no-parent-directory path ;
: parent-directory ( path -- parent )
2008-03-25 20:50:39 -04:00
dup root-directory? [
2008-09-05 18:12:30 -04:00
trim-right-separators
2008-03-25 20:50:39 -04:00
dup last-path-separator [
1+ cut
2008-03-26 16:24:54 -04:00
] [
drop "." swap
] if
{ "" "." ".." } member? [
no-parent-directory
] when
2008-03-25 20:50:39 -04:00
] unless ;
<PRIVATE
: head-path-separator? ( path1 ? -- ?' )
[
2008-09-06 18:10:32 -04:00
[ t ] [ first path-separator? ] if-empty
2008-03-25 20:50:39 -04:00
] [
drop f
] if ;
: head.? ( path -- ? ) "." ?head head-path-separator? ;
: head..? ( path -- ? ) ".." ?head head-path-separator? ;
: append-path-empty ( path1 path2 -- path' )
{
{ [ dup head.? ] [
2008-09-05 18:12:30 -04:00
rest trim-left-separators append-path-empty
2008-03-25 20:50:39 -04:00
] }
{ [ dup head..? ] [ drop no-parent-directory ] }
2008-04-11 13:53:22 -04:00
[ nip ]
2008-03-25 20:50:39 -04:00
} cond ;
PRIVATE>
: windows-absolute-path? ( path -- path ? )
{
{ [ dup "\\\\?\\" head? ] [ t ] }
{ [ dup length 2 < ] [ f ] }
{ [ dup second CHAR: : = ] [ t ] }
2008-04-11 13:53:22 -04:00
[ f ]
} cond ;
2008-03-25 20:50:39 -04:00
: absolute-path? ( path -- ? )
{
{ [ dup empty? ] [ f ] }
{ [ dup "resource:" head? ] [ t ] }
2008-04-02 19:25:33 -04:00
{ [ os windows? ] [ windows-absolute-path? ] }
{ [ dup first path-separator? ] [ t ] }
2008-04-11 13:53:22 -04:00
[ f ]
} cond nip ;
2008-03-25 20:50:39 -04:00
: append-path ( str1 str2 -- str )
{
{ [ over empty? ] [ append-path-empty ] }
{ [ dup empty? ] [ drop ] }
2008-09-05 18:12:30 -04:00
{ [ over trim-right-separators "." = ] [ nip ] }
2008-03-25 20:50:39 -04:00
{ [ dup absolute-path? ] [ nip ] }
2008-09-05 18:12:30 -04:00
{ [ dup head.? ] [ rest trim-left-separators append-path ] }
2008-03-25 20:50:39 -04:00
{ [ dup head..? ] [
2008-09-05 18:12:30 -04:00
2 tail trim-left-separators
2008-03-25 20:50:39 -04:00
>r parent-directory r> append-path
] }
{ [ over absolute-path? over first path-separator? and ] [
>r 2 head r> append
] }
2008-04-11 13:53:22 -04:00
[
2008-09-05 18:12:30 -04:00
>r trim-right-separators "/" r>
trim-left-separators 3append
2008-04-11 13:53:22 -04:00
]
2007-11-12 17:11:17 -05:00
} cond ;
2007-09-20 18:09:08 -04:00
2008-03-25 20:50:39 -04:00
: prepend-path ( str1 str2 -- str )
swap append-path ; inline
2007-09-20 18:09:08 -04:00
: file-name ( path -- string )
2008-03-25 20:50:39 -04:00
dup root-directory? [
2008-09-05 18:12:30 -04:00
trim-right-separators
2008-05-10 16:22:38 -04:00
dup last-path-separator [ 1+ tail ] [
drop "resource:" ?head [ file-name ] when
] if
2008-03-25 20:50:39 -04:00
] unless ;
2007-09-20 18:09:08 -04:00
2008-06-02 16:00:51 -04:00
: file-extension ( filename -- extension )
"." last-split1 nip ;
2008-03-25 20:50:39 -04:00
! File info
2008-10-20 01:30:24 -04:00
TUPLE: file-info type size permissions created modified
accessed ;
2008-02-29 00:46:27 -05:00
HOOK: file-info io-backend ( path -- info )
! Symlinks
2008-03-06 13:04:54 -05:00
HOOK: link-info io-backend ( path -- info )
2008-02-29 00:46:27 -05:00
2008-04-03 22:39:52 -04:00
HOOK: make-link io-backend ( target symlink -- )
2008-04-03 22:39:52 -04:00
HOOK: read-link io-backend ( symlink -- path )
2008-04-03 22:39:52 -04:00
: copy-link ( target symlink -- )
2008-03-30 15:48:49 -04:00
>r read-link r> make-link ;
2008-02-29 00:46:27 -05:00
SYMBOL: +regular-file+
SYMBOL: +directory+
2008-04-03 22:39:52 -04:00
SYMBOL: +symbolic-link+
2008-02-29 00:46:27 -05:00
SYMBOL: +character-device+
SYMBOL: +block-device+
SYMBOL: +fifo+
SYMBOL: +socket+
SYMBOL: +unknown+
2008-02-27 15:59:15 -05:00
! File metadata
2008-05-15 00:23:12 -04:00
: exists? ( path -- ? ) normalize-path (exists?) ;
2007-09-20 18:09:08 -04:00
2008-05-15 00:23:12 -04:00
: directory? ( file-info -- ? ) type>> +directory+ = ;
2008-02-27 15:59:15 -05:00
2008-10-20 01:30:24 -04:00
! File-system
2008-10-23 14:18:00 -04:00
TUPLE: file-system-info device-name mount-point type free-space ;
2008-10-20 01:30:24 -04:00
HOOK: file-system-info os ( path -- file-system-info )
2008-04-03 19:34:47 -04:00
<PRIVATE
2008-02-27 15:59:15 -05:00
HOOK: cd io-backend ( path -- )
HOOK: cwd io-backend ( -- path )
2008-03-26 16:24:54 -04:00
M: object cwd ( -- path ) "." ;
2008-04-03 19:34:47 -04:00
PRIVATE>
SYMBOL: current-directory
[
cwd current-directory set-global
2008-09-18 23:08:12 -04:00
13 getenv cwd prepend-path \ image set-global
14 getenv cwd prepend-path \ vm set-global
image parent-directory "resource-path" set-global
] "io.files" add-init-hook
2008-03-25 20:50:39 -04:00
: resource-path ( path -- newpath )
"resource-path" get prepend-path ;
: (normalize-path) ( path -- path' )
"resource:" ?head [
2008-09-05 18:12:30 -04:00
trim-left-separators resource-path
(normalize-path)
] [
current-directory get prepend-path
] if ;
M: object normalize-path ( path -- path' )
(normalize-path) ;
2008-03-27 17:22:24 -04:00
: set-current-directory ( path -- )
2008-04-04 23:22:38 -04:00
(normalize-path) current-directory set ;
: with-directory ( path quot -- )
>r (normalize-path) current-directory r> with-variable ; inline
2008-03-27 17:22:24 -04:00
2008-02-27 15:59:15 -05:00
! Creating directories
HOOK: make-directory io-backend ( path -- )
2007-09-20 18:09:08 -04:00
: make-directories ( path -- )
2008-09-05 18:12:30 -04:00
normalize-path trim-right-separators {
2007-09-20 18:09:08 -04:00
{ [ dup "." = ] [ ] }
{ [ dup root-directory? ] [ ] }
{ [ dup empty? ] [ ] }
{ [ dup exists? ] [ ] }
2008-04-11 13:53:22 -04:00
[
dup parent-directory make-directories
2007-09-20 18:09:08 -04:00
dup make-directory
2008-04-11 13:53:22 -04:00
]
2007-09-20 18:09:08 -04:00
} cond drop ;
2008-10-19 13:55:48 -04:00
TUPLE: directory-entry name type ;
HOOK: >directory-entry os ( byte-array -- directory-entry )
HOOK: (directory-entries) os ( path -- seq )
2008-02-27 15:59:15 -05:00
2008-10-19 13:55:48 -04:00
: directory-entries ( path -- seq )
normalize-path
(directory-entries)
[ name>> { "." ".." } member? not ] filter ;
: directory-files ( path -- seq )
directory-entries [ name>> ] map ;
2008-02-27 15:59:15 -05:00
2008-10-19 13:55:48 -04:00
: with-directory-files ( path quot -- )
[ "" directory-files ] prepose with-directory ; inline
2008-02-27 15:59:15 -05:00
! Touching files
HOOK: touch-file io-backend ( path -- )
! Deleting files
HOOK: delete-file io-backend ( path -- )
HOOK: delete-directory io-backend ( path -- )
: delete-tree ( path -- )
dup link-info type>> +directory+ = [
2008-10-19 13:55:48 -04:00
[ [ [ delete-tree ] each ] with-directory-files ]
[ delete-directory ]
bi
] [ delete-file ] if ;
2008-02-27 15:59:15 -05:00
2008-06-08 16:32:55 -04:00
: to-directory ( from to -- from to' )
over file-name append-path ;
2008-02-27 15:59:15 -05:00
! Moving and renaming files
HOOK: move-file io-backend ( from to -- )
: move-file-into ( from to -- )
2008-02-27 15:59:15 -05:00
to-directory move-file ;
: move-files-into ( files to -- )
[ move-file-into ] curry each ;
2008-02-27 15:59:15 -05:00
! Copying files
2007-11-24 16:38:20 -05:00
HOOK: copy-file io-backend ( from to -- )
M: object copy-file
dup parent-directory make-directories
2008-02-16 17:25:45 -05:00
binary <file-writer> [
swap binary <file-reader> [
swap stream-copy
] with-disposal
] with-disposal ;
: copy-file-into ( from to -- )
2008-02-27 15:59:15 -05:00
to-directory copy-file ;
: copy-files-into ( files to -- )
[ copy-file-into ] curry each ;
2008-02-27 17:31:13 -05:00
DEFER: copy-tree-into
2008-02-27 15:59:15 -05:00
: copy-tree ( from to -- )
normalize-path
2008-03-30 15:48:49 -04:00
over link-info type>>
{
{ +symbolic-link+ [ copy-link ] }
{ +directory+ [
2008-10-19 13:55:48 -04:00
swap [
[ swap copy-tree-into ] with each
] with-directory-files
2008-03-30 15:48:49 -04:00
] }
[ drop copy-file ]
} case ;
2008-02-27 15:59:15 -05:00
: copy-tree-into ( from to -- )
2008-02-27 15:59:15 -05:00
to-directory copy-tree ;
: copy-trees-into ( files to -- )
[ copy-tree-into ] curry each ;
2008-02-27 17:31:13 -05:00
2008-02-27 15:59:15 -05:00
! Special paths
2008-02-22 02:01:14 -05:00
: temp-directory ( -- path )
2008-03-23 12:38:26 -04:00
"temp" resource-path dup make-directories ;
2008-02-21 23:08:03 -05:00
2008-03-27 03:12:15 -04:00
: temp-file ( name -- path )
temp-directory prepend-path ;
2008-03-25 20:50:39 -04:00
! Pathname presentations
TUPLE: pathname string ;
C: <pathname> pathname
2008-08-29 18:09:19 -04:00
M: pathname <=> [ string>> ] compare ;
2008-03-25 20:50:39 -04:00
2008-02-27 15:59:15 -05:00
! Home directory
2008-10-18 22:24:14 -04:00
HOOK: home io-backend ( -- dir )
2008-04-11 13:53:22 -04:00
2008-10-18 22:24:14 -04:00
M: object home "" resource-path ;