% \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} % %\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} % % \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" % \end{syntax} % Reserves the name 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" \Arg{file name} % "\iow_open:Nn" \Arg{file name} % \end{syntax} % Opens for writing (\cs{iow_\ldots}) or reading % (\cs{ior_\ldots}) using as the csname by which the % file is accessed. If was already open (for either writing % or reading) it is closed before the new operation begins. The % is available for access immediately after issuing an % \texttt{open} instruction. The will remain allocated % to 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" % "\ior_close:N" % \end{syntax} % Closes , 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 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" \Arg{tokens} % \end{syntax} % \cs{iow_now:Nx} immediately writes the expansion of to the % output . If the is not open output goes to the % terminal. The variant \cs{iow_now:Nn} writes out 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" \Arg{tokens} % \end{syntax} % Immediately write expanded to , 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" \Arg{tokens} % \end{syntax} % If is open, writes the to the in the % same manner as \cs{iow_now:N(n/x)}. If the is not open, % the are simply thrown away. %\end{function} % %\begin{function}{ % \iow_shipout:Nx | % \iow_shipout:Nn %} % \begin{syntax} % "\iow_shipout:Nx" \Arg{tokens} % \end{syntax} % Write to at the point at which the current page % is finished. The 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" \Arg{tokens} % \end{syntax} % Write to at the point at which the current page % is finished. The 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 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" "\" % "\iow_char:N" "\%" % \end{syntax} % Inserts 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" % \end{syntax} % Functions that reads one or more lines (until an equal number of left % and right braces are found) from the input stream and places % the result locally or globally into the . % If 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" \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the end of a has been reached during a reading % operation. The test will also return a \texttt{true} value if % the is not open or the associated with % a 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" % \end{syntax} % Creates a new low-level 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" "\else:" "\fi:" % \end{syntax} % Tests if the end of 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: % %<*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 % %<*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 } % %<*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> \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 } % %<*package> \cs_set_eq:NN \iow_raw_new:N \newwrite \cs_set_eq:NN \ior_raw_new:N \newread % %<*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 } } { % %<*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 } % %<*initex> \iow_raw_new:c { g_iow_ \int_use:N \l_iow_stream_int _stream } % %<*initex|package> \cs_gset_eq:Nc #1 { g_iow_ \int_use:N \l_iow_stream_int _stream } } } % %<*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: } } } % %<*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 } } { % %<*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 } % %<*initex> \ior_raw_new:c { g_ior_ \int_use:N \l_ior_stream_int _stream } % %<*initex|package> \cs_gset_eq:Nc #1 { g_ior_ \int_use:N \l_ior_stream_int _stream } } } % %<*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: } } } % %<*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 } % % \end{macrocode} %\end{macro} %\end{macro} % % \end{implementation}