;; data/core/posix.scm - posix module
;;
;; Copyright (C) 2000 Martin Grabmueller <mgrabmue@cs.tu-berlin.de>
;;
;; This is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; 
;; This software is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;; 
;; You should have received a copy of the GNU General Public License
;; along with this package; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.  

(define-module (core posix))


(export stat:dev stat:ino stat:mode stat:nlink
	stat:uid stat:gid stat:rdev stat:size stat:atime stat:mtime
	stat:ctime stat:blksize stat:blocks stat:type stat:perms
	pw:name pw:passwd pw:uid pw:gid pw:gecos pw:dir pw:shell
	tm:sec tm:min tm:hour tm:mday tm:month tm:year tm:wday
	tm:yday tm:isdst tm:zoff tm:zname
	file-exists? file-is-directory? file-is-symlink?
	file-regular? file-char-special? file-block-special? file-fifo?
	file-socket?
	quotify)

;; Various accessor functions for Posix structures ===================

(define (stat:dev v)    (vector-ref v 0))
(define (stat:ino v)    (vector-ref v 1))
(define (stat:mode v)   (vector-ref v 2))
(define (stat:nlink v)  (vector-ref v 3))
(define (stat:uid v)    (vector-ref v 4))
(define (stat:gid v)    (vector-ref v 5))
(define (stat:rdev v)   (vector-ref v 6))
(define (stat:size v)   (vector-ref v 7))
(define (stat:atime v)  (vector-ref v 8))
(define (stat:mtime v)  (vector-ref v 9))
(define (stat:ctime v)  (vector-ref v 10))
(define (stat:blksize v) (vector-ref v 11))
(define (stat:blocks v) (vector-ref v 12))
(define (stat:type v)   (vector-ref v 13))
(define (stat:perms v)  (vector-ref v 14))

(define (pw:name pw)    (vector-ref pw 0))
(define (pw:passwd pw)  (vector-ref pw 1))
(define (pw:uid pw)     (vector-ref pw 2))
(define (pw:gid pw)     (vector-ref pw 3))
(define (pw:gecos pw)   (vector-ref pw 4))
(define (pw:dir pw)     (vector-ref pw 5))
(define (pw:shell pw)   (vector-ref pw 6))

(define (tm:sec tm)     (vector-ref tm 0))
(define (tm:min tm)     (vector-ref tm 1))
(define (tm:hour tm)    (vector-ref tm 2))
(define (tm:mday tm)    (vector-ref tm 3))
(define (tm:month tm)   (vector-ref tm 4))
(define (tm:year tm)    (vector-ref tm 5))
(define (tm:wday tm)    (vector-ref tm 6))
(define (tm:yday tm)    (vector-ref tm 7))
(define (tm:isdst tm)   (vector-ref tm 8))
(define (tm:zoff tm)    (vector-ref tm 9))
(define (tm:zname tm)   (vector-ref tm 10))

;; File handling =====================================================

;;;
;;; FIXME: Add the following procedure to the reference manual
;;;

#!:doc
file-exists?
(file-exists? filename) => boolean
Return @code{#t}, if a file (or directory) called @var{filename} exists.
doc:!#
(define (file-exists? filename)
  (let ((st (false-if-exception (stat filename))))
    (not (not st))))

#!:doc
file-is-directory?
(file-directory? filename) => boolean
Return @code{#t}, if @var{filename} is a directory.
doc:!#
(define (file-is-directory? filename)
  (let ((st (false-if-exception (stat filename))))
    (and st (eq? (stat:type st) 'directory))))

#!:doc
file-is-symlink?
(file-is-symlink? filename) => boolean
Return @code{#t}, if @var{filename} is a symbolic link.
doc:!#
(define (file-is-symlink? filename)
  (let ((st (false-if-exception (lstat filename))))
    (and st (eq? (stat:type st) 'symlink))))

#!:doc
file-regular?
(file-regular? filename) => boolean
Return @code{#t}, if @var{filename} is a regular file.
doc:!#
(define (file-regular? filename)
  (let ((st (false-if-exception (stat filename))))
    (and st (eq? (stat:type st) 'regular))))

#!:doc
file-char-special?
(file-char-special? filename) => boolean
Return @code{#t}, if @var{filename} is a special character device file.
doc:!#
(define (file-char-special? filename)
  (let ((st (false-if-exception (stat filename))))
    (and st (eq? (stat:type st) 'char-special))))

#!doc
file-block-special?
(file-block-special? filename) => boolean
Return @code{#t}, if @var{filename} is a special block device file.
doc:!#
(define (file-block-special? filename)
  (let ((st (false-if-exception (stat filename))))
    (and st (eq? (stat:type st) 'block-special))))

#!:doc
file-fifo?
(file-fifo? filename) => boolean
Return @code{#t}, if @var{filename} is a fifo file.
doc:!#
(define (file-fifo? filename)
  (let ((st (false-if-exception (stat filename))))
    (and st (eq? (stat:type st) 'fifo))))

#!:doc
file-socket?
(file-socket? filename) => boolean
Return @code{#t}, if @var{filename} is a socket file.
doc:!#
(define (file-socket? filename)
  (let ((st (false-if-exception (stat filename))))
    (and st (eq? (stat:type st) 'socket))))

#!:doc
quotify
(quotify str) => string
Return a string with the same contents as @var{str}, but quote all
shell meta-characters.  
doc:!#
(define (quotify string)
 (let loop ((chars (string->list string)) (c '()))
  (if (null? chars)
      (list->string (reverse c))
      (loop (cdr chars)
	    (cons (car chars)
		  (if (or (char=? (car chars) #\\)
			  (char=? (car chars) #\")
			  (char=? (car chars) #\$)
			  (char=? (car chars) #\&))
		      (cons #\\ c)
		      c))))))
