-
Notifications
You must be signed in to change notification settings - Fork 0
/
io.zp
182 lines (160 loc) · 5.64 KB
/
io.zp
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
(define (read? x)
"read from a file if it is an input file, else return #f.
params:
- x: the file to read from
complexity: O(1)
returns: a line of the file if it is a fil, else false"
(if (input-port? x)
(read x)
#f))
(define (write? x s)
"write <par>s</par> to a file if it is an output file, else return #f.
params:
- x: the output file
- s: the thing to write out
complexity: O(1)
returns: nil if it succeeded, false if it did not"
(if (output-port? x)
(write s x)
#f))
(define (newline . port)
"print newline to <par>port</par> or stdout if no port is given.
params:
- port: the port to write to (optional)
- complexity: O(1)
returns: nil if it could write, false if not or if the input arguments were malformed"
(cond
((null? port) (write ""))
((eq? (length port) 1) (write? (car port) ""))
(else #f)))
(define (with-input-file s p)
"open an input file of name <par>s</par> and apply a procedure <par>p</par>
to it, then close the file.
params:
- s: the filename
- p: the procedure to call
complexity: O(n) (where n is the complexity of p)
returns: the return value of <par>p</par> or false if the file could not be opened"
(let ((inport (open-input-file s)))
(if (eq? inport #f)
inport
(let ((res (p inport)))
(close-input-file inport)
res))))
(define (with-output-file s p)
"open an output file of name <par>s</par> and apply a procedure <par>p</par>
to it, then close the file.
params:
- s: the filename
- p: the procedure to call
complexity: O(n) (where n is the complexity of p)
returns: the return value of <par>p</par> or false if the file could not be opened"
(let ((outport (open-output-file s)))
(if (eq? outport #f)
outport
(let ((res (p outport)))
(close-output-file outport)
res))))
(define (error . args)
"print an error to stderr.
params:
- args: the things to print (vararg)
complexity: O(n)
returns: nil"
(write (string:join (cons "Error:" (map ->string args)) " ") :stderr))
(define (read-line . port)
"reads a line from the input port <par>port</par>. If no port is given, the standard
input will be used.
params:
- port: the input port to use (optional)
complexity: O(n) where n is the length of the line
returns: the line that was read"
(let loop ((line "")
(char (apply read-char port)))
(if (or (boolean? char) (eq? char #\newline) (eq? char #\carriage))
line
(loop (++ line char) (apply read-char port)))))
(define (file-exists? file)
"test whether the file with the name <par>file</par> exists.
It will not work on directories.
params:
- file: the name of the file to check
complexity: O(1)
returns: a boolean"
(not (boolean? (open-input-file file))))
(define (escape-sequence code str? output)
"send escape sequence <par>code</par> to output channel <par>output</par>.
If <par>str?</par> is true, it will not be printed but returned as a string.
params:
- code: the escape sequence
- str?: a boolean signalling whether we want to print the result or return it as a string
- output: the output channel (can be nil if <par>str?</par> is set)
complexity: O(1)
returns: a string if <par>str?</par> is true, else nil"
(let ((str (++ (string #\x1b) "[" (->string code) "m")))
(if str?
str
(display str output))))
(define (color col . args)
"color output using <par>col</par> to output channel (default: stdout).
Example:
<zepto>
; colors the output to stdout blue
(color :blue)
; colors the background of the output to stderr black
(color :bg-black #{:output :stderr})
; returns the ANSI escape sequence to make the output italic as a string
(color :italic #{:to-str #t})
</zepto>
params:
- col: an atom representing the color/style
- args: optional configuration arguments as hashmap (understands keys :output and :to-str)
complexity: O(1)
returns: a string if :to-str in <par>args</par> is set, else nil"
(define colors #{:black 30
:red 31
:green 32
:yellow 33
:blue 34
:magenta 35
:cyan 36
:white 37
:reset 0
:none 0
:bold 1
:italic 3
:underline 4
:blink-slow 5
:blink-rapid 6
:bg-black 40
:bg-red 41
:bg-green 42
:bg-yellow 43
:bg-blue 44
:bg-magenta 45
:bg-cyan 46
:bg-white 47})
(let* ((args (if (truthy? args) (car args) #{}))
(output (get-from args :output :stdout))
(str? (get-from args :to-str #f))
(col (if (number? col) col (colors col))))
(escape-sequence col str? output)))
(define-syntax with-output-to-file
(syntax-rules "call the function <par>fun</par> with the standard output set to
a port pointing to the file at <par>fname</par>.
params:
- fname: the file name of the file to use
- fun: the function to execute
complexity: O(n) (where n is the complexity of <par>fun</par>)
returns: the result of <par>fun</par>" ()
((_ fname fun)
(let ((f (open-output-file fname)))
(begin
(define d display)
(define w write)
(set! write (lambda (x) (w x f)))
(set! display (lambda (x) (d x f)))
(define res (fun))
(set! write w)
(set! display d)
res)))))