Module: system-internals Author: Gary Palter Synopsis: A platform independent file system API Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// Types /// Needs a better name, I think ... define constant = one-of(#"file", #"directory", #"link"); define constant = one-of(#"signal", #"replace"); define open abstract class () end class ; define class (, ) end class ; define class (, ) end class ; define sealed class (, ) end class ; define sealed class () constant slot file-error-locator :: , required-init-keyword: locator:; end class ; define sealed class () end class ; define sealed class () end class ; define sealed class () end class ; /// Locators define constant = type-union(, ); define method as (class == , string :: ) => (locator :: ) as(, string) end method as; /// Condition reporting define method condition-to-string (error :: ) => (string :: ) format-to-string("File %s exists", file-error-locator(error)) end method condition-to-string; define method condition-to-string (error :: ) => (string :: ) format-to-string("File %s does not exist", file-error-locator(error)) end method condition-to-string; define method condition-to-string (error :: ) => (string :: ) format-to-string("Invalid file permissions for file %s", file-error-locator(error)) end method condition-to-string; /// And now, the functions ... /// Given a pathname, returns its fully exanded form define generic expand-pathname (path :: ) => (expanded-path :: ); define method expand-pathname (path :: ) => (expanded-path :: ) %expand-pathname(path) end method expand-pathname; define method expand-pathname (path :: ) => (expanded-path :: ) expand-pathname(as(, path)) end method expand-pathname; /// Given a pathname, returns the shortest equivalent form (e.g., a DOS pathname on Windows) define generic shorten-pathname (path :: ) => (shortened-path :: ); define method shorten-pathname (path :: ) => (shortened-path :: ) %shorten-pathname(path) end method shorten-pathname; define method shorten-pathname (path :: ) => (shortened-path :: ) shorten-pathname(as(, path)) end method shorten-pathname; /// define generic file-exists? (file :: ) => (exists? :: ); define method file-exists? (file :: ) => (exists? :: ); %file-exists?(file) end method file-exists?; define method file-exists? (file :: ) => (exists? :: ); file-exists?(as(, file)) end method file-exists?; /// define generic file-type (file :: ) => (file-type :: ); define method file-type (file :: ) => (file-type :: ) %file-type(file) end method file-type; define method file-type (file :: ) => (file-type :: ) file-type(as(, file)) end method file-type; /// define generic link-target (link :: ) => (target :: ); define method link-target (link :: ) => (target :: ) %link-target(link) end method link-target; define method link-target (link :: ) => (target :: ) link-target(as(, link)) end method link-target; /// define generic delete-file (file :: ) => (); define method delete-file (file :: ) => () %delete-file(file) end method delete-file; define method delete-file (file :: ) => () delete-file(as(, file)) end method delete-file; /// define generic copy-file (source :: , destination :: , #key if-exists :: = #"signal") => (); define method copy-file (source :: , destination :: , #key if-exists :: = #"signal") => () %copy-file(source, destination, if-exists: if-exists) end method copy-file; define method copy-file (source :: , destination :: , #key if-exists :: = #"signal") => () copy-file(source, as(, destination), if-exists: if-exists) end method copy-file; define method copy-file (source :: , destination :: , #key if-exists :: = #"signal") => () copy-file(as(, source), destination, if-exists: if-exists) end method copy-file; define method copy-file (source :: , destination :: , #key if-exists :: = #"signal") => () copy-file(as(, source), as(, destination), if-exists: if-exists) end method copy-file; /// define generic rename-file (source :: , destination :: , #key if-exists :: = #"signal") => (); define method rename-file (source :: , destination :: , #key if-exists :: = #"signal") => () %rename-file(source, destination, if-exists: if-exists) end method rename-file; define method rename-file (source :: , destination :: , #key if-exists :: = #"signal") => () rename-file(source, as(, destination), if-exists: if-exists) end method rename-file; define method rename-file (source :: , destination :: , #key if-exists :: = #"signal") => () rename-file(as(, source), destination, if-exists: if-exists) end method rename-file; define method rename-file (source :: , destination :: , #key if-exists :: = #"signal") => () rename-file(as(, source), as(, destination), if-exists: if-exists) end method rename-file; /// define generic file-properties (file :: ) => (properties :: ); define method file-properties (file :: ) => (properties :: ) let properties = %file-properties(file); properties[#"write-date"] := properties[#"modification-date"]; properties end method file-properties; define method file-properties (file :: ) => (properties :: ) file-properties(as(, file)) end method file-properties; /// "Standard" properties are: /// author, size, creation-date, access-date, modification-date, readable?, executable? /// Other properties may be defined by the platform. define generic file-property (file :: , key :: ) => (value); define method file-property (file :: , key :: ) => (value) %file-property(file, key) end method file-property; define method file-property (file :: , key :: ) => (value) file-property(as(, file), key) end method file-property; define generic %file-property (file :: , key :: ) => (value); define method %file-property (file :: , key == #"write-date") => (write-date :: false-or()) %file-property(file, #"modification-date") end method %file-property; define method %file-property (file :: , key :: ) => (value) error(make(, format-string: "Native file system does not implement the %s property", format-arguments: list(key))) end method %file-property; /// Not all properties are settable: /// See the platform's implementation for details define generic file-property-setter (new-value, file :: , key :: ) => (new-value); define method file-property-setter (new-value, file :: , key :: ) => (new-value) %file-property-setter(new-value, file, key) end method file-property-setter; define method file-property-setter (new-value, file :: , key :: ) => (new-value) file-property-setter(new-value, as(, file), key) end method file-property-setter; define generic %file-property-setter (new-value, file :: , key :: ) => (new-value); define method %file-property-setter (new-write-date :: false-or(), file :: , key == #"write-date") => (new-write-date :: false-or()) %file-property-setter(new-write-date, file, #"modification-date") end method %file-property-setter; define method %file-property-setter (new-value, file :: , key :: ) => (new-value) error(make(, format-string: "Native file system cannot set the %s property", format-arguments: list(key))) end method %file-property-setter; /// define generic do-directory (f :: , directory :: ) => (); define method do-directory (f :: , directory :: ) => () %do-directory(f, directory) end method do-directory; define method do-directory (f :: , directory :: ) => () do-directory(f, locator-directory(directory)) end method do-directory; define method do-directory (f :: , directory :: ) => () do-directory(f, as(, directory)) end method do-directory; ///---*** FINISH ME! define function directory-contents () => () error(make(, format-string: "directory-contents is not yet implemented", format-arguments: #())) end function directory-contents; /// define generic create-directory (parent :: , name :: ) => (directory :: ); define method create-directory (parent :: , name :: ) => (directory :: ) let directory = subdirectory-locator(parent, name); %create-directory(directory) end method create-directory; define method create-directory (parent :: , name :: ) => (directory :: ) create-directory(locator-directory(parent), name) end method create-directory; define method create-directory (parent :: , name :: ) => (directory :: ) create-directory(as(, parent), name) end method create-directory; /// ///---*** Should we add an 'if-not-empty?' keyword argument? define generic delete-directory (directory :: ) => (); define method delete-directory (directory :: ) => () %delete-directory(directory) end method delete-directory; define method delete-directory (directory :: ) => () delete-directory(locator-directory(directory)) end method delete-directory; define method delete-directory (directory :: ) => () delete-directory(as(, directory)) end method delete-directory; /// define generic ensure-directories-exist (file :: ) => (created? :: ); define method ensure-directories-exist (file :: ) => (created? :: ) local method doit (directory :: false-or()) => (created? :: ) if (false?(directory)) #f // Presume that the root exists... elseif (file-exists?(directory)) #f else let parent = locator-directory(directory); doit(parent); %create-directory(directory); #t end end method doit; doit(file) end method ensure-directories-exist; define method ensure-directories-exist (file :: ) => (created? :: ) ensure-directories-exist(locator-directory(file)) end method ensure-directories-exist; define method ensure-directories-exist (file :: ) => (created? :: ) ensure-directories-exist(as(, file)) end method ensure-directories-exist; /// define generic directory-empty? (directory :: ) => (empty? :: ); define method directory-empty? (directory :: ) => (empty? :: ) %directory-empty?(directory) end method directory-empty?; define method directory-empty? (directory :: ) => (empty? :: ) directory-empty?(locator-directory(directory)) end method directory-empty?; define method directory-empty? (directory :: ) => (empty? :: ) directory-empty?(as(, directory)) end method directory-empty?; /// define function home-directory () => (home-directory :: false-or()) %home-directory() end function home-directory; /// define function working-directory () => (working-directory :: false-or()) %working-directory() end function working-directory; /// define generic working-directory-setter (new-working-directory :: ) => (new-working-directory :: ); define method working-directory-setter (new-working-directory :: ) => (new-working-directory :: ) %working-directory-setter(new-working-directory) end method working-directory-setter; define method working-directory-setter (new-working-directory :: ) => (new-working-directory :: ) working-directory-setter(locator-directory(new-working-directory)) end method working-directory-setter; define method working-directory-setter (new-working-directory :: ) => (new-working-directory :: ) working-directory-setter(as(, new-working-directory)) end method working-directory-setter; /// define function temp-directory () => (temp-directory :: false-or()) %temp-directory() end function temp-directory; /// define function root-directories () => (roots :: ) %root-directories() end function root-directories; /// Finally, two functions defined as part of Common Dylan's locators-protocol module /// define sideways method supports-list-locator? (directory :: ) => (listable? :: ) ~directory.locator-relative? end method supports-list-locator?; /// define sideways method list-locator (locator :: ) => (locators :: ) let locators :: = make(); do-directory (method (directory :: , name :: , type :: ) ignore(directory); let sublocator = select (type) #"file", #"link" => make(, directory: locator, name: name); #"directory" => subdirectory-locator(locator, name); end; add!(locators, sublocator) end, locator); locators end method list-locator;