% \iffalse
%% File: l3io.dtx Copyright (C) 1990-2010 LaTeX3 project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
%% license or (at your option) any later version.  The latest version
%% of this license is in the file
%%
%%    http://www.latex-project.org/lppl.txt
%%
%% This file is part of the ``expl3 bundle'' (The Work in LPPL)
%% and all files in that bundle must be distributed together.
%%
%% The released version of this bundle is available from CTAN.
%%
%% -----------------------------------------------------------------------
%%
%% The development version of the bundle can be found at
%%
%%    http://www.latex-project.org/svnroot/experimental/trunk/
%%
%% for those people who are interested.
%%
%%%%%%%%%%%
%% NOTE: %%
%%%%%%%%%%%
%%
%%   Snapshots taken from the repository represent work in progress and may
%%   not work or may contain conflicting material!  We therefore ask
%%   people _not_ to put them into distributions, archives, etc. without
%%   prior consultation with the LaTeX Project Team.
%%
%% -----------------------------------------------------------------------
%
%<*driver|package>
\RequirePackage{l3names}
%</driver|package>
%\fi
\GetIdInfo$Id: l3io.dtx 2063 2010-10-03 08:26:49Z mittelba $
          {L3 Experimental i/o module}
%\iffalse
%<*driver>
%\fi
\ProvidesFile{\filename.\filenameext}
  [\filedate\space v\fileversion\space\filedescription]
%\iffalse
\documentclass[full]{l3doc}
\begin{document}
  \DocInput{l3io.dtx}
