elk/examples/unix/calc.scm

61 lines
1.7 KiB
Scheme

;;; -*-Scheme-*-
;;;
;;; Demonstrate pipes, fork, exec.
;;;
;;; (calc-open) -- Open two pipes to/from UNIX dc command
;;; (calc expr) -- Send expression to dc, return result as a string
;;; (calc-close) -- Close pipes, wait for child process
;;;
;;;
;;; This program requires vanilla UNIX dc. It does not work with GNU dc,
;;; because GNU dc uses buffered output even if standard output points to
;;; a pipe. This means that GNU dc does not produce any output until the
;;; pipe is closed; the call to read-string therefore just hangs.
(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 "/usr/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)
(if (feature? 'unix:wait-process)
(unix-wait-process calc-dc-pid)
(unix-wait)))
;;; Test -- print sqrt(2):
(calc-open)
(display (calc "10k 2v p")) (newline)
(calc-close)