% \iffalse %% File: l3io.dtx Copyright (C) 1990-1998 LaTeX3 project % %<*dtx> \ProvidesFile{l3io.dtx} % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{l3io} % \ProvidesFile{l3io.drv} % \fi % \ProvidesFile{l3io.dtx} [1998/04/20 v1.0c L3 Experimental i/o module] % % \iffalse %<*driver> \documentclass{l3doc} \begin{document} \DocInput{l3io.dtx} \end{document} % % \fi % % \section{Low-level file i/o} % % \TeX{} is capable of reading from and writing up to 16 individual % streams. These i/o operations are accessable in \LaTeX3 with functions % from the "\io.." modules. In most cases it will be % sufficiant for the programmer to use the functions provided by the % auxiliary file module, but here are the necessary functions for % manipulating private streams. % % Sometimes it is not know beforehand how much text is going to be % written with a single call. As a result some internal \TeX{} buffer % may overflow. To avoid this kind of problem, \LaTeX3 maintains beside % direct write operations like "\iow_expanded:Nn" also so called ``long'' % writes where the output is broken into individual lines on every blank % in the text to be written. The resulting files are difficult to read % for humans but since they usually serve only as internal storage this % poses no problem. % % Beside the functions that immediately act (e.g., "\iow_expanded:Nn", % etc.) we also have deferred operations that are saved away until the % next page is finished. This allow to expand the at the right % time to get correct page numbers etc. % % \subsection{Functions for output streams} % % \begin{function}{\iow_new:N | % \iow_new:c % } % \begin{syntax} % "\iow_new:N" % \end{syntax} % Defines to be a new identifer denoting an output stream for % use in subsequent functions. % \begin{texnote} % "\iow_new:N" corresponds to the plain \TeX{} \tn{newwrite} % allocation routine. % \end{texnote} % \end{function} % % \begin{function}{\iow_open:Nn | % \iow_open:cn % } % \begin{syntax} % "\iow_open:Nn" "{" "}" % \end{syntax} % Opens output stream to write to . The output % stream is immediately available for use. If the was already % used as an output stream to some other file, this file gets closed % first.\footnote{This is a precaution since on some OS it is possible % to open the same file for output more than once which then results in % some internal errors at the end of the run.} Also, all output streams % still open at the end of the \TeX{} run will be automatically closed. % \end{function} % % \begin{function}{\iow_expanded:Nn | % \iow_unexpanded:Nn % } % \begin{syntax} % "\iow_expanded:Nn" "{" "}" % \end{syntax} % This function immediately writes the expansion of to the % output stream . If is not open output goes to the % terminal. The variant "\iow_unexpanded:Nn" writes out without any % further expansion (verbatim). % \end{function} % % \begin{function}{\iow_expanded_log:n | % \iow_expanded_term:n | % \iow_unexpanded_term:n % } % \begin{syntax} % "\iow_expanded_log:n" "{" "}" % \end{syntax} % These functions write to the transcript or to the terminal % respectively. So they are equivalent to "\iow_expanded:Nn" where % is the transcript file ("\c_iow_log_stream") or the terminal % ("\c_io_term_stream"). % \end{function} % % \begin{function}{\iow_long_expanded:Nx | % \iow_long_unexpanded:Nn % } % \begin{syntax} % "\iow_long_expanded:Nn" "{" "}" % \end{syntax} % Like "\iow_expanded:Nn" but splits at every blank into separate % lines. % \end{function} % % \begin{function}{\iow_unexpanded_if_avail:Nn| % \iow_unexpanded_if_avail:cn|} % \begin{syntax} % "\iow_unexpanded_if_avail:Nn" "{" "}" % \end{syntax} % This special function first checks if the is open of writing. % If not it does nothing otherwise it behaves like "\iow_unexpanded:Nn". % \end{function} % % \begin{function}{\iow_deferred_expanded:Nn | % \iow_deferred_unexpanded:Nn} % \begin{syntax} % "\iow_deferred_expanded:Nn" "{" "}" % \end{syntax} % These functions save away until the next page is ready to be % shipped out. Then, in case of "\iow_deferred_expanded:Nn" get % expanded and afterwards written to . "\iow_deferred_expanded:Nn" % also always needs "{}" around the second argument. The use of % "\iow_deferred_unexpanded:Nn" is probably seldom necessary. % \begin{texnote} % "\iow_deferred_expanded:Nn" was known as \tn{write}. % \end{texnote} % \end{function} % % \begin{function}{\iow_newline:} % \begin{syntax} % "\iow_newline:" % \end{syntax} % Function that produces a new line when used within the % that gets written some output stream in non-verbatim mode. % \end{function} % % \subsection{Functions for input streams} % % \begin{function}{\ior_new:N % } % \begin{syntax} % "\ior_new:N" % \end{syntax} % This function defines to be a new input stream constant. % \begin{texnote} % This is the new name and new implementation for plain \TeX's % \tn{newread}. % \end{texnote} % \end{function} % % \begin{function}{\ior_open:Nn} % \begin{syntax} % "\ior_open:Nn" "{" "}" % \end{syntax} % This function opens as an input stream for the external file % . If doesn't exist or is an empty file the % stream is considered to be fully read, a condition which can be tested % with "\ior_eof:NTF" etc. If was already used to read from some % other file this file will be closed first. The input stream is ready % for immediate use. % \end{function} % % \begin{function}{\ior_close:N} % \begin{syntax} % "\ior_close:N" % \end{syntax} % This function closes the read stream . % \begin{texnote} % This is a new name for \tn{closein} but it is considered bad practice % to make use of this knowledge :-) % \end{texnote} % \end{function} % % \begin{function}{\ior_eof:NTF | % \ior_eof:NF} % \begin{syntax} % "\ior_eof:NTF" "{" "}{" "}" % \end{syntax} % Conditional that tests if some input stream is fully read. The % condition is also true if the input stream is not open. % \end{function} % % \begin{function}{\if_eof:w} % \begin{syntax} % "\if_eof:w" "\else:" "\fi:" % \end{syntax} % \begin{texnote} % This is the primitive \tn{ifeof} but we allow only a and not % a plain number after it. % \end{texnote} % \end{function} % % \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 . If is not open % input is requested from the terminal. % \end{function} % % \subsection{Constants} % % \begin{variable}{\c_iow_comment_char | % \c_iow_lbrace_char | % \c_iow_rbrace_char} % Constants that can be used to represent comment character, left and % right brace in token lists that should be written to a file. % \end{variable} % % \begin{variable}{\c_io_term_stream} % Input or output stream denoting the terminal. If used as an input % stream the user is prompted with the name of the (that is used % in the call "\ior_to:NN" or "\ior_gto:NN") followed by an equal sign. % If you don't want an automatic prompt of this sort ``misuse'' % "\c_iow_log_stream" as an input stream. % \end{variable} % % \begin{variable}{\c_iow_log_stream} % Output stream that writes only to the transcript file (e.g., the % {\tt.log} file on most systems). You may ``misuse'' this stream as an % input stream. In this case it acts as a terminal stream without user % prompting. % \end{variable} % % \begin{variable}{\g_iow_newline_code} % Global variable holding the character number of the character that % denotes a new line when something is written to an output stream. % \begin{texnote} % A.k.a \tn{newlinechar}. % \end{texnote} % \end{variable} % % \subsection{Internal functions} % % \begin{function}{\iow_long_expanded_aux:w} % Function used to implement immediate writing where a new line is % started at every blank. % \end{function} % % \begin{function}{% % \tex_read:D | % \tex_immediate:D | % \tex_closeout:D | % \tex_openin:D | % \tex_openout:D | % } % These are the functions of the primitive interface to \TeX. % \begin{texnote} % The \TeX{} primitives \tn{read}, \tn{immediate}, \tn{closeout}, % \tn{openin}, and \tn{openout} are all renamed and should not be used % by a programmer since the functionality is covered by the \LaTeX3 % functions above. % \end{texnote} % \end{function} % % % \section{Lowlevel i/o-commands} % % We start by ensuring that the required packages are loaded. % \begin{macrocode} %\RequirePackage{l3chk}\par %\RequirePackage{l3toks}\par %<*package> % \end{macrocode} % % This section is primarily concerned with input and output streams. % The naming conventions for i/o streams is |ior| (for read) and |iow| % (for write) as module names. e.g.\ |\c_ior_test_stream| is an input stream % variable called `test'. % % \subsection{Output streams} % % \begin{macro}{\iow_new:N} % \begin{macro}{\iow_new:c} % Allocation of new output streams is done by these functions. % As we currently do not distribute a new allocation module we nick % the |\newwrite| function. % \begin{macrocode} \def_new:Npn \iow_new:N {} \let:NN \iow_new:N \newwrite \def_new:Npn \iow_new:c {\exp_args:Nc \iow_new:N} % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\iow_open:Nn} % \begin{macro}{\iow_open:cn} % To open streams for reading or writing the following two functions % are provided. The streams are opened immediately. % % From some bad experiences on the mainframe, I learned that it is % better to force the close before opening a dataset for writing. % We have to check whether this is also necessary in case of % |\tex_openin:D|. % \begin{macrocode} \def_new:Npn \iow_open:Nn #1#2{\iow_close:N #1 \tex_immediate:D\tex_openout:D#1#2\scan_stop:} \def_new:Npn \iow_open:cn {\exp_args:Nc \iow_open:Nn} % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\iow_close:N} % Since we close output streams prior to opening, a separate closing % operation is probably not necessary. But here it is, just in % case\ldots. Actually you will need this if you intend to write % and then read in the same pass from some stream. % \begin{macrocode} \def_new:Npn \iow_close:N {\tex_immediate:D\tex_closeout:D} % \end{macrocode} % \end{macro} % % % \begin{macro}{\c_io_term_stream} % \begin{macro}{\c_iow_log_stream} % Here we allocate two output streams for writing to the transcript % file only (|\c_iow_log_stream|) and to both the terminal and transcript % file (|\c_io_term_stream|). The latter can also be used to read % from therefore it is called |..io_..|. % \begin{macrocode} \let_new:NN \c_io_term_stream \c_sixteen \let_new:NN \c_iow_log_stream \c_minus_one % \end{macrocode} % \end{macro} % \end{macro} % % \subsubsection{Immediate writing} % % \begin{macro}{\iow_expanded:Nn} % An abbreviation for an often used operation, which immediately % writes its second argument to the output stream. % \begin{macrocode} \def_new:Npn \iow_expanded:Nn {\tex_immediate:D\iow_deferred_expanded:Nn} % \end{macrocode} % \end{macro} % % \begin{macro}{\iow_unexpanded:Nn} % This routine writes the second argument verbatim onto the output % stream. If this stream isn't open, the output goes to the terminal. % If the first argument is no output stream at all, we get an % internal error. % \begin{macrocode} \def_new:Npn \iow_unexpanded:Nn #1#2{\toks_gset:Nn \g_tmpa_toks {#2} \iow_expanded:Nn #1{\toks_use:N \g_tmpa_toks}} % \end{macrocode} % \end{macro} % % % \begin{macro}{\iow_expanded_log:n} % \begin{macro}{\iow_expanded_term:n} % Now we redefine two functions for which we needed a definition % very early on. They both write their second argument fully % expanded to the output stream. % \begin{macrocode} \def:Npn \iow_expanded_log:n {\iow_expanded:Nn \c_iow_log_stream} \def:Npn \iow_expanded_term:n{\iow_expanded:Nn \c_io_term_stream} % \end{macrocode} % The second one isn't exactly equivalent to the old |\typeout| since % we need to control expansion in the function we provide for the user. % \end{macro} % \end{macro} % \begin{macro}{\iow_unexpanded_term:n} % This function writes its argument verbatim to the the terminal. % \begin{macrocode} \def_new:Npn \iow_unexpanded_term:n {\iow_unexpanded:Nn \c_io_term_stream} % \end{macrocode} % \end{macro} % % % \begin{macro}{\iow_unexpanded_if_avail:Nn} % \begin{macro}{\iow_unexpanded_if_avail:cn} % |\iow_unexpanded_if_avail:Nn | \m{stream} \m{code}. This routine writes % its second argument unexpanded to the stream given by the first % argument, provided that this stream was opened for writing. Note, % that |#| characters get doubled within \m{code}. % \begin{macrocode} \def_new:Npn \iow_unexpanded_if_avail:Nn #1{ % \end{macrocode} % In this routine we have to check whether or not the output stream % that was requested is defined at all. % So we check if the name is still free. % \begin{macrocode} \cs_free:NTF #1\use_none:n {\iow_unexpanded:Nn #1}} % \end{macrocode} % Note: the next function could be streamlined for speed if we use % the faster |\cs_free:cTF|. (space viz time). % \begin{macrocode} \def_new:Npn \iow_unexpanded_if_avail:cn { \exp_args:Nc \iow_unexpanded_if_avail:Nn } % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\iow_long_expanded:Nn} % \begin{macro}{\iow_long_unexpanded:Nn} % \begin{macro}{\iow_long_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 |\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} \def_new:Npn \iow_long_expanded_aux:w #1#2#3{ \group_begin:\g_iow_newline_code`\ #1#2{#3}\group_end:} \def_new:Npn \iow_long_expanded:Nn {\iow_long_expanded_aux:w \iow_expanded:Nn} \def_new:Npn \iow_long_unexpanded:Nn {\iow_long_expanded_aux:w \iow_unexpanded:Nn} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % \subsubsection{Deferred writing} % % Deferred writing to output streams is a bit more complicated because % there seems to be no nice hack for writing unexpanded. The only % relatively sure bet is to use |\token_to_meaning:N| expansion of some token % list. That's the way the following functions are implemented. % % Another possibility would be to reserve a certain number of scratch % token registers that could be used to hold the tokens until after the % next |\tex_shipout:D|. But such an approach would probably fail because of % the limited number of available token registers that would need to % be reserved for this special application. % % % \begin{macro}{\iow_deferred_expanded:Nn} % First the easy part, this is the primitive. % \begin{macrocode} \let:NN \iow_deferred_expanded:Nn \tex_write:D % \end{macrocode} % \end{macro} % % % \begin{macro}{\iow_deferred_unexpanded:Nn} % Now the harder part: % \begin{macrocode} \def_new:Npn \iow_deferred_unexpanded:Nn #1#2{ \tlp_set:Nn \l_tmpa_tlp {#2} \tlp_set:Nx \l_tmpb_tlp {\iow_deferred_expanded:Nn #1{\tlp_to_str:N \l_tmpa_tlp}} \l_tmpb_tlp} % \end{macrocode} % \end{macro} % % Long forms of these functions are not possible since the deferred % writing will restore the value of |\g_iow_newline_code| before it will have % a chance to act. But on the other hand it is nevertheless possible % to make all deferred writes long by setting the |\g_iow_newline_code| % inside the output routine just before the |\tex_shipout:D|. The only % disadvantage of this method is the fact that messages to the % terminal during this time will also then break at spaces. But we % should consider this. % % \subsubsection{Special characters for writing} % % % \begin{macro}{\c_iow_comment_char} % \begin{macro}{\c_iow_lbrace_char} % \begin{macro}{\c_iow_rbrace_char} % We also need to be able to write braces and the comment character. We % achieve this by defining global constants to expand into a version of % these characters with |\tex_catcode:D|${}=12$. % \begin{macrocode} \tex_catcode:D `\%= 12 \scan_stop: \tlp_new:Nn \c_iow_comment_char {%} \tex_catcode:D `\%= 14 \scan_stop: % \end{macrocode} % To avoid another allocation function which is probably only % necessary here we use the |\def:Npx| command directly. % \begin{macrocode} \tlp_new:Nn \c_iow_lbrace_char{} \tlp_new:Nn \c_iow_rbrace_char{} \def:Npx\c_iow_lbrace_char {\token_to_string:N{} \def:Npx\c_iow_rbrace_char {\token_to_string:N}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % \subsection{Input streams} % % \begin{macro}{\ior_new:N} % Allocation of new input streams is done by this function. % As we currently do not distribute a new allocation module we nick % the |\newwread| function. % \begin{macrocode} \def_new:Npn \ior_new:N {} \let:NN \ior_new:N \newread % \end{macrocode} % \end{macro} % % \begin{macro}{\ior_open:Nn} % Processing of input-streams (via |\tex_openin:D| and |closein|) is % always `immediate' as far as \TeX{} is concerned. An extra % |\tex_immediate:D| is silently ignored. % \begin{macrocode} \def_new:Npn \ior_open:Nn #1#2{\ior_close:N #1\scan_stop: \tex_openin:D#1#2\scan_stop:} % \end{macrocode} % \end{macro} % % \begin{macro}{\ior_eof:NTF} % |\ior_eof:NTF | \m{stream} \m{true case} \m{false case}. To % test if some particular input stream is exhausted the following % conditional is provided: % \begin{macrocode} \def_new:Npn \ior_eof:NTF #1{\if_eof:w#1 \exp_after:NN\use_choice_i:nn \else: \exp_after:NN\use_choice_ii:nn \fi:} % \end{macrocode} % \end{macro} % % \begin{macro}{\ior_eof:NF} % |\ior_eof:NF | \m{stream} \m{false case}. Do something if % if there is still something to read from this file: % \begin{macrocode} \def_new:Npn \ior_eof:NF #1{\if_eof:w#1 \exp_after:NN \use_none:nn \fi: \use:n} % \end{macrocode} % \end{macro} % % % \begin{macro}{\ior_to:NN} % \begin{macro}{\ior_gto:NN} % And here we read from files. % \begin{macrocode} %<*check> \def_new:Npn \ior_to:NN #1#2{\tex_read:D#1to#2 \chk_local_or_pref_global:N #2} % %<-check> \def_new:Npn \ior_to:NN #1{\tex_read:D#1to} \def_new:Npn \ior_gto:NN { %<*check> \pref_global_chk: % %<-check> \pref_global:D \ior_to:NN} % \end{macrocode} % \end{macro} % \end{macro} % % % Show token usage: % \begin{macrocode} % %<*showmemory> \showMemUsage % % \end{macrocode} % %