-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathsrfi-207.html
417 lines (355 loc) · 25.3 KB
/
srfi-207.html
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SRFI 207: String-notated bytevectors</title>
<link href="/favicon.png" rel="icon" sizes="192x192" type="image/png">
<link rel="stylesheet" href="https://srfi.schemers.org/srfi.css" type="text/css">
<style>pre.example { margin-left: 2em; }</style>
<meta name="viewport" content="width=device-width, initial-scale=1"></head>
<body>
<h1><a href="https://srfi.schemers.org/"><img class="srfi-logo" src="https://srfi.schemers.org/srfi-logo.svg" alt="SRFI logo" /></a>207: String-notated bytevectors</h1>
<p>by
Daphne Preston-Kendal (external notation),
John Cowan (procedure design),
Wolfgang Corcoran-Mathe (implementation)
</p>
<h2 id="status">Status</h2>
<p>This SRFI is currently in <em>final</em> status. Here is <a href="https://srfi.schemers.org/srfi-process.html">an explanation</a> of each status that a SRFI can hold. To provide input on this SRFI, please send email to <code><a href="mailto:srfi+minus+207+at+srfi+dotschemers+dot+org">srfi-207@<span class="antispam">nospam</span>srfi.schemers.org</a></code>. To subscribe to the list, follow <a href="https://srfi.schemers.org/srfi-list-subscribe.html">these instructions</a>. You can access previous messages via the mailing list <a href="https://srfi-email.schemers.org/srfi-207">archive</a>.</p>
<ul>
<li>Received: 2020-08-15</li>
<li>Draft #1 published: 2020-08-15</li>
<li>Draft #2 published: 2020-08-17</li>
<li>Draft #3 published: 2020-09-09</li>
<li>Draft #4 published: 2020-10-05</li>
<li>Draft #5 published: 2020-10-12</li>
<li>Draft #6 published: 2020-10-15</li>
<li>Draft #7 published: 2020-10-24</li>
<li>Finalized: 2020-10-29</li>
<li>Revised to fix errata:
<ul>
<li>2021-03-10 (Fix <a href="#errata-1">description</a>
of <code>make-bytestring!</code>.)</li>
<li>2025-02-06 (Fix <a href="#errata-2">explanation</a> of how
to compare bytevectors for equality.)</li></ul></li>
</ul>
<h2 id="abstract">Abstract</h2>
<p>To ease the human reading and writing of Scheme code involving
binary data that for mnemonic reasons corresponds
as a whole or in part to ASCII-coded text, a notation
for bytevectors is defined which allows printable ASCII characters
to be used literally without being converted to their corresponding
integer forms. In addition, this SRFI provides a set of procedures
known as the bytestring library
for constructing a bytevector from a sequence of integers,
characters, strings, and/or bytevectors, and for manipulating
bytevectors as if they were strings as far as possible.
<h2 id="rationale">Rationale</h2>
<p>Binary file formats are usually not self-describing, and if they are,
the descriptive portion is itself binary, which makes it hard for human beings
to interpret. To assist with this problem, it is common to have a
human-readable section at the beginning of the file, or in some cases
at the beginning of each distinct section of the file.
For historical reasons and to avoid text encoding complications, it is usual
for this human-readable section to be expressed as ASCII text.</p>
<p>For example, ZIP files begin with the hex bytes <code>50 4B</code>
which are the ASCII encoding for the characters "PK", the initials
of Phil Katz, the inventor of ZIP format. As another example,
the GIF image format begins with <code>47 49 46 38 39 61</code>,
the ASCII encoding for "GIF89a", where "89a" is the format version.
A third example is the PNG image format, where the file header
begins <code>89 50 4E 47</code>. The first byte is intentionally
non-ASCII, but the next three are "PNG". Furthermore, a PNG
file is divided into chunks, each of which contains a 4-byte
"chunk type" code. The letters in the chunk type are mnemonics
for its purpose, such as "PLTE" for a palette, "bKGD" for a
default background color, and "iTXt" for descriptive text in UTF-8.</p>
<p>When bytevectors contain string data of this kind, it is much more tractable for
human programmers to deal with them in the form <code>#u8"recursion"</code>
than in the form <code>#u8(114 101 99 117 114 115 105 111 110)</code>.
This is true even when non-ASCII bytes are incorporated
into the bytevector: the complete 8-bit PNG file header can be written as
<code>#u8"\x89;PNG\r\n\x1A;\n"</code>
instead of <code>#u8(0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A)</code>.</p>
<p>In addition, this SRFI provides bytevectors with additional procedures that closely resemble those provided for strings. For example, bytevectors can be padded or trimmed, compared case-sensitively or case-insensitively, searched, joined, and split.
<p>In this specification it is assumed that bytevectors are as defined in R7RS-small section 6.9. Implementations may also consider them equivalent to R6RS bytevectors (R6RS 4.3.4) or <a href="https://srfi.schemers.org/srfi-4/srfi-4.html">SRFI 4</a> <code>u8vector</code>s, depending which kind of homogeneous vectors of unsigned 8-bit integers an implementation supports.
<h2 id="specification">Specification</h2>
<p>Most of the procedures of this SRFI begin with <code>bytestring-</code>
in order to distinguish them from other bytevector procedures.
This does not mean that they accept or return a separate bytestring type:
bytestrings and bytevectors are exactly the same type.</p>
<h3>External notation</h3>
<p>The basic form of a string-notated bytevector is:
<blockquote><code>#u8"</code> <var>content</var> <code>"</code></blockquote>
<p>To avoid character encoding issues within string-notated bytevectors, only printable ASCII characters (that is, Unicode codepoints in the range from U+0020 to U+007E inclusive) are allowed to be used within the <var>content</var> of a string-notated bytevector. All other characters must be expressed through mnemonic or inline hex escapes, and <code>"</code> and <code>\</code> must also be escaped as in normal Scheme strings.
<p>Within the <var>content</var> of a string-notated bytevector:
<ul>
<li>the sequence <code>\"</code> represents the integer 34;
<li>the sequence <code>\\</code> represents the integer 92;
<li>the following mnemonic sequences represent the corresponding integers:
<table>
<tr><th>Seq. <th>Integer
<tr><td><code>\a</code> <td>7
<tr><td><code>\b</code> <td>8
<tr><td><code>\t</code> <td>9
<tr><td><code>\n</code> <td>10
<tr><td><code>\r</code> <td>13
<tr><td><code>\|</code> <td>124
</table>
<li>the sequence <code>\x</code> followed by zero or more <code>0</code> characters, followed by one or two hexadecimal digits, followed by <code>;</code> represents the integer specified by the hexadecimal digits;
<li>the sequence <code>\</code> followed by zero or more intraline whitespace characters, followed by a newline, followed by zero or more further intraline whitespace characters, is ignored and corresponds to no entry in the resulting bytevector;
<li>any other printable ASCII character represents the character number of that character in the ASCII/Unicode code chart; and
<li>it is an error to use any other character or sequence beginning with <code>\</code> within a string-notated bytevector.
</ul>
<p>Note: The <code>\|</code> sequence is provided so that
string parsing, symbol parsing, and string-notated bytevector parsing
can all use the same sequences.
However, we give a complete definition of the valid lexical syntax
in this SRFI rather than inheriting the native syntax of strings,
so that it is clear that <code>#u8"ι"</code> and
<code>#u8"\xE000;"</code> are invalid.</p>
<p>When the Scheme reader encounters a string-notated bytevector, it produces a datum as if that bytevector had been written out in full. That is, <code>#u8"A"</code> is exactly equivalent to <code>#u8(65)</code>.
<p>A Scheme implementation which supports string-notated bytevectors may not by default use this notation when any of the <code>write</code> family of procedures is called upon a bytevector or upon another datum containing a bytevector. A future SRFI is expected to add a configurable version of the <code>write</code> procedure which may enable the use of this notation in this context.
<h3>Formal syntax</h3>
<p>The formal syntax of Scheme (defined in R7RS-small 7.1) is amended as follows.
<ul>
<li><p>In the definition of ⟨token⟩, after ‘| ⟨string⟩’, insert ‘| ⟨string-notated bytevector⟩’.
<li><p>After the definition of ⟨byte⟩ is inserted:
<blockquote>
<p>⟨string-notated bytevector⟩ → <code>#u8"</code> ⟨string-notated bytevector element⟩* <code>"</code><br>
⟨string-notated bytevector element⟩ → ⟨any printable ASCII character other than <code>"</code> or <code>\</code>⟩<br>
<span style="margin-left:1em">| ⟨mnemonic escape⟩ | <code>\"</code> | <code>\\</code></span><br>
<span style="margin-left:1em">| <code>\</code>⟨intraline whitespace⟩*⟨line ending⟩⟨intraline whitespace⟩*</span><br>
<span style="margin-left:1em">| ⟨inline hex escape⟩</span>
</blockquote>
</ul>
<h3>Constructors</h3>
<p><code>(bytestring</code> <var>arg</var> …<code>)</code></p>
<p>Converts <var>args</var> into a sequence of small integers and returns them as a bytevector as follows:</p>
<ul>
<li>
<p>If <var>arg</var> is an exact integer in the range 0-255 inclusive, it is added to the result.</p>
</li>
<li>
<p>If <var>arg</var> is an ASCII character (that is, its codepoint is in the range 0-127 inclusive), it is converted to its codepoint and added to the result.</p>
</li>
<li>
<p>If <var>arg</var> is a bytevector, its elements are added to the result.</p>
</li>
<li>
<p>If <var>arg</var> is a string of ASCII characters, it is converted to a sequence of codepoints which are added to the result.</p>
</li>
</ul>
<p>Otherwise, an error satisfying <code>bytestring-error?</code> is signaled.</p>
<p>Examples:</p>
<pre class="example"><code>(bytestring "lo" #\r #x65 #u8(#x6d)) ⇒ #u8"lorem"
(bytestring "η" #\space #u8(#x65 #x71 #x75 #x69 #x76)) ⇒</code> <em>error</em>
</pre>
<p><code>(make-bytestring</code> <var>list</var><code>)</code></p>
<p>If the elements of <var>list</var> are suitable arguments for
<code>bytestring</code>, returns the bytevector that would be the
result of applying <code>bytestring</code> to <var>list</var>.
Otherwise, an error satisfying <code>bytestring-error?</code> is signaled.</p>
<p id="errata-1"><code>(make-bytestring!</code> <var>bytevector at list</var><code>)</code></p>
<p>If the elements of <var>list</var> are suitable arguments for
<code>bytestring</code>, writes the bytes of the bytevector that would be the
result of calling <code>make-bytestring</code>
into <var>bytevector</var> starting at index <var>at</var>.</p>
<pre class="example"><code>(define bstring (make-bytevector 10 #x20))
(make-bytestring! bstring 2 '(#\s #\c "he" #u8(#x6d #x65)))
bstring ⇒ #u8" scheme "</code></pre>
<h3>Conversion</h3>
<p><code>(bytevector->hex-string</code> <var>bytevector</var><code>)</code><br>
<code>(hex-string->bytevector</code> <var>string</var><code>)</code></p>
<p>Converts between a bytevector and a string containing pairs of hexadecimal digits.
If <var>string</var> is not pairs of hexadecimal digits, an error satisfying <code>bytestring-error?</code> is raised.</p>
<pre class="example"><code>(bytevector->hex-string #u8"Ford") ⇒ "467f7264"
(hex-string->bytevector "5a6170686f64") ⇒ #u8"Zaphod"</code></pre>
<p><code>(bytevector->base64</code> <var>bytevector</var> [<var>digits</var>]<code>)</code><br>
<code>(base64->bytevector</code> <var>string</var> [<var>digits</var>]<code>)</code></p>
<p>Converts between a bytevector and its base-64 encoding as a string. The 64 digits are represented by the characters 0-9, A-Z, a-z, and the symbols + and /. However, there are different variants of base-64 encoding which use different representations of the 62nd and 63rd digit. If the optional argument <var>digits</var> (a two-character string) is provided, those two characters will be used as the 62nd and 63rd digit instead.
Details can be found in
<a href="https://tools.ietf.org/html/rfc4648">RFC 4648</a>.
If <var>string</var> is not in base-64 format, an error satisfying <code>bytestring-error?</code> is raised.
However, characters that satisfy <code>char-whitespace?</code>
are silently ignored.</p>
<pre class="example"><code>(bytevector->base64 #u8(1 2 3 4 5 6)) ⇒ "AQIDBAUG"
(bytevector->base64 #u8"Arthur Dent") ⇒ "QXJ0aHVyIERlbnQ="
(base64->bytevector "+/ /+") ⇒ #u8(#xfb #xff #xfe)</code></pre>
<p><code>(bytestring->list</code> <var>bytevector</var> [ <var>start</var> [ <var>end</var> ] ]<code>)</code></p>
<p>Converts all or part of a bytevector
into a list of the same length containing
characters for elements in the range 32 to 127
and exact integers for all other elements.</p>
<pre class="example"><code>(bytestring->list #u8(#x41 #x42 1 2) 1 3) ⇒ (#\B 1)</code></pre>
<p><code>(make-bytestring-generator</code> <var>arg</var> …<code>)</code></p>
<p>Returns a generator that when invoked will return consecutive bytes
of the bytevector that <code>bytestring</code> would create when applied
to <var>args</var>, but without creating any bytevectors.
The <var>args</var> are validated before any bytes are generated;
if they are ill-formed, an error satisfying
<code>bytestring-error?</code> is raised.</p>
<pre class="example"><code>(generator->list (make-bytestring-generator "lorem"))
⇒ (#x6c #x6f #x72 #x65 #x6d)</code></pre>
<h3>Selection</h3>
<p><code>(bytestring-pad</code> <var>bytevector len char-or-u8</var><code>)</code><br>
<code>(bytestring-pad-right</code> <var>bytevector len char-or-u8</var><code>)</code></p>
<p>Returns a newly allocated bytevector with the contents of <var>bytevector</var> plus sufficient additional bytes at the beginning/end containing <var>char-or-u8</var> (which can be either an ASCII character or an exact integer in the range 0-255) such that the length of the result is at least <var>len</var>.</p>
<pre class="example"><code>(bytestring-pad #u8"Zaphod" 10 #\_) ⇒ #u8"____Zaphod"
(bytestring-pad-right #u8(#x80 #x7f) 8 0) ⇒ #u8(#x80 #x7f 0 0 0 0 0 0)</code></pre>
<p><code>(bytestring-trim</code> <var>bytevector pred</var><code>)</code><br>
<code>(bytestring-trim-right</code> <var>bytevector pred</var><code>)</code><br>
<code>(bytestring-trim-both</code> <var>bytevector pred</var><code>)</code></p>
<p>Returns a newly allocated bytevector with the contents of <var>bytevector</var>, except that consecutive bytes at the beginning / the end / both the beginning and the end that satisfy <var>pred</var> are not included.</p>
<pre class="example"><code>(bytestring-trim #u8" Trillian" (lambda (b) (= b #x20)))
⇒ #u8"Trillian"
(bytestring-trim-both #u8(0 0 #x80 #x7f 0 0 0) zero?) ⇒ #u8(#x80 #x7f)</code></pre>
<h3>Replacement</h3>
<p><code>(bytestring-replace</code> <var>bytevector1 bytevector2 start1 end1 [start2 end2]</var><code>)</code></p>
<p>Returns a newly allocated bytevector with the contents of <var>bytevector1</var>, except that the bytes indexed by <var>start1</var> and <var>end1</var> are not included but are replaced by the bytes of <var>bytevector2</var> indexed by <var>start2</var> and <var>end2</var>.</p>
<pre class="example"><code>(bytestring-replace #u8"Vogon torture" #u8"poetry" 6 13)
⇒ #u8"Vogon poetry"</code></pre>
<h3>Comparison</h3>
<p id="errata-2">To compare bytevectors for equality, use the
procedure <code>bytevector=?</code> from
the R6RS library <code>(rnrs bytevectors)</code> or
<code>equal?</code> in R7RS.
<p><code>(bytestring<?</code> <var>bytevector1 bytevector2</var><code>)</code><br>
<code>(bytestring>?</code> <var>bytevector1 bytevector2</var><code>)</code><br>
<code>(bytestring<=?</code> <var>bytevector1 bytevector2</var><code>)</code><br>
<code>(bytestring>=?</code> <var>bytevector1 bytevector2</var><code>)</code></p>
<p>Returns <code>#t</code> if <var>bytevector1</var> is less than / greater than / less than or equal to / greater than or equal to <var>bytevector2</var>. Comparisons are lexicographical: shorter bytevectors compare before longer ones, all elements being equal.</p>
<pre class="example"><code>(bytestring<? #u8"Heart Of Gold" #u8"Heart of Gold") ⇒ #t
(bytestring<=? #u8(#x81 #x95) #u8(#x80 #xa0)) ⇒ #f
(bytestring>? #u8(1 2 3) #u8(1 2)) ⇒ #t
</code></pre>
<h3>Searching</h3>
<p><code>(bytestring-index</code> <var>bytevector pred</var> [<var>start</var> [<var>end</var>]]<code>)</code><br>
<code>(bytestring-index-right</code> <var>bytevector pred</var> [<var>start</var> [<var>end</var>]]<code>)</code></p>
<p>Searches <var>bytevector</var> from <var>start</var> to <var>end</var> / from <var>end</var> to <var>start</var> for the first byte that satisfies <var>pred</var>, and returns the index into <var>bytevector</var> containing that byte. In either direction, <var>start</var> is inclusive and <var>end</var> is exclusive. If there are no such bytes, returns <code>#f</code>.</p>
<pre class="example"><code>(bytestring-index #u8(#x65 #x72 #x83 #x6f) (lambda (b) (> b #x7f))) ⇒ 2
(bytestring-index #u8"Beeblebrox" (lambda (b) (> b #x7f))) ⇒ #f
(bytestring-index-right #u8"Zaphod" odd?) ⇒ 4
</code></pre>
<p><code>(bytestring-break</code> <var>bytevector pred</var><code>)</code><br>
<code>(bytestring-span</code> <var>bytevector pred</var><code>)</code></p>
<p>Returns two values, a bytevector containing the maximal sequence of characters (searching from the beginning of <var>bytevector</var> to the end) that do not satisfy / do satisfy <var>pred</var>, and another bytevector containing the remaining characters.</p>
<pre class="example"><code>(bytestring-break #u8(#x50 #x4b 0 0 #x1 #x5) zero?)
⇒ #u8(#x50 #x4b)
#u8(0 0 #x1 #x5)
(bytestring-span #u8"ABCDefg" (lambda (b) (and (> b 40) (< b 91))))
⇒ #u8"ABCD"
#u8"efg"
</code></pre>
<h3 id="joining-and-splitting">Joining and splitting</h3>
<p><code>(bytestring-join</code> <var>bytevector-list delimiter</var> [<var>grammar</var>]<code>)</code></p>
<p>Pastes the bytevectors in <var>bytevector-list</var> together
using the <var>delimiter</var>,
which can be anything suitable as an argument to <code>bytestring</code>.
The <var>grammar</var>
argument is a symbol that determines how the delimiter is used, and
defaults to <code>infix</code>. It is an error for grammar to be
any symbol other than these four:</p>
<ul>
<li><code>infix</code> means an infix or separator grammar: inserts the delimiter between list elements. An empty list will produce an empty bytevector.</li>
<li><code>strict-infix</code> means the same as <code>infix</code> if the list is non-empty, but will signal an error satisfying <code>bytestring-error?</code> if given an empty list.</li>
<li><code>suffix</code> means a suffix or terminator grammar: inserts the delimiter after every list element.</li>
<li><code>prefix</code> means a prefix grammar: inserts the delimiter before every list element.</li>
</ul>
<pre class="example"><code>(bytestring-join '(#u8"Heart" #u8"of" #u8"Gold") #x20) ⇒ #u8"Heart of Gold"
(bytestring-join '(#u8(#xef #xbb) #u8(#xbf)) 0 'prefix) ⇒ #u8(0 #xef #xbb 0 #xbf)
(bytestring-join '() 0 'strict-infix) ⇒</code> <em>error</em></pre>
<p><code>(bytestring-split</code> <var>bytevector delimiter</var> [<var>grammar</var>]<code>)</code></p>
<p>Divides the elements of <var>bytevector</var> and returns a list of newly allocated bytevectors using the <var>delimiter</var> (an ASCII character or exact integer in the range 0-255 inclusive). Delimiter bytes are not included in the result bytevectors.</p>
<p>The <var>grammar</var> argument is used to control how <var>bytevector</var> is divided. It has the same default and meaning as in <code>bytestring-join</code>, except that <code>infix</code> and <code>strict-infix</code> mean the same thing. That is, if <var>grammar</var> is <code>prefix</code> or <code>suffix</code>, then ignore any delimiter in the first or last position of <var>bytevector</var> respectively.</p>
<pre class="example"><code>(bytestring-split #u8"Beeblebrox" #x62) ⇒ (#u8"Bee" #u8"le" #u8"rox")
(bytestring-split #u8(1 0 2 0) 0 'suffix) ⇒ (#u8(1) #u8(2))
</code></pre>
<h3>I/O</h3>
<code>(read-textual-bytestring</code> <var>prefix</var> [ <var>port</var> ]<code>)</code>
<p>Reads a string in the external format described in this SRFI
from <var>port</var> and return it as a bytevector.
If the <var>prefix</var> argument is false, this procedure assumes
that "<code>#u8</code>" has already been read from <var>port</var>.
If <var>port</var> is omitted, it defaults to the value of <code>(current-input-port)</code>.
If the characters read are not in the external format,
an error satisfying <code>bytestring-error?</code> is raised.</p>
<pre class="example"><code>(call-with-port (open-input-string "#u8\"AB\\xad;\\xf0;\\x0d;CD\"")
(lambda (port)
(read-textual-bytestring #t port)))
⇒ #u8(#x41 #x42 #xad #xf0 #x0d #x43 #x44)
</code></pre>
<p><code>(write-textual-bytestring</code> <var>bytevector</var> [ <var>port</var> ]<code>)</code></p>
<p>Writes <var>bytevector</var> in the external format described in this SRFI to <var>port</var>.
Bytes representing non-graphical ASCII characters are unencoded:
all other bytes are encoded with a single letter if possible,
otherwise with a <code>\x</code> escape.
If <var>port</var> is omitted, it defaults to the value of <code>(current-output-port)</code>.</p>
<pre class="example"><code>(call-with-port (open-output-string)
(lambda (port)
(write-textual-bytestring
#u8(#x9 #x41 #x72 #x74 #x68 #x75 #x72 #xa)
port)
(get-output-string port)))
⇒ "#u8\"\\tArthur\\n\""
</code></pre>
<p><code>(write-binary-bytestring</code> <var>port arg</var> …<code>)</code></p>
<p>Outputs each <var>arg</var> to the binary output port <var>port</var>
using the same interpretations as <code>bytestring</code>,
but without creating any bytevectors.
The <var>args</var> are validated before any bytes are written to
<var>port</var>; if they are ill-formed, an error satisfying
<code>bytestring-error?</code> is raised.</p>
<pre class="example"><code>(call-with-port (open-output-bytevector)
(lambda (port)
(write-binary-bytestring port #\Z #x61 #x70 "hod")
(get-output-bytevector port)))
⇒ #u8"Zaphod"
</code></pre>
<h3>Exception</h3>
<p><code>(bytestring-error?</code> <var>obj</var><code>)</code></p>
<p>Returns <code>#t</code> if <var>obj</var> is an object signaled by any of the
following procedures, in the circumstances described above:</p>
<ul>
<li><code>bytestring</code></li>
<li><code>hex-string->bytestring</code></li>
<li><code>base64->bytestring</code></li>
<li><code>make-bytestring</code></li>
<li><code>make-bytestring!</code></li>
<li><code>bytestring-join</code></li>
<li><code>read-textual-bytestring</code></li>
<li><code>write-binary-bytestring</code></li>
<li><code>make-bytestring-generator</code></li>
</ul>
<h2 id="implementation">Implementation</h2>
<p>There is a sample implementation of the procedures,
but not the notation, in the repository of this SRFI.
<h2 id="acknowledgements">Acknowledgements</h2>
<p>Daphne Preston-Kendal devised the string notation for bytevectors; John Cowan, the procedure library; Wolfgang Corcoran-Mathe, the sample implementation of the procedures.
<p>The notation is inspired by the notation used in Python since version 2.6 for <code>bytes</code> objects, which are fundamentally similar in purpose to Scheme bytevectors, especially in R7RS. In addition, many of the procedures are closely analogous to those of <a href="https://srfi.schemers.org/srfi-152/srfi-152.html">SRFI 152</a>.
<p>Thanks is also due to the participants in the SRFI mailing list. In particular: Lassi Kortela corrected an embarrassing technical error; Marc Nieper-Wißkirchen explained why the <code>write</code> procedure ought not to be allowed to use this notation by default.
<h2 id="copyright">Copyright</h2>
<p>© 2020 Daphne Preston-Kendal, John Cowan, and Wolfgang Corcoran-Mathe.</p>
<p>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:</p>
<p>
The above copyright notice and this permission notice (including the
next paragraph) shall be included in all copies or substantial
portions of the Software.</p>
<p>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.</p>
<hr>
<address>Editor: <a href="mailto:srfi-editors+at+srfi+dot+schemers+dot+org">Arthur A. Gleckler</a></address></body></html>