;;; Pathname expansion, to replace the deprecated core functionality.
;
; Copyright (c) 2014, The CHICKEN Team
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions
; are met:
;
; Redistributions of source code must retain the above copyright
; notice, this list of conditions and the following disclaimer.
;
; Redistributions in binary form must reproduce the above copyright
; notice, this list of conditions and the following disclaimer in
; the documentation and/or other materials provided with the
; distribution.
;
; Neither the name of the author nor the names of its contributors
; may be used to endorse or promote products derived from this
; software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
; COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
; INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
; OF THE POSSIBILITY OF SUCH DAMAGE.
(module pathname-expand
(pathname-expand)
(import chicken scheme)
(use srfi-13 files posix)
;; Expand pathname starting with "~", and/or apply base directory to
;; relative pathname
;
; Inspired by Gambit's "path-expand" procedure.
(define pathname-expand
(let* ((home
;; Effective uid might be changed at runtime so this has to
;; be a lambda, but we could try to cache the result on uid.
(lambda ()
(cond-expand
((and windows (not cygwin))
(or (get-environment-variable "USERPROFILE")
(get-environment-variable "HOME")
"."))
(else
(let ((info (user-information (current-effective-user-id))))
(list-ref info 5))))))
(slash
(cond-expand
((and windows (not cygwin)) '(#\\ #\/))
(else '(#\/))))
(ts (string-append "~" (string (car slash))))
(tts (string-append "~" ts)))
(lambda (path #!optional (base (current-directory)))
(if (absolute-pathname? path)
path
(let ((len (string-length path)))
(cond
((or (string=? "~~" path)
(and (fx>= len 3) (string=? tts (substring path 0 3))))
;; Repository-path
(let ((rp (repository-path)))
(if rp
(string-append rp (substring path 2 len))
(signal
(make-composite-condition
(make-property-condition
'exn 'location 'pathname-expand
'message "No repository path defined"
'arguments (list path))
(make-property-condition 'pathname-expand)
(make-property-condition 'repository-path))))))
((or (string=? "~" path)
(and (fx> len 2) (string=? ts (substring path 0 2))))
;; Current user's home dir
(string-append (home) (substring path 1 len)))
((and (fx> len 0) (char=? #\~ (string-ref path 0)))
;; Arbitrary user's home dir
(let ((rest (substring path 1 len)))
(if (and (fx> len 1) (memq (string-ref path 1) slash))
(string-append (home) rest)
(let* ((p (string-index path (lambda (c) (memq c slash))))
(user (substring path 1 (or p len)))
(info (user-information user)))
(if info
(let ((dir (list-ref info 5)))
(if p
(make-pathname dir (substring path p))
dir))
(signal
(make-composite-condition
(make-property-condition
'exn 'location 'pathname-expand
'message "Cannot expand homedir for user"
'arguments (list path))
(make-property-condition 'pathname-expand)
(make-property-condition 'username))))))))
(else (make-pathname base path))))))))
)