summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/morewrites/morewrites.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/morewrites/morewrites.dtx')
-rw-r--r--Master/texmf-dist/source/latex/morewrites/morewrites.dtx1147
1 files changed, 593 insertions, 554 deletions
diff --git a/Master/texmf-dist/source/latex/morewrites/morewrites.dtx b/Master/texmf-dist/source/latex/morewrites/morewrites.dtx
index cc8d2d23121..4766f3abe5e 100644
--- a/Master/texmf-dist/source/latex/morewrites/morewrites.dtx
+++ b/Master/texmf-dist/source/latex/morewrites/morewrites.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: morewrites.dtx Copyright (C) 2011 Bruno Le Floch
+%% File: morewrites.dtx Copyright (C) 2011-2012 Bruno Le Floch
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -13,8 +13,6 @@
%
%<*driver|package>
\RequirePackage{l3names}
-\GetIdInfo$Id: morewrites.dtx 0.1 2011-09-09 00:00:00Z bruno $
- {Always room for a new write}%
%</driver|package>
%<*driver>
\RequirePackage{morewrites}
@@ -22,6 +20,7 @@
\newwrite\foo \newwrite\foo \newwrite\foo \newwrite\foo
\newwrite\foo \newwrite\foo \newwrite\foo \newwrite\foo
\newwrite\foo \newwrite\foo \newwrite\foo \newwrite\foo
+\newcommand{\proc}[1]{\texttt{#1}}
\begin{document}
\DocInput{\jobname.dtx}
\end{document}
@@ -30,47 +29,55 @@
%
% \title{The \textsf{morewrites} package: \\
% Always room for a new \cs{write}\thanks{This
-% file has version number \ExplFileVersion, last revised \ExplFileDate.}}
+% file has version number v0.2, last revised 2012-07-10.}}
% \author{Bruno Le Floch}
-% \date{\ExplFileDate}
+% \date{July 10, 2012}
%
% \maketitle
% \tableofcontents
%
% \begin{documentation}
%
-% \section{\pkg{morewrites} documentation}
-%
-% This \LaTeX{} package is meant to be a solution for the error
-% \enquote{no room for a new \cs{write}}, which occurs when too
-% many macro packages reserve streams to write data to various
-% auxiliary files. It is in principle possible to rewrite packages
-% so that they are less greedy on resources, but that is often
-% unpractical for the end-user. Instead, \pkg{morewrites} hooks
-% at the lowest level (\TeX{} primitives). If I did my job
-% correctly, you simply need to add the line
-% |\usepackage{morewrites}| somewhere near the beginning of your
-% \LaTeX{} file, and the \enquote{no room for a new \cs{write}}
-% error should vanish.
-%
-% As this is a rather new package, it has not been tested very
-% thoroughly yet. I thus encourage you to check that references
-% are correct after loading that package: if they are correct
-% without \pkg{morewrites}, but wrong with, please send me a
-% minimal file showing the problem, or post a question on the
-% \url{tex.stackexchange.com} question and answers website,
-% or the \url{comp.text.tex} newsgroup.
-%
-% This package loads the \pkg{expl3} package, hence the
-% \pkg{l3kernel} bundle needs to be up to date. If Heiko
-% Oberdiek's package %^^A \pkg{atveryend}
-% \pkg{atbegshi} is available, it will be used.
-%
-% \section{Known deficiencies}
-%
-% Some distributions of \TeX{} allow a quoted syntax for file
-% names with spaces. I haven't yet coded that. A temporary fix
-% is to avoid file names with spaces.
+% \section{\pkg{morewrites} documentation}
+%
+% This \LaTeX{} package is meant to be a solution for the error
+% \enquote{no room for a new \cs{write}}, which occurs when too many
+% macro packages reserve streams to write data to various auxiliary
+% files. It is in principle possible to rewrite packages so that they
+% are less greedy on resources, but that is often unpractical for the
+% end-user. Instead, \pkg{morewrites} hooks at the lowest level (\TeX{}
+% primitives). If I did my job correctly, you simply need to add the
+% line |\usepackage{morewrites}| somewhere near the beginning of your
+% \LaTeX{} file, and the \enquote{no room for a new \cs{write}} error
+% should vanish.
+%
+% I have tried to make the code as robust as possible, but there may
+% still be bugs lurking as this package has not been tested very
+% thoroughly yet. I thus encourage you to check that references are
+% correct after loading that package: if they are correct without
+% \pkg{morewrites}, but wrong with, please send me a minimal file
+% showing the problem, or post a question on the
+% \url{tex.stackexchange.com} question and answers website, or the
+% \url{comp.text.tex} newsgroup.
+%
+% This package loads the \pkg{expl3} package, hence the \pkg{l3kernel}
+% bundle needs to be up to date. If Heiko Oberdiek's package
+% \pkg{atbegshi} is available, it will be used.
+%
+% \section{Known deficiencies}
+%
+% Some distributions of \TeX{} allow a quoted syntax for file names with
+% spaces. I haven't yet coded that. A temporary fix is to avoid file
+% names with spaces.
+%
+% The package code is not very legible, and definitely uses too many
+% |:D| control sequences, whose name means \enquote{do not use}. The
+% author does not see a way to avoid using primitives in this package,
+% since hooking into the primitives \tn{immediate}, \tn{write},
+% \emph{etc.} requires having a very strong control on what every
+% command does. \emph{Do not take this package as an example of how to
+% code with \pkg{expl3}; go and see Joseph Wright's \pkg{siunitx}
+% instead.}
%
% \end{documentation}
%
@@ -81,637 +88,647 @@
%<*package>
% \begin{macrocode}
\ProvidesExplPackage
- {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
-\RequirePackage{expl3}
-% \end{macrocode}
-%
-% Let us recall the syntax of the commands that we need to modify
-% (from Chapter 24 of the \TeX{}book): each of those can be preceeded
-% by \cs{immediate}, which we will thus also have to modify.
+ {morewrites} {2012/07/10} {0.2} {Always room for a new write}
+\RequirePackage{expl3, primargs}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=morewrites>
+% \end{macrocode}
+%
+% \subsection{Overview of relevant \TeX{} facts}
+%
+% The aim of the \pkg{morewrites} package is to lift \TeX{}'s
+% restriction of only having $16$ files open for writing at the same
+% time. We must thus patch $4$ primitives, \tn{openout}, \tn{write},
+% \tn{closeout} and \tn{immediate}, and the \cs{newwrite} macro, defined
+% by \LaTeX{} (and plain \TeX{}). Each of those commands must be made
+% to accept numbers outside the range $[0,15]$. Let us review the
+% syntax of the various commands we need to alter (see Chapter~24 of the
+% \TeX{}book).
+%
+% We start with the three \enquote{actions}.
+% \begin{syntax}
+% \tn{openout} \meta{integer} \meta{equals} \meta{file name}
+% \end{syntax}
+% \TeX{} searches the path for a file with a name given by
+% \meta{file name}. If found, this file is opened in the writing stream
+% \meta{integer}, which must be a number in the range $[0,15]$.
+% \begin{syntax}
+% \tn{write} \meta{integer} \meta{filler} \meta{general text}
+% \end{syntax}
+% \TeX{} expands the \meta{general text} as for an \texttt{x}-type
+% expansion, with the caveat that macro parameter characters do not need
+% to be doubled; converts the result to a string, and writes it in the
+% writing stream \meta{integer}. If the writing stream \meta{integer}
+% is open (in particular it must be in the range $[0,15]$), then this
+% writes to the corresponding file. Otherwise, if the \meta{integer} is
+% negative, the text is written to the log file, and a non-negative
+% \meta{integer} writes to the terminal. One exception: if the
+% \meta{integer} is $18$, the text is sent to a shell to be run as shell
+% code.
+% \begin{syntax}
+% \tn{closeout} \meta{integer}
+% \end{syntax}
+% If the writing stream \meta{integer} is open, it is closed.
+% Otherwise, if the \meta{integer} is not in the range $[0,15]$ an error
+% may be raised, or nothing happens.
+%
+% By default, each one of those three \enquote{actions} are recorded in
+% a whatsit node in the current list, and will be performed when the box
+% containing the whatsit node is sent to the final \texttt{pdf},
+% \emph{i.e.}, at \enquote{shipout} time. In particular, the
+% \meta{general text} for the \tn{write} primitive is expanded at
+% shipout time. This behaviour may be modified by putting
+% \tn{immediate} before any of the three \enquote{actions} to force
+% \TeX{} to perform the action immediately instead of recording it in a
+% whatsit node.
+%
+% Since the \tn{openout}, \tn{write}, and \tn{closeout} primitives
+% operate at \tn{shipout} time, we will have to hook into this primitive
+% too. It expects to be followed by a box specification such as
+% \tn{box}\meta{integer}, or \tn{hbox}\Arg{material to typeset}.
+%
+% Finally, the \cs{newwrite} macro expects one token as its argument,
+% and defines this token (with \tn{chardef}) to be an integer
+% corresponding to the first available writing stream. We must extend
+% it to let it allocate higher (virtual) write registers.
+%
+% All of the primitives above perform full expansion of all tokens when
+% looking for their operands. In most cases, only the \tn{meaning} of
+% tokens encountered in this way matters. Specifically,
% \begin{itemize}
-% \item \cs{openout} \meta{4-bit number} \meta{equals} \meta{filename}
-% \item \cs{write} \meta{number} \meta{general text}
-% with a special case when \meta{number} is $18$.
-% \item \cs{closeout} \meta{4-bit number}
+% \item \meta{integer} denotes an integer in any form that \TeX{}
+% accepts as the right-hand side of a primitive integer assignment of
+% the form \tn{count}|0=|\meta{integer};
+% \item \meta{equals} is an arbitrary (optional) number of explicit or
+% implicit space characters, an optional explicit equal sign of
+% category other, and further (optional) explicit or implicit space
+% characters;
+% \item \meta{file name} is an arbitrary sequence of explicit or implicit
+% characters with arbitrary category codes (except active characters,
+% which are expanded before reaching \TeX{}'s mouth), ending either
+% with a space character (character code $32$, arbitrary non-active
+% category code, explicit or implicit), which is removed, or with a
+% non-expandable token, with some care needed for the case of a
+% \tn{notexpanded:} expandable token;
+% \item \meta{filler} is an arbitrary combination of tokens whose
+% meaning is \tn{relax} or a character with category code $10$;
+% \item \meta{general text} is formed of braced tokens, starting with an
+% explicit or implicit begin-group character, and ending with the
+% matching explicit end-group character (both with any character
+% code), with an equal number of explicit begin-group and end-group
+% characters in between: this is precisely the right-hand side of an
+% assignment of the form \tn{toks}|0=|\meta{general text}.
% \end{itemize}
-% Finally, we also need to modify \cs{newwrite} to let it allocate
-% more than $16$ streams.
%
-% \begin{macro}[aux]{\mw_tex_openin:w,\mw_tex_read:w,
-% \mw_etex_readline:w,\mw_tex_closein:w}
-% \begin{macro}[aux]{\mw_tex_immediate:w,\mw_tex_openout:w,
-% \mw_tex_write:w,\mw_tex_closeout:w}
-% First save the primitives (including those for input,
-% because this package might be extended to cover that
-% as well).
+% \subsection{Renaming primitives (again)}
+%
+% \begin{macro}[int]
+% {
+% \@@_tex_immediate:w ,
+% \@@_tex_openout:w ,
+% \@@_tex_write:w ,
+% \@@_tex_closeout:w
+% }
+% First save the output-related primitives.
% \begin{macrocode}
-\cs_new_eq:NN \mw_tex_openin:w \tex_openin:D
-\cs_new_eq:NN \mw_tex_read:w \tex_read:D
-\cs_new_eq:NN \mw_etex_readline:w \etex_readline:D
-\cs_new_eq:NN \mw_tex_closein:w \tex_closein:D
-\cs_new_eq:NN \mw_tex_immediate:w \tex_immediate:D
-\cs_new_eq:NN \mw_tex_openout:w \tex_openout:D
-\cs_new_eq:NN \mw_tex_write:w \tex_write:D
-\cs_new_eq:NN \mw_tex_closeout:w \tex_closeout:D
-\cs_new_eq:NN \mw_tex_shipout:w \tex_shipout:D
+\cs_new_eq:NN \@@_tex_immediate:w \tex_immediate:D
+\cs_new_eq:NN \@@_tex_openout:w \tex_openout:D
+\cs_new_eq:NN \@@_tex_write:w \tex_write:D
+\cs_new_eq:NN \@@_tex_closeout:w \tex_closeout:D
% \end{macrocode}
% \end{macro}
+%
+% \begin{macro}[int]{\@@_tex_shipout:w}
+% Since the non-\tn{immediate} output primitives act at \tn{shipout}
+% time, we need to alter this primitive too.
+% %^^A Not sure if the shipout primitive is done right.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_tex_shipout:w \tex_shipout:D
+% \end{macrocode}
% \end{macro}
%
% \subsection{Variables}
%
-% \begin{variable}{\g_mw_late_write_int}
-% The integer \cs{g_mw_late_write_int} labels the various
-% non-immediate operations in the order in which they appear
-% in the source.
-% \begin{macrocode}
-\int_new:N \g_mw_late_write_int
+% \begin{variable}{\g_@@_late_write_int}
+% The integer \cs{g_@@_late_write_int} labels the various
+% non-immediate operations in the order in which they appear in the
+% source. We can never reuse a number because there is no way to know
+% if a whatsit was recorded in a box register, which could be reused
+% in a shipped-out box:
+% \begin{quote}
+% \cs{vbox_set:Nn} \cs{l_my_box} \\
+% ~~|{| \cs{iow_shipout_x:Nn} \cs{c_term_iow} \Arg{text} |}|
+% \cs{tex_shipout:D} \cs{tex_copy:D} \cs{l_my_box}
+% \cs{tex_shipout:D} \cs{tex_copy:D} \cs{l_my_box}
+% \end{quote}
+% will print \meta{text} to the terminal twice.
+% \begin{macrocode}
+\int_new:N \g_@@_late_write_int
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{\g_mw_writes_prop}
-% The property list \cs{g_mw_writes_prop}
-% associates a file name to each open stream.
+% \begin{variable}{\g_@@_iow_prop}
+% The property list \cs{g_@@_iow_prop} associates a file name to each
+% open stream.
% \begin{macrocode}
-\prop_new:N \g_mw_writes_prop
+\prop_new:N \g_@@_iow_prop
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{\g_mw_read,\c_mw_tmp_file_tl}
-% The expansion that \cs{write} performs is impossible
-% to emulate with anything else than \cs{write}. We will
-% need to write to a file and read back from it for things
-% to work properly.
+% \begin{variable}{\g_@@_iow, \g_@@_ior, \g_@@_tmp_file_tl}
+% The expansion that \tn{write} performs is impossible to emulate with
+% anything else than \tn{write}. We will write on the stream
+% \cs{g_@@_iow} to the file \cs{g_@@_tmp_file_tl} and read back from
+% it in the stream \cs{g_@@_ior} for things to work properly.
+% Unfortunately, this means that the file is repeatedly opened and
+% closed, leaving a trace of that in the log.
% \begin{macrocode}
-\newread \g_mw_read
-\tl_const:Nn \c_mw_tmp_file_tl { \jobname.mw }
-\newwrite \g_mw_write
+\newwrite \g_@@_iow
+\newread \g_@@_ior
+\tl_new:N \g_@@_tmp_file_tl
+\tl_gset:Nn \g_@@_tmp_file_tl { \jobname.mw }
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{\g_mw_reserved_writes_seq}
-% Some of the writing streams are already allocated when loading
-% this package, and we let \LaTeX{} manage them.
+% \begin{variable}{\g_@@_reserved_iow_clist}
+% Some of the writing streams are already allocated when loading this
+% package, and we let the engine manage them. This variable is a
+% clist because it only contains integers and the main task is to test
+% if a given integer is in the comma list.
% \begin{macrocode}
-\seq_new:N \g_mw_reserved_writes_seq
-\prg_stepwise_inline:nnnn {0} {1} { \g_mw_write - 1 }
- { \seq_gput_right:Nn \g_mw_reserved_writes_seq {#1} }
-\seq_gput_right:Nn \g_mw_reserved_writes_seq {18}
+\clist_new:N \g_@@_reserved_iow_clist
+\int_step_inline:nnnn {0} {1} { \g_@@_iow - 1 }
+ { \clist_gput_right:Nn \g_@@_reserved_iow_clist {#1} }
+\clist_gput_right:Nn \g_@@_reserved_iow_clist {18}
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{\l_mw_tmpa_tl,\g_mw_step_int,\g_mw_tmpa_int,\g_mw_box}
+% \begin{variable}[int]{\g_@@_stream_int}
+% An integer holding the \meta{number} argument of various primitives,
+% namely a writing stream.
% \begin{macrocode}
-\tl_new:N \l_mw_tmpa_tl
-\int_new:N \g_mw_step_int
-\int_new:N \g_mw_tmpa_int
-\newbox \g_mw_box
+\int_new:N \g_@@_stream_int
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{\g_mw_stream_int,\g_mw_filename_tl,\g_mw_text_tl}
-% What parsing finds is stored in those three variables.
+% \begin{macro}[int]{\s_@@}
+% A recognizable version of \cs{scan_stop:}. This is inspired
+% from\footnote{Historically, this might have happened the other way
+% around, since the author of this package is also on the \LaTeX3
+% Team.} scan marks (see the \pkg{l3quark} module of \LaTeX3), but
+% note that we don't use \cs{__scan_new:N} directly, since it is
+% internal to \LaTeX3.
% \begin{macrocode}
-\int_new:N \g_mw_stream_int
-\tl_new:N \g_mw_filename_tl
-\tl_new:N \g_mw_text_tl
+\cs_new_eq:NN \s_@@ \scan_stop:
% \end{macrocode}
-% \end{variable}
+% \end{macro}
%
-% \begin{macro}[aux]{\mw_scan_stop:}
-% A recognizable version of \cs{scan_stop:}.
+% \begin{variable}[int]{\l_@@_internal_tl}
+% Temporary token list, used for scratch purposes.
% \begin{macrocode}
-\cs_new_eq:NN \mw_scan_stop: \scan_stop:
+\tl_new:N \l_@@_internal_tl
% \end{macrocode}
-% \end{macro}
+% \end{variable}
%
% \subsection{Parsing}
%
-% \begin{macro}[aux]{\mw_parse_number:Nw}
-% Stores a number in \cs{g_mw_stream_int} before performing |#1|.
+% \begin{macro}[aux]{\@@_equals_file_name:N}
+% Most of the parsing for primitive arguments is done using
+% \pkg{primargs}, except for one case we care about: after its
+% \meta{number} argument, the \tn{openout} primitive expects an
+% \meta{equals} (optional spaces and |=|) and a \meta{file name}.
% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_parse_number:Nw #1
- {
- \tex_afterassignment:D #1
- \tex_global:D \g_mw_stream_int
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[aux]{\mw_parse_text:Nw}
-% This is used for the \cs{write} command: to grab
-% a \meta{general text} we assign a \cs{toks}, within
-% a group to avoid clobbering \cs{toks}\texttt{0}.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_parse_text:Nw #1
+\cs_new_protected:Npn \@@_equals_file_name:N #1
{
\group_begin:
\tex_aftergroup:D #1
- \tex_afterassignment:D \mw_parse_text_aux:
- \tex_toks:D \c_zero =
- }
-\cs_new_protected_nopar:Npn \mw_parse_text_aux:
- {
- \tl_gset:Nx \g_mw_text_tl { \tex_the:D \tex_toks:D \c_zero }
- \group_end:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[aux]{\mw_parse_equals_filename:Nw}
-% Remove a potential \texttt{=} sign.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_parse_equals_filename:Nw #1
- {
- \peek_meaning_remove:NTF =
- { \mw_parse_filename:Nw #1 } { \mw_parse_filename:Nw #1 }
+ \primargs_remove_equals:N \@@_parse_file_name:
}
+\cs_new_protected:Npn \@@_parse_file_name:
+ { \primargs_get_file_name:N \group_end: }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux]{\mw_parse_filename:Nw}
-% Empty the filename, and build it one character at a time.
-% We need to expand tokens as in an f-type expansion, but
-% without losing spaces. For that, we use \cs{peek_gafter:Nw}
-% to find out whether the coming token is expandable or not,
-% and distinguish further depending on what kind of
-% non-expandable token it is.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_parse_filename:Nw #1
- {
- \group_begin:
- \group_align_safe_begin:
- \tex_aftergroup:D #1
- \tl_gclear:N \g_mw_filename_tl
- \mw_parse_filename_loop:w
- }
-\cs_new_protected_nopar:Npn \mw_parse_filename_loop:w
- { \peek_gafter:Nw \mw_parse_filename_loop_test: }
-% \end{macrocode}
-% The test \cs{token_if_expandable:NTF} should not be used here,
-% since it returns false for undefined control sequences (by design).
-% But when parsing a file name, undefined control sequences would
-% be expanded, and cause errors. In order to keep this behaviour,
-% we do the test ourselves.
-%
-% A non-expandable token is either a non-space character, a space
-% character, or a control sequence (either a primitive or a register).
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_parse_filename_loop_test:
- {
- \exp_after:wN \if_meaning:w \exp_not:N \g_peek_token \g_peek_token
- \exp_after:wN \use_ii:nn
- \else:
- \exp_after:wN \use_i:nn
- \fi:
- { \exp_after:wN \mw_parse_filename_loop:w }
- {
- \token_if_cs:NTF \g_peek_token
- { \mw_parse_filename_end: }
- {
- \mw_parse_filename_space_test:NTF \g_peek_token
- { \mw_parse_filename_space_do:w }
- {
- \exp_after:wN \mw_parse_filename_push:w
- \token_to_meaning:N
- }
- }
- }
- }
-% \end{macrocode}
-% We stop at the first non-expandable non-character token.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_parse_filename_end:
- {
- \group_align_safe_end:
- \group_end:
- }
-% \end{macrocode}
-% We also stop when seeing a space, after removing it.
-% \begin{macrocode}
- %^^A TeXlive's behaviour (?): space with any catcode
-\cs_new_protected_nopar:Npn \mw_parse_filename_space_test:NTF
- { \token_if_eq_charcode:NNTF \c_space_token }
-\cs_new_protected_nopar:Npn \mw_parse_filename_space_do:w
- {
- \tex_afterassignment:D \mw_parse_filename_end:
- \cs_set_eq:NN \g_peek_token
- }
-% \end{macrocode}
-% Finally, the case of normal characters. It seems
-% that e.g., \cs{bgroup} is seen in the same way as an
-% explicit left-brace character. Hence, we work with
-% the \cs{meaning} of the character we are looking at.
-% Most meanings of characters are two words, followed
-% by the character. Three exceptions: ``math shift character'',
-% ``alignment tab character'', and ``macro parameter character'',
-% which have three words.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_parse_filename_push:w #1 ~ %
- {
- \tl_if_in:nnTF { math ~ alignment ~ macro } { #1 }
- { \mw_parse_filename_push_three:w }
- { \mw_parse_filename_push_two:w }
- }
-\cs_new_protected_nopar:Npn \mw_parse_filename_push_two:w #1 ~ #2
- {
- \tl_gput_right:Nn \g_mw_filename_tl {#2}
- \mw_parse_filename_loop:w
- }
-\cs_new_protected_nopar:Npn \mw_parse_filename_push_three:w #1 ~ #2 ~ #3
- {
- \tl_gput_right:Nn \g_mw_filename_tl {#3}
- \mw_parse_filename_loop:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-%
% \subsection{Immediate (writing)}
%
% In the context of immediate writing, we can store the text
% in a token list, and only write it at the corresponding
-% \cs{closeout} command. We keep track of a property list,
-% \cs{g_mw_writes_prop}, of the writes which are
+% \tn{closeout} command. We keep track of a property list,
+% \cs{g_@@_iow_prop}, of the writes which are
% open (from the point of view of the user), with the
% corresponding file name.
%
-% \subsubsection{What follows \cs{immediate}}
-%
-% \begin{macro}[aux]{\mw_prg_case_meaning:Nnn}
-% \begin{macro}[aux]{\mw_prg_case_meaning_aux:Nw}
-% See \cs{prg_case_tl:Nnn}. Here, it is used by \cs{mw_immediate:w}
-% to decide whether the following token is a writing command.
-% \begin{macrocode}
-\cs_new:Npn \mw_prg_case_meaning:Nnn #1#2#3
- { \mw_prg_case_meaning_aux:Nw #1 #2 #1 {#3} \q_recursion_stop }
-\cs_new:Npn \mw_prg_case_meaning_aux:Nw #1#2#3
- {
- \token_if_eq_meaning:NNTF #1 #2
- { \prg_case_end:nw {#3} }
- { \mw_prg_case_meaning_aux:Nw #1 }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[aux]{\mw_exp_after:Nf}
-% Eventually, this should be replaced by a slow \cs{futurelet}-based
-% expansion which does not lose a space.
-% \begin{macrocode}
-\cs_new:Npn \mw_exp_after:Nf #1
- { \exp_after:wN #1 \tex_romannumeral:D -`0 }
-% \end{macrocode}
-% \end{macro}
+% \subsubsection{What follows \tn{immediate}}
%
-% \begin{macro}[aux]{\mw_immediate:w}
-% This is a little bit subtle: \TeX{}'s \cs{immediate} primitive
+% \begin{macro}[aux]{\@@_immediate:w}
+% \begin{macro}[aux]{\@@_immediate_ii:, \@@_immediate_iii:N}
+% \begin{macro}[aux]{\@@_immediate_iv:NN}
+% \begin{macro}[aux, EXP]{\@@_immediate_v:w}
+% This is a little bit subtle: \TeX{}'s \tn{immediate} primitive
% raises a flag which is cancelled once \TeX{} sees a non-expandable
-% token. This can be emulated by expanding tokens in front of it until
-% the first non-expandable token, and checking if it is either
-% \cs{openout}, \cs{write}, or \cs{closeout}. We will use f-type
-% expansion.\footnote{Unfortunately, this is not quite correct, since it
-% loses a space if someone puts \cs{immediate} at places where it
-% does not belong, such as \cs{immediate} \cs{c_space_tl}.}
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_immediate:w
- {
- \scan_stop: %^^A?
- \mw_exp_after:Nf \mw_immediate_aux:w
- }
-\cs_new_protected_nopar:Npn \mw_immediate_aux:w
+% token. We use \pkg{primargs}'s \texttt{read_x_token} function to
+% fully expand in the \TeX{} way, then test for \tn{openout},
+% \tn{write}, or \tn{closeout}. We don't test for the primitives
+% themselves, but rather for a recognizable marker, \cs{s_@@}, equal
+% to \tn{relax}. If present, replace |morewrites| by
+% |morewrites_immediate| in the csname of the second token after it
+% (it turns out that this is the correct structure).
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_immediate:w
+ { \primargs_read_x_token:N \@@_immediate_ii: }
+\cs_new_protected_nopar:Npn \@@_immediate_ii:
{
- \peek_meaning:NT \mw_scan_stop:
- { \mw_immediate_mw_scan_stop:N }
+ \token_if_eq_meaning:NNT \g_primargs_token \s_@@
+ { \@@_immediate_iii:N }
}
-\cs_new_protected_nopar:Npn \mw_immediate_mw_scan_stop:N #1
+\cs_new_protected:Npn \@@_immediate_iii:N #1
{
- \str_if_eq:nnTF { #1 } { \mw_scan_stop: }
- { \mw_immediate_do:NN }
+ \tl_if_eq:nnTF { #1 } { \s_@@ }
+ { \@@_immediate_iv:NN }
{ #1 }
}
-\cs_new_protected_nopar:Npn \mw_immediate_do:NN #1 #2
+\cs_new_protected:Npn \@@_immediate_iv:NN #1 #2
{
- \exp_args:Nc \mw_parse_number:Nw
+ \exp_args:Nc #1
{
- \exp_after:wN \mw_immediate_do_aux:w
+ \exp_after:wN \@@_immediate_v:w
\token_to_str:N #2
}
}
\use:x
{
- \cs_new_protected_nopar:Npn \exp_not:N \mw_immediate_do_aux:w
- ##1 \tl_to_str:n {mw_} { mw_immediate_ }
+ \cs_new:Npn \exp_not:N \@@_immediate_v:w
+ ##1 \tl_to_str:n { @@ } { @@_immediate }
}
% \end{macrocode}
% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
%
% \subsubsection{Immediate closeout}
%
-% \begin{macro}[aux]{\mw_immediate_closeout_test:}
+% \begin{macro}[aux]{\@@_immediate_closeout_test:n}
% When the user requests to close a stream, we look in
-% \cs{g_mw_reserved_writes_seq} to see if it is a reserved
+% \cs{g_@@_reserved_iow_clist} to see if it is a reserved
% stream: in this case, we simply use the primitive.
% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_immediate_closeout_test:
+\cs_new_protected:Npn \@@_immediate_closeout_test:n #1
{
- \seq_if_in:NVTF \g_mw_reserved_writes_seq \g_mw_stream_int
- { \mw_tex_immediate:w \mw_tex_closeout:w \g_mw_stream_int }
- { \mw_immediate_closeout_aux: }
+ \int_gset:Nn \g_@@_stream_int {#1}
+ \clist_if_in:NnTF \g_@@_reserved_iow_clist {#1}
+ { \@@_tex_immediate:w \@@_tex_closeout:w \g_@@_stream_int }
+ { \@@_immediate_closeout_aux: }
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux]{\mw_immediate_closeout_aux:}
-% We then look in \cs{g_mw_writes_prop} to find
-% the file name corresponding to that stream number. If the
-% stream does not appear as a key in the property list,
-% then it was not open yet, and we do nothing.
+% \begin{macro}[aux]{\@@_immediate_closeout_aux:}
+% We then look in \cs{g_@@_iow_prop} to find the file name
+% corresponding to that stream number. If the stream does not appear
+% as a key in the property list, then it was not open yet, and we do
+% nothing. Otherwise, the key is removed, and we write the collected
+% material to the file.
% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_immediate_closeout_aux:
+\cs_new_protected_nopar:Npn \@@_immediate_closeout_aux:
{
- \exp_args:NNV \prop_pop:NnNT
- \g_mw_writes_prop \g_mw_stream_int \l_mw_tmpa_tl
+ \exp_args:NNV \prop_pop:NnNT \g_@@_iow_prop
+ \g_@@_stream_int \l_@@_internal_tl
{
- \mw_tex_immediate:w \mw_tex_openout:w
- \g_mw_write \l_mw_tmpa_tl \scan_stop:
- \group_begin:
- \int_set_eq:NN \tex_newlinechar:D \c_minus_one
- \tl_use:c { g_mw_write_ \int_use:N \g_mw_stream_int _tl }
- \tl_gclear:c { g_mw_write_ \int_use:N \g_mw_stream_int _tl }
- \group_end:
- \mw_tex_immediate:w \mw_tex_closeout:w \g_mw_write
+ \@@_immediate_write_and_close:nn
+ { \g_@@_stream_int } { \l_@@_internal_tl }
}
}
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}[aux]{\@@_immediate_write_and_close:nn}
+% The code to write the material collected so far for a given output
+% \meta{stream} is in the token list \cs{g_@@_iow_\meta{stream}_tl}.
+% We do this writing in the actual stream \cs{g_@@_iow}, briefly
+% opened and closed on the file |#2|.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_immediate_write_and_close:nn #1#2
+ {
+ \@@_tex_immediate:w \@@_tex_openout:w
+ \g_@@_iow #2 \scan_stop:
+ \group_begin:
+ \int_set_eq:NN \tex_newlinechar:D \c_minus_one
+ \tl_use:c { g_@@_iow_ \int_eval:n {#1} _tl }
+ \tl_gclear:c { g_@@_iow_ \int_eval:n {#1} _tl }
+ \group_end:
+ \@@_tex_immediate:w \@@_tex_closeout:w \g_@@_iow
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \subsubsection{Immediate openout}
%
-% \begin{macro}[aux]{\mw_immediate_openout_test:}
-% Read the stream number. If it is one of the reserved streams,
-% we use the primitive. Otherwise, parse an optional equal sign,
+% \begin{macro}[aux]{\@@_immediate_openout_test:n}
+% Read the stream number. If it is one of the reserved streams, we
+% use the primitive. Otherwise, parse an optional equal sign,
% followed by the file name.
% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_immediate_openout_test:
+\cs_new_protected:Npn \@@_immediate_openout_test:n #1
{
- \seq_if_in:NVTF \g_mw_reserved_writes_seq \g_mw_stream_int
- { \mw_tex_immediate:w \mw_tex_openout:w \g_mw_stream_int }
- { \mw_parse_equals_filename:Nw \mw_immediate_openout_aux: }
+ \int_gset:Nn \g_@@_stream_int {#1}
+ \clist_if_in:NnTF \g_@@_reserved_iow_clist {#1}
+ { \@@_tex_immediate:w \@@_tex_openout:w \g_@@_stream_int }
+ { \@@_equals_file_name:N \@@_immediate_openout_aux:n }
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux]{\mw_immediate_openout_aux:}
-% When the user requests to open a stream, it might already be
-% open, with another file as its destination. We thus need to
-% first close the stream, writing all that we collected so far
-% to that other file. This has no effect if the stream was not
-% open yet.
+% \begin{macro}[aux]{\@@_immediate_openout_aux:n}
+% When the user requests to open a stream, it might already be open,
+% with another file as its destination. We thus need to first close
+% the stream, writing all that we collected so far to that other
+% file. This has no effect if the stream was not open yet.
%
-% We then put the stream and its associated filename in the
-% property list, and empty the corresponding token list.
+% We then put the stream and its associated file name in the property
+% list, and empty/create the corresponding token list.
% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_immediate_openout_aux:
+\cs_new_protected:Npn \@@_immediate_openout_aux:n #1
{
- \mw_immediate_closeout_aux:
- \prop_gput:NVV \g_mw_writes_prop \g_mw_stream_int \g_mw_filename_tl
- \tl_gclear_new:c { g_mw_write_ \int_use:N \g_mw_stream_int _tl }
+ \@@_immediate_closeout_aux:
+ \prop_gput:NVn \g_@@_iow_prop \g_@@_stream_int {#1}
+ \tl_gclear_new:c { g_@@_iow_ \int_use:N \g_@@_stream_int _tl }
}
% \end{macrocode}
% \end{macro}
%
% \subsubsection{Immediate write}
%
-% \begin{macro}[aux]{\mw_immediate_write_test:}
-% Read the stream number. If it is one of the reserved streams,
-% we use the primitive. Otherwise, parse the text.
+% \begin{macro}[aux]{\@@_immediate_write_test:n}
+% Read the stream number. If it is one of the reserved streams, we
+% use the primitive. Otherwise, parse the text.
% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_immediate_write_test:
+\cs_new_protected:Npn \@@_immediate_write_test:n #1
{
- \seq_if_in:NVTF \g_mw_reserved_writes_seq \g_mw_stream_int
- { \mw_tex_immediate:w \mw_tex_write:w \g_mw_stream_int }
- { \mw_parse_text:Nw \mw_immediate_write_aux: }
+ \int_gset:Nn \g_@@_stream_int {#1}
+ \clist_if_in:NnTF \g_@@_reserved_iow_clist {#1}
+ { \@@_tex_immediate:w \@@_tex_write:w \g_@@_stream_int }
+ { \primargs_get_general_text:N \@@_immediate_write_aux:n }
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux]{\mw_immediate_write_aux:}
-% Only \cs{write} itself can emulate how \cs{write} expands tokens,
-% because |#| don't have to be doubled. Hence, we write to a file,
-% and re-read from it, setting \cs{endlinechar} to $-1$ to avoid
-% spurious characters. Lines will be written one at a time: this
-% allows us to set \cs{newlinechar} to $-1$ when writing, so that
-% no extra line will be created.
+% \begin{macro}[aux]{\@@_immediate_write_aux:n}
+% Test whether the stream is allocated or not.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_immediate_write_aux:n
+ {
+ \prop_if_in:NVTF \g_@@_iow_prop \g_@@_stream_int
+ { \@@_immediate_write_open:n }
+ { \@@_immediate_write_closed:n }
+ }
+% \end{macrocode}
+% \end{macro}
%
-% If the stream \cs{g_mw_stream_int} is not allocated,
-% then write either to the terminal or only to the log file.
+% \begin{macro}[aux]{\@@_immediate_write_closed:n}
+% If the stream \cs{g_@@_stream_int} is not allocated, then write
+% either to the terminal or only to the log file, depending on the
+% sign.
% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_immediate_write_aux:
+\cs_new_protected:Npn \@@_immediate_write_closed:n #1
{
- \prop_if_in:NVTF \g_mw_writes_prop \g_mw_stream_int
- {
- \mw_tex_immediate:w \mw_tex_openout:w \g_mw_write
- \c_mw_tmp_file_tl \scan_stop:
- \mw_tex_immediate:w \mw_tex_write:w \g_mw_write { \g_mw_text_tl }
- \mw_tex_immediate:w \mw_tex_closeout:w \g_mw_write
- \group_begin:
- \int_set_eq:NN \tex_endlinechar:D \c_minus_one
- \mw_tex_openin:w \g_mw_read \c_mw_tmp_file_tl \scan_stop:
- \mw_immediate_write_aux_readlines:
- \mw_tex_closein:w \g_mw_read
- \group_end:
- }
- {
- \mw_tex_immediate:w \mw_tex_write:w
- \if_num:w \g_mw_stream_int < \c_zero
- -1
- \else:
- 16
- \fi:
- { \g_mw_text_tl }
- }
+ \@@_tex_immediate:w \@@_tex_write:w
+ \if_num:w \g_@@_stream_int < \c_zero
+ -1
+ \else:
+ 16
+ \fi:
+ {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\@@_immediate_write_open:n}
+% \begin{macro}[aux]{\@@_immediate_write_readlines_loop:}
+% Only \tn{write} itself can emulate how \tn{write} expands tokens,
+% because |#| don't have to be doubled, and because the
+% \tn{newlinechar} has to be changed to new lines. Hence, we start by
+% writing |#1| to a file, yielding some lines. The lines are then
+% read one at a time using \eTeX{}'s \tn{readline} with
+% \tn{endlinechar} set to $-1$ to avoid spurious characters. Each
+% line becomes a \tn{immediate} \tn{write} statement added to the
+% token list \cs{g_@@_iow_\meta{stream}_tl}. This token list will be
+% called when it is time to actually write to the file. At that time,
+% \tn{newlinechar} will be $-1$, so that writing each line will
+% produce no extra line.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_immediate_write_open:n #1
+ {
+ \@@_tex_immediate:w \@@_tex_openout:w \g_@@_iow
+ \g_@@_tmp_file_tl \scan_stop:
+ \@@_tex_immediate:w \@@_tex_write:w \g_@@_iow {#1}
+ \@@_tex_immediate:w \@@_tex_closeout:w \g_@@_iow
+ \group_begin:
+ \int_set_eq:NN \tex_endlinechar:D \c_minus_one
+ \tex_openin:D \g_@@_ior \g_@@_tmp_file_tl \scan_stop:
+ \@@_immediate_write_readlines_loop:
+ \tex_closein:D \g_@@_ior
+ \group_end:
}
-\cs_new_protected_nopar:Npn \mw_immediate_write_aux_readlines:
+\cs_new_protected_nopar:Npn \@@_immediate_write_readlines_loop:
{
- \mw_etex_readline:w \g_mw_read to \l_tmpa_tl
- \ior_if_eof:NF \g_mw_read
+ \etex_readline:D \g_@@_ior to \l_@@_internal_tl
+ \ior_if_eof:NF \g_@@_ior
{
\tl_gput_right:cx
- { g_mw_write_ \int_use:N \g_mw_stream_int _tl }
- { \mw_tex_immediate:w \mw_tex_write:w \g_mw_write { \l_tmpa_tl } }
- \mw_immediate_write_aux_readlines:
+ { g_@@_iow_ \int_use:N \g_@@_stream_int _tl }
+ {
+ \@@_tex_immediate:w \@@_tex_write:w \g_@@_iow
+ { \l_@@_internal_tl }
+ }
+ \@@_immediate_write_readlines_loop:
}
}
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
%
% \subsection{Non-immediate writing}
%
-% This is trickier, because the expansion of the text for
-% a non-immediate \cs{write} takes place immediately after
-% the page containing it is shipped out. We store each
-% non-immediate \cs{openout}, \cs{write}, or \cs{closeout}
-% without expansion in separate token lists
-% \cs{g_mw_late_write_}\meta{N}\texttt{_tl} to be used later,
-% and instead write |`(|\meta{N}|)| to a file (including the
-% strange delimiters). After each shipout, we can read the
-% file to see which output operations we need to perform,
-% and in what order.
-%
-% \begin{macro}[aux]{\mw_late_aux:nN}
-% Store the action to be done at shipout in a token list,
-% and non-immediately write the label \cs{g_mw_late_write_int}
-% of the output operation to the temporary file.
-% Here, |#1| holds an assignment similar to the lines above it,
-% and |#2| holds the relevant immediate action to be performed
-% after shipout.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_late_aux:nN #1 #2
+% This is trickier, because the expansion of the text for a
+% non-immediate \tn{write} takes place immediately after the page
+% containing it is shipped out. We store each non-immediate
+% \tn{openout}, \tn{write}, or \tn{closeout} without expansion in
+% separate token lists \cs{g_@@_late_write_\meta{stream}_tl} to be used
+% later, and instead write |`(|\meta{stream}|)| to a file (including the
+% strange delimiters). After each shipout, we can read the file to see
+% which output operations we need to perform, and in what order.
+%
+% ^^A todo: check "_nopar"?
+%
+% \subsubsection{Replacement for primitives}
+%
+% \begin{macro}[aux]{\@@_late:n}
+% Store the action to be done at shipout in a token list, and
+% non-immediately write the label \cs{g_@@_late_write_int} of the
+% output operation to the temporary file. Here, |#1| holds an
+% assignment similar to the lines above it, and |#2| holds the
+% relevant immediate action to be performed after shipout.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_late:n #1
{
- \int_gincr:N \g_mw_late_write_int
- \tl_const:cx { c_mw_late_write_ \int_use:N \g_mw_late_write_int _tl }
+ \int_gincr:N \g_@@_late_write_int
+ \tl_const:cx
{
- \int_gset:Nn \exp_not:N \g_mw_stream_int
- { \exp_not:V \g_mw_stream_int }
- #1
- \exp_not:N #2
+ c_@@_late_write_
+ \int_use:N \g_@@_late_write_int
+ _tl
+ }
+ {
+ \int_gset:Nn \exp_not:N \g_@@_stream_int
+ { \exp_not:V \g_@@_stream_int }
+ \exp_not:n {#1}
}
- \exp_args:NNx \mw_tex_write:w \g_mw_write
- { `( \int_use:N \g_mw_late_write_int ) }
+ \exp_args:NNx \@@_tex_write:w \g_@@_iow
+ { `( \int_use:N \g_@@_late_write_int ) }
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux]{\mw_openout:w}
-% \begin{macro}[aux]{\mw_openout_test:,\mw_openout_aux:}
-% \cs{openout} tests if the number to come is among reserved streams.
-% If it is, use the primitive, otherwise, parse a filename.
+% \begin{macro}[aux]{\@@_openout:w}
+% \begin{macro}[aux]{\@@_openout_test:n, \@@_openout_aux:n}
+% \tn{openout} tests if the number to come is among reserved streams.
+% If it is, use the primitive, otherwise, parse a file name.
% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_openout:w
- { \mw_scan_stop: \mw_parse_number:Nw \mw_openout_test: }
-\cs_new_protected_nopar:Npn \mw_openout_test:
- {
- \seq_if_in:NVTF \g_mw_reserved_writes_seq \g_mw_stream_int
- { \mw_tex_openout:w \g_mw_stream_int }
- { \mw_parse_equals_filename:Nw \mw_openout_aux: }
- }
-\cs_new_protected_nopar:Npn \mw_openout_aux:
+\cs_new_protected_nopar:Npn \@@_openout:w
+ { \s_@@ \primargs_get_number:N \@@_openout_test:n }
+\cs_new_protected:Npn \@@_openout_test:n #1
{
- \mw_late_aux:nN
- {
- \tl_gset:Nn \exp_not:N \g_mw_filename_tl
- { \exp_not:V \g_mw_filename_tl }
- }
- \mw_immediate_openout_aux:
+ \int_gset:Nn \g_@@_stream_int {#1}
+ \clist_if_in:NnTF \g_@@_reserved_iow_clist {#1}
+ { \@@_tex_openout:w \g_@@_stream_int }
+ { \@@_equals_file_name:N \@@_openout_aux:n }
}
+\cs_new_protected:Npn \@@_openout_aux:n #1
+ { \@@_late:n { \@@_immediate_openout_aux:n {#1} } }
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[aux]{\mw_write:w}
-% \begin{macro}[aux]{\mw_write_test:,\mw_write_aux:}
-% Same idea for \cs{write}, except that we parse a text.
+% \begin{macro}[aux]{\@@_write:w}
+% \begin{macro}[aux]{\@@_write_test:n, \@@_write_aux:n}
+% Same idea for \tn{write}, except that we parse a text.
% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_write:w
- { \mw_scan_stop: \mw_parse_number:Nw \mw_write_test: }
-\cs_new_protected_nopar:Npn \mw_write_test:
+\cs_new_protected_nopar:Npn \@@_write:w
+ { \s_@@ \primargs_get_number:N \@@_write_test:n }
+\cs_new_protected:Npn \@@_write_test:n #1
{
- \seq_if_in:NVTF \g_mw_reserved_writes_seq \g_mw_stream_int
- { \mw_tex_write:w \g_mw_stream_int }
- { \mw_parse_text:Nw \mw_write_aux: }
- }
-\cs_new_protected_nopar:Npn \mw_write_aux:
- {
- \mw_late_aux:nN
- {
- \tl_gset:Nn \exp_not:N \g_mw_text_tl
- { \exp_not:V \g_mw_text_tl }
- }
- \mw_immediate_write_aux:
+ \int_gset:Nn \g_@@_stream_int {#1}
+ \clist_if_in:NnTF \g_@@_reserved_iow_clist {#1}
+ { \@@_tex_write:w \g_@@_stream_int }
+ { \primargs_get_general_text:N \@@_write_aux:n }
}
+\cs_new_protected:Npn \@@_write_aux:n #1
+ { \@@_late:n { \@@_immediate_write_aux:n {#1} } }
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[aux]{\mw_closeout:w}
-% \begin{macro}[aux]{\mw_closeout_test:,\mw_closeout_aux:}
-% Same idea for \cs{closeout}, and we don't need to parse
+% \begin{macro}[aux]{\@@_closeout:w}
+% \begin{macro}[aux]{\@@_closeout_test:n, \@@_closeout_aux:}
+% Same idea for \tn{closeout}, and we don't need to parse
% anything else than the number.
% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_closeout:w
- { \mw_scan_stop: \mw_parse_number:Nw \mw_closeout_test: }
-\cs_new_protected_nopar:Npn \mw_closeout_test:
+\cs_new_protected_nopar:Npn \@@_closeout:w
+ { \s_@@ \primargs_get_number:N \@@_closeout_test:n }
+\cs_new_protected:Npn \@@_closeout_test:n #1
{
- \seq_if_in:NVTF \g_mw_reserved_writes_seq \g_mw_stream_int
- { \mw_tex_closeout:w \g_mw_stream_int }
- { \mw_closeout_aux: }
+ \int_gset:Nn \g_@@_stream_int {#1}
+ \clist_if_in:NnTF \g_@@_reserved_iow_clist {#1}
+ { \@@_tex_closeout:w \g_@@_stream_int }
+ { \@@_closeout_aux: }
}
-\cs_new_protected_nopar:Npn \mw_closeout_aux:
- { \mw_late_aux:nN { } \mw_immediate_closeout_aux: }
+\cs_new_protected_nopar:Npn \@@_closeout_aux:
+ { \@@_late:n { \@@_immediate_closeout_aux: } }
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[aux]{\mw_before_shipout:}
-% Immediately before the shipout, we must open the writing stream
-% \cs{g_mw_write}. Each delayed output operation has been replaced
-% by \cs{write} \cs{g_mw_write} |{`(|\meta{operation number}|}|.
-% The delimiters we chose to put around numbers must be at least
-% two distinct characters on the left (then \cs{tex_newlinechar:D}
-% cannot be equal to the delimiter), and at least one non-digit
-% character on the right.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_before_shipout:
- {
- \mw_tex_immediate:w \mw_tex_openout:w \g_mw_write
- \c_mw_tmp_file_tl \scan_stop:
- }
-% \end{macrocode}
-% \end{macro}
+% \subsubsection{Shipout business}
%
-% \begin{macro}[aux]{\mw_after_shipout:}
-% After all the \cs{write}s are performed, we read the file,
-% and grab the relevant pieces in a seq.
-% \begin{macrocode}
-\seq_new:N \g_mw_operations_seq
-\cs_new_protected_nopar:Npn \mw_after_shipout:
- {
- \mw_tex_immediate:w \mw_tex_closeout:w \g_mw_write
+% \begin{macro}[aux]{\@@_before_shipout:}
+% Immediately before the shipout, we must open the writing stream
+% \cs{g_@@_iow}. Each delayed output operation has been replaced by
+% \tn{write} \cs{g_@@_iow} |{`(|\meta{operation number}|}|. The
+% delimiters we chose to put around numbers must be at least two
+% distinct characters on the left (then \cs{tex_newlinechar:D} cannot
+% be equal to the delimiter), and at least one non-digit character on
+% the right.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_before_shipout:
+ {
+ \@@_tex_immediate:w \@@_tex_openout:w \g_@@_iow
+ \g_@@_tmp_file_tl \scan_stop:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%% ^^A todo: \shipout{\immediate\write4{}} => bug.
+% \begin{macro}[aux]{\@@_after_shipout:}
+% \begin{macro}[aux, rEXP]{\@@_after_shipout_loop:ww}
+% Immediately after all the \tn{write}s are performed, close the file,
+% then read the file with \tn{endlinechar} set to
+% \tn{newlinechar}\footnote{Note that the \tn{newlinechar} used by
+% \tn{write}s at \tn{shipout} time are those in effect when the page
+% is shipped out, \emph{i.e.}, just after the closing brace of the
+% \tn{shipout} construction, which is exactly where we have added
+% this hook.} to get exactly the original characters that have been
+% written, possibly with extra characters between |`(|\ldots{}|)|
+% groups. The file is then read with all the appropriate category
+% codes set up (no other character can appear in the file). The
+% looping auxiliary \cs{@@_after_shipout_loop:ww} extract the
+% \meta{operation} numbers from the file, and makes a token list out
+% of those. This token list is then used in a mapping function to
+% perform the appropriate \tn{write} operations. Note that those
+% operations may reuse the file, so we have to fully parse the file
+% before moving on.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_after_shipout:
+ {
+ \@@_tex_immediate:w \@@_tex_closeout:w \g_@@_iow
\group_begin:
\int_set_eq:NN \tex_endlinechar:D \tex_newlinechar:D
+ \char_set_catcode_other:n { \tex_endlinechar:D }
\tl_map_inline:nn { `(0123456789) }
{ \char_set_catcode_other:n {`##1} }
\etex_everyeof:D { `() \exp_not:N }
- \tl_gset:Nx \g_mw_operations_seq
- { \if_false: } \fi:
- \exp_after:wN \mw_after_shipout_loop:ww
- \tex_input:D \c_mw_tmp_file_tl \scan_stop:
+ \exp_args:NNx
\group_end:
- \seq_map_inline:Nn \g_mw_operations_seq
+ \tl_map_inline:nn
{
- \tl_use:c
- { c_mw_late_write_ ##1 _tl }
+ \exp_after:wN \@@_after_shipout_loop:ww
+ \tex_input:D \g_@@_tmp_file_tl \c_space_tl %^^A bug?
}
+ { \tl_use:c { c_@@_late_write_ ##1 _tl } }
}
-\cs_new:Npn \mw_after_shipout_loop:ww #1 `( #2 )
+\cs_new:Npn \@@_after_shipout_loop:ww #1 `( #2 )
{
- \tl_if_empty:nTF {#2}
- { \if_false: { \fi: } }
+ \tl_if_empty:nF {#2}
{
- \exp_not:N \seq_item:n {#2}
- \mw_after_shipout_loop:ww
+ {#2}
+ \@@_after_shipout_loop:ww
}
}
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
% \begin{macro}[aux]{\shipout}
-% \begin{macro}[aux]{\mw_shipout:w}
+% \begin{macro}[aux]{\@@_shipout:w}
+% \begin{variable}{\g_@@_group_level_int, \g_@@_shipout_box}
% If \pkg{atbegshi} is available, patch it by adding
-% \cs{mw_after_shipout:} at the right place. Otherwise,
-% redefine \cs{shipout} to add a hook.
+% \cs{@@_before_shipout:} and \cs{@@_after_shipout:} at the right
+% place: the two transformations are needed to cover several versions
+% of the package. Otherwise, redefine \tn{shipout} to add a hook (see
+% Heiko's \pkg{atbegshi} for details).
% \begin{macrocode}
\IfFileExists{atbegshi.sty}
{
@@ -719,120 +736,142 @@
\tl_replace_once:Nnn \AtBegShi@Output
{ \AtBegShi@OrgShipout \box \AtBeginShipoutBox }
{
- \mw_before_shipout:
+ \@@_before_shipout:
\AtBegShi@OrgShipout \box \AtBeginShipoutBox
- \mw_after_shipout:
+ \@@_after_shipout:
}
\tl_replace_once:Nnn \AtBegShi@Output
{ \AtBeginShipoutOriginalShipout \box \AtBeginShipoutBox }
{
- \mw_before_shipout:
+ \@@_before_shipout:
\AtBeginShipoutOriginalShipout \box \AtBeginShipoutBox
- \mw_after_shipout:
+ \@@_after_shipout:
}
}
{
- \cs_new_protected_nopar:Npn \mw_shipout:w
+ \int_new:N \g_@@_group_level_int
+ \box_new:N \g_@@_shipout_box
+ \cs_new_protected_nopar:Npn \@@_shipout:w
{
- \int_gset_eq:NN \g_mw_tmpa_int \etex_currentgrouplevel:D
- \tex_afterassignment:D \mw_shipout_aux:
- \tex_global:D \tex_setbox:D \g_mw_box
+ \int_gset_eq:NN \g_@@_group_level_int \etex_currentgrouplevel:D
+ \tex_afterassignment:D \@@_shipout_i:
+ \tex_global:D \tex_setbox:D \g_@@_shipout_box
}
- \cs_new_protected_nopar:Npn \mw_shipout_aux:
+ \cs_new_protected_nopar:Npn \@@_shipout_i:
{
- \int_compare:nNnTF { \g_mw_tmpa_int }
+ \int_compare:nNnTF { \g_@@_group_level_int }
= { \etex_currentgrouplevel:D }
- { \mw_shipout_aux_ii: }
- { \tex_aftergroup:D \mw_shipout_aux_ii: }
+ { \@@_shipout_ii: }
+ { \tex_aftergroup:D \@@_shipout_ii: }
}
- \cs_new_protected_nopar:Npn \mw_shipout_aux_ii:
+ \cs_new_protected_nopar:Npn \@@_shipout_ii:
{
- \mw_before_shipout:
- \mw_tex_shipout:w \tex_box:D \g_mw_box
- \mw_after_shipout:
+ \@@_before_shipout:
+ \@@_tex_shipout:w \tex_box:D \g_@@_shipout_box
+ \@@_after_shipout:
}
- \cs_gset_eq:NN \shipout \mw_shipout:w
+ \AtBeginDocument { \cs_gset_eq:NN \shipout \@@_shipout:w }
}
% \end{macrocode}
+% \end{variable}
% \end{macro}
% \end{macro}
%
% \subsection{Hook at the very end}
%
-% \begin{macro}[aux]{\mw_close_all:}
+% \begin{variable}{\g_@@_at_end_int}
+% At the end of the run, we try very hard to put some material at the
+% |\@@end|. This integer controls how many times to call
+% \cs{@@_close_all_at_end:w}, to avoid infinite loops in case two
+% packages compete for that last place.
+% \begin{macrocode}
+\int_new:N \g_@@_at_end_int
+\int_gset:Nn \g_@@_at_end_int { 10 }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[aux]{\@@_close_all:}
% At the end of the document, close all the files.
% \begin{macrocode}
-\cs_new_protected_nopar:Npn \mw_close_all:
+\cs_new_protected_nopar:Npn \@@_close_all:
{
- \prop_map_inline:Nn \g_mw_writes_prop
- {
- \mw_tex_immediate:w \mw_tex_openout:w \g_mw_write ##2 \scan_stop:
- \group_begin:
- \int_set_eq:NN \tex_newlinechar:D \c_minus_one
- \tl_use:c { g_mw_write_ ##1 _tl }
- \tl_gclear:c { g_mw_write_ ##1 _tl }
- \group_end:
- \mw_tex_immediate:w \mw_tex_closeout:w \g_mw_write
- }
- \prop_gclear:N \g_mw_writes_prop
+ \prop_map_function:NN \g_@@_iow_prop
+ \@@_immediate_write_and_close:nn
+ \prop_gclear:N \g_@@_iow_prop
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux]{\mw_put_at_end:Nw}
+% \begin{macro}[aux]{\@@_close_all_at_end:w}
% This pushes its first argument to the very end of the \LaTeX{} run,
-% recursively, just in case some other code adds things there.
-% If \pkg{atveryend} is available, we use it instead.
-% \begin{macrocode}
- % \IfFileExists{atveryend.sty} { \use_i:nn } { \use_ii:nn }
- % {
- % \RequirePackage {atveryend} [2011/06/29]
- % \AtVeryVeryEnd { \mw_close_all: }
- % }
- % {
- \cs_new_protected:Npn \mw_put_at_end:Nw #1 #2 \@@end
+% recursively (at most $10$ times, initial value of
+% \cs{g_@@_at_end_int}), just in case some other code adds things
+% there.
+% \begin{macrocode}
+\cs_set:Npn \@@_tmp:w #1
+ {
+ \cs_new_protected:Npn \@@_close_all_at_end:w ##1 #1
{
- \tl_if_empty:nTF {#2}
- { #1 \@@end }
- { #2 \mw_put_at_end:Nw #1 \@@end }
+ \int_gdecr:N \g_@@_at_end_int
+ \int_compare:nNnTF \g_@@_at_end_int > \c_zero
+ {
+ \tl_if_empty:nTF {##1}
+ { ##1 \@@_close_all: }
+ { ##1 \@@_close_all_at_end:w }
+ }
+ { \@@_close_all: ##1 }
+ #1
}
- \AtEndDocument { \mw_put_at_end:Nw \mw_close_all: }
- % }
+ }
+\exp_args:Nc \@@_tmp:w { @ @ end }
+\AtEndDocument { \@@_close_all_at_end:w }
% \end{macrocode}
% \end{macro}
%
% \subsection{Modified \cs{newwrite}}
%
+% \begin{variable}{\g_@@_alloc_int}
+% The counter that \LaTeXe{} uses to allocate \tn{write} registers.
+% \begin{macrocode}
+\tex_countdef:D \g_@@_alloc_int 17 \scan_stop:
+% \end{macrocode}
+% \end{variable}
+%
% \begin{macro}[aux]{\newwrite}
% We need to allow \cs{newwrite} to allocate more than $16$ writes,
% but beware that $18$ is reserved, and that packages might expect
-% $16$ or $17$ to write to the terminal. So instead skip until $20$.
+% $16$ or $17$ to write to the terminal. So instead skip until $20$,
+% to be on the safe side.
+% % ^^A todo: redefine the LaTeX3 things too?
% \begin{macrocode}
-\countdef \mw_write_int 17 \scan_stop:
-\cs_new:Npn \mw_newwrite:N #1
+\cs_new:Npn \@@_newwrite:N #1
{
- \if_num:w \mw_write_int = \c_sixteen
- \int_gset:Nn \mw_write_int { 20 }
+ \int_gincr:N \g_@@_alloc_int
+ \if_num:w \g_@@_alloc_int = \c_sixteen
+ \int_gset:Nn \g_@@_alloc_int { 20 }
\fi:
- \int_set_eq:NN \allocationnumber \mw_write_int
- \int_gincr:N \mw_write_int
+ \int_set_eq:NN \allocationnumber \g_@@_alloc_int
\cs_undefine:N #1
\int_const:Nn #1 { \allocationnumber }
- \wlog {\string #1=\string \write \the \allocationnumber }
+ \wlog
+ {
+ \token_to_str:N #1
+ = \token_to_str:N \write \int_use:N \allocationnumber
+ }
}
% \end{macrocode}
% \end{macro}
%
% \subsection{Redefining the ``normal'' control sequences}
%
-% \begin{macro}[aux]{\immediate,\openout,\write,\closeout,\newwrite}
-% \cs{shipout} has been redefined earlier.
+% \begin{macro}[aux]{\immediate, \openout, \write, \closeout, \newwrite}
+% \tn{shipout} has been redefined earlier.
% \begin{macrocode}
-\cs_gset_eq:NN \immediate \mw_immediate:w
-\cs_gset_eq:NN \openout \mw_openout:w
-\cs_gset_eq:NN \write \mw_write:w
-\cs_gset_eq:NN \closeout \mw_closeout:w
-\cs_gset_eq:NN \newwrite \mw_newwrite:N
+\cs_gset_eq:NN \immediate \@@_immediate:w
+\cs_gset_eq:NN \openout \@@_openout:w
+\cs_gset_eq:NN \write \@@_write:w
+\cs_gset_eq:NN \closeout \@@_closeout:w
+\cs_gset_eq:NN \newwrite \@@_newwrite:N
% \end{macrocode}
% \end{macro}
%