This program implements a simple program interface to the UNIX dc desktop calculator command. The procedure calc-open starts the dc command and establishes two pipes to/from the child process; the procedure calc sends its argument (a dc expression as a string) as input to dc; calc-close closes the pipes and waits for the subprocess to terminate.
(require 'unix)
(define calc-from-dc) ; input port: standard output of dc command
(define calc-to-dc) ; output port: standard input of dc command
(define calc-dc-pid) ; process-ID of child process running dc
(define calc-dc-command "/bin/dc")
(define (calc-open)
(let* ((from (unix-pipe))
(to (unix-pipe))
(redirect-fd (lambda (a b)
(unix-dup a b) (unix-close a))))
(set! calc-dc-pid (unix-fork))
(if (zero? calc-dc-pid)
(begin
(unix-close (car from))
(unix-close (cdr to))
(redirect-fd (car to) 0)
(redirect-fd (cdr from) 1)
(unix-exec calc-dc-command '("dc")))
(begin
(unix-close (cdr from))
(unix-close (car to))
(set! calc-to-dc (unix-filedescriptor->port (cdr to) "w"))
(set! calc-from-dc (unix-filedescriptor->port (car from) "r"))))))
(define (calc expr)
(format calc-to-dc "~a~%" expr)
(flush-output-port calc-to-dc)
(read-string calc-from-dc))
(define (calc-close)
(close-output-port calc-to-dc)
(close-input-port calc-from-dc)
(unix-wait-process calc-dc-pid))
;;; Test -- print sqrt(2):
(calc-open)
(display (calc "10k 2v p")) (newline)
(calc-close)
The following procedure copies a file; the arguments are the source and target file names. The second argument may name a directory, in this case the file is copied into the directory. The target file must not yet exist. copy-file preserves the access mode of the source file.
(require 'unix)
(define copy-buffer-size 8192)
(define (copy-file from to)
(let ((from-stat (unix-stat from))
(to-stat (unix-errval (unix-stat to))))
(if (eq? (stat-type from-stat) 'directory) ; complain if "from"
(error 'copy-file "~s is a directory" from)) ; is a directory
(if (and (not (unix-error? to-stat)) ; destination exists
(eq? (stat-type to-stat) 'directory)) ; and is a directory?
(set! to (format #f "~a/~a" to from)))
(let* ((to-fd (unix-open to '(write create exclusive)
(stat-mode from-stat)))
(from-fd (unix-open from '(read)))
(buf (make-string copy-buffer-size)))
(let loop ((num-chars (unix-read-string-fill! from-fd buf)))
(if (positive? num-chars)
(begin
(unix-write to-fd buf num-chars)
(loop (unix-read-string-fill! from-fd buf)))))
(unix-close from-fd)
(unix-close to-fd))))
lock-vi starts the vi editor with the specified file name. It provides exclusive access to the file during the editing session by applying a write lock to the file and removing it when the editor finishes. A message is displayed periodically if the lock is held by somebody else.
(require 'unix)
(define (lock-vi file)
(let* ((fd (unix-open file '(read write)))
(lock ((record-constructor lock-record) #t 'set 0 0)))
(let loop ()
(if (not (unix-set-lock fd lock #f))
(begin
(format #t "Someone else is editing ~s...~%" file)
(unix-sleep 10)
(loop))))
(unix-system (format #f "vi ~a" file))
(unix-remove-lock fd lock)))
pipe-size attempts to determine the capacity of a pipe. It creates a pipe, places the write end of the pipe into non-blocking I/O mode and writes into the pipe until it is full, counting the characters successfully written.
(require 'unix)
(define (pipe-size)
(let* ((pipe (unix-pipe))
(flags (unix-filedescriptor-flags (cdr pipe)))
(len 32) ; assumes capacity is multiple of len
(noise (make-string len)))
;; enable non-blocking I/O for write side of pipe:
(unix-filedescriptor-flags (cdr pipe) (cons 'ndelay flags))
(unwind-protect
(let loop ((size 0))
(if (unix-error? (unix-errval (unix-write (cdr pipe) noise)))
(if (memq (unix-errno) '(eagain ewouldblock))
size
(error 'pipe-size "~E"))
(loop (+ size 32))))
(unix-close (car pipe))
(unix-close (cdr pipe)))))