\end{document}
%</driver>
% \fi
%
% \title{The \textsf{l3io} package\thanks{This file
%         has version number \fileversion, last
%         revised \filedate.}\\
% Low-level file i/o}
% \author{\Team}
% \date{\filedate}
% \maketitle
%
%\begin{documentation}
%
% Reading and writing from file streams is handled in \LaTeX3 using
% functions with prefixes \cs{iow_\ldots} (file reading) and
% \cs{ior_\ldots} (file writing). Many of the basic functions are
% very similar, with reading and writing using the same syntax and
% function concepts. As a result, the reading and writing functions
% are documented together where this makes sense.
% 
% As \TeX\ is limited to \(16\) input streams and \(16\) output
% streams, direct use of the streams by the programmer is not 
% supported in \LaTeX3. Instead, an internal pool of streams is
% maintained, and these are allocated and deallocated as needed
% by other modules. As a result, the programmer should close streams
% when they are no longer needed, to release them for other processes.
% 
% Reading from or writing to a file requires a \meta{stream} to
% be used. This is a csname which refers to the file being processed,
% and is independent of the name of the file (except of course that
% the file name is needed when the file is opened).
% 
%\section{Opening and closing streams}
%
%\begin{function}{
%  \iow_new:N |
%  \iow_new:c |
%  \ior_new:N |
%  \ior_new:c 
%}
%  \begin{syntax}
%    "\iow_new:N" <stream>
%  \end{syntax}
%  Reserves the name <stream> for use in accessing a file stream. 
%  This operation does not open a raw \TeX\ stream, which is handled
%  internally using a pool and is should not be accessed directly by
%  the programmer.
%\end{function}
%
%\begin{function}{
%  \iow_open:Nn |
%  \iow_open:cn |
%  \ior_open:Nn |
%  \ior_open:cn
%}
%  \begin{syntax}
%    "\iow_open:Nn" <stream> \Arg{file name} 
%    "\iow_open:Nn" <stream> \Arg{file name}
%  \end{syntax}
%  Opens <file name> for writing (\cs{iow_\ldots}) or reading
%  (\cs{ior_\ldots}) using <stream> as the csname by which the
%  file is accessed. If <stream> was already open (for either writing
%  or reading) it is closed before the new operation begins. The
%  <stream> is available for access immediately after issuing an
%  \texttt{open} instruction. The <stream> will remain allocated
%  to <file name> until a \texttt{close} instruction is given or at
%  the end of the \TeX\ run.
%  
%  Opening a file for writing will clear any existing content in the
%  file (\emph{i.e}.~writing is \emph{not} additive). As the total
%  number of writing streams is limited, it may well be best to save
%  material to be written to an intermediate storage format (for example
%  a token list or toks), and to write the material in one `shot' 
%  from this variable. In this way the file stream is only required
%  for a limited time.
%\end{function}
%
%\begin{function}{
%  \iow_close:N |
%  \iow_close:c |
%  \ior_close:N |
%  \ior_close:c
%}
%  \begin{syntax}
%    "\iow_close:N" <stream> 
%    "\ior_close:N" <stream> 
%  \end{syntax}
%  Closes <stream>, freeing up one of the underlying \TeX\ streams
%  for reuse. Streams should always be closed when they are finished
%  with as this ensures that they remain available to other 
%  programmers (the resources here are limited). The name of
%  the <stream> will be freed at this stage, to ensure that any
%  further attempts to write to it result in an error.
%\end{function}
%
%\begin{function}{
%  \iow_open_streams: |
%  \iow_open_streams: 
%}
%  \begin{syntax}
%    "\iow_open_streams:"
%  \end{syntax}
%  Displays a list of the file names associated with each open
%  stream: intended for tracking down problems.
%\end{function}
%
%\subsection{Writing to files}
%
%\begin{function}{ 
%  \iow_now:Nx |
%  \iow_now:Nn 
%}
%  \begin{syntax}
%    "\iow_now:Nx" <stream> \Arg{tokens}
%  \end{syntax}
%  \cs{iow_now:Nx} immediately writes the expansion of <tokens> to the
%  output <stream>. If the <stream> is not open output goes to the
%  terminal. The variant \cs{iow_now:Nn} writes out <tokens> without any
%  further expansion.
%  \begin{texnote}
%    These are the equivalent of \TeX's "\immediate\write" with and 
%    without expansion control.
%  \end{texnote}
%\end{function}
%
%\begin{function}{ 
%  \iow_log:n  | 
%  \iow_log:x  |
%  \iow_term:n | 
%  \iow_term:x 
%}
%  \begin{syntax}
%   "\iow_log:x" \Arg{tokens}
%  \end{syntax}
%  These are dedicated functions which write to the log (transcript)
%  file and the terminal, respectively. They are equivalent to using
%  \cs{iow_now:N(n/x)} to the streams \cs{c_iow_log_stream} and
%  \cs{c_iow_term_stream}. The writing takes place immediately.
% \end{function}
% 
%\begin{function}{
%  \iow_now_buffer_safe:Nn |
%  \iow_now_buffer_safe:Nx 
%}
%  \begin{syntax}
%    "\iow_now_buffer_safe:Nn" <stream> \Arg{tokens}
%  \end{syntax}
%  Immediately write <tokens> expanded to <stream>, with every space
%  converted into a newline. This mean that the file can be 
%  read back without the danger that very long lines overflow 
%  \TeX's buffer.
% \end{function}
% 
%\begin{function}{
%  \iow_now_when_avail:Nn |
%  \iow_now_when_avail:cn |
%  \iow_now_when_avail:Nx |
%  \iow_now_when_avail:cx 
%}
%  \begin{syntax}
%    "\iow_now_when_avail:Nn" <stream> \Arg{tokens}
%  \end{syntax}
%  If <stream> is open, writes the <tokens> to the <stream> in the
%  same manner as \cs{iow_now:N(n/x)}. If the <stream> is not open,
%  the <tokens> are simply thrown away.
%\end{function}
% 
%\begin{function}{ 
%  \iow_shipout:Nx |
%  \iow_shipout:Nn 
%}
%  \begin{syntax}
%    "\iow_shipout:Nx" <stream> \Arg{tokens}
%  \end{syntax}
%  Write <tokens> to <stream> at the point at which the current page
%  is finished. The <tokens> are either written unexpanded 
%  (\cs{iow_shipout:Nn}) or expanded only at the point that the 
%  function is used (\cs{iow_shipout:Nx}), \emph{i.e}.~no expansion
%  takes place when writing to the file.
%\end{function}
%
%\begin{function}{ 
%  \iow_shipout_x:Nx |
%  \iow_shipout_x:Nn 
%}
%  \begin{syntax}
%    "\iow_shipout_x:Nx" <stream> \Arg{tokens}
%  \end{syntax}
%  Write <tokens> to <stream> at the point at which the current page
%  is finished. The <tokens> are expanded at the time of writing
%  in addition to any expansion at the time of use of the function.
%  This makes these functions suitable for including material finalised
%  during the page building process (such as the page number integer).
%  \begin{texnote}
%    These are the equivalent of \TeX's \cs{write} with and 
%    without expansion control at point of use.
%  \end{texnote}
%\end{function}
%
%\begin{function}{\iow_newline: / (EXP) }
%  \begin{syntax}
%    "\iow_newline:"
%  \end{syntax}
%  Function to add a new line within the <tokens> written to a file.
%  The function has no effect if writing is taking place without
%  expansion (\emph{e.g}.~in a \cs{iow_now:Nn} call).
%\end{function}
%
%\begin{function}{\iow_char:N / (EXP) }
%  \begin{syntax}
%    "\iow_char:N" "\"<char>
%    "\iow_char:N" "\%"
%  \end{syntax}
%  Inserts <char> into the output stream. Useful when trying to write 
%  difficult characters such as "%", "{", "}", \emph{etc}.~in messages,
%  for example:
%  \begin{verbatim}
%    \iow_now:Nx \g_my_stream { \iow_char:N \{ text \iow_char:N \} }
%  \end{verbatim}
%  The function has no effect if writing is taking place without
%  expansion (\emph{e.g}.~in a \cs{iow_now:Nn} call).
%\end{function}
%
%\subsection{Reading from files}
%
%\begin{function}{ 
%  \ior_to:NN  |
%  \ior_gto:NN 
%}
%  \begin{syntax}
%    "\ior_to:NN" <stream> <token list variable>
%  \end{syntax}
%  Functions that reads one or more lines (until an equal number of left
%  and right braces are found) from the input stream <stream> and places
%  the result locally or globally into the <token list variable>.
%  If <stream> is not open, input is requested from the terminal.
%\end{function}
%
%\begin{function}{ 
%  \ior_if_eof_p:N / (EXP)      | 
%  \ior_if_eof:N   / (EXP) (TF)  
%}
%  \begin{syntax}
%    "\ior_if_eof:NTF" <stream> \Arg{true code} \Arg{false code}
%  \end{syntax}
%  Tests if the end of a <stream> has been reached during a reading
%  operation. The test will also return a \texttt{true} value if
%  the <stream> is not open or the <file name> associated with
%  a <stream> does not exist at all.
%\end{function}
%
%\section{Internal functions}
%
%\begin{function}{
%  \iow_raw_new:N |
%  \iow_raw_new:c |
%  \ior_raw_new:N |
%  \ior_raw_new:c 
%}
%  \begin{syntax}
%    "\iow_raw_new:N" <stream>
%  \end{syntax}
%  Creates a new low-level <stream> for use in subsequent functions.
%  As allocations are made using a pool \emph{do not use this function!}
%  \begin{texnote}
%    This is \LaTeXe's \cs{newwrite}.
%  \end{texnote}
%\end{function}
%
%\begin{function}{\if_eof:w / (EXP) }
%  \begin{syntax}
%    "\if_eof:w" <stream> <true code> "\else:" <false code> "\fi:"
%  \end{syntax}
%  Tests if the end of <stream> has been reached during a reading
%  operation.
%  \begin{texnote}
%    This is the primitive \cs{ifeof}.
%  \end{texnote}
%\end{function}
%
%\section{Variables and constants}
%
%\begin{variable}{\c_io_streams_tl}
%  A list of the positions available for stream allocation (numbers 
%  \(0\) to \(15\)).
%\end{variable}
%
%\begin{variable}{
%  \c_iow_term_stream |
%  \c_ior_term_stream |
%  \c_iow_log_stream  |
%  \c_ior_log_stream  
%}
%  Fixed stream numbers for accessing to the log and the terminal. The
%  reading and writing values are the same but are provided so that the
%  meaning is clear.
%\end{variable}
%
%\begin{variable}{
%  \g_iow_streams_prop |
%  \g_ior_streams_prop  
%}
%  Allocation records for streams, linking the stream number to
%  the current name being used for that stream.
%\end{variable}
%
%\begin{variable}{
%  \g_iow_tmp_stream |
%  \g_ior_tmp_stream
%}
%  Used when creating new streams at the \TeX\ level.
%\end{variable}
%
%\begin{variable}{
%  \l_iow_stream_int |
%  \l_ior_stream_int
%}
%  Number of stream currently being allocated.
%\end{variable}
%
%\end{documentation}
% 
%\begin{implementation}
% 
%\section{\pkg{l3io} implementation}
%
%    We start by ensuring that the required packages are loaded.
%    \begin{macrocode}
%<*package>
\ProvidesExplPackage
  {\filename}{\filedate}{\fileversion}{\filedescription}
\package_check_loaded_expl:
%</package>
%<*initex|package>
%    \end{macrocode}
%    
%\subsection{Variables and constants}
%
%\begin{macro}{\c_iow_term_stream}
%\begin{macro}{\c_ior_term_stream}
%\begin{macro}{\c_iow_log_stream}
%\begin{macro}{\c_ior_log_stream}
% Here we allocate two output streams for writing to the transcript
% file only (\cs{c_iow_log_stream}) and to both the terminal and 
% transcript file (\cs{c_iow_term_stream}). Both can be used to read 
% from and have equivalent \cs{c_ior} versions.
%    \begin{macrocode}
\cs_new_eq:NN \c_iow_term_stream \c_sixteen
\cs_new_eq:NN \c_ior_term_stream \c_sixteen
\cs_new_eq:NN \c_iow_log_stream  \c_minus_one
\cs_new_eq:NN \c_ior_log_stream  \c_minus_one
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\c_iow_streams_tl}
%\begin{macro}{\c_ior_streams_tl}
% The list of streams available, by number.
%    \begin{macrocode}
\tl_const:Nn \c_iow_streams_tl
  {
    \c_zero 
    \c_one
    \c_two
    \c_three
    \c_four
    \c_five
    \c_six
    \c_seven
    \c_eight
    \c_nine
    \c_ten
    \c_eleven
    \c_twelve
    \c_thirteen
    \c_fourteen
    \c_fifteen
  }
\cs_new_eq:NN \c_ior_streams_tl \c_iow_streams_tl
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\g_iow_streams_prop}
%\begin{macro}{\g_ior_streams_prop}
% The allocations for streams are stored in property lists, which 
% are set up to have a 'full' set of allocations from the start.
% In package mode, a few slots are always taken, so these are 
% blocked off from use.
%    \begin{macrocode}
\prop_new:N \g_iow_streams_prop
\prop_new:N \g_ior_streams_prop
%</initex|package>
%<*package>
\prop_put:Nnn \g_iow_streams_prop { 0 } { LaTeX2e~reserved }
\prop_put:Nnn \g_iow_streams_prop { 1 } { LaTeX2e~reserved }
\prop_put:Nnn \g_iow_streams_prop { 2 } { LaTeX2e~reserved }
\prop_put:Nnn \g_ior_streams_prop { 0 } { LaTeX2e~reserved }
%</package>
%<*initex|package>
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\l_iow_stream_int}
%\begin{macro}{\l_ior_stream_int}
% Used to track the number allocated to the stream being created:
% this is taken from the property list but does alter.
%    \begin{macrocode}
\int_new:N \l_iow_stream_int
\cs_new_eq:NN \l_ior_stream_int \l_iow_stream_int
%    \end{macrocode}
%\end{macro}
%\end{macro}
%    
%\subsection{Stream management}
%
%\begin{macro}{\iow_raw_new:N} 
%\begin{macro}{\ior_raw_new:N}
% The lowest level for stream management is actually creating raw \TeX\ 
% streams. As these are very limited (even with \eTeX) this should not 
% be addressed directly.
%    \begin{macrocode}
%</initex|package>
%<*initex>
\alloc_setup_type:nnn { iow } \c_zero \c_sixteen
\cs_new_protected_nopar:Npn \iow_raw_new:N #1 {
  \alloc_reg:NnNN g { iow } \tex_chardef:D #1
}
\alloc_setup_type:nnn { ior } \c_zero \c_sixteen
\cs_new_protected_nopar:Npn \ior_raw_new:N #1 {
  \alloc_reg:NnNN g { ior } \tex_chardef:D #1
}
%</initex>
%<*package>
\cs_set_eq:NN \iow_raw_new:N \newwrite
\cs_set_eq:NN \ior_raw_new:N \newread
%</package>
%<*initex|package>
\cs_generate_variant:Nn \iow_raw_new:N { c }
\cs_generate_variant:Nn \ior_raw_new:N { c }
%    \end{macrocode}  
%\end{macro}
%\end{macro}
%
%\begin{macro}{\iow_new:N}
%\begin{macro}{\iow_new:c}
%\begin{macro}{\ior_new:N}
%\begin{macro}{\ior_new:c}
% These are not needed but are included for consistency with other
% variable types.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \iow_new:N #1 {
  \cs_new_eq:NN #1 \c_iow_log_stream
}
\cs_generate_variant:Nn \iow_new:N { c }
\cs_new_protected_nopar:Npn \ior_new:N #1 {
  \cs_new_eq:NN #1 \c_ior_log_stream
}
\cs_generate_variant:Nn \ior_new:N { c }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\iow_open:Nn}
%\begin{macro}{\iow_open:cn}
%\begin{macro}{\ior_open:Nn}
%\begin{macro}{\ior_open:cn}
% In both cases, opening a stream starts with a call to the closing 
% function: this is safest. There is then a loop through the 
% allocation number list to find the first free stream number.
% When one is found the allocation can take place, the information
% can be stored and finally the file can actually be opened.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \iow_open:Nn #1#2 {
  \iow_close:N #1
  \int_set:Nn \l_iow_stream_int { \c_sixteen }
  \tl_map_function:NN \c_iow_streams_tl \iow_alloc_write:n
  \int_compare:nTF { \l_iow_stream_int = \c_sixteen }
    { \msg_kernel_error:nn { iow } { streams-exhausted } }
    {
      \iow_stream_alloc:N #1
      \prop_gput:NVn \g_iow_streams_prop \l_iow_stream_int {#2}
      \tex_immediate:D \tex_openout:D #1#2 \scan_stop:
    }
}
\cs_generate_variant:Nn \iow_open:Nn { c } 
\cs_new_protected_nopar:Npn \ior_open:Nn #1#2 {
  \ior_close:N #1 
  \int_set:Nn \l_ior_stream_int { \c_sixteen }
  \tl_map_function:NN \c_ior_streams_tl \ior_alloc_read:n
  \int_compare:nTF { \l_ior_stream_int = \c_sixteen }
    { \msg_kernel_error:nn { ior } { streams-exhausted } }
    {
      \ior_stream_alloc:N  #1
      \prop_gput:NVn \g_ior_streams_prop \l_ior_stream_int {#2}
      \tex_openin:D #1#2 \scan_stop:
    }
}
\cs_generate_variant:Nn \ior_open:Nn { c } 
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}[aux]{\iow_alloc_write:n}
%\begin{macro}[aux]{\ior_alloc_read:n}
% These functions are used to see if a particular stream is available.
% The property list contains file names for streams in use, so
% any unused ones are for the taking.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \iow_alloc_write:n #1 {
  \prop_if_in:NnF \g_iow_streams_prop {#1}
    {
      \int_set:Nn \l_iow_stream_int {#1}
      \tl_map_break: 
    }
}
\cs_new_protected_nopar:Npn \ior_alloc_read:n #1 {
  \prop_if_in:NnF \g_iow_streams_prop {#1}
    {
      \int_set:Nn \l_ior_stream_int {#1}
      \tl_map_break: 
    }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}[aux]{\iow_stream_alloc:N}
%\begin{macro}[aux]{\ior_stream_alloc:N}
%\begin{macro}[aux]{\iow_stream_alloc_aux:}
%\begin{macro}[aux]{\ior_stream_alloc_aux:}
%\begin{macro}[aux]{\g_iow_tmp_stream}
%\begin{macro}[aux]{\g_ior_tmp_stream}
% Allocating a raw stream is much easier in initex mode than for
% the package. For the format, all streams will be allocated by
% \pkg{l3io} and so there is a simple check to see if a raw
% stream is actually available. On the other hand, for the 
% package there will be non-managed streams. So if the managed
% one is not open, a check is made to see if some other managed
% stream is available before deciding to open a new one. If a new
% one is needed, we get the number allocated by \LaTeXe\ to get
% `back on track' with allocation.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \iow_stream_alloc:N #1 {
  \cs_if_exist:cTF { g_iow_ \int_use:N \l_iow_stream_int _stream } 
    { \cs_gset_eq:Nc #1 { g_iow_ \int_use:N \l_iow_stream_int _stream } }
    {
%</initex|package>
%<*package>
      \iow_stream_alloc_aux:
      \int_compare:nT { \l_iow_stream_int = \c_sixteen }
        {
          \iow_raw_new:N \g_iow_tmp_stream
          \int_set:Nn \l_iow_stream_int { \g_iow_tmp_stream } 
          \cs_gset_eq:cN
            { g_iow_ \int_use:N \l_iow_stream_int _stream }
            \g_iow_tmp_stream
        }
%</package>
%<*initex>
      \iow_raw_new:c { g_iow_ \int_use:N \l_iow_stream_int _stream }
%</initex>
%<*initex|package>
      \cs_gset_eq:Nc #1 { g_iow_ \int_use:N \l_iow_stream_int _stream }
    }
}
%</initex|package>
%<*package>
\cs_new_protected_nopar:Npn \iow_stream_alloc_aux: {
  \int_incr:N \l_iow_stream_int
  \int_compare:nT
    { \l_iow_stream_int < \c_sixteen }
    {
       \cs_if_exist:cTF { g_iow_ \int_use:N \l_iow_stream_int _stream }
         {
           \prop_if_in:NVT \g_iow_streams_prop \l_iow_stream_int
             { \iow_stream_alloc_aux: } 
         } 
         { \iow_stream_alloc_aux: } 
    }
}
%</package>
%<*initex|package>
\cs_new_protected_nopar:Npn \ior_stream_alloc:N #1 {
  \cs_if_exist:cTF { g_ior_ \int_use:N \l_ior_stream_int _stream } 
    { \cs_gset_eq:Nc #1 { g_ior_ \int_use:N \l_ior_stream_int _stream } }
    {
%</initex|package>
%<*package>
      \ior_stream_alloc_aux:
      \int_compare:nT { \l_ior_stream_int = \c_sixteen }
        {
          \ior_raw_new:N \g_ior_tmp_stream
          \int_set:Nn \l_ior_stream_int { \g_ior_tmp_stream } 
          \cs_gset_eq:cN
            { g_ior_ \int_use:N \l_iow_stream_int _stream }
            \g_ior_tmp_stream
        }
%</package>
%<*initex>
      \ior_raw_new:c { g_ior_ \int_use:N \l_ior_stream_int _stream }
%</initex>
%<*initex|package>
      \cs_gset_eq:Nc #1 { g_ior_ \int_use:N \l_ior_stream_int _stream }
    }
}
%</initex|package>
%<*package>
\cs_new_protected_nopar:Npn \ior_stream_alloc_aux: {
  \int_incr:N \l_ior_stream_int
  \int_compare:nT
    { \l_ior_stream_int < \c_sixteen }
    {
       \cs_if_exist:cTF { g_ior_ \int_use:N \l_ior_stream_int _stream }
         {
           \prop_if_in:NVT \g_ior_streams_prop \l_ior_stream_int
             { \ior_stream_alloc_aux: } 
         } 
         { \ior_stream_alloc_aux: } 
    }
}
%</package>
%<*initex|package>
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\iow_close:N}
%\begin{macro}{\iow_close:c}
%\begin{macro}{\iow_close:N}
%\begin{macro}{\iow_close:c}
% Closing a stream is not quite the reverse of opening one. First, 
% the close operation is easier than the open one, and second as the 
% stream is actually a number we can use it directly to show that the 
% slot has been freed up.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \iow_close:N #1 {
  \cs_if_exist:NT #1
    {
      \int_compare:nF { #1 = \c_minus_one }
        {
          \tex_immediate:D \tex_closeout:D #1
          \prop_gdel:NV \g_iow_streams_prop #1
          \cs_gundefine:N #1
        }
    }
}
\cs_generate_variant:Nn \iow_close:N { c }
\cs_new_protected_nopar:Npn \ior_close:N #1 {
  \cs_if_exist:NT #1
    {
      \int_compare:nF { #1 = \c_minus_one }
        {
          \tex_closein:D #1
          \prop_gdel:NV \g_ior_streams_prop #1 
          \cs_gundefine:N #1
        }  
    }
}
\cs_generate_variant:Nn \ior_close:N { c }
%    \end{macrocode}
%\end{macro} 
%\end{macro} 
%\end{macro} 
%\end{macro} 
%
%\begin{macro}{\iow_open_streams:}
%\begin{macro}{\ior_open_streams:}
% Simply show the property lists.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \iow_open_streams: {
  \prop_display:N \g_iow_streams_prop
}
\cs_new_protected_nopar:Npn \ior_open_streams: {
  \prop_display:N \g_ior_streams_prop
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
% Text for the error messages.
%    \begin{macrocode}
\msg_kernel_new:nnnn { iow } { streams-exhausted }
  {Output streams exhausted}
  {%
    TeX can only open up to 16 output streams at one time.\\%
    All 16 are currently in use, and something wanted to open 
    another one.%
  }
\msg_kernel_new:nnnn { ior } { streams-exhausted }
  {Input streams exhausted}
  {%
    TeX can only open up to 16 input streams at one time.\\%
    All 16 are currently in use, and something wanted to open 
    another one.%
  }
%    \end{macrocode}
%    
%\subsection{Immediate writing}   
%
%\begin{macro}{\iow_now:Nx}
% An abbreviation for an often used operation, which immediately
% writes its second argument expanded to the output stream.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \iow_now:Nx { \tex_immediate:D \iow_shipout_x:Nn }
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\iow_now:Nn}
% This routine writes the second argument onto the output stream without 
% expansion. If this stream isn't open, the output goes to the terminal 
% instead. If the first argument is no output stream at all, we get an
% internal error.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \iow_now:Nn #1#2 {
  \iow_now:Nx #1 { \exp_not:n {#2} }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\iow_log:n}
