% \iffalse meta-comment
%
%% File: morewrites.dtx Copyright (C) 2011-2024 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
%% 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 work has the LPPL maintenance status 'maintained'
%% and the current maintainer is Bruno Le Floch.
%% -----------------------------------------------------------------------
%
%<*driver>
\RequirePackage{morewrites}
\ExplSyntaxOn
\prg_replicate:nn { 300 } { \newwrite \foo }
\ExplSyntaxOff
\documentclass[full]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{The \textsf{morewrites} package: \\
%   Always room for a new \tn{write}}
% \author{Bruno Le Floch}
% \date{2024/02/02}
%
% \maketitle
% \tableofcontents
%
% \begin{documentation}
%
% \section{\pkg{morewrites} documentation}
%
% This \LaTeX{} package is a solution for the error
% \enquote{no room for a new \tn{write}},
% which occurs when a document reserves too many streams to write data
% to various auxiliary files.
% It is in principle possible to rewrite other 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).
%
% Simply add the line |\usepackage{morewrites}| near the beginning of
% your \LaTeX{} file's preamble: the \enquote{no room for a new
% \tn{write}} error should vanish.  If it does not, please
% contact me so that I can correct the problem.  This can be done by
% posting a question on the \url{tex.stackexchange.com} question and
% answers website, logging an issue on GitHub
% (\url{https://github.com/blefloch/latex-morewrites}), or emailing me a
% minimal file showing the problem.
%
% Notes.
% \begin{itemize}
% \item This package loads the \pkg{expl3} package, hence the
%   \pkg{l3kernel} bundle needs to be up to date.
% \item This package uses an auxiliary file, \meta{job~name}|.mw|,
%   which can safely be deleted.  The package only overwrites this
%   auxiliary file if it is empty, and otherwise uses a modified
%   file name, obtained by adding an integer to the name (previously
%   it was obtained by appending additional copies of |.mw| to the
%   name).  Such files can be safely deleted.  Be careful though to
%   not delete a Maple worksheet by accident when cleaning up your
%   files.
% \item \LuaTeX{} allows $128$ \tn{write} streams, so this package does
%   nothing (with a warning) when used with \LuaTeX{}.
% \end{itemize}
%
% \subsection{Commands defined or altered by \pkg{morewrites}}
%
% \begin{function}[added = 2014-07-26]{\morewritessetup}
%   \begin{syntax}
%     \cs{morewritessetup} \Arg{key--value list}
%   \end{syntax}
%   Sets the options described by the \meta{key--value list}.
% \end{function}
%
% \begin{function}[added = 2017-04-10]{allocate}
%   \begin{syntax}
%     \cs{morewritessetup} |{| |allocate| |=| \meta{integer} |}|
%   \end{syntax}
%   Sets to (at least) \meta{integer} the number of \tn{write} streams
%   allocated to the inner workings of \pkg{morewrites}.  By default
%   this is zero but increasing this value to 10 (or so) may speed up
%   \pkg{morewrites}.
% \end{function}
%
% \begin{function}[added = 2014-07-26, updated = 2024-01-05]{file}
%   \begin{syntax}
%     \cs{morewritessetup} |{| |file| |=| \meta{file name} |}|
%   \end{syntax}
%   Sets (globally) the name of the file which will be used by internal
%   processes of \pkg{morewrites}.  The file name is \tn{jobname}|.mw|
%   by default (technically, \cs{c_sys_jobname_str}|.mw|).  Contrarily
%   to earlier versions of \pkg{morewrites} non-empty files will not be
%   overwritten; this design choice may lead to unwanted |.mw| files
%   remaining.
% \end{function}
%
% \begin{function}[added = 2024-01-05]{verbose}
%   \begin{syntax}
%     \cs{morewritessetup} |{| |verbose| |}|
%   \end{syntax}
%   This boolean option (\texttt{false} by default) makes the package
%   write to the terminal all of the operations that it performs.  This
%   can render \pkg{morewrites} useful for debugging some file-writing
%   operations.
% \end{function}
%
% \begin{function}[updated = 2015-08-01]{\newwrite}
%   This macro is redefined by \pkg{morewrites}.  Since \pkg{morewrites}
%   allows more than~$16$ write streams, it removes the corresponding
%   restrictions in \tn{newwrite}.
%   \begin{texnote}
%     The revised \tn{newwrite} allocate stream numbers starting at
%     $129$.  This might break some code that expects stream numbers to
%     be less than $16$.
%   \end{texnote}
% \end{function}
%
% \begin{function}[updated = 2015-08-01]{\immediate}
%   This primitive is altered by \pkg{morewrites}, to detect a following
%   \tn{write} or \tn{openout} or \tn{closeout} and perform the
%   appropriate action.
% \end{function}
%
% \begin{function}[updated = 2017-04-20]{\openout, \write, \closeout}
%   These three primitives are altered by \pkg{morewrites} so that they
%   accept stream numbers outside the normal range $[0,15]$ and
%   open/write/close files as appropriate.
%   \begin{texnote}
%     System calls using \tn{write}|18| are detected and forwarded to the engine.
%   \end{texnote}
% \end{function}
%
% \begin{function}{\shipout}
%   This primitive is altered by \pkg{morewrites} to ensure that delayed
%   \tn{openout}, \tn{write} and \tn{closeout} commands are performed at
%   \tn{shipout} time, and in the correct order.
% \end{function}
%
% \subsection{Known deficiencies and open questions}
%
% See the bug tracker \url{https://github.com/blefloch/latex-morewrites/issues/}
% for a list of issues with \pkg{morewrites}.
%
% The package code is not good \pkg{expl3} code.  \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.}  It uses
% \cs[no-index]{\ldots{}:D} primitives directly (the |:D| stands for
% \enquote{do not use}).  This is unavoidable in order to hook into the
% primitives \tn{immediate}, \tn{write}, \emph{etc.\@} and to keep a
% very strong control on what every command does.
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{morewrites} implementation}
%
%<*package>
%    \begin{macrocode}
\RequirePackage {primargs} [2024/01/05]
\ProvidesExplPackage
  {morewrites} {2024/02/02} {} {Always room for a new write}
%    \end{macrocode}
%
% Quit early under \LuaTeX{}.
%    \begin{macrocode}
\sys_if_engine_luatex:T
  {
    \cs_new_protected:Npn \morewritessetup #1 { }
    \msg_new:nnn { morewrites } { luatex }
      { The~morewrites~package~is~unnecessary~in~LuaTeX. }
    \msg_warning:nn { morewrites } { luatex }
    \tex_endinput:D
  }%
%    \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.  This requires patching the primitives \tn{immediate},
% \tn{openout}, \tn{write}, \tn{closeout}, and \tn{shipout}, and the
% macro \tn{newwrite} present in plain \TeX{} and \LaTeXe{}.
%
% Note that doing the same for \tn{read} streams is impossible due to
% the \tn{ifeof} primitive: that primitive cannot be replaced by a macro
% without breaking nesting of conditionals.
%
% The \pkg{morewrites} package should be loaded as early as possible, so
% that any package loaded later uses the redefined macros instead of the
% primitives.  However, the format (plain \TeX{} or \LaTeXe{}) and the
% \pkg{expl3} programming language are always loaded before
% \pkg{morewrites}, and their interaction must be carefully monitored.
%
% Henceforth, ``\TeX{} stream'' will refer to stream numbers in the
% range $[0,15]$ provided to \TeX{}'s write primitives, while
% ``user stream'' will denote stream numbers in $[0,15]\cup[129,\infty)$
% manipulated by the redefined \tn{openout}, \tn{write}, \tn{closeout},
% and \tn{newwrite}.  A user stream in $[0,15]$ (reserved by \LaTeXe{}
% or allocated by \pkg{expl3}) is mapped to the same \TeX{} stream
% number, while a user stream in $[129,\infty)$ is mapped to a \TeX{}
% stream according to the property list (with integer keys and values)
% \cs{l_@@_write_prop}.  Stream numbers $16$,
% $17$ and $18$ are unused because \tn{write}16 is often used to write
% to the terminal, and \tn{write}18 sends its argument to a shell.
% The stream number $128$ is also often used like $16$ to avoid
% distinguishing \LuaTeX{}.  Rather than special-casing it we skip
% directly to larger stream numbers.
%
% The primitives \tn{openout}, \tn{write}, and \tn{closeout} expect to
% be followed by an \meta{integer}, normally in the range $[0,15]$, then
% some further arguments.
% \begin{quote}
%   \tn{openout}    \meta{integer} \meta{equals} \meta{file name}        \\
%   \tn{write}      \meta{integer} \meta{filler} \meta{general text}     \\
%   \tn{closeout}   \meta{integer}
% \end{quote}
% All of the primitives above perform full expansion of all tokens when
% looking for their operands.
% \begin{itemize}
% \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 whose category code is $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}
%
% The \pkg{morewrites} package redefines these three control sequences
% to expect a user stream number rather than a \TeX{} stream number as
% the \meta{integer}, then map such a user stream to a \TeX{} stream to
% call the primitive with the appropriate argument.  The primitive
% \tn{immediate} must also be redefined to detect \tn{openout},
% \tn{write}, and \tn{closeout} and make them immediate, while still
% working with other primitives that can be made immediate.  Finally,
% \tn{newwrite} must be patched to allocate stream numbers beyond $15$.
%
% A few comments on the behaviour of primitives concerning the
% \meta{integer} (\TeX{} stream).  The \tn{openout} primitive trigger
% errors if the \meta{integer} is not in $[0,15]$.  The primitive
% \tn{write} outputs to the log if the \meta{integer} is negative, and
% to the terminal if the \TeX{} stream is closed or greater than $15$,
% with the exception of \tn{write}|18| which runs code in a shell.  The
% \tn{closeout} primitive triggers an error if the \meta{integer} is not
% in $[0,15]$ and silently do nothing if the \TeX{} stream is not open,
% with the exception of \tn{closeout}|18| which causes a segfault at
% least in some versions.
%
% By default, \tn{openout}, \tn{write} and \tn{closeout} 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 these three primitives 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, for instance
% \tn{box}\meta{integer} or \tn{hbox}\Arg{material to typeset}.
%
% Finally, the \tn{newwrite} macro expects one token as its argument,
% and defines this token (with \tn{chardef}) to be an integer
% corresponding to the first available (\TeX{}) write stream.  This must
% be extended to allocate higher (user) streams.
%
% \subsection{Preliminaries}
%
% \subsubsection{Copying some commands}
%
% \begin{macro}
%   {
%     \@@_tex_immediate:w ,
%     \@@_tex_openout:w   ,
%     \@@_tex_write:w     ,
%     \@@_tex_closeout:w  ,
%   }
%   Aliases for the write-related primitives, to avoid
%   having |:D| throughout the code.
%    \begin{macrocode}
\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}{\@@_tex_newwrite:N}
%   Copy \tn{newwrite} but making sure that it is
%   not \tn{outer}.  This copy will not be affected by redefinitions
%   of \tn{newwrite} later on.
%    \begin{macrocode}
\exp_args:NNf \cs_new_protected:Npn \@@_tex_newwrite:N
  { \exp_args:NNc \exp_after:wN \exp_stop_f: { newwrite } }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Variants}
