1296 lines
173 KiB
HTML
1296 lines
173 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<html>
|
|
<head>
|
|
<title>Streams</title>
|
|
<meta name="viewport" content="width=device-width initial-scale=1">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<meta http-equiv="Content-Language" content="en-gb">
|
|
<link href="../inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
</head>
|
|
<body>
|
|
<nav role="navigation">
|
|
<h1><a href="../webs.html">Sources</a></h1>
|
|
<ul>
|
|
<li><a href="../inweb/index.html">inweb</a></li>
|
|
</ul>
|
|
<h2>Foundation</h2>
|
|
<ul>
|
|
<li><a href="../foundation-module/index.html">foundation-module</a></li>
|
|
<li><a href="../foundation-test/index.html">foundation-test</a></li>
|
|
</ul>
|
|
|
|
|
|
</nav>
|
|
<main role="main">
|
|
|
|
<!--Weave of 'Streams' generated by 7-->
|
|
<ul class="crumbs"><li><a href="../webs.html">Source</a></li><li><a href="index.html">foundation</a></li><li><a href="index.html#2">Chapter 2: Memory, Streams and Collections</a></li><li><b>Streams</b></li></ul><p class="purpose">Support for writing structured textual output, perhaps to the screen, to a file, or to a flexible-sized wide string.</p>
|
|
|
|
<ul class="toc"><li><a href="#SP1">§1. About streams</a></li><li><a href="#SP19">§19. Initialising the stream structure</a></li><li><a href="#SP21">§21. Logging</a></li><li><a href="#SP22">§22. Standard I/O wrappers</a></li><li><a href="#SP24">§24. Creating file streams</a></li><li><a href="#SP26">§26. Creating memory streams</a></li><li><a href="#SP28">§28. Converting from C strings</a></li><li><a href="#SP29">§29. Converting to C strings</a></li><li><a href="#SP32">§32. Locale versions</a></li><li><a href="#SP33">§33. Flush and close</a></li><li><a href="#SP35">§35. Writing</a></li><li><a href="#SP39">§39. Memory-stream-only functions</a></li><li><a href="#SP43">§43. Writer</a></li></ul><hr class="tocbar">
|
|
|
|
<p class="inwebparagraph"><a id="SP1"></a><b>§1. About streams. </b>The Inform tools produce textual output in many formats (HTML, EPS, plain
|
|
text, Inform 6 code, XML, and so on), writing to a variety of files, and
|
|
often need to juggle and rearrange partially written segments. These
|
|
texts tend to be structured with running indentation, and may eventually
|
|
need to be written to a disc file with either ISO Latin-1 or UTF-8
|
|
encodings, perhaps escaped for XML.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">"Streams" are an abstraction to make it easy to handle all of this. The
|
|
writer to a stream never needs to know where the text will come out, or how
|
|
it should be indented or encoded.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Moreover, streams unify text files and strings, and can hold arbitrary
|
|
Unicode text. This text is encoded internally as a sequence of 32-bit Unicode
|
|
code points, in a form we might call semi-composed, in that all possible
|
|
compositions of ISO Latin-1 characters are made: e.g., E plus acute accent
|
|
is composed to a single code point as E-acute.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">We give just one character value a non-Unicode meaning:
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="constant">NEWLINE_IN_STRING</span><span class="plain"> ((</span><span class="reserved">char</span><span class="plain">) </span><span class="constant">0x7f</span><span class="plain">) </span><span class="comment"> Within quoted text, all newlines are converted to this</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP2"></a><b>§2. </b>The <code class="display"><span class="extract">text_stream</span></code> type began as a generalisation of the standard C library's
|
|
<code class="display"><span class="extract">FILE</span></code>, and it is used in mostly similar ways. The user — the whole
|
|
program outside of this section — deals only with <code class="display"><span class="extract">text_stream *</span></code> pointers to
|
|
represent streams in use.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">All stream handling is defined via macros. While many operations could be
|
|
handled by ordinary functions, others cannot. <code class="display"><span class="extract">text_stream</span></code> cannot have exactly
|
|
the semantics of <code class="display"><span class="extract">FILE</span></code> since we cannot rely on the host operating system
|
|
to allocate and deallocate the structures behind <code class="display"><span class="extract">text_stream *</span></code> pointers; and
|
|
we cannot use our own memory system, either, since we need stream handling
|
|
to work both before the memory allocator starts and after it has finished.
|
|
Our macros allow us to hide all this. Besides that, a macro approach makes it
|
|
easier to retrofit new implementations as necessary. (The present
|
|
implementation is the second stab at it.)
|
|
</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP3"></a><b>§3. </b>We'll define a few variadic macros here, because there are awkward issues
|
|
with code ordering if we leave them until later. They are written in the
|
|
old-fashioned way, for compatibility with old copies of GCC, and avoid the
|
|
need for comma deletion around empty tokens, as that is a point of
|
|
incompatibility between implementations of the C preprocessor <code class="display"><span class="extract">cpp</span></code>. All the
|
|
same, if you're porting this code, you may need to rewrite the macro with
|
|
<code class="display"><span class="extract">...</span></code> in place of <code class="display"><span class="extract">args...</span></code> in the header, and then <code class="display"><span class="extract">__VA_ARGS__</span></code> in place
|
|
of <code class="display"><span class="extract">args</span></code> in the definition: that being the modern way, apparently.
|
|
</p>
|
|
|
|
<p class="inwebparagraph"><code class="display"><span class="extract">WRITE</span></code> is essentially <code class="display"><span class="extract">sprintf</span></code> and <code class="display"><span class="extract">fprintf</span></code> combined, since it prints
|
|
formatted text to the current stream, which could be either a string or a
|
|
file. <code class="display"><span class="extract">PRINT</span></code> does the same but to <code class="display"><span class="extract">STDOUT</span></code>, and is thus essentially <code class="display"><span class="extract">printf</span></code>.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">#</span><span class="identifier">define</span><span class="plain"> </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="identifier">args</span><span class="plain">...) </span><span class="functiontext">Writers::printf</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">args</span><span class="plain">)</span>
|
|
|
|
<span class="plain">#</span><span class="identifier">define</span><span class="plain"> </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="identifier">args</span><span class="plain">...) </span><span class="functiontext">Writers::printf</span><span class="plain">(</span><span class="constant">STDOUT</span><span class="plain">, </span><span class="identifier">args</span><span class="plain">)</span>
|
|
|
|
<span class="plain">#</span><span class="identifier">define</span><span class="plain"> </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">args</span><span class="plain">...) </span><span class="functiontext">Writers::printf</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">args</span><span class="plain">)</span>
|
|
|
|
<span class="plain">#</span><span class="identifier">define</span><span class="plain"> </span><span class="identifier">LOG</span><span class="plain">(</span><span class="identifier">args</span><span class="plain">...) </span><span class="functiontext">Writers::printf</span><span class="plain">(</span><span class="identifier">DL</span><span class="plain">, </span><span class="identifier">args</span><span class="plain">)</span>
|
|
|
|
<span class="plain">#</span><span class="identifier">define</span><span class="plain"> </span><span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">aspect</span><span class="plain">, </span><span class="identifier">args</span><span class="plain">...) { \</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Log::aspect_switched_on</span><span class="plain">(</span><span class="identifier">aspect</span><span class="plain">##</span><span class="identifier">_DA</span><span class="plain">)) </span><span class="functiontext">Writers::printf</span><span class="plain">(</span><span class="identifier">DL</span><span class="plain">, </span><span class="identifier">args</span><span class="plain">); \</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP4"></a><b>§4. </b>The main purpose of many functions is to write textual material to some
|
|
file. Such functions almost always have a special argument in their
|
|
prototypes: <code class="display"><span class="extract">OUTPUT_STREAM</span></code>. This tells them where to pipe their output, which
|
|
is always to a "current stream" called <code class="display"><span class="extract">OUT</span></code>. What this leads to, and who will
|
|
see that it's properly opened and closed, are not their concern.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="constant">OUTPUT_STREAM</span><span class="plain"> </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">OUT</span><span class="plain"> </span><span class="comment"> used only as a function prototype argument</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP5"></a><b>§5. </b>Three output streams are always open. One is <code class="display"><span class="extract">NULL</span></code>, that is, its value
|
|
as a <code class="display"><span class="extract">text_stream *</span></code> pointer is <code class="display"><span class="extract">NULL</span></code>, the generic C null pointer. This represents
|
|
an oubliette: it is entirely valid to use it, but output sent to <code class="display"><span class="extract">NULL</span></code> will
|
|
never be seen again.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">The others are <code class="display"><span class="extract">STDOUT</span></code> and <code class="display"><span class="extract">STDERR</span></code>. As the names suggest these are wrappers
|
|
for <code class="display"><span class="extract">stdout</span></code> and <code class="display"><span class="extract">stderr</span></code>, the standard console output and error messages
|
|
"files" provided by the C library.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">We should always use <code class="display"><span class="extract">PRINT(...)</span></code> instead of <code class="display"><span class="extract">printf(...)</span></code> for console output,
|
|
so that there are no uses of <code class="display"><span class="extract">printf</span></code> anywhere in the program.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="constant">STDOUT</span><span class="plain"> </span><span class="functiontext">Streams::get_stdout</span><span class="plain">()</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">STDERR</span><span class="plain"> </span><span class="functiontext">Streams::get_stderr</span><span class="plain">()</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP6"></a><b>§6. </b><code class="display"><span class="extract">PUT</span></code> and <code class="display"><span class="extract">PUT_TO</span></code> similarly print single characters, which are
|
|
specified as unsigned integer values. In practice, <code class="display"><span class="extract">WRITE_TO</span></code> and
|
|
<code class="display"><span class="extract">PUT_TO</span></code> are seldom needed because there is almost always only one
|
|
stream of interest at a time — <code class="display"><span class="extract">OUT</span></code>, the current stream.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="identifier">PUT</span><span class="plain">(</span><span class="identifier">c</span><span class="plain">) </span><span class="functiontext">Streams::putc</span><span class="plain">(</span><span class="identifier">c</span><span class="plain">, </span><span class="identifier">OUT</span><span class="plain">)</span>
|
|
<span class="definitionkeyword">define</span> <span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">c</span><span class="plain">) </span><span class="functiontext">Streams::putc</span><span class="plain">(</span><span class="identifier">c</span><span class="plain">, </span><span class="identifier">stream</span><span class="plain">)</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP7"></a><b>§7. </b>Each stream has a current indentation level, initially 0. Lines of text
|
|
will be indented by one tab stop for each level; it's an error for the level
|
|
to become negative.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="constant">INDENT</span><span class="plain"> </span><span class="functiontext">Streams::indent</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">);</span>
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_INDENT</span><span class="plain">(</span><span class="identifier">x</span><span class="plain">) </span><span class="functiontext">Streams::indent</span><span class="plain">(</span><span class="identifier">x</span><span class="plain">);</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">OUTDENT</span><span class="plain"> </span><span class="functiontext">Streams::outdent</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">);</span>
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_OUTDENT</span><span class="plain">(</span><span class="identifier">x</span><span class="plain">) </span><span class="functiontext">Streams::outdent</span><span class="plain">(</span><span class="identifier">x</span><span class="plain">);</span>
|
|
<span class="definitionkeyword">define</span> <span class="identifier">SET_INDENT</span><span class="plain">(</span><span class="identifier">N</span><span class="plain">) </span><span class="functiontext">Streams::set_indentation</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">N</span><span class="plain">);</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP8"></a><b>§8. </b>Other streams only exist when explicitly created, or "opened". A function
|
|
is only allowed to open a new stream if it can be proved that this stream will
|
|
always subsequently be "closed". (Except for the possibility of the tool
|
|
halting with an internal error, and therefore an <code class="display"><span class="extract">exit(1)</span></code>, while the stream
|
|
is still open.) A stream can be opened and closed only once, and outside that
|
|
time its state is undefined: it must not be used at all.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">The simplest way is to make a temporary stream, which can be used as a sort
|
|
of clipboard. For instance, suppose we have to compile X before Y, but have to
|
|
ensure Y comes before X in the eventual output. We create a temporary stream,
|
|
compile X into it, then compile Y to <code class="display"><span class="extract">OUT</span></code>, then copy the temporary stream
|
|
into <code class="display"><span class="extract">OUT</span></code> and dispose of it.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Temporary streams are always created in memory, held in C's local stack frame
|
|
rather than allocated and freed via <code class="display"><span class="extract">malloc</span></code> and <code class="display"><span class="extract">free</span></code>. It must always be
|
|
possible to prove that execution passes from <code class="display"><span class="extract">TEMPORARY_TEXT</span></code> to
|
|
<code class="display"><span class="extract">DISCARD_TEXT</span></code>, unless the program makes a fatal exit in between. The stream,
|
|
let's call it <code class="display"><span class="extract">TEMP</span></code>, exists only between those macros. We can legitimately
|
|
create a temporary stream many times in one function (for instance inside a
|
|
loop body) because each time <code class="display"><span class="extract">TEMP</span></code> is created as a new stream, overwriting the
|
|
old one. <code class="display"><span class="extract">TEMP</span></code> is a different stream each time it is created, so it does
|
|
not violate the rule that every stream is opened and closed once only.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">T</span><span class="plain">)</span>
|
|
<span class="identifier">wchar_t</span><span class="plain"> </span><span class="identifier">T</span><span class="plain">##</span><span class="identifier">_dest</span><span class="plain">[2048];</span>
|
|
<span class="reserved">text_stream</span><span class="plain"> </span><span class="identifier">T</span><span class="plain">##</span><span class="identifier">_stream_structure</span><span class="plain"> = </span><span class="functiontext">Streams::new_buffer</span><span class="plain">(2048, </span><span class="identifier">T</span><span class="plain">##</span><span class="identifier">_dest</span><span class="plain">);</span>
|
|
<span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">T</span><span class="plain"> = &</span><span class="identifier">T</span><span class="plain">##</span><span class="identifier">_stream_structure</span><span class="plain">;</span>
|
|
<span class="definitionkeyword">define</span> <span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">T</span><span class="plain">)</span>
|
|
<span class="identifier">STREAM_CLOSE</span><span class="plain">(</span><span class="identifier">T</span><span class="plain">);</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP9"></a><b>§9. </b>Otherwise we can create new globally existing streams, provided we take on
|
|
the responsibility for seeing that they are properly closed. There are two
|
|
choices: a stream in memory, allocated via <code class="display"><span class="extract">malloc</span></code> and freed by <code class="display"><span class="extract">free</span></code> when
|
|
the stream is closed; or a file written to disc, opened via <code class="display"><span class="extract">fopen</span></code> and
|
|
later closed by <code class="display"><span class="extract">fclose</span></code>. Files are always written in text mode, that is,
|
|
<code class="display"><span class="extract">"w"</span></code> not <code class="display"><span class="extract">"wb"</span></code>, for those platforms where this makes a difference.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">We use streams to handle all of our text file output, so there should be no
|
|
calls to <code class="display"><span class="extract">fprintf</span></code> anywhere in the program except for binary files.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_OPEN_TO_FILE</span><span class="plain">(</span><span class="identifier">new</span><span class="plain">, </span><span class="identifier">fn</span><span class="plain">, </span><span class="identifier">enc</span><span class="plain">) </span><span class="functiontext">Streams::open_to_file</span><span class="plain">(</span><span class="identifier">new</span><span class="plain">, </span><span class="identifier">fn</span><span class="plain">, </span><span class="identifier">enc</span><span class="plain">)</span>
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_OPEN_TO_FILE_APPEND</span><span class="plain">(</span><span class="identifier">new</span><span class="plain">, </span><span class="identifier">fn</span><span class="plain">, </span><span class="identifier">enc</span><span class="plain">) </span><span class="functiontext">Streams::open_to_file_append</span><span class="plain">(</span><span class="identifier">new</span><span class="plain">, </span><span class="identifier">fn</span><span class="plain">, </span><span class="identifier">enc</span><span class="plain">)</span>
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_OPEN_IN_MEMORY</span><span class="plain">(</span><span class="identifier">new</span><span class="plain">) </span><span class="functiontext">Streams::open_to_memory</span><span class="plain">(</span><span class="identifier">new</span><span class="plain">, </span><span class="constant">20480</span><span class="plain">)</span>
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_CLOSE</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">) </span><span class="functiontext">Streams::close</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">)</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP10"></a><b>§10. </b>The following operation is equivalent to <code class="display"><span class="extract">fflush</span></code> and makes it more likely
|
|
(I put it no higher) that the text written to a stream has all actually been
|
|
copied onto the disc, rather than sitting in some operating system buffer.
|
|
This helps ensure that any debugging log is up to the minute, in case of
|
|
a crash, but its absence wouldn't hurt our normal function. Flushing
|
|
a memory stream is legal but does nothing.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_FLUSH</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">) </span><span class="functiontext">Streams::flush</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">)</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP11"></a><b>§11. </b>A piece of information we can read for any stream is the number of characters
|
|
written to it: its "extent". In fact, UTF-8 multi-byte encoding schemes,
|
|
together with differing platform interpretations of C's <code class="display"><span class="extract">'\n'</span></code>, mean that this
|
|
extent is not necessarily either the final file size in bytes or the final
|
|
number of human-readable characters. We will only actually use it to detect
|
|
whether text has, or has not, been written to a stream between two points in
|
|
time, by seeing whether or not it has increased.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_EXTENT</span><span class="plain">(</span><span class="identifier">x</span><span class="plain">) </span><span class="functiontext">Streams::get_position</span><span class="plain">(</span><span class="identifier">x</span><span class="plain">)</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP12"></a><b>§12. </b>The remaining operations are available only for streams in memory (well, and
|
|
for <code class="display"><span class="extract">NULL</span></code>, but of course they do nothing when applied to that). While they
|
|
could be provided for file streams, this would be so inefficient that we will
|
|
pretend it is impossible. Any function which might need to use one
|
|
of these operations should open with the following sentinel macro:
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_MUST_BE_IN_MEMORY</span><span class="plain">(</span><span class="identifier">x</span><span class="plain">)</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">x</span><span class="plain"> != </span><span class="identifier">NULL</span><span class="plain">) && (</span><span class="identifier">x</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">))</span>
|
|
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"text_stream not in memory"</span><span class="plain">);</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP13"></a><b>§13. </b>First, we can erase one or more recently written characters:
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_BACKSPACE</span><span class="plain">(</span><span class="identifier">x</span><span class="plain">) </span><span class="functiontext">Streams::set_position</span><span class="plain">(</span><span class="identifier">x</span><span class="plain">, </span><span class="functiontext">Streams::get_position</span><span class="plain">(</span><span class="identifier">x</span><span class="plain">) - </span><span class="constant">1</span><span class="plain">)</span>
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_ERASE_BACK_TO</span><span class="plain">(</span><span class="identifier">start_position</span><span class="plain">) </span><span class="functiontext">Streams::set_position</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">start_position</span><span class="plain">)</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP14"></a><b>§14. </b>Second, we can look at the text written. The minimal form is to look at
|
|
just the most recent character, but we can also copy one entire memory
|
|
stream into another stream (where the target can be either a memory or file
|
|
stream).
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_MOST_RECENT_CHAR</span><span class="plain">(</span><span class="identifier">x</span><span class="plain">) </span><span class="functiontext">Streams::latest</span><span class="plain">(</span><span class="identifier">x</span><span class="plain">)</span>
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_COPY</span><span class="plain">(</span><span class="identifier">to</span><span class="plain">, </span><span class="identifier">from</span><span class="plain">) </span><span class="functiontext">Streams::copy</span><span class="plain">(</span><span class="identifier">to</span><span class="plain">, </span><span class="identifier">from</span><span class="plain">)</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP15"></a><b>§15. </b>So much for the definition; now the implementation. Here is the <code class="display"><span class="extract">text_stream</span></code>
|
|
structure. Open memory streams are represented by structures where
|
|
<code class="display"><span class="extract">write_to_memory</span></code> is valid, open file streams by those where <code class="display"><span class="extract">write_to_file</span></code>
|
|
is valid. That counts every open stream except <code class="display"><span class="extract">NULL</span></code>, which of course
|
|
doesn't point to a <code class="display"><span class="extract">text_stream</span></code> structure at all.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Any stream can have <code class="display"><span class="extract">USES_XML_ESCAPES_STRF</span></code> set or cleared. When this is set, the
|
|
XML (and HTML) escapes of <code class="display"><span class="extract">&amp;</span></code> for ampersand, and <code class="display"><span class="extract">&lt;</span></code> and <code class="display"><span class="extract">&gt;</span></code> for
|
|
angle brackets, will be used automatically on writing. By default this flag
|
|
is clear, that is, no conversion is made.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="constant">MALLOCED_STRF</span><span class="plain"> </span><span class="constant">0x00000001</span><span class="plain"> </span><span class="comment"> was the <code class="display"><span class="extract">write_to_memory</span></code> pointer claimed by <code class="display"><span class="extract">malloc</span></code>?</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">USES_XML_ESCAPES_STRF</span><span class="plain"> </span><span class="constant">0x00000002</span><span class="plain"> </span><span class="comment"> see above</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">USES_LOG_ESCAPES_STRF</span><span class="plain"> </span><span class="constant">0x00000004</span><span class="plain"> </span><span class="comment"> <code class="display"><span class="extract">WRITE</span></code> to this stream supports <code class="display"><span class="extract">$</span></code> escapes</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">INDENT_PENDING_STRF</span><span class="plain"> </span><span class="constant">0x00000008</span><span class="plain"> </span><span class="comment"> we have just ended a line, so further text should indent</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">FILE_ENCODING_ISO_STRF</span><span class="plain"> </span><span class="constant">0x00000010</span><span class="plain"> </span><span class="comment"> relevant only for file streams</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">FILE_ENCODING_UTF8_STRF</span><span class="plain"> </span><span class="constant">0x00000020</span><span class="plain"> </span><span class="comment"> relevant only for file streams</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">FOR_RE_STRF</span><span class="plain"> </span><span class="constant">0x00000100</span><span class="plain"> </span><span class="comment"> for debugging only</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">FOR_TT_STRF</span><span class="plain"> </span><span class="constant">0x00000200</span><span class="plain"> </span><span class="comment"> for debugging only</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">FOR_CO_STRF</span><span class="plain"> </span><span class="constant">0x00000400</span><span class="plain"> </span><span class="comment"> for debugging only</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">FOR_FI_STRF</span><span class="plain"> </span><span class="constant">0x00000800</span><span class="plain"> </span><span class="comment"> for debugging only</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">FOR_OM_STRF</span><span class="plain"> </span><span class="constant">0x00001000</span><span class="plain"> </span><span class="comment"> for debugging only</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">USES_I6_ESCAPES_STRF</span><span class="plain"> </span><span class="constant">0x00002000</span><span class="plain"> </span><span class="comment"> as if an Inform 6 string</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">READ_ONLY_STRF</span><span class="plain"> </span><span class="constant">0x00008000</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">INDENTATION_BASE_STRF</span><span class="plain"> </span><span class="constant">0x00010000</span><span class="plain"> </span><span class="comment"> number of tab stops in from the left margin</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">INDENTATION_MASK_STRF</span><span class="plain"> </span><span class="constant">0x0FFF0000</span><span class="plain"> </span><span class="comment"> (held in these bits)</span>
|
|
</pre>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">text_stream</span><span class="plain"> {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">stream_flags</span><span class="plain">; </span><span class="comment"> bitmap of the <code class="display"><span class="extract">*_STRF</span></code> values above</span>
|
|
<span class="reserved">FILE</span><span class="plain"> *</span><span class="identifier">write_to_file</span><span class="plain">; </span><span class="comment"> for an open stream, exactly one of these is <code class="display"><span class="extract">NULL</span></code></span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">HTML_file_state</span><span class="plain"> *</span><span class="identifier">as_HTML</span><span class="plain">; </span><span class="comment"> relevant only to the <code class="display"><span class="extract">HTML::</span></code> section</span>
|
|
<span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">write_to_memory</span><span class="plain">;</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">file_written</span><span class="plain">; </span><span class="comment"> ditto</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">chars_written</span><span class="plain">; </span><span class="comment"> number of characters sent, counting <code class="display"><span class="extract">\n</span></code> as 1</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">chars_capacity</span><span class="plain">; </span><span class="comment"> maximum number the stream can accept without claiming more resources</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream_continues</span><span class="plain">; </span><span class="comment"> if one memory stream is extended by another</span>
|
|
<span class="plain">} </span><span class="reserved">text_stream</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The structure text_stream is accessed in 2/wal, 4/pm and here.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP16"></a><b>§16. </b>A theological question: what is the text encoding for the null stream?
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="identifier">STREAM_USES_UTF8</span><span class="plain">(</span><span class="identifier">x</span><span class="plain">) ((</span><span class="identifier">x</span><span class="plain">)?((</span><span class="identifier">x</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain">) & </span><span class="constant">FILE_ENCODING_UTF8_STRF</span><span class="plain">):</span><span class="constant">FALSE</span><span class="plain">)</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP17"></a><b>§17. </b>When text is stored at <code class="display"><span class="extract">write_to_memory</span></code>, it is kept as a zero-terminated C
|
|
wide string, with one word per Unicode code point. It turns out to be
|
|
efficient to preserve a small margin of clear space at the end of the space,
|
|
so out of the <code class="display"><span class="extract">chars_capacity</span></code> space, the following amount will be kept clear:
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="constant">SPACE_AT_END_OF_STREAM</span><span class="plain"> </span><span class="constant">6</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP18"></a><b>§18. </b>A statistic we keep, since it costs little:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">total_file_writes</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">; </span><span class="comment"> number of text files opened for writing during the run</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP19"></a><b>§19. Initialising the stream structure. </b>Note that the following fills in sensible defaults for every field, but the
|
|
result is not a valid open stream; it's a blank form ready to be filled in.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">By default the upper limit on file size is 2 GB. It's very hard to see this
|
|
ever being approached for any tool associated with the Inform project, where
|
|
text files have a size which is proportionate to the result of human writing.
|
|
The only output file with a sorceror's-apprentice-like ability to grow and
|
|
grow is the debugging file, and if it should reach 2 GB then it deserves to be
|
|
truncated and we will shed no tears.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::initialise</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">from</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tried to initialise NULL stream"</span><span class="plain">);</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> = </span><span class="identifier">from</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_capacity</span><span class="plain"> = </span><span class="constant">2147483647</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">as_HTML</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">file_written</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::initialise is used in <a href="#SP22">§22</a>, <a href="#SP23">§23</a>, <a href="#SP24">§24</a>, <a href="#SP25">§25</a>, <a href="#SP26">§26</a>, <a href="#SP27">§27</a>, <a href="#SP35_3">§35.3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP20"></a><b>§20. </b>Any stream can have the following flag set or cleared. When this is set, the
|
|
XML (and HTML) escapes of <code class="display"><span class="extract">&amp;</span></code> for ampersand, and <code class="display"><span class="extract">&lt;</span></code> and <code class="display"><span class="extract">&gt;</span></code> for
|
|
angle brackets, will be used automatically on writing. By default this flag
|
|
is clear, that is, no conversion is made.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::enable_XML_escapes</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">) </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">USES_XML_ESCAPES_STRF</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::disable_XML_escapes</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">stream</span><span class="plain">) && (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> & </span><span class="constant">USES_XML_ESCAPES_STRF</span><span class="plain">))</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> -= </span><span class="constant">USES_XML_ESCAPES_STRF</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">I6_escapes_globally_enabled</span><span class="plain"> = </span><span class="constant">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::enable_I6_escapes</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">) </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">USES_I6_ESCAPES_STRF</span><span class="plain">;</span>
|
|
<span class="identifier">I6_escapes_globally_enabled</span><span class="plain"> = </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::disable_I6_escapes</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">stream</span><span class="plain">) && (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> & </span><span class="constant">USES_I6_ESCAPES_STRF</span><span class="plain">))</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> -= </span><span class="constant">USES_I6_ESCAPES_STRF</span><span class="plain">;</span>
|
|
<span class="identifier">I6_escapes_globally_enabled</span><span class="plain"> = </span><span class="constant">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Streams::I6_escapes_enabled</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">I6_escapes_globally_enabled</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::enable_debugging</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">) </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">USES_LOG_ESCAPES_STRF</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::disable_debugging</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">stream</span><span class="plain">) && (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> & </span><span class="constant">USES_LOG_ESCAPES_STRF</span><span class="plain">))</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> -= </span><span class="constant">USES_LOG_ESCAPES_STRF</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::mark_as_read_only</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">) </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">READ_ONLY_STRF</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::declare_as_HTML</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">HTML_file_state</span><span class="plain"> *</span><span class="identifier">hs</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">) </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">as_HTML</span><span class="plain"> = </span><span class="identifier">hs</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">HTML_file_state</span><span class="plain"> *</span><span class="functiontext">Streams::get_HTML_file_state</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">as_HTML</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::enable_XML_escapes appears nowhere else.</p>
|
|
|
|
<p class="endnote">The function Streams::disable_XML_escapes appears nowhere else.</p>
|
|
|
|
<p class="endnote">The function Streams::enable_I6_escapes appears nowhere else.</p>
|
|
|
|
<p class="endnote">The function Streams::disable_I6_escapes appears nowhere else.</p>
|
|
|
|
<p class="endnote">The function Streams::I6_escapes_enabled appears nowhere else.</p>
|
|
|
|
<p class="endnote">The function Streams::enable_debugging is used in 2/dl (<a href="2-dl.html#SP5">§5</a>).</p>
|
|
|
|
<p class="endnote">The function Streams::disable_debugging appears nowhere else.</p>
|
|
|
|
<p class="endnote">The function Streams::mark_as_read_only is used in 4/sm (<a href="4-sm.html#SP26_1">§26.1</a>).</p>
|
|
|
|
<p class="endnote">The function Streams::declare_as_HTML is used in 5/htm (<a href="5-htm.html#SP2">§2</a>).</p>
|
|
|
|
<p class="endnote">The function Streams::get_HTML_file_state is used in 5/htm (<a href="5-htm.html#SP3">§3</a>, <a href="5-htm.html#SP4">§4</a>, <a href="5-htm.html#SP5">§5</a>, <a href="5-htm.html#SP7">§7</a>, <a href="5-htm.html#SP8">§8</a>, <a href="5-htm.html#SP10">§10</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP21"></a><b>§21. Logging. </b></p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::log</span><span class="plain">(</span><span class="constant">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">void</span><span class="plain"> *</span><span class="identifier">vS</span><span class="plain">) {</span>
|
|
<span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain"> = (</span><span class="reserved">text_stream</span><span class="plain"> *) </span><span class="identifier">vS</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"NULL"</span><span class="plain">);</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">) {</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"F'%f'(%d)"</span><span class="plain">, </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">file_written</span><span class="plain">, </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">);</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"S%x("</span><span class="plain">, (</span><span class="reserved">long</span><span class="plain"> </span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">stream</span><span class="plain">);</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%d/%d"</span><span class="plain">, </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">, </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_capacity</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"+"</span><span class="plain">);</span>
|
|
<span class="identifier">stream</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">")"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::log is used in 1/fm (<a href="1-fm.html#SP8_3">§8.3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP22"></a><b>§22. Standard I/O wrappers. </b>The first call to <code class="display"><span class="extract">Streams::get_stdout()</span></code> creates a suitable wrapper for <code class="display"><span class="extract">stdout</span></code>
|
|
and returns a <code class="display"><span class="extract">text_stream *</span></code> pointer to it; subsequent calls just return this wrapper.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">text_stream</span><span class="plain"> </span><span class="identifier">STDOUT_struct</span><span class="plain">; </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">stdout_wrapper_initialised</span><span class="plain"> = </span><span class="constant">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">text_stream</span><span class="plain"> *</span><span class="functiontext">Streams::get_stdout</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stdout_wrapper_initialised</span><span class="plain"> == </span><span class="constant">FALSE</span><span class="plain">) {</span>
|
|
<span class="functiontext">Streams::initialise</span><span class="plain">(&</span><span class="identifier">STDOUT_struct</span><span class="plain">, </span><span class="constant">0</span><span class="plain">); </span><span class="identifier">STDOUT_struct</span><span class="plain">.</span><span class="element">write_to_file</span><span class="plain"> = </span><span class="identifier">stdout</span><span class="plain">;</span>
|
|
<span class="identifier">stdout_wrapper_initialised</span><span class="plain"> = </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="constant">LOCALE_IS_ISO</span>
|
|
<span class="identifier">STDOUT_struct</span><span class="plain">.</span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">FILE_ENCODING_ISO_STRF</span><span class="plain">;</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span>
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">LOCALE_IS_UTF8</span>
|
|
<span class="identifier">STDOUT_struct</span><span class="plain">.</span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">FILE_ENCODING_UTF8_STRF</span><span class="plain">;</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> &</span><span class="identifier">STDOUT_struct</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::get_stdout is used in <a href="#SP5">§5</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP23"></a><b>§23. </b>And similarly for the standard error file.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">text_stream</span><span class="plain"> </span><span class="identifier">STDERR_struct</span><span class="plain">; </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">stderr_wrapper_initialised</span><span class="plain"> = </span><span class="constant">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">text_stream</span><span class="plain"> *</span><span class="functiontext">Streams::get_stderr</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stderr_wrapper_initialised</span><span class="plain"> == </span><span class="constant">FALSE</span><span class="plain">) {</span>
|
|
<span class="functiontext">Streams::initialise</span><span class="plain">(&</span><span class="identifier">STDERR_struct</span><span class="plain">, </span><span class="constant">0</span><span class="plain">); </span><span class="identifier">STDERR_struct</span><span class="plain">.</span><span class="element">write_to_file</span><span class="plain"> = </span><span class="identifier">stderr</span><span class="plain">;</span>
|
|
<span class="identifier">stderr_wrapper_initialised</span><span class="plain"> = </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="constant">LOCALE_IS_ISO</span>
|
|
<span class="identifier">STDERR_struct</span><span class="plain">.</span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">FILE_ENCODING_ISO_STRF</span><span class="plain">;</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span>
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">LOCALE_IS_UTF8</span>
|
|
<span class="identifier">STDERR_struct</span><span class="plain">.</span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">FILE_ENCODING_UTF8_STRF</span><span class="plain">;</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> &</span><span class="identifier">STDERR_struct</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::get_stderr is used in <a href="#SP5">§5</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP24"></a><b>§24. Creating file streams. </b>Note that this can fail, if the host filing system refuses to open the file,
|
|
so we return <code class="display"><span class="extract">TRUE</span></code> if and only if successful.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Streams::open_to_file</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">name</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">encoding</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tried to open NULL stream"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">name</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stream_open_to_file on null filename"</span><span class="plain">);</span>
|
|
<span class="functiontext">Streams::initialise</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="constant">FOR_FI_STRF</span><span class="plain">);</span>
|
|
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">encoding</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">UTF8_ENC:</span><span class="plain"> </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">FILE_ENCODING_UTF8_STRF</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">ISO_ENC:</span><span class="plain"> </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">FILE_ENCODING_ISO_STRF</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="identifier">default:</span><span class="plain"> </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stream has unknown text encoding"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain"> = </span><span class="functiontext">Filenames::fopen</span><span class="plain">(</span><span class="identifier">name</span><span class="plain">, </span><span class="string">"w"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">file_written</span><span class="plain"> = </span><span class="identifier">name</span><span class="plain">;</span>
|
|
<span class="identifier">total_file_writes</span><span class="plain">++;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::open_to_file is used in <a href="#SP9">§9</a>, 8/bf (<a href="8-bf.html#SP4">§4</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP25"></a><b>§25. </b>Similarly for appending:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Streams::open_to_file_append</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">name</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">encoding</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tried to open NULL stream"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">name</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stream_open_to_file on null filename"</span><span class="plain">);</span>
|
|
<span class="functiontext">Streams::initialise</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="constant">FOR_FI_STRF</span><span class="plain">);</span>
|
|
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">encoding</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">UTF8_ENC:</span><span class="plain"> </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">FILE_ENCODING_UTF8_STRF</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">ISO_ENC:</span><span class="plain"> </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">FILE_ENCODING_ISO_STRF</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="identifier">default:</span><span class="plain"> </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stream has unknown text encoding"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain"> = </span><span class="functiontext">Filenames::fopen</span><span class="plain">(</span><span class="identifier">name</span><span class="plain">, </span><span class="string">"a"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
|
|
<span class="identifier">total_file_writes</span><span class="plain">++;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::open_to_file_append is used in <a href="#SP9">§9</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP26"></a><b>§26. Creating memory streams. </b>Here we have a choice. One option is to use <code class="display"><span class="extract">malloc</span></code> to allocate memory to hold
|
|
the text of the stream; this too can fail for host platform reasons, so again
|
|
we return a success code.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Streams::open_to_memory</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">capacity</span><span class="plain">) {</span>
|
|
<span class="identifier">CREATE_MUTEX</span><span class="plain">(</span><span class="identifier">mutex</span><span class="plain">);</span>
|
|
<span class="identifier">LOCK_MUTEX</span><span class="plain">(</span><span class="identifier">mutex</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tried to open NULL stream"</span><span class="plain">);</span>
|
|
<span class="identifier">capacity</span><span class="plain"> += </span><span class="constant">SPACE_AT_END_OF_STREAM</span><span class="plain">;</span>
|
|
<span class="functiontext">Streams::initialise</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="constant">FOR_OM_STRF</span><span class="plain">);</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain"> = </span><span class="functiontext">Memory::I7_calloc</span><span class="plain">(</span><span class="identifier">capacity</span><span class="plain">, </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="identifier">wchar_t</span><span class="plain">), </span><span class="constant">STREAM_MREASON</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">(</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">)[0] = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">MALLOCED_STRF</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_capacity</span><span class="plain"> = </span><span class="identifier">capacity</span><span class="plain">;</span>
|
|
<span class="identifier">UNLOCK_MUTEX</span><span class="plain">(</span><span class="identifier">mutex</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::open_to_memory is used in <a href="#SP9">§9</a>, <a href="#SP28_3">§28.3</a>, 4/sm (<a href="4-sm.html#SP2">§2</a>, <a href="4-sm.html#SP3">§3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP27"></a><b>§27. </b>The other option avoids <code class="display"><span class="extract">malloc</span></code> by using specific storage already available.
|
|
If called validly, this cannot fail.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">text_stream</span><span class="plain"> </span><span class="functiontext">Streams::new_buffer</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">capacity</span><span class="plain">, </span><span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">at</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">at</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tried to make stream wrapper for NULL string"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">capacity</span><span class="plain"> < </span><span class="constant">SPACE_AT_END_OF_STREAM</span><span class="plain">)</span>
|
|
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"memory stream too small"</span><span class="plain">);</span>
|
|
<span class="reserved">text_stream</span><span class="plain"> </span><span class="identifier">stream</span><span class="plain">;</span>
|
|
<span class="functiontext">Streams::initialise</span><span class="plain">(&</span><span class="identifier">stream</span><span class="plain">, </span><span class="constant">FOR_TT_STRF</span><span class="plain">);</span>
|
|
<span class="identifier">stream</span><span class="plain">.</span><span class="element">write_to_memory</span><span class="plain"> = </span><span class="identifier">at</span><span class="plain">;</span>
|
|
<span class="plain">(</span><span class="identifier">stream</span><span class="plain">.</span><span class="element">write_to_memory</span><span class="plain">)[0] = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">.</span><span class="element">chars_capacity</span><span class="plain"> = </span><span class="identifier">capacity</span><span class="plain"> - </span><span class="constant">SPACE_AT_END_OF_STREAM</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">stream</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::new_buffer is used in <a href="#SP8">§8</a>, 4/pm (<a href="4-pm.html#SP10">§10</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28"></a><b>§28. Converting from C strings. </b>We then have three ways to open a stream whose initial contents are given
|
|
by a C string. First, a wide string (a sequence of 32-bit Unicode code
|
|
points, null terminated):
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Streams::open_from_wide_string</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">c_string</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tried to open NULL stream"</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">capacity</span><span class="plain"> = (</span><span class="identifier">c_string</span><span class="plain">)?((</span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">wcslen</span><span class="plain">(</span><span class="identifier">c_string</span><span class="plain">)):0;</span>
|
|
<<span class="cwebmacro">Ensure a capacity large enough to hold the initial string in one frame</span> <span class="cwebmacronumber">28.3</span>><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c_string</span><span class="plain">) </span><span class="functiontext">Streams::write_wide_string</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">c_string</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::write_wide_string</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">c_string</span><span class="plain">) {</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">c_string</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]; </span><span class="identifier">i</span><span class="plain">++) </span><span class="functiontext">Streams::putc</span><span class="plain">(</span><span class="identifier">c_string</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">stream</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::open_from_wide_string is used in 4/sm (<a href="4-sm.html#SP4">§4</a>, <a href="4-sm.html#SP5">§5</a>).</p>
|
|
|
|
<p class="endnote">The function Streams::write_wide_string is used in 4/sm (<a href="4-sm.html#SP17">§17</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28_1"></a><b>§28.1. </b>Similarly, an ISO string (a sequence of 8-bit code points in the first
|
|
page of the Unicode set, null terminated):
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Streams::open_from_ISO_string</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">c_string</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tried to open NULL stream"</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">capacity</span><span class="plain"> = (</span><span class="identifier">c_string</span><span class="plain">)?((</span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">strlen</span><span class="plain">(</span><span class="identifier">c_string</span><span class="plain">)):0;</span>
|
|
<<span class="cwebmacro">Ensure a capacity large enough to hold the initial string in one frame</span> <span class="cwebmacronumber">28.3</span>><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c_string</span><span class="plain">) </span><span class="functiontext">Streams::write_ISO_string</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">c_string</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::write_ISO_string</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">c_string</span><span class="plain">) {</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">c_string</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]; </span><span class="identifier">i</span><span class="plain">++) </span><span class="functiontext">Streams::putc</span><span class="plain">(</span><span class="identifier">c_string</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">stream</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::open_from_ISO_string is used in <a href="#SP32">§32</a>, 4/sm (<a href="4-sm.html#SP4">§4</a>).</p>
|
|
|
|
<p class="endnote">The function Streams::write_ISO_string is used in <a href="#SP32">§32</a>, 4/sm (<a href="4-sm.html#SP17">§17</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28_2"></a><b>§28.2. </b>Finally, a UTF-8 encoded C string:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Streams::open_from_UTF8_string</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">c_string</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tried to open NULL stream"</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">capacity</span><span class="plain"> = (</span><span class="identifier">c_string</span><span class="plain">)?((</span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">strlen</span><span class="plain">(</span><span class="identifier">c_string</span><span class="plain">)):0;</span>
|
|
<<span class="cwebmacro">Ensure a capacity large enough to hold the initial string in one frame</span> <span class="cwebmacronumber">28.3</span>><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c_string</span><span class="plain">) </span><span class="functiontext">Streams::write_UTF8_string</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">c_string</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::write_UTF8_string</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">c_string</span><span class="plain">) {</span>
|
|
<span class="reserved">unicode_file_buffer</span><span class="plain"> </span><span class="identifier">ufb</span><span class="plain"> = </span><span class="functiontext">TextFiles::create_ufb</span><span class="plain">();</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain">;</span>
|
|
<span class="reserved">while</span><span class="plain"> ((</span><span class="identifier">c</span><span class="plain"> = </span><span class="functiontext">TextFiles::utf8_fgetc</span><span class="plain">(</span><span class="identifier">NULL</span><span class="plain">, &</span><span class="identifier">c_string</span><span class="plain">, </span><span class="constant">FALSE</span><span class="plain">, &</span><span class="identifier">ufb</span><span class="plain">)) != </span><span class="constant">0</span><span class="plain">)</span>
|
|
<span class="functiontext">Streams::putc</span><span class="plain">(</span><span class="identifier">c</span><span class="plain">, </span><span class="identifier">stream</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::open_from_UTF8_string is used in <a href="#SP32">§32</a>, 4/sm (<a href="4-sm.html#SP4">§4</a>).</p>
|
|
|
|
<p class="endnote">The function Streams::write_UTF8_string is used in <a href="#SP32">§32</a>, 4/sm (<a href="4-sm.html#SP17">§17</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28_3"></a><b>§28.3. </b>...all of which use:
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Ensure a capacity large enough to hold the initial string in one frame</span> <span class="cwebmacronumber">28.3</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">capacity</span><span class="plain"> < </span><span class="constant">8</span><span class="plain">) </span><span class="identifier">capacity</span><span class="plain"> = </span><span class="constant">8</span><span class="plain">;</span>
|
|
<span class="identifier">capacity</span><span class="plain"> += </span><span class="constant">1</span><span class="plain">+</span><span class="constant">SPACE_AT_END_OF_STREAM</span><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rv</span><span class="plain"> = </span><span class="functiontext">Streams::open_to_memory</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">capacity</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rv</span><span class="plain"> == </span><span class="constant">FALSE</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP28">§28</a>, <a href="#SP28_1">§28.1</a>, <a href="#SP28_2">§28.2</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP29"></a><b>§29. Converting to C strings. </b>Now for the converse problem.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::write_as_wide_string</span><span class="plain">(</span><span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">C_string</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">buffer_size</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">buffer_size</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) { </span><span class="identifier">C_string</span><span class="plain">[0] = </span><span class="constant">0</span><span class="plain">; </span><span class="reserved">return</span><span class="plain">; }</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stream_get_text on file stream"</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">j</span><span class="plain">=0; </span><span class="identifier">j</span><span class="plain"><</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">; </span><span class="identifier">j</span><span class="plain">++) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain"> >= </span><span class="identifier">buffer_size</span><span class="plain">-1) </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="identifier">C_string</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++] = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">[</span><span class="identifier">j</span><span class="plain">];</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">stream</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">C_string</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::write_as_wide_string is used in 4/sm (<a href="4-sm.html#SP6">§6</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP30"></a><b>§30. </b>Unicode code points outside the first page are flattened to <code class="display"><span class="extract">'?'</span></code> in an
|
|
ISO string:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::write_as_ISO_string</span><span class="plain">(</span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">C_string</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">buffer_size</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">buffer_size</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) { </span><span class="identifier">C_string</span><span class="plain">[0] = </span><span class="constant">0</span><span class="plain">; </span><span class="reserved">return</span><span class="plain">; }</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stream_get_text on file stream"</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">j</span><span class="plain">=0; </span><span class="identifier">j</span><span class="plain"><</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">; </span><span class="identifier">j</span><span class="plain">++) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain"> >= </span><span class="identifier">buffer_size</span><span class="plain">-1) </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="identifier">wchar_t</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">[</span><span class="identifier">j</span><span class="plain">];</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> < </span><span class="constant">256</span><span class="plain">) </span><span class="identifier">C_string</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++] = (</span><span class="reserved">char</span><span class="plain">) </span><span class="identifier">c</span><span class="plain">; </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">C_string</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++] = </span><span class="character">'?'</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">stream</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">C_string</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::write_as_ISO_string is used in <a href="#SP32">§32</a>, 4/sm (<a href="4-sm.html#SP6">§6</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP31"></a><b>§31. </b></p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::write_as_UTF8_string</span><span class="plain">(</span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">C_string</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">buffer_size</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">buffer_size</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) { </span><span class="identifier">C_string</span><span class="plain">[0] = </span><span class="constant">0</span><span class="plain">; </span><span class="reserved">return</span><span class="plain">; }</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stream_get_text on file stream"</span><span class="plain">);</span>
|
|
<span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">to</span><span class="plain"> = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> *) </span><span class="identifier">C_string</span><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">j</span><span class="plain">=0; </span><span class="identifier">j</span><span class="plain"><</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">; </span><span class="identifier">j</span><span class="plain">++) {</span>
|
|
<span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">[</span><span class="identifier">j</span><span class="plain">];</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> >= </span><span class="constant">0x800</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain"> >= </span><span class="identifier">buffer_size</span><span class="plain">-3) </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="identifier">to</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++] = </span><span class="constant">0xE0</span><span class="plain"> + (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain">) (</span><span class="identifier">c</span><span class="plain"> >> </span><span class="constant">12</span><span class="plain">);</span>
|
|
<span class="identifier">to</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++] = </span><span class="constant">0x80</span><span class="plain"> + (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain">) ((</span><span class="identifier">c</span><span class="plain"> >> </span><span class="constant">6</span><span class="plain">) & </span><span class="constant">0x3f</span><span class="plain">);</span>
|
|
<span class="identifier">to</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++] = </span><span class="constant">0x80</span><span class="plain"> + (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain">) (</span><span class="identifier">c</span><span class="plain"> & </span><span class="constant">0x3f</span><span class="plain">);</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> >= </span><span class="constant">0x80</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain"> >= </span><span class="identifier">buffer_size</span><span class="plain">-2) </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="identifier">to</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++] = </span><span class="constant">0xC0</span><span class="plain"> + (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain">) (</span><span class="identifier">c</span><span class="plain"> >> </span><span class="constant">6</span><span class="plain">);</span>
|
|
<span class="identifier">to</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++] = </span><span class="constant">0x80</span><span class="plain"> + (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain">) (</span><span class="identifier">c</span><span class="plain"> & </span><span class="constant">0x3f</span><span class="plain">);</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain"> >= </span><span class="identifier">buffer_size</span><span class="plain">-1) </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="identifier">to</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++] = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain">) </span><span class="identifier">c</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">stream</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">to</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::write_as_UTF8_string is used in <a href="#SP32">§32</a>, 4/sm (<a href="4-sm.html#SP6">§6</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP32"></a><b>§32. Locale versions. </b></p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Streams::open_from_locale_string</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">C_string</span><span class="plain">) {</span>
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">LOCALE_IS_UTF8</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Streams::open_from_UTF8_string</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">C_string</span><span class="plain">);</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span>
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="constant">LOCALE_IS_ISO</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Streams::open_from_ISO_string</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">C_string</span><span class="plain">);</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::write_as_locale_string</span><span class="plain">(</span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">C_string</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">buffer_size</span><span class="plain">) {</span>
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">LOCALE_IS_UTF8</span>
|
|
<span class="functiontext">Streams::write_as_UTF8_string</span><span class="plain">(</span><span class="identifier">C_string</span><span class="plain">, </span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">buffer_size</span><span class="plain">);</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span>
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="constant">LOCALE_IS_ISO</span>
|
|
<span class="functiontext">Streams::write_as_ISO_string</span><span class="plain">(</span><span class="identifier">C_string</span><span class="plain">, </span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">buffer_size</span><span class="plain">);</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::write_locale_string</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">C_string</span><span class="plain">) {</span>
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">LOCALE_IS_UTF8</span>
|
|
<span class="functiontext">Streams::write_UTF8_string</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">C_string</span><span class="plain">);</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span>
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="constant">LOCALE_IS_ISO</span>
|
|
<span class="functiontext">Streams::write_ISO_string</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="identifier">C_string</span><span class="plain">);</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::open_from_locale_string is used in 4/sm (<a href="4-sm.html#SP4">§4</a>, <a href="4-sm.html#SP5">§5</a>).</p>
|
|
|
|
<p class="endnote">The function Streams::write_as_locale_string is used in 3/shl (<a href="3-shl.html#SP5">§5</a>), 4/sm (<a href="4-sm.html#SP6">§6</a>).</p>
|
|
|
|
<p class="endnote">The function Streams::write_locale_string is used in 3/cla (<a href="3-cla.html#SP8">§8</a>), 3/drc (<a href="3-drc.html#SP2">§2</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP33"></a><b>§33. Flush and close. </b>Note that flush is an operation which can be performed on any stream, including
|
|
<code class="display"><span class="extract">NULL</span></code>:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::flush</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">) </span><span class="identifier">fflush</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::flush is used in <a href="#SP10">§10</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP34"></a><b>§34. </b>But closing is not allowed for <code class="display"><span class="extract">NULL</span></code> or the standard I/O wrappers:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::close</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tried to close NULL stream"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == &</span><span class="identifier">STDOUT_struct</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tried to close STDOUT stream"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == &</span><span class="identifier">STDERR_struct</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tried to close STDERR stream"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_capacity</span><span class="plain"> == -1) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stream closed twice"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">) {</span>
|
|
<span class="functiontext">Streams::close</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">);</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_capacity</span><span class="plain"> = -1; </span><span class="comment"> mark as closed</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">) </span><<span class="cwebmacro">Take suitable action to close the file stream</span> <span class="cwebmacronumber">34.1</span>><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">) </span><<span class="cwebmacro">Take suitable action to close the memory stream</span> <span class="cwebmacronumber">34.2</span>><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::close is used in <a href="#SP9">§9</a>, <a href="#SP40">§40</a>, <a href="#SP41">§41</a>, 8/bf (<a href="8-bf.html#SP4">§4</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP34_1"></a><b>§34.1. </b>Note that we need do nothing to close a memory stream when the storage
|
|
was supplied by our client; it only needs freeing if we were the ones who
|
|
allocated it.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Inscrutably, <code class="display"><span class="extract">fclose</span></code> returns <code class="display"><span class="extract">EOF</span></code> to report any failure.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Take suitable action to close the file stream</span> <span class="cwebmacronumber">34.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">ferror</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">)) || (</span><span class="identifier">fclose</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">) == </span><span class="identifier">EOF</span><span class="plain">))</span>
|
|
<span class="functiontext">Errors::fatal</span><span class="plain">(</span><span class="string">"The host computer reported an error trying to write a text file"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> != </span><span class="identifier">DL</span><span class="plain">)</span>
|
|
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">TEXT_FILES</span><span class="plain">, </span><span class="string">"Text file '%f' (%s): %d characters written\n"</span><span class="plain">,</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">file_written</span><span class="plain">,</span>
|
|
<span class="plain">(</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> & </span><span class="constant">FILE_ENCODING_UTF8_STRF</span><span class="plain">)?</span><span class="string">"UTF8"</span><span class="plain">:</span><span class="string">"ISO"</span><span class="plain">,</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">);</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP34">§34</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP34_2"></a><b>§34.2. </b>Note that we need do nothing to close a memory stream when the storage
|
|
was supplied by our client; it only needs freeing if we were the ones who
|
|
allocated it. <code class="display"><span class="extract">free</span></code> is a void function; in theory it cannot fail, if
|
|
supplied a valid argument.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">We have to be very careful once we have called <code class="display"><span class="extract">free</span></code>, because that memory
|
|
may well contain the <code class="display"><span class="extract">text_stream</span></code> structure to which <code class="display"><span class="extract">stream</span></code> points — see
|
|
how continuations are made, below.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Take suitable action to close the memory stream</span> <span class="cwebmacronumber">34.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain">) & </span><span class="constant">MALLOCED_STRF</span><span class="plain">) {</span>
|
|
<span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">mem</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="functiontext">Memory::I7_free</span><span class="plain">(</span><span class="identifier">mem</span><span class="plain">, </span><span class="constant">STREAM_MREASON</span><span class="plain">, </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_capacity</span><span class="plain">*((</span><span class="reserved">int</span><span class="plain">) </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="identifier">wchar_t</span><span class="plain">)));</span>
|
|
<span class="identifier">stream</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP34">§34</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP35"></a><b>§35. Writing. </b>Our equivalent of <code class="display"><span class="extract">fputc</span></code> reads:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::putc</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">c_int</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c_int</span><span class="plain"> >= </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">c</span><span class="plain"> = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">c_int</span><span class="plain">; </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">int</span><span class="plain">) (</span><span class="identifier">c_int</span><span class="plain"> + </span><span class="constant">256</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">first_stream</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> != </span><span class="character">'\n'</span><span class="plain">) </span><<span class="cwebmacro">Insert indentation if this is pending</span> <span class="cwebmacronumber">35.2</span>><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> & </span><span class="constant">READ_ONLY_STRF</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"modifying read-only stream"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain">) & </span><span class="constant">USES_XML_ESCAPES_STRF</span><span class="plain">) {</span>
|
|
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">c</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">NEWLINE_IN_STRING:</span><span class="plain"> </span><span class="functiontext">Streams::literal</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="string">"<br>"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="character">'&'</span><span class="plain">: </span><span class="functiontext">Streams::literal</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="string">"&amp;"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="character">'<'</span><span class="plain">: </span><span class="functiontext">Streams::literal</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="string">"&lt;"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="character">'>'</span><span class="plain">: </span><span class="functiontext">Streams::literal</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">, </span><span class="string">"&gt;"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">) </span><span class="identifier">stream</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">;</span>
|
|
<<span class="cwebmacro">Ensure there is room to expand the escape sequence into</span> <span class="cwebmacronumber">35.3</span>><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> & </span><span class="constant">FILE_ENCODING_UTF8_STRF</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Put a UTF8-encoded character into the underlying file</span> <span class="cwebmacronumber">35.1</span>>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> & </span><span class="constant">FILE_ENCODING_ISO_STRF</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> >= </span><span class="constant">0x100</span><span class="plain">) </span><span class="identifier">c</span><span class="plain"> = </span><span class="character">'?'</span><span class="plain">;</span>
|
|
<span class="identifier">fputc</span><span class="plain">((</span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">c</span><span class="plain">, </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">);</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stream has unknown text encoding"</span><span class="plain">);</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">c</span><span class="plain"> >= </span><span class="constant">0x0300</span><span class="plain">) && (</span><span class="identifier">c</span><span class="plain"> <= </span><span class="constant">0x036F</span><span class="plain">) && (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain"> > </span><span class="constant">0</span><span class="plain">)) {</span>
|
|
<span class="identifier">c</span><span class="plain"> = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">int</span><span class="plain">) </span><span class="functiontext">Characters::combine_accent</span><span class="plain">(</span>
|
|
<span class="plain">(</span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">c</span><span class="plain">, (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">)[</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain"> - </span><span class="constant">1</span><span class="plain">]);</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">--;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">(</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">)[</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">] = (</span><span class="identifier">wchar_t</span><span class="plain">) </span><span class="identifier">c</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'\n'</span><span class="plain">) </span><span class="identifier">first_stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> |= </span><span class="constant">INDENT_PENDING_STRF</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">++;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::putc is used in <a href="#SP6">§6</a>, <a href="#SP28">§28</a>, <a href="#SP28_1">§28.1</a>, <a href="#SP28_2">§28.2</a>, <a href="#SP35_2">§35.2</a>, <a href="#SP36">§36</a>, <a href="#SP42">§42</a>, 2/wal (<a href="2-wal.html#SP6">§6</a>, <a href="2-wal.html#SP6_1_1">§6.1.1</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP35_1"></a><b>§35.1. </b>Where we pack large character values, up to 65535, as follows.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Put a UTF8-encoded character into the underlying file</span> <span class="cwebmacronumber">35.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> >= </span><span class="constant">0x800</span><span class="plain">) {</span>
|
|
<span class="identifier">fputc</span><span class="plain">(</span><span class="constant">0xE0</span><span class="plain"> + (</span><span class="identifier">c</span><span class="plain"> >> </span><span class="constant">12</span><span class="plain">), </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">);</span>
|
|
<span class="identifier">fputc</span><span class="plain">(</span><span class="constant">0x80</span><span class="plain"> + ((</span><span class="identifier">c</span><span class="plain"> >> </span><span class="constant">6</span><span class="plain">) & </span><span class="constant">0x3f</span><span class="plain">), </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">);</span>
|
|
<span class="identifier">fputc</span><span class="plain">(</span><span class="constant">0x80</span><span class="plain"> + (</span><span class="identifier">c</span><span class="plain"> & </span><span class="constant">0x3f</span><span class="plain">), </span><span class="identifier">stream</span><span class="plain">-></span><span class="identifier">write_to_file</span><span class="plain">);</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> >= </span><span class="constant">0x80</span><span class="plain">) {</span>
|
|
<span class="identifier">fputc</span><span class="plain">(</span><span class="constant">0xC0</span><span class="plain"> + (</span><span class="identifier">c</span><span class="plain"> >> </span><span class="constant">6</span><span class="plain">), </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">);</span>
|
|
<span class="identifier">fputc</span><span class="plain">(</span><span class="constant">0x80</span><span class="plain"> + (</span><span class="identifier">c</span><span class="plain"> & </span><span class="constant">0x3f</span><span class="plain">), </span><span class="identifier">stream</span><span class="plain">-></span><span class="identifier">write_to_file</span><span class="plain">);</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">fputc</span><span class="plain">((</span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">c</span><span class="plain">, </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP35">§35</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP35_2"></a><b>§35.2. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Insert indentation if this is pending</span> <span class="cwebmacronumber">35.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">first_stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> & </span><span class="constant">INDENT_PENDING_STRF</span><span class="plain">) {</span>
|
|
<span class="identifier">first_stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> -= </span><span class="constant">INDENT_PENDING_STRF</span><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">L</span><span class="plain"> = (</span><span class="identifier">first_stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> & </span><span class="constant">INDENTATION_MASK_STRF</span><span class="plain">)/</span><span class="constant">INDENTATION_BASE_STRF</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain"><</span><span class="identifier">L</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) {</span>
|
|
<span class="functiontext">Streams::putc</span><span class="plain">(</span><span class="character">' '</span><span class="plain">, </span><span class="identifier">first_stream</span><span class="plain">); </span><span class="functiontext">Streams::putc</span><span class="plain">(</span><span class="character">' '</span><span class="plain">, </span><span class="identifier">first_stream</span><span class="plain">);</span>
|
|
<span class="functiontext">Streams::putc</span><span class="plain">(</span><span class="character">' '</span><span class="plain">, </span><span class="identifier">first_stream</span><span class="plain">); </span><span class="functiontext">Streams::putc</span><span class="plain">(</span><span class="character">' '</span><span class="plain">, </span><span class="identifier">first_stream</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP35">§35</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP35_3"></a><b>§35.3. </b>The following is checked before any numerical <code class="display"><span class="extract">printf</span></code>-style escape is expanded
|
|
into the stream, or before any single character is written. Thus we cannot
|
|
overrun our buffers unless the expansion of a numerical escape exceeds
|
|
<code class="display"><span class="extract">SPACE_AT_END_OF_STREAM</span></code> plus 1 in size. Since no outside influence gets to
|
|
choose what formatting escapes we use (so that <code class="display"><span class="extract">%3000d</span></code>, say, can't occur),
|
|
we can be pretty confident.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">The interesting case occurs when we run out of memory in a memory stream.
|
|
We make a continuation to a fresh <code class="display"><span class="extract">text_stream</span></code> structure, which points to twice
|
|
as much memory as the original, allocated via <code class="display"><span class="extract">malloc</span></code>. (We will actually need
|
|
a little more memory than that because we also have to make room for the
|
|
<code class="display"><span class="extract">text_stream</span></code> structure itself.) We then set <code class="display"><span class="extract">stream</span></code> to the <code class="display"><span class="extract">continuation</span></code>. Given
|
|
that <code class="display"><span class="extract">malloc</span></code> was successful — and it must have been or we would have stopped
|
|
with a fatal error — the continuation is guaranteed to be large enough,
|
|
since it's twice the size of the original, which itself was large enough to
|
|
hold any escape sequence when opened.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Ensure there is room to expand the escape sequence into</span> <span class="cwebmacronumber">35.3</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain"> + </span><span class="constant">SPACE_AT_END_OF_STREAM</span><span class="plain"> >= </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_capacity</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">; </span><span class="comment"> write nothing further</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">offset</span><span class="plain"> = (32 + </span><span class="constant">2</span><span class="plain">*(</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_capacity</span><span class="plain">))*((</span><span class="reserved">int</span><span class="plain">) </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="identifier">wchar_t</span><span class="plain">));</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">needed</span><span class="plain"> = </span><span class="identifier">offset</span><span class="plain"> + ((</span><span class="reserved">int</span><span class="plain">) </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain">)) + </span><span class="constant">32</span><span class="plain">;</span>
|
|
<span class="reserved">void</span><span class="plain"> *</span><span class="identifier">further_allocation</span><span class="plain"> = </span><span class="functiontext">Memory::I7_malloc</span><span class="plain">(</span><span class="identifier">needed</span><span class="plain">, </span><span class="constant">STREAM_MREASON</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">further_allocation</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="functiontext">Errors::fatal</span><span class="plain">(</span><span class="string">"Out of memory"</span><span class="plain">);</span>
|
|
<span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">continuation</span><span class="plain"> = (</span><span class="reserved">text_stream</span><span class="plain"> *) (</span><span class="identifier">further_allocation</span><span class="plain"> + </span><span class="identifier">offset</span><span class="plain">);</span>
|
|
<span class="functiontext">Streams::initialise</span><span class="plain">(</span><span class="identifier">continuation</span><span class="plain">, </span><span class="constant">FOR_CO_STRF</span><span class="plain">);</span>
|
|
<span class="identifier">continuation</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain"> = </span><span class="identifier">further_allocation</span><span class="plain">;</span>
|
|
<span class="identifier">continuation</span><span class="plain">-></span><span class="element">chars_capacity</span><span class="plain"> = </span><span class="constant">2</span><span class="plain">*</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_capacity</span><span class="plain">;</span>
|
|
<span class="plain">(</span><span class="identifier">continuation</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">)[0] = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain"> = </span><span class="identifier">continuation</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain"> = </span><span class="identifier">continuation</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP35">§35</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP36"></a><b>§36. </b>Literal printing is just printing with XML escapes switched off:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::literal</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">, </span><span class="identifier">x</span><span class="plain"> = ((</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain">) & </span><span class="constant">USES_XML_ESCAPES_STRF</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">x</span><span class="plain">) </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> -= </span><span class="constant">USES_XML_ESCAPES_STRF</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]; </span><span class="identifier">i</span><span class="plain">++) </span><span class="functiontext">Streams::putc</span><span class="plain">((</span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">stream</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">x</span><span class="plain">) </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> += </span><span class="constant">USES_XML_ESCAPES_STRF</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::literal is used in <a href="#SP35">§35</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP37"></a><b>§37. </b>Shifting indentation. For every indent there must be an equal and opposite
|
|
outdent, but error conditions can cause some compilation routines to issue
|
|
problem messages and then leave what they're doing incomplete, so we will
|
|
be a little cautious about assuming that a mismatch means an error.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::indent</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> += </span><span class="constant">INDENTATION_BASE_STRF</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::outdent</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> & </span><span class="constant">INDENTATION_MASK_STRF</span><span class="plain">) == </span><span class="constant">0</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Errors::have_occurred</span><span class="plain">() == </span><span class="constant">FALSE</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stream indentation negative"</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> -= </span><span class="constant">INDENTATION_BASE_STRF</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::set_indentation</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">N</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">B</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> & </span><span class="constant">INDENTATION_MASK_STRF</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> -= </span><span class="identifier">B</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> += </span><span class="identifier">N</span><span class="plain">*</span><span class="constant">INDENTATION_BASE_STRF</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::indent is used in <a href="#SP7">§7</a>.</p>
|
|
|
|
<p class="endnote">The function Streams::outdent is used in <a href="#SP7">§7</a>.</p>
|
|
|
|
<p class="endnote">The function Streams::set_indentation is used in <a href="#SP7">§7</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP38"></a><b>§38. </b>We can read the position for any stream, including <code class="display"><span class="extract">NULL</span></code>, but no matter
|
|
how much is written to <code class="display"><span class="extract">NULL</span></code> this position never budges.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Because of continuations, this is not as simple as returning the <code class="display"><span class="extract">chars_written</span></code>
|
|
field.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Streams::get_position</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">t</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="identifier">t</span><span class="plain"> += </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">t</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::get_position is used in <a href="#SP11">§11</a>, <a href="#SP13">§13</a>, 4/sm (<a href="4-sm.html#SP8">§8</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP39"></a><b>§39. Memory-stream-only functions. </b>While it would be easy enough to implement this for file streams too, there's
|
|
no point, since it is used only in concert with backspacing.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Streams::latest</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stream_latest on file stream"</span><span class="plain">);</span>
|
|
<span class="reserved">while</span><span class="plain"> ((</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">) && (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain"> > </span><span class="constant">0</span><span class="plain">))</span>
|
|
<span class="identifier">stream</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain"> > </span><span class="constant">0</span><span class="plain">)</span>
|
|
<span class="reserved">return</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain">) ((</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">)[</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain"> - </span><span class="constant">1</span><span class="plain">]);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::latest is used in <a href="#SP14">§14</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP40"></a><b>§40. </b>Accessing characters by index. Note that the stream terminates at the first
|
|
zero byte found, so that putting a zero truncates it.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">wchar_t</span><span class="plain"> </span><span class="functiontext">Streams::get_char_at_index</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">position</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"examining null stream"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"examining file stream"</span><span class="plain">);</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">position</span><span class="plain"> >= </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">) {</span>
|
|
<span class="identifier">position</span><span class="plain"> = </span><span class="identifier">position</span><span class="plain"> - </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">)[</span><span class="identifier">position</span><span class="plain">];</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::put_char_at_index</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">position</span><span class="plain">, </span><span class="identifier">wchar_t</span><span class="plain"> </span><span class="identifier">C</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"modifying null stream"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"modifying file stream"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> & </span><span class="constant">READ_ONLY_STRF</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"modifying read-only stream"</span><span class="plain">);</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">position</span><span class="plain"> >= </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">) {</span>
|
|
<span class="identifier">position</span><span class="plain"> = </span><span class="identifier">position</span><span class="plain"> - </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"overrun memory stream"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">(</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">)[</span><span class="identifier">position</span><span class="plain">] = </span><span class="identifier">C</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">C</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) {</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain"> = </span><span class="identifier">position</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">) {</span>
|
|
<span class="functiontext">Streams::close</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">);</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::get_char_at_index is used in 4/sm (<a href="4-sm.html#SP13">§13</a>).</p>
|
|
|
|
<p class="endnote">The function Streams::put_char_at_index is used in 4/sm (<a href="4-sm.html#SP14">§14</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP41"></a><b>§41. </b>Now for what is the trickiest function, because the position may be moved back
|
|
so that later continuations fall away. This will very rarely happen, so we
|
|
won't worry about the inefficiency of freeing up the memory saved by closing
|
|
such continuation blocks (which would be inefficient if we immediately had
|
|
to open similar ones again).
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::set_position</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">stream</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">position</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">position</span><span class="plain"> < </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">position</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">; </span><span class="comment"> to simplify the implementation of backspacing</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_file</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stream_set_position on file stream"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_flags</span><span class="plain"> & </span><span class="constant">READ_ONLY_STRF</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"modifying read-only stream"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">) {</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">position</span><span class="plain"> > </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">) {</span>
|
|
<span class="identifier">position</span><span class="plain"> = </span><span class="identifier">position</span><span class="plain"> - </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">;</span>
|
|
<span class="identifier">stream</span><span class="plain"> = </span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"can't set position forwards"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain"> = </span><span class="identifier">position</span><span class="plain">;</span>
|
|
<span class="plain">(</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">)[</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">] = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">) {</span>
|
|
<span class="functiontext">Streams::close</span><span class="plain">(</span><span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">);</span>
|
|
<span class="identifier">stream</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::set_position is used in <a href="#SP13">§13</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP42"></a><b>§42. </b>Lastly, our copying function, where <code class="display"><span class="extract">from</span></code> has to be a memory stream (or
|
|
<code class="display"><span class="extract">NULL</span></code>) but <code class="display"><span class="extract">to</span></code> can be anything (including <code class="display"><span class="extract">NULL</span></code>).
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::copy</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">to</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">from</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">from</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) || (</span><span class="identifier">to</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">from</span><span class="plain">-></span><span class="identifier">write_to_file</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stream_copy from file stream"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">from</span><span class="plain">-></span><span class="identifier">write_to_memory</span><span class="plain">) {</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain"><</span><span class="identifier">from</span><span class="plain">-></span><span class="element">chars_written</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = (</span><span class="reserved">int</span><span class="plain">) ((</span><span class="identifier">from</span><span class="plain">-></span><span class="element">write_to_memory</span><span class="plain">)[</span><span class="identifier">i</span><span class="plain">]);</span>
|
|
<span class="functiontext">Streams::putc</span><span class="plain">(</span><span class="identifier">c</span><span class="plain">, </span><span class="identifier">to</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">from</span><span class="plain">-></span><span class="identifier">stream_continues</span><span class="plain">) </span><span class="functiontext">Streams::copy</span><span class="plain">(</span><span class="identifier">to</span><span class="plain">, </span><span class="identifier">from</span><span class="plain">-></span><span class="element">stream_continues</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::copy is used in <a href="#SP14">§14</a>, <a href="#SP43">§43</a>, 4/sm (<a href="4-sm.html#SP3">§3</a>, <a href="4-sm.html#SP16">§16</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP43"></a><b>§43. Writer. </b>This writes one stream into another one, which implements <code class="display"><span class="extract">%S</span></code>.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Streams::writer</span><span class="plain">(</span><span class="constant">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">format_string</span><span class="plain">, </span><span class="reserved">void</span><span class="plain"> *</span><span class="identifier">vS</span><span class="plain">) {</span>
|
|
<span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">S</span><span class="plain"> = (</span><span class="reserved">text_stream</span><span class="plain"> *) </span><span class="identifier">vS</span><span class="plain">;</span>
|
|
<span class="functiontext">Streams::copy</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Streams::writer is used in 1/fm (<a href="1-fm.html#SP8_1">§8.1</a>).</p>
|
|
|
|
<hr class="tocbar">
|
|
<ul class="toc"><li><a href="2-mmr.html">Back to 'Memory'</a></li><li><a href="2-wal.html">Continue with 'Writers and Loggers'</a></li></ul><hr class="tocbar">
|
|
<!--End of weave-->
|
|
</main>
|
|
</body>
|
|
</html>
|
|
|