Module: system-internals Synopsis: Abstract modeling of locations Author: Andy Armstrong 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 define constant $posix-separator = '/'; define constant $posix-extension-separator = '.'; define sealed abstract class () end class ; define sealed method string-as-locator (class == , string :: ) => (locator :: ) let pos = find-delimiter-from-end(string, $posix-separator); if (pos == string.size - 1) string-as-locator(, string) else string-as-locator(, string) end end method string-as-locator; define sealed class (, ) sealed constant slot locator-relative? :: = #f, init-keyword: relative?:; sealed constant slot locator-path :: , required-init-keyword: path:; end class ; define sealed method make (class == , #key server :: false-or() = #f, path :: false-or() = #f, relative? :: = #f, directory :: false-or() = #f, name :: false-or()) => (locator :: ) if (server) locator-error("Cannot specify server for posix directory locator: %=", server) end; let path = if (name | directory) concatenate(if (directory) directory.locator-path else #[] end, if (name) vector(name) else #[] end) else path end; next-method(class, path: canonicalize-path(path), relative?: relative?) end method make; define sealed method initialize (locator :: , #key server) => () next-method(); end method initialize; define method locator-server (locator :: ) => (server == #f) #f end method locator-server; define sealed method locator-name (locator :: ) => (name :: false-or()) let path = locator.locator-path; unless (empty?(path)) path[size(path) - 1] end end method locator-name; define sealed method \= (locator1 :: , locator2 :: ) => (equal? :: ) locator1.locator-relative? = locator2.locator-relative? & locator1.locator-path.size = locator2.locator-path.size & every?(\=, locator1.locator-path, locator2.locator-path) end method \=; define sealed method string-as-locator (class == , string :: ) => (locator :: ) let (path, relative?) = parse-path(string, test: curry(\==, $posix-separator)); make(, path: path, relative?: relative?) end method string-as-locator; define sealed method locator-as-string (class :: subclass(), locator :: ) => (string :: ) let separator = $posix-separator; path-to-string(locator.locator-path, class: class, separator: separator, relative?: locator.locator-relative?) end method locator-as-string; define sealed method locator-test (locator :: ) => (test :: ) \= end method locator-test; define method locator-might-have-links? (locator :: ) => (links? == #t) #t end method locator-might-have-links?; define sealed class (, ) sealed constant slot locator-directory :: false-or() = #f, init-keyword: directory:; sealed constant slot locator-base :: false-or() = #f, init-keyword: base:; sealed constant slot locator-extension :: false-or() = #f, init-keyword: extension:; end class ; define sealed method make (class == , #key directory :: false-or(), base :: false-or(), extension :: false-or(), name :: false-or()) => (locator :: ) let directory = unless (directory & current-directory-locator?(directory)) directory end; let pos = name & find-delimiter-from-end(name, $posix-extension-separator); let base = base | if (pos) copy-sequence(name, end: pos) else name end; let extension = extension | if (pos) copy-sequence(name, start: pos + 1) end; if (~base) locator-error("Attemped to create a file locator without a base") end; next-method(class, directory: directory, base: base, extension: extension) end method make; define sealed method locator-name (locator :: ) => (name :: false-or()) let base = locator.locator-base; let extension = locator.locator-extension; if (extension) concatenate(base | "", delimiter-to-string($posix-extension-separator), extension) else base end end method locator-name; define sealed method \= (locator1 :: , locator2 :: ) => (equal? :: ) locator1.locator-directory = locator2.locator-directory & locator1.locator-base = locator2.locator-base & locator1.locator-extension = locator2.locator-extension end method \=; define sealed method locator-as-string (class :: subclass(), locator :: ) => (string :: ) let directory = locator.locator-directory; let name = locator.locator-name; if (directory) concatenate-as(class, as(, directory), name) else name end end method locator-as-string; define sealed method string-as-locator (class == , string :: ) => (locator :: ) let pos = find-delimiter-from-end(string, $posix-separator); let (directory, name) = if (pos) values(as(, copy-sequence(string, end: pos)), copy-sequence(string, start: pos + 1)) else values(#f, string) end; make(, directory: directory, name: name) end method string-as-locator; /// Posix locator overrides define method simplify-locator (locator :: ) => (simplified-locator :: ) // Posix locators can't safely be simplified because '..' has a complicated // meaning when dealing with links, so just return the original. locator end method simplify-locator;