texlive[43862] Master/texmf-dist: morewrites (14apr17)

commits+karl at tug.org commits+karl at tug.org
Mon Apr 17 00:19:40 CEST 2017


Revision: 43862
          http://tug.org/svn/texlive?view=revision&revision=43862
Author:   karl
Date:     2017-04-17 00:19:40 +0200 (Mon, 17 Apr 2017)
Log Message:
-----------
morewrites (14apr17)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/morewrites/morewrites.pdf
    trunk/Master/texmf-dist/doc/latex/morewrites/primargs.pdf
    trunk/Master/texmf-dist/source/latex/morewrites/morewrites.dtx
    trunk/Master/texmf-dist/source/latex/morewrites/primargs.dtx
    trunk/Master/texmf-dist/tex/latex/morewrites/morewrites.sty
    trunk/Master/texmf-dist/tex/latex/morewrites/primargs.sty

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/latex/morewrites/README.md

Removed Paths:
-------------
    trunk/Master/texmf-dist/doc/latex/morewrites/README

Deleted: trunk/Master/texmf-dist/doc/latex/morewrites/README
===================================================================
--- trunk/Master/texmf-dist/doc/latex/morewrites/README	2017-04-16 22:19:27 UTC (rev 43861)
+++ trunk/Master/texmf-dist/doc/latex/morewrites/README	2017-04-16 22:19:40 UTC (rev 43862)
@@ -1,15 +0,0 @@
-----------------------------------------------------------------
-morewrites --- Always room for a new write
-E-mail: blflatex at gmail.com
-Released under the LaTeX Project Public License v1.3c or later
-See http://www.latex-project.org/lppl.txt
-----------------------------------------------------------------
-
-The morewrites package silently hooks into the TeX primitives
-responsible for writing to files to lift the restriction on
-the number of files open at the same time (16). Load the package
-with "\usepackage{morewrites}" as early as possible.
-
-This package uses the l3kernel bundle.
-
-This is work in progress, all suggestions/comments/bug reports are welcome!

Added: trunk/Master/texmf-dist/doc/latex/morewrites/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/morewrites/README.md	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/morewrites/README.md	2017-04-16 22:19:40 UTC (rev 43862)
@@ -0,0 +1,16 @@
+Provide more writing streams in LaTeX
+=====================================
+* E-mail: blflatex at gmail.com
+* Released under the LaTeX Project Public License v1.3c or later
+  See http://www.latex-project.org/lppl.txt
+
+The morewrites LaTeX package should be used when encountering the
+`No room for a new \write ` error.  This is done by redefining a
+few TeX primitives related to output.
+
+This package uses the `l3kernel` bundle.
+
+This is work in progress, all suggestions/comments/bug reports
+are welcome!  See https://github.com/blefloch/latex-morewrites
+
+


Property changes on: trunk/Master/texmf-dist/doc/latex/morewrites/README.md
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/texmf-dist/doc/latex/morewrites/morewrites.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/morewrites/primargs.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/morewrites/morewrites.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/morewrites/morewrites.dtx	2017-04-16 22:19:27 UTC (rev 43861)
+++ trunk/Master/texmf-dist/source/latex/morewrites/morewrites.dtx	2017-04-16 22:19:40 UTC (rev 43862)
@@ -1,6 +1,6 @@
 % \iffalse meta-comment
 %
-%% File: morewrites.dtx Copyright (C) 2011-2013 Bruno Le Floch
+%% File: morewrites.dtx Copyright (C) 2011-2017 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,11 +13,10 @@
 %
 %<*driver>
 \RequirePackage{morewrites}
+\ExplSyntaxOn
+\prg_replicate:nn { 300 } { \newwrite \foo }
+\ExplSyntaxOff
 \documentclass[full]{l3doc}
-\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}
@@ -25,10 +24,9 @@
 % \fi
 %
 % \title{The \textsf{morewrites} package: \\
-%   Always room for a new \cs{write}\thanks{This
-%     file has version number v0.2e, last revised 2013/01/08.}}
+%   Always room for a new \tn{write}}
 % \author{Bruno Le Floch}
-% \date{2013/01/08}
+% \date{2017/04/10}
 %
 % \maketitle
 % \tableofcontents
@@ -37,54 +35,118 @@
 %
 % \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
+% This \LaTeX{} package is a solution for the errors
+% \begin{itemize}
+% \item \enquote{no room for a new \tn{write}},
+% \item \enquote{no room for a new \tn{read}},
+% \end{itemize}
+% which occur when a document reserves too many streams to write data
+% to various auxiliary files or read from them.
+% 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).  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.
+% primitives).
 %
-% 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.
+% Simply add the line |\usepackage{morewrites}| near the beginning of
+% your \LaTeX{} file's preamble: the \enquote{no room for a new
+% \tn{write}/\tn{read}} 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.
 %
-% 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.
+% 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.  Versions from 2015 and later will only
+%   use the auxiliary file if it is originally empty, to avoid
+%   destroying data (such as |.mw| files used by Maple).  This means
+%   that |.mw| files generated by versions before 2015 should be
+%   deleted by hand.
+% \item \LuaTeX{} allows $128$ \tn{write} streams, so this package does
+%   nothing (with a warning) when used with \LuaTeX{}.
+% \end{itemize}
 %
-% \section{Known deficiencies and open questions}
+% \subsection{Commands defined or altered by \pkg{morewrites}}
 %
-% 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.
+% \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}
 %
-% The current code trims spaces at the end of every line that is written
-% to a file.  I might be able to change the code to avoid this.
+% \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 may speed up
+%   \pkg{morewrites}.
+% \end{function}
 %
-% 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.}
+% \begin{function}[added = 2014-07-26, updated = 2015-08-01]{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}
 %
-% Things that I need to do.
-% \begin{itemize}
-% \item Redefine the \LaTeX3 functions to use \pkg{morewrites} too?
-% \item Should \tn{newwrite} be protected?
-% \end{itemize}
+% \begin{function}[updated = 2015-08-01]{\newread, \newwrite}
+%   These macros are redefined by \pkg{morewrites}.
+%   Since \pkg{morewrites} allows more than~$16$ read/write streams, it
+%   removes the corresponding restrictions in \tn{newread} and
+%   \tn{newwrite}.
+%   \begin{texnote}
+%     The revised \tn{newread} and \tn{newwrite} allocate stream
+%     numbers starting at $19$.  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 = 2015-08-01]{\openin, \read, \readline, \closein, \openout, \write, \closeout}
+%   These seven primitives are altered by \pkg{morewrites} so that they
+%   accept stream numbers outside the normal range $[0,15]$ and
+%   open/read/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}
@@ -93,13 +155,25 @@
 %
 %<*package>
 %    \begin{macrocode}
-\RequirePackage {expl3} [2012/08/14]
-\RequirePackage {primargs} [2013/01/08]
+\RequirePackage {expl3} [2017/03/18]
+\RequirePackage {primargs} [2017/04/10]
 \ProvidesExplPackage
-  {morewrites} {2013/01/08} {0.2e} {Always room for a new write}
+  {morewrites} {2017/04/10} {} {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}
 %
@@ -106,64 +180,47 @@
 % \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).
+% restriction of only having $16$ files open for reading at the same
+% time, and the same restriction for writing.  This requires patching
+% the primitives \tn{openin}, \tn{read}, \tn{readline}, \tn{closein},
+% \tn{immediate}, \tn{openout}, \tn{write}, \tn{closeout}, and
+% \tn{shipout}, and the macros \tn{newread} and \tn{newwrite} present
+% in plain \TeX{} and \LaTeXe{}.
 %
-% 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.
+% 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.
 %
-% 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.
+% Henceforth, ``\TeX{} stream'' will refer to stream numbers in the
+% range $[0,15]$ provided to \TeX{}'s read/write primitives, while
+% ``user stream'' will denote stream numbers in $[0,15]\cup[19,\infty)$
+% manipulated by the redefined \tn{openin}, \tn{read}, \tn{readline},
+% \tn{closein}, \tn{openout}, \tn{write}, \tn{closeout}, \tn{newread},
+% 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 $[19,\infty)$ is mapped to a \TeX{}
+% stream according to the property lists (with integer keys and values)
+% \cs{l_@@_read_prop} and \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.
 %
-% 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.
-%
+% The primitives \tn{openin}, \tn{read}, \tn{readline}, \tn{closein},
+% \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{openin}     \meta{integer} \meta{equals} \meta{file name}        \\
+%   \tn{read}       \meta{integer} \texttt{to}   \meta{control sequence} \\
+%   \tn{readline}   \meta{integer} \texttt{to}   \meta{control sequence} \\
+%   \tn{closein}    \meta{integer}                                       \\
+%   \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.  In most cases, only the \tn{meaning} of
-% tokens encountered in this way matters.  Specifically,
+% 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
@@ -180,7 +237,7 @@
 %   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$;
+%   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
@@ -189,46 +246,120 @@
 %   assignment of the form \tn{toks}|0=|\meta{general text}.
 % \end{itemize}
 %
-% \subsection{Variants}
+% The \pkg{morewrites} package redefines these seven 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{newread} and \tn{newwrite} must be patched to allocate stream
+% numbers beyond $15$.
 %
-% \begin{macro}[aux]{\prop_gpop:NVNT}
-%   We need this function later.
-%    \begin{macrocode}
-\cs_generate_variant:Nn \prop_gpop:NnNT { NV }
-%    \end{macrocode}
-% \end{macro}
+% A few comments on the behaviour of primitives concerning the
+% \meta{integer} (\TeX{} stream).  The primitives \tn{openin} and
+% \tn{openout} trigger errors if the \meta{integer} is not in $[0,15]$.
+% The primitives \tn{read} and \tn{readline} prompt the user for input
+% if the \TeX{} stream is closed or beyond $[0,15]$, with no explicit
+% prompt if the stream number is negative.  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
+% primitives \tn{closein} and \tn{closeout} trigger errors 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.
 %
-% \subsection{Renaming primitives (again)}
+% 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.
 %
-% \begin{macro}[int]
+% 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{newread} and \tn{newwrite} macros expect one token as
+% their argument, and define this token (with \tn{chardef}) to be an
+% integer corresponding to the first available (\TeX{}) read/write
+% stream.  This must be extended to allocate higher (user) streams.
+%
+% \subsection{Preliminaries}
+%
+% \subsubsection{Copying some commands}
+%
+% \begin{macro}[aux]
 %   {
 %     \@@_tex_immediate:w ,
 %     \@@_tex_openout:w   ,
 %     \@@_tex_write:w     ,
-%     \@@_tex_closeout:w
+%     \@@_tex_closeout:w  ,
+%     \@@_tex_openin:w    ,
+%     \@@_tex_read:w      ,
+%     \@@_tex_readline:w  ,
+%     \@@_tex_closein:w   ,
 %   }
-%   First save the output-related primitives.
+%   Aliases for the read- and 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
+\cs_new_eq:NN \@@_tex_openin:w    \tex_openin:D
+\cs_new_eq:NN \@@_tex_read:w      \tex_read:D
+\cs_new_eq:NN \@@_tex_readline:w  \etex_readline:D
+\cs_new_eq:NN \@@_tex_closein:w   \tex_closein: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{macro}[aux]{\@@_tex_newread:N, \@@_tex_newwrite:N}
+%   Copy \tn{newread} and \tn{newwrite} but making sure that they are
+%   not \tn{outer}.  These copies will not be affected by redefinitions
+%   of \tn{newread} and \tn{newwrite} later on.
 %    \begin{macrocode}
-\cs_new_eq:NN \@@_tex_shipout:w   \tex_shipout:D
+\exp_args:NNf \cs_new_protected:Npn \@@_tex_newread:N
+  { \exp_args:NNc \exp_after:wN \exp_stop_f: { newread } }
+\exp_args:NNf \cs_new_protected:Npn \@@_tex_newwrite:N
+  { \exp_args:NNc \exp_after:wN \exp_stop_f: { newwrite } }
 %    \end{macrocode}
 % \end{macro}
 %
-% \subsection{Variables}
+% \subsubsection{Variants}
 %
-% \begin{variable}{\g_@@_late_write_int}
-%   The integer \cs{g_@@_late_write_int} labels the various
+% \begin{macro}[aux]{\prop_gpop:NVNT, \prop_gput:NVx, \tl_gput_right:Nv}
+%   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}
+% \end{macro}
+%
+% \subsubsection{Variables}
+%
+% \begin{variable}{\l_@@_internal_tl}
+%   Used for temporary scratch purposes.
+%    \begin{macrocode}
+\tl_new:N \l_@@_internal_tl
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}[aux]{\@@_tmp:w}
+%   Used for temporary definitions.
+%    \begin{macrocode}
+\cs_new_eq:NN \@@_tmp:w ?
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}[aux]{\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
@@ -236,25 +367,81 @@
 %   \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}
+%     \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_@@_late_write_int
+\int_new:N \g_@@_later_int
 %    \end{macrocode}
 % \end{variable}
 %
-% \begin{variable}{\g_@@_iow_prop}
-%   The property list \cs{g_@@_iow_prop} associates a file name to each
-%   open stream.
+% ^^A todo: populate \g_@@_write_seq because we don't use \newwrite; this should be done in \morewritessetup
+% \begin{variable}[aux]{\g_@@_read_seq, \g_@@_write_seq}
+%   Keep track of \TeX{} stream numbers managed by \pkg{morewrites} that
+%   are currently not in use as user streams.
 %    \begin{macrocode}
-\prop_new:N \g_@@_iow_prop
+\seq_new:N \g_@@_read_seq
+\seq_new:N \g_@@_write_seq
 %    \end{macrocode}
 % \end{variable}
 %
-% \begin{variable}{\g_@@_iow, \g_@@_ior, \g_@@_tmp_file_tl}
-%   The expansion that \tn{write} performs is impossible to emulate with
+% \begin{variable}[aux]{\g_@@_read_prop, \g_@@_write_prop}
+%   Map user streams to \TeX{} streams.
+%    \begin{macrocode}
+\prop_new:N \g_@@_read_prop
+\prop_new:N \g_@@_write_prop
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}[aux]{\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}[aux]{\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}[aux]{\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}[aux]{\l_@@_tstr_token}
+%   This token is given as an argument to \cs{@@_tex_newread:N} or
+%   \cs{@@_tex_newwrite:N}.
+%    \begin{macrocode}
+\cs_new_eq:NN \l_@@_tstr_token ?
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[aux]{\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 currently
+%   internal to \LaTeX3.
+%    \begin{macrocode}
+\cs_new_eq:NN \s_@@ \scan_stop:
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}[aux]{\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.
@@ -263,309 +450,566 @@
 %    \begin{macrocode}
 \newwrite \g_@@_iow
 \newread \g_@@_ior
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}[aux]{\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
-\tl_gset:Nn \g_@@_tmp_file_tl { \jobname.mw }
+\bool_new:N \g_@@_tmp_file_bool
+\bool_gset_false:N \g_@@_tmp_file_bool
 %    \end{macrocode}
 % \end{variable}
 %
-% \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{variable}[aux]{\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}
-\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}
+\int_new:N \g_@@_group_level_int
 %    \end{macrocode}
 % \end{variable}
 %
-% \begin{variable}[int]{\g_@@_stream_int}
-%   An integer holding the \meta{number} argument of various primitives,
-%   namely a writing stream.
+% \begin{variable}[aux]{\g_@@_shipout_box}
+%   The page to be shipped out.
 %    \begin{macrocode}
-\int_new:N \g_@@_stream_int
+\box_new:N \g_@@_shipout_box
 %    \end{macrocode}
 % \end{variable}
 %
-% \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.
+% \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|).  Mark that the file has not been
+%   checked.
 %    \begin{macrocode}
-\cs_new_eq:NN \s_@@ \scan_stop:
+\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{variable}[int]{\l_@@_internal_tl}
-%   Temporary token list, used for scratch purposes.
+% \begin{macro}[aux]{\@@_empty_file:n}
+%   Empties the file \cs{g_@@_tmp_file_tl} 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}
-\tl_new:N  \l_@@_internal_tl
+\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{variable}
+% \end{macro}
 %
