201 lines
11 KiB
HTML
201 lines
11 KiB
HTML
|
<!DOCTYPE html>
|
||
|
<html>
|
||
|
<!-- Created by GNU Texinfo 7.1, https://www.gnu.org/software/texinfo/ -->
|
||
|
<head>
|
||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||
|
<!-- This manual documents Guile version 3.0.10.
|
||
|
|
||
|
Copyright (C) 1996-1997, 2000-2005, 2009-2023 Free Software Foundation,
|
||
|
Inc.
|
||
|
|
||
|
Copyright (C) 2021 Maxime Devos
|
||
|
|
||
|
Copyright (C) 2024 Tomas Volf
|
||
|
|
||
|
|
||
|
Permission is granted to copy, distribute and/or modify this document
|
||
|
under the terms of the GNU Free Documentation License, Version 1.3 or
|
||
|
any later version published by the Free Software Foundation; with no
|
||
|
Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
|
||
|
copy of the license is included in the section entitled "GNU Free
|
||
|
Documentation License." -->
|
||
|
<title>Custom Ports (Guile Reference Manual)</title>
|
||
|
|
||
|
<meta name="description" content="Custom Ports (Guile Reference Manual)">
|
||
|
<meta name="keywords" content="Custom Ports (Guile Reference Manual)">
|
||
|
<meta name="resource-type" content="document">
|
||
|
<meta name="distribution" content="global">
|
||
|
<meta name="Generator" content=".texi2any-real">
|
||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
|
|
||
|
<link href="index.html" rel="start" title="Top">
|
||
|
<link href="Concept-Index.html" rel="index" title="Concept Index">
|
||
|
<link href="index.html#SEC_Contents" rel="contents" title="Table of Contents">
|
||
|
<link href="Port-Types.html" rel="up" title="Port Types">
|
||
|
<link href="Soft-Ports.html" rel="next" title="Soft Ports">
|
||
|
<link href="String-Ports.html" rel="prev" title="String Ports">
|
||
|
<style type="text/css">
|
||
|
<!--
|
||
|
a.copiable-link {visibility: hidden; text-decoration: none; line-height: 0em}
|
||
|
div.example {margin-left: 3.2em}
|
||
|
span:hover a.copiable-link {visibility: visible}
|
||
|
strong.def-name {font-family: monospace; font-weight: bold; font-size: larger}
|
||
|
-->
|
||
|
</style>
|
||
|
<link rel="stylesheet" type="text/css" href="https://www.gnu.org/software/gnulib/manual.css">
|
||
|
|
||
|
|
||
|
</head>
|
||
|
|
||
|
<body lang="en">
|
||
|
<div class="subsubsection-level-extent" id="Custom-Ports">
|
||
|
<div class="nav-panel">
|
||
|
<p>
|
||
|
Next: <a href="Soft-Ports.html" accesskey="n" rel="next">Soft Ports</a>, Previous: <a href="String-Ports.html" accesskey="p" rel="prev">String Ports</a>, Up: <a href="Port-Types.html" accesskey="u" rel="up">Types of Port</a> [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html" title="Index" rel="index">Index</a>]</p>
|
||
|
</div>
|
||
|
<hr>
|
||
|
<h4 class="subsubsection" id="Custom-Ports-1"><span>6.12.10.4 Custom Ports<a class="copiable-link" href="#Custom-Ports-1"> ¶</a></span></h4>
|
||
|
|
||
|
<p>Custom ports allow the user to provide input and handle output via
|
||
|
user-supplied procedures. The most basic of these operates on the level
|
||
|
of bytes, calling user-supplied functions to supply bytes for input and
|
||
|
accept bytes for output. In Guile, textual ports are built on top of
|
||
|
binary ports, encoding and decoding their codepoint sequences from the
|
||
|
bytes; the higher-level textual layer for custom ports allows users to
|
||
|
deal in characters instead of bytes.
|
||
|
</p>
|
||
|
<p>Before using these procedures, import the appropriate module:
|
||
|
</p>
|
||
|
<div class="example">
|
||
|
<pre class="example-preformatted">(use-modules (ice-9 binary-ports))
|
||
|
(use-modules (ice-9 textual-ports))
|
||
|
</pre></div>
|
||
|
|
||
|
<a class="index-entry-id" id="index-custom-binary-input-ports"></a>
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-make_002dcustom_002dbinary_002dinput_002dport"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">make-custom-binary-input-port</strong> <var class="def-var-arguments">id read! get-position set-position! close</var><a class="copiable-link" href="#index-make_002dcustom_002dbinary_002dinput_002dport"> ¶</a></span></dt>
|
||
|
<dd><p>Return a new custom binary input port named <var class="var">id</var> (a string) whose
|
||
|
input is drained by invoking <var class="var">read!</var> and passing it a bytevector, an
|
||
|
index where bytes should be written, and the number of bytes to read.
|
||
|
The <code class="code">read!</code> procedure must return an integer indicating the number
|
||
|
of bytes read, or <code class="code">0</code> to indicate the end-of-file.
|
||
|
</p>
|
||
|
<p>Optionally, if <var class="var">get-position</var> is not <code class="code">#f</code>, it must be a thunk
|
||
|
that will be called when <code class="code">port-position</code> is invoked on the custom
|
||
|
binary port and should return an integer indicating the position within
|
||
|
the underlying data stream; if <var class="var">get-position</var> was not supplied, the
|
||
|
returned port does not support <code class="code">port-position</code>.
|
||
|
</p>
|
||
|
<p>Likewise, if <var class="var">set-position!</var> is not <code class="code">#f</code>, it should be a
|
||
|
one-argument procedure. When <code class="code">set-port-position!</code> is invoked on the
|
||
|
custom binary input port, <var class="var">set-position!</var> is passed an integer
|
||
|
indicating the position of the next byte is to read.
|
||
|
</p>
|
||
|
<p>Finally, if <var class="var">close</var> is not <code class="code">#f</code>, it must be a thunk. It is
|
||
|
invoked when the custom binary input port is closed.
|
||
|
</p>
|
||
|
<p>The returned port is fully buffered by default, but its buffering mode
|
||
|
can be changed using <code class="code">setvbuf</code> (see <a class="pxref" href="Buffering.html">Buffering</a>).
|
||
|
</p>
|
||
|
<p>Using a custom binary input port, the <code class="code">open-bytevector-input-port</code>
|
||
|
procedure (see <a class="pxref" href="Bytevector-Ports.html">Bytevector Ports</a>) could be implemented as follows:
|
||
|
</p>
|
||
|
<div class="example lisp">
|
||
|
<pre class="lisp-preformatted">(define (open-bytevector-input-port source)
|
||
|
(define position 0)
|
||
|
(define length (bytevector-length source))
|
||
|
|
||
|
(define (read! bv start count)
|
||
|
(let ((count (min count (- length position))))
|
||
|
(bytevector-copy! source position
|
||
|
bv start count)
|
||
|
(set! position (+ position count))
|
||
|
count))
|
||
|
|
||
|
(define (get-position) position)
|
||
|
|
||
|
(define (set-position! new-position)
|
||
|
(set! position new-position))
|
||
|
|
||
|
(make-custom-binary-input-port "the port" read!
|
||
|
get-position set-position!
|
||
|
#f))
|
||
|
|
||
|
(read (open-bytevector-input-port (string->utf8 "hello")))
|
||
|
⇒ hello
|
||
|
</pre></div>
|
||
|
</dd></dl>
|
||
|
|
||
|
<a class="index-entry-id" id="index-custom-binary-output-ports"></a>
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-make_002dcustom_002dbinary_002doutput_002dport"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">make-custom-binary-output-port</strong> <var class="def-var-arguments">id write! get-position set-position! close</var><a class="copiable-link" href="#index-make_002dcustom_002dbinary_002doutput_002dport"> ¶</a></span></dt>
|
||
|
<dd><p>Return a new custom binary output port named <var class="var">id</var> (a string) whose
|
||
|
output is sunk by invoking <var class="var">write!</var> and passing it a bytevector, an
|
||
|
index where bytes should be read from this bytevector, and the number of
|
||
|
bytes to be “written”. The <code class="code">write!</code> procedure must return an
|
||
|
integer indicating the number of bytes actually written; when it is
|
||
|
passed <code class="code">0</code> as the number of bytes to write, it should behave as
|
||
|
though an end-of-file was sent to the byte sink.
|
||
|
</p>
|
||
|
<p>The other arguments are as for <code class="code">make-custom-binary-input-port</code>.
|
||
|
</p></dd></dl>
|
||
|
|
||
|
<a class="index-entry-id" id="index-custom-binary-input_002foutput-ports"></a>
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-make_002dcustom_002dbinary_002dinput_002foutput_002dport"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">make-custom-binary-input/output-port</strong> <var class="def-var-arguments">id read! write! get-position set-position! close</var><a class="copiable-link" href="#index-make_002dcustom_002dbinary_002dinput_002foutput_002dport"> ¶</a></span></dt>
|
||
|
<dd><p>Return a new custom binary input/output port named <var class="var">id</var> (a string).
|
||
|
The various arguments are the same as for The other arguments are as for
|
||
|
<code class="code">make-custom-binary-input-port</code> and
|
||
|
<code class="code">make-custom-binary-output-port</code>. If buffering is enabled on the
|
||
|
port, as is the case by default, input will be buffered in both
|
||
|
directions; See <a class="xref" href="Buffering.html">Buffering</a>. If the <var class="var">set-position!</var> function is
|
||
|
provided and not <code class="code">#f</code>, then the port will also be marked as
|
||
|
random-access, causing the buffer to be flushed between reads and
|
||
|
writes.
|
||
|
</p></dd></dl>
|
||
|
|
||
|
<a class="index-entry-id" id="index-custom-textual-ports"></a>
|
||
|
<a class="index-entry-id" id="index-custom-textual-input-ports"></a>
|
||
|
<a class="index-entry-id" id="index-custom-textual-output-ports"></a>
|
||
|
<a class="index-entry-id" id="index-custom-textual-input_002foutput-ports"></a>
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-make_002dcustom_002dtextual_002dinput_002dport"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">make-custom-textual-input-port</strong> <var class="def-var-arguments">id read! get-position set-position! close</var><a class="copiable-link" href="#index-make_002dcustom_002dtextual_002dinput_002dport"> ¶</a></span></dt>
|
||
|
<dt class="deffnx def-cmd-deffn" id="index-make_002dcustom_002dtextual_002doutput_002dport"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">make-custom-textual-output-port</strong> <var class="def-var-arguments">id write! get-position set-position! close</var><a class="copiable-link" href="#index-make_002dcustom_002dtextual_002doutput_002dport"> ¶</a></span></dt>
|
||
|
<dt class="deffnx def-cmd-deffn" id="index-make_002dcustom_002dtextual_002dinput_002foutput_002dport"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">make-custom-textual-input/output-port</strong> <var class="def-var-arguments">id read! write! get-position set-position! close</var><a class="copiable-link" href="#index-make_002dcustom_002dtextual_002dinput_002foutput_002dport"> ¶</a></span></dt>
|
||
|
<dd><p>Like their custom binary port counterparts, but for textual ports.
|
||
|
Concretely this means that instead of being passed a bytevector, the
|
||
|
<var class="var">read</var> function is passed a mutable string to fill, and likewise for
|
||
|
the buffer supplied to <var class="var">write</var>. Port positions are still expressed
|
||
|
in bytes, however.
|
||
|
</p>
|
||
|
<p>If string ports were not supplied with Guile, we could implement them
|
||
|
With custom textual ports:
|
||
|
</p><div class="example">
|
||
|
<pre class="example-preformatted">(define (open-string-input-port source)
|
||
|
(define position 0)
|
||
|
(define length (string-length source))
|
||
|
|
||
|
(define (read! dst start count)
|
||
|
(let ((count (min count (- length position))))
|
||
|
(string-copy! dst start source position (+ position count))
|
||
|
(set! position (+ position count))
|
||
|
count))
|
||
|
|
||
|
(make-custom-textual-input-port "strport" read! #f #f #f))
|
||
|
|
||
|
(read (open-string-input-port "hello"))
|
||
|
</pre></div>
|
||
|
</dd></dl>
|
||
|
|
||
|
</div>
|
||
|
<hr>
|
||
|
<div class="nav-panel">
|
||
|
<p>
|
||
|
Next: <a href="Soft-Ports.html">Soft Ports</a>, Previous: <a href="String-Ports.html">String Ports</a>, Up: <a href="Port-Types.html">Types of Port</a> [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html" title="Index" rel="index">Index</a>]</p>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
|
||
|
</body>
|
||
|
</html>
|