#lang scheme/base
(require (lib "pretty.ss")
(lib "match.ss")
(lib "process.ss") )
(provide
read-byte-timeout
with-output-to-file/safe
with-output-to-string
write-tree
file-in-path
resolve-path-list
filename->path
file->syntax-list
port->syntax-list
when-file
)
(define (port-ready? timeout port)
(sync/timeout timeout port))
(define (read-byte-timeout port timeout)
(let again ()
(if (port-ready? timeout port)
(read-byte port)
(begin
(error 'time-out "~a" timeout)
))))
(define (write-tree . args)
(apply pretty-print args))
(define (file-in-path path filename)
(let next ((p path))
(if (null? p)
(error 'file-not-in-path "~a ~a" filename path)
(let ((full (format "~a/~a" (car p) filename)))
(if (file-exists? full)
full
(next (cdr p)))))))
(define (delete-if-exists file)
(when (file-exists? file) (delete-file file)))
(define (with-output-to-file/safe file thunk)
(define (add-suffix f s)
(string-append (path->string (build-path f)) s))
(let ((file.bak (add-suffix file "~"))
(file.tmp (add-suffix file ".bak")))
(delete-if-exists file.tmp)
(let ((value
(with-output-to-file
file.tmp thunk)))
(delete-if-exists file.bak)
(when (file-exists? file)
(rename-file-or-directory file file.bak))
(rename-file-or-directory file.tmp file)
value)))
(define (with-output-to-string thunk)
(let ((p (open-output-string)))
(parameterize ((current-output-port p)) (thunk))
(close-output-port p)
(get-output-string p)))
(define (resolve-path-list rel-file path-list)
(cond
((file-exists? rel-file) rel-file)
((absolute-path? rel-file) (error 'not-found "~a" rel-file))
(else
(let next ((lst path-list))
(if (null? lst)
(error 'file-not-found "~a" rel-file)
(let ((file (build-path (car lst) rel-file)))
(if (file-exists? file) file
(next (cdr lst)))))))))
(define (port->syntax-list [port (current-input-port)] [stx #f])
(let slurp ()
(let ((atom (read port)))
(if (eof-object? atom) '()
(cons (datum->syntax stx atom) (slurp))))))
(define (file->syntax-list filename [stx #f])
(port->syntax-list (open-input-file filename) stx))
(define (filename->path filename)
(let-values (((path _ __) (split-path filename)))
(when (eq? path 'relative) (set! path (current-load-relative-directory)))
(unless (complete-path? path) (set! path (path->complete-path path)))
path))
(define (when-file f fn)
(when (file-exists? f)
(fn f)))