-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathecho.scm
executable file
·78 lines (70 loc) · 2.16 KB
/
echo.scm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/guile \
-e main -s
!#
(use-modules (ice-9 binary-ports))
(define status #t)
(define (main args)
(setlocale LC_ALL "")
(let loop ((args (cdr args))
(first-arg #t))
(cond ((null? args)
(newline)
(quit status))
(else
(unless first-arg
(write-char #\space))
(let ((arg (car args)))
(call-with-input-string arg initial)
(loop (cdr args) #f))))))
(define (echo ch port)
(write-char ch)
(initial port))
(define (initial port)
(define ch (read-char port))
(cond ((eqv? ch #\\)
(backslash port))
((not (eof-object? ch))
(echo ch port))))
(define (backslash port)
(define ch (read-char port))
(case ch
((#\a) (echo #\alarm port))
((#\b) (echo #\backspace port))
((#\c) (quit status))
((#\f) (echo #\page port))
((#\n) (echo #\newline port))
((#\r) (echo #\return port))
((#\t) (echo #\tab port))
((#\v) (echo #\vtab port))
((#\\) (echo #\\ port))
((#\0) (let ((next (peek-char port)))
(if (and (assv next octal-digits)
(not (char=? next #\0)))
(octal port)
(echo #\nul port))))
(else (set! status #f)
(write-char #\\)
(unless (eof-object? ch)
(unread-char ch port)
(initial port)))))
(define (octal port)
(let loop ((value 0)
(waiting 3))
(cond ((zero? waiting)
(if (< value 256)
(put-u8 (current-output-port) value)
(set! status #f))
(initial port))
(else (let ((ch (read-char port)))
(cond ((eof-object? ch)
(loop value 0))
((assv ch octal-digits)
=> (lambda (ass)
(loop (+ (* value 8) (cdr ass))
(1- waiting))))
(else
(unread-char ch port)
(loop value 0))))))))
(define octal-digits
'((#\0 . 0) (#\1 . 1) (#\2 . 2) (#\3 . 3)
(#\4 . 4) (#\5 . 5) (#\6 . 6) (#\7 . 7)))