%\begin{macro}{\iow_log:x}
%\begin{macro}{\iow_term:n}
%\begin{macro}{\iow_term:x}
% Now we redefine two functions for which we needed a definition
% very early on.
%    \begin{macrocode}
\cs_set_protected_nopar:Npn \iow_log:x  { \iow_now:Nx \c_iow_log_stream  }
\cs_new_protected_nopar:Npn \iow_log:n  { \iow_now:Nn \c_iow_log_stream  }
\cs_set_protected_nopar:Npn \iow_term:x { \iow_now:Nx \c_iow_term_stream }
\cs_new_protected_nopar:Npn \iow_term:n { \iow_now:Nn \c_iow_term_stream }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\iow_now_when_avail:Nn}
%\begin{macro}{\iow_now_when_avail:cn}
%\begin{macro}{\iow_now_when_avail:Nx}
%\begin{macro}{\iow_now_when_avail:cx}
% For writing only if the stream requested is open at all.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \iow_now_when_avail:Nn #1 {
  \cs_if_free:NTF #1 { \use_none:n } { \iow_now:Nn #1 }
}
\cs_generate_variant:Nn \iow_now_when_avail:Nn { c }
\cs_new_protected_nopar:Npn \iow_now_when_avail:Nx #1 {
  \cs_if_free:NTF #1 { \use_none:n } { \iow_now:Nx #1 }
}
\cs_generate_variant:Nn \iow_now_when_avail:Nx { c }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\iow_now_buffer_safe:Nn}
%\begin{macro}{\iow_now_buffer_safe:Nx}
%\begin{macro}[aux]{\iow_now_buffer_safe_expanded_aux:w}
% Another type of writing onto an output stream is used for
% potentially long token sequences. We break the output lines at
% every blank in the second argument. This avoids the problem of
% buffer overflow when reading back, or badly broken lines on
% systems with limited file records.  The only thing we have to
% take care of, is the danger of two blanks in succession since
% these get converted into a \cs{par} when we read the stuff back.
% But this can happen only if things like  two spaces find their way 
% into the second argument.  Usually, multiple spaces are removed by 
% \TeX's scanner.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \iow_now_buffer_safe:Nn {
  \iow_now_buffer_safe_aux:w \iow_now:Nx
}
\cs_new_protected_nopar:Npn \iow_now_buffer_safe:Nx {
  \iow_now_buffer_safe_aux:w \iow_now:Nn
}
\cs_new_protected_nopar:Npn \iow_now_buffer_safe_aux:w #1#2#3 {
  \group_begin: \tex_newlinechar:D`\ #1#2 {#3} \group_end:
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro} 
% 
%\subsection{Deferred writing}
%
%\begin{macro}{\iow_shipout_x:Nn}
%\begin{macro}{\iow_shipout_x:Nx}
% First the easy part, this is the primitive.
%    \begin{macrocode}
\cs_set_eq:NN \iow_shipout_x:Nn \tex_write:D
\cs_generate_variant:Nn \iow_shipout_x:Nn  {Nx }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\iow_shipout:Nn}
%\begin{macro}{\iow_shipout:Nx}
% With \eTeX\ available deferred writing is easy.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \iow_shipout:Nn #1#2 {
  \iow_shipout_x:Nn #1 { \exp_not:n {#2} }
}
\cs_generate_variant:Nn \iow_shipout:Nn { Nx }
%    \end{macrocode}
%\end{macro} 
%\end{macro} 
%
%\section{Special characters for writing}
%
%\begin{macro}{\iow_newline:}
% Global variable holding the character that forces a new line when
% something is written to an output stream.
%    \begin{macrocode}
\cs_new_nopar:Npn \iow_newline: { ^^J }
%    \end{macrocode}
% \end{macro}
%
%\begin{macro}{\iow_char:N}
% Function to write any escaped char to an output stream.
%    \begin{macrocode}
\cs_new:Npn \iow_char:N #1 { \cs_to_str:N #1 }
%    \end{macrocode}
%\end{macro}
%
%\subsection{Reading input}
%
%\begin{macro}{\if_eof:w}
% A simple primitive renaming.
%    \begin{macrocode}
\cs_new_eq:NN \if_eof:w \tex_ifeof:D
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\ior_if_eof_p:N}
%\begin{macro}[TF]{\ior_if_eof:N}
% To test if some particular input stream is exhausted the following
% conditional is provided. As the pool model means that closed
% streams are undefined control sequences, the test has two parts.
%    \begin{macrocode}
\prg_new_conditional:Nnn \ior_if_eof:N { p , TF , T , F } {
  \cs_if_exist:NTF #1
    { \tex_ifeof:D #1 \prg_return_true: \else: \prg_return_false: \fi: }
    { \prg_return_true: }
}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% 
%\begin{macro}{\ior_to:NN}
%\begin{macro}{\ior_gto:NN}
%  And here we read from files.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ior_to:NN #1#2 {
  \tex_read:D #1 to #2
}
\cs_new_protected_nopar:Npn \ior_gto:NN {
  \pref_global:D \ior_to:NN
}
%</initex|package>
%    \end{macrocode}
%\end{macro}
%\end{macro}
% 
% \end{implementation}
