%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \iffalse %%%%
%                                                                              %
%  Copyright (c) 2016 - Michiel Helvensteijn   (www.mhelvens.net)              %
%                                                                              %
%  This work may be distributed and/or modified under the conditions           %
%  of the LaTeX Project Public License, either version 1.3 of this             %
%  license or (at your option) any later version. The latest version           %
%  of this license is in       http://www.latex-project.org/lppl.txt           %
%  and version 1.3 or later is part of all distributions of LaTeX              %
%  version 2005/12/01 or later.                                                %
%                                                                              %
%  This work has the LPPL maintenance status `maintained'.                     %
%                                                                              %
%  The Current Maintainer of this work is Michiel Helvensteijn.                %
%                                                                              %
%  This work consists of the files withargs.tex and withargs.sty.              %
%                                                                              %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi %%%%

% \CheckSum{116}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \subsection{Package Info}                                                    %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 
%    \begin{macrocode}
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{expl3}
\ProvidesExplPackage{withargs}{2019/11/04}{0.3.1}
  {an inline construct for passing token lists as TeX parameters}
%    \end{macrocode}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \subsection{Required Packages}                                               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  
%  We just need some expl3-ish packages.
%  
%    \begin{macrocode}
\RequirePackage{xparse}
%    \end{macrocode}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \subsection{\LaTeX3 Functions}                                               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % \begin{macro}{\withargs:nn,\withargs:nnn,\withargs:nnnn,\withargs:nnnnn,\withargs:nnnnnn,
  %               \withargs:nnnnnnn,\withargs:nnnnnnnn,\withargs:nnnnnnnnn}
  % \(\overbrace{\hbox{\marg1 \marg2 \marg3 \marg4 \marg5 \marg6 \marg7 \marg8}}^{1-8}\)
  % \marg{body}
%%% \\[-.5\belowdisplayskip]\nopagebreak
%  
%  \noindent These are the |expl3| API versions of the |\withargs| command.
%  The implementation is quite straight-forward. This technique has to
%  be used by any library command that accepts \TeX-style parameters.
%  
%    \begin{macrocode}
\cs_new_protected:Nn \withargs:nn {
  \cs_set:Npn \__withargs:n ##1 {#2}
              \__withargs:n     {#1} }
\cs_new_protected:Nn \withargs:nnn {
  \cs_set:Npn \__withargs:nn ##1##2 {#3}
              \__withargs:nn    {#1}{#2} }
\cs_new_protected:Nn \withargs:nnnn {
  \cs_set:Npn \__withargs:nnn ##1##2##3 {#4}
              \__withargs:nnn   {#1}{#2}{#3} }
\cs_new_protected:Nn \withargs:nnnnn {
  \cs_set:Npn \__withargs:nnnn ##1##2##3##4 {#5}
              \__withargs:nnnn  {#1}{#2}{#3}{#4} }
\cs_new_protected:Nn \withargs:nnnnnn {
  \cs_set:Npn \__withargs:nnnnn ##1##2##3##4##5 {#6}
              \__withargs:nnnnn {#1}{#2}{#3}{#4}{#5} }
\cs_new_protected:Nn \withargs:nnnnnnn {
  \cs_set:Npn \__withargs:nnnnnn ##1##2##3##4##5##6  {#7}
              \__withargs:nnnnnn {#1}{#2}{#3}{#4}{#5}{#6} }
\cs_new_protected:Nn \withargs:nnnnnnnn {
  \cs_set:Npn \__withargs:nnnnnnn ##1##2##3##4##5##6##7   {#8}
              \__withargs:nnnnnnn {#1}{#2}{#3}{#4}{#5}{#6}{#7} }
\cs_new_protected:Nn \withargs:nnnnnnnnn {
  \cs_set:Npn \__withargs:nnnnnnnn ##1##2##3##4##5##6##7##8    {#9}
              \__withargs:nnnnnnnn {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8} }
%    \end{macrocode}
% 
%%% \end{macro}
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \subsection{Document Level Command}                                          %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % \begin{macro}{\__withargs_var:x} \marg{argument specifier}
%%% \\[-.5\belowdisplayskip]\nopagebreak
%  
%  \noindent This is a convenience command for generating
%  and using a |\withargs:| variant in one go. I only use it
%  for the document-level command, since those users can't
%  roll their own. 
%  
%  |#1| should be the number of optional |\withargs| arguments
%  and |#2| should be a \LaTeX3 argument specification not
%  longer than |#1| --- a prefix.
%  
%    \begin{macrocode}
\cs_new:Nn \__withargs_var:nn {
  \cs_generate_variant:cx
    { withargs : \prg_replicate:nn{#1}{n} n }
    { #2 n }
  \use:c {
    withargs :
    #2
    \prg_replicate:nn{#1-\tl_count:n{#2}}{n}
    n
  }
}
%    \end{macrocode}
%    \uninteresting\begin{macrocode}
\cs_generate_variant:Nn \__withargs_var:nn {nx}
\cs_generate_variant:Nn \cs_generate_variant:Nn {cx}
%    \end{macrocode}
%
%%% \end{macro} \vspace{-2mm}
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % \begin{macro}{\__withargs_process_uniquecsname:n}
  % \marg{argument}
%%% \\[-.5\belowdisplayskip]\nopagebreak
%  
%  \noindent An |xparse| processor function to pass a unique
%  control sequence name if the argument given was '|\uniquecsname|'. 
%  
%    \begin{macrocode}
\cs_new_protected:Nn\__withargs_process_uniquecsname:n{
  \tl_if_eq:nnTF {#1} {\uniquecsname} {
    \int_gincr:N \g__with_unique_int
    \tl_set:Nx \ProcessedArgument
        { Unique-CS-Name-( \int_use:N\g__with_unique_int ) }
  }{
    \tl_set:Nn \ProcessedArgument {#1}
  }
}	
\int_new:N \g__with_unique_int
%    \end{macrocode}
%
%%% \end{macro} \vspace{-2mm}
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % \begin{macro}{\__withargs_remove_spaces:n}
  % \marg{argument}
%%% \\[-.5\belowdisplayskip]\nopagebreak
%  
%  \noindent An |xparse| processor function to remove all
%  spaces from the argument.
%  
%    \begin{macrocode}
\cs_new_protected:Nn\__withargs_remove_spaces:n{
  \tl_set:Nn       \ProcessedArgument {#1}
  \tl_remove_all:Nn\ProcessedArgument {~}
}
%    \end{macrocode}
%
%%% \end{macro} \vspace{-2mm}
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


% \pagebreak


  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % \begin{macro}{\withargs}
  % \texttt{\bfseries(}\meta{argument specification}\texttt{\bfseries)}
  % \oarg{1} \oarg{2} \oarg{3} \oarg{4} \oarg{5} \oarg{6} \oarg{7}
  % \marg{body}
%%% \\[-.5\belowdisplayskip]\nopagebreak
%  
%  \noindent This is the document version of the |\withargs| command.
%  
%  \changes{0.0.2}{2013/10/11}
%    {made the first argument optional and delimited by parentheses}
%  
%    \begin{macrocode}
\NewDocumentCommand {\withargs}
    { >{\__withargs_remove_spaces:n}         D(){} % argument spec
      >{\__withargs_process_uniquecsname:n} +o     % up to 7 optional args
      >{\__withargs_process_uniquecsname:n} +o
      >{\__withargs_process_uniquecsname:n} +o
      >{\__withargs_process_uniquecsname:n} +o
      >{\__withargs_process_uniquecsname:n} +o
      >{\__withargs_process_uniquecsname:n} +o
      >{\__withargs_process_uniquecsname:n} +o
                                            +m } { % the body to execute
%    \end{macrocode}
%
%  We first check if the argument specification is valid.
%  It has to be between 0 and 7 characters long and each
%  symbol has to be one of `|noxfcv|'. Otherwise: error!
%  The variants `|N|' and `|V|' are not supported (yet) because
%  they collect arguments differently than the others, and frankly,
%  I didn't want to bother.
%
%    \begin{macrocode}
  \regex_match:nnF {^[nofxcv]{0,7}$} {#1}
    { \msg_critical:nnn{withargs}{invalid-parameter-specs}{#1} }
%    \end{macrocode}
%
%  The next bit counts the number of optional arguments provided
%  using binary search.
%  If |#1| specifies \emph{more} arguments than were provided: error!
%
%    \begin{macrocode}
  \int_set:Nn \l__with_arg_int {
    \IfNoValueTF {#5}
     { \IfNoValueTF {#3} { \IfNoValueTF{#2} 0 1 }
                         { \IfNoValueTF{#4} 2 3 } }
     { \IfNoValueTF {#7} { \IfNoValueTF{#6} 4 5 }
                         { \IfNoValueTF{#8} 6 7 } }
  }
  
  \int_compare:nNnT {\tl_count:n{#1}} > {\l__with_arg_int} {
    \msg_error:nnxxx{withargs}{invalid-parameter-number}
      { \tl_count:n{#1} }
      { \int_use:N \l__with_arg_int }
      { #1 }
  }
%    \end{macrocode}
%
%  We can then call the right variant of |\withargs:|.
%
%    \begin{macrocode}
  \int_case:nnF {\l__with_arg_int} {
    {1} { \__withargs_var:nx1{#1} {#2}                        {#9} }
    {2} { \__withargs_var:nx2{#1} {#2}{#3}                    {#9} }
    {3} { \__withargs_var:nx3{#1} {#2}{#3}{#4}                {#9} }
    {4} { \__withargs_var:nx4{#1} {#2}{#3}{#4}{#5}            {#9} }
    {5} { \__withargs_var:nx5{#1} {#2}{#3}{#4}{#5}{#6}        {#9} }
    {6} { \__withargs_var:nx6{#1} {#2}{#3}{#4}{#5}{#6}{#7}    {#9} }
    {7} { \__withargs_var:nx7{#1} {#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9} }
  }{}
%    \end{macrocode}
%    \uninteresting\begin{macrocode}
}
\int_new:N \l__with_arg_int
%    \end{macrocode}
%
%%% \end{macro}
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  
%  \noindent The following is the error message displayed
%  if the argument specification is ill-formed:
%  
%    \begin{macrocode}
\msg_new:nnnn{withargs}{invalid-parameter-specs}{
  The~argument~specification~'#1'~is~not~valid.
}{
  The~argument~specification~should~consist~of~between~one~
  and~seven~of~the~letters~'n',~'o',~'f',~'x',~'c',~'v'.
}
%    \end{macrocode}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  
%  \noindent This is the error message displayed if the
%  number of provided optional arguments is inconsistent
%  with the provided argument specification.
%  
%    \begin{macrocode}
\msg_new:nnnn{withargs}{invalid-parameter-number}{
  You~specified~#1~arguments~but~provided~#2.
}{
  Your~argument~specification~is~'#3',~which~means~you~should~
  provide~#1~optional~arguments.~However,~you~provided~#2.~
  You~should~fix~that.
}
%    \end{macrocode}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%