-% \subsection{Parsing}
+% \begin{macro}[aux,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 \scan_stop:
+      \if_eof:w \g_@@_ior
+        \cs_gset_eq:NN \@@_tmp:w \prg_return_true:
+      \else:
+        \int_set:Nn \tex_endlinechar:D { -1 }
+        \etex_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}[aux]{\@@_equals_file_name:N}
+% \begin{macro}[aux]{\@@_chk_file:}
+%   Check that the file \cs{g_@@_tmp_file_tl} does not exist or is blank.
+%   If not, try the file name obtained by adding |.mw|.
+%   This avoids clobbering files that the user would not want to lose.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_chk_file:
+  {
+    \@@_if_file_trivial:nTF { \g_@@_tmp_file_tl }
+      { \bool_gset_true:N \g_@@_tmp_file_bool }
+      {
+        \msg_warning:nnxx { morewrites } { file-exists }
+          { \g_@@_tmp_file_tl }
+          { \g_@@_tmp_file_tl .mw }
+        \tl_gput_right:Nn \g_@@_tmp_file_tl { .mw }
+        \@@_chk_file:
+      }
+  }
+\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}[aux]{\@@_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_name:N #1
+\cs_new_protected:Npn \@@_equals_file:N #1
   {
     \group_begin:
+      \tex_aftergroup:D \primargs_get_file_name:N
       \tex_aftergroup:D #1
-      \primargs_remove_equals:N \@@_parse_file_name:
+      \primargs_remove_equals:N \group_end:
   }
-\cs_new_protected_nopar:Npn \@@_parse_file_name:
-  { \primargs_get_file_name:N \group_end: }
 %    \end{macrocode}
 % \end{macro}
 %
-% \subsection{Immediate (writing)}
+% \begin{macro}[aux]{\@@_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}
 %
-% In the context of immediate writing, we can store the text
-% in a token list, and only write it at the corresponding
-% \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 \tn{immediate}}
-%
-% \begin{macro}[aux, updated = 2012-12-05]{\@@_immediate:w}
-% \begin{macro}[aux, updated = 2012-12-05]{\@@_immediate_ii:}
-% \begin{macro}[aux]{\@@_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.  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).  If absent, what
-%   follows may be a command that should not appear after
-%   \tn{immediate}, but it may also be a non-\TeX\ primitive such as
-%   \tn{pdfobj} that the \pkg{morewrite} does not know about; hence we
-%   must still call the primitive \tn{immediate}.
+% \begin{macro}[aux]{\@@_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 $19$ are not managed by \pkg{morewrites}: actual \TeX{}
+%   streams in $[0,15]$; negative for writing to \texttt{log} and
+%   reading without prompt; $16$, $17$ for writing to terminal and
+%   reading with prompt; $18$ for shell escape.  Larger stream numbers
+%   are looked up in the property list |#1|, either \cs{g_@@_read_prop}
+%   or \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_nopar:Npn \@@_immediate:w
-  { \primargs_read_x_token:N \@@_immediate_ii: }
-\cs_new_protected_nopar:Npn \@@_immediate_ii:
+\cs_new_protected:Npn \@@_user_to_tstr:NTF #1
   {
-    \token_if_eq_meaning:NNTF \g_primargs_token \s_@@
-      { \@@_immediate_iii:N }
-      { \@@_tex_immediate:w }
+    \tl_set:NV \l_@@_tstr_tl \l_@@_user_int
+    \int_compare:nNnTF { \l_@@_user_int } < { 19 }
+      { \use_i:nn }
+      { \prop_get:NVNTF #1 \l_@@_user_int \l_@@_tstr_tl }
   }
-\cs_new_protected:Npn \@@_immediate_iii:N #1
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}[aux]{\l_@@_collect_next_int}
+% \begin{macro}[aux]
+%   {
+%     \@@_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_if_eq:nnTF { #1 } { \s_@@ }
-      { \@@_immediate_iv:NN }
-      { #1 }
+    \tl_set:Nx \l_@@_internal_tl {#1}
+    \@@_collect_aux:cf { l_@@_0_tl } { 1 }
   }
-\cs_new_protected:Npn \@@_immediate_iv:NN #1 #2
+\cs_new_protected:Npn \@@_collect_aux:Nn #1#2
   {
-    \exp_args:Nc #1
+    \int_compare:nNnT {#2} > \l_@@_collect_next_int
       {
-        \exp_after:wN \@@_immediate_v:w
-        \token_to_str:N #2
+        \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 } }
+      }
   }
-\use:x
+\cs_generate_variant:Nn \@@_collect_aux:Nn { cf }
+\cs_new_protected:Npn \@@_collect_gput_right:N #1
   {
-    \cs_new:Npn \exp_not:N \@@_immediate_v:w
-        ##1 \tl_to_str:n { @@ } { @@_immediate }
+    \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{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
+% \end{variable}
 %
-% \subsubsection{Immediate closeout}
-%
-% \begin{macro}[aux]{\@@_immediate_closeout_test:n}
-%   When the user requests to close a stream, we look in
-%   \cs{g_@@_reserved_iow_clist} to see if it is a reserved
-%   stream: in this case, we simply use the primitive.
+% \begin{macro}[aux, 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_protected:Npn \@@_immediate_closeout_test:n #1
-  {
-    \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: }
-  }
+\cs_new:Npn \@@_user_tl_name:n #1
+  { g_@@_iow_ \int_eval:n {#1} _tl }
 %    \end{macrocode}
 % \end{macro}
 %
-% \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.
+% \subsection{Reading}
+%
+% \begin{macro}[aux]{\@@_openin:w}
+%   Set \cs{l_@@_user_int} to a user stream then convert it to a \TeX{}
+%   stream \cs{l_@@_tstr_tl} and call the primitive.  If the user stream
+%   is closed (not associated to any \TeX{} stream), the \texttt{false}
+%   branch of \cs{@@_user_to_tstr:NTF} is taken.  Then get a stream from
+%   \cs{g_@@_read_seq} (\TeX{} streams managed by \pkg{morewrites} but
+%   not in use) or use the copy of \tn{newread} as a fallback.  Store
+%   the new mapping from user stream to \TeX{} stream into
+%   \cs{g_@@_read_prop}.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_immediate_closeout_aux:
+\cs_new_protected:Npn \@@_openin:w
   {
-    \prop_gpop:NVNT \g_@@_iow_prop \g_@@_stream_int \l_@@_internal_tl
+    \@@_get_user:n
       {
-        \@@_immediate_write_and_close:nn
-          { \g_@@_stream_int } { \l_@@_internal_tl }
+        \@@_user_to_tstr:NTF \g_@@_read_prop { }
+          {
+            \seq_pop:NNF \g_@@_read_seq \l_@@_tstr_tl
+              {
+                \@@_tex_newread:N \l_@@_tstr_token
+                \tl_set:NV \l_@@_tstr_tl \l_@@_tstr_token
+              }
+            \prop_gput:NVV \g_@@_read_prop \l_@@_user_int \l_@@_tstr_tl
+          }
+        \@@_tex_openin:w \l_@@_tstr_tl \exp_stop_f:
       }
   }
 %    \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{macro}[aux]{\@@_read:w, \@@_readline:w}
+%   Set \cs{l_@@_user_int} to a user stream and convert it to a \TeX{}
+%   stream \cs{l_@@_tstr_tl} then call the primitive.  Nothing needs to
+%   be done for streams not managed by \pkg{morewrites} or for user
+%   streams that do not correspond to any \TeX{} stream, as the
+%   primitive will simply read user input from the terminal as \TeX{}
+%   would do.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_immediate_write_and_close:nn #1#2
+\cs_new_protected:Npn \@@_read:w
   {
-    \@@_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
+    \@@_get_user:n
+      {
+        \@@_user_to_tstr:NTF \g_@@_read_prop { } { }
+        \@@_tex_read:w \l_@@_tstr_tl \exp_stop_f:
+      }
   }
+\cs_new_protected:Npn \@@_readline:w
+  {
+    \@@_get_user:n
+      {
+        \@@_user_to_tstr:NTF \g_@@_read_prop { } { }
+        \@@_tex_readline:w \l_@@_tstr_tl \exp_stop_f:
+      }
+  }
 %    \end{macrocode}
 % \end{macro}
 %
-% \subsubsection{Immediate openout}
-%
-% \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{macro}[aux]{\@@_closein:w}
+%   There is slightly more work than for |read| and |readline| because
+%   closing a user stream managed by \pkg{morewrites} means removing it
+%   from the mapping and putting it back in the list of available
+%   streams.  To avoid useless work, only do this if there was indeed a
+%   non-trivial mapping between user and \TeX{} stream.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_immediate_openout_test:n #1
+\cs_new_protected:Npn \@@_closein:w
   {
-    \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 }
+    \@@_get_user:n
+      {
+        \@@_user_to_tstr:NTF \g_@@_read_prop { } { }
+        \int_compare:nNnF { \l_@@_tstr_tl } = { \l_@@_user_int }
+          {
+            \prop_gremove:NV \g_@@_read_prop \l_@@_user_int
+            \seq_gput_left:NV \g_@@_read_seq \l_@@_tstr_tl
+          }
+        \@@_tex_closein:w \l_@@_tstr_tl \exp_stop_f:
+      }
   }
 %    \end{macrocode}
 % \end{macro}
 %
-% \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.
+% \subsection{Writing}
 %
-%   We then put the stream and its associated file name in the property
-%   list, and empty/create the corresponding token list.
+% Writing is much harder than reading for several reasons.
+%
+% Contrarily to reading, it is possible to 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} (like we did for reading), 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}[aux, updated = 2012-12-05]{\@@_immediate:w}
+% \begin{macro}[aux]{\@@_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.  This code performs
+%   too much expansion for some nonsensical uses of \tn{noexpand} after
+%   \tn{immediate}.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_immediate_openout_aux:n #1
+\cs_new_protected:Npn \@@_immediate:w
+  { \primargs_read_x_token:N \@@_immediate_auxii: }
+\cs_new_protected:Npn \@@_immediate_auxii:
   {
-    \@@_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 }
+    \token_if_eq_meaning:NNTF \g_primargs_token \s_@@
+      { \@@_immediate_auxiii:N }
+      { \@@_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 write}
+% \subsubsection{Immediate actions}
 %
-% \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.
+% 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.  Here, we implement the immediate versions only.
+%
+% \begin{macro}[aux]{\@@_closeout:w, \@@_closeout_now:, \@@_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 \@@_immediate_write_test:n #1
+\cs_new_protected:Npn \@@_closeout:w
   {
-    \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 }
+    \s_@@
+    \use_i:nn
+      { \@@_get_user:n { \@@_closeout_later: } }
+      { \@@_get_user:n { \@@_closeout_now: } }
   }
+\cs_new_protected:Npn \@@_closeout_now:
+  {
+    \@@_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 \scan_stop:
+    \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}[aux]{\@@_immediate_write_aux:n}
-%   Test whether the stream is allocated or not.
+% \begin{macro}[aux]{\@@_openout:w, \@@_openout_now: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_nopar:Npn \@@_immediate_write_aux:n
+\cs_new_protected:Npn \@@_openout:w
   {
-    \prop_get:NVNTF \g_@@_iow_prop \g_@@_stream_int \l_@@_internal_tl
-      { \@@_immediate_write_open:n }
-      { \@@_immediate_write_closed:n }
+    \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
+  {
+    \@@_closeout_now:
+    \seq_pop: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} \scan_stop:
+      }
+      {
+        \@@_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 } }
+      }
+  }
 %    \end{macrocode}
 % \end{macro}
 %
-% \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{macro}[aux]{\@@_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 \@@_immediate_write_closed:n #1
+\cs_new_protected:Npn \@@_write:w
   {
-    \@@_tex_immediate:w \@@_tex_write:w
-      \if_int_compare:w \g_@@_stream_int < \c_zero
-        -1
-      \else:
-        16
-      \fi:
-      {#1}
+    \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
+      { \@@_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
+  {
+    \prop_get:NVNTF \g_@@_write_file_prop \l_@@_user_int \l_@@_internal_tl
+      { \@@_write_now_open:n }
+      { \@@_tex_immediate:w \@@_tex_write:w 16 }
+  }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[aux]{\@@_immediate_write_open:n}
-% \begin{macro}[aux]{\@@_immediate_write_readlines_loop:}
+% \begin{macro}[aux]{\@@_write_now_open:n}
+% \begin{macro}[aux]{\@@_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, 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,
+%   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 \@@_immediate_write_open:n #1
+\cs_new_protected:Npn \@@_write_now_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
+    \bool_if:NF \g_@@_tmp_file_bool { \@@_chk_file: }
+    \@@_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:
+      \int_set:Nn \tex_endlinechar:D { -1 }
+      \tex_openin:D \g_@@_ior = \g_@@_tmp_file_tl \scan_stop:
+      \@@_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_nopar:Npn \@@_immediate_write_readlines_loop:
+\cs_new_protected:Npn \@@_write_now_loop:
   {
     \etex_readline:D \g_@@_ior to \l_@@_internal_tl
     \ior_if_eof:NF \g_@@_ior
       {
-        \tl_gput_right:cx
-          { g_@@_iow_ \int_use:N \g_@@_stream_int _tl }
+        \@@_collect:x
           {
-            \@@_tex_immediate:w \@@_tex_write:w \g_@@_iow
-              { \l_@@_internal_tl }
+            \@@_tex_immediate:w \@@_tex_write:w
+              \g_@@_iow { \l_@@_internal_tl }
           }
-        \@@_immediate_write_readlines_loop:
+        \@@_write_now_loop:
       }
   }
 %    \end{macrocode}
@@ -573,108 +1017,88 @@
 % \end{macro}
 %
 %
-% \subsection{Non-immediate writing}
+% \subsubsection{Delayed actions}
 %
-% 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.
-%
-% \subsubsection{Replacement for primitives}
-%
-% \begin{macro}[aux]{\@@_late:n}
+% \begin{macro}[aux]{\@@_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_@@_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.
+%   non-immediately write the label \cs{g_@@_later_int} of the
+%   output operation to the temporary file.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_late:n #1
+\cs_new_protected:Npn \@@_later:n #1
   {
-    \int_gincr:N \g_@@_late_write_int
+    \int_gincr:N \g_@@_later_int
     \tl_const:cx
       {
-        c_@@_late_write_
-        \int_use:N \g_@@_late_write_int
+        c_@@_later_
+        \int_use:N \g_@@_later_int
         _tl
       }
       {
-        \int_gset:Nn \exp_not:N \g_@@_stream_int
-          { \exp_not:V \g_@@_stream_int }
+        \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_@@_late_write_int ) }
+      { `( \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}[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{macro}[aux]{\@@_closeout_later:}
+%   If the user stream is a \TeX{} stream, use the primitive, otherwise
+%   save \cs{@@_closeout_now:} for later.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_openout:w
-  { \s_@@ \primargs_get_number:N \@@_openout_test:n }
-\cs_new_protected:Npn \@@_openout_test:n #1
+\cs_new_protected:Npn \@@_closeout_later:
   {
-    \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 }
+    \int_compare:nNnTF \l_@@_user_int < { 19 }
+      { \@@_tex_closeout:w \l_@@_user_int }
+      { \@@_later:n { \@@_closeout_now: } }
   }
-\cs_new_protected:Npn \@@_openout_aux:n #1
-  { \@@_late:n { \@@_immediate_openout_aux:n {#1} } }
 %    \end{macrocode}
 % \end{macro}
-% \end{macro}
 %
-% \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{macro}[aux]{\@@_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:n} later.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_write:w
-  { \s_@@ \primargs_get_number:N \@@_write_test:n }
-\cs_new_protected:Npn \@@_write_test:n #1
+\cs_new_protected:Npn \@@_openout_later:w
   {
-    \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 }
+    \int_compare:nNnTF \l_@@_user_int < { 19 }
+      { \@@_tex_openout:w \l_@@_user_int }
+      { \@@_equals_file:N \@@_openout_later:n }
   }
-\cs_new_protected:Npn \@@_write_aux:n #1
-  { \@@_late:n { \@@_immediate_write_aux:n {#1} } }
+\cs_new_protected:Npn \@@_openout_later:n #1
+  { \@@_later:n { \@@_openout_now:n {#1} } }
 %    \end{macrocode}
 % \end{macro}
-% \end{macro}
 %
-% \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{macro}[aux]{\@@_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_nopar:Npn \@@_closeout:w
-  { \s_@@ \primargs_get_number:N \@@_closeout_test:n }
-\cs_new_protected:Npn \@@_closeout_test:n #1
+\cs_new_protected:Npn \@@_write_later:w
   {
-    \int_gset:Nn \g_@@_stream_int {#1}
-    \clist_if_in:NnTF \g_@@_reserved_iow_clist {#1}
-      { \@@_tex_closeout:w \g_@@_stream_int }
-      { \@@_closeout_aux: }
+    \int_compare:nNnTF \l_@@_user_int < { 19 }
+      { \@@_tex_write:w \l_@@_user_int }
+      { \primargs_get_general_text:N \@@_write_later:n }
   }
-\cs_new_protected_nopar:Npn \@@_closeout_aux:
-  { \@@_late:n { \@@_immediate_closeout_aux: } }
+\cs_new_protected:Npn \@@_write_later: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: }
+      { \@@_write_now:n }
+  }
 %    \end{macrocode}
 % \end{macro}
-% \end{macro}
 %
 % \subsubsection{Shipout business}
 %
-% In this section, we hook into the \cs{shipout} primitive, and redefine
+% 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:} \\
@@ -681,24 +1105,23 @@
 %   \meta{primitive shipout} \meta{collected box} \\
 %   \cs{@@_after_shipout:}
 % \end{quote}
-% This is correct even if the values of the \tn{newlinechar} is changed
-% within the user code which builds the shipped out box, because the
-% value that \TeX{} uses is the value in effect immediately after
-% \tn{shipout}.
 %
+% 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}[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.
+%   \cs{g_@@_iow} (after making sure we are allowed to alter the
+%   auxiliary file).
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_before_shipout:
+\cs_new_protected:Npn \@@_before_shipout:
   {
-    \@@_tex_immediate:w \@@_tex_openout:w \g_@@_iow
-      \g_@@_tmp_file_tl \scan_stop:
+    \bool_if:NF \g_@@_tmp_file_bool { \@@_chk_file: }
+    \@@_tex_immediate:w \@@_tex_openout:w
+      \g_@@_iow = \g_@@_tmp_file_tl \scan_stop:
   }
 %    \end{macrocode}
 % \end{macro}
@@ -715,7 +1138,7 @@
 %   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
+%   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
@@ -722,9 +1145,10 @@
 %   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:
+\cs_new_protected:Npn \@@_after_shipout:
   {
-    \@@_tex_immediate:w \@@_tex_closeout:w \g_@@_iow
+    \@@_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 }
@@ -731,14 +1155,15 @@
       \tl_map_inline:nn { `(0123456789) }
         { \char_set_catcode_other:n {`##1} }
       \etex_everyeof:D { `() \exp_not:N }
-      \tl_gset:Nx \g_@@_internal_tl
+      \tl_set:Nx \l_@@_internal_tl
         {
           \exp_after:wN \@@_after_shipout_loop:ww
           \tex_input:D \g_@@_tmp_file_tl \c_space_tl
         }
+      \@@_empty_file:n { \g_@@_tmp_file_tl }
+      \exp_args:NNo
     \group_end:
-    \tl_map_inline:Nn \g_@@_internal_tl
-      { \tl_use:c { c_@@_late_write_ ##1 _tl } }
+    \tl_map_function:nN { \l_@@_internal_tl } \@@_later_do:n
   }
 \cs_new:Npn \@@_after_shipout_loop:ww #1 `( #2 )
   {
@@ -752,141 +1177,164 @@
 % \end{macro}
 % \end{macro}
 %
-% \begin{macro}[aux]{\shipout}
 % \begin{macro}[aux]{\@@_shipout:w}
-% \begin{variable}{\g_@@_group_level_int, \g_@@_shipout_box}
-%   If \pkg{atbegshi} is available, patch it by adding
-%   \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{macro}[aux]{\@@_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}
-\IfFileExists{atbegshi.sty}
+\cs_new_protected:Npn \@@_shipout:w
   {
-    \RequirePackage{atbegshi}
-    \tl_replace_once:Nnn \AtBegShi at Output
-      { \AtBegShi at OrgShipout \box \AtBeginShipoutBox }
-      {
-        \@@_before_shipout:
-        \AtBegShi at OrgShipout \box \AtBeginShipoutBox
-        \@@_after_shipout:
-      }
-    \tl_replace_once:Nnn \AtBegShi at Output
-      { \AtBeginShipoutOriginalShipout \box \AtBeginShipoutBox }
-      {
-        \@@_before_shipout:
-        \AtBeginShipoutOriginalShipout \box \AtBeginShipoutBox
-        \@@_after_shipout:
-      }
+    \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:Npn \@@_shipout_i:
   {
-    \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_@@_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 \@@_shipout_i:
-      {
-        \int_compare:nNnTF { \g_@@_group_level_int }
-                         = { \etex_currentgrouplevel:D }
-          { \@@_shipout_ii: }
-          { \tex_aftergroup:D \@@_shipout_ii: }
-      }
-    \cs_new_protected_nopar:Npn \@@_shipout_ii:
-      {
-        \@@_before_shipout:
-        \@@_tex_shipout:w \tex_box:D \g_@@_shipout_box
-        \@@_after_shipout:
-      }
-    \AtBeginDocument { \cs_gset_eq:NN \shipout \@@_shipout:w }
+    \int_compare:nNnTF { \g_@@_group_level_int }
+                     = { \etex_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{variable}
 % \end{macro}
 % \end{macro}
 %
-% \subsection{Hook at the very end}
-%
-% \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{macro}[aux]{\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}
-\int_new:N \g_@@_at_end_int
-\int_gset:Nn \g_@@_at_end_int { 10 }
+\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 at shipout
+    \PDFSYNCship at ut@ld
+    \CROP at shipout
+    \@soORI
+    \tex_shipout:D
+    \zwpl at Hship
+    \o at shipout@TP
+    \LL at shipout
+    \Shipout
+    \GXTorg at shipout
+    \AtBegShi at OrgShipout
+    \AtBeginShipoutOriginalShipout
+    \shipout
+  }
+  {
+    \str_if_eq_x:nnT
+      { \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{variable}
+% \end{macro}
 %
+% \subsubsection{Hook at the very end}
+%
 % \begin{macro}[aux]{\@@_close_all:}
 %   At the end of the document, close all the files.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_close_all:
+\cs_new_protected:Npn \@@_close_all:
   {
-    \prop_map_function:NN \g_@@_iow_prop
-      \@@_immediate_write_and_close:nn
-    \prop_gclear:N \g_@@_iow_prop
+    \prop_map_function:NN \g_@@_write_prop
+      \@@_closeout_now:nn
+    \prop_gclear:N \g_@@_write_prop
   }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[aux]{\@@_close_all_at_end:w}
-%   This pushes its first argument to the very end of the \LaTeX{} run,
-%   recursively (at most $10$ times, initial value of
-%   \cs{g_@@_at_end_int}), just in case some other code adds things
-%   there.
+% \begin{macro}[aux]{\@@_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_set:Npn \@@_tmp:w #1
+\cs_new_protected:Npn \@@_close_all_at_end:nw #1#2 \@@@@end
   {
-    \cs_new_protected:Npn \@@_close_all_at_end:w ##1 #1
-      {
-        \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
-      }
+    \int_compare:nNnTF {#1} > \c_zero
+      { #2 \@@_close_all_at_end:nw { #1 - 1 } }
+      { \@@_close_all: #2 }
+    \@@@@end
   }
-\exp_args:Nc \@@_tmp:w { @ @ end }
-\AtEndDocument { \@@_close_all_at_end:w }
+\AtEndDocument { \@@_close_all_at_end:nw { 5 } }
 %    \end{macrocode}
 % \end{macro}
 %
-% \subsection{Modified \cs{newwrite}}
+% \subsection{Redefining commands}
 %
-% \begin{variable}{\g_@@_alloc_int}
-%   The counter that \LaTeXe{} uses to allocate \tn{write} registers.
+% \subsubsection{Modified \tn{newwrite}}
+%
+% \begin{variable}[aux]{\g_@@_alloc_read_int, \g_@@_alloc_write_int}
+%   Counters to allocate user streams.  Initialized to $18$ so that the
+%   first user stream allocated by \pkg{morewrites} is $19$.  Indeed,
+%   $18$ is reserved for shell commands and packages may expect $16$ or
+%   $17$ to write to the terminal.
 %    \begin{macrocode}
-\tex_countdef:D \g_@@_alloc_int 17 \scan_stop:
+\int_new:N \g_@@_alloc_read_int
+\int_set:Nn \g_@@_alloc_read_int { 18 }
+\int_new:N \g_@@_alloc_write_int
+\int_set:Nn \g_@@_alloc_write_int { 18 }
 %    \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$,
-%   to be on the safe side.  This really ought to be \tn{protected}, but
-%   none of the formats does that.
+% \begin{macro}[aux]{\@@_newread:N}
+%   Reimplementation of \tn{newread} but protected and using a counter
+%   \cs{g_@@_alloc_read_int} instead of what \TeX{}/\LaTeXe{} use.
 %    \begin{macrocode}
-\cs_new:Npn \@@_newwrite:N #1
+\cs_new_protected:Npn \@@_newread:N #1
   {
-    \int_gincr:N \g_@@_alloc_int
-    \if_int_compare:w \g_@@_alloc_int = \c_sixteen
-      \int_gset:Nn \g_@@_alloc_int { 20 }
-    \fi:
-    \int_set_eq:NN \allocationnumber \g_@@_alloc_int
+    \int_gincr:N \g_@@_alloc_read_int
+    \int_set_eq:NN \allocationnumber \g_@@_alloc_read_int
     \cs_undefine:N #1
     \int_const:Nn #1 { \allocationnumber }
     \wlog
       {
         \token_to_str:N #1
+        = \token_to_str:N \read \int_use:N \allocationnumber
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\@@_newwrite:N}
+%   Same as for \tn{newread}.
+%    \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
       }
   }
@@ -893,12 +1341,61 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \subsection{Redefining the ``normal'' control sequences}
+% \begin{macro}[aux]{\@@_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_put_right:NV \g_@@_write_seq \l_@@_tstr_token
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
 %
-% \begin{macro}[aux, updated = 2012-12-05]{\immediate}
-% \begin{macro}[aux]{\openout, \write, \closeout, \newwrite}
-%   \tn{shipout} has been redefined earlier.
+% \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
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[updated = 2015-08-01]
+%   {
+%     \openin, \read, \readline, \closein, \newread,
+%     \immediate, \openout, \write, \closeout, \newwrite
+%   }
+%    \begin{macrocode}
+\cs_gset_eq:NN \openin    \@@_openin:w
+\cs_gset_eq:NN \read      \@@_read:w
+\cs_gset_eq:NN \readline  \@@_readline:w
+\cs_gset_eq:NN \closein   \@@_closein:w
+\cs_gset_eq:NN \newread   \@@_newread:N
 \cs_gset_eq:NN \immediate \@@_immediate:w
 \cs_gset_eq:NN \openout   \@@_openout:w
 \cs_gset_eq:NN \write     \@@_write:w
@@ -906,10 +1403,10 @@
 \cs_gset_eq:NN \newwrite  \@@_newwrite:N
 %    \end{macrocode}
 % \end{macro}
-% \end{macro}
 %
 %</package>
 %
 % \end{implementation}
 %
-% \endinput
+% \clearpage
+% \PrintIndex

Modified: trunk/Master/texmf-dist/source/latex/morewrites/primargs.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/morewrites/primargs.dtx	2017-04-16 22:19:27 UTC (rev 43861)
+++ trunk/Master/texmf-dist/source/latex/morewrites/primargs.dtx	2017-04-16 22:19:40 UTC (rev 43862)
@@ -1,6 +1,6 @@
 % \iffalse meta-comment
 %
-%% File: primargs.dtx Copyright (C) 2012-2013 Bruno Le Floch
+%% File: primargs.dtx Copyright (C) 2012-2017 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
@@ -21,10 +21,9 @@
 % \fi
 %
 % \title{The \textsf{primargs} package: \\
-%   Parsing arguments of primitives\thanks{This
-%     file has version number v0.2e, last revised 2013/01/08.}}
+%   Parsing arguments of primitives}
 % \author{Bruno Le Floch}
-% \date{2013/01/08}
+% \date{2017/04/10}
 %
 % \maketitle
 % \tableofcontents
@@ -33,103 +32,196 @@
 %
 % \section{\pkg{primargs} documentation}
 %
-% This \LaTeX{} package is currently used by \pkg{morewrites} when
-% redefining primitives: it allows to read arguments of primitives in
-% place of \TeX{}.  Of course, this is much slower than letting \TeX{}
-% do things directly, but it may not be possible.
+% This \TeX{} and \LaTeX{} package is currently used by \pkg{morewrites}
+% when redefining primitives: it allows to read arguments of primitives
+% in place of \TeX{}, which is useful to add hooks to primitives.  Of
+% course, this is much slower than letting \TeX{} do things directly.
 %
-% \subsection{Read one token}
+% All assignments done by this package are global.  While a negative
+% value of the \tn{globaldefs} (primitive) parameter normally makes all
+% assignments local, this package makes sure \tn{globaldefs} is
+% non-negative before assignments.
 %
-% \begin{variable}{\g_primargs_token}
-%   The result of \cs{primargs_read_x_token:N} and
-%   \cs{primargs_read_token:N}.
+% \subsection{Reading one token without removing it}
+%
+% \begin{variable}[tested = primargs001]{\g_primargs_token}
+%   The token read by \cs{primargs_read_token:N} or
+%   \cs{primargs_read_x_token:N}.  Its value is always set globally.
+%   It can be an \tn{outer} macro.
 % \end{variable}
 %
-% \begin{function}{\primargs_read_x_token:N}
+% \begin{function}[tested = primargs001]{\primargs_read_token:N}
 %   \begin{syntax}
-%     \cs{primargs_read_x_token:N} \meta{function}
+%     \cs{primargs_read_token:N} \meta{function}
 %   \end{syntax}
-%   Expands tokens recursively with \cs{exp_after:wN}, until
-%   encountering a non-expandable token, and calls the \meta{function}
-%   afterwards.  The non-expandable token found is stored as
-%   \cs{g_primargs_token}.
+%   Sets \cs{g_primargs_token} equal to the token following the
+%   \meta{function}, then calls the \meta{function}.  The token
+%   following the \meta{function} is not removed.
+%   \begin{texnote}
+%     This is essentially \tn{global} \tn{futurelet}
+%     \cs{g_primargs_token} \meta{function}, with the added guarantee
+%     that the assignment is global even when $\tn{globaldefs}$ is negative.
+%   \end{texnote}
 % \end{function}
 %
-% \begin{function}{\primargs_read_token:N}
+% \begin{function}[tested = primargs001]{\primargs_read_x_token:N}
 %   \begin{syntax}
-%     \cs{primargs_read_token:N} \meta{function}
+%     \cs{primargs_read_x_token:N} \meta{function}
 %   \end{syntax}
-%   Sets \cs{g_primargs_token} globally to the value of the next token,
-%   then calls the \meta{function}.
+%   Expands tokens recursively with \cs{exp_after:wN} until encountering
+%   a non-expandable token and afterwards calls the \meta{function}.
+%   The non-expandable token following the \meta{function} is not
+%   removed and \cs{g_primargs_token} is also set (globally) equal to
+%   that token.
 % \end{function}
 %
-% \subsection{Grabbing arguments}
+% \subsection{Removing tokens}
 %
-% A whole lot of functions have the same syntax:
-% \begin{syntax}
-%   \cs{primargs_get_\meta{foo}:N} \meta{function}
-% \end{syntax}
-% Finds what \TeX{}'s grammar calls a \meta{foo} in the input stream,
-% and feeds its value as a braced argument to the \meta{function}.  Here
-% is a list of the functions currently defined:
-% \begin{itemize}
-%   \item \cs{primargs_get_number:N}
-%   \item \cs{primargs_get_dimen:N}
-%   \item \cs{primargs_get_glue:N}
-%   \item \cs{primargs_get_mudimen:N} (\emph{not implemented properly})
-%   \item \cs{primargs_get_muglue:N}
-%   \item \cs{primargs_get_general_text:N}
-%   \item \cs{primargs_get_file_name:N}
-% \end{itemize}
-%
-% \subsection{Discarding tokens}
-%
-% \begin{function}{\primargs_remove_token:N}
+% \begin{function}[tested = primargs005]{\primargs_remove_token:N}
 %   \begin{syntax}
 %     \cs{primargs_remove_token:N} \meta{function}
 %   \end{syntax}
-%   Removes one \meta{token} following the \meta{function}, which is
-%   performed next.
+%   Removes the \meta{token} which follows the \meta{function}, then
+%   calls the \meta{function}.  This also sets \cs{g_primargs_token}
+%   (globally) equal to the removed token.
 % \end{function}
 %
-% \begin{function}{\primargs_remove_one_optional_space:N}
+% \begin{function}[tested = primargs005]{\primargs_remove_one_optional_space:N}
 %   \begin{syntax}
 %     \cs{primargs_remove_one_optional_space:N} \meta{function}
 %   \end{syntax}
-%   Removes \meta{one optional space} after the \meta{function}.
+%   Expands tokens following the \meta{function} until a non-expandable
+%   token is found, and sets \cs{g_primargs_token} (globally) equal to this token,
+%   then removes the token if it has catcode~$10$ (space).  Finally,
+%   call the \meta{function}.
 % \end{function}
 %
-% \begin{function}{\primargs_remove_optional_spaces:N}
+% \begin{function}[tested = primargs005]{\primargs_remove_optional_spaces:N}
 %   \begin{syntax}
 %     \cs{primargs_remove_optional_spaces:N} \meta{function}
 %   \end{syntax}
-%   Removes \meta{optional spaces} after the \meta{function}.
+%   Expands tokens following the \meta{function}, removing any token
+%   with catcode~$10$ (space), then sets \cs{g_primargs_token} (globally) equal to
+%   the first non-space token and calls the \meta{function}.
 % \end{function}
 %
-% \begin{function}{\primargs_remove_equals:N}
+% \begin{function}[tested = primargs005]{\primargs_remove_equals:N}
 %   \begin{syntax}
 %     \cs{primargs_remove_equals:N} \meta{function}
 %   \end{syntax}
-%   Removes \meta{equals}, namely \meta{optional spaces} followed
-%   optionally by an explicit |=| character with category other.
+%   Expands tokens following the \meta{function}, removing any token
+%   with catcode~$10$ (space), then sets \cs{g_primargs_token} (globally) equal to
+%   the first non-space token.  If this token is an explicit~|=|
+%   character token with catcode~$12$ (other), then it is removed as
+%   well.  Finally, calls the \meta{function}.
 % \end{function}
 %
-% \subsection{Afterassignment and \tn{globaldefs}}
+% \begin{function}[added = 2014-08-06, tested = primargs005]{\primargs_remove_filler:N}
+%   \begin{syntax}
+%     \cs{primargs_remove_filler:N} \meta{function}
+%   \end{syntax}
+%   Expands tokens following the \meta{function}, removing any token
+%   with catcode~$10$ (space) or equal to \tn{relax}, then sets
+%   \cs{g_primargs_token} (globally) equal to the next
+%   token.  Finally, calls the \meta{function}.
+% \end{function}
 %
-% The \tn{globaldefs} parameter is not taken into account yet, and
-% setting it to a non-zero value may make everything crash.  It is
-% straightforward to fix that for negative \tn{globaldefs}, but positive
-% \tn{globaldefs} make things complicated.
+% \subsection{Grabbing arguments}
 %
-% Tokens inserted using \tn{afterassignment} may be lost when using this
-% package, since it uses \tn{afterassignment} internally.
+% \begin{function}[tested = primargs002]
+%   {
+%     \primargs_get_number:N,
+%     \primargs_get_dimen:N,
+%     \primargs_get_glue:N,
+%     \primargs_get_mudimen:N,
+%     \primargs_get_muglue:N,
+%   }
+%   \begin{syntax}
+%     \cs{primargs_get_number:N} \meta{function}
+%   \end{syntax}
+%   Reads a number/dimension/glue/math dimension/math glue following the
+%   \meta{function}, then calls the \meta{function} with a braced
+%   argument containing the value found.  For instance,
+%   \begin{verbatim}
+%     \primargs_get_glue:N \test 3sp plus \numexpr 2-3 fill X
+%   \end{verbatim}
+%   yields
+%   \begin{verbatim}
+%     \test {3sp plus -1fill}X
+%   \end{verbatim}
+%   A word of warning: the \cs{primargs_get_mudimen:N} function
+%   currently parses a \meta{muskip} instead of a \meta{mudimen}.
+% \end{function}
 %
-% \subsection{Internal functions}
+% \begin{function}[updated = 2014-08-06, tested = primargs003]
+%   {\primargs_get_general_text:N}
+%   \begin{syntax}
+%     \cs{primargs_get_general_text:N} \meta{function}
+%   \end{syntax}
+%   Finds what \TeX{}'s grammar calls a \meta{general text} (that is, a
+%   \meta{filler}, a catcode~$1$ token, a \meta{balanced text}, and an
+%   explicit catcode~$2$ token) following the \meta{function}, and calls
+%   the \meta{function} with the \meta{balanced text} as a braced
+%   argument.
+% \end{function}
 %
-% \begin{function}{\@@_get_rhs:NnN, \@@_get_rhs:NoN}
+% \begin{function}[updated = 2017-04-10, tested = primargs004]{\primargs_get_file_name:N, \primargs_get_input_file_name:N}
 %   \begin{syntax}
-%     \cs{@@_get_rhs:NnN} \meta{register} \Arg{register rhs} \meta{function}
+%     \cs{primargs_get_file_name:N} \meta{function}
+%     \cs{primargs_get_input_file_name:N} \meta{function}
 %   \end{syntax}
+%   Reads a \meta{file name} following the \meta{function} and calls the
+%   \meta{function} with this \meta{file name} as a braced argument.
+%   The two functions are identical except in the \LuaTeX{} engine where
+%   \cs{primargs_get_input_file_name:N} allows braced file names:
+%   \LuaTeX{} allows such braced file names for some primitives (\tn{input}
+%   and \tn{openin}) but not others (\tn{openout}).
+%   \begin{texnote}
+%     When braced file names are disallowed, the file name is obtained
+%     by discarding \meta{optional spaces} then repeatedly doing the
+%     following.  Fully expand what follows in the input stream.  If
+%     the next token is an explicit or implicit character token
+%     (regardless of its catcode) then add that character to the
+%     file name and remove it from the input stream, and go back to
+%     expanding tokens, except in one case: if the character code
+%     is~$32$ (space) and the number of quote characters (code~$34$)
+%     already in the file name is even, then the space is removed from
+%     the input stream, not included in the file name, and parsing
+%     ends.  Finally, if the next token is a non-expandable command
+%     (be it a control sequence or an active character) then the file
+%     name ends and the command is left in the input stream.
+%
+%     When braced file names are allowed, the following steps are added
+%     prior to the procedure above.  First remove a \meta{filler}.  If
+%     the next token is of catcode~$1$ then fully expand tokens one by
+%     one and add their string representation (with \cs{tl_to_str:n},
+%     not \cs{token_to_str:N}) to the file name.
+%   \end{texnote}
+% \end{function}
+%
+% \subsection{Comments and internal functions}
+%
+% This package is not idiomatic \pkg{expl3} and should not be used as an
+% example of good coding practices.  It uses \cs[no-index]{\ldots{}:D}
+% primitives directly:
+% \begin{itemize}
+% \item to cope with \tn{outer} tokens, since this package is meant to
+%   be used quite broadly;
+% \item for primitives with (rightfully) no \pkg{expl3} interface (or a
+%   slightly incomplete interface), namely \tn{afterassignment},
+%   \tn{globaldefs}, \tn{aftergroup}, \tn{the}, \tn{deadcycles},
+%   \tn{hoffset}, \tn{topskip}, \tn{thinmuskip}, \tn{unexpanded};
+% \item to test that a token's meaning is a given primitive when the
+%   \pkg{expl3} interface is not (or not obviously) a copy of the primitive.
+% \end{itemize}
+% As a result, \emph{do not take this package as an example of how to
+% code with \pkg{expl3}; go and see Joseph Wright's \pkg{siunitx} for
+% instance.}
+%
+% \begin{function}{\__primargs_get_rhs:NnN, \__primargs_get_rhs:NoN}
+%   \begin{syntax}
+%     \cs{__primargs_get_rhs:NnN} \meta{register} \Arg{register rhs} \meta{function}
+%   \end{syntax}
 %   Use the \meta{register} to find a right-hand side of a valid
 %   assignment for this type of variable, and feed the value found to
 %   the \meta{function}.  The value of the \meta{register} is then
@@ -140,6 +232,28 @@
 %   cause trouble with others.
 % \end{function}
 %
+% Despite large efforts expended to make this package robust against
+% changes to the \tn{globaldefs} parameter, setting it to a non-zero
+% value may make some parts of this package crash.
+%
+% Tokens inserted using \tn{afterassignment} may be lost when using this
+% package, since it uses \tn{afterassignment} internally.
+%
+% Todo list.
+% \begin{itemize}
+% \item Test all functions within alignments and understand their
+%   interaction with the master counter.
+% \item Correct the parsing of \meta{mudimen}.
+% \item Perhaps parse \meta{muglue} and \meta{glue} by hand to avoid bad
+%   interactions with \tn{globaldefs}.  Otherwise put up a warning about
+%   \tn{globaldefs} when relevant.  Better partial fix: declare a skip and a muskip.
+% \item Write tests of engine behaviour, especially \LuaTeX{}'s \tn{input},
+%   \tn{openin}, \tn{openout} including behaviour of |#| and spaces and
+%   character-code-zero, to detect unexpected changes.  In
+%   \tn{input}|{|\ldots{}\tn{input}\ldots{}|}|, \LuaTeX{} expands the
+%   inner \tn{input} but uses the inner file name as the outer file name.
+% \end{itemize}
+%
 % \end{documentation}
 %
 % \begin{implementation}
@@ -148,9 +262,9 @@
 %
 %<*package>
 %    \begin{macrocode}
-\RequirePackage {expl3} [2012/08/14]
+\RequirePackage {expl3} [2017/03/18]
 \ProvidesExplPackage
-  {primargs} {2013/01/08} {0.2e} {Parsing arguments of primitives}
+  {primargs} {2017/04/10} {} {Parsing arguments of primitives}
 %    \end{macrocode}
 %
 %    \begin{macrocode}
@@ -157,32 +271,38 @@
 %<@@=primargs>
 %    \end{macrocode}
 %
-% \subsection{Helpers}
+% \subsection{Variables and helpers}
 %
 % \begin{macro}[aux]{\g_@@_code_tl}
 %   Used to contain temporary code.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \g_@@_code_tl { }
+\tl_new:N \g_@@_code_tl
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[aux]{\@@_no_afterassignment:}
-%   Supersedes any \tn{afterassignment} token.
+% \begin{variable}[int]{\g_@@_file_name_tl, \g_@@_file_name_level_tl}
+%   Token list used to build a file name, one character at a time.
+%   Token list holding the level of nesting in quotes or braces.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_no_afterassignment:
-  { \tex_afterassignment:D \tex_relax:D }
+\tl_new:N \g_@@_file_name_tl
+\tl_new:N \g_@@_file_name_level_tl
 %    \end{macrocode}
-% \end{macro}
+% \end{variable}
 %
-% \begin{macro}[aux]{\@@_no_localdefs:}
-%   This function, which must be called in a group, ensures that
-%   \tn{global} indeed makes definitions global.
+% \begin{macro}[aux]{\@@_safe:}
+%   This function, which must be called in a group, cancels any
+%   \tn{afterassignment} token and makes the \tn{globaldefs} parameter
+%   non-negative.  This ensures that assignments prefixed with
+%   \tn{global} are indeed global.  When \tn{globaldefs} is positive,
+%   every assignment is global, and it is not possible to safely
+%   (locally) set it to zero.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_no_localdefs:
+\cs_new_protected:Npn \@@_safe:
   {
-    \@@_no_afterassignment:
-    \int_compare:nNnF \tex_globaldefs:D > \c_zero
-      { \tex_globaldefs:D = \c_zero }
+    \tex_afterassignment:D \tex_relax:D
+    \if_int_compare:w 0 > \tex_globaldefs:D
+      \int_zero:N \tex_globaldefs:D
+    \fi:
   }
 %    \end{macrocode}
 % \end{macro}
@@ -191,22 +311,23 @@
 %
 % \TeX{} often calls the \proc{get_x_token} procedure when parsing
 % various parts of its grammar.  This expands tokens recursively until
-% reaching a non-expandable token.  We emulate this by expanding with
-% \tn{expandafter}, then checking whether the upcoming token is
-% expandable or not using \tn{futurelet}, and if it is, expanding again.
+% reaching a non-expandable token.  We emulate this by reading the next
+% token with \tn{futurelet}, checking whether it is expandable or not by
+% comparing its meaning to its meaning when acted upon by \tn{noexpand},
+% and expanding it with \tn{expandafter} if it is expandable.
 %
 % One thing to be careful about is that
 % \begin{quote}
-%   \tn{expandafter} \tn{show} \tn{noexpand} \cs{space}
+%   \tn{expandafter} \tn{show} \tn{noexpand} \tn{space}
 % \end{quote}
-% shows the \tn{meaning} of the \tn{notexpanded:} \cs{space},
+% shows the \tn{meaning} of the |\notexpanded: \space|,
 % namely \tn{relax} (frozen, in fact, hence a bit different from the
 % normal \tn{relax}), while expanding twice with
 % \begin{quote}
 %   \tn{expandafter} \tn{expandafter} \tn{expandafter} \tn{show}
-%   \tn{noexpand} \cs{space}
+%   \tn{noexpand} \tn{space}
 % \end{quote}
-% expands the \cs{space} to the underlying space character token.
+% expands the \tn{space} to the underlying space character token.
 % What this means is that we must first check if the token is expandable
 % or not, and only then expand, and that the token should not be queried
 % again using \tn{futurelet}.  On this latter point, run
@@ -214,52 +335,73 @@
 %   \def \test { \show \next \futurelet \next \test }
 %   \expandafter \test \noexpand \space
 % \end{verbatim}
-% to see how \cs{next} changes from \tn{relax} to becoming a macro.
+% to see how \tn{next} changes from \tn{relax} to becoming a macro.
 %
 % \begin{macro}{\primargs_read_x_token:N}
-% \begin{macro}[aux]{\@@_read_x_token:N, \@@_read_x_token_ii:N}
+% \begin{macro}[aux]
+%   {
+%     \@@_read_x_token:N, \@@_read_x_token_aux:N,
+%     \@@_read_x_token_std:N, \@@_read_x_token_file:N
+%   }
+%   This is a bit messy, because we need to support the fact that
+%   \TeX{} does not consider \tn{input} as expandable when it is
+%   looking for a file name.  This variation is encapsulated by
+%   letting \cs{@@_read_x_token_aux:N} equal to either a standard
+%   (\texttt{std}) version or a version specific to file names
+%   (\texttt{file}).
+%
 %   First query the following token.  Then test whether it is
 %   expandable, using a variant of the \cs{token_if_expandable:NTF}
 %   test.\footnote{This \LaTeX3 test returns \texttt{false} for
 %     undefined tokens (by design), but \TeX{}'s \proc{get_x_token}
 %     expands those undefined tokens, causing errors, so we should as
-%     well.}  If the token is expandable, \cs{exp_not:N} will change its
+%     well.} If the token is expandable, \cs{exp_not:N} will change its
 %   \tn{meaning} to \tn{relax}, the test is \texttt{false}, we expand,
-%   and call the loop.  Otherwise, we stop.  Interestingly, we don't
-%   ever need to take the user's function as an argument.
+%   and call the loop.  Otherwise, we stop.  In the \texttt{file}
+%   version there is an extra test for \cs{tex_input:D}.  By default
+%   use the standard version.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \primargs_read_x_token:N
+\cs_new_protected:Npn \primargs_read_x_token:N
   {
     \group_begin:
-      \@@_no_localdefs:
+      \@@_safe:
       \@@_read_x_token:N
   }
-\cs_new_protected_nopar:Npn \@@_read_x_token:N
+\cs_new_protected:Npn \@@_read_x_token:N
   {
-    \tex_afterassignment:D \@@_read_x_token_ii:N
+    \tex_afterassignment:D \@@_read_x_token_aux:N
     \tex_global:D \tex_futurelet:D \g_primargs_token
   }
-\cs_new_protected_nopar:Npn \@@_read_x_token_ii:N
+\cs_new_protected:Npn \@@_read_x_token_std:N
   {
     \exp_after:wN
     \if_meaning:w \exp_not:N \g_primargs_token \g_primargs_token
-      \group_end:
-      \exp_after:wN \use_none:nnn
+      \group_end: \use_i:nnnn
     \fi:
     \exp_after:wN \@@_read_x_token:N \exp_after:wN
   }
+\cs_new_eq:NN \@@_read_x_token_aux:N
+              \@@_read_x_token_std:N
+\cs_new_protected:Npn \@@_read_x_token_file:N
+  {
+    \if_meaning:w \tex_input:D \g_primargs_token
+      \use_i_ii:nnn \group_end:
+    \fi:
+    \@@_read_x_token_std:N
+  }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
 %
 % \begin{macro}{\primargs_read_token:N}
-%   The same without expansion, for use when we already know that what
-%   follows is expanded.
+%   The same without expansion, useful for instance when we already know
+%   that what follows is expanded.  Interestingly, we don't ever need to
+%   take the user's function as an argument.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \primargs_read_token:N
+\cs_new_protected:Npn \primargs_read_token:N
   {
     \group_begin:
-      \@@_no_localdefs:
+      \@@_safe:
       \tex_afterassignment:D \group_end:
       \tex_global:D \tex_futurelet:D \g_primargs_token
   }
@@ -268,17 +410,15 @@
 %
 % \subsection{Removing tokens}
 %
-% \subsubsection{One token}
-%
 % \begin{macro}{\primargs_remove_token:N}
 %   Remove token using \tn{let} (note the presence of |=| and a space,
 %   to correctly remove explicit space characters), then insert the
-%   \meta{function} with \tn{afterassignment}.
+%   \meta{function} after closing the group.
 %    \begin{macrocode}
 \cs_new_protected:Npn \primargs_remove_token:N #1
   {
     \group_begin:
-      \@@_no_localdefs:
+      \@@_safe:
       \tex_aftergroup:D #1
       \tex_afterassignment:D \group_end:
       \tex_global:D \tex_let:D \g_primargs_token = ~
@@ -286,10 +426,6 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \subsubsection{Optional space token}
-%
-% ^^A Not sure of the interaction with \notexpanded:
-%
 % \begin{macro}{\primargs_remove_one_optional_space:N}
 % \begin{macro}[aux]{\@@_remove_one_optional_space:}
 %   Start a group: we will insert the \meta{function} at its end.
@@ -297,13 +433,13 @@
 \cs_new_protected:Npn \primargs_remove_one_optional_space:N #1
   {
     \group_begin:
-      \@@_no_localdefs:
+      \@@_safe:
       \tex_aftergroup:D #1
       \primargs_read_x_token:N \@@_remove_one_optional_space:
   }
-\exp_args:NNo \cs_new_protected_nopar:Npn \@@_remove_one_optional_space:
+\cs_new_protected:Npn \@@_remove_one_optional_space:
   {
-    \use:n { \if_catcode:w } ~ \exp_not:N \g_primargs_token
+    \if_catcode:w \c_space_token \exp_not:N \g_primargs_token
       \exp_after:wN \primargs_remove_token:N
     \fi:
     \group_end:
@@ -314,21 +450,23 @@
 %
 % \begin{macro}{\primargs_remove_optional_spaces:N}
 % \begin{macro}[aux]
-%   {\@@_remove_optional_spaces:, \@@_remove_optional_spaces_ii:}
-%   Start a group: we will insert the \meta{function} at its end.
+%   {\@@_remove_optional_spaces:, \@@_remove_optional_spaces_aux:}
+%   Start a group, make assignments safe, then recursively expand tokens
+%   and remove any token with catcode~$10$ (space).  Once another token
+%   is found, close the group hence insert the \meta{function}~|#1|.
 %    \begin{macrocode}
 \cs_new_protected:Npn \primargs_remove_optional_spaces:N #1
   {
     \group_begin:
-      \@@_no_localdefs:
+      \@@_safe:
       \tex_aftergroup:D #1
       \@@_remove_optional_spaces:
   }
-\cs_new_protected_nopar:Npn \@@_remove_optional_spaces:
-  { \primargs_read_x_token:N \@@_remove_optional_spaces_ii: }
-\exp_args:NNo \cs_new_protected_nopar:Npn \@@_remove_optional_spaces_ii:
+\cs_new_protected:Npn \@@_remove_optional_spaces:
+  { \primargs_read_x_token:N \@@_remove_optional_spaces_aux: }
+\cs_new_protected:Npn \@@_remove_optional_spaces_aux:
   {
-    \use:n { \if_catcode:w } ~ \exp_not:N \g_primargs_token
+    \if_catcode:w \c_space_token \exp_not:N \g_primargs_token
       \exp_after:wN \primargs_remove_token:N
       \exp_after:wN \@@_remove_optional_spaces:
     \else:
@@ -340,9 +478,10 @@
 % \end{macro}
 %
 % \begin{macro}{\primargs_remove_equals:N}
-%   Remove \meta{optional spaces}, then test for an explicit |=|, both
-%   in \tn{meaning} and as a token list (once we know its \tn{meaning},
-%   we can grab it safely).
+% \begin{macro}[aux]{\@@_remove_equals:, \@@_remove_equals_aux:NN}
+%   Remove \meta{optional spaces}, then test for an explicit~|=|, both
+%   in \tn{meaning} and as a token list: once we know its \tn{meaning},
+%   we can grab it safely.
 %    \begin{macrocode}
 \cs_new_protected:Npn \primargs_remove_equals:N #1
   {
@@ -350,18 +489,61 @@
       \tex_aftergroup:D #1
       \primargs_remove_optional_spaces:N \@@_remove_equals:
   }
-\cs_new_protected_nopar:Npn \@@_remove_equals:
+\cs_new_protected:Npn \@@_remove_equals:
   {
       \if_meaning:w = \g_primargs_token
-        \exp_after:wN \@@_remove_equals_ii:NN
+        \exp_after:wN \@@_remove_equals_aux:NN
       \fi:
     \group_end:
   }
-\cs_new_protected:Npn \@@_remove_equals_ii:NN #1#2
+\cs_new_protected:Npn \@@_remove_equals_aux:NN #1#2
   { \tl_if_eq:nnTF { #2 } { = } { #1 } { #1 #2 } }
 %    \end{macrocode}
 % \end{macro}
+% \end{macro}
 %
+% \begin{macro}{\primargs_remove_filler:N}
+% \begin{macro}[aux]
+%   {
+%     \@@_remove_filler:,
+%     \@@_remove_filler_aux:,
+%     \@@_remove_filler_end:NNNNN
+%   }
+%   Within a group remove a \meta{filler}, and insert the user's |#1|
+%   after closing the group.  A \meta{filler} consists of tokens with
+%   catcode~$10$ (space) or equal to \tn{relax} or to the
+%   \enquote{frozen \tn{relax}} command.
+%    \begin{macrocode}
+\cs_new_protected:Npn \primargs_remove_filler:N #1
+  {
+    \group_begin:
+      \@@_safe:
+      \tex_aftergroup:D #1
+      \@@_remove_filler:
+  }
+\cs_new_protected:Npn \@@_remove_filler:
+  { \primargs_read_x_token:N \@@_remove_filler_aux: }
+\cs_new_protected:Npn \@@_remove_filler_aux:
+  {
+    \if_catcode:w \c_space_token \exp_not:N \g_primargs_token
+    \else:
+      \if_meaning:w \tex_relax:D \g_primargs_token
+      \else:
+        \exp_after:wN
+        \if_meaning:w \exp_not:N \prg_do_nothing: \g_primargs_token
+        \else:
+          \@@_remove_filler_end:NNNNN
+        \fi:
+      \fi:
+    \fi:
+    \primargs_remove_token:N \@@_remove_filler:
+  }
+\cs_new_protected:Npn \@@_remove_filler_end:NNNNN #1#2#3#4#5
+  { #1 #2 #3 \group_end: }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
 % \subsection{Right-hand sides of assignments}
 %
 % The naive approach to reading an integer, or a general text, is to let
@@ -376,15 +558,13 @@
 % assignments to the parameter itself, preventing us from setting it to
 % zero locally; hence, we are stuck with global assignments (if
 % \tn{globaldefs} is negative, we can change it, locally, to whatever
-% value pleases us, as done by \cs{@@_no_localdefs:}).  We may thus not
+% value pleases us, as done by \cs{@@_safe:}).  We may thus not
 % use scratch registers to parse integers, general texts, and other
 % pieces of \TeX{}'s grammar.
 %
 % For integers, we will use \tn{deadcycles}, a parameter which is
 % automatically assigned globally, and we revert it to its previous
-% value afterwards.  For general text, we will use \tn{errhelp}, which
-% we will assign locally if possible (\tn{globaldefs} negative or zero),
-% and otherwise reset to be empty.
+% value afterwards.
 %
 % \begin{macro}[int]{\@@_get_rhs:NnN, \@@_get_rhs:NoN}
 %   The last two lines of this function are the key: assign to |#1|,
@@ -397,7 +577,7 @@
 \cs_new_protected:Npn \@@_get_rhs:NnN #1#2#3
   {
     \group_begin:
-      \@@_no_localdefs:
+      \@@_safe:
       \tex_aftergroup:D #3
       \tl_gset:Nn \g_@@_code_tl
         {
@@ -419,7 +599,7 @@
 %   \tn{deadcycles}, for which all assignments are global: thus,
 %   restoring its value will not interact badly with groups.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \primargs_get_number:N
+\cs_new_protected:Npn \primargs_get_number:N
   {
     \@@_get_rhs:NoN \tex_deadcycles:D
       { \tex_the:D \tex_deadcycles:D }
@@ -433,7 +613,7 @@
 %   important since normally, \tn{globaldefs} is zero, and everything is
 %   done within a group).
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \primargs_get_dimen:N
+\cs_new_protected:Npn \primargs_get_dimen:N
   {
     \@@_get_rhs:NoN \tex_hoffset:D
       { \tex_the:D \tex_hoffset:D }
@@ -444,7 +624,7 @@
 % \begin{macro}{\primargs_get_glue:N}
 %   Use \tn{topskip}.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \primargs_get_glue:N
+\cs_new_protected:Npn \primargs_get_glue:N
   {
     \@@_get_rhs:NoN \tex_topskip:D
       { \tex_the:D \tex_topskip:D }
@@ -457,7 +637,7 @@
 %   own to parse a \meta{mudimen}.  Warn about that problem, and parse a
 %   \meta{muglue} instead.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \primargs_get_mudimen:N
+\cs_new_protected:Npn \primargs_get_mudimen:N
   {
     \msg_warning:nn { primargs } { get-mudimen }
     \primargs_get_muglue:N
@@ -470,7 +650,7 @@
 % \begin{macro}{\primargs_get_muglue:N}
 %   Use \tn{thinmuskip}.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \primargs_get_muglue:N
+\cs_new_protected:Npn \primargs_get_muglue:N
   {
     \@@_get_rhs:NoN \tex_thinmuskip:D
       { \tex_the:D \tex_thinmuskip:D }
@@ -479,44 +659,72 @@
 % \end{macro}
 %
 % \begin{macro}{\primargs_get_general_text:N}
-%   For a general text, use \tn{errhelp}, since it shouldn't be a big
-%   problem if that's changed.  We don't revert it to its value, but to
-%   be empty (note the extra braces, though, since it's a token
-%   register), because it is probably better to have no help than the
-%   wrong help hanging around.  Besides, \tn{errhelp} is always set
-%   for immediate use.
+% \begin{macro}[aux]
+%   {\@@_get_general_text:, \@@_get_general_text_error:n}
+%   Getting a \meta{general text} is more tricky, as an assignment to
+%   \tn{errhelp} (for instance) would also allow constructions such as
+%   |\toks0|.  Instead, we remove a \meta{filler} then test whether the
+%   next token (already expanded) is a catcode~$1$ token, in which case
+%   we replace it by an explicit left brace before calling the function.
+%   When the next token is not of catcode~$1$, we produce an error,
+%   attempting to imitate as closely as possible the \TeX{} error.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \primargs_get_general_text:N
-  { \@@_get_rhs:NoN \tex_errhelp:D { { } } }
+\cs_new_protected:Npn \primargs_get_general_text:N #1
+  {
+    \group_begin:
+      \@@_safe:
+      \tex_aftergroup:D #1
+      \tex_aftergroup:D { \if_false: } \fi:
+      \primargs_remove_filler:N \@@_get_general_text:
+  }
+\cs_new_protected:Npn \@@_get_general_text:
+  {
+    \if_catcode:w \c_group_begin_token \g_primargs_token
+      \exp_after:wN \primargs_remove_token:N
+    \else:
+      \group_begin:
+        \tex_aftergroup:D \@@_get_general_text_error:n
+        \if_catcode:w \c_group_end_token \g_primargs_token
+          \tex_aftergroup:D {
+          \tex_aftergroup:D }
+        \fi:
+    \fi:
+    \group_end:
+  }
+\cs_new_protected:Npn \@@_get_general_text_error:n #1
+  {
+    \exp_after:wN \group_end:
+    \etex_unexpanded:D \if_int_compare:w `{ = \c_zero \fi: #1 }
+  }
 %    \end{macrocode}
 % \end{macro}
+% \end{macro}
 %
 % \subsection{Get file name}
 %
-% ^^A todo: Figure out when \group_align_safe_begin: is needed.
-%
-% \begin{variable}{\g_@@_file_name_tl}
-%   Token list used to build a file name, one character at a time.
-%    \begin{macrocode}
-\tl_new:N \g_@@_file_name_tl
-%    \end{macrocode}
-% \end{variable}
-%
 % \begin{macro}{\primargs_get_file_name:N}
 %   Empty the file name (globally), and build it one character at a time.
 %   The \meta{function} is added at the end of a group, started here.
 %   As described in the \TeX{}book, a \meta{file name} should start with
-%   \meta{optional spaces}, which we remove, then character tokens,
+%   \meta{optional spaces} (\LuaTeX{} changes that to \meta{filler}),
+%   which we remove, then character tokens,
 %   ending with a non-expandable character or control sequence.  After
 %   space removal, \cs{g_primargs_token} contains the next token, so no
 %   need for \cs{primargs_read_token:N}.
+%   When \TeX{} reads a file name, the \tn{input} primitive is
+%   temporarily not expandable, so we temporarily change
+%   \cs{primargs_read_x_token:N} to not expand this primitive.  This is
+%   reverted by \cs{@@_get_file_name_end:}.
 %    \begin{macrocode}
 \cs_new_protected:Npn \primargs_get_file_name:N #1
   {
     \group_begin:
-      \@@_no_localdefs:
+      \@@_safe:
+      \cs_gset_eq:NN \@@_read_x_token_aux:N
+                     \@@_read_x_token_file:N
       \tex_aftergroup:D #1
       \tl_gclear:N \g_@@_file_name_tl
+      \tl_gset:Nn \g_@@_file_name_level_tl { 0 }
       \primargs_remove_optional_spaces:N \@@_get_file_name_test:
   }
 %    \end{macrocode}
@@ -524,18 +732,18 @@
 %
 % \begin{macro}[aux]{\@@_get_file_name_test:}
 %   The token read is in \cs{g_primargs_token}, and is non-expandable.
-%   If it is a control sequence, end the \meta{file name}.  If it is a
-%   space, the the \meta{file name} ends after its removal.  Otherwise,
+%   If it is a control sequence, end the \meta{file name}.  Spaces are
+%   special (quotes too, but that is treated elsewhere).  Otherwise,
 %   we extract the character from the \tn{meaning} of the \meta{token},
 %   which we remove anyways: in that case, we'll recurse.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_get_file_name_test:
+\cs_new_protected:Npn \@@_get_file_name_test:
   {
     \token_if_cs:NTF \g_primargs_token
       { \@@_get_file_name_end: }
       {
         \token_if_eq_charcode:NNTF \c_space_token \g_primargs_token
-          { \primargs_remove_token:N \@@_get_file_name_end: }
+          { \primargs_remove_token:N \@@_get_file_name_space: }
           { \primargs_remove_token:N \@@_get_file_name_char: }
       }
   }
@@ -543,17 +751,42 @@
 % \end{macro}
 %
 % \begin{macro}[aux]{\@@_get_file_name_end:}
-%   When the end of the file name is reached, end the group, after
+%   When the end of the file name is reached, reinstate the original
+%   definition of |read_x_token| so as to make \tn{input} expandable
+%   again, then end the group, after
 %   expanding the contents of \cs{g_@@_file_name_tl}.
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_get_file_name_end:
-  { \exp_args:No \group_end: \g_@@_file_name_tl }
+\cs_new_protected:Npn \@@_get_file_name_end:
+  {
+    \cs_gset_eq:NN \@@_read_x_token_aux:N
+                   \@@_read_x_token_std:N
+    \exp_args:No \group_end: \g_@@_file_name_tl
+  }
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[aux]{\@@_get_file_name_space:}
+%   We have already removed the space from the input stream.  If
+%   there is an odd number of quotes so far, add a space to the
+%   file name and continue.  Otherwise the file name ends.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_get_file_name_space:
+  {
+    \int_if_odd:nTF { \g_@@_file_name_level_tl }
+      {
+        \tl_gput_right:Nn \g_@@_file_name_tl { ~ }
+        \primargs_read_x_token:N \@@_get_file_name_test:
+      }
+      { \@@_get_file_name_end: }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}[aux]{\@@_get_file_name_char:}
 % \begin{macro}[aux, EXP]
 %   {\@@_get_file_name_char_ii:w, \@@_get_file_name_char_iii:w}
+%   Check for a quote, which switches \cs{g_@@_file_name_level_tl}
+%   from $0$ to $1$ or back.
 %   With an explicit character, applying \tn{string} would give the
 %   character code.  Here, implicit characters have to be converted too,
 %   so we must work with the \tn{meaning}, which is two or three words
@@ -564,8 +797,13 @@
 %   character).  Then loop with expansion.  This technique would fail if
 %   the character could be a space (character code~$32$).
 %    \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_get_file_name_char:
+\cs_new_protected:Npn \@@_get_file_name_char:
   {
+    \token_if_eq_charcode:NNT " \g_primargs_token
+      {
+        \tl_set:Nx \g_@@_file_name_level_tl
+          { \int_eval:n { 1 - \g_@@_file_name_level_tl } }
+      }
     \tl_gput_right:Nx \g_@@_file_name_tl
       {
         \exp_after:wN \@@_get_file_name_char_ii:w
@@ -581,39 +819,98 @@
 % \end{macro}
 % \end{macro}
 %
-% \section{Examples}
+% \begin{macro}{\primargs_get_input_file_name:N}
+% \begin{macro}[aux]
+%   {
+%     \@@_get_input_file_name_first:,
+%     \@@_get_input_file_name_loop:, \@@_get_input_file_name_test:,
+%     \@@_get_input_file_name_brace:, \@@_get_input_file_name_aux:N
+%   }
+%   For most engines this is an alias of \cs{primargs_get_file_name:N}.
+%   In \LuaTeX{} we test for a catcode $1$ token (after a filler) then
+%   expand and collect tokens (turned to strings) one by one, counting
+%   begin-group and end-group tokens in \cs{g_@@_file_name_level_tl}.
+%   The control sequence \tn{par} is ignored.  After removing a filler
+%   or after expansion, \cs{g_primargs_token} cannot be \tn{outer} hence
+%   the tests are safe.  We use primitives to cope with outer macro
+%   hidden by \tn{noexpand} upon first expansion.
+%    \begin{macrocode}
+\sys_if_engine_luatex:TF
+  {
+    \cs_new_protected:Npn \primargs_get_input_file_name:N #1
+      {
+        \group_begin:
+          \@@_safe:
+          \tex_aftergroup:D #1
+          \tl_gclear:N \g_@@_file_name_tl
+          \tl_gset:Nn \g_@@_file_name_level_tl { 1 }
+          \primargs_remove_filler:N \@@_get_input_file_name_first:
+      }
+    \cs_new_protected:Npn \@@_get_input_file_name_first:
+      {
+        \token_if_eq_catcode:NNTF \g_primargs_token \c_group_begin_token
+          { \primargs_remove_token:N \@@_get_input_file_name_loop: }
+          { \primargs_get_file_name:N \group_end: }
+      }
+    \cs_new_protected:Npn \@@_get_input_file_name_loop:
+      { \primargs_read_x_token:N \@@_get_input_file_name_test: }
+    \cs_new_protected:Npn \@@_get_input_file_name_test:
+      {
+        \token_if_eq_catcode:NNTF \g_primargs_token \c_group_begin_token
+          {
+            \tl_gset:Nx \g_@@_file_name_level_tl
+              { \int_eval:n { \g_@@_file_name_level_tl + 1 } }
+            \primargs_remove_token:N \@@_get_input_file_name_brace:
+          }
+          {
+            \token_if_eq_catcode:NNTF \g_primargs_token \c_group_end_token
+              {
+                \tl_gset:Nx \g_@@_file_name_level_tl
+                  { \int_eval:n { \g_@@_file_name_level_tl - 1 } }
+                \int_compare:nNnTF { \g_@@_file_name_level_tl } > 0
+                  { \primargs_remove_token:N \@@_get_input_file_name_brace: }
+                  { \primargs_remove_token:N \@@_get_file_name_end: }
+              }
+              {
+                \token_if_eq_meaning:NNTF \g_primargs_token \c_space_token
+                  {
+                    \tl_gput_right:Nn \g_@@_file_name_tl { ~ }
+                    \primargs_remove_token:N \@@_get_input_file_name_loop:
+                  }
+                  { \exp_after:wN \@@_get_input_file_name_aux:N \exp_not:N }
+              }
+          }
+      }
+    \cs_new_protected:Npn \@@_get_input_file_name_brace:
+      {
+        \tl_gput_right:Nx \g_@@_file_name_tl
+          {
+            \exp_after:wN \@@_get_file_name_char_ii:w
+            \token_to_meaning:N \g_primargs_token
+            \q_stop
+          }
+        \@@_get_input_file_name_loop:
+      }
+    \cs_new_protected:Npn \@@_get_input_file_name_aux:N #1
+      {
+        \exp_after:wN \str_if_eq_x:nnT
+        \exp_after:wN { \token_to_str:N #1 } { \token_to_str:N \par }
+          { \use_none:nnn }
+        \tex_xdef:D \g_@@_file_name_tl
+          {
+            \g_@@_file_name_tl
+            \exp_after:wN \tl_to_str:n \exp_after:wN { \exp_not:N #1 }
+          }
+        \@@_get_input_file_name_loop:
+      }
+  }
+  { \cs_new_eq:NN \primargs_get_input_file_name:N \primargs_get_file_name:N }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
 %
-% [Old text which I don't want to remove yet.]  A few examples of what
-% this package can parse.
-% \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 each of
-%     whose meaning is \tn{relax} or a character with category code
-%     $10$;
-%   \item \meta{general text} is a \meta{filler}, followed by 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}
+%</package> 
 %
-%</package>
-%
 % \end{implementation}
 %
-% \endinput
+% \PrintIndex

Modified: trunk/Master/texmf-dist/tex/latex/morewrites/morewrites.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/morewrites/morewrites.sty	2017-04-16 22:19:27 UTC (rev 43861)
+++ trunk/Master/texmf-dist/tex/latex/morewrites/morewrites.sty	2017-04-16 22:19:40 UTC (rev 43862)
@@ -9,7 +9,7 @@
 %% Communicate any suggestions for changing this package
 %% to Bruno Le Floch (blflatex at gmail.com).
 %% 
-%% File: morewrites.dtx Copyright (C) 2011-2013 Bruno Le Floch
+%% File: morewrites.dtx Copyright (C) 2011-2017 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
@@ -19,211 +19,386 @@
 %%    http://www.latex-project.org/lppl.txt
 %%
 %% -----------------------------------------------------------------------
-\RequirePackage {expl3} [2012/08/14]
-\RequirePackage {primargs} [2013/01/08]
+\RequirePackage {expl3} [2017/03/18]
+\RequirePackage {primargs} [2017/04/10]
 \ProvidesExplPackage
-  {morewrites} {2013/01/08} {0.2e} {Always room for a new write}
-\cs_generate_variant:Nn \prop_gpop:NnNT { NV }
+  {morewrites} {2017/04/10} {} {Always room for a new write}
+\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
+  }%
 \cs_new_eq:NN \__morewrites_tex_immediate:w \tex_immediate:D
 \cs_new_eq:NN \__morewrites_tex_openout:w   \tex_openout:D
 \cs_new_eq:NN \__morewrites_tex_write:w     \tex_write:D
 \cs_new_eq:NN \__morewrites_tex_closeout:w  \tex_closeout:D
-\cs_new_eq:NN \__morewrites_tex_shipout:w   \tex_shipout:D
-\int_new:N \g__morewrites_late_write_int
-\prop_new:N \g__morewrites_iow_prop
+\cs_new_eq:NN \__morewrites_tex_openin:w    \tex_openin:D
+\cs_new_eq:NN \__morewrites_tex_read:w      \tex_read:D
+\cs_new_eq:NN \__morewrites_tex_readline:w  \etex_readline:D
+\cs_new_eq:NN \__morewrites_tex_closein:w   \tex_closein:D
+\exp_args:NNf \cs_new_protected:Npn \__morewrites_tex_newread:N
+  { \exp_args:NNc \exp_after:wN \exp_stop_f: { newread } }
+\exp_args:NNf \cs_new_protected:Npn \__morewrites_tex_newwrite:N
+  { \exp_args:NNc \exp_after:wN \exp_stop_f: { newwrite } }
+\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 }
+\tl_new:N \l__morewrites_internal_tl
+\cs_new_eq:NN \__morewrites_tmp:w ?
+\int_new:N \g__morewrites_later_int
+\seq_new:N \g__morewrites_read_seq
+\seq_new:N \g__morewrites_write_seq
+\prop_new:N \g__morewrites_read_prop
+\prop_new:N \g__morewrites_write_prop
+\prop_new:N \g__morewrites_write_file_prop
+\tl_new:N \l__morewrites_code_tl
+\int_new:N \l__morewrites_user_int
+\tl_new:N \l__morewrites_tstr_tl
+\cs_new_eq:NN \l__morewrites_tstr_token ?
+\cs_new_eq:NN \s__morewrites \scan_stop:
 \newwrite \g__morewrites_iow
 \newread \g__morewrites_ior
 \tl_new:N \g__morewrites_tmp_file_tl
-\tl_gset:Nn \g__morewrites_tmp_file_tl { \jobname.mw }
-\clist_new:N \g__morewrites_reserved_iow_clist
-\int_step_inline:nnnn {0} {1} { \g__morewrites_iow - 1 }
-  { \clist_gput_right:Nn \g__morewrites_reserved_iow_clist {#1} }
-\clist_gput_right:Nn \g__morewrites_reserved_iow_clist {18}
-\int_new:N \g__morewrites_stream_int
-\cs_new_eq:NN \s__morewrites \scan_stop:
-\tl_new:N  \l__morewrites_internal_tl
-\cs_new_protected:Npn \__morewrites_equals_file_name:N #1
+\bool_new:N \g__morewrites_tmp_file_bool
+\bool_gset_false:N \g__morewrites_tmp_file_bool
+\int_new:N \g__morewrites_group_level_int
+\box_new:N \g__morewrites_shipout_box
+\cs_new_protected:Npn \__morewrites_set_file:n #1
   {
+    \bool_gset_false:N \g__morewrites_tmp_file_bool
+    \tl_gset:Nn \g__morewrites_tmp_file_tl {#1}
+  }
+\cs_new_protected:Npn \__morewrites_empty_file:n #1
+  {
+    \__morewrites_tex_immediate:w \__morewrites_tex_openout:w
+      \g__morewrites_iow = #1 \scan_stop:
+    \__morewrites_tex_immediate:w \__morewrites_tex_closeout:w
+      \g__morewrites_iow
+  }
+\prg_new_conditional:Npnn \__morewrites_if_file_trivial:n #1 { TF }
+  {
     \group_begin:
+      \tex_openin:D \g__morewrites_ior = #1 \scan_stop:
+      \if_eof:w \g__morewrites_ior
+        \cs_gset_eq:NN \__morewrites_tmp:w \prg_return_true:
+      \else:
+        \int_set:Nn \tex_endlinechar:D { -1 }
+        \etex_readline:D \g__morewrites_ior to \l__morewrites_internal_tl
+        \if_eof:w \g__morewrites_ior
+          \cs_gset_eq:NN \__morewrites_tmp:w \prg_return_true:
+        \else:
+          \cs_gset_eq:NN \__morewrites_tmp:w \prg_return_false:
+        \fi:
+      \fi:
+      \tex_closein:D \g__morewrites_ior
+    \group_end:
+    \__morewrites_tmp:w
+  }
+\cs_new_protected:Npn \__morewrites_chk_file:
+  {
+    \__morewrites_if_file_trivial:nTF { \g__morewrites_tmp_file_tl }
+      { \bool_gset_true:N \g__morewrites_tmp_file_bool }
+      {
+        \msg_warning:nnxx { morewrites } { file-exists }
+          { \g__morewrites_tmp_file_tl }
+          { \g__morewrites_tmp_file_tl .mw }
+        \tl_gput_right:Nn \g__morewrites_tmp_file_tl { .mw }
+        \__morewrites_chk_file:
+      }
+  }
+\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.
+  }
+\cs_new_protected:Npn \__morewrites_equals_file:N #1
+  {
+    \group_begin:
+      \tex_aftergroup:D \primargs_get_file_name:N
       \tex_aftergroup:D #1
-      \primargs_remove_equals:N \__morewrites_parse_file_name:
+      \primargs_remove_equals:N \group_end:
   }
-\cs_new_protected_nopar:Npn \__morewrites_parse_file_name:
-  { \primargs_get_file_name:N \group_end: }
-\cs_new_protected_nopar:Npn \__morewrites_immediate:w
-  { \primargs_read_x_token:N \__morewrites_immediate_ii: }
-\cs_new_protected_nopar:Npn \__morewrites_immediate_ii:
+\cs_new_protected:Npn \__morewrites_get_user:n #1
   {
-    \token_if_eq_meaning:NNTF \g_primargs_token \s__morewrites
-      { \__morewrites_immediate_iii:N }
-      { \__morewrites_tex_immediate:w }
+    \tl_set:Nn \l__morewrites_code_tl {#1}
+    \tex_afterassignment:D \l__morewrites_code_tl
+    \l__morewrites_user_int =
   }
-\cs_new_protected:Npn \__morewrites_immediate_iii:N #1
+\cs_new_protected:Npn \__morewrites_user_to_tstr:NTF #1
   {
-    \tl_if_eq:nnTF { #1 } { \s__morewrites }
-      { \__morewrites_immediate_iv:NN }
-      { #1 }
+    \tl_set:NV \l__morewrites_tstr_tl \l__morewrites_user_int
+    \int_compare:nNnTF { \l__morewrites_user_int } < { 19 }
+      { \use_i:nn }
+      { \prop_get:NVNTF #1 \l__morewrites_user_int \l__morewrites_tstr_tl }
   }
-\cs_new_protected:Npn \__morewrites_immediate_iv:NN #1 #2
+\int_new:N \l__morewrites_collect_next_int
+\cs_new_protected:Npn \__morewrites_collect:x #1
   {
-    \exp_args:Nc #1
+    \tl_set:Nx \l__morewrites_internal_tl {#1}
+    \__morewrites_collect_aux:cf { l__morewrites_0_tl } { 1 }
+  }
+\cs_new_protected:Npn \__morewrites_collect_aux:Nn #1#2
+  {
+    \int_compare:nNnT {#2} > \l__morewrites_collect_next_int
       {
-        \exp_after:wN \__morewrites_immediate_v:w
-        \token_to_str:N #2
+        \tl_clear_new:N #1
+        \int_set:Nn \l__morewrites_collect_next_int {#2}
       }
+    \tl_if_empty:NTF #1
+      { \tl_set_eq:NN #1 \l__morewrites_internal_tl }
+      {
+        \tl_put_left:No \l__morewrites_internal_tl {#1}
+        \tl_clear:N #1
+        \__morewrites_collect_aux:cf { l__morewrites_#2_tl }
+          { \int_eval:n { #2 + 1 } }
+      }
   }
-\use:x
+\cs_generate_variant:Nn \__morewrites_collect_aux:Nn { cf }
+\cs_new_protected:Npn \__morewrites_collect_gput_right:N #1
   {
-    \cs_new:Npn \exp_not:N \__morewrites_immediate_v:w
-        ##1 \tl_to_str:n { __morewrites } { __morewrites_immediate }
+    \int_compare:nNnF \l__morewrites_collect_next_int = 0
+      {
+        \int_decr:N \l__morewrites_collect_next_int
+        \tl_gput_right:Nv #1
+          {
+            l__morewrites_
+            \int_use:N \l__morewrites_collect_next_int
+            _tl
+          }
+        \__morewrites_collect_gput_right:N #1
+      }
   }
-\cs_new_protected:Npn \__morewrites_immediate_closeout_test:n #1
+\cs_generate_variant:Nn \__morewrites_collect_gput_right:N { c }
+\cs_new:Npn \__morewrites_user_tl_name:n #1
+  { g__morewrites_iow_ \int_eval:n {#1} _tl }
+\cs_new_protected:Npn \__morewrites_openin:w
   {
-    \int_gset:Nn \g__morewrites_stream_int {#1}
-    \clist_if_in:NnTF \g__morewrites_reserved_iow_clist {#1}
-      { \__morewrites_tex_immediate:w \__morewrites_tex_closeout:w \g__morewrites_stream_int }
-      { \__morewrites_immediate_closeout_aux: }
+    \__morewrites_get_user:n
+      {
+        \__morewrites_user_to_tstr:NTF \g__morewrites_read_prop { }
+          {
+            \seq_pop:NNF \g__morewrites_read_seq \l__morewrites_tstr_tl
+              {
+                \__morewrites_tex_newread:N \l__morewrites_tstr_token
+                \tl_set:NV \l__morewrites_tstr_tl \l__morewrites_tstr_token
+              }
+            \prop_gput:NVV \g__morewrites_read_prop \l__morewrites_user_int \l__morewrites_tstr_tl
+          }
+        \__morewrites_tex_openin:w \l__morewrites_tstr_tl \exp_stop_f:
+      }
   }
-\cs_new_protected_nopar:Npn \__morewrites_immediate_closeout_aux:
+\cs_new_protected:Npn \__morewrites_read:w
   {
-    \prop_gpop:NVNT \g__morewrites_iow_prop \g__morewrites_stream_int \l__morewrites_internal_tl
+    \__morewrites_get_user:n
       {
-        \__morewrites_immediate_write_and_close:nn
-          { \g__morewrites_stream_int } { \l__morewrites_internal_tl }
+        \__morewrites_user_to_tstr:NTF \g__morewrites_read_prop { } { }
+        \__morewrites_tex_read:w \l__morewrites_tstr_tl \exp_stop_f:
       }
   }
-\cs_new_protected:Npn \__morewrites_immediate_write_and_close:nn #1#2
+\cs_new_protected:Npn \__morewrites_readline:w
   {
-    \__morewrites_tex_immediate:w \__morewrites_tex_openout:w
-      \g__morewrites_iow #2 \scan_stop:
+    \__morewrites_get_user:n
+      {
+        \__morewrites_user_to_tstr:NTF \g__morewrites_read_prop { } { }
+        \__morewrites_tex_readline:w \l__morewrites_tstr_tl \exp_stop_f:
+      }
+  }
+\cs_new_protected:Npn \__morewrites_closein:w
+  {
+    \__morewrites_get_user:n
+      {
+        \__morewrites_user_to_tstr:NTF \g__morewrites_read_prop { } { }
+        \int_compare:nNnF { \l__morewrites_tstr_tl } = { \l__morewrites_user_int }
+          {
+            \prop_gremove:NV \g__morewrites_read_prop \l__morewrites_user_int
+            \seq_gput_left:NV \g__morewrites_read_seq \l__morewrites_tstr_tl
+          }
+        \__morewrites_tex_closein:w \l__morewrites_tstr_tl \exp_stop_f:
+      }
+  }
+\cs_new_protected:Npn \__morewrites_immediate:w
+  { \primargs_read_x_token:N \__morewrites_immediate_auxii: }
+\cs_new_protected:Npn \__morewrites_immediate_auxii:
+  {
+    \token_if_eq_meaning:NNTF \g_primargs_token \s__morewrites
+      { \__morewrites_immediate_auxiii:N }
+      { \__morewrites_tex_immediate:w }
+  }
+\cs_new_protected:Npn \__morewrites_immediate_auxiii:N #1
+  { \str_if_eq:nnTF { #1 } { \s__morewrites } { \use_iii:nnn } { #1 } }
+\cs_new_protected:Npn \__morewrites_closeout:w
+  {
+    \s__morewrites
+    \use_i:nn
+      { \__morewrites_get_user:n { \__morewrites_closeout_later: } }
+      { \__morewrites_get_user:n { \__morewrites_closeout_now: } }
+  }
+\cs_new_protected:Npn \__morewrites_closeout_now:
+  {
+    \__morewrites_user_to_tstr:NTF \g__morewrites_write_prop
+      {
+        \__morewrites_tex_immediate:w \__morewrites_tex_closeout:w \l__morewrites_tstr_tl \exp_stop_f:
+        \int_compare:nNnF { \l__morewrites_tstr_tl } = { \l__morewrites_user_int }
+          {
+            \prop_gremove:NV \g__morewrites_write_prop \l__morewrites_user_int
+            \seq_gput_left:NV \g__morewrites_write_seq \l__morewrites_tstr_tl
+          }
+      }
+      {
+        \prop_gpop:NVNT \g__morewrites_write_file_prop \l__morewrites_user_int \l__morewrites_internal_tl
+          { \__morewrites_closeout_now:nn { \l__morewrites_user_int } { \l__morewrites_internal_tl } }
+      }
+  }
+\cs_new_protected:Npn \__morewrites_closeout_now:nn #1#2
+  {
+    \__morewrites_tex_immediate:w \__morewrites_tex_openout:w \g__morewrites_iow = #2 \scan_stop:
     \group_begin:
-      \int_set_eq:NN \tex_newlinechar:D \c_minus_one
-      \tl_use:c { g__morewrites_iow_ \int_eval:n {#1} _tl }
-      \tl_gclear:c { g__morewrites_iow_ \int_eval:n {#1} _tl }
+      \int_set:Nn \tex_newlinechar:D { -1 }
+      \tl_use:c { \__morewrites_user_tl_name:n {#1} }
+      \tl_gclear:c { \__morewrites_user_tl_name:n {#1} }
     \group_end:
     \__morewrites_tex_immediate:w \__morewrites_tex_closeout:w \g__morewrites_iow
   }
-\cs_new_protected:Npn \__morewrites_immediate_openout_test:n #1
+\cs_new_protected:Npn \__morewrites_openout:w
   {
-    \int_gset:Nn \g__morewrites_stream_int {#1}
-    \clist_if_in:NnTF \g__morewrites_reserved_iow_clist {#1}
-      { \__morewrites_tex_immediate:w \__morewrites_tex_openout:w \g__morewrites_stream_int }
-      { \__morewrites_equals_file_name:N \__morewrites_immediate_openout_aux:n }
+    \s__morewrites
+    \use_i:nn
+      { \__morewrites_get_user:n { \__morewrites_openout_later:w } }
+      { \__morewrites_get_user:n { \__morewrites_equals_file:N \__morewrites_openout_now:n } }
   }
-\cs_new_protected:Npn \__morewrites_immediate_openout_aux:n #1
+\cs_new_protected:Npn \__morewrites_openout_now:n #1
   {
-    \__morewrites_immediate_closeout_aux:
-    \prop_gput:NVn \g__morewrites_iow_prop \g__morewrites_stream_int {#1}
-    \tl_gclear_new:c { g__morewrites_iow_ \int_use:N \g__morewrites_stream_int _tl }
+    \__morewrites_closeout_now:
+    \seq_pop:NNTF \g__morewrites_write_seq \l__morewrites_tstr_tl
+      {
+        \prop_gput:NVV \g__morewrites_write_prop \l__morewrites_user_int \l__morewrites_tstr_tl
+        \__morewrites_tex_immediate:w \__morewrites_tex_openout:w \l__morewrites_tstr_tl \exp_stop_f:
+          = \tl_to_str:n {#1} \scan_stop:
+      }
+      {
+        \__morewrites_empty_file:n {#1}
+        \prop_gput:NVx \g__morewrites_write_file_prop \l__morewrites_user_int
+          { \tl_to_str:n {#1} }
+        \tl_gclear_new:c { \__morewrites_user_tl_name:n { \l__morewrites_user_int } }
+      }
   }
-\cs_new_protected:Npn \__morewrites_immediate_write_test:n #1
+\cs_new_protected:Npn \__morewrites_write:w
   {
-    \int_gset:Nn \g__morewrites_stream_int {#1}
-    \clist_if_in:NnTF \g__morewrites_reserved_iow_clist {#1}
-      { \__morewrites_tex_immediate:w \__morewrites_tex_write:w \g__morewrites_stream_int }
-      { \primargs_get_general_text:N \__morewrites_immediate_write_aux:n }
+    \s__morewrites
+    \use_i:nn
+      { \__morewrites_get_user:n { \__morewrites_write_later:w } }
+      { \__morewrites_get_user:n { \__morewrites_write_now:w } }
   }
-\cs_new_protected_nopar:Npn \__morewrites_immediate_write_aux:n
+\cs_new_protected:Npn \__morewrites_write_now:w
   {
-    \prop_get:NVNTF \g__morewrites_iow_prop \g__morewrites_stream_int \l__morewrites_internal_tl
-      { \__morewrites_immediate_write_open:n }
-      { \__morewrites_immediate_write_closed:n }
+    \__morewrites_user_to_tstr:NTF \g__morewrites_write_prop
+      { \__morewrites_tex_immediate:w \__morewrites_tex_write:w \l__morewrites_tstr_tl \exp_stop_f: }
+      { \primargs_get_general_text:N \__morewrites_write_now:n }
   }
-\cs_new_protected:Npn \__morewrites_immediate_write_closed:n #1
+\cs_new_protected:Npn \__morewrites_write_now:n
   {
-    \__morewrites_tex_immediate:w \__morewrites_tex_write:w
-      \if_int_compare:w \g__morewrites_stream_int < \c_zero
-        -1
-      \else:
-        16
-      \fi:
-      {#1}
+    \prop_get:NVNTF \g__morewrites_write_file_prop \l__morewrites_user_int \l__morewrites_internal_tl
+      { \__morewrites_write_now_open:n }
+      { \__morewrites_tex_immediate:w \__morewrites_tex_write:w 16 }
   }
-\cs_new_protected:Npn \__morewrites_immediate_write_open:n #1
+\cs_new_protected:Npn \__morewrites_write_now_open:n #1
   {
-    \__morewrites_tex_immediate:w \__morewrites_tex_openout:w \g__morewrites_iow
-      \g__morewrites_tmp_file_tl \scan_stop:
-    \__morewrites_tex_immediate:w \__morewrites_tex_write:w \g__morewrites_iow {#1}
-    \__morewrites_tex_immediate:w \__morewrites_tex_closeout:w \g__morewrites_iow
+    \bool_if:NF \g__morewrites_tmp_file_bool { \__morewrites_chk_file: }
+    \__morewrites_tex_immediate:w \__morewrites_tex_openout:w
+      \g__morewrites_iow = \g__morewrites_tmp_file_tl \scan_stop:
+    \__morewrites_tex_immediate:w \__morewrites_tex_write:w
+      \g__morewrites_iow {#1}
+    \__morewrites_tex_immediate:w \__morewrites_tex_closeout:w
+      \g__morewrites_iow
     \group_begin:
-      \int_set_eq:NN \tex_endlinechar:D \c_minus_one
-      \tex_openin:D \g__morewrites_ior \g__morewrites_tmp_file_tl \scan_stop:
-      \__morewrites_immediate_write_readlines_loop:
+      \int_set:Nn \tex_endlinechar:D { -1 }
+      \tex_openin:D \g__morewrites_ior = \g__morewrites_tmp_file_tl \scan_stop:
+      \__morewrites_write_now_loop:
       \tex_closein:D \g__morewrites_ior
+      \__morewrites_collect_gput_right:c
+        { \__morewrites_user_tl_name:n { \l__morewrites_user_int } }
     \group_end:
+    \__morewrites_empty_file:n { \g__morewrites_tmp_file_tl }
   }
-\cs_new_protected_nopar:Npn \__morewrites_immediate_write_readlines_loop:
+\cs_new_protected:Npn \__morewrites_write_now_loop:
   {
     \etex_readline:D \g__morewrites_ior to \l__morewrites_internal_tl
     \ior_if_eof:NF \g__morewrites_ior
       {
-        \tl_gput_right:cx
-          { g__morewrites_iow_ \int_use:N \g__morewrites_stream_int _tl }
+        \__morewrites_collect:x
           {
-            \__morewrites_tex_immediate:w \__morewrites_tex_write:w \g__morewrites_iow
-              { \l__morewrites_internal_tl }
+            \__morewrites_tex_immediate:w \__morewrites_tex_write:w
+              \g__morewrites_iow { \l__morewrites_internal_tl }
           }
-        \__morewrites_immediate_write_readlines_loop:
+        \__morewrites_write_now_loop:
       }
   }
-\cs_new_protected:Npn \__morewrites_late:n #1
+\cs_new_protected:Npn \__morewrites_later:n #1
   {
-    \int_gincr:N \g__morewrites_late_write_int
+    \int_gincr:N \g__morewrites_later_int
     \tl_const:cx
       {
-        c__morewrites_late_write_
-        \int_use:N \g__morewrites_late_write_int
+        c__morewrites_later_
+        \int_use:N \g__morewrites_later_int
         _tl
       }
       {
-        \int_gset:Nn \exp_not:N \g__morewrites_stream_int
-          { \exp_not:V \g__morewrites_stream_int }
+        \int_set:Nn \exp_not:N \l__morewrites_user_int
+          { \exp_not:V \l__morewrites_user_int }
         \exp_not:n {#1}
       }
     \exp_args:NNx \__morewrites_tex_write:w \g__morewrites_iow
-      { `( \int_use:N \g__morewrites_late_write_int ) }
+      { `( \int_use:N \g__morewrites_later_int ) }
   }
-\cs_new_protected_nopar:Npn \__morewrites_openout:w
-  { \s__morewrites \primargs_get_number:N \__morewrites_openout_test:n }
-\cs_new_protected:Npn \__morewrites_openout_test:n #1
+\cs_new_protected:Npn \__morewrites_later_do:n #1
+  { \tl_use:c { c__morewrites_later_ \int_eval:n {#1} _tl } }
+\cs_new_protected:Npn \__morewrites_closeout_later:
   {
-    \int_gset:Nn \g__morewrites_stream_int {#1}
-    \clist_if_in:NnTF \g__morewrites_reserved_iow_clist {#1}
-      { \__morewrites_tex_openout:w \g__morewrites_stream_int }
-      { \__morewrites_equals_file_name:N \__morewrites_openout_aux:n }
+    \int_compare:nNnTF \l__morewrites_user_int < { 19 }
+      { \__morewrites_tex_closeout:w \l__morewrites_user_int }
+      { \__morewrites_later:n { \__morewrites_closeout_now: } }
   }
-\cs_new_protected:Npn \__morewrites_openout_aux:n #1
-  { \__morewrites_late:n { \__morewrites_immediate_openout_aux:n {#1} } }
-\cs_new_protected_nopar:Npn \__morewrites_write:w
-  { \s__morewrites \primargs_get_number:N \__morewrites_write_test:n }
-\cs_new_protected:Npn \__morewrites_write_test:n #1
+\cs_new_protected:Npn \__morewrites_openout_later:w
   {
-    \int_gset:Nn \g__morewrites_stream_int {#1}
-    \clist_if_in:NnTF \g__morewrites_reserved_iow_clist {#1}
-      { \__morewrites_tex_write:w \g__morewrites_stream_int }
-      { \primargs_get_general_text:N \__morewrites_write_aux:n }
+    \int_compare:nNnTF \l__morewrites_user_int < { 19 }
+      { \__morewrites_tex_openout:w \l__morewrites_user_int }
+      { \__morewrites_equals_file:N \__morewrites_openout_later:n }
   }
-\cs_new_protected:Npn \__morewrites_write_aux:n #1
-  { \__morewrites_late:n { \__morewrites_immediate_write_aux:n {#1} } }
-\cs_new_protected_nopar:Npn \__morewrites_closeout:w
-  { \s__morewrites \primargs_get_number:N \__morewrites_closeout_test:n }
-\cs_new_protected:Npn \__morewrites_closeout_test:n #1
+\cs_new_protected:Npn \__morewrites_openout_later:n #1
+  { \__morewrites_later:n { \__morewrites_openout_now:n {#1} } }
+\cs_new_protected:Npn \__morewrites_write_later:w
   {
-    \int_gset:Nn \g__morewrites_stream_int {#1}
-    \clist_if_in:NnTF \g__morewrites_reserved_iow_clist {#1}
-      { \__morewrites_tex_closeout:w \g__morewrites_stream_int }
-      { \__morewrites_closeout_aux: }
+    \int_compare:nNnTF \l__morewrites_user_int < { 19 }
+      { \__morewrites_tex_write:w \l__morewrites_user_int }
+      { \primargs_get_general_text:N \__morewrites_write_later:n }
   }
-\cs_new_protected_nopar:Npn \__morewrites_closeout_aux:
-  { \__morewrites_late:n { \__morewrites_immediate_closeout_aux: } }
-\cs_new_protected_nopar:Npn \__morewrites_before_shipout:
+\cs_new_protected:Npn \__morewrites_write_later:n #1
+  { \__morewrites_later:n { \__morewrites_write_later_aux:n {#1} } }
+\cs_new_protected:Npn \__morewrites_write_later_aux:n
   {
-    \__morewrites_tex_immediate:w \__morewrites_tex_openout:w \g__morewrites_iow
-      \g__morewrites_tmp_file_tl \scan_stop:
+    \__morewrites_user_to_tstr:NTF \g__morewrites_write_prop
+      { \__morewrites_tex_immediate:w \__morewrites_tex_write:w \l__morewrites_tstr_tl \exp_stop_f: }
+      { \__morewrites_write_now:n }
   }
-\cs_new_protected_nopar:Npn \__morewrites_after_shipout:
+\cs_new_protected:Npn \__morewrites_before_shipout:
   {
-    \__morewrites_tex_immediate:w \__morewrites_tex_closeout:w \g__morewrites_iow
+    \bool_if:NF \g__morewrites_tmp_file_bool { \__morewrites_chk_file: }
+    \__morewrites_tex_immediate:w \__morewrites_tex_openout:w
+      \g__morewrites_iow = \g__morewrites_tmp_file_tl \scan_stop:
+  }
+\cs_new_protected:Npn \__morewrites_after_shipout:
+  {
+    \__morewrites_tex_immediate:w \__morewrites_tex_closeout:w
+      \g__morewrites_iow
     \group_begin:
       \int_set_eq:NN \tex_endlinechar:D \tex_newlinechar:D
       \char_set_catcode_other:n { \tex_endlinechar:D }
@@ -230,14 +405,15 @@
       \tl_map_inline:nn { `(0123456789) }
         { \char_set_catcode_other:n {`##1} }
       \etex_everyeof:D { `() \exp_not:N }
-      \tl_gset:Nx \g__morewrites_internal_tl
+      \tl_set:Nx \l__morewrites_internal_tl
         {
           \exp_after:wN \__morewrites_after_shipout_loop:ww
           \tex_input:D \g__morewrites_tmp_file_tl \c_space_tl
         }
+      \__morewrites_empty_file:n { \g__morewrites_tmp_file_tl }
+      \exp_args:NNo
     \group_end:
-    \tl_map_inline:Nn \g__morewrites_internal_tl
-      { \tl_use:c { c__morewrites_late_write_ ##1 _tl } }
+    \tl_map_function:nN { \l__morewrites_internal_tl } \__morewrites_later_do:n
   }
 \cs_new:Npn \__morewrites_after_shipout_loop:ww #1 `( #2 )
   {
@@ -247,81 +423,93 @@
         \__morewrites_after_shipout_loop:ww
       }
   }
-\IfFileExists{atbegshi.sty}
+\cs_new_protected:Npn \__morewrites_shipout:w
   {
-    \RequirePackage{atbegshi}
-    \tl_replace_once:Nnn \AtBegShi at Output
-      { \AtBegShi at OrgShipout \box \AtBeginShipoutBox }
-      {
-        \__morewrites_before_shipout:
-        \AtBegShi at OrgShipout \box \AtBeginShipoutBox
-        \__morewrites_after_shipout:
-      }
-    \tl_replace_once:Nnn \AtBegShi at Output
-      { \AtBeginShipoutOriginalShipout \box \AtBeginShipoutBox }
-      {
-        \__morewrites_before_shipout:
-        \AtBeginShipoutOriginalShipout \box \AtBeginShipoutBox
-        \__morewrites_after_shipout:
-      }
+    \int_gset_eq:NN \g__morewrites_group_level_int \etex_currentgrouplevel:D
+    \tex_afterassignment:D \__morewrites_shipout_i:
+    \tex_global:D \tex_setbox:D \g__morewrites_shipout_box
   }
+\cs_new_protected:Npn \__morewrites_shipout_i:
   {
-    \int_new:N \g__morewrites_group_level_int
-    \box_new:N \g__morewrites_shipout_box
-    \cs_new_protected_nopar:Npn \__morewrites_shipout:w
-      {
-        \int_gset_eq:NN \g__morewrites_group_level_int \etex_currentgrouplevel:D
-        \tex_afterassignment:D \__morewrites_shipout_i:
-        \tex_global:D \tex_setbox:D \g__morewrites_shipout_box
-      }
-    \cs_new_protected_nopar:Npn \__morewrites_shipout_i:
-      {
-        \int_compare:nNnTF { \g__morewrites_group_level_int }
-                         = { \etex_currentgrouplevel:D }
-          { \__morewrites_shipout_ii: }
-          { \tex_aftergroup:D \__morewrites_shipout_ii: }
-      }
-    \cs_new_protected_nopar:Npn \__morewrites_shipout_ii:
-      {
-        \__morewrites_before_shipout:
-        \__morewrites_tex_shipout:w \tex_box:D \g__morewrites_shipout_box
-        \__morewrites_after_shipout:
-      }
-    \AtBeginDocument { \cs_gset_eq:NN \shipout \__morewrites_shipout:w }
+    \int_compare:nNnTF { \g__morewrites_group_level_int }
+                     = { \etex_currentgrouplevel:D }
+      { \__morewrites_shipout_ii: }
+      { \tex_aftergroup:D \__morewrites_shipout_ii: }
   }
-\int_new:N \g__morewrites_at_end_int
-\int_gset:Nn \g__morewrites_at_end_int { 10 }
-\cs_new_protected_nopar:Npn \__morewrites_close_all:
+\cs_new_protected:Npn \__morewrites_shipout_ii:
   {
-    \prop_map_function:NN \g__morewrites_iow_prop
-      \__morewrites_immediate_write_and_close:nn
-    \prop_gclear:N \g__morewrites_iow_prop
+    \__morewrites_before_shipout:
+    \__morewrites_tex_shipout:w \tex_box:D \g__morewrites_shipout_box
+    \__morewrites_after_shipout:
   }
-\cs_set:Npn \__morewrites_tmp:w #1
+\cs_gset_protected:Npn \__morewrites_tmp:w #1
   {
-    \cs_new_protected:Npn \__morewrites_close_all_at_end:w ##1 #1
+    \cs_if_exist:NF \__morewrites_tex_shipout:w
+      { \cs_new_eq:NN \__morewrites_tex_shipout:w #1 }
+    \cs_gset_eq:NN #1 \__morewrites_shipout:w
+  }
+\tl_map_inline:nn
+  {
+    \xyrealshipout@
+    \org at shipout
+    \PDFSYNCship at ut@ld
+    \CROP at shipout
+    \@soORI
+    \tex_shipout:D
+    \zwpl at Hship
+    \o at shipout@TP
+    \LL at shipout
+    \Shipout
+    \GXTorg at shipout
+    \AtBegShi at OrgShipout
+    \AtBeginShipoutOriginalShipout
+    \shipout
+  }
+  {
+    \str_if_eq_x:nnT
+      { \cs_meaning:N #1 }
+      { \token_to_str:N \shipout }
+      { \__morewrites_tmp:w #1 }
+  }
+\cs_if_exist:NF \__morewrites_tex_shipout:w
+  {
+    \cs_new_eq:NN \__morewrites_tex_shipout:w \shipout
+    \cs_gset_eq:NN \shipout \__morewrites_shipout:w
+  }
+\cs_new_protected:Npn \__morewrites_close_all:
+  {
+    \prop_map_function:NN \g__morewrites_write_prop
+      \__morewrites_closeout_now:nn
+    \prop_gclear:N \g__morewrites_write_prop
+  }
+\cs_new_protected:Npn \__morewrites_close_all_at_end:nw #1#2 \@@end
+  {
+    \int_compare:nNnTF {#1} > \c_zero
+      { #2 \__morewrites_close_all_at_end:nw { #1 - 1 } }
+      { \__morewrites_close_all: #2 }
+    \@@end
+  }
+\AtEndDocument { \__morewrites_close_all_at_end:nw { 5 } }
+\int_new:N \g__morewrites_alloc_read_int
+\int_set:Nn \g__morewrites_alloc_read_int { 18 }
+\int_new:N \g__morewrites_alloc_write_int
+\int_set:Nn \g__morewrites_alloc_write_int { 18 }
+\cs_new_protected:Npn \__morewrites_newread:N #1
+  {
+    \int_gincr:N \g__morewrites_alloc_read_int
+    \int_set_eq:NN \allocationnumber \g__morewrites_alloc_read_int
+    \cs_undefine:N #1
+    \int_const:Nn #1 { \allocationnumber }
+    \wlog
       {
-        \int_gdecr:N \g__morewrites_at_end_int
-        \int_compare:nNnTF \g__morewrites_at_end_int > \c_zero
-          {
-            \tl_if_empty:nTF {##1}
-              { ##1 \__morewrites_close_all: }
-              { ##1 \__morewrites_close_all_at_end:w }
-          }
-          { \__morewrites_close_all: ##1 }
-        #1
+        \token_to_str:N #1
+        = \token_to_str:N \read \int_use:N \allocationnumber
       }
   }
-\exp_args:Nc \__morewrites_tmp:w { @ @ end }
-\AtEndDocument { \__morewrites_close_all_at_end:w }
-\tex_countdef:D \g__morewrites_alloc_int 17 \scan_stop:
-\cs_new:Npn \__morewrites_newwrite:N #1
+\cs_new_protected:Npn \__morewrites_newwrite:N #1
   {
-    \int_gincr:N \g__morewrites_alloc_int
-    \if_int_compare:w \g__morewrites_alloc_int = \c_sixteen
-      \int_gset:Nn \g__morewrites_alloc_int { 20 }
-    \fi:
-    \int_set_eq:NN \allocationnumber \g__morewrites_alloc_int
+    \int_gincr:N \g__morewrites_alloc_write_int
+    \int_set_eq:NN \allocationnumber \g__morewrites_alloc_write_int
     \cs_undefine:N #1
     \int_const:Nn #1 { \allocationnumber }
     \wlog
@@ -330,6 +518,34 @@
         = \token_to_str:N \write \int_use:N \allocationnumber
       }
   }
+\cs_new_protected:Npn \__morewrites_allocate:n #1
+  {
+    \prg_replicate:nn
+      {
+        \int_max:nn { 0 }
+          {
+            (#1) - \seq_count:N \g__morewrites_write_seq
+            - \prop_count:N \g__morewrites_write_prop
+          }
+      }
+      {
+        \__morewrites_tex_newwrite:N \l__morewrites_tstr_token
+        \seq_put_right:NV \g__morewrites_write_seq \l__morewrites_tstr_token
+      }
+  }
+\cs_new_protected:Npn \morewritessetup #1
+  { \keys_set:nn { __morewrites } {#1} }
+\keys_define:nn { __morewrites }
+  {
+    allocate .code:n = \__morewrites_allocate:n {#1} ,
+    file .code:n = \__morewrites_set_file:n {#1} ,
+    file .initial:n = \c_sys_jobname_str .mw
+  }
+\cs_gset_eq:NN \openin    \__morewrites_openin:w
+\cs_gset_eq:NN \read      \__morewrites_read:w
+\cs_gset_eq:NN \readline  \__morewrites_readline:w
+\cs_gset_eq:NN \closein   \__morewrites_closein:w
+\cs_gset_eq:NN \newread   \__morewrites_newread:N
 \cs_gset_eq:NN \immediate \__morewrites_immediate:w
 \cs_gset_eq:NN \openout   \__morewrites_openout:w
 \cs_gset_eq:NN \write     \__morewrites_write:w

Modified: trunk/Master/texmf-dist/tex/latex/morewrites/primargs.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/morewrites/primargs.sty	2017-04-16 22:19:27 UTC (rev 43861)
+++ trunk/Master/texmf-dist/tex/latex/morewrites/primargs.sty	2017-04-16 22:19:40 UTC (rev 43862)
@@ -9,7 +9,7 @@
 %% Communicate any suggestions for changing this package
 %% to Bruno Le Floch (blflatex at gmail.com).
 %% 
-%% File: primargs.dtx Copyright (C) 2012-2013 Bruno Le Floch
+%% File: primargs.dtx Copyright (C) 2012-2017 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
@@ -19,42 +19,51 @@
 %%    http://www.latex-project.org/lppl.txt
 %%
 %% -----------------------------------------------------------------------
-\RequirePackage {expl3} [2012/08/14]
+\RequirePackage {expl3} [2017/03/18]
 \ProvidesExplPackage
-  {primargs} {2013/01/08} {0.2e} {Parsing arguments of primitives}
-\cs_new_protected_nopar:Npn \g__primargs_code_tl { }
-\cs_new_protected_nopar:Npn \__primargs_no_afterassignment:
-  { \tex_afterassignment:D \tex_relax:D }
-\cs_new_protected_nopar:Npn \__primargs_no_localdefs:
+  {primargs} {2017/04/10} {} {Parsing arguments of primitives}
+\tl_new:N \g__primargs_code_tl
+\tl_new:N \g__primargs_file_name_tl
+\tl_new:N \g__primargs_file_name_level_tl
+\cs_new_protected:Npn \__primargs_safe:
   {
-    \__primargs_no_afterassignment:
-    \int_compare:nNnF \tex_globaldefs:D > \c_zero
-      { \tex_globaldefs:D = \c_zero }
+    \tex_afterassignment:D \tex_relax:D
+    \if_int_compare:w 0 > \tex_globaldefs:D
+      \int_zero:N \tex_globaldefs:D
+    \fi:
   }
-\cs_new_protected_nopar:Npn \primargs_read_x_token:N
+\cs_new_protected:Npn \primargs_read_x_token:N
   {
     \group_begin:
-      \__primargs_no_localdefs:
+      \__primargs_safe:
       \__primargs_read_x_token:N
   }
-\cs_new_protected_nopar:Npn \__primargs_read_x_token:N
+\cs_new_protected:Npn \__primargs_read_x_token:N
   {
-    \tex_afterassignment:D \__primargs_read_x_token_ii:N
+    \tex_afterassignment:D \__primargs_read_x_token_aux:N
     \tex_global:D \tex_futurelet:D \g_primargs_token
   }
-\cs_new_protected_nopar:Npn \__primargs_read_x_token_ii:N
+\cs_new_protected:Npn \__primargs_read_x_token_std:N
   {
     \exp_after:wN
     \if_meaning:w \exp_not:N \g_primargs_token \g_primargs_token
-      \group_end:
-      \exp_after:wN \use_none:nnn
+      \group_end: \use_i:nnnn
     \fi:
     \exp_after:wN \__primargs_read_x_token:N \exp_after:wN
   }
-\cs_new_protected_nopar:Npn \primargs_read_token:N
+\cs_new_eq:NN \__primargs_read_x_token_aux:N
+              \__primargs_read_x_token_std:N
+\cs_new_protected:Npn \__primargs_read_x_token_file:N
   {
+    \if_meaning:w \tex_input:D \g_primargs_token
+      \use_i_ii:nnn \group_end:
+    \fi:
+    \__primargs_read_x_token_std:N
+  }
+\cs_new_protected:Npn \primargs_read_token:N
+  {
     \group_begin:
-      \__primargs_no_localdefs:
+      \__primargs_safe:
       \tex_afterassignment:D \group_end:
       \tex_global:D \tex_futurelet:D \g_primargs_token
   }
@@ -61,7 +70,7 @@
 \cs_new_protected:Npn \primargs_remove_token:N #1
   {
     \group_begin:
-      \__primargs_no_localdefs:
+      \__primargs_safe:
       \tex_aftergroup:D #1
       \tex_afterassignment:D \group_end:
       \tex_global:D \tex_let:D \g_primargs_token = ~
@@ -69,13 +78,13 @@
 \cs_new_protected:Npn \primargs_remove_one_optional_space:N #1
   {
     \group_begin:
-      \__primargs_no_localdefs:
+      \__primargs_safe:
       \tex_aftergroup:D #1
       \primargs_read_x_token:N \__primargs_remove_one_optional_space:
   }
-\exp_args:NNo \cs_new_protected_nopar:Npn \__primargs_remove_one_optional_space:
+\cs_new_protected:Npn \__primargs_remove_one_optional_space:
   {
-    \use:n { \if_catcode:w } ~ \exp_not:N \g_primargs_token
+    \if_catcode:w \c_space_token \exp_not:N \g_primargs_token
       \exp_after:wN \primargs_remove_token:N
     \fi:
     \group_end:
@@ -83,15 +92,15 @@
 \cs_new_protected:Npn \primargs_remove_optional_spaces:N #1
   {
     \group_begin:
-      \__primargs_no_localdefs:
+      \__primargs_safe:
       \tex_aftergroup:D #1
       \__primargs_remove_optional_spaces:
   }
-\cs_new_protected_nopar:Npn \__primargs_remove_optional_spaces:
-  { \primargs_read_x_token:N \__primargs_remove_optional_spaces_ii: }
-\exp_args:NNo \cs_new_protected_nopar:Npn \__primargs_remove_optional_spaces_ii:
+\cs_new_protected:Npn \__primargs_remove_optional_spaces:
+  { \primargs_read_x_token:N \__primargs_remove_optional_spaces_aux: }
+\cs_new_protected:Npn \__primargs_remove_optional_spaces_aux:
   {
-    \use:n { \if_catcode:w } ~ \exp_not:N \g_primargs_token
+    \if_catcode:w \c_space_token \exp_not:N \g_primargs_token
       \exp_after:wN \primargs_remove_token:N
       \exp_after:wN \__primargs_remove_optional_spaces:
     \else:
@@ -104,19 +113,45 @@
       \tex_aftergroup:D #1
       \primargs_remove_optional_spaces:N \__primargs_remove_equals:
   }
-\cs_new_protected_nopar:Npn \__primargs_remove_equals:
+\cs_new_protected:Npn \__primargs_remove_equals:
   {
       \if_meaning:w = \g_primargs_token
-        \exp_after:wN \__primargs_remove_equals_ii:NN
+        \exp_after:wN \__primargs_remove_equals_aux:NN
       \fi:
     \group_end:
   }
-\cs_new_protected:Npn \__primargs_remove_equals_ii:NN #1#2
+\cs_new_protected:Npn \__primargs_remove_equals_aux:NN #1#2
   { \tl_if_eq:nnTF { #2 } { = } { #1 } { #1 #2 } }
+\cs_new_protected:Npn \primargs_remove_filler:N #1
+  {
+    \group_begin:
+      \__primargs_safe:
+      \tex_aftergroup:D #1
+      \__primargs_remove_filler:
+  }
+\cs_new_protected:Npn \__primargs_remove_filler:
+  { \primargs_read_x_token:N \__primargs_remove_filler_aux: }
+\cs_new_protected:Npn \__primargs_remove_filler_aux:
+  {
+    \if_catcode:w \c_space_token \exp_not:N \g_primargs_token
+    \else:
+      \if_meaning:w \tex_relax:D \g_primargs_token
+      \else:
+        \exp_after:wN
+        \if_meaning:w \exp_not:N \prg_do_nothing: \g_primargs_token
+        \else:
+          \__primargs_remove_filler_end:NNNNN
+        \fi:
+      \fi:
+    \fi:
+    \primargs_remove_token:N \__primargs_remove_filler:
+  }
+\cs_new_protected:Npn \__primargs_remove_filler_end:NNNNN #1#2#3#4#5
+  { #1 #2 #3 \group_end: }
 \cs_new_protected:Npn \__primargs_get_rhs:NnN #1#2#3
   {
     \group_begin:
-      \__primargs_no_localdefs:
+      \__primargs_safe:
       \tex_aftergroup:D #3
       \tl_gset:Nn \g__primargs_code_tl
         {
@@ -130,22 +165,22 @@
       #1 =
   }
 \cs_generate_variant:Nn \__primargs_get_rhs:NnN { No }
-\cs_new_protected_nopar:Npn \primargs_get_number:N
+\cs_new_protected:Npn \primargs_get_number:N
   {
     \__primargs_get_rhs:NoN \tex_deadcycles:D
       { \tex_the:D \tex_deadcycles:D }
   }
-\cs_new_protected_nopar:Npn \primargs_get_dimen:N
+\cs_new_protected:Npn \primargs_get_dimen:N
   {
     \__primargs_get_rhs:NoN \tex_hoffset:D
       { \tex_the:D \tex_hoffset:D }
   }
-\cs_new_protected_nopar:Npn \primargs_get_glue:N
+\cs_new_protected:Npn \primargs_get_glue:N
   {
     \__primargs_get_rhs:NoN \tex_topskip:D
       { \tex_the:D \tex_topskip:D }
   }
-\cs_new_protected_nopar:Npn \primargs_get_mudimen:N
+\cs_new_protected:Npn \primargs_get_mudimen:N
   {
     \msg_warning:nn { primargs } { get-mudimen }
     \primargs_get_muglue:N
@@ -152,36 +187,81 @@
   }
 \msg_new:nnn { primargs } { get-mudimen }
   { The~\iow_char:N\\primargs_get_mudimen:N~function~is~buggy. }
-\cs_new_protected_nopar:Npn \primargs_get_muglue:N
+\cs_new_protected:Npn \primargs_get_muglue:N
   {
     \__primargs_get_rhs:NoN \tex_thinmuskip:D
       { \tex_the:D \tex_thinmuskip:D }
   }
-\cs_new_protected_nopar:Npn \primargs_get_general_text:N
-  { \__primargs_get_rhs:NoN \tex_errhelp:D { { } } }
-\tl_new:N \g__primargs_file_name_tl
+\cs_new_protected:Npn \primargs_get_general_text:N #1
+  {
+    \group_begin:
+      \__primargs_safe:
+      \tex_aftergroup:D #1
+      \tex_aftergroup:D { \if_false: } \fi:
+      \primargs_remove_filler:N \__primargs_get_general_text:
+  }
+\cs_new_protected:Npn \__primargs_get_general_text:
+  {
+    \if_catcode:w \c_group_begin_token \g_primargs_token
+      \exp_after:wN \primargs_remove_token:N
+    \else:
+      \group_begin:
+        \tex_aftergroup:D \__primargs_get_general_text_error:n
+        \if_catcode:w \c_group_end_token \g_primargs_token
+          \tex_aftergroup:D {
+          \tex_aftergroup:D }
+        \fi:
+    \fi:
+    \group_end:
+  }
+\cs_new_protected:Npn \__primargs_get_general_text_error:n #1
+  {
+    \exp_after:wN \group_end:
+    \etex_unexpanded:D \if_int_compare:w `{ = \c_zero \fi: #1 }
+  }
 \cs_new_protected:Npn \primargs_get_file_name:N #1
   {
     \group_begin:
-      \__primargs_no_localdefs:
+      \__primargs_safe:
+      \cs_gset_eq:NN \__primargs_read_x_token_aux:N
+                     \__primargs_read_x_token_file:N
       \tex_aftergroup:D #1
       \tl_gclear:N \g__primargs_file_name_tl
+      \tl_gset:Nn \g__primargs_file_name_level_tl { 0 }
       \primargs_remove_optional_spaces:N \__primargs_get_file_name_test:
   }
-\cs_new_protected_nopar:Npn \__primargs_get_file_name_test:
+\cs_new_protected:Npn \__primargs_get_file_name_test:
   {
     \token_if_cs:NTF \g_primargs_token
       { \__primargs_get_file_name_end: }
       {
         \token_if_eq_charcode:NNTF \c_space_token \g_primargs_token
-          { \primargs_remove_token:N \__primargs_get_file_name_end: }
+          { \primargs_remove_token:N \__primargs_get_file_name_space: }
           { \primargs_remove_token:N \__primargs_get_file_name_char: }
       }
   }
-\cs_new_protected_nopar:Npn \__primargs_get_file_name_end:
-  { \exp_args:No \group_end: \g__primargs_file_name_tl }
-\cs_new_protected_nopar:Npn \__primargs_get_file_name_char:
+\cs_new_protected:Npn \__primargs_get_file_name_end:
   {
+    \cs_gset_eq:NN \__primargs_read_x_token_aux:N
+                   \__primargs_read_x_token_std:N
+    \exp_args:No \group_end: \g__primargs_file_name_tl
+  }
+\cs_new_protected:Npn \__primargs_get_file_name_space:
+  {
+    \int_if_odd:nTF { \g__primargs_file_name_level_tl }
+      {
+        \tl_gput_right:Nn \g__primargs_file_name_tl { ~ }
+        \primargs_read_x_token:N \__primargs_get_file_name_test:
+      }
+      { \__primargs_get_file_name_end: }
+  }
+\cs_new_protected:Npn \__primargs_get_file_name_char:
+  {
+    \token_if_eq_charcode:NNT " \g_primargs_token
+      {
+        \tl_set:Nx \g__primargs_file_name_level_tl
+          { \int_eval:n { 1 - \g__primargs_file_name_level_tl } }
+      }
     \tl_gput_right:Nx \g__primargs_file_name_tl
       {
         \exp_after:wN \__primargs_get_file_name_char_ii:w
@@ -193,6 +273,76 @@
 \cs_new:Npn \__primargs_get_file_name_char_ii:w #1 ~ #2 ~ #3 \q_stop
   { \__primargs_get_file_name_char_iii:w #3 ~ #3 ~ \q_stop }
 \cs_new:Npn \__primargs_get_file_name_char_iii:w #1 ~ #2 ~ #3 \q_stop {#2}
+\sys_if_engine_luatex:TF
+  {
+    \cs_new_protected:Npn \primargs_get_input_file_name:N #1
+      {
+        \group_begin:
+          \__primargs_safe:
+          \tex_aftergroup:D #1
+          \tl_gclear:N \g__primargs_file_name_tl
+          \tl_gset:Nn \g__primargs_file_name_level_tl { 1 }
+          \primargs_remove_filler:N \__primargs_get_input_file_name_first:
+      }
+    \cs_new_protected:Npn \__primargs_get_input_file_name_first:
+      {
+        \token_if_eq_catcode:NNTF \g_primargs_token \c_group_begin_token
+          { \primargs_remove_token:N \__primargs_get_input_file_name_loop: }
+          { \primargs_get_file_name:N \group_end: }
+      }
+    \cs_new_protected:Npn \__primargs_get_input_file_name_loop:
+      { \primargs_read_x_token:N \__primargs_get_input_file_name_test: }
+    \cs_new_protected:Npn \__primargs_get_input_file_name_test:
+      {
+        \token_if_eq_catcode:NNTF \g_primargs_token \c_group_begin_token
+          {
+            \tl_gset:Nx \g__primargs_file_name_level_tl
+              { \int_eval:n { \g__primargs_file_name_level_tl + 1 } }
+            \primargs_remove_token:N \__primargs_get_input_file_name_brace:
+          }
+          {
+            \token_if_eq_catcode:NNTF \g_primargs_token \c_group_end_token
+              {
+                \tl_gset:Nx \g__primargs_file_name_level_tl
+                  { \int_eval:n { \g__primargs_file_name_level_tl - 1 } }
+                \int_compare:nNnTF { \g__primargs_file_name_level_tl } > 0
+                  { \primargs_remove_token:N \__primargs_get_input_file_name_brace: }
+                  { \primargs_remove_token:N \__primargs_get_file_name_end: }
+              }
+              {
+                \token_if_eq_meaning:NNTF \g_primargs_token \c_space_token
+                  {
+                    \tl_gput_right:Nn \g__primargs_file_name_tl { ~ }
+                    \primargs_remove_token:N \__primargs_get_input_file_name_loop:
+                  }
+                  { \exp_after:wN \__primargs_get_input_file_name_aux:N \exp_not:N }
+              }
+          }
+      }
+    \cs_new_protected:Npn \__primargs_get_input_file_name_brace:
+      {
+        \tl_gput_right:Nx \g__primargs_file_name_tl
+          {
+            \exp_after:wN \__primargs_get_file_name_char_ii:w
+            \token_to_meaning:N \g_primargs_token
+            \q_stop
+          }
+        \__primargs_get_input_file_name_loop:
+      }
+    \cs_new_protected:Npn \__primargs_get_input_file_name_aux:N #1
+      {
+        \exp_after:wN \str_if_eq_x:nnT
+        \exp_after:wN { \token_to_str:N #1 } { \token_to_str:N \par }
+          { \use_none:nnn }
+        \tex_xdef:D \g__primargs_file_name_tl
+          {
+            \g__primargs_file_name_tl
+            \exp_after:wN \tl_to_str:n \exp_after:wN { \exp_not:N #1 }
+          }
+        \__primargs_get_input_file_name_loop:
+      }
+  }
+  { \cs_new_eq:NN \primargs_get_input_file_name:N \primargs_get_file_name:N }
 %% 
 %%
 %% End of file `primargs.sty'.



More information about the tex-live-commits mailing list