%
%   We need these variants.
%    \begin{macrocode}
\cs_generate_variant:Nn \prop_gpop:NnNT { NV }
\cs_generate_variant:Nn \prop_gput:Nnn { NVx }
\cs_generate_variant:Nn \tl_gput_right:Nn { Nv }
%    \end{macrocode}
%
% \subsubsection{Variables}
%
% \begin{variable}{\l_@@_internal_tl, \l_@@_internal_seq}
%   Used for temporary scratch purposes.
%    \begin{macrocode}
\tl_new:N \l_@@_internal_tl
\seq_new:N \l_@@_internal_seq
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\@@_tmp:w}
%   Used for temporary definitions.
%    \begin{macrocode}
\cs_new_eq:NN \@@_tmp:w ?
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_verbose_bool}
%   When this boolean is set true, \pkg{morewrites} will print to the terminal all of the operations that it does.
%    \begin{macrocode}
\bool_new:N \l_@@_verbose_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_later_int}
%   The integer \cs{g_@@_later_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} |}|
%     \tn{shipout} \tn{copy} \cs{l_my_box}
%     \tn{shipout} \tn{copy} \cs{l_my_box}
%   \end{quote}
%   will print \meta{text} to the terminal twice.
%    \begin{macrocode}
\int_new:N \g_@@_later_int
%    \end{macrocode}
% \end{variable}
%
% ^^A todo: populate \g_@@_write_seq because we don't use \newwrite; this should be done in \morewritessetup
% \begin{variable}{\g_@@_write_seq}
%   Keep track of \TeX{} stream numbers managed by \pkg{morewrites} that
%   are currently not in use as user streams.
%    \begin{macrocode}
\seq_new:N \g_@@_write_seq
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_write_prop}
%   Map user streams to \TeX{} streams.
%    \begin{macrocode}
\prop_new:N \g_@@_write_prop
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_write_file_prop}
%   Map user streams with no associated \TeX{} streams to file names.
%    \begin{macrocode}
\prop_new:N \g_@@_write_file_prop
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_code_tl}
%   Stores the code to run after finding a user stream, in
%   \cs{@@_get_user:n}.
%    \begin{macrocode}
\tl_new:N \l_@@_code_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_user_int, \l_@@_tstr_tl}
%   The user stream number following redefined primitives is stored in
%   \cs{l_@@_user_int} (see \cs{@@_get_user:N}).  The corresponding
%   \TeX{} stream number is eventually stored in \cs{l_@@_tstr_tl} (a
%   token list).
%    \begin{macrocode}
\int_new:N \l_@@_user_int
\tl_new:N \l_@@_tstr_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_tstr_token}
%   This token is given as an argument to \cs{@@_tex_newwrite:N}.
%    \begin{macrocode}
\cs_new_eq:NN \l_@@_tstr_token ?
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\s_@@}
%   A recognizable version of \cs{scan_stop:}.  This is inspired
%   by\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
%   \cs{scan_new:N} is not used directly, since it is has been made
%   available in \LaTeX3 too recently.
%    \begin{macrocode}
\cs_new_eq:NN \s_@@ \scan_stop:
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\g_@@_iow, \g_@@_ior}
%   The expansion that \tn{write} performs is impossible to emulate (in \XeTeX{} at least) 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}
\newwrite \g_@@_iow
\newread \g_@@_ior
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_tmp_file_tl, \g_@@_tmp_file_bool}
%   Temporary file used to do the correct expansion for each \tn{write}.
%   Boolean indicating whether we have already checked that the file can
%   be used by \pkg{morewrites}: before using a file, the
%   \pkg{morewrites} package now checks it is empty, so as to avoid
%   clobbering user data.
%    \begin{macrocode}
\tl_new:N \g_@@_tmp_file_tl
\bool_new:N \g_@@_tmp_file_bool
\bool_gset_false:N \g_@@_tmp_file_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_group_level_int}
%   The group level when \tn{shipout} is called: this is used to
%   distinguish between explicit boxes and box registers.
%    \begin{macrocode}
\int_new:N \g_@@_group_level_int
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_shipout_box}
%   The page to be shipped out.
%    \begin{macrocode}
\box_new:N \g_@@_shipout_box
%    \end{macrocode}
% \end{variable}
%
% \subsubsection{Verbosity}
%
% \begin{macro}{\@@_verbose:n}
%   Messages to put in the terminal if the \texttt{verbose} option is
%   selected.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_verbose:n #1
  { \bool_if:NT \l_@@_verbose_bool { \iow_term:e { morewrites:~#1 } } }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Helpers for auxiliary file}
%
% \begin{macro}{\@@_set_file:n}
%   Sets \cs{g_@@_tmp_file_tl} to the given value (initially
%   \cs{c_sys_jobname_str}|.mw|).  We do not yet expand, delaying that
%   to the time where we start opening/closing the file, in case |#1|
%   contains something that has not yet been fixed.  Mark that the file
%   has not been checked.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_file:n #1
  {
    \bool_gset_false:N \g_@@_tmp_file_bool
    \tl_gset:Nn \g_@@_tmp_file_tl {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_empty_file:n}
%   Empties a file by opening it and closing it
%   right away.  This is used when performing \tn{immediate}
%   \tn{openout}.  It is also used to ensure the file used by
%   \pkg{morewrites} is left empty.  We do this every time the auxiliary
%   file is used, in case that run ends with an error mid-document.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_empty_file:n #1
  {
    \@@_tex_immediate:w \@@_tex_openout:w
      \g_@@_iow = {#1} \scan_stop:
    \@@_tex_immediate:w \@@_tex_closeout:w
      \g_@@_iow
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[TF]{\@@_if_file_trivial:n}
%   True if the file does not exist, or if it is empty.
%   Only the \texttt{TF} variant is defined.  We set
%   \cs{@@_tmp:w} to \cs{prg_return_true:} or \cs{prg_return_false:}
%   within the group and use it after cleaning up.  The first
%   \texttt{eof} test is \texttt{true} if the file does not exist.
%   Then we read one line, the second \texttt{eof} test is
%   \texttt{true} if the file was empty (it is \texttt{false} if
%   the file contained anything, even a single space).
%    \begin{macrocode}
\prg_new_conditional:Npnn \@@_if_file_trivial:n #1 { TF }
  {
    \group_begin:
      \tex_openin:D \g_@@_ior = {#1}
      \if_eof:w \g_@@_ior
        \cs_gset_eq:NN \@@_tmp:w \prg_return_true:
      \else:
        \int_set:Nn \tex_endlinechar:D { -1 }
        \tex_readline:D \g_@@_ior to \l_@@_internal_tl
        \if_eof:w \g_@@_ior
          \cs_gset_eq:NN \@@_tmp:w \prg_return_true:
        \else:
          \cs_gset_eq:NN \@@_tmp:w \prg_return_false:
        \fi:
      \fi:
      \tex_closein:D \g_@@_ior
    \group_end:
    \@@_tmp:w
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_chk_file:}
%   Expand the file name in \cs{g_@@_tmp_file_tl} once and for all.
%   Check that the file does not exist or is
%   blank.  If not, try another file name obtained as follows: if it
%   ends with |.mw| pick up any number that lies just before |.mw| and
%   increment it, and otherwise just add |.mw| at the end of the file.
%   This avoids clobbering files that the user would not want to lose.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_chk_file:
  {
    \tl_gset:Ne \g_@@_tmp_file_tl
      { \tl_to_str:e { \g_@@_tmp_file_tl } }
    \@@_if_file_trivial:nTF { \g_@@_tmp_file_tl }
      { \bool_gset_true:N \g_@@_tmp_file_bool }
      {
        \@@_chk_file_aux:
        \msg_warning:nnxx { morewrites } { file-exists }
          { \g_@@_tmp_file_tl } { \l_@@_internal_tl }
        \tl_gset_eq:NN \g_@@_tmp_file_tl \l_@@_internal_tl
        \@@_chk_file:
      }
  }
\cs_new_protected:Npn \@@_chk_file_aux:
  {
    \regex_extract_once:nVNTF
      { \A (\D*) (\d*) .mw \Z } \g_@@_tmp_file_tl \l_@@_internal_seq
      {
        \tl_set:Ne \l_@@_internal_tl
          {
            \seq_item:Nn \l_@@_internal_seq { 2 }
            \int_eval:n { \seq_item:Nn \l_@@_internal_seq { 3 } + 1 }
            .mw
          }
      }
      { \tl_set:Ne \l_@@_internal_tl { \g_@@_tmp_file_tl .mw } }
  }
\msg_new:nnnn { morewrites } { file-exists }
  { File~'#1'~exists,~using~'#2'~instead. }
  {
    The~file~`#1'~exists~and~was~not~created~by~this~version~of~the~
    `morewrites'~package.~Please~move~or~delete~that~file,~or~provide~
    another~file~name~by~adding
    \\ \\
    \iow_indent:n { \iow_char:N\\morewritessetup~{~file~=~other-name~} }
    \\ \\
    to~your~source~file.~In~the~meantime,~the~file~`#2'~will~be~used.
  }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Parsing and other helpers}
%
% \begin{macro}{\@@_equals_file: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:Npn \@@_equals_file:N #1
  {
    \group_begin:
      \tex_aftergroup:D \primargs_get_input_file_name:N
      \tex_aftergroup:D #1
      \primargs_remove_equals:N \group_end:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_get_user:n}
%   \pkg{primargs} commands only take \texttt{N}-type arguments, but we
%   often need to find an integer, save it in \cs{l_@@_user_int}, and
%   run some code |#1|.  This is analogous to \cs{primargs_get_number:N}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_get_user:n #1
  {
    \tl_set:Nn \l_@@_code_tl {#1}
    \tex_afterassignment:D \l_@@_code_tl
    \l_@@_user_int =
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_user_to_tstr:NTF}
%   The goal is to go from a user stream \cs{l_@@_user_int} to a \TeX{}
%   stream \cs{l_@@_tstr_tl} (it defaults to the user stream).  Streams
%   less than $129$ are not managed by \pkg{morewrites}: actual \TeX{}
%   streams in $[0,15]$; negative for writing to \texttt{log}; $16$,
%   $17$, $128$ for writing to terminal; $18$ for shell escape.  Larger stream
%   numbers are looked up in the property list |#1|, namely
%   \cs{g_@@_write_prop}.  If present, use the corresponding value as
%   the \TeX{} stream, otherwise run the \texttt{false} branch.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_user_to_tstr:NTF #1
  {
    \tl_set:NV \l_@@_tstr_tl \l_@@_user_int
    \int_compare:nNnTF { \l_@@_user_int } < { 129 }
      { \use_i:nn }
      { \prop_get:NVNTF #1 \l_@@_user_int \l_@@_tstr_tl }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_@@_collect_next_int}
% \begin{macro}
%   {
%     \@@_collect:x, \@@_collect_aux:Nn,
%     \@@_collect_aux:cf, \@@_collect_gput_right:N, \@@_collect_gput_right:c
%   }
%   When encountering very large \tn{write} statements we may need to
%   collect many lines.  This can easily become an $O(n^2)$ task, and
%   here we make sure that it remains around $O(n\log n)$, with a large
%   constant unfortunately.  Each of the token lists
%   \cs[no-index]{l_@@_$k$_tl} is empty or contains $2^k$ lines.  As
%   lines accumulate, they move to token lists with larger values
%   of~$k$, and eventually all are combined.  The integer
%   \cs{l_@@_collect_next_int} is (one plus) the maximal $k$ among
%   non-empty token lists.
%    \begin{macrocode}
\int_new:N \l_@@_collect_next_int
\cs_new_protected:Npn \@@_collect:x #1
  {
    \tl_set:Nx \l_@@_internal_tl {#1}
    \@@_collect_aux:cf { l_@@_0_tl } { 1 }
  }
\cs_new_protected:Npn \@@_collect_aux:Nn #1#2
  {
    \int_compare:nNnT {#2} > \l_@@_collect_next_int
      {
        \tl_clear_new:N #1
        \int_set:Nn \l_@@_collect_next_int {#2}
      }
    \tl_if_empty:NTF #1
      { \tl_set_eq:NN #1 \l_@@_internal_tl }
      {
        \tl_put_left:No \l_@@_internal_tl {#1}
        \tl_clear:N #1
        \@@_collect_aux:cf { l_@@_#2_tl }
          { \int_eval:n { #2 + 1 } }
      }
  }
\cs_generate_variant:Nn \@@_collect_aux:Nn { cf }
\cs_new_protected:Npn \@@_collect_gput_right:N #1
  {
    \int_compare:nNnF \l_@@_collect_next_int = 0
      {
        \int_decr:N \l_@@_collect_next_int
        \tl_gput_right:Nv #1
          {
            l_@@_
            \int_use:N \l_@@_collect_next_int
            _tl
          }
        \@@_collect_gput_right:N #1
      }
  }
\cs_generate_variant:Nn \@@_collect_gput_right:N { c }
%    \end{macrocode}
% \end{macro}
% \end{variable}
%
% \begin{macro}[EXP]{\@@_user_tl_name:n}
%   The name of a global token list variable holding the text of a given
%   user stream.
%    \begin{macrocode}
\cs_new:Npn \@@_user_tl_name:n #1
  { g_@@_iow_ \int_eval:n {#1} _tl }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Writing}
%
% We can hold on to material while a file is being written and only
% write it in one go once the file closes, to avoid using a stream
% throughout.
%
% At any given time, each user stream may point to an open \TeX{}
% stream, given in \cs{g_@@_write_prop}, or may point to a token list
% that will eventually be written to a file whose file name is stored in
% \cs{g_@@_write_file_prop}, or may be closed.
%
% When a user stream points to a token list rather than a \TeX{} stream,
% any material to be written must be written to our temporary file and
% read back in to apply the same expansion as \tn{write} does.
%
% Another difficulty is that users may mix immediate and non-immediate
% operations.  The biggest difficulty comes from the possibility of
% copying boxes containing delayed actions.  If we ever produced a
% whatsit \tn{write}\meta{number}\Arg{text} then the \TeX{} stream
% \meta{number} would have to be reserved forever, as as copies of the
% box containing this delayed actions may be shipped out at any later
% point in the document.
%
% Each delayed action is thus saved in a separate numbered token list
% and \tn{write}\cs{g_@@_iow}\Arg{number} is inserted instead of the
% delayed action.  At each \tn{shipout}, the stream \cs{g_@@_iow} is
% opened, to catch the \meta{number} of each action that should be
% performed at this \tn{shipout}.
%
% \subsubsection{Redefining \tn{immediate}}
%
% To accomodate the \tn{immediate} primitive, our versions of
% \tn{openout}, \tn{write} and \tn{closeout} will take the form
% \begin{quote}
%   \cs{s_@@} \cs{use_i:nn}
%   \quad \Arg{code for delayed action} \\
%   \quad \Arg{code for immediate action} \\
%   \meta{further code}
% \end{quote}
% The leading \cs{s_@@} allows the redefined \tn{immediate} to detect
% these redefined primitives, and to run the \meta{code for immediate
% action} instead of the \meta{code for delayed action} which is run by
% default.  In both cases, any \meta{further code} is run.
%
% \begin{macro}[updated = 2012-12-05]{\@@_immediate:w}
% \begin{macro}{\@@_immediate_auxii:, \@@_immediate_auxiii:N}
%   \TeX{}'s \tn{immediate} primitive raises a flag which is cancelled
%   after \TeX{} sees a non-expandable token.  We use
%   \cs{primargs_read_x_token:N} to find the next non-expandable token
%   then test for \tn{openout}, \tn{write}, and \tn{closeout}.  More
%   precisely we test for the marker \cs{s_@@} and run the appropriate
%   code as described above.  Otherwise we call the primitive, for cases
%   where the next token is \tn{pdfobj} or similar.  In contrived
%   situations involving nonsensical uses of \tn{noexpand} after
%   \tn{immediate}, this code does not perfectly match how \TeX{}
%   expands.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_immediate:w
  { \primargs_read_x_token:N \@@_immediate_auxii: }
\cs_new_protected:Npn \@@_immediate_auxii:
  {
    \token_if_eq_meaning:NNTF \g_primargs_token \s_@@
      { \@@_immediate_auxiii:N }
      {
        \@@_verbose:n
          { \tl_to_str:n { \immediate } \token_to_meaning:N \g_primargs_token }
        \@@_tex_immediate:w
      }
  }
\cs_new_protected:Npn \@@_immediate_auxiii:N #1
  { \str_if_eq:nnTF { #1 } { \s_@@ } { \use_iii:nnn } { #1 } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsubsection{Immediate actions}
%
% The \tn{openout}, \tn{write}, and \tn{closeout} primitive can be
% either delayed or immediate.  In all cases they begin by looking for a
% user stream.  In this subsubsection we implement the immediate versions
% only.
%
% \begin{macro}{\@@_closeout:w, \@@_closeout_now:, \@@_closeout_now_silent:, \@@_closeout_now:nn}
%   In the immediate case \cs{@@_closeout_now:}, there are three cases.
%   The stream may point to a \TeX{} stream, in which case it is closed,
%   removed from \cs{g_@@_write_prop}, and put back in the list of
%   usable streams.  The stream may point to a token list, in which case
%   that token list should be written to the appropriate file.  The
%   stream may be closed, in which case nothing happens.
%   The auxiliary \cs{@@_closeout_now:nn} writes the material collected
%   so far for a given user stream |#1| to the file |#2|.  This uses the
%   \TeX{} stream \cs{g_@@_iow}.  The token list consists of multiple
%   \tn{immediate} \tn{write} \cs{g_@@_iow} \Arg{text} statements
%   because that is the only safe way to obtain new lines.  We do not
%   remove the stream/file pair from \cs{g_@@_write_file_prop}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_closeout:w
  {
    \s_@@
    \use_i:nn
      { \@@_get_user:n { \@@_closeout_later: } }
      { \@@_get_user:n { \@@_closeout_now: } }
  }
\cs_new_protected:Npn \@@_closeout_now:
  {
    \@@_verbose:n { \tl_to_str:n { \immediate \closeout } \int_use:N \l_@@_user_int }
    \@@_closeout_now_silent:
  }
\cs_new_protected:Npn \@@_closeout_now_silent:
  {
    \@@_user_to_tstr:NTF \g_@@_write_prop
      {
        \@@_tex_immediate:w \@@_tex_closeout:w \l_@@_tstr_tl \exp_stop_f:
        \int_compare:nNnF { \l_@@_tstr_tl } = { \l_@@_user_int }
          {
            \prop_gremove:NV \g_@@_write_prop \l_@@_user_int
            \seq_gput_left:NV \g_@@_write_seq \l_@@_tstr_tl
          }
      }
      {
        \prop_gpop:NVNT \g_@@_write_file_prop \l_@@_user_int \l_@@_internal_tl
          { \@@_closeout_now:nn { \l_@@_user_int } { \l_@@_internal_tl } }
      }
  }
\cs_new_protected:Npn \@@_closeout_now:nn #1#2
  {
    \@@_tex_immediate:w \@@_tex_openout:w \g_@@_iow = {#2}
    \group_begin:
      \int_set:Nn \tex_newlinechar:D { -1 }
      \tl_use:c { \@@_user_tl_name:n {#1} }
      \tl_gclear:c { \@@_user_tl_name:n {#1} }
    \group_end:
    \@@_tex_immediate:w \@@_tex_closeout:w \g_@@_iow
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_openout:w, \@@_openout_now:n, \@@_openout_now_silent:n}
%   In the immediate case find a file name, then allocate a \TeX{}
%   stream if possible, and otherwise point the user stream to a token
%   list.  In all cases, close the stream to avoid losing any material
%   that \TeX{} would have written, and empty the file by opening and
%   closing it (actually that's done automatically by the primitive).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_openout:w
  {
    \s_@@
    \use_i:nn
      { \@@_get_user:n { \@@_openout_later:w } }
      { \@@_get_user:n { \@@_equals_file:N \@@_openout_now:n } }
  }
\cs_new_protected:Npn \@@_openout_now:n #1
  {
    \@@_verbose:n
      {
        \tl_to_str:n { \immediate\openout }
        \int_use:N \l_@@_user_int
        \c_space_tl = ~ {#1}
      }
    \@@_openout_now_silent:n {#1}
  }
\cs_new_protected:Npn \@@_openout_now_silent:n #1
  {
    \@@_closeout_now_silent:
    \int_compare:nNnTF { \l_@@_user_int } < { 129 }
      {
        \@@_tex_immediate:w \@@_tex_openout:w \l_@@_user_int
          = { \tl_to_str:n {#1} }
      }
      {
        \seq_gpop:NNTF \g_@@_write_seq \l_@@_tstr_tl
          {
            \prop_gput:NVV \g_@@_write_prop \l_@@_user_int \l_@@_tstr_tl
            \@@_tex_immediate:w \@@_tex_openout:w \l_@@_tstr_tl \exp_stop_f:
              = { \tl_to_str:n {#1} }
          }
          {
            \@@_empty_file:n {#1}
            \prop_gput:NVx \g_@@_write_file_prop \l_@@_user_int
              { \tl_to_str:n {#1} }
            \tl_gclear_new:c { \@@_user_tl_name:n { \l_@@_user_int } }
          }
      }
  }
\sys_if_engine_xetex:T
  {
    \cs_new_eq:NN \@@_openout_now_silent_aux:n \@@_openout_now_silent:n
    \cs_gset_protected:Npn \@@_openout_now_silent:n #1
      {
        \tl_set:Nn \l_@@_internal_tl {#1}
        \tl_remove_all:Nn \l_@@_internal_tl { " } % { " }
        \exp_args:No \@@_openout_now_silent_aux:n \l_@@_internal_tl
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_write:w, \@@_write_now:w, \@@_write_now:n}
%   In the immediate case we use \cs{@@_write_now_open:n} if the stream
%   points to a token list, and otherwise use the primitive, with the
%   dummy stream $16$ if closed (the text is then written to the
%   terminal).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_write:w
  {
    \s_@@
    \use_i:nn
      { \@@_get_user:n { \@@_write_later:w } }
      { \@@_get_user:n { \@@_write_now:w } }
  }
\cs_new_protected:Npn \@@_write_now:w
  {
    \@@_user_to_tstr:NTF \g_@@_write_prop
      {
        \int_compare:nNnT \l_@@_user_int = { 18 } { \use_iii:nnn }
        \int_compare:nT { -1 < \l_@@_user_int < 16 }
          {
            \@@_verbose:n
              {
                \tl_to_str:n { \immediate \write }
                \int_use:N \l_@@_user_int
              }
          }
        \@@_tex_immediate:w \@@_tex_write:w \l_@@_tstr_tl \exp_stop_f:
      }
      { \primargs_get_general_text:N \@@_write_now:n }
  }
\cs_new_protected:Npn \@@_write_now:n #1
  {
    \prop_get:NVNTF \g_@@_write_file_prop \l_@@_user_int \l_@@_internal_tl
      {
        \@@_verbose:n
          {
            \tl_to_str:n { \immediate \write }
            \int_use:N \l_@@_user_int
            \tl_to_str:n { ~ {#1} }
          }
        \@@_write_now_open:n {#1}
      }
      {
        \@@_verbose:n
          {
            \tl_to_str:n { \immediate \write }
            \int_use:N \l_@@_user_int
            \tl_to_str:n { ~ (closed) ~ {#1} }
          }
        \@@_tex_immediate:w \@@_tex_write:w 16 {#1}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_write_now_open:n}
% \begin{macro}{\@@_write_now_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 (after making sure we are allowed to alter
%   it), 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 a token list whose name is constructed
%   using \cs{@@_user_tl_name:n}.  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 \@@_write_now_open:n #1
  {
    \bool_if:NF \g_@@_tmp_file_bool { \@@_chk_file: }
    \@@_tex_immediate:w \@@_tex_openout:w
      \g_@@_iow = { \g_@@_tmp_file_tl }
    \@@_tex_immediate:w \@@_tex_write:w
      \g_@@_iow {#1}
    \@@_tex_immediate:w \@@_tex_closeout:w
      \g_@@_iow
    \group_begin:
      \int_set:Nn \tex_endlinechar:D { -1 }
      \tex_openin:D \g_@@_ior = { \g_@@_tmp_file_tl }
      \@@_write_now_loop:
      \tex_closein:D \g_@@_ior
      \@@_collect_gput_right:c
        { \@@_user_tl_name:n { \l_@@_user_int } }
    \group_end:
    \@@_empty_file:n { \g_@@_tmp_file_tl }
  }
\cs_new_protected:Npn \@@_write_now_loop:
  {
    \tex_readline:D \g_@@_ior to \l_@@_internal_tl
    \ior_if_eof:NF \g_@@_ior
      {
        \@@_collect:x
          {
            \@@_tex_immediate:w \@@_tex_write:w
              \g_@@_iow { \l_@@_internal_tl }
          }
        \@@_write_now_loop:
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
% \subsubsection{Delayed actions}
%
% \begin{macro}{\@@_later:n, \@@_later_do:n}
%   Store the action to be done at shipout in a token list, and
%   non-immediately write the label \cs{g_@@_later_int} of the
%   output operation to the temporary file.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_later:n #1
  {
    \int_gincr:N \g_@@_later_int
    \tl_const:cx
      {
        c_@@_later_
        \int_use:N \g_@@_later_int
        _tl
      }
      {
        \int_set:Nn \exp_not:N \l_@@_user_int
          { \exp_not:V \l_@@_user_int }
        \exp_not:n {#1}
      }
    \exp_args:NNx \@@_tex_write:w \g_@@_iow
      { `( \int_use:N \g_@@_later_int ) }
  }
\cs_new_protected:Npn \@@_later_do:n #1
  { \tl_use:c { c_@@_later_ \int_eval:n {#1} _tl } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_closeout_later:}
%   If the user stream is a \TeX{} stream, use the primitive, otherwise
%   save \cs{@@_closeout_now_silent:} for later.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_closeout_later:
  {
    \@@_verbose:n { \tl_to_str:n { \closeout (later) ~ } \int_use:N \l_@@_user_int }
    \int_compare:nNnTF \l_@@_user_int < { 129 }
      { \@@_tex_closeout:w \l_@@_user_int }
      { \@@_later:n { \@@_closeout_now_silent: } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_openout_later:w, \@@_openout_later:n}
%   If the user stream is a \TeX{} stream use the primitive, otherwise
%   find a file name and call \cs{@@_openout_now_silent:n} later.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_openout_later:w
  {
    \int_compare:nNnTF \l_@@_user_int < { 129 }
      {
        \@@_verbose:n { \tl_to_str:n { \openout (later) ~ } \int_use:N \l_@@_user_int }
        \@@_tex_openout:w \l_@@_user_int
      }
      { \@@_equals_file:N \@@_openout_later:n }
  }
\cs_new_protected:Npn \@@_openout_later:n #1
  {
    \@@_verbose:n
      {
        \tl_to_str:n { \openout (later)~ }
        \int_use:N \l_@@_user_int
        \c_space_tl = ~ {#1}
      }
    \@@_later:n { \@@_openout_now_silent:n {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_write_later:w, \@@_write_later:n, \@@_write_later_aux:n}
%   For \TeX{} streams use the primitive, otherwise find a general text
%   and save it for later; the auxiliary is very similar to
%   \cs{@@_write_now:w}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_write_later:w
  {
    \int_compare:nNnTF \l_@@_user_int < { 129 }
      {
        \@@_verbose:n { \tl_to_str:n { \write (later)~ } \int_use:N \l_@@_user_int }
        \@@_tex_write:w \l_@@_user_int
      }
      { \primargs_get_general_text:N \@@_write_later:n }
  }
\cs_new_protected:Npn \@@_write_later:n #1
  {
    \@@_verbose:n
      {
        \tl_to_str:n { \write (later)~ }
        \int_use:N \l_@@_user_int
        \tl_to_str:n { ~ {#1} }
      }
    \@@_later:n { \@@_write_later_aux:n {#1} }
  }
\cs_new_protected:Npn \@@_write_later_aux:n
  {
    \@@_user_to_tstr:NTF \g_@@_write_prop
      { \@@_tex_immediate:w \@@_tex_write:w \l_@@_tstr_tl \exp_stop_f: }
      {
        \prop_get:NVNTF \g_@@_write_file_prop \l_@@_user_int \l_@@_internal_tl
          { \@@_write_now_open:n }
          { \@@_tex_immediate:w \@@_tex_write:w 16 \exp_stop_f: }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Shipout business}
%
% In this section, we hook into the \tn{shipout} primitive, and redefine
% it to first build a box with the material to ship out, then perform
% \begin{quote}
%   \cs{@@_before_shipout:} \\
%   \meta{primitive shipout} \meta{collected box} \\
%   \cs{@@_after_shipout:}
% \end{quote}
%
% 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{macro}{\@@_before_shipout:}
%   Immediately before the shipout, we must open the writing stream
%   \cs{g_@@_iow} (after making sure we are allowed to alter the
%   auxiliary file).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_before_shipout:
  {
    \bool_if:NF \g_@@_tmp_file_bool { \@@_chk_file: }
    \@@_tex_immediate:w \@@_tex_openout:w
      \g_@@_iow = { \g_@@_tmp_file_tl }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_after_shipout:}
% \begin{macro}[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} extracts 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: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} }
      \tex_everyeof:D { `() \exp_not:N }
      \tl_set:Nx \l_@@_internal_tl
        {
          \exp_after:wN \@@_after_shipout_loop:ww
          \tex_input:D { \g_@@_tmp_file_tl }
        }
      \@@_empty_file:n { \g_@@_tmp_file_tl }
      \exp_args:NNo
    \group_end:
    \tl_map_function:nN { \l_@@_internal_tl } \@@_later_do:n
  }
\cs_new:Npn \@@_after_shipout_loop:ww #1 `( #2 )
  {
    \tl_if_empty:nF {#2}
      {
        {#2}
        \@@_after_shipout_loop:ww
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_shipout:w}
% \begin{macro}{\@@_shipout_i:, \@@_shipout_ii:}
%   Grab the shipped out box using \tn{setbox} and regain control using
%   \tn{afterassignment}.  There are two cases: either the box is given
%   as \tn{box} or \tn{copy} followed by a number, in which case
%   \cs{@@_shipout_i:} is inserted afterwards at the same group level,
%   or the box is given as \tn{hbox} (or \tn{vtop} and so on) and an
%   additional \tn{aftergroup} is needed to reach a point where we can
%   use the box saved in \cs{g_@@_shipout_box}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_shipout:w
  {
    \int_gset_eq:NN \g_@@_group_level_int \tex_currentgrouplevel:D
    \tex_afterassignment:D \@@_shipout_i:
    \tex_global:D \tex_setbox:D \g_@@_shipout_box
  }
\cs_new_protected:Npn \@@_shipout_i:
  {
    \int_compare:nNnTF { \g_@@_group_level_int }
                     = { \tex_currentgrouplevel:D }
      { \@@_shipout_ii: }
      { \tex_aftergroup:D \@@_shipout_ii: }
  }
\cs_new_protected:Npn \@@_shipout_ii:
  {
    \@@_before_shipout:
    \@@_tex_shipout:w \tex_box:D \g_@@_shipout_box
    \@@_after_shipout:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\shipout, \@@_tex_shipout:w}
%   The task is now to locate the shipout primitive, which may have been
%   renamed and hooked into by many different packages loaded before
%   \pkg{morewrites}.  Any of those control sequences which are equal to
%   the primitive are redefined to do \cs{@@_shipout:w} instead.  If the
%   primitive is not located at all, the fallback is to hook into the
%   control sequence \tn{shipout}.
%    \begin{macrocode}
\cs_gset_protected:Npn \@@_tmp:w #1
  {
    \cs_if_exist:NF \@@_tex_shipout:w
      { \cs_new_eq:NN \@@_tex_shipout:w #1 }
    \cs_gset_eq:NN #1 \@@_shipout:w
  }
\tl_map_inline:nn
  {
    \xyrealshipout@
    \org@shipout
    \PDFSYNCship@ut@ld
    \CROP@shipout
    \@soORI
    \tex_shipout:D
    \zwpl@Hship
    \o@shipout@TP
    \LL@shipout
    \Shipout
    \GXTorg@shipout
    \AtBegShi@OrgShipout
    \AtBeginShipoutOriginalShipout
    \minidocument@orig@shipout
    \shipout
  }
  {
    \str_if_eq:eeT
      { \cs_meaning:N #1 }
      { \token_to_str:N \shipout }
      { \@@_tmp:w #1 }
  }
\cs_if_exist:NF \@@_tex_shipout:w
  {
    \cs_new_eq:NN \@@_tex_shipout:w \shipout
    \cs_gset_eq:NN \shipout \@@_shipout:w
  }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Hook at the very end}
%
% \begin{macro}{\@@_close_all:}
%   At the end of the document, close all the files.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_close_all:
  {
    \prop_map_inline:Nn \g_@@_write_prop
      {
        \@@_verbose:n { \tl_to_str:n { \immediate \closeout } ##1 ~ (at~end) }
        \@@_tex_immediate:w \@@_tex_closeout:w ##2 \scan_stop:
      }
    \prop_gclear:N \g_@@_write_prop
    \prop_map_function:NN \g_@@_write_file_prop
      \@@_closeout_now:nn
    \prop_gclear:N \g_@@_write_file_prop
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_close_all_at_end:nw}
%   At the end of the run, we try very hard to put some material at the
%   \tn{@@end}, just in case some other very late code writes to files
%   that are not yet closed.  This is tried at most $5$~times, to avoid
%   infinite loops in case two packages compete for that last place.
%   The four |@| become two after \pkg{l3docstrip}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_close_all_at_end:nw #1#2 \@@@@end
  {
    \int_compare:nNnTF {#1} > 0
      { #2 \@@_close_all_at_end:nw { #1 - 1 } }
      { \@@_close_all: #2 }
    \@@@@end
  }
\AtEndDocument { \@@_close_all_at_end:nw { 5 } }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Redefining commands}
%
% \subsubsection{Modified \tn{newwrite}}
%
% \begin{variable}{\g_@@_alloc_write_int}
%   Counter to allocate user streams.  We used to initialize it to $18$
%   so that the first user stream allocated by \pkg{morewrites} was
%   $19$.  Indeed, $18$ is reserved for shell commands and packages may
%   expect $16$ or $17$ to write to the terminal.  This is now changed
%   to start allocation at $129$, since some packages that do not want
%   to distinguish \LuaTeX{} from other engines simply use $128$ as a
%   never-open stream.
%    \begin{macrocode}
\int_new:N \g_@@_alloc_write_int
\int_gset:Nn \g_@@_alloc_write_int { 128 }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_newwrite:N}
%   Reimplementation of \tn{newwrite} but protected and using a counter
%   \cs{g_@@_alloc_write_int} instead of what \TeX{}/\LaTeXe{} use.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_newwrite:N #1
  {
    \int_gincr:N \g_@@_alloc_write_int
    \int_set_eq:NN \allocationnumber \g_@@_alloc_write_int
    \cs_undefine:N #1
    \int_const:Nn #1 { \allocationnumber }
    \wlog
      {
        \token_to_str:N #1
        = \token_to_str:N \write \int_use:N \allocationnumber
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_allocate:n}
%   Raise to |#1| the number of \tn{write} streams allocated to \pkg{morewrites}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_allocate:n #1
  {
    \prg_replicate:nn
      {
        \int_max:nn { 0 }
          {
            (#1) - \seq_count:N \g_@@_write_seq
            - \prop_count:N \g_@@_write_prop
          }
      }
      {
        \@@_tex_newwrite:N \l_@@_tstr_token
        \seq_gput_right:NV \g_@@_write_seq \l_@@_tstr_token
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{User commands and keys}
%
% \begin{macro}[added = 2014-07-26]{\morewritessetup}
%   Set whatever keys the user passes to \cs{morewritessetup}.
%    \begin{macrocode}
\cs_new_protected:Npn \morewritessetup #1
  { \keys_set:nn { @@ } {#1} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[added = 2014-07-26]{file}
%   Because of our use of |.initial:n|, this code must appear after
%   \cs{@@_set_file:n} is defined.
%    \begin{macrocode}
\keys_define:nn { @@ }
  {
    allocate .code:n = \@@_allocate:n {#1} ,
    file .code:n = \@@_set_file:n {#1} ,
    file .initial:n = \c_sys_jobname_str .mw ,
    verbose .bool_set:N = \l_@@_verbose_bool
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[updated = 2015-08-01]
%   {\immediate, \openout, \write, \closeout, \newwrite}
%    \begin{macrocode}
\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}
%
%</package>
%
% \end{implementation}
%
% \clearpage
% \PrintIndex
