370 lines
279 KiB
HTML
370 lines
279 KiB
HTML
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||
|
<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"/><meta name="viewport" content="width=device-width, initial-scale=0.8"/><title>13.1.9 Custom Ports</title><link rel="stylesheet" type="text/css" href="../scribble.css" title="default"/><link rel="stylesheet" type="text/css" href="extras.css" title="default"/><link rel="stylesheet" type="text/css" href="../racket.css" title="default"/><link rel="stylesheet" type="text/css" href="../manual-style.css" title="default"/><link rel="stylesheet" type="text/css" href="../manual-racket.css" title="default"/><link rel="stylesheet" type="text/css" href="../manual-racket.css" title="default"/><link rel="stylesheet" type="text/css" href="../doc-site.css" title="default"/><script type="text/javascript" src="../scribble-common.js"></script><script type="text/javascript" src="../manual-racket.js"></script><script type="text/javascript" src="../manual-racket.js"></script><script type="text/javascript" src="../doc-site.js"></script><script type="text/javascript" src="../local-redirect/local-redirect.js"></script><script type="text/javascript" src="../local-redirect/local-user-redirect.js"></script><!--[if IE 6]><style type="text/css">.SIEHidden { overflow: hidden; }</style><![endif]--></head><body id="doc-racket-lang-org"><div class="tocset"><div class="tocview"><div class="tocviewlist tocviewlisttopspace"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,"tocview_0");">►</a></td><td></td><td><a href="index.html" class="tocviewlink" data-pltdoc="x">The Racket Reference</a></td></tr></table></div><div class="tocviewsublisttop" style="display: none;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1 </td><td><a href="model.html" class="tocviewlink" data-pltdoc="x">Language Model</a></td></tr><tr><td align="right">2 </td><td><a href="notation.html" class="tocviewlink" data-pltdoc="x">Notation for Documentation</a></td></tr><tr><td align="right">3 </td><td><a href="syntax.html" class="tocviewlink" data-pltdoc="x">Syntactic Forms</a></td></tr><tr><td align="right">4 </td><td><a href="data.html" class="tocviewlink" data-pltdoc="x">Datatypes</a></td></tr><tr><td align="right">5 </td><td><a href="structures.html" class="tocviewlink" data-pltdoc="x">Structures</a></td></tr><tr><td align="right">6 </td><td><a href="mzlib_class.html" class="tocviewlink" data-pltdoc="x">Classes and Objects</a></td></tr><tr><td align="right">7 </td><td><a href="mzlib_unit.html" class="tocviewlink" data-pltdoc="x">Units</a></td></tr><tr><td align="right">8 </td><td><a href="contracts.html" class="tocviewlink" data-pltdoc="x">Contracts</a></td></tr><tr><td align="right">9 </td><td><a href="match.html" class="tocviewlink" data-pltdoc="x">Pattern Matching</a></td></tr><tr><td align="right">10 </td><td><a href="control.html" class="tocviewlink" data-pltdoc="x">Control Flow</a></td></tr><tr><td align="right">11 </td><td><a href="concurrency.html" class="tocviewlink" data-pltdoc="x">Concurrency and Parallelism</a></td></tr><tr><td align="right">12 </td><td><a href="Macros.html" class="tocviewlink" data-pltdoc="x">Macros</a></td></tr><tr><td align="right">13 </td><td><a href="input-and-output.html" class="tocviewselflink" data-pltdoc="x">Input and Output</a></td></tr><tr><td align="right">14 </td><td><a href="security.html" class="tocviewlink" data-pltdoc="x">Reflection and Security</a></td></tr><tr><td align="right">15 </td><td><a href="os.html" class="tocviewlink" data-pltdoc="x">Operating System</a></td></tr><tr><td align="right">16 </td><td><a href="memory.html" class="tocviewlink" data-pltdoc="x">Memory Management</a></td></tr><tr><td align="right">17 </td><td><a href="unsafe.html" class="tocviewlink" data-pltdoc="x">Unsafe Operations</a></td></tr><tr><td align="right">18 </td><td><a href="running.html" class="to
|
||
|
create <a name="(tech._custom._port)"></a><span style="font-style: italic">custom ports</span> with arbitrary control procedures (much like
|
||
|
implementing a device driver). Custom ports are mainly useful to
|
||
|
obtain fine control over the action of committing bytes as read or
|
||
|
written.</p><p><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" cellpadding="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><table cellspacing="0" cellpadding="0" class="prototype RForeground"><tr><td valign="top"><span class="RktPn">(</span><a name="(def._((quote._~23~25kernel)._make-input-port))"></a><span title="Provided from: racket/base, racket | Package: base"><span class="RktSym"><a href="customport.html#%28def._%28%28quote._~23~25kernel%29._make-input-port%29%29" class="RktValDef RktValLink" data-pltdoc="x">make-input-port</a></span></span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="RktVar">name</span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td></tr><tr><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="RktVar">read-in</span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td></tr><tr><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="RktVar">peek</span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td></tr><tr><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="RktVar">close</span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td></tr><tr><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span><span class="RktOpt">[</span></td><td valign="top"><span class="RktVar">get-progress-evt</span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td></tr><tr><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="RktVar">commit</span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td></tr><tr><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="RktVar">get-location</span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td></tr><tr><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="RktVar">count-lines!</span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td></tr><tr><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="hspace"> </span></td><td valign="top"><span class="RktVar">init-position</span></td><td valign="top"
|
||
|
<span class="RktVar">close</span> procedure has no side effects, then the port need not
|
||
|
be explicitly closed. See also <span class="RktSym"><a href="port-lib.html#%28def._%28%28lib._racket%2Fport..rkt%29._make-input-port%2Fread-to-peek%29%29" class="RktValLink" data-pltdoc="x">make-input-port/read-to-peek</a></span>.</div></p><p>The arguments implement the port as follows:</p><ul><li><p><span class="RktVar">name</span> —<wbr></wbr> the name for the input port.</p></li><li><p><div class="SIntrapara"><span class="RktVar">read-in</span> —<wbr></wbr> either an input port, in which case reads
|
||
|
are redirected to the given port, or a procedure that takes a single
|
||
|
argument:
|
||
|
a mutable byte string to receive read bytes. The procedure’s
|
||
|
result is one of the following:
|
||
|
</div><div class="SIntrapara"><ul><li><p>the number of bytes read, as an exact, non-negative integer;</p></li><li><p><span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span>;</p></li><li><p>a procedure of arity four (representing a “special”
|
||
|
result, as discussed <a href="customport.html#%28elem._special%29" data-pltdoc="x">further below</a>),
|
||
|
but a procedure result is allowed only
|
||
|
when <span class="RktVar">peek</span> is not <span class="RktVal">#f</span>;</p></li><li><p>a <a href="pipeports.html#%28tech._pipe%29" data-pltdoc="x">pipe</a> input port that supplies bytes to be
|
||
|
used as long as the pipe has content (see
|
||
|
<span class="RktSym"><a href="pipeports.html#%28def._%28%28quote._~23~25kernel%29._pipe-content-length%29%29" class="RktValLink" data-pltdoc="x">pipe-content-length</a></span>) or until <span class="RktVar">read-in</span> or
|
||
|
<span class="RktVar">peek</span> is called again; or</p></li><li><p>a <a href="sync.html#%28tech._synchronizable._event%29" class="techoutside" data-pltdoc="x"><span class="techinside">synchronizable event</span></a> (see <a href="sync.html" data-pltdoc="x">Events</a>) other
|
||
|
than a pipe input port or procedure of arity four; the event
|
||
|
becomes ready when the read is complete (roughly): the event’s
|
||
|
value can be one of the above four results or another event like
|
||
|
itself; in the last case, a reading process loops with
|
||
|
<span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._sync%29%29" class="RktValLink" data-pltdoc="x">sync</a></span> until it gets a non-event result.</p></li></ul></div></p><p>The <span class="RktVar">read-in</span> procedure must not block indefinitely. If no
|
||
|
bytes are immediately available for reading, the <span class="RktVar">read-in</span>
|
||
|
must return <span class="RktVal">0</span> or an event, and preferably an event (to
|
||
|
avoid busy waits). The <span class="RktVar">read-in</span> should not return
|
||
|
<span class="RktVal">0</span> (or an event whose value is <span class="RktVal">0</span>) when data is
|
||
|
available in the port, otherwise polling the port will behave
|
||
|
incorrectly. An event result from an event can also break polling.</p><p>If the result of a <span class="RktVar">read-in</span> call is not one of the above
|
||
|
values, the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised. If a returned integer is
|
||
|
larger than the supplied byte string’s length, the
|
||
|
<span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised. If <span class="RktVar">peek</span> is <span class="RktVal">#f</span> and
|
||
|
a procedure for a <a href="customport.html#%28elem._special%29" data-pltdoc="x">special</a> result is returned,
|
||
|
the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised.</p><p>The <span class="RktVar">read-in</span> procedure can report an error by raising an
|
||
|
exception, but only if no bytes are read. Similarly, no bytes
|
||
|
should be read if <span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span>, an event, or a procedure is
|
||
|
returned. In other words, no bytes should be lost due to spurious
|
||
|
exceptions or non-byte data.</p><p>A port’s reading procedure may be called in multiple threads
|
||
|
simultaneously (if the port is accessible in multiple threads),
|
||
|
and the port is responsible for its own internal
|
||
|
synchronization. Note that improper implementation of such
|
||
|
synchronization mechanisms might cause a non-blocking read
|
||
|
procedure to block indefinitely.</p><p>If the result is a pipe input port, then previous
|
||
|
<span class="RktVar">get-progress-evt</span> calls whose event is not yet ready must
|
||
|
have been the pipe input port itself. Furthermore,
|
||
|
<span class="RktVar">get-progress-evt</span> must continue to return the pipe as long
|
||
|
as it contains data, or until the <span class="RktVar">read-in</span> or
|
||
|
<span class="RktSym">peek-in</span> procedure is called again (instead of using the
|
||
|
pipe, for whatever reason). If <span class="RktVar">read-in</span> or
|
||
|
<span class="RktSym">peek-in</span> is called, any previously associated pipe (as
|
||
|
returned by a previous call) is disassociated from the
|
||
|
port and is not in use by any other thread as a result of the
|
||
|
previous association.</p><p>If <span class="RktVar">peek</span>, <span class="RktVar">get-progress-evt</span>, and
|
||
|
<span class="RktVar">commit</span> are all provided and
|
||
|
non-<span class="RktVal">#f</span>, then the following is an acceptable implementation
|
||
|
of <span class="RktVar">read-in</span>:</p><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">bstr</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="let.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._let%2A%29%29" class="RktStxLink" data-pltdoc="x">let*</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktPn">[</span><span class="RktSym">progress-evt</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktVar">get-progress-evt</span><span class="RktPn">)</span><span class="RktPn">]</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">[</span><span class="RktSym">v</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktVar">peek</span><span class="hspace"> </span><span class="RktSym">bstr</span><span class="hspace"> </span><span class="RktVal">0</span><span class="hspace"> </span><span class="RktSym">progress-evt</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="if.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._cond%29%29" class="RktStxLink" data-pltdoc="x">cond</a></span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._sync%2Ftimeout%29%29" class="RktValLink" data-pltdoc="x">sync/timeout</a></span><span class="hspace"> </span><span class="RktVal">0</span><span class="hspace"> </span><span class="RktSym">progress-evt</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">]</span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">try again</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._evt~3f%29%29" class="RktValLink" data-pltdoc="x">evt?</a></span><span class="hspace"> </span><span class="RktSym">v</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._wrap-evt%29%29" class="RktValLink" data-pltdoc="x">wrap-evt</a></span><span class="hspace"> </span><span class="RktSym">v</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">x</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">0</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">]</span><span class="hspace"> </span><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">sync, try again</span></td></tr><tr><td><span class="hspace"> </span><span class="RktPn">[</span><span class="RktPn">(</span><span class="RktSym"><a href="if.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._and%29%29" class="RktStxLink" data-pltdoc="x">and</a></span><span class="hspace"> </span><span class="RktPn">(</span><sp
|
||
|
<span class="RktVar">get-progress-evt</span>, and <span class="RktVar">commit</span>
|
||
|
procedures, however, and even an implementor who does supply
|
||
|
them may provide a different <span class="RktVar">read-in</span>
|
||
|
that uses a fast path for non-blocking reads.</p><p>In an input port is provided for <span class="RktVar">read-in</span>, then an input port
|
||
|
must also be provided for <span class="RktVar">peek</span>.</p></li><li><p><span class="RktVar">peek</span> —<wbr></wbr> either <span class="RktVal">#f</span>, an input port (in which
|
||
|
case peeks are redirected to the given port), or a procedure
|
||
|
that takes three arguments:</p><ul><li><p>a mutable byte string to receive peeked bytes;</p></li><li><p>a non-negative number of bytes (or
|
||
|
<a href="customport.html#%28elem._special%29" data-pltdoc="x">specials</a>) to skip before peeking; and</p></li><li><p>either <span class="RktVal">#f</span> or a progress event produced by
|
||
|
<span class="RktVar">get-progress-evt</span>.</p></li></ul><p>The results and conventions for <span class="RktVar">peek</span> are mostly the same
|
||
|
as for <span class="RktVar">read-in</span>. The main difference is in the handling of
|
||
|
the progress event, if it is not <span class="RktVal">#f</span>. If the given
|
||
|
progress event becomes ready, the <span class="RktVar">peek</span> must abort any
|
||
|
skip attempts and not peek any values. In particular,
|
||
|
<span class="RktVar">peek</span> must not peek any values if the progress event is
|
||
|
initially ready. If the port has been closed, the progress event
|
||
|
should be ready, in which case <span class="RktVar">peek</span> should complete
|
||
|
(instead of failing because the port is closed).</p><p>Unlike <span class="RktVar">read-in</span>, <span class="RktVar">peek</span> should produce
|
||
|
<span class="RktVal">#f</span> (or an event whose value is <span class="RktVal">#f</span>) if no bytes
|
||
|
were peeked because the progress event became ready. Like
|
||
|
<span class="RktVar">read-in</span>, a <span class="RktVal">0</span> result indicates that another
|
||
|
attempt is likely to succeed, so <span class="RktVal">0</span> is inappropriate when
|
||
|
the progress event is ready. Also like <span class="RktVar">read-in</span>,
|
||
|
<span class="RktVar">peek</span> must not block indefinitely.</p><p>The skip count provided to <span class="RktVar">peek</span> is a number of bytes (or
|
||
|
<a href="customport.html#%28elem._special%29" data-pltdoc="x">specials</a>) that must remain present in the
|
||
|
port—<wbr></wbr>in addition to the peek results—<wbr></wbr>when the peek results are
|
||
|
reported. If the skip count requests reading data that is past an eof,
|
||
|
it should not, and instead produce <span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span> (until the eof is
|
||
|
consumed).</p><p>If a progress event is supplied, then the peek is
|
||
|
effectively canceled when another process reads data before the
|
||
|
given number can be skipped. If a progress event is not supplied
|
||
|
and data is read, then the peek must effectively restart with the
|
||
|
original skip count.</p><p>The system does not check that multiple peeks return consistent
|
||
|
results, or that peeking and reading produce consistent results,
|
||
|
although they must.</p><p>If <span class="RktVar">peek</span> is <span class="RktVal">#f</span>, then peeking for the port is
|
||
|
implemented automatically in terms of reads, but with several
|
||
|
limitations. First, the automatic implementation is not
|
||
|
thread-safe. Second, the automatic implementation cannot handle
|
||
|
<a href="customport.html#%28elem._special%29" data-pltdoc="x">special</a> results (non-byte and non-eof), so
|
||
|
<span class="RktVar">read-in</span> cannot return a procedure for a
|
||
|
<a href="customport.html#%28elem._special%29" data-pltdoc="x">special</a> when <span class="RktVar">peek</span> is
|
||
|
<span class="RktVal">#f</span>. Finally, the automatic peek implementation is
|
||
|
incompatible with progress events, so if <span class="RktVar">peek</span> is
|
||
|
<span class="RktVal">#f</span>, then <span class="RktVar">get-progress-evt</span> and <span class="RktVar">commit</span> must
|
||
|
be <span class="RktVal">#f</span>. See also <span class="RktSym"><a href="port-lib.html#%28def._%28%28lib._racket%2Fport..rkt%29._make-input-port%2Fread-to-peek%29%29" class="RktValLink" data-pltdoc="x">make-input-port/read-to-peek</a></span>,
|
||
|
which implements peeking in terms of <span class="RktVar">read-in</span> without
|
||
|
these constraints.</p><p>In an input port is provided for <span class="RktVar">peek</span>, then an input port
|
||
|
must also be provided for <span class="RktVar">read-in</span>.</p></li><li><p><span class="RktVar">close</span> —<wbr></wbr> a procedure of zero arguments that is
|
||
|
called to close the port. The port is not considered closed until
|
||
|
the closing procedure returns. The port’s procedures will never be
|
||
|
used again via the port after it is closed. However, the closing
|
||
|
procedure can be called simultaneously in multiple threads (if the
|
||
|
port is accessible in multiple threads), and it may be called
|
||
|
during a call to the other procedures in another thread; in the
|
||
|
latter case, any outstanding reads and peeks should be terminated
|
||
|
with an error.</p></li><li><p><span class="RktVar">get-progress-evt</span> —<wbr></wbr> either <span class="RktVal">#f</span> (the
|
||
|
default), or a procedure that takes no arguments and returns an
|
||
|
event. The event must become ready only after data is next read
|
||
|
from the port or the port is closed. If the port is already closed,
|
||
|
the event must be ready. After the event becomes
|
||
|
ready, it must remain so. See the description of <span class="RktVar">read-in</span>
|
||
|
for information about the allowed results of this function when
|
||
|
<span class="RktVar">read-in</span> returns a pipe input port. See also
|
||
|
<span class="RktSym"><a href="semaphore.html#%28def._%28%28quote._~23~25kernel%29._semaphore-peek-evt%29%29" class="RktValLink" data-pltdoc="x">semaphore-peek-evt</a></span>, which is sometimes useful for
|
||
|
implementing <span class="RktVar">get-progress-evt</span>.</p><p>If <span class="RktVar">get-progress-evt</span> is <span class="RktVal">#f</span>, then
|
||
|
<span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._port-provides-progress-evts~3f%29%29" class="RktValLink" data-pltdoc="x">port-provides-progress-evts?</a></span> applied to the port will
|
||
|
produce <span class="RktVal">#f</span>, and the port will not be a valid argument to
|
||
|
<span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._port-progress-evt%29%29" class="RktValLink" data-pltdoc="x">port-progress-evt</a></span>.</p><p>The result event will not be exposed directly by
|
||
|
<span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._port-progress-evt%29%29" class="RktValLink" data-pltdoc="x">port-progress-evt</a></span>. Instead, it will be wrapped in an
|
||
|
event for which <span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._progress-evt~3f%29%29" class="RktValLink" data-pltdoc="x">progress-evt?</a></span> returns true.</p></li><li><p><span class="RktVar">commit</span> —<wbr></wbr> either <span class="RktVal">#f</span> (the
|
||
|
default), or a procedure that takes three arguments:</p><ul><li><p>an exact, positive integer <span style="font-style: italic">k</span><span style="vertical-align: sub; font-size: 80%"><span style="font-style: italic">r</span></span><span style="font-style: italic"></span>;</p></li><li><p>a progress event produced by <span class="RktVar">get-progress-evt</span>;</p></li><li><p>an event, <span class="RktVar">done</span>, that is either a channel-put
|
||
|
event, channel, semaphore, semaphore-peek event, always
|
||
|
event, or never event.</p></li></ul><p>A <span style="font-style: italic">commit</span> corresponds to removing data from the stream
|
||
|
that was previously peeked, but only if no other process removed
|
||
|
data first. (The removed data does not need to be reported,
|
||
|
because it has been peeked already.) More precisely, assuming
|
||
|
that <span style="font-style: italic">k</span><span style="vertical-align: sub; font-size: 80%"><span style="font-style: italic">p</span></span><span style="font-style: italic"></span> bytes, <a href="customport.html#%28elem._special%29" data-pltdoc="x">specials</a>, and
|
||
|
mid-stream <span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span>s have been previously peeked or skipped
|
||
|
at the start of the port’s stream, <span class="RktVar">commit</span> must satisfy
|
||
|
the following constraints:</p><ul><li><p>It must return only when the commit is complete or when the
|
||
|
given progress event becomes ready.</p></li><li><p>It must commit only if <span style="font-style: italic">k</span><span style="vertical-align: sub; font-size: 80%"><span style="font-style: italic">p</span></span><span style="font-style: italic"></span> is positive.</p></li><li><p>If it commits, then it must do so with either <span style="font-style: italic">k</span><span style="vertical-align: sub; font-size: 80%"><span style="font-style: italic">r</span></span><span style="font-style: italic"></span> items
|
||
|
or <span style="font-style: italic">k</span><span style="vertical-align: sub; font-size: 80%"><span style="font-style: italic">p</span></span><span style="font-style: italic"></span> items, whichever is smaller, and only if <span style="font-style: italic">k</span><span style="vertical-align: sub; font-size: 80%"><span style="font-style: italic">p</span></span><span style="font-style: italic"></span> is
|
||
|
positive.</p></li><li><p>It must never choose <span class="RktVar">done</span> in a synchronization
|
||
|
after the given progress event is ready, or after <span class="RktVar">done</span>
|
||
|
has been synchronized once.</p></li><li><p>It must not treat any data as read from the port unless
|
||
|
<span class="RktVar">done</span> is chosen in a synchronization.</p></li><li><p>It must not block indefinitely if <span class="RktVar">done</span> is ready;
|
||
|
it must return soon after the read completes or soon after the
|
||
|
given progress event is ready, whichever is first.</p></li><li><p>It can report an error by raising an exception, but only if
|
||
|
no data has been committed. In other words, no data should be lost due to
|
||
|
an exception, including a break exception.</p></li><li><p>It must return a true value if data has been committed,
|
||
|
<span class="RktVal">#f</span> otherwise. When it returns a value, the given
|
||
|
progress event must be ready (perhaps because data has just been
|
||
|
committed).</p></li><li><p>It should return a byte string as a true result when line
|
||
|
counting is enabled and <span class="RktVar">get-location</span> is <span class="RktVal">#f</span> (so
|
||
|
that line counting is implemented the default way); the result
|
||
|
byte string represents the data that was committed for the
|
||
|
purposes of character and line counting. If any other true result
|
||
|
is returned when a byte string is expected, it is treated like a
|
||
|
byte string where each byte corresponds to a non-newline
|
||
|
character.</p></li><li><p>It must raise an exception if no data (including
|
||
|
<span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span>) has been peeked from the beginning of the port’s
|
||
|
stream, or if it would have to block indefinitely to wait for the
|
||
|
given progress event to become ready.</p></li></ul><p>A call to <span class="RktVar">commit</span> is <span class="RktSym"><a href="breakhandler.html#%28form._%28%28lib._racket%2Fprivate%2Fmore-scheme..rkt%29._parameterize-break%29%29" class="RktStxLink" data-pltdoc="x">parameterize-break</a></span>ed to
|
||
|
disable breaks.</p></li><li><p><span class="RktVar">get-location</span> —<wbr></wbr> either <span class="RktVal">#f</span> (the
|
||
|
default), or a procedure that takes no arguments and returns three
|
||
|
values: the line number for the next item in the port’s stream (a
|
||
|
positive number or <span class="RktVal">#f</span>), the column number for the next
|
||
|
item in the port’s stream (a non-negative number or <span class="RktVal">#f</span>),
|
||
|
and the position for the next item in the port’s stream (a
|
||
|
positive number or <span class="RktVal">#f</span>). See also <a href="linecol.html" data-pltdoc="x">Counting Positions, Lines, and Columns</a>.</p><p>This procedure is called to implement <span class="RktSym"><a href="linecol.html#%28def._%28%28quote._~23~25kernel%29._port-next-location%29%29" class="RktValLink" data-pltdoc="x">port-next-location</a></span>,
|
||
|
but only if line counting is enabled for the port via
|
||
|
<span class="RktSym"><a href="linecol.html#%28def._%28%28quote._~23~25kernel%29._port-count-lines%21%29%29" class="RktValLink" data-pltdoc="x">port-count-lines!</a></span> (in which case <span class="RktVar">count-lines!</span> is
|
||
|
called). The <span class="RktSym"><a href="Reading.html#%28def._%28%28quote._~23~25kernel%29._read%29%29" class="RktValLink" data-pltdoc="x">read</a></span> and <span class="RktSym"><a href="Reading.html#%28def._%28%28quote._~23~25kernel%29._read-syntax%29%29" class="RktValLink" data-pltdoc="x">read-syntax</a></span> procedures
|
||
|
assume that reading a non-whitespace character increments the
|
||
|
column and position by one.</p></li><li><p><span class="RktVar">count-lines!</span> —<wbr></wbr> a procedure of no arguments
|
||
|
that is called if and when line counting is enabled for the port.
|
||
|
The default procedure is <span class="RktSym"><a href="void.html#%28def._%28%28quote._~23~25kernel%29._void%29%29" class="RktValLink" data-pltdoc="x">void</a></span>.</p></li><li><p><span class="RktVar">init-position</span> —<wbr></wbr> normally an exact, positive integer
|
||
|
that determines the position of the port’s first item, which is
|
||
|
used by <span class="RktSym"><a href="port-buffers.html#%28def._%28%28quote._~23~25kernel%29._file-position%29%29" class="RktValLink" data-pltdoc="x">file-position</a></span> or when line counting is
|
||
|
<span style="font-style: italic">not</span> enabled for the port. The default is <span class="RktVal">1</span>. If
|
||
|
<span class="RktVar">init-position</span> is <span class="RktVal">#f</span>, the port is treated as
|
||
|
having an unknown position. If <span class="RktVar">init-position</span> is a port,
|
||
|
then the given port’s position is always used for the new port’s
|
||
|
position. If <span class="RktVar">init-position</span> is a procedure, it is called
|
||
|
as needed to obtain the port’s position.</p></li><li><p><span class="RktVar">buffer-mode</span> —<wbr></wbr> either <span class="RktVal">#f</span> (the default) or a
|
||
|
procedure that accepts zero or one arguments. If
|
||
|
<span class="RktVar">buffer-mode</span> is <span class="RktVal">#f</span>, then the resulting port does
|
||
|
not support a buffer-mode setting. Otherwise, the procedure is
|
||
|
called with one symbol argument (<span class="RktVal">'</span><span class="RktVal">block</span> or
|
||
|
<span class="RktVal">'</span><span class="RktVal">none</span>) to set the buffer mode, and it is called with zero
|
||
|
arguments to get the current buffer mode. In the latter case, the
|
||
|
result must be <span class="RktVal">'</span><span class="RktVal">block</span>, <span class="RktVal">'</span><span class="RktVal">none</span>, or <span class="RktVal">#f</span>
|
||
|
(unknown). See <a href="port-buffers.html" data-pltdoc="x">Port Buffers and Positions</a> for more information on
|
||
|
buffer modes.</p></li></ul><p><a name="(elem._special)"></a><span style="font-weight: bold">“Special” results:</span> When
|
||
|
<span class="RktVar">read-in</span> or <span class="RktVar">peek</span> (or an event produced by one of
|
||
|
these) returns a procedure, the procedure is used to obtain a
|
||
|
non-byte result. (This non-byte result is <span style="font-style: italic">not</span> intended to
|
||
|
return a character or <span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span>; in particular, <span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._read-char%29%29" class="RktValLink" data-pltdoc="x">read-char</a></span>
|
||
|
raises an exception if it encounters a special-result procedure, even
|
||
|
if the procedure produces a byte.) A special-result procedure must
|
||
|
accept four arguments that represent a source location. The first
|
||
|
argument is <span class="RktVal">#f</span> when the special read is triggered by <span class="RktSym"><a href="Reading.html#%28def._%28%28quote._~23~25kernel%29._read%29%29" class="RktValLink" data-pltdoc="x">read</a></span>
|
||
|
or <span class="RktSym"><a href="Reading.html#%28def._%28%28quote._~23~25kernel%29._read%2Frecursive%29%29" class="RktValLink" data-pltdoc="x">read/recursive</a></span>.</p><p>The special-value procedure can return an arbitrary value, and it
|
||
|
will be called zero or one times (not necessarily before further
|
||
|
reads or peeks from the port). See <a href="reader-procs.html" data-pltdoc="x">Reader-Extension Procedures</a> for
|
||
|
more details on the procedure’s result.</p><p>If <span class="RktVar">read-in</span> or <span class="RktVar">peek</span> returns a special
|
||
|
procedure when called by any reading procedure other than
|
||
|
<span class="RktSym"><a href="Reading.html#%28def._%28%28quote._~23~25kernel%29._read%29%29" class="RktValLink" data-pltdoc="x">read</a></span>, <span class="RktSym"><a href="Reading.html#%28def._%28%28quote._~23~25kernel%29._read-syntax%29%29" class="RktValLink" data-pltdoc="x">read-syntax</a></span>, <span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._read-char-or-special%29%29" class="RktValLink" data-pltdoc="x">read-char-or-special</a></span>,
|
||
|
<span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._peek-char-or-special%29%29" class="RktValLink" data-pltdoc="x">peek-char-or-special</a></span>, <span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._read-byte-or-special%29%29" class="RktValLink" data-pltdoc="x">read-byte-or-special</a></span>, or
|
||
|
<span class="RktSym"><a href="Byte_and_String_Input.html#%28def._%28%28quote._~23~25kernel%29._peek-byte-or-special%29%29" class="RktValLink" data-pltdoc="x">peek-byte-or-special</a></span>, then the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised.</p><p><div class="SIntrapara">Examples:</div><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">A port with no input...</span></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Easy: </span><span class="RktPn">(</span><span class="RktSym"><a href="stringport.html#%28def._%28%28quote._~23~25kernel%29._open-input-bytes%29%29" class="RktValLink" data-pltdoc="x">open-input-bytes</a></span><span class="stt"> </span><span class="RktVal">#""</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">Hard:</span></td></tr><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktSym">/dev/null-in</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="customport.html#%28def._%28%28quote._~23~25kernel%29._make-input-port%29%29" class="RktValLink" data-pltdoc="x">make-input-port</a></span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">null</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">s</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">skip</span><span class="hspace"> </span><span class="RktSym">s</span><span class="hspace"> </span><span class="RktSym">progress-evt</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktSym"><a href="port-ops.html#%28def._%28%28quote._~23~25kernel%29._eof%29%29" class="RktValLink" data-pltdoc="x">eof</a></span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktSym"><a href="void.html#%28def._%28%28quote._~23~25kernel%29._void%29%29" class="RktValLink" data-pltdoc="x">void</a></span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span c
|
||
|
writing. If <span class="RktVar">close</span> procedure has no side effects, then
|
||
|
the port need not be explicitly closed. The port can buffer data
|
||
|
within its <span class="RktVar">write-out</span> and <span class="RktVar">write-out-special</span>
|
||
|
procedures.</div></p><ul><li><p><span class="RktVar">name</span> —<wbr></wbr> the name for the output port.</p></li><li><p><span class="RktVar">evt</span> —<wbr></wbr> a synchronization event (see <a href="sync.html" data-pltdoc="x">Events</a>;
|
||
|
e.g., a semaphore or another port). The event is used in place of
|
||
|
the output port when the port is supplied to synchronization
|
||
|
procedures like <span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._sync%29%29" class="RktValLink" data-pltdoc="x">sync</a></span>. Thus, the event should be
|
||
|
unblocked when the port is ready for writing at least one byte
|
||
|
without blocking, or ready to make progress in flushing an
|
||
|
internal buffer without blocking. The event must not unblock
|
||
|
unless the port is ready for writing; otherwise, the guarantees of
|
||
|
<span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._sync%29%29" class="RktValLink" data-pltdoc="x">sync</a></span> will be broken for the output port. Use
|
||
|
<span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._always-evt%29%29" class="RktValLink" data-pltdoc="x">always-evt</a></span> if writes to the port always succeed without
|
||
|
blocking.</p></li><li><p><span class="RktVar">write-out</span> —<wbr></wbr> either an output port, which indicates that
|
||
|
writes should be redirected to the given port, or a procedure
|
||
|
of five arguments:</p><ul><li><p>an immutable byte string containing bytes to write;</p></li><li><p>a non-negative exact integer for a starting offset
|
||
|
(inclusive) into the byte string;</p></li><li><p>a non-negative exact integer for an ending offset
|
||
|
(exclusive) into the byte string;</p></li><li><p>a boolean; <span class="RktVal">#f</span> indicates that the port is allowed
|
||
|
to keep the written bytes in a buffer, and that it is
|
||
|
allowed to block indefinitely; <span class="RktVal">#t</span> indicates that the
|
||
|
write should not block, and that the port should attempt to flush
|
||
|
its buffer and completely write new bytes instead of
|
||
|
buffering them;</p></li><li><p>a boolean; <span class="RktVal">#t</span> indicates that if the port blocks
|
||
|
for a write, then it should enable breaks while blocking (e.g.,
|
||
|
using <span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._sync%2Fenable-break%29%29" class="RktValLink" data-pltdoc="x">sync/enable-break</a></span>); this argument is always
|
||
|
<span class="RktVal">#f</span> if the fourth argument is <span class="RktVal">#t</span>.</p></li></ul><p>The procedure returns one of the following:</p><ul><li><p>a non-negative exact integer representing the number of
|
||
|
bytes written or buffered;</p></li><li><p><span class="RktVal">#f</span> if no bytes could be written, perhaps because
|
||
|
the internal buffer could not be completely flushed;</p></li><li><p>a <a href="pipeports.html#%28tech._pipe%29" data-pltdoc="x">pipe</a> output port (when buffering is allowed
|
||
|
and not when flushing) for buffering bytes as long as the pipe is
|
||
|
not full and until <span class="RktVar">write-out</span> or
|
||
|
<span class="RktVar">write-out-special</span> is called; or</p></li><li><p>a synchronizable event (see <a href="sync.html" data-pltdoc="x">Events</a>) other than a
|
||
|
pipe output port that acts like the result of
|
||
|
<span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._write-bytes-avail-evt%29%29" class="RktValLink" data-pltdoc="x">write-bytes-avail-evt</a></span> to complete the write.</p></li></ul><p>Since <span class="RktVar">write-out</span> can produce an event, an acceptable
|
||
|
implementation of <span class="RktVar">write-out</span> is to pass its first three
|
||
|
arguments to the port’s <span class="RktVar">get-write-evt</span>. Some port
|
||
|
implementors, however, may choose not to provide
|
||
|
<span class="RktVar">get-write-evt</span> (perhaps because writes cannot be
|
||
|
made atomic), or may implement <span class="RktVar">write-out</span> to
|
||
|
enable a fast path for non-blocking writes or to
|
||
|
enable buffering.</p><p>From a user’s perspective, the difference between buffered and
|
||
|
completely written data is (1) buffered data can be lost in the
|
||
|
future due to a failed write, and (2) <span class="RktSym"><a href="port-buffers.html#%28def._%28%28quote._~23~25kernel%29._flush-output%29%29" class="RktValLink" data-pltdoc="x">flush-output</a></span> forces
|
||
|
all buffered data to be completely written. Under no circumstances
|
||
|
is buffering required.</p><p>If the start and end indices are the same, then the fourth
|
||
|
argument to <span class="RktVar">write-out</span> will be <span class="RktVal">#f</span>, and the write
|
||
|
request is actually a flush request for the port’s buffer (if
|
||
|
any), and the result should be <span class="RktVal">0</span> for a successful flush
|
||
|
(or if there is no buffer).</p><p>The result should never be <span class="RktVal">0</span> if the start and end indices
|
||
|
are different, otherwise the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised.
|
||
|
Similarly, the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised if <span class="RktVar">write-out</span>
|
||
|
returns a pipe output port when buffering is disallowed or when it
|
||
|
is called for flushing. If a returned integer is larger than the
|
||
|
supplied byte-string range, the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised.</p><p>The <span class="RktVal">#f</span> result should be avoided, unless the next write
|
||
|
attempt is likely to work. Otherwise, if data cannot be written,
|
||
|
return an event instead.</p><p>An event returned by <span class="RktVar">write-out</span> can return <span class="RktVal">#f</span> or
|
||
|
another event like itself, in contrast to events produced by
|
||
|
<span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._write-bytes-avail-evt%29%29" class="RktValLink" data-pltdoc="x">write-bytes-avail-evt</a></span> or <span class="RktVar">get-write-evt</span>.
|
||
|
A writing process loops with <span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._sync%29%29" class="RktValLink" data-pltdoc="x">sync</a></span> until it obtains a
|
||
|
non-event result.</p><p>The <span class="RktVar">write-out</span> procedure is always called with breaks
|
||
|
disabled, independent of whether breaks were enabled when the write
|
||
|
was requested by a client of the port. If breaks were enabled for
|
||
|
a blocking operation, then the fifth argument to <span class="RktVar">write-out</span>
|
||
|
will be <span class="RktVal">#t</span>, which indicates that <span class="RktVar">write-out</span> should
|
||
|
re-enable breaks while blocking.</p><p>If the writing procedure raises an exception, due to write
|
||
|
or commit operations, it must not have committed any bytes
|
||
|
(though it may have committed previously buffered bytes).</p><p>A port’s writing procedure may be called in multiple threads
|
||
|
simultaneously (if the port is accessible in multiple
|
||
|
threads). The port is responsible for its own internal
|
||
|
synchronization. Note that improper implementation of such
|
||
|
synchronization mechanisms might cause a non-blocking write
|
||
|
procedure to block.</p></li><li><p><span class="RktVar">close</span> —<wbr></wbr> a procedure of zero arguments that is
|
||
|
called to close the port. The port is not considered closed until
|
||
|
the closing procedure returns. The port’s procedures will never be
|
||
|
used again via the port after it is closed. However, the closing
|
||
|
procedure can be called simultaneously in multiple threads (if the
|
||
|
port is accessible in multiple threads), and it may be called
|
||
|
during a call to the other procedures in another thread; in the
|
||
|
latter case, any outstanding writes or flushes should be
|
||
|
terminated immediately with an error.</p></li><li><p><span class="RktVar">write-out-special</span> —<wbr></wbr> either <span class="RktVal">#f</span> (the
|
||
|
default), an output port (which indicates that
|
||
|
special writes should be redirected to the given port),
|
||
|
or a procedure to handle <span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._write-special%29%29" class="RktValLink" data-pltdoc="x">write-special</a></span> calls
|
||
|
for the port. If <span class="RktVal">#f</span>, then the port does not support
|
||
|
special output, and <span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._port-writes-special~3f%29%29" class="RktValLink" data-pltdoc="x">port-writes-special?</a></span> will return
|
||
|
<span class="RktVal">#f</span> when applied to the port.</p><p>If a procedure is supplied, it takes three arguments: the special
|
||
|
value to write, a boolean that is <span class="RktVal">#f</span> if the procedure can
|
||
|
buffer the special value and block indefinitely, and a boolean
|
||
|
that is <span class="RktVal">#t</span> if the procedure should enable breaks while
|
||
|
blocking. The result is one of the following:</p><ul><li><p>a non-event true value, which indicates that the special is
|
||
|
written;</p></li><li><p><span class="RktVal">#f</span> if the special could not be written, perhaps
|
||
|
because an internal buffer could not be completely flushed;</p></li><li><p>a synchronizable event (see <a href="sync.html" data-pltdoc="x">Events</a>) that acts like
|
||
|
the result of <span class="RktVar">get-write-special-evt</span> to complete the write.</p></li></ul><p>Since <span class="RktVar">write-out-special</span> can return an event,
|
||
|
passing the first argument to an implementation of
|
||
|
<span class="RktVar">get-write-special-evt</span> is acceptable as a
|
||
|
<span class="RktVar">write-out-special</span>.</p><p>As for <span class="RktVar">write-out</span>, the <span class="RktVal">#f</span> result is discouraged,
|
||
|
since it can lead to busy waiting. Also as for <span class="RktVar">write-out</span>,
|
||
|
an event produced by <span class="RktVar">write-out-special</span> is allowed
|
||
|
to produce <span class="RktVal">#f</span> or another event like itself. The
|
||
|
<span class="RktVar">write-out-special</span> procedure is always called with
|
||
|
breaks disabled, independent of whether breaks were enabled when
|
||
|
the write was requested by a client of the port.</p></li><li><p><span class="RktVar">get-write-evt</span> —<wbr></wbr> either <span class="RktVal">#f</span> (the
|
||
|
default) or a procedure of three arguments:</p><ul><li><p>an immutable byte string containing bytes to write;</p></li><li><p>a non-negative exact integer for a starting offset
|
||
|
(inclusive) into the byte string; and</p></li><li><p>a non-negative exact integer for an ending offset
|
||
|
(exclusive) into the byte string.</p></li></ul><p>The result is a synchronizable event (see <a href="sync.html" data-pltdoc="x">Events</a>) to act as
|
||
|
the result of <span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._write-bytes-avail-evt%29%29" class="RktValLink" data-pltdoc="x">write-bytes-avail-evt</a></span> for the port (i.e.,
|
||
|
to complete a write or flush), which becomes available only as
|
||
|
data is committed to the port’s underlying device, and whose
|
||
|
result is the number of bytes written.</p><p>If <span class="RktVar">get-write-evt</span> is <span class="RktVal">#f</span>, then
|
||
|
<span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._port-writes-atomic~3f%29%29" class="RktValLink" data-pltdoc="x">port-writes-atomic?</a></span> will produce <span class="RktVal">#f</span> when applied
|
||
|
to the port, and the port will not be a valid argument to
|
||
|
procedures such as <span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._write-bytes-avail-evt%29%29" class="RktValLink" data-pltdoc="x">write-bytes-avail-evt</a></span>.
|
||
|
Otherwise, an event returned by <span class="RktVar">get-write-evt</span> must
|
||
|
not cause data to be written to the port unless the event is
|
||
|
chosen in a synchronization, and it must write to the port if the
|
||
|
event is chosen (i.e., the write must appear atomic with respect
|
||
|
to the synchronization).</p><p>If the event’s result integer is larger than the supplied
|
||
|
byte-string range, the <span class="RktSym"><a href="exns.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._exn~3afail~3acontract%29%29" class="RktValLink" data-pltdoc="x">exn:fail:contract</a></span> exception is raised by a wrapper
|
||
|
on the event. If the start and end indices are the same (i.e., no
|
||
|
bytes are to be written), then the event should produce <span class="RktVal">0</span>
|
||
|
when the buffer is completely flushed. (If the port has no buffer,
|
||
|
then it is effectively always flushed.)</p><p>If the event raises an exception, due to write or commit
|
||
|
operations, it must not have committed any new bytes (though it
|
||
|
may have committed previously buffered bytes).</p><p>Naturally, a port’s events may be used in multiple threads
|
||
|
simultaneously (if the port is accessible in multiple
|
||
|
threads). The port is responsible for its own internal
|
||
|
synchronization.</p></li><li><p><span class="RktVar">get-write-special-evt</span> —<wbr></wbr> either <span class="RktVal">#f</span>
|
||
|
(the default), or a procedure to handle <span class="RktSym"><a href="Byte_and_String_Output.html#%28def._%28%28quote._~23~25kernel%29._write-special-evt%29%29" class="RktValLink" data-pltdoc="x">write-special-evt</a></span>
|
||
|
calls for the port. This argument must be <span class="RktVal">#f</span> if either
|
||
|
<span class="RktVar">write-out-special</span> or <span class="RktVar">get-write-evt</span>
|
||
|
is <span class="RktVal">#f</span>, and it must be a procedure if both of those
|
||
|
arguments are procedures.</p><p>If it is a procedure, it takes one argument: the special value to
|
||
|
write. The resulting event (with its constraints) is analogous to
|
||
|
the result of <span class="RktVar">get-write-evt</span>.</p><p>If the event raises an exception, due to write or commit
|
||
|
operations, it must not have committed the special value (though
|
||
|
it may have committed previously buffered bytes and values).</p></li><li><p><span class="RktVar">get-location</span> —<wbr></wbr> either <span class="RktVal">#f</span> (the
|
||
|
default), or a procedure that takes no arguments and returns three
|
||
|
values: the line number for the next item written to the port’s
|
||
|
stream (a positive number or <span class="RktVal">#f</span>), the column number for
|
||
|
the next item written to port’s stream (a non-negative number or
|
||
|
<span class="RktVal">#f</span>), and the position for the next item written to port’s
|
||
|
stream (a positive number or <span class="RktVal">#f</span>). See also
|
||
|
<a href="linecol.html" data-pltdoc="x">Counting Positions, Lines, and Columns</a>.</p><p>This procedure is called to implement <span class="RktSym"><a href="linecol.html#%28def._%28%28quote._~23~25kernel%29._port-next-location%29%29" class="RktValLink" data-pltdoc="x">port-next-location</a></span>
|
||
|
for the port, but only if line counting is enabled for the port
|
||
|
via <span class="RktSym"><a href="linecol.html#%28def._%28%28quote._~23~25kernel%29._port-count-lines%21%29%29" class="RktValLink" data-pltdoc="x">port-count-lines!</a></span> (in which case
|
||
|
<span class="RktVar">count-lines!</span> is called).</p></li><li><p><span class="RktVar">count-lines!</span> —<wbr></wbr> a procedure of no arguments
|
||
|
that is called if and when line counting is enabled for the port.
|
||
|
The default procedure is <span class="RktSym"><a href="void.html#%28def._%28%28quote._~23~25kernel%29._void%29%29" class="RktValLink" data-pltdoc="x">void</a></span>.</p></li><li><p><span class="RktVar">init-position</span> —<wbr></wbr> normally an exact, positive integer
|
||
|
that determines the position of the port’s first item, which is
|
||
|
used by <span class="RktSym"><a href="port-buffers.html#%28def._%28%28quote._~23~25kernel%29._file-position%29%29" class="RktValLink" data-pltdoc="x">file-position</a></span> or when line counting is
|
||
|
<span style="font-style: italic">not</span> enabled for the port. The default is <span class="RktVal">1</span>. If
|
||
|
<span class="RktVar">init-position</span> is <span class="RktVal">#f</span>, the port is treated as
|
||
|
having an unknown position. If <span class="RktVar">init-position</span> is a port,
|
||
|
then the given port’s position is always used for the new port’s
|
||
|
position. If <span class="RktVar">init-position</span> is a procedure, it is called
|
||
|
as needed to obtain the port’s position.</p></li><li><p><span class="RktVar">buffer-mode</span> —<wbr></wbr> either <span class="RktVal">#f</span> (the
|
||
|
default) or a procedure that accepts zero or one arguments. If
|
||
|
<span class="RktVar">buffer-mode</span> is <span class="RktVal">#f</span>, then the resulting
|
||
|
port does not support a buffer-mode setting. Otherwise, the
|
||
|
procedure is called with one symbol argument (<span class="RktVal">'</span><span class="RktVal">block</span>,
|
||
|
<span class="RktVal">'</span><span class="RktVal">line</span>, or <span class="RktVal">'</span><span class="RktVal">none</span>) to set the buffer mode, and it is
|
||
|
called with zero arguments to get the current buffer mode. In the
|
||
|
latter case, the result must be <span class="RktVal">'</span><span class="RktVal">block</span>, <span class="RktVal">'</span><span class="RktVal">line</span>,
|
||
|
<span class="RktVal">'</span><span class="RktVal">none</span>, or <span class="RktVal">#f</span> (unknown). See <a href="port-buffers.html" data-pltdoc="x">Port Buffers and Positions</a>
|
||
|
for more information on buffer modes.</p></li></ul><p><div class="SIntrapara">Examples:</div><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="RktCmt">;</span><span class="RktCmt"> </span><span class="RktCmt">A port that writes anything to nowhere:</span></td></tr><tr><td><table cellspacing="0" cellpadding="0" class="RktBlk"><tr><td><span class="stt">> </span><span class="RktPn">(</span><span class="RktSym"><a href="define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define%29%29" class="RktStxLink" data-pltdoc="x">define</a></span><span class="hspace"> </span><span class="RktSym">/dev/null-out</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="customport.html#%28def._%28%28quote._~23~25kernel%29._make-output-port%29%29" class="RktValLink" data-pltdoc="x">make-output-port</a></span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktVal">'</span><span class="RktVal">null</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktSym"><a href="sync.html#%28def._%28%28quote._~23~25kernel%29._always-evt%29%29" class="RktValLink" data-pltdoc="x">always-evt</a></span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">s</span><span class="hspace"> </span><span class="RktSym">start</span><span class="hspace"> </span><span class="RktSym">end</span><span class="hspace"> </span><span class="RktSym">non-block?</span><span class="hspace"> </span><span class="RktSym">breakable?</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="generic-numbers.html#%28def._%28%28quote._~23~25kernel%29._-%29%29" class="RktValLink" data-pltdoc="x"><span class="nobreak">-</span></a></span><span class="hspace"> </span><span class="RktSym">end</span><span class="hspace"> </span><span class="RktSym">start</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktSym"><a href="void.html#%28def._%28%28quote._~23~25kernel%29._void%29%29" class="RktValLink" data-pltdoc="x">void</a></span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">special</span><span class="hspace"> </span><span class="RktSym">non-block?</span><span class="hspace"> </span><span class="RktSym">breakable?</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktVal">#t</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace"> </span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="lambda.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29" class="RktStxLink" data-pltdoc="x">lambda</a></span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym">s</span><span class="hspace"> </span><span class="RktSym">start</span><span class="hspace"> </span><span class="RktSym">end</span><span class="RktPn">)</span><span class="hspace"> </span><span class="RktPn">(</span><span class="RktSym"><a href="sync.html#%28def._%
|