diff options
author | Karl Berry <karl@freefriends.org> | 2007-05-22 17:46:23 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2007-05-22 17:46:23 +0000 |
commit | f4eb27d3314d15838f674a3872000159d029f88b (patch) | |
tree | 6e9ab33c5a2d702912b4a969ade4e4e2ac586d62 /Master/texmf-dist/source | |
parent | 14af3f447439750920f754792b89f113d019076a (diff) |
update expl3
git-svn-id: svn://tug.org/texlive/trunk@4335 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source')
32 files changed, 17973 insertions, 2037 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/l3.ins b/Master/texmf-dist/source/latex/expl3/l3.ins index 786fcff9a9b..14ac72c8532 100644 --- a/Master/texmf-dist/source/latex/expl3/l3.ins +++ b/Master/texmf-dist/source/latex/expl3/l3.ins @@ -30,7 +30,7 @@ Do not distribute a modified version of this file. \generate{\file{l3basics.sty}{\from{l3basics.dtx}{package,trace}}} -% Define some basic commands That check various conditions +% Define some basic commands that check various conditions % related to defining commands eg defined/undefined global/local % Not sure how much of this really makes sense as a package, but... \generate{\file{l3chk.sty}{\from{l3chk.dtx}{package,trace}}} @@ -56,6 +56,10 @@ Do not distribute a modified version of this file. \generate{\file{l3seq.sty}{\from{l3seq.dtx}{package,trace}}} +%% LaTeX3 clists. +\generate{\file{l3clist.sty}{\from{l3clist.dtx}{package,trace}}} + + %% LaTeX3 property lists. \generate{\file{l3prop.sty}{\from{l3prop.dtx}{package,trace}}} @@ -64,14 +68,40 @@ Do not distribute a modified version of this file. \generate{\file{l3int.sty}{\from{l3int.dtx}{package,trace}}} -%% LaTeX3 precompilation -\generate{\file{l3precom.sty}{\from{l3precom.dtx}{package,precompile,trace}}} +%% LaTeX3 fake integer macros. +\generate{\file{l3num.sty}{\from{l3num.dtx}{package,trace}}} + +%% LaTeX3 skip registers. +\generate{\file{l3skip.sty}{\from{l3skip.dtx}{package,trace}}} %% LaTeX3 precompilation +\generate{\file{l3precom.sty}{\from{l3precom.dtx}{package,precompile,trace}}} + +%% LaTeX3 I/O module. \generate{\file{l3io.sty}{\from{l3io.dtx}{package,trace}}} +%% LaTeX3 program control structures (loops, booleans, ...) +\generate{\file{l3prg.sty}{\from{l3prg.dtx}{package}}} -\endbatchfile +%% LaTeX3 box module +\generate{\file{l3box.sty}{\from{l3box.dtx}{package}}} + +%% LaTeX3 messages +\generate{\file{l3messages.sty}{\from{l3messages.dtx}{package}}} + +%% LaTeX3 tokens +\generate{\file{l3token.sty}{\from{l3token.dtx}{package}}} + +%% LaTeX3 cross references +\generate{\file{l3xref.sty}{\from{l3xref.dtx}{package}}} +\generate{\file{l3xref-test.tex}{\from{l3xref.dtx}{testfile}}} +%% LaTeX3 calc module +\generate{\file{l3calc.sty}{\from{l3calc.dtx}{package}}} +%% LaTeX3 keyval module +\generate{\file{l3keyval.sty}{\from{l3keyval.dtx}{package}}} + + +\endbatchfile diff --git a/Master/texmf-dist/source/latex/expl3/l3alloc.dtx b/Master/texmf-dist/source/latex/expl3/l3alloc.dtx new file mode 100644 index 00000000000..0fa4f2aef57 --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3alloc.dtx @@ -0,0 +1,276 @@ +% \iffalse +%% File: l3alloc.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3alloc.dtx 581 2006-12-12 12:28:27Z morten $ + {L3 Experimental register allocation}% +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3alloc.dtx} +\end{document} +%</driver> +% \fi +% +% +% \title{The \textsf{l3alloc} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}\\ +% Allocating registers and the like} +% \author{\Team} +% \date{\filedate} +% \maketitle +% +% \section{Allocating registers and the like} +% +% This module provides the basic mechanism for allocating \TeX's +% registers. While designing this we have to take into account the +% following characteristics: +% \begin{itemize} +% \item |\box255| is reserved for use in the output routine, so it +% should not be allocated otherwise. +% \item \TeX\ can load up 256 hyphenation patterns (registers +% |\tex_language:D| 0-255), +% \item \TeX\ can load no more than 16 math families, +% \item \TeX\ supports no more than 16 io-streams for reading +% (|\tex_read:D|) and 16 io-streams for writing (|\tex_write:D|), +% \item \TeX\ supports no more than 256 inserts, Omega supports more. +% \item The other registers (|\tex_count:D|, |\tex_dimen:D|, +% |\tex_skip:D|, |\tex_muskip:D|, |\tex_box:D|, and |\tex_toks:D| +% range from 0 to 32768, but registers numbered above 255 are +% accessed somewhat less efficient. +% \item Registers could be allocated both globally and locally; the +% use of regsiters could also be globaly or locally. Here we +% provide support for globally allocated registers for both +% gloabl and local use and for locally allocated registers for +% local use only. +% \end{itemize} +% We also need to allow for some bookkeeping: we need to know which +% register was allocated last and which registers can not be +% allocated by the standard mechanisms. +% +% \subsection{Functions} +% +% \begin{function}{\alloc_setup_type:nnn} +% \begin{syntax} +% "\alloc_setup_type:nnn" <type> <g_start_num> <l_start_num> +% \end{syntax} +% Sets up the storage needed for the administration of registers of +% type <type>.\\ +% <type> should be a token list in braces, it can be one of +% "int", "dimen", "skip", "muskip", "box", "toks", "ior", "iow", +% "pattern", or "ins".\\ +% <g_start_num> is the number of the first not allocated global +% register, it will be incremented by 1 when the allocation is done. +% <l_start_num> is the number of the first not allocated local +% register, it will be decremented by 1 when the allocation is done. +% \end{function} +% +% \begin{function}{\alloc_reg:NnNN} +% \begin{syntax} +% "\alloc_reg:NnNN" <g-l> <type> <alloc_cmd> <cs> +% \end{syntax} +% Performs the allocation of a register of type <type> to copntrol +% sequence <cs>, using the command <alloc_cmd>. The "g" or "l" +% indicaties whether the allocation should be global or local. +% This macro is the basic building block for the definition of the +% "\"<type>"_new:N" commands +% \end{function} +% +% \StopEventually{} +% +% \subsection{The Implementation} +% +% We start by ensuring that the required packages are loaded when +% this file is loaded as a package on top of \LaTeXe. +% +% \begin{macrocode} +%<package>\RequirePackage{l3expan} +%<package>\RequirePackage{l3num} +%<package>\RequirePackage{l3seq}\par +% \end{macrocode} +% +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macro}{\alloc_setup_type:nnn} +% For each type of register we need to `counters' that hold the +% last allocated global or local register. We also need a sequence +% to store the `excpetions'. +% \begin{macrocode} +\def_new:Npn \alloc_setup_type:nnn #1 #2 #3{ + \num_new:c {g_ #1 _allocation_num} + \num_new:c {l_ #1 _allocation_num} + \seq_new:c {g_ #1 _allocation_seq} + \num_set:cn {g_ #1 _allocation_num}{#2} + \num_set:cn {l_ #1 _allocation_num}{#3} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\alloc_next_g:n} +% \begin{macro}{\alloc_next_l:n} +% These routines find the next free register. For globally allocated +% registers we first increment the counter that keeps track of them. +% \begin{macrocode} +\def_new:Npn \alloc_next_g:n #1 { + \num_gincr:c {g_ #1 _allocation_num} +% \end{macrocode} +% Then we need to check whether we have run out of registers. +% \begin{macrocode} + \num_compare:cNcTF {g_ #1 _allocation_num} = {l_ #1 _allocation_num} + {\io_put_term:x{We~ ran~ out~ of~ registers~ of~ type~ g_#1!}} + { +% \end{macrocode} +% We also need to check wether the value of the counter already +% occurs in the list of already allocated registers. +% \begin{macrocode} + \seq_if_in:cxTF {g_ #1 _allocation_seq} + {\num_use:c{g_ #1 _allocation_num}} + {\io_put_term:x{\num_use:c{g_ #1 _allocation_num}~Already~ allocated!} +% \end{macrocode} +% If it does, we find the next value. +% \begin{macrocode} + \alloc_next_g:n {#1} } + {\use_noop:} + } +% \end{macrocode} +% By now the |.._allocation_num| counter will contain the number of +% the register we will assign a control seuence for. +% \begin{macrocode} + } +% \end{macrocode} +% For the locally allocated registers we have a similar function. +% \begin{macrocode} +\def_new:Npn \alloc_next_l:n #1 { + \num_gdecr:c {l_ #1 _allocation_num} + \num_compare:cNcTF {g_ #1 _allocation_num} = {l_ #1 _allocation_num} + {\io_put_term:x{We~ ran~ out~ of~ registers~ of~ type~ l_#1!}} + { + \seq_if_in:cxTF {g_ #1 _allocation_seq} + {\num_use:c{l_ #1 _allocation_num}} + {\io_put_term:x{\num_use:c{l_ #1 _allocation_num}~Already~ allocated!} + \alloc_next_l:n {#1} } + {\io_put_term:x{\num_use:c{l_ #1 _allocation_num}~Free!}} + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\alloc_reg:NnNN} +% This internal macro performs the actual allocation. It's first +% argument is either 'g' for a globally allocated register or `l' +% for a locally allocated register. The second argument is the +% type of register to allocate, the third argument is the command +% to use and the fourth argument is the control sequence that is to +% be defined to point to the register. +% \begin{macrocode} +\def_new:Npn \alloc_reg:NnNN #1 #2 #3 #4{ +% \end{macrocode} +% It first checks that the control sequence that is to denote the +% register does not already exist. +% \begin{macrocode} + \chk_new_cs:N #4 +% \end{macrocode} +% Next, it decides whether a prefix is needed for the allocation +% command; +% \begin{macrocode} + \if:w#1g + \exp_after:NN \pref_global:D + \fi: +% \end{macrocode} +% And finally the actual allocation takes place. +% \begin{macrocode} + #3 #4 \num_use:c{#1_ #2 _allocation_num} + %%\cs_record_meaning:N#1 +% \end{macrocode} +% All that's left to do is write a message in the log file. +% \begin{macrocode} + \io_put_log:x{ + \token_to_string:N#4=#2~register~\num_use:c{#1_ #2 _allocation_num}} +% \end{macrocode} +% Finally, it calls |\alloc_next_<g/l>| to find the next free register +% number. +% \begin{macrocode} + \cs_use:c{alloc_next_#1:n} {#2} + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macrocode} +%<*showmemory> +\showMemUsage +%</showmemory> +%</initex|package> +% \end{macrocode} +% +% \endinput +% +% $Log$ +% Revision 1.6 2006/03/20 18:26:32 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.5 2006/01/15 14:02:58 braams +% Added a \SopEventually{} command +% +% Revision 1.4 2005/12/27 16:02:18 morten +% Changed RCS information retrieval +% +% Revision 1.3 2005/04/06 22:32:38 braams +% Removed the functins that belong in other modules; +% Fixed the naming conventions +% +% Revision 1.2 2005/04/05 22:12:44 braams +% First, working, version of the regsiter allocation support +% +% Revision 1.1 2005/03/16 22:50:02 braams +% Initial register allocation module +% diff --git a/Master/texmf-dist/source/latex/expl3/l3basics.dtx b/Master/texmf-dist/source/latex/expl3/l3basics.dtx index 8a4170e79cf..4181fad3182 100644 --- a/Master/texmf-dist/source/latex/expl3/l3basics.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3basics.dtx @@ -1,16 +1,49 @@ % \iffalse -%% File: l3basics.dtx Copyright (C) 1990-1998 LaTeX3 project -% +%% File: l3basics.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%<package>\RequirePackage{l3names} %<*dtx> - \ProvidesFile{l3basics.dtx} +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse %</dtx> -%<package>\NeedsTeXFormat{LaTeX2e} -%<package>\ProvidesPackage{l3basics} -%<driver> \ProvidesFile{l3basics.drv} -% \fi -% \ProvidesFile{l3basics.dtx} - [1998/05/04 v1.0i L3 Experimental basic definitions] -% +%\fi +\GetIdInfo$Id: l3basics.dtx 583 2006-12-12 17:26:44Z morten $ + {L3 Experimental basic definitions} % \iffalse %<*driver> \documentclass{l3doc} @@ -21,7 +54,6 @@ %</driver> % \fi % -% \GetFileInfo{l3basics.dtx} % \title{The \textsf{l3basics} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ @@ -31,109 +63,236 @@ % \maketitle % % -% We start by ensuring that the required packages are loaded. In -% this case there is a boot-strapping problem since, to use much of -% the code in this file, the `l3expan' package needs to be loaded; -% but this file must be loaded first. -% \begin{macrocode} -%<package>\RequirePackage{l3names}\par -% \end{macrocode} -% % As the name suggest this package holds some basic definitions which % are needed by most or all other packages in this set. % -% \section{Basics} -% -% Here we describe those functions that used all over the place. +% \section{Basics} +% +% Here we describe those functions that used all over the place. With +% that we mean functions dealing with the construction and testing of +% control sequences. Furthermore the basic parts of conditional +% processing are covered; conditional processing dealing with specific +% data types is described in the modules specific for the respective +% data types. +% +% \subsection{Predicates and conditionals} % -% \subsection{Functions} +% \subsubsection{Primitive conditionals} +% +% The \eTeX\ engine itself provides many different conditionals. Some +% expand whatever comes after them and others don't. Hence the names +% for these underlying functions will often contain a |:w| part but +% higher level functions are often available. See for instance +% |\int_compare_p:nNn| which is a wrapper for |\if_num:w|. +% +% Certain conditionals deal with specific data types like boxes and +% fonts and are described there. The ones described below are either +% the universal conditionals or deal with control sequences. We will +% prefix primitive conditionals with |\if_|. % -% \begin{function}{\cs_to_str:N} +% \begin{function}{% +% \if_true: | +% \if_false: | +% \else: | +% \fi: | +% \reverse_if:N | +% } % \begin{syntax} -% "\cs_to_str:N" <cs> +% "\if_true:" <true code> "\else:" <false code> "\fi:" \\ +% "\if_false:" <true code> "\else:" <false code> "\fi:" \\ +% "\reverse_if:N" <primitive conditional> % \end{syntax} -% This function return the name of <cs> as a sequence of letters with -% the escape character removed. +% "\if_true:" always executes <true code>, while "\if_false:" always +% executes <false code>. "\reverse_if:N" reverses any two-way primitive +% conditional. "\else:" and "\fi:" delimit the branches of the conditional. % \end{function} % -% \begin{function}{\cs_gen_sym:N | -% \cs_ggen_sym:N} +% \begin{function}{% +% \if_meaning:NN | +% \if_cs_meaning_eq:NN | +% \if_token_eq:NN | +% } % \begin{syntax} -% "\cs_gen_sym:N" <tlp> +% "\if_meaning:NN" <cs1> <cs2> <true code> "\else:" <false code> +% "\fi:" \\ +% "\if_cs_meaning_eq:NN" <cs1> <cs2> <true code> "\else:" +% <false code> "\fi:" \\ +% "\if_token_eq:NN" <token1> <token2> <true code> "\else:" <false +% code> "\fi:" % \end{syntax} -% These functions will generate a new control sequence name for use as a -% pointer, e.g.\ some tree structure like the LDB. The new unique name -% is returned locally in <tlp> for further use. The names are generated -% using the roman numeral representation of some special counters -% together with a prefix of "\l*" (local) or "\g*"( global). +% "\if_meaning:NN" executes <true code> when the replacement text, +% i.e., the expansion of <cs1> and <cs2> are the same, otherwise it +% executes <false code>. However this name isn't really that +% good. What the \TeX\ primitive does is compare two tokens to see if +% they are equal. Hence this is actually a "token" functions. A +% similar argument applies to the situation where it is used to +% compare control sequences, where it is the meaning being compared. +% Something to be cleaned up at some point. % \end{function} -% -% -% \subsection{Predicates and conditionals} -% +% % \begin{function}{% -% \if_meaning:NN | +% \if:w | +% \if_charcode:w | +% \if_catcode:w % } % \begin{syntax} -% "\if_meaning:NN" <cs1> <cs2> <true code> "\else:" <false code> "\fi:" +% "\if:w" <token1> <token2> <true code> "\else:" <false code> "\fi:" \\ +% "\if_catcode:w" <token1> <token2> <true code> "\else:" <false +% code> "\fi:" % \end{syntax} -% This conditional executes <true code> when the replacement text, i.e., -% the expansion of <cs1> and <cs2> are the same, otherwise it executes -% <false code>. -% \begin{texnote} -% This is the primitive \tn{ifx}. -% \end{texnote} +% These conditionals will expand any following tokens until two +% unexpandable tokens are left. If you wish to prevent this expansion, +% prefix the token in question with "\exp_not:N". "\if_catcode:w" +% tests if the category codes of the two tokens are the same whereas +% "\if:w" tests if the character codes are +% identical. "\if_charcode:w" is an alternative name for "\if:w". % \end{function} +% % \begin{function}{% -% \cs_eq_p:NN | +% \if_cs_exist:N | +% \if_cs_exist:w % } % \begin{syntax} -% "\cs_eq_p:NN" <cs1> <cs2> +% "\if_cs_exist:N" <cs> <true code> "\else:" <false code> "\fi:" \\ +% "\if_cs_exist:w" <tokens> "\cs_end:" <true code> "\else:" <false +% code> "\fi:" +% \end{syntax} +% Check if <cs> appears in the hash table or if the control sequence +% that can be formed from <tokens> appears in the hash table. The +% latter function does not turn the control sequence in question into +% "\scan_stop:"! This can be useful when dealing with control +% sequences which cannot be entered as a single token. +% \end{function} +% +% \begin{function}{ +% \if_mode_horizontal: | +% \if_mode_vertical: | +% \if_mode_math: | +% \if_mode_inner: +% } +% \begin{syntax} +% "\if_horizontal_mode:" <true code> "\else:" <false code> "\fi:" +% \end{syntax} +% Execute <true code> if currently in horizontal mode, otherwise +% execute <false code>. Similar for the other functions. +% \end{function} +% +% \subsubsection{Non-primitive conditionals} +% +% \begin{function}{% +% \cs_if_eq_p:NN +% } +% \begin{syntax} +% "\cs_if_eq_p:NN" <cs1> <cs2> % \end{syntax} % Returns `true' if <cs1> and <cs2> are textually the same, i.e.\ have % the same name, otherwise it returns `false'. % \end{function} -% % % \begin{function}{% -% \cs_free_p:N | +% \cs_if_eq:NNTF | +% \cs_if_eq:NNT | +% \cs_if_eq:NNF | +% \cs_if_eq:cNTF | +% \cs_if_eq:cNT | +% \cs_if_eq:cNF | +% \cs_if_eq:NcTF | +% \cs_if_eq:NcT | +% \cs_if_eq:NcF | +% \cs_if_eq:ccTF | +% \cs_if_eq:ccT | +% \cs_if_eq:ccF +% } +% \begin{syntax} +% "\cs_if_eq:NNTF" <cs1> <cs2> "{"<true code>"}{"<false code>"}" +% \end{syntax} +% These functions check if <cs1> and <cs2> have same meaning and then +% execute either <true code> or <false code>. +% \end{function} +% +% +% \begin{function}{% +% \cs_if_free_p:N % } % \begin{syntax} -% "\cs_free_p:N" <cs> +% "\cs_if_free_p:N" <cs> % \end{syntax} % Returns `true' if <cs> is either undefined or equal to "\scan_stop:". % However, it returns `false' if <cs> is textually "\c_undefined" (the % constantly undefined function), or textually "\scan_stop:". % \end{function} -% +% % \begin{function}{% -% \cs_free:NTF | -% \cs_free:NF | -% \cs_free:NT | -% \cs_free:cF | -% \cs_free:cTF | +% \cs_if_free:NTF | +% \cs_if_free:NT | +% \cs_if_free:NF | +% \cs_if_free:cTF | +% \cs_if_free:cT | +% \cs_if_free:cF % } % \begin{syntax} -% "\cs_free:NTF" <cs> "{"<true code>"}{"<false code>"}" +% "\cs_if_free:NTF" <cs> "{"<true code>"}{"<false code>"}" % \end{syntax} % These functions check if <cs> is free and then execute either <true % code> or <false code>. % \begin{texnote} -% The conditional "\cs_free:cTF" is the \LaTeX3 implementation of the -% \LaTeX2 function \tn{@ifundefined}. The other functions haven't been -% around before. +% The conditional "\cs_if_free:cTF" is the \LaTeX3 implementation of +% the \LaTeX2 function \tn{@ifundefined}. The other functions +% haven't been around before. % \end{texnote} % \end{function} -% +% % \begin{function}{% -% \cs_exist_p:N | +% \cs_if_really_free:cTF | +% \cs_if_really_free:cF | +% \cs_if_really_free:cT % } % \begin{syntax} -% "\cs_exist_p:N" <cs> +% "\cs_if_really_free:cTF" "{"<tokens>"}" "{"<true code>"} {"<false +% code>"}" % \end{syntax} -% This function does the opposite of "\cs_free_p:N". +% Similar to "\cs_if_free:cTF" but does not put anything previously +% undefined into the hash table. Useful for special control sequences +% like "\foo/bar" which cannot be entered as one token. % \end{function} -% +% +% \begin{function}{% +% \cs_if_exist_p:N +% } +% \begin{syntax} +% "\cs_if_exist_p:N" <cs> +% \end{syntax} +% This function does the opposite of "\cs_if_free_p:N". +% \end{function} +% +% \begin{function}{% +% \cs_if_exist:NTF | +% \cs_if_exist:NT | +% \cs_if_exist:NF | +% \cs_if_exist:cTF | +% \cs_if_exist:cT | +% \cs_if_exist:cF +% } +% \begin{syntax} +% "\cs_if_exist:NTF" <cs> "{"<true code>"}{"<false code>"}" +% \end{syntax} +% These functions check if <cs> exists and then execute either <true +% code> or <false code>. Exactly the opposite of "\cs_if_free:NTF". +% \end{function} +% +% \begin{function}{% +% \cs_if_really_exist:cTF | +% \cs_if_really_exist:cF | +% \cs_if_really_exist:cT +% } +% \begin{syntax} +% "\cs_if_really_exist:cTF" "{"<tokens>"}" "{"<true code>"} {"<false +% code>"}" +% \end{syntax} +% The opposite of "\cs_if_really_free:cTF". +% \end{function} +% +% % \begin{function}{% % \chk_new_cs:N | % } @@ -145,9 +304,10 @@ % control sequences by \TeX{} when "\cs:w" "..." "\cs_end:" is % used). % \end{function} -% +% % \begin{function}{% % \chk_exist_cs:N | +% \chk_exist_cs:c % } % \begin{syntax} % "\chk_exist_cs:N" <cs> @@ -155,14 +315,136 @@ % This function checks that <cs> is defined. If it is not an error % is generated. % \end{function} -% -% +% +% +% \begin{variable}{% +% \c_true | +% \c_false +% } +% \begin{syntax} +% \end{syntax} +% Constants that represent `true' or `false', respectively. Used to +% implement predicates. +% \end{variable} +% +% +% +% \subsection{Selecting and discarding tokens from the input stream} +% +% The conditional processing could not have been implemented without +% being able to gobble and select which tokens to use from the input +% stream. +% +% \begin{function}{% +% \use_none:n | +% \use_none:nn | +% \use_none:nnn | +% \use_none:nnnn | +% \use_none:nnnnn | +% \use_none:nnnnnn | +% \use_none:nnnnnnn | +% \use_none:nnnnnnnn | +% \use_none:nnnnnnnnn | +% } +% \begin{syntax} +% "\use_none:n" "{"<arg1>"}"\\ +% "\use_none:nn" "{"<arg1>"}{"<arg2>"}" +% \end{syntax} +% These functions gobble the tokens or brace groups from the input +% stream. +% \end{function} +% +% +% \begin{function}{\use_arg_i:n} +% \begin{syntax} +% "\use_arg_i:n" "{" <code1> "}" +% \end{syntax} +% Function that executes the next argument after removing the +% surrounding braces. Used to implement conditionals. +% \end{function} +% +% \begin{function}{% +% \use_arg_i:nn | +% \use_arg_ii:nn | +% } +% \begin{syntax} +% "\use_arg_i:nn" "{" <code1> "}{" <code2> "}" +% \end{syntax} +% Functions that execute the first or second argument respectively, +% after removing the surrounding braces. Primarily used to implement +% conditionals. +% \end{function} +% +% \begin{function}{% +% \use_arg_i:nnn | +% \use_arg_ii:nnn | +% \use_arg_iii:nnn | +% } +% \begin{syntax} +% "\use_arg_i:nnn" "{" <arg1> "}{" <arg2> "}{" <arg3> "}" +% \end{syntax} +% Functions that pick up one of three arguments and execute them after +% removing the surrounding braces. Should be described somewhere else. +% \end{function} +% +% \begin{function}{% +% \use_arg_i:nnnn | +% \use_arg_ii:nnnn | +% \use_arg_iii:nnnn | +% \use_arg_iv:nnnn | +% } +% \begin{syntax} +% "\use_arg_i:nnnn" "{" <arg1> "}{" <arg2> "}{" <arg3> "}{" <arg4> "}" +% \end{syntax} +% Functions that pick up one of four arguments and execute them after +% removing the surrounding braces. +% \end{function} +% +% A different kind of functions for selecting tokens from the token +% stream are those that use delimited arguments. +% +% \begin{function}{% +% \use_none_delimit_by_q_nil:w | +% \use_none_delimit_by_q_stop:w | +% } +% \begin{syntax} +% "\use_none_delimit_by_q_nil:w" <balanced text> "\q_nil" +% \end{syntax} +% Gobbles <balanced text>. Useful in gobbling the remainder in a list +% structure. +% \end{function} +% +% \begin{function}{% +% \use_arg_i_delimit_by_q_nil:nw | +% \use_arg_i_delimit_by_q_stop:nw | +% } +% \begin{syntax} +% "\use_arg_i_delimit_by_q_nil:nw" "{"<arg>"}" <balanced text> "\q_nil" +% \end{syntax} +% Gobbles <balanced text> and executes <arg> afterwards. This can also +% be used to get the first item in a token list. +% \end{function} +% +% +% \begin{function}{% +% \use_arg_i_after_fi:nw | +% \use_arg_i_after_else:nw | +% \use_arg_i_after_or:nw +% } +% \begin{syntax} +% "\use_arg_i_after_fi:nw" "{"<arg>"}" "\fi:" +% "\use_arg_i_after_else:nw" "{"<arg>"}" "\else:" <balanced text> "\fi:" +% "\use_arg_i_after_or:nw" "{"<arg>"}" "\or:" <balanced text> "\fi:" +% \end{syntax} +% Executes <arg> after executing closing out "\fi:". +% \end{function} +% % \subsection{Internal functions} -% +% % \begin{function}{% % \cs:w | -% \cs_end: | -% } +% \cs_end: +% } % \begin{syntax} % "\cs:w" <tokens> "\cs_end:" % \end{syntax} @@ -175,10 +457,11 @@ % "\cs_end:". % \end{texnote} % \end{function} -% +% % \begin{function}{\pref_global:D | % \pref_long:D | -% } +% \pref_protected:D | +% } % \begin{syntax} % "\pref_global:D" "\def:Npn" % \end{syntax} @@ -186,61 +469,55 @@ % functions (namely \ldots). The result of prefixing a function % definition with "\pref_global:D" makes the definition global, % "\pref_long:D" change the argument scanning mechanism so that it -% allows "\par" tokens in the argument of the prefixed function. -% +% allows "\par" tokens in the argument of the prefixed function, +% and "\pref_protected:D" makes the definition robust in "\write"s etc. +% +% % None of these internal functions should be used by a programmer since % the necessary combinations are all available as separate function, % e.g., "\def_long:Npn" is internally implemented as "\pref_long:D" -% "\def_long:Npn". +% "\def:Npn". % \begin{texnote} -% These prefixes are the primitives \tn{global}, \tn{long}. -% The \tn{outer} isn't used at all within \LaTeX3 -% because \ldots +% These prefixes are the primitives \tn{global}, \tn{long}, and +% \tn{protected}. The \tn{outer} isn't used at all within \LaTeX3 +% because \ldots % \end{texnote} % \end{function} -% -% \subsection{Choice functions} % -% \begin{function}{% -% \use_choice_i:nn | -% \use_choice_ii:nn | -% } -% \begin{syntax} -% "\use_choice_i:nn" "{" <code1> "}{" <code2> "}" -% \end{syntax} -% Functions that execute the first or second argument respectively, -% after removing the surrounding braces. Used to implement conditionals. -% \end{function} % -% \begin{function}{% -% \use_choice_i:nnn | -% \use_choice_ii:nnn | -% \use_choice_iii:nnn | +% +% \begin{function}{\io_put_log:x | +% \io_put_term:x | +% \io_put_deferred:Nx | % } % \begin{syntax} -% "\use_choice_i:nnn" "{" <arg1> "}{" <arg2> "}{" <arg2> "}" +% "\io_put_log:x" "{"<message>"}" +% "\io_put_deferred:Nx" <write_stream> "{"<message>"}" % \end{syntax} -% Functions that pick up one of three arguments and execute them after -% removing the surrounding braces. Should be described somewhere else. +% Writes <message> to either to log or the terminal. % \end{function} % -% \begin{function}{\use:n} -% \begin{syntax} -% "\use:n" "{" <code1> "}" -% \end{syntax} -% Function that executes the next argument after removing the -% surrounding braces. Used to implement conditionals. -% \end{function} +% \subsection{Defining functions} +% % -% \section{Defining functions} -% % There are two types of function definitions in \LaTeX3: versions % that check if the function name is still unused, and versions that % simply make the definition. The later are used for internal scratch % functions that get new meanings all over the place. -% -% (Parts of this module are a mess, as far as naming conventions are -% concerned.) +% +% For each type there is an additional choice to be made: Does the +% function to be defined contain delimited arguments? The answer in +% 99\% of the cases is no, so in most cases the programmer just want +% to input the number of arguments, which is basically how +% \cs{newcommand} in \LaTeXe{} works. Therefore we provide functions +% that expect a number as the primary type and later on in this module +% you can find the ones with the more primitive syntax. +% +% A definition of a new function can be done locally and globally. Currently +% nearly all function definitions are done locally on top level, in +% other words they are global but don't show it. Therefore I think it may +% be better to remove the local variants in the future and declare all +% checked function definitions global. % % \begin{texnote} % While \TeX{} makes all definition functions directly available to the @@ -249,15 +526,117 @@ % \TeX{} a combination of prefixes and definition functions are provided % as individual functions. % \end{texnote} -% -% \subsection{Defining new functions} -% -% A definition of a new function can be done locally and globally. Currently -% nearly all function definitions are done locally on top level, in -% other words they are global but don't show it. Therefore I think it may -% be better to remove the local variants in the future and declare all -% checked function definitions global. -% +% +% +% \subsubsection{Defining new functions} +% +% Firstly comes to variants most used namely those taking a number to +% denote the number of arguments. +% +% \begin{function}{\def_new:NNn | +% \def_new:NNx | +% \def_new:cNn | +% \def_new:cNx +% } +% \begin{syntax} +% "\def_new:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Defines a new function, making sure that <cs> is unused so far. +% <num> is the number of arguments which is in the interval $[0,9]$ +% otherwise an error is raised. It is under the responsibility of the +% programmer to name the new function according to the rules laid out +% in the previous section. <code> is either passed literally or may +% be subject to expansion (under the "x" variants). +% \end{function} +% +% \begin{function}{\gdef_new:NNn | +% \gdef_new:cNn | +% \gdef_new:NNx | +% \gdef_new:cNx +% } +% \begin{syntax} +% "\gdef_new:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Like "\def_new:NNn" but defines the new function globally. +% \end{function} +% +% \begin{function}{\def_long_new:NNn | +% \def_long_new:NNx | +% \def_long_new:cNn | +% \def_long_new:cNx +% } +% \begin{syntax} +% "\def_long_new:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Defines a function that may contain "\par" tokens in the argument(s) +% when called. This is not allowed for normal functions. +% \end{function} +% +% \begin{function}{\gdef_long_new:NNn | +% \gdef_long_new:NNx | +% \gdef_long_new:cNn | +% \gdef_long_new:cNx +% } +% \begin{syntax} +% "\gdef_long_new:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Global versions of the above functions. +% \end{function} +% +% \begin{function}{\def_protected_new:NNn | +% \def_protected_new:NNx | +% \def_protected_new:cNn | +% \def_protected_new:cNx +% } +% \begin{syntax} +% "\def_protected_new:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Defines a function that does not expand when inside an |x| type +% expansion. +% \end{function} +% +% \begin{function}{\gdef_protected_new:NNn | +% \gdef_protected_new:NNx | +% \gdef_protected_new:cNn | +% \gdef_protected_new:cNx +% } +% \begin{syntax} +% "\gdef_protected_new:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Global versions of the above functions. +% \end{function} +% +% \begin{function}{\def_protected_long_new:NNn | +% \def_protected_long_new:NNx | +% \def_protected_long_new:cNn | +% \def_protected_long_new:cNx +% } +% \begin{syntax} +% "\def_protected_long_new:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Defines a function that is both robust and may contain "\par" tokens +% in the argument(s) when called. +% \end{function} +% +% \begin{function}{\gdef_protected_long_new:NNn | +% \gdef_protected_long_new:NNx | +% \gdef_protected_long_new:cNn | +% \gdef_protected_long_new:cNx +% } +% \begin{syntax} +% "\gdef_protected_long_new:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Global versions of the above functions. +% \end{function} +% +% +% +% +% +% Secondly comes the ones where the programmer can use delimited +% arguments. Rarely needed outside the kernel. +% +% % \begin{function}{\def_new:Npn | % \def_new:Npx | % \def_new:cpn | @@ -274,7 +653,10 @@ % (under the "x" variants). % \end{function} % -% \begin{function}{\gdef_new:Npn +% \begin{function}{\gdef_new:Npn | +% \gdef_new:cpn | +% \gdef_new:Npx | +% \gdef_new:cpx % } % \begin{syntax} % "\gdef_new:Npn" <cs> <parms> "{" <code> "}" @@ -282,8 +664,11 @@ % Like "\def_new:Npn" but defines the new function globally. See % comments above. % \end{function} -% +% % \begin{function}{\def_long_new:Npn | +% \def_long_new:Npx | +% \def_long_new:cpn | +% \def_long_new:cpx % } % \begin{syntax} % "\def_long_new:Npn" <cs> <parms> "{" <code> "}" @@ -291,23 +676,198 @@ % Defines a function that may contain "\par" tokens in the argument(s) % when called. This is not allowed for normal functions. % \end{function} -% +% +% \begin{function}{\gdef_long_new:Npn | +% \gdef_long_new:Npx | +% \gdef_long_new:cpn | +% \gdef_long_new:cpx +% } +% \begin{syntax} +% "\gdef_long_new:Npn" <cs> <parms> "{" <code> "}" +% \end{syntax} +% Global versions of the above functions. +% \end{function} +% +% \begin{function}{\def_protected_new:Npn | +% \def_protected_new:Npx | +% \def_protected_new:cpn | +% \def_protected_new:cpx +% } +% \begin{syntax} +% "\def_protected_new:Npn" <cs> <parms> "{" <code> "}" +% \end{syntax} +% Defines a function that does not expand when inside an |x| type +% expansion. +% \end{function} +% +% \begin{function}{\gdef_protected_new:Npn | +% \gdef_protected_new:Npx | +% \gdef_protected_new:cpn | +% \gdef_protected_new:cpx +% } +% \begin{syntax} +% "\gdef_protected_new:Npn" <cs> <parms> "{" <code> "}" +% \end{syntax} +% Global versions of the above functions. +% \end{function} +% +% \begin{function}{\def_protected_long_new:Npn | +% \def_protected_long_new:Npx | +% \def_protected_long_new:cpn | +% \def_protected_long_new:cpx +% } +% \begin{syntax} +% "\def_protected_long_new:Npn" <cs> <parms> "{" <code> "}" +% \end{syntax} +% Defines a function that is both robust and may contain "\par" tokens +% in the argument(s) when called. +% \end{function} +% +% \begin{function}{\gdef_protected_long_new:Npn | +% \gdef_protected_long_new:Npx | +% \gdef_protected_long_new:cpn | +% \gdef_protected_long_new:cpx +% } +% \begin{syntax} +% "\gdef_protected_long_new:Npn" <cs> <parms> "{" <code> "}" +% \end{syntax} +% Global versions of the above functions. +% \end{function} +% % \begin{function}{\let_new:NN | -% \glet_new:NN} +% \let_new:cN | +% \let_new:Nc | +% \let_new:cc | +% \glet_new:NN| +% \glet_new:cN| +% \glet_new:Nc| +% \glet_new:cc } % \begin{syntax} % "\let_new:NN" <cs1> <cs2> % \end{syntax} % Gives the function <cs1> the current meaning of <cs2>. Again, we may -% do this alway globally. +% do this always globally. % \end{function} -% -% \subsection{Defining internal functions (no checks)} -% +% +% +% +% \subsubsection{Undefining functions} +% +% \begin{function}{ \cs_gundefine:N +% } +% \begin{syntax} +% "\cs_gundefine:N" <cs> +% \end{syntax} +% Undefines the control sequence. +% \end{function} +% +% \subsubsection{Defining internal functions (no checks)} +% % Besides the function definitions that check whether or not their % argument is an unused function we need function definitions that % overwrite currently used definitions. The following functions are % provided for this purpose. -% +% +% First comes the versions expecting a number to denote the number of +% arguments. +% +% \begin{function}{\def:NNn | +% \def:NNx | +% \def:cNn | +% \def:cNx | +% } +% \begin{syntax} +% "\def:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Like "\def_new:NNn" etc.\ but does not check the <cs> name. +% \end{function} +% +% \begin{function}{\gdef:NNn | +% \gdef:NNx | +% \gdef:cNn | +% \gdef:cNx | +% } +% \begin{syntax} +% "\gdef:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Like "\def:NNn" but defines the <cs> globally. +% \end{function} +% +% +% \begin{function}{\def_long:NNn | +% \def_long:NNx | +% \def_long:cNn | +% \def_long:cNx | +% } +% \begin{syntax} +% "\def_long:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Like "\def:NNn" but allows "\par" tokens in the arguments of the +% function being defined. +% \end{function} +% +% \begin{function}{\gdef_long:NNn | +% \gdef_long:NNx | +% \gdef_long:cNn | +% \gdef_long:cNx | +% } +% \begin{syntax} +% "\gdef_long:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Global variant of "\def_long:NNn". +% \end{function} +% +% \begin{function}{\def_protected:NNn | +% \def_protected:cNn | +% \def_protected:NNx | +% \def_protected:cNx | +% } +% \begin{syntax} +% "\def_protected:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Naturally robust macro that won't expand in an |x| type argument. +% This also comes as a |long| version. If you for some reason want to +% expand it inside an |x| type expansion, prefix it with +% |\exp_after:NN \use_noop:|. +% \end{function} +% +% \begin{function}{\gdef_protected:NNn | +% \gdef_protected:cNn | +% \gdef_protected:NNx | +% \gdef_protected:cNx | +% } +% \begin{syntax} +% "\gdef_protected:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Global versions of the above functions. +% \end{function} +% +% \begin{function}{\def_protected_long:NNn | +% \def_protected_long:cNn | +% \def_protected_long:NNx | +% \def_protected_long:cNx | +% } +% \begin{syntax} +% "\def_protected_long:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Naturally robust macro that won't expand in an |x| type argument. +% These varieties also allow |\par| tokens in the arguments of the +% function being defined. +% \end{function} +% +% \begin{function}{\gdef_protected_long:NNn | +% \gdef_protected_long:cNn | +% \gdef_protected_long:NNx | +% \gdef_protected_long:cNx | +% } +% \begin{syntax} +% "\gdef_protected_long:NNn" <cs> <num> "{" <code> "}" +% \end{syntax} +% Global versions of the above functions. +% \end{function} +% +% Secondly the ones that use the primitive parameter build-up: +% % \begin{function}{\def:Npn | % \def:Npx | % \def:cpn | @@ -323,7 +883,7 @@ % known in \LaTeX2 as \tn{@namedef}. "\def:cpx" has no equivalent. % \end{texnote} % \end{function} -% +% % \begin{function}{\gdef:Npn | % \gdef:Npx | % \gdef:cpn | @@ -338,21 +898,12 @@ % and \tn{xdef}. % \end{texnote} % \end{function} -% -% \begin{function}{\def:No | -% \gdef:No -% } -% \begin{syntax} -% "\def:No" <cs> "{" <code> "}" -% \end{syntax} -% Local and global variant that expands code once before defining <cs>. -% The function may not take <parms> as the others do. Perhaps this -% should be changed. -% \end{function} -% +% +% % \begin{function}{\def_long:Npn | % \def_long:Npx | % \def_long:cpn | +% \def_long:cpx | % } % \begin{syntax} % "\def_long:Npn" <cs> <parms> "{" <code> "}" @@ -360,21 +911,77 @@ % Like "\def:Npn" but allows "\par" tokens in the arguments of the % function being defined. % \end{function} -% +% % \begin{function}{\gdef_long:Npn | % \gdef_long:Npx | +% \gdef_long:cpn | +% \gdef_long:cpx | % } % \begin{syntax} % "\gdef_long:Npn" <cs> <parms> "{" <code> "}" % \end{syntax} % Global variant of "\def_long:Npn". % \end{function} -% +% +% \begin{function}{\def_protected:Npn | +% \def_protected:cpn | +% \def_protected:Npx | +% \def_protected:cpx | +% } +% \begin{syntax} +% "\def_protected:Npn" <cs> <parms> "{" <code> "}" +% \end{syntax} +% Naturally robust macro that won't expand in an |x| type argument. +% This also comes as a |long| version. If you for some reason want to +% expand it inside an |x| type expansion, prefix it with +% |\exp_after:NN \use_noop:|. +% \end{function} +% +% \begin{function}{\gdef_protected:Npn | +% \gdef_protected:cpn | +% \gdef_protected:Npx | +% \gdef_protected:cpx | +% } +% \begin{syntax} +% "\gdef_protected:Npn" <cs> <parms> "{" <code> "}" +% \end{syntax} +% Global versions of the above functions. +% \end{function} +% +% \begin{function}{\def_protected_long:Npn | +% \def_protected_long:cpn | +% \def_protected_long:Npx | +% \def_protected_long:cpx | +% } +% \begin{syntax} +% "\def_protected_long:Npn" <cs> <parms> "{" <code> "}" +% \end{syntax} +% Naturally robust macro that won't expand in an |x| type argument. +% These varieties also allow |\par| tokens in the arguments of the +% function being defined. +% \end{function} +% +% \begin{function}{\gdef_protected_long:Npn | +% \gdef_protected_long:cpn | +% \gdef_protected_long:Npx | +% \gdef_protected_long:cpx | +% } +% \begin{syntax} +% "\gdef_protected_long:Npn" <cs> <parms> "{" <code> "}" +% \end{syntax} +% Global versions of the above functions. +% \end{function} +% +% +% % \begin{function}{\let:NN | -% \glet:NN | % \let:cN | % \let:Nc | -% \let:cc +% \let:cc | +% \glet:NN | +% \glet:cN | +% \glet:Nc | +% \glet:cc % } % \begin{syntax} % "\let:cN" <cs1> <cs2> @@ -382,7 +989,7 @@ % Gives the function <cs1> the current meaning of <cs2>. Again, we may % always do this globally. % \end{function} -% +% % \begin{function}{\let:NwN} % \begin{syntax} % "\let:NwN" <cs1> <cs2> @@ -399,61 +1006,388 @@ % \end{function} % % +% \subsection{Defining test functions} +% +% +% \begin{function}{ +% \def_test_function:npn | +% \def_long_test_function:npn | +% \def_test_function_new:npn | +% \def_long_test_function_new:npn | +% } +% \begin{syntax} +% "\def_test_function_new:npn" "{"name"}" <parms> "{"<test>"}" +% \end{syntax} +% Define all the common test cases for a simple test to reduce the +% risk of typos. As an example here's how we defined the functions +% "\cs_free:cTF", "\cs_free:cT" and "\cs_free:cF". You just have to +% fill in the test. +% \begin{verbatim} +% \def_test_function:npn{cs_free:c} #1 { +% \exp_after:NN \if_meaning:NN \cs:w#1\cs_end: \scan_stop:} +% \end{verbatim} +% Be careful not to use this function inside some primitive +% conditional as \TeX\ will most likely get confused because of the +% unmatched conditionals. +% \end{function} +% +% +% \subsection{The innards of a function} +% +% \begin{function}{\cs_to_str:N} +% \begin{syntax} +% "\cs_to_str:N" <cs> +% \end{syntax} +% This function return the name of <cs> as a sequence of letters with +% the escape character removed. +% \end{function} +% +% \begin{function}{\token_to_string:N} +% \begin{syntax} +% "\token_to_string:N" <arg> +% \end{syntax} +% This function return the name of <arg> as a sequence of letters +% including the escape character. +% \end{function} +% +% \begin{function}{\token_to_meaning:N} +% \begin{syntax} +% "\token_to_meaning:N" <arg> +% \end{syntax} +% This function returns the type and definition of <arg> as a sequence +% of letters. +% \end{function} +% +% Other functions regarding arbitrary tokens can be found in the +% \textsf{l3token} module. +% +% \subsection{Grouping and scanning} +% +% \begin{function}{\scan_stop:} +% \begin{syntax} +% "\scan_stop:" +% \end{syntax} +% This function stops \TeX's scanning ahead when ending a number. +% \begin{texnote} +% This is the \TeX{} primitive \tn{relax} renamed. +% \end{texnote} +% \end{function} +% +% +% \begin{function}{\group_begin:| +% \group_end:} +% \begin{syntax} +% "\group_begin:" <...> "\group_end:" +% \end{syntax} +% Encloses <...> inside a group. +% \begin{texnote} +% These are the \TeX{} primitives \tn{begingroup} and \tn{endgroup} +% renamed. +% \end{texnote} +% \end{function} +% +% +% \subsection{Engine specific definitions} +% +% \begin{function}{\engine_aleph:TF} +% \begin{syntax} +% "\engine_aleph:TF" "{"<true code>"}" "{"<false code>"}" +% \end{syntax} +% This function detects if we're running an Aleph based format. This +% is particularly useful when allocating registers. +% \end{function} +% +% +% % \StopEventually{} -% -% \section{Renaming some \TeX{} primitives (again)} % +% +% \subsection{The Implementation} +% We start by ensuring that the required packages are loaded. We need +% \textsf{l3names} to get things going but we actually need it very +% early on, so it is loaded at the very top of this file. Also, most +% of the code below won't run until \textsf{l3expan} has been +% loaded. +% +% \subsubsection{Renaming some \TeX{} primitives (again)} +% +% \begin{macro}{\let:NwN} % Having given all the tex primitives a consistent name, we need to % give sensible names to the ones we actually want to use. -% These will be defined as needed in the apropriate modules, but +% These will be defined as needed in the appropriate modules, but % do a few now, just to get started.\footnote{This renaming gets expensive % in terms of csname usage, an alternative scheme would be to just use % the ``tex\ldots D'' name in the cases where no good alternative exists.} % \begin{macrocode} -%<*package> +%<*initex|package> \tex_let:D \let:NwN \tex_let:D -\let:NwN \def:Npn \tex_def:D -\let:NwN \gdef:Npn \tex_gdef:D -\let:NwN \def:Npx \tex_edef:D -\let:NwN \gdef:Npx \tex_xdef:D -\let:NwN \if:w \tex_if:D -\let:NwN \if_num:w \tex_ifnum:D -\let:NwN \if_meaning:NN \tex_ifx:D +% \end{macrocode} +% \end{macro} +% \begin{macro}{\if_true:} +% \begin{macro}{\if_false:} +% \begin{macro}{\else:} +% \begin{macro}{\fi:} +% \begin{macro}{\reverse_if:N} +% \begin{macro}{\if:w} +% \begin{macro}{\if_charcode:w} +% \begin{macro}{\if_catcode:w} +% Then some conditionals. +% \begin{macrocode} +\let:NwN \if_true: \tex_iftrue:D \let:NwN \if_false: \tex_iffalse:D \let:NwN \else: \tex_else:D \let:NwN \fi: \tex_fi:D +\let:NwN \reverse_if:N \etex_unless:D +\let:NwN \if:w \tex_if:D +\let:NwN \if_charcode:w \tex_if:D +\let:NwN \if_catcode:w \tex_ifcat:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\if_meaning:NN} +% \begin{macro}{\if_token_eq:NN} +% \begin{macro}{\if_cs_meaning_eq:NN} +% Some different names for |\ifx|.\footnote{MH: Clean up at some point} +% \begin{macrocode} +\let:NwN \if_meaning:NN \tex_ifx:D +\let:NwN \if_token_eq:NN \tex_ifx:D +\let:NwN \if_cs_meaning_eq:NN\tex_ifx:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\if_mode_math:} +% \begin{macro}{\if_mode_horizontal:} +% \begin{macro}{\if_mode_vertical:} +% \begin{macro}{\if_mode_inner:} +% \TeX{} lets us detect some if its modes. +% \begin{macrocode} +\let:NwN \if_mode_math: \tex_ifmmode:D +\let:NwN \if_mode_horizontal:\tex_ifhmode:D +\let:NwN \if_mode_vertical: \tex_ifvmode:D +\let:NwN \if_mode_inner: \tex_ifinner:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\if_cs_exist:N} +% \begin{macro}{\if_cs_exist:w} +% \begin{macrocode} +\let:NwN \if_cs_exist:N \etex_ifdefined:D +\let:NwN \if_cs_exist:w \etex_ifcsname:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\exp_after:NN} +% \begin{macro}{\exp_not:N} +% \begin{macro}{\exp_not:n} +% The three |\exp_| functions are used in the \textsf{l3expan} module +% where they are described. +% \begin{macrocode} +\let:NwN \exp_after:NN \tex_expandafter:D +\let:NwN \exp_not:N \tex_noexpand:D +\let:NwN \exp_not:n \etex_unexpanded:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\io_put_deferred:Nx} +% \begin{macro}{\token_to_meaning:N} +% \begin{macro}{\token_to_string:N} +% \begin{macro}{\cs:w} +% \begin{macro}{\cs_end:} +% \begin{macro}{\cs_meaning:N} +% \begin{macro}{\cs_meaning:c} +% \begin{macro}{\cs_show:N} +% \begin{macro}{\cs_show:c} +% \begin{macrocode} \let:NwN \io_put_deferred:Nx \tex_write:D \let:NwN \token_to_meaning:N \tex_meaning:D \let:NwN \token_to_string:N \tex_string:D \let:NwN \cs:w \tex_csname:D \let:NwN \cs_end: \tex_endcsname:D -\let:NwN \exp_after:NN \tex_expandafter:D +\let:NwN \cs_meaning:N \tex_meaning:D +\tex_def:D \cs_meaning:c #1{\exp_after:NN\cs_meaning:N\cs:w #1\cs_end:} +\let:NwN \cs_show:N \tex_show:D +\tex_def:D \cs_show:c #1{\exp_after:NN\cs_show:N\cs:w #1\cs_end:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\scan_stop:} +% \begin{macro}{\group_begin:} +% \begin{macro}{\group_end:} +% The next three are basic functions for which there also exist +% versions that are safe inside alignments. These safe versions are +% defined in the \textsf{l3prg} module. +% \begin{macrocode} \let:NwN \scan_stop: \tex_relax:D -\let:NwN \exp_not:N \tex_noexpand:D \let:NwN \group_begin: \tex_begingroup:D \let:NwN \group_end: \tex_endgroup:D % \end{macrocode} -% +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\group_execute_after:N} +% \begin{macrocode} +\let:NwN \group_execute_after:N \tex_aftergroup:D +% \end{macrocode} +% \end{macro} +% \begin{macro}{\the_internal:D} +% \begin{macro}{\pref_global:D} +% \begin{macro}{\pref_long:D} +% \begin{macro}{\pref_protected:D} % These following names are temporary and should be removed as soon % as possible (April 1998). % \begin{macrocode} \let:NwN \the_internal:D \tex_the:D \let:NwN \pref_global:D \tex_global:D % \end{macrocode} +% "\pref_long:D" has been documented for years but didn't exist\dots{} +% Added it and the robustness prefix. +% \begin{macrocode} +\let:NwN \pref_long:D \tex_long:D +\let:NwN \pref_protected:D \etex_protected:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \subsubsection {Defining functions} +% +% +% We start by providing functions for the typical definition +% functions. First the local ones. +% +% \begin{macro}{\def:Npn} +% \begin{macro}{\def:Npx} +% \begin{macro}{\def_long:Npn} +% \begin{macro}{\def_long:Npx} +% \begin{macro}{\def_protected:Npn} +% \begin{macro}{\def_protected:Npx} +% \begin{macro}{\def_protected_long:Npn} +% \begin{macro}{\def_protected_long:Npx} +% All assignment functions in \LaTeX3 should be naturally robust; +% after all, the \TeX\ primitives for assignments are and it can be +% a cause of problems if others aren't. +% \begin{macrocode} +\let:NwN \def:Npn \tex_def:D +\let:NwN \def:Npx \tex_edef:D +\pref_protected:D \def:Npn \def_long:Npn {\pref_long:D \def:Npn} +\pref_protected:D \def:Npn \def_long:Npx {\pref_long:D \def:Npx} +\pref_protected:D \def:Npn \def_protected:Npn {\pref_protected:D \def:Npn} +\pref_protected:D \def:Npn \def_protected:Npx {\pref_protected:D \def:Npx} +\def_protected:Npn \def_protected_long:Npn { + \pref_protected:D \pref_long:D \def:Npn +} +\def_protected:Npn \def_protected_long:Npx { + \pref_protected:D \pref_long:D \def:Npx +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % -% -% \section {Defining and checking (new) functions} +% \begin{macro}{\gdef:Npn} +% \begin{macro}{\gdef:Npx} +% \begin{macro}{\gdef_long:Npn} +% \begin{macro}{\gdef_long:Npx} +% \begin{macro}{\gdef_protected:Npn} +% \begin{macro}{\gdef_protected:Npx} +% \begin{macro}{\gdef_protected_long:Npn} +% \begin{macro}{\gdef_protected_long:Npx} +% Global versions of the above functions. +% \begin{macrocode} +\let:NwN \gdef:Npn \tex_gdef:D +\let:NwN \gdef:Npx \tex_xdef:D +\def_protected:Npn \gdef_long:Npn {\pref_long:D \gdef:Npn} +\def_protected:Npn \gdef_long:Npx {\pref_long:D \gdef:Npx} +\def_protected:Npn \gdef_protected:Npn {\pref_protected:D \gdef:Npn} +\def_protected:Npn \gdef_protected:Npx {\pref_protected:D \gdef:Npx} +\def_protected:Npn \gdef_protected_long:Npn { + \pref_protected:D \pref_long:D \gdef:Npn +} +\def_protected:Npn \gdef_protected_long:Npx { + \pref_protected:D \pref_long:D \gdef:Npx +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsubsection{Predicate implementation} % -% We need some constants now, that should actually all be defined -% together. We try to avoid using count registers for constants as -% much as possible. +% I think Michael originated the idea of expandable boolean tests. At +% first these were supposed to expand into either \texttt{TT} or +% \texttt{TF} to be tested using |\if:w| but this was later changed to +% \texttt{00} and \texttt{01}, so they can be used in logical +% operations (see the \textsf{l3prg} module). We need this from the +% get-go. % +% \begin{macro}{\c_true} +% \begin{macro}{\c_false} +% Here are the canonical boolean values. % \begin{macrocode} -\let:NwN\c_minus_one\m@ne -\tex_chardef:D \c_one = 1\scan_stop: +\def:Npn \c_true {00} +\def:Npn \c_false {01} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection {Defining and checking (new) functions} +% +% \begin{macro}{\c_minus_one} +% \begin{macro}{\c_sixteen} +% We need the constants |\c_minus_one| and |\c_sixteen| now for +% writing information to the log and the terminal but the +% rest are defined in the \textsf{l3num} module -- at least for the +% ones that can be defined with |\tex_chardef:D| or +% |\tex_mathchardef:D|. Otherwise the \textsf{l3int} module is +% required but it can't be used until the allocation has been set +% up properly! The actual allocation mechanism is in +% \textsf{l3alloc} and as \TeX{} wants to reserve count registers +% 0--9, the first available one is~10 so we use that for +% |\c_minus_one|. +% \begin{macrocode} +%<*!initex> +\let:NwN \c_minus_one\m@ne +%</!initex> +%<*!package> +\tex_countdef:D \c_minus_one = 10 \scan_stop: +\c_minus_one = -1 \scan_stop: +%</!package> \tex_chardef:D \c_sixteen = 16\scan_stop: -\tex_mathchardef:D \c_two_hundred_fifty_six = 256\scan_stop: % \end{macrocode} +% \end{macro} +% \end{macro} % % We provide two kinds of functions that can be used to define % control sequences. On the one hand we have functions that check @@ -462,11 +1396,11 @@ % if the argument is already defined. % % Before we can define them, we need some auxiliary macros that -% allow us to generate error messages. The definitions here are +% allow us to generate error messages. The definitions here are % only temporary, they will be redefined later on. % -% \begin{macro}{\io_put_log:x} -% \begin{macro}{\io_put_term:x} +% \begin{macro}{\io_put_log:x} +% \begin{macro}{\io_put_term:x} % We define a routine to write only to the log file. And a % similar one for writing to both the log file and the terminal. % @@ -476,18 +1410,18 @@ \def:Npn \io_put_term:x{ \tex_immediate:D\io_put_deferred:Nx \c_sixteen } % \end{macrocode} -% \end{macro} -% \end{macro} +% \end{macro} +% \end{macro} % -% \begin{macro}{\err_latex_bug:n} +% \begin{macro}{\err_latex_bug:x} % This will show internal errors. % \begin{macrocode} -\def:Npn\err_latex_bug:n#1{ +\def:Npn\err_latex_bug:x#1{ \io_put_term:x{This~is~a~LaTeX~bug!~Check~coding!}\tex_errmessage:D{#1}} % \end{macrocode} % \end{macro} % -% \begin{macro}{\cs_record_meaning:N} +% \begin{macro}{\cs_record_meaning:N} % This macro will be used later on for tracing purposes. But we % need some more modules to define it, so we just give some dummy % definition here. @@ -496,241 +1430,894 @@ \def:Npn \cs_record_meaning:N#1{} %</trace> % \end{macrocode} -% \end{macro} -% -% \subsection{Checking new definitions} +% \end{macro} % +% We need these two to make |\chk_new_cs:N| bulletproof. +% \begin{macrocode} +\def_long:Npn \use_none:n #1{} +\def_long:Npn \use_arg_i:n #1{#1} +% \end{macrocode} % \begin{macro}{\chk_new_cs:N} -% This command is called by |\def_new:Npn| and |\let_new:NN| etc.\ -% to make sure that the argument sequence is not already in use. If -% it is, an error is signalled. -% It checks if \m{csname} is undefined or -% |\scan_stop:|. Otherwise an error message is issued. +% This command is called by |\def_new:Npn| and |\let_new:NN| etc.\ +% to make sure that the argument sequence is not already in use. If +% it is, an error is signalled. It checks if \m{csname} is +% undefined or |\scan_stop:|. Otherwise an error message is +% issued. We have to make sure we don't put the argument into the +% conditional processing since it may be an |\if...| type function! % \begin {macrocode} \def:Npn \chk_new_cs:N #1{ - \if_meaning:NN #1\c_undefined - \else: - \if_meaning:NN #1\scan_stop: - \else: - \err_latex_bug:n {Command~name~`\token_to_string:N #1'~ - already~defined!~ - Current~meaning:~\token_to_meaning:N #1 - } - \fi: - \fi: + \if:w \cs_if_free_p:N #1 + \exp_after:NN \use_none:n + \else: + \exp_after:NN \use_arg_i:n + \fi: + { + \err_latex_bug:x {Command~name~`\token_to_string:N #1'~ + already~defined!~ + Current~meaning:~\token_to_meaning:N #1 + } + } %<*trace> - \cs_record_meaning:N#1 -% \io_put_term:x{Defining~\token_to_string:N #1~on~ - \io_put_log:x{Defining~\token_to_string:N #1~on~ - line~\tex_the:D \tex_inputlineno:D} + \cs_record_meaning:N#1 +% \io_put_term:x{Defining~\token_to_string:N #1~on~%} + \io_put_log:x{Defining~\token_to_string:N #1~on~ + line~\tex_the:D \tex_inputlineno:D} %</trace> - } +} % \end{macrocode} -% \end {macro} +% \end{macro} % -% \begin{macro}{\cs_exist_p:N} -% Expands into |\c_true| if the control sequence given as its -% argument {\em is} in use. +% On 2005/11/20 Morten said: I think names for testing if a certain +% condition is true or false should always contain |if| to avoid +% confusion. This is what we do for lots of other types of test +% functions. For now I have defined both names for the functions +% checking names of control sequences. % +% \begin{macro}{\cs_if_exist_p:N} +% Expands into |\c_true| if the control sequence given as its +% argument \emph{is} in use. % \begin{macrocode} -\def:Npn \cs_exist_p:N #1{ - \if:w \cs_free_p:N #1 +\def:Npn \cs_if_exist_p:N #1{ + \if:w \cs_if_free_p:N #1 \c_false \else: \c_true \fi:} % \end{macrocode} % \end{macro} % -% \begin{macro}{\chk_exist_cs:N } -% This function issues a warning message when the control sequence +% \begin{macro}{\chk_if_exist_cs:N } +% \begin{macro}{\chk_if_exist_cs:c } +% This function issues a warning message when the control sequence % in its argument does not exist. % \begin{macrocode} -\def:Npn \chk_exist_cs:N #1 { - \if:w \cs_exist_p:N #1 +\def:Npn \chk_if_exist_cs:N #1 { + \if:w \cs_if_exist_p:N #1 \else: - \err_latex_bug:n{Command~ `\token_to_string:N #1'~ + \err_latex_bug:x{Command~ `\token_to_string:N #1'~ not~ yet~ defined!} \fi:} +\def:Npn \chk_if_exist_cs:c #1 { + \exp_after:NN \chk_if_exist_cs:N \cs:w #1\cs_end: } % \end{macrocode} % \end{macro} +% \end{macro} % -% \begin{macro}{\cs_free_p:N} +% \begin{macro}{\cs_if_free_p:N} % Expands into |\c_true| if the control sequence given as its % argument is not yet in use. Note that we make sure to expand -% into |\c_false | if the control sequence is textually +% into |\c_false| if the control sequence is textually % |\c_undefined| or |\scan_stop:|, so that we don't end up % (re)defining them. % \begin{macrocode} -\def:Npn \cs_free_p:N #1{ - \if_meaning:NN#1\c_undefined - \if:w\cs_eq_p:NN #1\c_undefined \c_false - \else: \c_true \fi: - \else: +\def:Npn \cs_if_free_p:N #1{ + \if_cs_exist:N #1 \if_meaning:NN#1\scan_stop: - \if:w\cs_eq_p:NN #1\scan_stop: \c_false - \else: \c_true \fi: - \else: - \c_false \fi:\fi:} + \if:w\cs_if_eq_name_p:NN #1\scan_stop: + \c_false \else: \c_true \fi: + \else: + \c_false + \fi: + \else: + \if:w \cs_if_eq_name_p:NN #1\c_undefined + \c_false \else: \c_true \fi: + \fi: +} +\let:NwN \cs_free_p:N \cs_if_free_p:N % \end{macrocode} % \end{macro} % -% \subsection{More new definitions} % -% \begin{macro}{\let:NN} -% \begin{macro}{\let:cN} -% \begin{macro}{\let:Nc} -% \begin{macro}{\let:cc} -% These macros allow us to copy the definition of a control sequence -% to another control sequence. Maybe we should implement a few more -% of these. +% \begin{macro}{\str_if_eq_p:nn} +% \begin{macro}{\str_if_eq_p_aux:w} +% Takes 2 lists of characters as arguments and expands into +% |\c_true| if they are equal, and |\c_false| otherwise. Note that +% in the current implementation spaces in these strings are +% ignored.\footnote{This is a function which could use +% \cs{tlist_compare:xx}.} +% \begin{macrocode} +\def:Npn \str_if_eq_p:nn #1#2{ + \str_if_eq_p_aux:w #1\scan_stop:\\#2\scan_stop:\\ +} +\def:Npn \str_if_eq_p_aux:w #1#2\\#3#4\\{ + \if_meaning:NN#1#3 + \if_meaning:NN#1\scan_stop:\c_true \else: + \if_meaning:NN#3\scan_stop:\c_false \else: + \str_if_eq_p_aux:w #2\\#4\\\fi:\fi: + \else:\c_false \fi:} +% \end{macrocode} +% \end{macro} +% \end{macro} % +% \begin{macro}{\cs_if_eq_name_p:NN} +% An application of the above function, already streamlined for +% speed, so I put it in here. It takes two control sequences as +% arguments and expands into true iff they have the same name. +% We make it long in case one of them is |\par|! % \begin{macrocode} -\tex_long:D\def:Npn \let:NN #1{ +\def_long:Npn \cs_if_eq_name_p:NN #1#2{ + \exp_after:NN\exp_after:NN + \exp_after:NN\str_if_eq_p_aux:w + \exp_after:NN\token_to_string:N + \exp_after:NN#1 + \exp_after:NN\scan_stop: + \exp_after:NN\\ + \token_to_string:N#2\scan_stop:\\} % \end{macrocode} -% The |=| sign allows us to define funny char tokens like .|=| -% itself or \verb*= = with this function. For the definition of -% |\c_space_chartok{~}| to work we need the |~| after the |=| +% \end{macro} +% % +% \begin{macro}{\str_if_eq_var_p:nf} +% \begin{macro}{\str_if_eq_var_start:nnN} +% \begin{macro}{\str_if_eq_var_stop:w} +% A variant of |\str_if_eq_p:nn| which has the advantage of obeying +% spaces in at least the second argument. See \textsf{l3quark} for +% an application. From the hand of David Kastrup with slight +% modifications to make it fit with the remainder of the expl3 +% language. +% +% The macro builds a string of |\if:w \fi:| pairs from the first +% argument. The idea is to turn the comparison of |ab| and |cde| +% into +% \begin{verbatim} +% \tex_number:D +% \if:w \scan_stop: \if:w b\if:w a cde\scan_stop: '\fi: \fi: \fi: +% 13 +% \end{verbatim} +% The |'| is important here. If all tests are true, the |'| is read +% as part of the number in which case the returned number is |13| in +% octal notation so |\tex_number:D| returns |11|. If one test +% returns false the |'| is never seen and then we get just |13|. We +% wrap the whole process in an external |\if:w| in order to make it +% return either |\c_true| or |\c_false| since some parts of +% \textsf{l3prg} expect a predicate to return one of these two +% tokens. % \begin{macrocode} - \let:NwN #1=~} -\def:Npn\let:cN #1 {\exp_after:NN\let:NwN\cs:w#1\cs_end:=~} -\def:Npn\let:Nc{\exp_args:NNc\let:NN} -\def:Npn\let:cc{\exp_args:Ncc\let:NN} -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% -% \begin {macro}{\def_new:Npn} -% \begin {macro}{\def_new:Npx} -% \begin {macro}{\let_new:NN} -% These are like |\def:Npn| and |\let:NN|, but they first check that -% the argument command is not already in use. You may use -% |\tex_global:D|, |\tex_long:D|, and |\tex_outer:D| as -% prefixes. +\def:Npn \str_if_eq_var_p:nf#1{ + \if:w \tex_number:D\str_if_eq_var_start:nnN{}{}#1\scan_stop: +} +\def:Npn\str_if_eq_var_start:nnN#1#2#3{ + \if:w#3\scan_stop:\exp_after:NN\str_if_eq_var_stop:w\fi: + \str_if_eq_var_start:nnN{\if:w#3#1}{#2\fi:} +} +\def:Npn\str_if_eq_var_stop:w\str_if_eq_var_start:nnN#1#2#3{ + #1#3\scan_stop:'#213~\c_true\else:\c_false\fi: +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% +% \subsubsection{More new definitions} +% +% +% +% \begin{macro}{\def_new:Npn} +% \begin{macro}{\def_new:Npx} +% \begin{macro}{\def_long_new:Npn} +% \begin{macro}{\def_long_new:Npx} +% \begin{macro}{\def_protected_new:Npn} +% \begin{macro}{\def_protected_new:Npx} +% \begin{macro}{\def_protected_long_new:Npn} +% \begin{macro}{\def_protected_long_new:Npx} +% These are like |\def:Npn| and |\let:NN|, but they first check that +% the argument command is not already in use. You may use +% |\pref_global:D|, |\pref_long:D|, |\pref_protected:D|, and +% |\tex_outer:D| as prefixes. % \begin {macrocode} -\def:Npn \def_new:Npn #1{\chk_new_cs:N #1 +\def_protected:Npn \def_new:Npn #1{\chk_new_cs:N #1 \def:Npn #1} -\def:Npn \def_new:Npx #1{\chk_new_cs:N #1 +\def_protected:Npn \def_new:Npx #1{\chk_new_cs:N #1 \def:Npx #1} -\def_new:Npn \let_new:NN #1{\chk_new_cs:N #1 - \let:NN #1} +\def_protected:Npn \def_long_new:Npn #1{\chk_new_cs:N #1 + \def_long:Npn #1} +\def_protected:Npn \def_long_new:Npx #1{\chk_new_cs:N #1 + \def_long:Npx #1} +\def_protected:Npn \def_protected_new:Npn #1{\chk_new_cs:N #1 + \def_protected:Npn #1} +\def_protected:Npn \def_protected_new:Npx #1{\chk_new_cs:N #1 + \def_protected:Npx #1} +\def_protected:Npn \def_protected_long_new:Npn #1{\chk_new_cs:N #1 + \def_protected_long:Npn #1} +\def_protected:Npn \def_protected_long_new:Npx #1{\chk_new_cs:N #1 + \def_protected_long:Npx #1} % \end{macrocode} -% \end {macro} -% \end {macro} -% \end {macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\gdef_new:Npn} +% \begin{macro}{\gdef_new:Npx} +% \begin{macro}{\gdef_long_new:Npn} +% \begin{macro}{\gdef_long_new:Npx} +% \begin{macro}{\gdef_protected_new:Npn} +% \begin{macro}{\gdef_protected_new:Npx} +% \begin{macro}{\gdef_protected_long_new:Npn} +% \begin{macro}{\gdef_protected_long_new:Npx} +% Global versions of the above functions. +% \begin {macrocode} +\def_protected_new:Npn \gdef_new:Npn #1{\chk_new_cs:N #1 + \gdef:Npn #1} +\def_protected_new:Npn \gdef_new:Npx #1{\chk_new_cs:N #1 + \gdef:Npx #1} +\def_protected_new:Npn \gdef_long_new:Npn #1{\chk_new_cs:N #1 + \gdef_long:Npn #1} +\def_protected_new:Npn \gdef_long_new:Npx #1{\chk_new_cs:N #1 + \gdef_long:Npx #1} +\def_protected_new:Npn \gdef_protected_new:Npn #1{\chk_new_cs:N #1 + \gdef_protected:Npn #1} +\def_protected_new:Npn \gdef_protected_new:Npx #1{\chk_new_cs:N #1 + \gdef_protected:Npx #1} +\def_protected_new:Npn \gdef_protected_long_new:Npn #1{\chk_new_cs:N #1 + \gdef_protected_long:Npn #1} +\def_protected_new:Npn \gdef_protected_long_new:Npx #1{\chk_new_cs:N #1 + \gdef_protected_long:Npx #1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % -% \begin {macro}{\def:cpn} -% \begin {macro}{\def:cpx} -% \begin {macro}{\def_new:cpn} -% \begin {macro}{\def_new:cpx} -% Like |\def:Npn| and |\def_new:Npn|, except that the first -% argument consists of the sequence of characters that should be -% used to form the name of the desired control sequence ( the |c| -% stands for csname argument, see the expansion module.). +% +% \begin{macro}{\def:cpn} +% \begin{macro}{\def:cpx} +% \begin{macro}{\gdef:cpn} +% \begin{macro}{\gdef:cpx} +% \begin{macro}{\def_new:cpn} +% \begin{macro}{\def_new:cpx} +% \begin{macro}{\gdef_new:cpn} +% \begin{macro}{\gdef_new:cpx} +% Like |\def:Npn| and |\def_new:Npn|, except that the first argument +% consists of the sequence of characters that should be used to form +% the name of the desired control sequence (the |c| stands for +% csname argument, see the expansion module.). Global versions are +% also provided. % % |\def:cpn|\m{string}\m{rep-text} will turn \m{string} into a % csname and then assign \m {rep-text} to it by using |\def:Npn|. % This means that there might be a parameter string between the two % arguments. -% \begin {macrocode} -\def_new:Npn \def:cpn #1{\exp_after:NN - \def:Npn - \cs:w #1\cs_end:} -\def_new:Npn \def:cpx #1{\exp_after:NN - \def:Npx - \cs:w #1\cs_end:} -\def_new:Npn \def_new:cpn #1{\exp_after:NN - \def_new:Npn - \cs:w #1\cs_end:} -\def_new:Npn \def_new:cpx #1{\exp_after:NN - \def_new:Npx - \cs:w #1\cs_end:} -% \end{macrocode} -% \end {macro} -% \end {macro} -% \end {macro} -% \end {macro} -% -% -% \begin{macro}{\def:No} -% |\def:No| expands its second argument one time before making -% the definition. % \begin{macrocode} -\def_new:Npn \def:No{\exp_args:NNo\def:Npn} +\def_new:Npn \def:cpn #1{\exp_after:NN \def:Npn \cs:w #1\cs_end:} +\def_new:Npn \def:cpx #1{\exp_after:NN \def:Npx \cs:w #1\cs_end:} +\def_new:Npn \gdef:cpn #1{\exp_after:NN \gdef:Npn \cs:w #1\cs_end:} +\def_new:Npn \gdef:cpx #1{\exp_after:NN \gdef:Npx \cs:w #1\cs_end:} +\def_new:Npn \def_new:cpn #1{\exp_after:NN \def_new:Npn \cs:w #1\cs_end:} +\def_new:Npn \def_new:cpx #1{\exp_after:NN \def_new:Npx \cs:w #1\cs_end:} +\def_new:Npn \gdef_new:cpn #1{\exp_after:NN \gdef_new:Npn \cs:w #1\cs_end:} +\def_new:Npn \gdef_new:cpx #1{\exp_after:NN \gdef_new:Npx \cs:w #1\cs_end:} % \end{macrocode} -% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % -% \begin {macro}{\def_long:Npn} -% \begin {macro}{\def_long_new:Npn} -% \begin {macro}{\def_long:cpn} -% \begin {macro}{\def_long:Npx} -% |\def_long:Npn| stands for |\tex_long:D| |\def:Npn|. -% |\def_long:Npx| expands its second argument. -% \begin {macrocode} -\def_new:Npn \def_long:Npn {\tex_long:D\def:Npn} -\def_new:Npn \def_long_new:Npn #1{\chk_new_cs:N #1 - \def_long:Npn #1} -\def_new:Npn \def_long:cpn #1{\exp_after:NN - \def_long:Npn - \cs:w #1\cs_end:} -\def_new:Npn \def_long:Npx {\tex_long:D\def:Npx} -% \end{macrocode} -% \end {macro} -% \end {macro} -% \end {macro} -% \end {macro} -% -% \begin {macro}{\glet:NN} -% \begin {macro}{\glet_new:NN} -% \begin {macro}{\gdef_new:Npn} -% \begin {macro}{\gdef:cpn} -% \begin {macro}{\gdef:cpx} -% \begin {macro}{\gdef:No} -% These are global versions of some of the previosly defined functions. -% \begin {macrocode} -\def_new:Npn \glet:NN {\tex_global:D \let:NN} +% +% +% \begin{macro}{\def_long:cpn} +% \begin{macro}{\def_long:cpx} +% \begin{macro}{\gdef_long:cpn} +% \begin{macro}{\gdef_long:cpx} +% \begin{macro}{\def_long_new:cpn} +% \begin{macro}{\def_long_new:cpx} +% \begin{macro}{\gdef_long_new:cpn} +% \begin{macro}{\gdef_long_new:cpx} +% Variants of the |\def_long:Npn| versions which make a csname out +% of the first arguments. We may also do this globally. +% \begin{macrocode} +\def_new:Npn \def_long:cpn #1{\exp_after:NN \def_long:Npn \cs:w #1\cs_end:} +\def_new:Npn \def_long:cpx #1{ + \exp_after:NN\def_long:Npx\cs:w #1\cs_end:} +\def_new:Npn \gdef_long:cpn #1{ + \exp_after:NN \gdef_long:Npn \cs:w #1\cs_end:} +\def_new:Npn \gdef_long:cpx #1{ + \exp_after:NN\gdef_long:Npx\cs:w #1\cs_end:} +\def_new:Npn \def_long_new:cpn #1{ + \exp_after:NN \def_long_new:Npn \cs:w #1\cs_end:} +\def_new:Npn \def_long_new:cpx #1{ + \exp_after:NN \def_long_new:Npx \cs:w #1\cs_end:} +\def_new:Npn \gdef_long_new:cpn #1{ + \exp_after:NN \gdef_long_new:Npn \cs:w #1\cs_end:} +\def_new:Npn \gdef_long_new:cpx #1{ + \exp_after:NN \gdef_long_new:Npx \cs:w #1\cs_end:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\def_protected:cpn} +% \begin{macro}{\def_protected:cpx} +% \begin{macro}{\gdef_protected:cpn} +% \begin{macro}{\gdef_protected:cpx} +% \begin{macro}{\def_protected_new:cpn} +% \begin{macro}{\def_protected_new:cpx} +% \begin{macro}{\gdef_protected_new:cpn} +% \begin{macro}{\gdef_protected_new:cpx} +% Variants of the |\def_protected:Npn| versions which make a csname +% out of the first arguments. We may also do this globally. +% \begin{macrocode} +\def_new:Npn \def_protected:cpn #1{ + \exp_after:NN \def_protected:Npn \cs:w #1\cs_end:} +\def_new:Npn \def_protected:cpx #1{ + \exp_after:NN\def_protected:Npx\cs:w #1\cs_end:} +\def_new:Npn \gdef_protected:cpn #1{ + \exp_after:NN \gdef_protected:Npn \cs:w #1\cs_end:} +\def_new:Npn \gdef_protected:cpx #1{ + \exp_after:NN\gdef_protected:Npx\cs:w #1\cs_end:} +\def_new:Npn \def_protected_new:cpn #1{ + \exp_after:NN \def_protected_new:Npn \cs:w #1\cs_end:} +\def_new:Npn \def_protected_new:cpx #1{ + \exp_after:NN \def_protected_new:Npx \cs:w #1\cs_end:} +\def_new:Npn \gdef_protected_new:cpn #1{ + \exp_after:NN \gdef_protected_new:Npn \cs:w #1\cs_end:} +\def_new:Npn \gdef_protected_new:cpx #1{ + \exp_after:NN \gdef_protected_new:Npx \cs:w #1\cs_end:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\def_protected_long:cpn} +% \begin{macro}{\def_protected_long:cpx} +% \begin{macro}{\gdef_protected_long:cpn} +% \begin{macro}{\gdef_protected_long:cpx} +% \begin{macro}{\def_protected_long_new:cpn} +% \begin{macro}{\def_protected_long_new:cpx} +% \begin{macro}{\gdef_protected_long_new:cpn} +% \begin{macro}{\gdef_protected_long_new:cpx} +% Variants of the |\def_protected_long:Npn| versions which make a csname +% out of the first arguments. We may also do this globally. +% \begin{macrocode} +\def_new:Npn \def_protected_long:cpn #1{ + \exp_after:NN \def_protected_long:Npn \cs:w #1\cs_end:} +\def_new:Npn \def_protected_long:cpx #1{ + \exp_after:NN\def_protected_long:Npx\cs:w #1\cs_end:} +\def_new:Npn \gdef_protected_long:cpn #1{ + \exp_after:NN \gdef_protected_long:Npn \cs:w #1\cs_end:} +\def_new:Npn \gdef_protected_long:cpx #1{ + \exp_after:NN\gdef_protected_long:Npx\cs:w #1\cs_end:} +\def_new:Npn \def_protected_long_new:cpn #1{ + \exp_after:NN \def_protected_long_new:Npn \cs:w #1\cs_end:} +\def_new:Npn \def_protected_long_new:cpx #1{ + \exp_after:NN \def_protected_long_new:Npx \cs:w #1\cs_end:} +\def_new:Npn \gdef_protected_long_new:cpn #1{ + \exp_after:NN \gdef_protected_long_new:Npn \cs:w #1\cs_end:} +\def_new:Npn \gdef_protected_long_new:cpx #1{ + \exp_after:NN \gdef_protected_long_new:Npx \cs:w #1\cs_end:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\def_aux_0:NNn} +% \begin{macro}{\def_aux_1:NNn} +% \begin{macro}{\def_aux_2:NNn} +% \begin{macro}{\def_aux_3:NNn} +% \begin{macro}{\def_aux_4:NNn} +% \begin{macro}{\def_aux_5:NNn} +% \begin{macro}{\def_aux_6:NNn} +% \begin{macro}{\def_aux_7:NNn} +% \begin{macro}{\def_aux_8:NNn} +% \begin{macro}{\def_aux_9:NNn} +% \begin{macro}{\def_aux:NNnn} +% \begin{macro}{\def_aux:Ncnn} +% \begin{macro}{\def_arg_number_error_msg:Nn} +% Defining a function with $n$ arguments. First some helper functions. +% \begin{macrocode} +\def_new:cpn {def_aux_0:NNn} #1#2 {#1 #2 } +\def_new:cpn {def_aux_1:NNn} #1#2 {#1 #2 ##1 } +\def_new:cpn {def_aux_2:NNn} #1#2 {#1 #2 ##1##2 } +\def_new:cpn {def_aux_3:NNn} #1#2 {#1 #2 ##1##2##3 } +\def_new:cpn {def_aux_4:NNn} #1#2 {#1 #2 ##1##2##3##4 } +\def_new:cpn {def_aux_5:NNn} #1#2 {#1 #2 ##1##2##3##4##5 } +\def_new:cpn {def_aux_6:NNn} #1#2 {#1 #2 ##1##2##3##4##5##6 } +\def_new:cpn {def_aux_7:NNn} #1#2 {#1 #2 ##1##2##3##4##5##6##7 } +\def_new:cpn {def_aux_8:NNn} #1#2 {#1 #2 ##1##2##3##4##5##6##7##8 } +\def_new:cpn {def_aux_9:NNn} #1#2 {#1 #2 ##1##2##3##4##5##6##7##8##9 } +% \end{macrocode} +% Then the function itself which checks for the existance of such a +% helper function. If it doesn't exist, return an error. Otherwise +% call it to define \verb|#2| with the correct number of arguments. +% \begin{macrocode} +\def_protected_long_new:Npn \def_aux:NNnn #1#2#3#4 { + \cs_if_really_exist:cTF {def_aux_\tex_the:D\etex_numexpr:D #3 :NNn} + { + \cs_use:c {def_aux_\tex_the:D\etex_numexpr:D #3 :NNn} #1 #2 {#4} + } + { \def_arg_number_error_msg:Nn #2{#3} } +} +\def_new:Npn \def_aux:Ncnn #1#2{ + \exp_after:NN \def_aux:NNnn \exp_after:NN #1 \cs:w #2\cs_end:} +% \end{macrocode} +% The error message. +% \begin{macrocode} +\def_new:Npn \def_arg_number_error_msg:Nn #1#2 { + \err_latex_bug:x{ + You're~ trying~ to~ define~ the~ command~ `\token_to_string:N #1'~ + with~ \use_arg_i:n{\tex_the:D\etex_numexpr:D #2\scan_stop:} ~ + arguments~ but~ I~ only~ allow~ 0-9~ arguments.~ I~ can~ probably~ + not~ help~ you~ here + } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\def_aux_use_0_parameter:} +% \begin{macro}{\def_aux_use_1_parameter:} +% \begin{macro}{\def_aux_use_2_parameter:} +% \begin{macro}{\def_aux_use_3_parameter:} +% \begin{macro}{\def_aux_use_4_parameter:} +% \begin{macro}{\def_aux_use_5_parameter:} +% \begin{macro}{\def_aux_use_6_parameter:} +% \begin{macro}{\def_aux_use_7_parameter:} +% \begin{macro}{\def_aux_use_8_parameter:} +% \begin{macro}{\def_aux_use_9_parameter:} +% Something similar to |\def_aux_9:NNn| but for using the +% parameters. +% \begin{macrocode} +\def:cpn{def_aux_use_0_parameter:}{} +\def:cpn{def_aux_use_1_parameter:}{{##1}} +\def:cpn{def_aux_use_2_parameter:}{{##1}{##2}} +\def:cpn{def_aux_use_3_parameter:}{{##1}{##2}{##3}} +\def:cpn{def_aux_use_4_parameter:}{{##1}{##2}{##3}{##4}} +\def:cpn{def_aux_use_5_parameter:}{{##1}{##2}{##3}{##4}{##5}} +\def:cpn{def_aux_use_6_parameter:}{{##1}{##2}{##3}{##4}{##5}{##6}} +\def:cpn{def_aux_use_7_parameter:}{{##1}{##2}{##3}{##4}{##5}{##6}{##7}} +\def:cpn{def_aux_use_8_parameter:}{ + {##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}} +\def:cpn{def_aux_use_9_parameter:}{ + {##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}{##9}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\def:NNn} +% \begin{macro}{\def:NNx} +% \begin{macro}{\def:cNn} +% \begin{macro}{\def:cNx} +% \begin{macro}{\gdef:NNn} +% \begin{macro}{\gdef:NNx} +% \begin{macro}{\gdef:cNn} +% \begin{macro}{\gdef:cNx} +% \begin{macro}{\def_new:NNn} +% \begin{macro}{\def_new:NNx} +% \begin{macro}{\def_new:cNn} +% \begin{macro}{\def_new:cNx} +% \begin{macro}{\gdef_new:NNn} +% \begin{macro}{\gdef_new:NNx} +% \begin{macro}{\gdef_new:cNn} +% \begin{macro}{\gdef_new:cNx} +% Defining macros without delimited arguments is now relatively +% easy. First local and global versions of the usual |\def:Npn| +% operation. +% \begin{macrocode} +\def_new:Npn \def:NNn { \def_aux:NNnn \def:Npn } +\def_new:Npn \def:NNx { \def_aux:NNnn \def:Npx } +\def_new:Npn \def:cNn { \def_aux:Ncnn \def:Npn } +\def_new:Npn \def:cNx { \def_aux:Ncnn \def:Npx } +\def_new:Npn \gdef:NNn { \def_aux:NNnn \gdef:Npn } +\def_new:Npn \gdef:NNx { \def_aux:NNnn \gdef:Npx } +\def_new:Npn \gdef:cNn { \def_aux:Ncnn \gdef:Npn } +\def_new:Npn \gdef:cNx { \def_aux:Ncnn \gdef:Npx } +\def_new:Npn \def_new:NNn { \def_aux:NNnn \def_new:Npn } +\def_new:Npn \def_new:NNx { \def_aux:NNnn \def_new:Npx } +\def_new:Npn \def_new:cNn { \def_aux:Ncnn \def_new:Npn } +\def_new:Npn \def_new:cNx { \def_aux:Ncnn \def_new:Npx } +\def_new:Npn \gdef_new:NNn { \def_aux:NNnn \gdef_new:Npn } +\def_new:Npn \gdef_new:NNx { \def_aux:NNnn \gdef_new:Npx } +\def_new:Npn \gdef_new:cNn { \def_aux:Ncnn \gdef_new:Npn } +\def_new:Npn \gdef_new:cNx { \def_aux:Ncnn \gdef_new:Npx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\def_long:NNn} +% \begin{macro}{\def_long:NNx} +% \begin{macro}{\def_long:cNn} +% \begin{macro}{\def_long:cNx} +% \begin{macro}{\gdef_long:NNn} +% \begin{macro}{\gdef_long:NNx} +% \begin{macro}{\gdef_long:cNn} +% \begin{macro}{\gdef_long:cNx} +% \begin{macro}{\def_long_new:NNn} +% \begin{macro}{\def_long_new:NNx} +% \begin{macro}{\def_long_new:cNn} +% \begin{macro}{\def_long_new:cNx} +% \begin{macro}{\gdef_long_new:NNn} +% \begin{macro}{\gdef_long_new:NNx} +% \begin{macro}{\gdef_long_new:cNn} +% \begin{macro}{\gdef_long_new:cNx} +% Long versions of the above. +% \begin{macrocode} +\def_new:Npn \def_long:NNn { \def_aux:NNnn \def_long:Npn } +\def_new:Npn \def_long:NNx { \def_aux:NNnn \def_long:Npx } +\def_new:Npn \def_long:cNn { \def_aux:Ncnn \def_long:Npn } +\def_new:Npn \def_long:cNx { \def_aux:Ncnn \def_long:Npx } +\def_new:Npn \gdef_long:NNn { \def_aux:NNnn \gdef_long:Npn } +\def_new:Npn \gdef_long:NNx { \def_aux:NNnn \gdef_long:Npx } +\def_new:Npn \gdef_long:cNn { \def_aux:Ncnn \gdef_long:Npn } +\def_new:Npn \gdef_long:cNx { \def_aux:Ncnn \gdef_long:Npx } +\def_new:Npn \def_long_new:NNn { \def_aux:NNnn \def_long_new:Npn } +\def_new:Npn \def_long_new:NNx { \def_aux:NNnn \def_long_new:Npx } +\def_new:Npn \def_long_new:cNn { \def_aux:Ncnn \def_long_new:Npn } +\def_new:Npn \def_long_new:cNx { \def_aux:Ncnn \def_long_new:Npx } +\def_new:Npn \gdef_long_new:NNn { \def_aux:NNnn \gdef_long_new:Npn } +\def_new:Npn \gdef_long_new:NNx { \def_aux:NNnn \gdef_long_new:Npx } +\def_new:Npn \gdef_long_new:cNn { \def_aux:Ncnn \gdef_long_new:Npn } +\def_new:Npn \gdef_long_new:cNx { \def_aux:Ncnn \gdef_long_new:Npx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\def_protected:NNn} +% \begin{macro}{\def_protected:NNx} +% \begin{macro}{\def_protected:cNn} +% \begin{macro}{\def_protected:cNx} +% \begin{macro}{\gdef_protected:NNn} +% \begin{macro}{\gdef_protected:NNx} +% \begin{macro}{\gdef_protected:cNn} +% \begin{macro}{\gdef_protected:cNx} +% \begin{macro}{\def_protected_new:NNn} +% \begin{macro}{\def_protected_new:NNx} +% \begin{macro}{\def_protected_new:cNn} +% \begin{macro}{\def_protected_new:cNx} +% \begin{macro}{\gdef_protected_new:NNn} +% \begin{macro}{\gdef_protected_new:NNx} +% \begin{macro}{\gdef_protected_new:cNn} +% \begin{macro}{\gdef_protected_new:cNx} +% Protected versions of the above. +% \begin{macrocode} +\def_new:Npn \def_protected:NNn { \def_aux:NNnn \def_protected:Npn } +\def_new:Npn \def_protected:NNx { \def_aux:NNnn \def_protected:Npx } +\def_new:Npn \def_protected:cNn { \def_aux:Ncnn \def_protected:Npn } +\def_new:Npn \def_protected:cNx { \def_aux:Ncnn \def_protected:Npx } +\def_new:Npn \gdef_protected:NNn { \def_aux:NNnn \gdef_protected:Npn } +\def_new:Npn \gdef_protected:NNx { \def_aux:NNnn \gdef_protected:Npx } +\def_new:Npn \gdef_protected:cNn { \def_aux:Ncnn \gdef_protected:Npn } +\def_new:Npn \gdef_protected:cNx { \def_aux:Ncnn \gdef_protected:Npx } +\def_new:Npn \def_protected_new:NNn { \def_aux:NNnn \def_protected_new:Npn } +\def_new:Npn \def_protected_new:NNx { \def_aux:NNnn \def_protected_new:Npx } +\def_new:Npn \def_protected_new:cNn { \def_aux:Ncnn \def_protected_new:Npn } +\def_new:Npn \def_protected_new:cNx { \def_aux:Ncnn \def_protected_new:Npx } +\def_new:Npn \gdef_protected_new:NNn { \def_aux:NNnn \gdef_protected_new:Npn } +\def_new:Npn \gdef_protected_new:NNx { \def_aux:NNnn \gdef_protected_new:Npx } +\def_new:Npn \gdef_protected_new:cNn { \def_aux:Ncnn \gdef_protected_new:Npn } +\def_new:Npn \gdef_protected_new:cNx { \def_aux:Ncnn \gdef_protected_new:Npx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\def_protected_long:NNn} +% \begin{macro}{\def_protected_long:NNx} +% \begin{macro}{\def_protected_long:cNn} +% \begin{macro}{\def_protected_long:cNx} +% \begin{macro}{\gdef_protected_long:NNn} +% \begin{macro}{\gdef_protected_long:NNx} +% \begin{macro}{\gdef_protected_long:cNn} +% \begin{macro}{\gdef_protected_long:cNx} +% \begin{macro}{\def_protected_long_new:NNn} +% \begin{macro}{\def_protected_long_new:NNx} +% \begin{macro}{\def_protected_long_new:cNn} +% \begin{macro}{\def_protected_long_new:cNx} +% \begin{macro}{\gdef_protected_long_new:NNn} +% \begin{macro}{\gdef_protected_long_new:NNx} +% \begin{macro}{\gdef_protected_long_new:cNn} +% \begin{macro}{\gdef_protected_long_new:cNx} +% And finally both long and protected. +% \begin{macrocode} +\def_new:Npn \def_protected_long:NNn { \def_aux:NNnn \def_protected_long:Npn } +\def_new:Npn \def_protected_long:NNx { \def_aux:NNnn \def_protected_long:Npx } +\def_new:Npn \def_protected_long:cNn { \def_aux:Ncnn \def_protected_long:Npn } +\def_new:Npn \def_protected_long:cNx { \def_aux:Ncnn \def_protected_long:Npx } +\def_new:Npn \gdef_protected_long:NNn { \def_aux:NNnn \gdef_protected_long:Npn } +\def_new:Npn \gdef_protected_long:NNx { \def_aux:NNnn \gdef_protected_long:Npx } +\def_new:Npn \gdef_protected_long:cNn { \def_aux:Ncnn \gdef_protected_long:Npn } +\def_new:Npn \gdef_protected_long:cNx { \def_aux:Ncnn \gdef_protected_long:Npx } +\def_new:Npn \def_protected_long_new:NNn { + \def_aux:NNnn \def_protected_long_new:Npn } +\def_new:Npn \def_protected_long_new:NNx { + \def_aux:NNnn \def_protected_long_new:Npx } +\def_new:Npn \def_protected_long_new:cNn { + \def_aux:Ncnn \def_protected_long_new:Npn } +\def_new:Npn \def_protected_long_new:cNx { + \def_aux:Ncnn \def_protected_long_new:Npx } +\def_new:Npn \gdef_protected_long_new:NNn { + \def_aux:NNnn \gdef_protected_long_new:Npn } +\def_new:Npn \gdef_protected_long_new:NNx { + \def_aux:NNnn \gdef_protected_long_new:Npx } +\def_new:Npn \gdef_protected_long_new:cNn { + \def_aux:Ncnn \gdef_protected_long_new:Npn } +\def_new:Npn \gdef_protected_long_new:cNx { + \def_aux:Ncnn \gdef_protected_long_new:Npx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\let:NN} +% \begin{macro}{\let:cN} +% \begin{macro}{\let:Nc} +% \begin{macro}{\let:cc} +% \begin{macro}{\let_new:NN} +% \begin{macro}{\let_new:cN} +% \begin{macro}{\let_new:Nc} +% \begin{macro}{\let_new:cc} +% These macros allow us to copy the definition of a control sequence +% to another control sequence. +% \begin{macrocode} +\def_protected_long_new:Npn \let:NN #1{ +% \end{macrocode} +% The |=| sign allows us to define funny char tokens like .|=| +% itself or \verb*= = with this function. For the definition of +% |\c_space_chartok{~}| to work we need the |~| after the |=| +% \begin{macrocode} + \let:NwN #1=~} +\def_new:Npn\let:cN #1 {\exp_after:NN\let:NN\cs:w#1\cs_end:} +\def_new:Npn\let:Nc{\exp_args:NNc\let:NN} +\def_new:Npn\let:cc{\exp_args:Ncc\let:NN} +\def_new:Npn \let_new:NN #1{\chk_new_cs:N #1 + \let:NN #1} +\def_new:Npn \let_new:cN {\exp_args:Nc \let_new:NN} +\def_new:Npn \let_new:Nc {\exp_args:NNc \let_new:NN} +\def_new:Npn \let_new:cc {\exp_args:Ncc \let_new:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\glet:NN} +% \begin{macro}{\glet:cN} +% \begin{macro}{\glet:Nc} +% \begin{macro}{\glet:cc} +% \begin{macro}{\glet_new:NN} +% \begin{macro}{\glet_new:cN} +% \begin{macro}{\glet_new:Nc} +% \begin{macro}{\glet_new:cc} +% These are global versions of some of the previously defined functions. +% \begin{macrocode} +\def_protected_new:Npn \glet:NN {\pref_global:D \let:NN} +\def_protected_new:Npn \glet:Nc {\exp_args:NNc \glet:NN} +\def_protected_new:Npn \glet:cN {\exp_args:Nc \glet:NN} +\def_new:Npn \glet:cc {\exp_args:Ncc \glet:NN} \def_new:Npn \glet_new:NN #1{\chk_new_cs:N #1 \tex_global:D\let:NN #1} -\def_new:Npn \gdef_new:Npn #1{\chk_new_cs:N #1 - \gdef:Npn #1} -\def_new:Npn \gdef:cpn {\tex_global:D \def:cpn} -\def_new:Npn \gdef:cpx {\tex_global:D \def:cpx} -\def_new:Npn \gdef:No {\exp_args:NNo\gdef:Npn} +\def_new:Npn \glet_new:cN {\exp_args:Nc \glet_new:NN} +\def_new:Npn \glet_new:Nc {\exp_args:NNc \glet_new:NN} +\def_new:Npn \glet_new:cc {\exp_args:Ncc \glet_new:NN} % \end{macrocode} -% \end {macro} -% \end {macro} -% \end {macro} -% \end {macro} -% \end {macro} -% \end {macro} - -% \begin {macro}{\gdef_long:Npn} -% \begin {macro}{\gdef_long:Npx} -% |\gdef_long:Npn| stands for |\tex_long:D| |\tex_global:D| |\def:Npn|. -% |\gdef_long:Npx| expands its second argument. -% \begin {macrocode} -\def_new:Npn \gdef_long:Npn {\tex_long:D\gdef:Npn} -\def_new:Npn \gdef_long:Npx {\tex_long:D\gdef:Npx} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\def:No} +% \begin{macro}{\gdef:No} +% |\def:No| expands its second argument one time before making +% the definition. +% \begin{macrocode} +\def_new:Npn \def:No{\exp_args:NNo\def:Npn} +\def_new:Npn \gdef:No {\exp_args:NNo\gdef:Npn} % \end{macrocode} -% \end {macro} -% \end {macro} +% \end{macro} +% \end{macro} % -% \begin {macro}{\gfuturelet:NNN} -% This is a global version of |\let_peek_after:NNN| -% \begin {macrocode} -\def_new:Npn \gfuturelet:NNN{\tex_global:D \let_peek_after:NNN} +% \begin{macro}{\def_test_function_aux:Nnnn} +% \begin{macro}{\def_test_function_aux:Nnnx} +% \begin{macro}{\def_test_function:npn} +% \begin{macro}{\def_test_function:npx} +% \begin{macro}{\def_long_test_function:npn} +% \begin{macro}{\def_long_test_function:npx} +% \begin{macro}{\def_test_function_new:npn} +% \begin{macro}{\def_test_function_new:npx} +% \begin{macro}{\def_long_test_function_new:npn} +% \begin{macro}{\def_long_test_function_new:npx} +% We will often be defining several almost identical TF, T and F +% type functions so it makes sense for us to define a small function +% that will do this for us so that we are less likely to introduce +% typos (it does tend to happen). By doing it in two steps as below +% we can still retain a simple interface where you write the \TeX\ +% parameters as usual. Just don't do it when you're already within a +% conditional! +% +% I think the ways of exiting conditionals below are as fast as they +% get. Using |\reverse_if:N| instead of |\else:| didn't give any +% difference I could measure. +% \begin{macrocode} +\def_long_new:Npn \def_test_function_aux:Nnnn #1#2#3#4{ + #1 {#2TF} #3 {#4 + \exp_after:NN\use_arg_i:nn\else:\exp_after:NN\use_arg_ii:nn\fi:} + #1 {#2T} #3 {#4 + \else:\exp_after:NN\use_none:nn\fi:\use_arg_i:n} + #1 {#2F} #3 {#4 + \exp_after:NN\use_none:nn\fi:\use_arg_i:n}} +\def_long_new:Npn \def_test_function_aux:Nnnx #1#2#3#4{ + #1 {#2TF} #3 {#4 + \exp_not:n{\exp_after:NN\use_arg_i:nn\else:\exp_after:NN\use_arg_ii:nn\fi:}} + #1 {#2T} #3 {#4 + \exp_not:n{\else:\exp_after:NN\use_none:nn\fi:\use_arg_i:n}} + #1 {#2F} #3 {#4 + \exp_not:n{\exp_after:NN\use_none:nn\fi:\use_arg_i:n}}} +\def_long_new:Npn \def_test_function:npn #1#2#{ + \def_test_function_aux:Nnnn \def:cpn {#1}{#2} +} +\def_long_new:Npn \def_test_function:npx #1#2#{ + \def_test_function_aux:Nnnx \def:cpx {#1}{#2} +} +\def_long_new:Npn \def_long_test_function:npn #1#2#{ + \def_test_function_aux:Nnnn \def_long:cpn {#1}{#2} +} +\def_long_new:Npn \def_long_test_function:npx #1#2#{ + \def_test_function_aux:Nnnx \def_long:cpx {#1}{#2} +} +\def_long_new:Npn \def_test_function_new:npn #1#2#{ + \def_test_function_aux:Nnnn \def_new:cpn {#1}{#2} +} +\def_long_new:Npn \def_long_test_function_new:npn #1#2#{ + \def_test_function_aux:Nnnn \def_long_new:cpn {#1}{#2} +} +\def_long_new:Npn \def_test_function_new:npx #1#2#{ + \def_test_function_aux:Nnnx \def_new:cpx {#1}{#2} +} +\def_long_new:Npn \def_long_test_function_new:npx #1#2#{ + \def_test_function_aux:Nnnx \def_long_new:cpx {#1}{#2} +} % \end{macrocode} -% \end {macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% % -% \subsection{Further checking} -% -% \begin{macro}{\cs_free:NTF} -% \begin{macro}{\cs_free:NT} -% \begin{macro}{\cs_free:NF} -% The old |\@ifundefined| of \LaTeX{} 2.09 is reimplemented in the +% \subsubsection{Further checking} +% +% \begin{macro}{\cs_if_free:NTF} +% \begin{macro}{\cs_if_free:NT} +% \begin{macro}{\cs_if_free:NF} +% The old |\@ifundefined| of \LaTeX{} 2.09 is re-implemented in the % function |\cs_free:cTF|, again in a way that |\else:| and |\fi:| % are removed. In this implementation this is absolutely % necessary because functions inside the conditional parts expect @@ -739,141 +2326,260 @@ % \m{csnames} directly and therefore allows both |\scan_stop:| and % |\c_undefined|. % \begin{macrocode} -\def_long_new:Npn \cs_free:NTF #1{\if:w\cs_free_p:N #1 - \exp_after:NN \use_choice_i:nn \else: - \exp_after:NN \use_choice_ii:nn \fi:} -\def_long_new:Npn \cs_free:NT #1{\if:w\cs_free_p:N #1 - \exp_after:NN \use:n \else: - \exp_after:NN \use_none:n \fi:} -\def_long_new:Npn \cs_free:NF #1{\if:w\cs_free_p:N #1 - \exp_after:NN \use_none:n \else: - \exp_after:NN \use:n \fi:} +\def_long_test_function_new:npn {cs_if_free:N}#1{\if:w\cs_if_free_p:N #1} +\let:NN \cs_free:NTF \cs_if_free:NTF +\let:NN \cs_free:NT \cs_if_free:NT +\let:NN \cs_free:NF \cs_if_free:NF % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % -% \begin{macro}{\cs_free:cTF} -% \begin{macro}{\cs_free:cT} -% \begin{macro}{\cs_free:cF} +% \begin{macro}{\cs_if_free:cTF} +% \begin{macro}{\cs_if_free:cT} +% \begin{macro}{\cs_if_free:cF} % We have to implement the |c| variants `by hand' because a different % test is necessary and I don't want the overhead for the test with % |\if:w|. What a mistake Don made by making this a % feature of |\cs:w|. If I'm not totally mistaken this % feature alone has cost him more than 600\$ for bug-checks. % \begin{macrocode} -\def_long_new:Npn \cs_free:cTF #1{ - \exp_after:NN - \if_meaning:NN - \cs:w#1\cs_end: - \scan_stop: - \exp_after:NN \use_choice_i:nn - \else: - \exp_after:NN \use_choice_ii:nn - \fi:} -\def_long_new:Npn \cs_free:cF #1{\exp_after:NN - \if_meaning:NN \cs:w#1\cs_end: \scan_stop: - \exp_after:NN \use_none:nn \fi: \use:n} -\def_long_new:Npn \cs_free:cT #1{\exp_after:NN - \if_meaning:NN \cs:w#1\cs_end: \scan_stop: - \else: - \exp_after:NN \use_none:nn \fi: \use:n} +\def_long_test_function_new:npn {cs_if_free:c}#1{ + \exp_after:NN \if_meaning:NN \cs:w#1\cs_end: \scan_stop:} +\let:NN \cs_free:cTF \cs_if_free:cTF +\let:NN \cs_free:cT \cs_if_free:cT +\let:NN \cs_free:cF \cs_if_free:cF % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % +% \begin{macro}{\cs_if_really_free:cTF} +% \begin{macro}{\cs_if_really_free:cT} +% \begin{macro}{\cs_if_really_free:cF} +% These versions are for special control sequences that can only be +% formed through |\cs:w ... \cs_end:|. They do not turn the control +% sequence formed into |\scan_stop:|. +% \begin{macrocode} +\def_long_test_function_new:npn {cs_if_really_free:c}#1{ + \reverse_if:N\if_cs_exist:w #1\cs_end:} +\let:NN \cs_really_free:cTF \cs_if_really_free:cTF +\let:NN \cs_really_free:cT \cs_if_really_free:cT +\let:NN \cs_really_free:cF \cs_if_really_free:cF +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\cs_if_exist:NTF} +% \begin{macro}{\cs_if_exist:NT} +% \begin{macro}{\cs_if_exist:NF} +% \begin{macro}{\cs_if_exist:cTF} +% \begin{macro}{\cs_if_exist:cT} +% \begin{macro}{\cs_if_exist:cF} +% \begin{macro}{\cs_if_really_exist:cTF} +% \begin{macro}{\cs_if_really_exist:cT} +% \begin{macro}{\cs_if_really_exist:cF} +% Now the same functions but with reverse logic: test if the control +% sequence exists. +% \begin{macrocode} +\def_long_test_function_new:npn {cs_if_exist:N}#1{\if:w\cs_if_exist_p:N #1} +\def_long_test_function_new:npn {cs_if_exist:c}#1{ + \exp_after:NN\reverse_if:N + \exp_after:NN \if_meaning:NN \cs:w#1\cs_end: \scan_stop:} +\def_long_test_function_new:npn {cs_if_really_exist:c}#1{ + \if_cs_exist:w #1\cs_end:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % -% \subsection{Freeing memory} % -% \begin{macro}{\gundefine:N } +% \subsubsection{Freeing memory} +% +% \begin{macro}{\cs_gundefine:N } % The following function is used to free the main memory from the % definition of some function that isn't in use any longer. % \begin{macrocode} -\def_new:Npn \gundefine:N #1{\glet:NN #1\c_undefined} +\def_new:Npn \cs_gundefine:N #1{\glet:NN #1\c_undefined} % \end{macrocode} % \end{macro} % -% \subsection{Gobbling tokens from input} % -% \begin{macro}{\use_none:n} -% \begin{macro}{\use_none:nn} -% \begin{macro}{\use_none:nnn} -% \begin{macro}{\use_none:nnnn} -% To gobble tokens from the input we use a standard naming -% convention: the number of tokens gobbled is given by the number -% of |n|'s following the |:| in the name. +% \subsubsection{Engine specific definitions} +% +% \begin{macro}{\engine_aleph:TF} +% In some cases it will be useful to know which engine we're running. % \begin{macrocode} -\def_long_new:Npn \use_none:n #1{} -\def_long_new:Npn \use_none:nn #1#2{} -\def_long_new:Npn \use_none:nnn #1{\use_none:nn} -\def_long_new:Npn \use_none:nnnn - {\exp_after:NN\use_none:nn \use_none:nn} +\def_test_function_new:npn {engine_aleph:}{\if_cs_exist:N \aleph_textdir:D} % \end{macrocode} % \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % % -% \subsection{Selecting tokens} % -% \begin{macro}{\use:n} +% \subsubsection{Selecting tokens} +% +% \begin{macro}{\use_arg_i:n} % This macro grabs its argument and returns it back to the input % (with outer braces removed). % \begin{macrocode} -\def_long_new:Npn \use:n #1{#1} +%\def_long_new:Npn \use_arg_i:n #1{#1}% moved earlier % \end{macrocode} % \end{macro} % % \begin{macro}{\use:c} +% \begin{macro}{\cs_use:c} % \begin{macro}{\use:cc} % This macro grabs its argument and returns a csname from it. % \begin{macrocode} \def_new:Npn \use:c #1{\cs:w #1\cs_end:} - +\def_new:Npn \cs_use:c #1 { \cs:w#1\cs_end: } % \end{macrocode} -% THE NAME IS COMPLETELY WRONG!!!!! +% THE NAME IS COMPLETELY WRONG!!!!! +% Morten says: Perhaps this is really |\exp_args:cc| instead? % \begin{macrocode} \def_new:Npn \use:cc #1#2 {\cs:w #1\exp_after:NN\cs_end:\cs:w #2\cs_end:} % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % -% \begin{macro}{\use_choice_i:nn} -% \begin{macro}{\use_choice_ii:nn} +% \begin{macro}{\use_arg_i:nn} +% \begin{macro}{\use_arg_ii:nn} % These macros are needed to provide functions with true and false % cases, as introduced by Michael some time ago. By using -% |\exp_after:NN| |\use_choice_i:nn | |\else:| constructions it +% |\exp_after:NN| |\use_arg_i:nn | |\else:| constructions it % is possible to write code where the true or false case is able to % access the following tokens from the input stream, which is not % possible if the |\c_true| syntax is used. % \begin{macrocode} -\def_long_new:Npn \use_choice_i:nn #1#2{#1} -\def_long_new:Npn \use_choice_ii:nn #1#2{#2} +\def_long_new:Npn \use_arg_i:nn #1#2{#1} +\def_long_new:Npn \use_arg_ii:nn #1#2{#2} % \end{macrocode} % \end{macro} % \end{macro} % % % -% \begin{macro}{\use_choice_i:nnn} -% \begin{macro}{\use_choice_ii:nnn} -% \begin{macro}{\use_choice_iii:nnn} +% \begin{macro}{\use_arg_i:nnn} +% \begin{macro}{\use_arg_ii:nnn} +% \begin{macro}{\use_arg_iii:nnn} +% \begin{macro}{\use_arg_i:nnnn} +% \begin{macro}{\use_arg_ii:nnnn} +% \begin{macro}{\use_arg_iii:nnnn} +% \begin{macro}{\use_arg_iv:nnnn} % We also need something for picking up arguments from a longer -% list. +% list. % \begin{macrocode} -\def_long_new:Npn\use_choice_i:nnn#1#2#3{#1} -\def_long_new:Npn\use_choice_ii:nnn#1#2#3{#2} -\def_long_new:Npn\use_choice_iii:nnn#1#2#3{#3} +\def_long_new:NNn \use_arg_i:nnn 3{#1} +\def_long_new:NNn \use_arg_ii:nnn 3{#2} +\def_long_new:NNn \use_arg_iii:nnn 3{#3} +\def_long_new:NNn \use_arg_i:nnnn 4{#1} +\def_long_new:NNn \use_arg_ii:nnnn 4{#2} +\def_long_new:NNn \use_arg_iii:nnnn 4{#3} +\def_long_new:NNn \use_arg_iv:nnnn 4{#4} % \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\use_arg_i_ii:nn} +% And a function for grabbing two arguments and returning them +% again. +% \begin{macrocode} +\def_long_new:NNn\use_arg_i_ii:nn 2{#1#2} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\use_none_delimit_by_q_nil:w} +% \begin{macro}{\use_none_delimit_by_q_stop:w} +% Functions that gobble everything until they see either |\q_nil| or +% |\q_stop| resp. +% \begin{macrocode} +\def_long_new:Npn \use_none_delimit_by_q_nil:w #1\q_nil{} +\def_long_new:Npn \use_none_delimit_by_q_stop:w #1\q_stop{} +% \end{macrocode} +% \end{macro} +% \end{macro} % +% \begin{macro}{\use_arg_i_delimit_by_q_nil:nw} +% \begin{macro}{\use_arg_i_delimit_by_q_stop:nw} +% Same as above but execute first argument after gobbling. Very +% useful when you need to skip the rest of a mapping sequence but +% want an easy way to control what should be expanded next. +% \begin{macrocode} +\def_long_new:Npn \use_arg_i_delimit_by_q_nil:nw #1#2\q_nil{#1} +\def_long_new:Npn \use_arg_i_delimit_by_q_stop:nw #1#2\q_stop{#1} +% \end{macrocode} +% \end{macro} +% \end{macro} % -% \subsection{Scratch functions} +% +% \begin{macro}{\use_arg_i_after_fi:nw} +% \begin{macro}{\use_arg_i_after_else:nw} +% \begin{macro}{\use_arg_i_after_or:nw} +% Returns the first argument after ending the conditional. +% \begin{macrocode} +\def_long_new:Npn \use_arg_i_after_fi:nw #1\fi:{\fi: #1} +\def_long_new:Npn \use_arg_i_after_else:nw #1\else:#2\fi:{\fi: #1} +\def_long_new:Npn \use_arg_i_after_or:nw #1\or: #2\fi: {\or:\fi:#1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsubsection{Gobbling tokens from input} +% +% \begin{macro}{\use_none:n} +% \begin{macro}{\use_none:nn} +% \begin{macro}{\use_none:nnn} +% \begin{macro}{\use_none:nnnn} +% \begin{macro}{\use_none:nnnnn} +% \begin{macro}{\use_none:nnnnnn} +% \begin{macro}{\use_none:nnnnnnn} +% \begin{macro}{\use_none:nnnnnnnn} +% \begin{macro}{\use_none:nnnnnnnnn} +% To gobble tokens from the input we use a standard naming +% convention: the number of tokens gobbled is given by the number of +% |n|'s following the |:| in the name. Although defining +% |\use_none:nnn| and above as separate calls of |\use_none:n| and +% |\use_none:nn| is slightly faster, this is very non-intuitive to +% the programmer who will assume that expanding such a function once +% will take care of gobbling all the tokens in one go. +% \begin{macrocode} +%\def_long_new:NNn \use_none:n 1{}% moved earlier +\def_long_new:NNn \use_none:nn 2{} +\def_long_new:NNn \use_none:nnn 3{} +\def_long_new:NNn \use_none:nnnn 4{} +\def_long_new:NNn \use_none:nnnnn 5{} +\def_long_new:NNn \use_none:nnnnnn 6{} +\def_long_new:NNn \use_none:nnnnnnn 7{} +\def_long_new:NNn \use_none:nnnnnnnn 8{} +\def_long_new:NNn \use_none:nnnnnnnnn 9{} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \subsubsection{Scratch functions} % % \begin{macro}{\gtmp:w} % This function is for global scratch definitions that are used @@ -902,92 +2608,68 @@ % \end{macrocode} % \end{macro} % -% \section{Strings and input stream token lists} +% \subsubsection{Strings and input stream token lists} % % \begin{macro}{\cs_to_str:N} -% This converts a control sequence into the character string of its +% This converts a control sequence into the character string of its % name, removing the leading escape character. % \begin{macrocode} \def_new:Npn \cs_to_str:N {\exp_after:NN\use_none:n \token_to_string:N} % \end{macrocode} % \end{macro} % -% \begin{macro}{\tlist_eq:nnTF} -% \begin{macro}{\tlist_eq:onTF} -% |\tlist_eq:nnTF| tests whether the first two arguments are equal and -% executes either its third or fourth argument. -% |\tlist_eq:onTF| expands its first argument once. -% \begin{macrocode} -\def_new:Npn \tlist_eq:nnTF #1#2{ - \tlp_gset:Nn \g_testa_tlp {#1} - \tlp_gset:Nn \g_testb_tlp {#2} - \if_meaning:NN\g_testa_tlp \g_testb_tlp - \exp_after:NN\use_choice_i:nn \else: - \exp_after:NN\use_choice_ii:nn \fi:} -\def_new:Npn \tlist_eq:onTF {\exp_args:No \tlist_eq:nnTF} -% \end{macrocode} -% \end{macro} -% \end{macro} % % -% \begin{macro}{\tlist_empty:nTF} -% \begin{macro}{\tlist_empty:nF} -% These test whether a token list is empty and act accordingly. -% \begin{macrocode} -\def_new:Npn \tlist_empty:nTF #1{\tlp_gset:Nn \g_testa_tlp {#1} - \if_meaning:NN\g_testa_tlp \c_empty_tlp - \exp_after:NN \use_choice_i:nn \else: - \exp_after:NN \use_choice_ii:nn \fi:} -\def_new:Npn \tlist_empty:nF #1{\tlp_gset:Nn \g_testa_tlp {#1} - \if_meaning:NN\g_testa_tlp \c_empty_tlp - \exp_after:NN \use_none:nn \fi: \use:n} -% \end{macrocode} -% \end{macro} -% \end{macro} % % -% \begin{macro}{\str_eq_p:nn} -% Takes 2 lists of characters as arguments and expands into -% |\c_true| if they are equal, and |\c_false| otherwise. I'm -% pretty sure that the non expandable version above is faster, but -% it's not expandable so we also include this one. +% \begin{macro}{\cs_if_eq:NNTF} +% \begin{macro}{\cs_if_eq:NNT} +% \begin{macro}{\cs_if_eq:NNF} +% \begin{macro}{\cs_if_eq:cNTF} +% \begin{macro}{\cs_if_eq:cNT} +% \begin{macro}{\cs_if_eq:cNF} +% \begin{macro}{\cs_if_eq:NcTF} +% \begin{macro}{\cs_if_eq:NcT} +% \begin{macro}{\cs_if_eq:NcF} +% \begin{macro}{\cs_if_eq:ccTF} +% \begin{macro}{\cs_if_eq:ccT} +% \begin{macro}{\cs_if_eq:ccF} +% Check if two control sequences are identical. % \begin{macrocode} -\def_new:Npn \str_eq_p:nn #1#2{\str_eq_p_aux:w #1\scan_stop:\\#2\scan_stop:\\} -\def_new:Npn \str_eq_p_aux:w #1#2\\#3#4\\{ - \if_meaning:NN#1#3 - \if_meaning:NN#1\scan_stop:\c_true \else: - \if_meaning:NN#3\scan_stop:\c_false \else: - \str_eq_p_aux:w #2\\#4\\\fi:\fi: - \else:\c_false \fi:} +\def_test_function_new:npn {cs_if_eq:NN} #1#2{\if_meaning:NN #1#2} +\def_new:Npn \cs_if_eq:cNTF {\exp_args:Nc \cs_if_eq:NNTF} +\def_new:Npn \cs_if_eq:cNT {\exp_args:Nc \cs_if_eq:NNT} +\def_new:Npn \cs_if_eq:cNF {\exp_args:Nc \cs_if_eq:NNF} +\def_new:Npn \cs_if_eq:NcTF {\exp_args:NNc \cs_if_eq:NNTF} +\def_new:Npn \cs_if_eq:NcT {\exp_args:NNc \cs_if_eq:NNT} +\def_new:Npn \cs_if_eq:NcF {\exp_args:NNc \cs_if_eq:NNF} +\def_new:Npn \cs_if_eq:ccTF {\exp_args:Ncc \cs_if_eq:NNTF} +\def_new:Npn \cs_if_eq:ccT {\exp_args:Ncc \cs_if_eq:NNT} +\def_new:Npn \cs_if_eq:ccF {\exp_args:Ncc \cs_if_eq:NNF} % \end{macrocode} % \end{macro} -% -% \begin{macro}{\cs_eq_p:NN} -% An application of the above function, already streamlined for -% speed, so I put it in here. It takes two control sequences as -% arguments and expands into true iff they have the same name. -% \begin{macrocode} -\def:Npn \cs_eq_p:NN #1#2{ - \exp_after:NN\exp_after:NN - \exp_after:NN\str_eq_p_aux:w - \exp_after:NN\token_to_string:N - \exp_after:NN#1 - \exp_after:NN\scan_stop: - \exp_after:NN\\ - \token_to_string:N#2\scan_stop:\\} -% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % \end{macro} % -% Finally some code that is needed as we -% do not distribute the file module at the moment (so we simply define -% the needed function via an existing \LaTeX{} command) and some other -% stuff which was set up elsewhere, in undistributed modules. +% Finally some code that is needed as we do not distribute the file +% module at the moment (so we simply define the needed function via an +% existing \LaTeX{} command) and some other stuff which was set up +% elsewhere, in undistributed modules. % \begin{macrocode} \def_new:Npn\file_not_found:nTF #1#2#3{\IfFileExists{#1}{#3}{#2}} % \end{macrocode} % -% -% \section{Predicates and conditionals} +% +% \subsubsection{Predicates and conditionals} % \label{sec:predicates} % % \LaTeX3 has three concepts for conditional flow processing: @@ -995,8 +2677,8 @@ % % \item % Functions that carry out a test an then execute, depending on its -% result, either the code supplied in the <true arg> or the <false -% arg>. These arguments are denoted with "T" and "F" repectively. An +% result, either the code supplied in the \m{true arg} or the \m{false +% arg}. These arguments are denoted with "T" and "F" repectively. An % example would be % \begin{quote} % "\cs_free:cTF{abc}{...}{...}" @@ -1027,52 +2709,108 @@ % thoughts. % \end{enumerate} % -% Important to note is that conditionals with <true code> and/or <false -% code> are always defined in a way that the code of the chosen +% Important to note is that conditionals with \m{true code} and/or +% \m{false code} are always defined in a way that the code of the chosen % alternative can operate on following tokens in the input stream while % the predicate implementations always have an "\else:" or "\fi:" % interfering. This can be important in scanner implementations. % -% \subsection{Variables} % -% \begin{variable}{% -% \c_true | \c_false | -% } -% Constants that represend `true' or `false', respectively. Used to -% implement predicates. -% \end{variable} +% \begin{macrocode} +%</initex|package> +%<*showmemory> +\showMemUsage +%</showmemory> +% \end{macrocode} % -% \begin{variable}{\l_testa_tlp | -% \l_testb_tlp | -% \g_testa_tlp | -% \g_testb_tlp | -% } -% All conditionals and predicates never use tmp variables. Instead they -% use the following reserved variables. -% \end{variable} +% \endinput % -% \subsection{Predicate implementation} +% $Log$ +% Revision 1.38 2006/08/06 17:05:25 morten +% Make \chk_new_cs:N bulletproof % -% I think Michael originated the idea of expandable boolean tests. -% They must expand into either \texttt{TT} or \texttt{TF} and are -% tested using |\if:w|. +% Revision 1.37 2006/07/30 14:37:47 morten +% Added \str_if_eq_var_p:nf % +% Revision 1.36 2006/07/23 13:43:21 morten +% Removed extra occurrence of \str_if_eq_p:nn % -% \begin{macro}{\c_true} -% \begin{macro}{\c_false} -% Here are the canonical boolean values. -% \begin{macrocode} -\def_new:Npn \c_true {TT} -\def_new:Npn \c_false {TF} -% \end{macrocode} -% \end{macro} -% \end{macro} +% Revision 1.35 2006/07/17 22:25:31 morten +% Fix logic of \chk_new_cs:N and rename \cs_if_eq_p:NN to +% \cs_if_eq_name_p:NN because it is not their meaning but their names +% which are compared. +% +% Revision 1.34 2006/07/08 22:46:17 morten +% Rearranged some code and added complete set of \use_none:<args> +% functions. +% +% Revision 1.33 2006/07/06 14:53:56 morten +% Added \def:NNn functions, reorganized code and much much more. +% +% Revision 1.32 2006/06/03 17:14:43 morten +% Added more \use_arg_... functions. +% +% Revision 1.31 2006/03/20 18:26:33 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.30 2006/01/22 19:35:46 morten +% Changed \use_none:nnn to gobble all tokens in one go and added +% \use_arg_i_ii:nn for l3keyval. +% +% Revision 1.29 2006/01/16 09:47:49 morten +% Fixed deleted brace +% +% Revision 1.28 2006/01/15 19:08:28 morten +% Fixed typos in some \if names +% +% Revision 1.27 2006/01/04 01:29:36 morten +% Changed "robust" to "protected". +% +% Revision 1.26 2005/12/27 09:53:55 morten +% Fixed some names, added a few more \use_... functions, changed RCS +% information retrieval +% +% Revision 1.25 2005/12/23 11:16:15 morten +% *** empty log message *** +% +% Revision 1.24 2005/12/02 15:21:55 morten +% Fixed minor typo +% +% Revision 1.23 2005/11/20 07:10:03 morten +% Added a few missing functions. New function type +% \def_test_function:npn to help define TF-type functions. +% +% Revision 1.22 2005/11/08 04:16:17 morten +% Fixed typo. +% +% Revision 1.21 2005/10/27 22:35:13 morten +% Cleaned up a bit and moved some code to l3num. +% +% Revision 1.20 2005/07/12 16:10:24 morten +% Allow \cs_if_eq_p:NN to accept \par. (Yes, real life experience) +% +% Revision 1.19 2005/04/06 21:34:55 morten +% Added more functions. Moved \engine_aleph:TF from l3prg +% +% Revision 1.18 2005/03/25 23:52:24 braams +% The definition of \next needs to be seen at initex time, +% not at typesetting time +% +% Revision 1.17 2005/03/22 23:28:46 morten +% Moved some code to l3prg, removed obsolete code, cleaned up documentation. +% +% Revision 1.16 2005/03/16 22:31:44 braams +% Changed definition of \c_zero and \c_minus_one +% +% Revision 1.15 2005/03/15 23:16:27 braams +% Some tweaking with the docstrip guards to get the documentation to +% come out right. +% +% Revision 1.14 2005/03/15 22:50:00 braams +% Made loadable by initex as the second file +% +% Revision 1.13 2005/03/11 21:32:21 braams +% Fixed the use of RCS information; +% moved \RequirePackage after \StopEventually % -% \begin{macrocode} -%</package> -%<*showmemory> -\showMemUsage -%</showmemory> -% \end{macrocode} -% - diff --git a/Master/texmf-dist/source/latex/expl3/l3box.dtx b/Master/texmf-dist/source/latex/expl3/l3box.dtx new file mode 100644 index 00000000000..96e0d4696a8 --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3box.dtx @@ -0,0 +1,933 @@ +% \iffalse +%% File: l3box.dtx Copyright (C) 2005-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3box.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental Box module} +% +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3box.dtx} +\end{document} +%</driver> +% \fi +% +% +% \title{The \textsf{l3box} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}\\ +% Boxes} +% \author{\Team} +% \date{\filedate} +% \maketitle +% +% \section{Boxes} +% +% +% There are three kinds of box operations: horizontal mode denoted +% with prefix |\hbox_|, vertical mode with prefix |\vbox_|, and the +% generic operations working in both modes with prefix |\box_|. +% +% +% \subsection{Generic functions} +% +% \begin{function}{% +% \box_new:N | +% \box_new:c | +% \box_new_l:N +% } +% \begin{syntax} +% "\box_new:N" <box> +% \end{syntax} +% Defines <box> to be a new variable of type "box". +% \begin{texnote} +% "\box_new:N" is the equivalent of plain \TeX{}'s \tn{newbox}. +% However, the internal register allocation is done differently. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \if_hbox:N | +% \if_vbox:N | +% \if_box_empty:N | +% } +% \begin{syntax} +% "\if_hbox:N" <box> <true code>"\else:" <false code>"\fi:" +% "\if_box_empty:N" <box> <true code>"\else:" <false code>"\fi:" +% \end{syntax} +% "\if_hbox:N" and "\if_vbox:N" check if <box> is an horizontal or +% vertical box resp. "\if_box_empty:N" tests if <box> is empty (void) +% and executes "code" according to the test outcome. +% \begin{texnote} +% These are the \TeX{} primitives \tn{ifhbox}, \tn{ifvbox} and +% \tn{ifvoid}. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \box_if_empty:NTF | +% \box_if_empty:cTF | +% \box_if_empty:NT | +% \box_if_empty:cT | +% \box_if_empty:NF | +% \box_if_empty:cF | +% } +% \begin{syntax} +% "\box_if_empty:NTF" <box> "{"\m{true code}"}" "{"\m{false code}"}" +% \end{syntax} +% Tests if <box> is empty (void) and executes "code" according to the +% test outcome. +% \begin{texnote} +% "\box_if_empty:NTF" is the \LaTeX3 function name for \tn{ifvoid}. +% \end{texnote} +% \end{function} +% +% +% \begin{function}{% +% \box_set_eq:NN | +% \box_set_eq:cN | +% \box_set_eq:Nc | +% \box_set_eq:cc | +% } +% \begin{syntax} +% "\box_set_eq:NN" <box1> <box2> +% \end{syntax} +% Sets <box1> equal to <box2>. Note that this eradicates the contents +% of <box2> afterwards. +% \end{function} +% +% +% \begin{function}{% +% \box_gset_eq:NN | +% \box_gset_eq:cN | +% \box_gset_eq:Nc | +% \box_gset_eq:cc | +% } +% \begin{syntax} +% "\box_gset_eq:NN" <box1> <box2> +% \end{syntax} +% Globally sets <box1> equal to <box2>. +% \end{function} +% +% +% \begin{function}{% +% \box_set_to_previous:N | +% \box_set_to_previous:c | +% \box_gset_to_previous:N | +% \box_gset_to_previous:c | +% } +% \begin{syntax} +% "\box_set_to_previous:N" <box> +% \end{syntax} +% Sets <box> equal to the previous box |\R_previous_box| and removes +% |\R_previous_box| from the current list (unless in outer vertical +% or math mode). +% \end{function} +% +% \begin{function}{% +% \box_move_right:nn | +% \box_move_left:nn | +% \box_move_up:nn | +% \box_move_down:nn | +% } +% \begin{syntax} +% "\box_move_left:nn" "{"<dimen>"}" "{"<box function>"}" +% \end{syntax} +% Moves <box function> <dimen> in the direction specified. <box +% function> is either an operation on a box such as "\box_use:N" or a +% ``raw'' box specification like "\vbox:n{xyz}". +% \end{function} +% +% \begin{function}{% +% \box_clear:N | +% \box_clear:c | +% \box_gclear:N | +% \box_gclear:c | +% } +% \begin{syntax} +% "\box_clear:N" <box> +% \end{syntax} +% Clears <box> by setting it to the constant "\c_void_box". +% "\box_gclear:N" does it globally. +% \end{function} +% +% +% \begin{function}{% +% \box_use:N | +% \box_use:c | +% \box_use_clear:N | +% \box_use_clear:c | +% } +% \begin{syntax} +% "\box_use:N" <box> \\ +% "\box_use_clear:N" <box> +% \end{syntax} +% "\box_use:N" puts a copy of <box> on the current list while +% "\box_use_clear:N" puts the box on the current list and then +% eradicates the contents of it. +% \begin{texnote} +% "\box_use:N" and "\box_use_clear:N" are the \TeX{} primitives +% \tn{copy} and \tn{box} with new (descriptive) names. +% \end{texnote} +% \end{function} +% +% +% \begin{function}{% +% \box_ht:N | +% \box_ht:c | +% \box_dp:N | +% \box_dp:c | +% \box_wd:N | +% \box_wd:c | +% } +% \begin{syntax} +% "\box_ht:N" <box> +% \end{syntax} +% Returns the height, depth, and width of <box> for use in dimension +% settings. +% \begin{texnote} +% These are the \TeX{} primitives \tn{ht}, \tn{dp} and \tn{wd}. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \box_show:N | +% \box_show:c | +% } +% \begin{syntax} +% "\box_show:N" <box> +% \end{syntax} +% Writes the contents of <box> to the log file. +% \begin{texnote} +% This is the \TeX{} primitive \tn{showbox}. +% \end{texnote} +% \end{function} +% +% +% \begin{variable}{% +% \c_empty_box | +% \l_tmpa_box | +% \l_tmpb_box | +% } +% \begin{syntax} +% \end{syntax} +% "\c_empty_box" is the constantly empty box. The others are scratch +% boxes. +% \end{variable} +% +% +% \begin{variable}{% +% \R_previous_box | +% } +% \begin{syntax} +% \end{syntax} +% "\R_previous_box" is a read-only box register. You can set other +% boxes to this box, which will then be removed from the current +% list. +% \end{variable} +% +% +% \subsection{Horizontal mode} +% +% \begin{function}{% +% \hbox:n | +% } +% \begin{syntax} +% "\hbox:n" "{"<contents>"}" +% \end{syntax} +% Places a "hbox" of natural size. +% \end{function} +% +% \begin{function}{% +% \hbox_set:Nn | +% \hbox_set:cn | +% \hbox_gset:Nn | +% \hbox_gset:cn | +% } +% \begin{syntax} +% "\hbox_set:Nn" <box> "{"\m{contents}"}" +% \end{syntax} +% Sets <box> to be a vertical mode box containing \m{contents}. It has +% it's natural size. "\hbox_gset:Nn" does it globally. +% \end{function} +% +% +% \begin{function}{% +% \hbox_set_to_wd:Nnn | +% \hbox_set_to_wd:cnn | +% \hbox_gset_to_wd:Nnn | +% \hbox_gset_to_wd:cnn | +% } +% \begin{syntax} +% "\hbox_set_to_wd:Nnn" <box> "{"\m{dimen}"}" "{"\m{contents}"}" +% \end{syntax} +% Sets <box> to contain \m{contents} and have width <dimen>. +% "\hbox_gset_to_wd:Nn" does it globally. +% \end{function} +% +% +% \begin{function}{% +% \hbox_to_wd:nn | +% } +% \begin{syntax} +% "\hbox_to_wd:nn" "{"<dimen>"}" <contents> +% \end{syntax} +% Places a <box> of width <dimen> containing <contents>. +% \end{function} +% +% +% \begin{function}{% +% \hbox_set_inline_begin:N | +% \hbox_set_inline_end: | +% \hbox_gset_inline_begin:N | +% \hbox_gset_inline_end: | +% } +% \begin{syntax} +% "\hbox_set_inline_begin:N" <box> <contents> +% "\hbox_set_inline_end:" +% \end{syntax} +% Sets <box> to contain <contents>. This type is useful for use in +% environment definitions. +% \end{function} +% +% +% \begin{function}{% +% \hbox_unpack:N | +% \hbox_unpack_clear:N | +% } +% \begin{syntax} +% "\hbox_unpack:N" <box> +% \end{syntax} +% "\hbox_unpack:N" unpacks the contents of the <box> register and +% "\hbox_unpack_clear:N" also clears the <box> after unpacking it. +% \begin{texnote} +% These are the \TeX{} primitives \tn{unhcopy} and \tn{unhbox}. +% \end{texnote} +% \end{function} +% +% +% +% +% +% \subsection{Vertical mode} +% +% \begin{function}{% +% \vbox_set:Nn | +% \vbox_set:cn | +% \vbox_gset:Nn | +% \vbox_gset:cn | +% } +% \begin{syntax} +% "\vbox_set:Nn" <box> "{"\m{contents}"}" +% \end{syntax} +% Sets <box> to be a vertical mode box containing \m{contents}. It has +% it's natural size. "\vbox_gset:Nn" does it globally. +% \end{function} +% +% +% \begin{function}{% +% \vbox_set_to_ht:Nnn | +% \vbox_set_to_ht:cnn | +% \vbox_gset_to_ht:Nnn | +% \vbox_gset_to_ht:cnn | +% \vbox_gset_to_ht:ccn | +% } +% \begin{syntax} +% "\vbox_set_to_ht:Nnn" <box> "{"\m{dimen}"}" "{"\m{contents}"}" +% \end{syntax} +% Sets <box> to contain \m{contents} and have total height <dimen>. +% "\vbox_gset_to_ht:Nn" does it globally. +% \end{function} +% +% +% \begin{function}{% +% \vbox_set_inline_begin:N | +% \vbox_set_inline_end: | +% \vbox_gset_inline_begin:N | +% \vbox_gset_inline_end: | +% } +% \begin{syntax} +% "\vbox_set_inline_begin:N" <box> <contents> +% "\vbox_set_inline_end:" +% \end{syntax} +% Sets <box> to contain \m{contents}. This type is useful for use in +% environment definitions. +% \end{function} +% +% \begin{function}{% +% \vbox_set_split_to_ht:NNn | +% } +% \begin{syntax} +% "\vbox_set_split_to_ht:NNn" <box1> <box2> "{"<dimen>"}" +% \end{syntax} +% Sets <box1> to contain the top <dimen> part of <box2>. +% \begin{texnote} +% This is the \TeX{} primitive \tn{vsplit}. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \vbox:n | +% } +% \begin{syntax} +% "\vbox:n" "{"<contents>"}" +% \end{syntax} +% Places a "vbox" of natural size with baseline equal to the baseline +% of the last line in the box. +% \end{function} +% +% \begin{function}{% +% \vbox_to_ht:nn | +% \vbox_to_zero:n | +% } +% \begin{syntax} +% "\vbox_to_ht:nn" "{"<dimen>"}" <contents> \\ +% "\vbox_to_zero:n" <contents> +% \end{syntax} +% Places a <box> of size <dimen> containing <contents>. +% \end{function} +% +% +% \begin{function}{% +% \vbox_unpack:N | +% \vbox_unpack_clear:N | +% } +% \begin{syntax} +% "\vbox_unpack:N" <box> +% \end{syntax} +% "\vbox_unpack:N" unpacks the contents of the <box> register and +% "\vbox_unpack_clear:N" also clears the <box> after unpacking it. +% \begin{texnote} +% These are the \TeX{} primitives \tn{unvcopy} and \tn{unvbox}. +% \end{texnote} +% \end{function} +% +% +% \StopEventually{} +% +% +% +% \subsection{The Implementation} +% +% +% We start by ensuring that the required packages are loaded. +% \begin{macrocode} +%<package&!check>\RequirePackage{l3prg}\par +%<package&check>\RequirePackage{l3chk}\par +%<*initex|package> +% \end{macrocode} +% +% The code in this module is very straight forward so I'm not going to +% comment it very extensively. +% +% +% \subsubsection{Generic boxes} +% +% \begin{macro}{\box_new:N} +% \begin{macro}{\box_new_l:N} +% \begin{macro}{\box_new:c} +% Defining a new \m{box} register. +% \begin{macrocode} +%<*initex> +\alloc_setup_type:nnn {box} \c_zero \c_max_register_num +% \end{macrocode} +% Now, remember that |\box255| has a special role in \TeX, it +% shouldn't be allocated\dots +% \begin{macrocode} +\seq_put_right:Nn \g_box_allocation_seq {255} +\def_new:Npn \box_new:N #1 {\alloc_reg:NnNN g {box} \tex_mathchardef:D #1} +\def_new:Npn \box_new_l:N #1 {\alloc_reg:NnNN l {box} \tex_mathchardef:D #1} +%</initex> +% \end{macrocode} +% When we run on top of \LaTeX, we just use its allocation +% mechanism. +% \begin{macrocode} +%<package>\let_new:NN \box_new:N \newbox +\def_new:Npn \box_new:c {\exp_args:Nc \box_new:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\if_hbox:N} +% \begin{macro}{\if_vbox:N} +% \begin{macro}{\if_box_empty:N} +% The primitives for testing if a \m{box} is empty/void or which +% type of box it is. +% \begin{macrocode} +\let_new:NN \if_hbox:N \tex_ifhbox:D +\let_new:NN \if_vbox:N \tex_ifvbox:D +\let_new:NN \if_box_empty:N \tex_ifvoid:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\box_if_empty:NTF} +% \begin{macro}{\box_if_empty:cTF} +% \begin{macro}{\box_if_empty:NT} +% \begin{macro}{\box_if_empty:cT} +% \begin{macro}{\box_if_empty:NF} +% \begin{macro}{\box_if_empty:cF} +% Testing if a \m{box} is empty/void. +% \begin{macrocode} +\def_test_function_new:npn {box_if_empty:N}#1{\if_box_empty:N #1} +\def_new:Npn \box_if_empty:cTF {\exp_args:Nc \box_if_empty:NTF} +\def_new:Npn \box_if_empty:cT {\exp_args:Nc \box_if_empty:NT} +\def_new:Npn \box_if_empty:cF {\exp_args:Nc \box_if_empty:NF} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\box_set_eq:NN} +% \begin{macro}{\box_set_eq:cN} +% \begin{macro}{\box_set_eq:Nc} +% \begin{macro}{\box_set_eq:cc} +% Assigning the contents of a box to be another box. +% This clears the second box globally (that's how \TeX{} does it). +% \begin{macrocode} +\def_new:Npn \box_set_eq:NN #1#2 {\tex_setbox:D #1 \tex_box:D #2} +\def_new:Npn \box_set_eq:cN {\exp_args:Nc \box_set_eq:NN} +\def_new:Npn \box_set_eq:Nc {\exp_args:NNc \box_set_eq:NN} +\def_new:Npn \box_set_eq:cc {\exp_args:Ncc \box_set_eq:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\box_gset_eq:NN} +% \begin{macro}{\box_gset_eq:cN} +% \begin{macro}{\box_gset_eq:Nc} +% \begin{macro}{\box_gset_eq:cc} +% Global version of the above. +% \begin{macrocode} +\def_new:Npn \box_gset_eq:NN {\pref_global:D\box_set_eq:NN} +\def_new:Npn \box_gset_eq:cN {\exp_args:Nc \box_gset_eq:NN} +\def_new:Npn \box_gset_eq:Nc {\exp_args:NNc \box_gset_eq:NN} +\def_new:Npn \box_gset_eq:cc {\exp_args:Ncc \box_gset_eq:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\R_previous_box} +% A different name for this read-only primitive. +% \begin{macrocode} +\let_new:NN \R_previous_box \tex_lastbox:D +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\box_set_to_previous:N} +% \begin{macro}{\box_set_to_previous:c} +% \begin{macro}{\box_gset_to_previous:N} +% \begin{macro}{\box_gset_to_previous:c} +% Set a box to the previous box. +% \begin{macrocode} +\def_new:Npn \box_set_to_previous:N #1{\tex_setbox:D#1\R_previous_box} +\def_new:Npn \box_set_to_previous:c {\exp_args:Nc \box_set_to_previous:N} +\def_new:Npn \box_gset_to_previous:N {\pref_global:D \box_set_to_previous:N} +\def_new:Npn \box_gset_to_previous:c {\exp_args:Nc \box_gset_to_previous:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\box_move_left:nn} +% \begin{macro}{\box_move_right:nn} +% \begin{macro}{\box_move_up:nn} +% \begin{macro}{\box_move_down:nn} +% Move box material in different directions. +% \begin{macrocode} +\def_long_new:Npn \box_move_left:nn #1#2{\tex_moveleft:D\dim_eval:n{#1}{#2}} +\def_long_new:Npn \box_move_right:nn #1#2{\tex_moveright:D\dim_eval:n{#1}{#2}} +\def_long_new:Npn \box_move_up:nn #1#2{\tex_raise:D\dim_eval:n{#1}{#2}} +\def_long_new:Npn \box_move_down:nn #1#2{\tex_lower:D\dim_eval:n{#1}{#2}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\box_clear:N} +% \begin{macro}{\box_clear:c} +% \begin{macro}{\box_gclear:N} +% \begin{macro}{\box_gclear:c} +% Clear a \m{box} register. +% \begin{macrocode} +\def_new:Npn \box_clear:N #1{\box_set_eq:NN #1 \c_empty_box } +\def_new:Npn \box_clear:c {\exp_args:Nc \box_clear:N } +\def_new:Npn \box_gclear:N {\pref_global:D\box_clear:N} +\def_new:Npn \box_gclear:c {\exp_args:Nc \box_gclear:c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\box_ht:N} +% \begin{macro}{\box_ht:c} +% \begin{macro}{\box_dp:N} +% \begin{macro}{\box_dp:c} +% \begin{macro}{\box_wd:n} +% \begin{macro}{\box_wd:c} +% Accessing the height, depth, and width of a \m{box} register. +% \begin{macrocode} +\let_new:NN \box_ht:N \tex_ht:D +\def_new:Npn \box_ht:c {\exp_args:Nc \box_ht:N} +\let_new:NN \box_dp:N \tex_dp:D +\def_new:Npn \box_dp:c {\exp_args:Nc \box_dp:N} +\let_new:NN \box_wd:N \tex_wd:D +\def_new:Npn \box_wd:c {\exp_args:Nc \box_wd:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\box_use_clear:N} +% \begin{macro}{\box_use_clear:c} +% \begin{macro}{\box_use:N} +% \begin{macro}{\box_use:c} +% Using a \m{box}. This is just \TeX{} primitives with meaningful +% names. +% \begin{macrocode} +\let_new:NN \box_use_clear:N \tex_box:D +\def_new:Npn \box_use_clear:c {\exp_args:Nc \box_use_clear:N} +\let_new:NN \box_use:N \tex_copy:D +\def_new:Npn \box_use:c {\exp_args:Nc \box_use:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\box_show:N} +% \begin{macro}{\box_show:c} +% Show the contents of a box and write it into the log file. +% \begin{macrocode} +\let:NN \box_show:N \tex_showbox:D +\def_new:Npn \box_show:c {\exp_args:Nc \box_show:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\c_empty_box} +% \begin{macro}{\l_tmpa_box} +% \begin{macro}{\l_tmpb_box} +% We allocate some \m{box} registers here (and borrow a few from \LaTeX). +% \begin{macrocode} +%<package>\let:NN \c_empty_box \voidb@x +%<package>\let_new:NN \l_tmpa_box \@tempboxa +%<initex>\box_new:N \c_empty_box +%<initex>\box_new:N \l_tmpa_box +\box_new:N \l_tmpb_box +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \subsubsection{Vertical boxes} +% +% +% \begin{macro}{\vbox:n} +% Put a vertical box directly into the input stream. +% \begin{macrocode} +\def_new:Npn \vbox:n {\tex_vbox:D \scan_stop:} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\vbox_set:Nn} +% \begin{macro}{\vbox_set:cn} +% \begin{macro}{\vbox_gset:Nn} +% \begin{macro}{\vbox_gset:cn} +% Storing material in a vertical box with a natural height. +% \begin{macrocode} +\def_long_new:Npn \vbox_set:Nn #1#2 {\tex_setbox:D #1 \tex_vbox:D {#2}} +\def_new:Npn \vbox_set:cn {\exp_args:Nc \vbox_set:Nn} +\def_new:Npn \vbox_gset:Nn {\pref_global:D \vbox_set:Nn} +\def_new:Npn \vbox_gset:cn {\exp_args:Nc \vbox_gset:Nn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\vbox_set_to_ht:Nnn} +% \begin{macro}{\vbox_set_to_ht:cnn} +% \begin{macro}{\vbox_gset_to_ht:Nnn} +% \begin{macro}{\vbox_gset_to_ht:cnn} +% \begin{macro}{\vbox_gset_to_ht:ccn} +% Storing material in a vertical box with a specified height. +% \begin{macrocode} +\def_long_new:Npn \vbox_set_to_ht:Nnn #1#2#3 { + \tex_setbox:D #1 \tex_vbox:D to #2 {#3}} +\def_new:Npn \vbox_set_to_ht:cnn{\exp_args:Nc \vbox_set_to_ht:Nnn } +\def_new:Npn \vbox_gset_to_ht:Nnn {\pref_global:D \vbox_set_to_ht:Nnn } +\def_new:Npn \vbox_gset_to_ht:cnn{\exp_args:Nc \vbox_gset_to_ht:Nnn } +\def_new:Npn \vbox_gset_to_ht:ccn {\exp_args:Ncc \vbox_gset_to_ht:Nnn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\vbox_set_inline_begin:N} +% \begin{macro}{\vbox_set_inline_end:} +% \begin{macro}{\vbox_gset_inline_begin:N} +% \begin{macro}{\vbox_set_inline_end:} +% Storing material in a vertical box. This type is useful in +% environment definitions. +% \begin{macrocode} +\def_new:Npn \vbox_set_inline_begin:N #1 { + \tex_setbox:D #1 \tex_vbox:D \c_group_begin_token } +\let_new:NN \vbox_set_inline_end: \c_group_end_token +\def_new:Npn \vbox_gset_inline_begin:N { + \pref_global:D \vbox_set_inline_begin:N } +\let_new:NN \vbox_gset_inline_end: \c_group_end_token +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\vbox_to_ht:nn} +% \begin{macro}{\vbox_to_zero:n} +% Put a vertical box directly into the input stream. +% \begin{macrocode} +\def_long_new:Npn \vbox_to_ht:nn #1#2{\tex_vbox:D to \dim_eval:n{#1}{#2}} +\def_long_new:Npn \vbox_to_zero:n #1 {\tex_vbox:D to \c_zero_dim {#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\vbox_set_split_to_ht:NNn} +% Splitting a vertical box in two. +% \begin{macrocode} +\def_new:Npn \vbox_set_split_to_ht:NNn #1#2#3{ + \tex_setbox:D #1 \tex_vsplit:D #2 to #3 +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\vbox_unpack:N} +% \begin{macro}{\vbox_unpack:c} +% \begin{macro}{\vbox_unpack_clear:N} +% \begin{macro}{\vbox_unpack_clear:c} +% Unpacking a box and if requested also clear it. +% \begin{macrocode} +\let_new:NN \vbox_unpack:N \tex_unvcopy:D +\def_new:Npn \vbox_unpack:c {\exp_args:Nc \vbox_unpack:N} +\let_new:NN \vbox_unpack_clear:N \tex_unvbox:D +\def_new:Npn \vbox_unpack_clear:c {\exp_args:Nc \vbox_unpack_clear:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% +% +% +% \subsubsection{Horizontal boxes} +% +% +% \begin{macro}{\hbox:n} +% Put a horizontal box directly into the input stream. +% \begin{macrocode} +\def_new:Npn \hbox:n {\tex_hbox:D \scan_stop:} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\hbox_set:Nn} +% \begin{macro}{\hbox_set:cn} +% \begin{macro}{\hbox_gset:Nn} +% \begin{macro}{\hbox_gset:cn} +% Assigning the contents of a box to be another box. +% This clears the second box globally (that's how \TeX{} does it). +% \begin{macrocode} +\def_long_new:Npn \hbox_set:Nn #1#2 {\tex_setbox:D #1 \tex_hbox:D {#2}} +\def_new:Npn \hbox_set:cn {\exp_args:Nc \hbox_set:Nn} +\def_new:Npn \hbox_gset:Nn {\pref_global:D \hbox_set:Nn} +\def_new:Npn \hbox_gset:cn {\exp_args:Nc \hbox_gset:Nn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hbox_set_to_wd:Nnn} +% \begin{macro}{\hbox_set_to_wd:cnn} +% \begin{macro}{\hbox_gset_to_wd:Nnn} +% \begin{macro}{\hbox_gset_to_wd:cnn} +% Storing material in a horizontal box with a specified width. +% \begin{macrocode} +\def_long_new:Npn \hbox_set_to_wd:Nnn #1#2#3 { + \tex_setbox:D #1 \tex_hbox:D to \dim_eval:n{#2} {#3}} +\def_new:Npn \hbox_set_to_wd:cnn{\exp_args:Nc \hbox_set_to_wd:Nnn } +\def_new:Npn \hbox_gset_to_wd:Nnn {\pref_global:D \hbox_set_to_wd:Nnn } +\def_new:Npn \hbox_gset_to_wd:cnn{\exp_args:Nc \hbox_gset_to_wd:Nnn } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\hbox_set_inline_begin:N} +% \begin{macro}{\hbox_set_inline_end:} +% \begin{macro}{\hbox_gset_inline_begin:N} +% \begin{macro}{\hbox_set_inline_end:} +% Storing material in a horizontal box. This type is useful in +% environment definitions. +% \begin{macrocode} +\def_new:Npn \hbox_set_inline_begin:N #1 { + \tex_setbox:D #1 \tex_hbox:D \c_group_begin_token } +\let_new:NN \hbox_set_inline_end: \c_group_end_token +\def_new:Npn \hbox_gset_inline_begin:N { + \pref_global:D \hbox_set_inline_begin:N } +\let_new:NN \hbox_gset_inline_end: \c_group_end_token +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hbox_to_wd:nn} +% \begin{macro}{\hbox_to_zero:n} +% Put a horizontal box directly into the input stream. +% \begin{macrocode} +\def_long_new:Npn \hbox_to_wd:nn #1#2 {\tex_hbox:D to #1 {#2}} +\def_long_new:Npn \hbox_to_zero:n #1 {\tex_hbox:D to \c_zero_skip {#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hbox_unpack:N} +% \begin{macro}{\hbox_unpack:c} +% \begin{macro}{\hbox_unpack_clear:N} +% \begin{macro}{\hbox_unpack_clear:c} +% Unpacking a box and if requested also clear it. +% \begin{macrocode} +\let_new:NN \hbox_unpack:N \tex_unhcopy:D +\def_new:Npn \hbox_unpack:c {\exp_args:Nc \hbox_unpack:N} +\let_new:NN \hbox_unpack_clear:N \tex_unhbox:D +\def_new:Npn \hbox_unpack_clear:c {\exp_args:Nc \hbox_unpack_clear:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +%^^A xo-or.sty:1528: \setbox\z@\vsplit\c_twohundred_fifty_five to\l_tmpa_dim +%^^A xo-or.dtx:222: \global\setbox\removed@guard@box\lastbox} +% +%^^A it probably should be \vbox_set:nn not \vbox_set:Nn as we can +%^^A have a number as the first arg ... do do we argue that this is not +%^^A supported on this level? +%^^A MH comment: +%^^A I don't think we should ever see people using numbers directly. +%^^A If they do it's \vbox_set:Nn \c_zero {...} anyway, not two-digit +%^^A numbers. +% +% \begin{macrocode} +%</initex|package> +%<*showmemory> +\showMemUsage +%</showmemory> +% \end{macrocode} +% +% \endinput +% +% $Log$ +% Revision 1.10 2006/03/20 18:26:34 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.9 2006/01/19 22:30:30 morten +% Added functions for accessing \tex_lastbox:D and moving box material +% in the four directions. +% +% Revision 1.8 2005/12/27 16:04:12 morten +% Changed RCS information retrieval +% +% Revision 1.7 2005/10/27 23:11:12 morten +% Moved \if_hbox:N, \if_vbox:N and _if_box_empty:N here +% +% Revision 1.6 2005/04/25 16:15:17 morten +% Fixed \bgroup/\egroup and made it run under initex +% +% Revision 1.5 2005/04/06 22:35:33 braams +% Now we have register allocation fitted +% +% Revision 1.4 2005/03/26 21:08:12 morten +% Fix \c_zero -> \c_zero_skip +% +% Revision 1.3 2005/03/16 22:36:46 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.2 2005/03/11 21:31:07 braams +% Fixed the use of RCS information; added \StopEventually +% diff --git a/Master/texmf-dist/source/latex/expl3/l3calc.dtx b/Master/texmf-dist/source/latex/expl3/l3calc.dtx new file mode 100644 index 00000000000..f00c2941940 --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3calc.dtx @@ -0,0 +1,930 @@ +% \iffalse +%% File: l3calc.dtx Copyright (C) 2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3calc.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental calc module} +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3calc.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3calc} package\thanks{This file has version +% number \fileversion, last +% revised \filedate.}\\ +% Infix notation arithmetic in \LaTeX3} +% \author{\Team} +% \date{\filedate} +% \maketitle +% +% \section{Infix notation arithmetic} +% +% This is pretty much a straight adaption of the \textsf{calc} package +% and as such has same syntax for the \meta{calc expression}. However, +% there are some noticeable differences. +% \begin{itemize} +% \item The calc expression is expanded fully, which means there are +% no problems with unfinished conditionals. However, the contents of +% |\widthof| etc.\ is not expanded at all. +% \item Muskip registers are supported although they can only be used +% in |\ratio| if already evaluating a muskip expression. For the +% other three register types, you can use points. +% \item All results are rounded, not truncated. More precisely, the +% primitive \TeX\ operations |\divide| and |\multiply| are not used. +% \end{itemize} +% +% \begin{function}{ +% \calc_int_set:Nn | +% \calc_int_gset:Nn | +% \calc_int_add:Nn | +% \calc_int_gadd:Nn | +% \calc_int_sub:Nn | +% \calc_int_gsub:Nn | +% } +% \begin{syntax} +% "\calc_int_set:Nn" <int> "{"<calc expression>"}" +% \end{syntax} +% Evaluates <calc expression> and either adds or subtracts it from +% <int> or sets <int> to it. These operations can also be global. +% \end{function} +% +% +% \begin{function}{ +% \calc_dim_set:Nn | +% \calc_dim_gset:Nn | +% \calc_dim_add:Nn | +% \calc_dim_gadd:Nn | +% \calc_dim_sub:Nn | +% \calc_dim_gsub:Nn | +% } +% \begin{syntax} +% "\calc_dim_set:Nn" <dim> "{"<calc expression>"}" +% \end{syntax} +% Evaluates <calc expression> and either adds or subtracts it from +% <dim> or sets <dim> to it. These operations can also be global. +% \end{function} +% +% +% \begin{function}{ +% \calc_skip_set:Nn | +% \calc_skip_gset:Nn | +% \calc_skip_add:Nn | +% \calc_skip_gadd:Nn | +% \calc_skip_sub:Nn | +% \calc_skip_gsub:Nn | +% } +% \begin{syntax} +% "\calc_skip_set:Nn" <skip> "{"<calc expression>"}" +% \end{syntax} +% Evaluates <calc expression> and either adds or subtracts it from +% <skip> or sets <skip> to it. These operations can also be global. +% \end{function} +% +% +% \begin{function}{ +% \calc_muskip_set:Nn | +% \calc_muskip_gset:Nn | +% \calc_muskip_add:Nn | +% \calc_muskip_gadd:Nn | +% \calc_muskip_sub:Nn | +% \calc_muskip_gsub:Nn | +% } +% \begin{syntax} +% "\calc_muskip_set:Nn" <muskip> "{"<calc expression>"}" +% \end{syntax} +% Evaluates <calc expression> and either adds or subtracts it from +% <muskip> or sets <muskip> to it. These operations can also be +% global. +% \end{function} +% +% +% \begin{function}{ +% \calc_calculate_box_size:nnn | +% } +% \begin{syntax} +% "\calc_calculate_box_size:nnn" "{"<dim-set>"}" \\ +% "{"<item 1> <item 2> ... <item n>"}" "{"<contents>"}" +% \end{syntax} +% Sets <contents> in a temporary box "\l_tmpa_box". Then <dim-set> +% is put in front of a loop that inserts "+"\meta{item$\sb{i}$} in +% front of "\l_tmpa_box" and this is evaluated. For instance, if we +% wanted to determine the total height of the text "xyz" and store +% it in "\l_tmpa_dim", we would call it as. +% \begin{verbatim} +% \calc_calculate_box_size:nnn +% {\dim_set:Nn\l_tmpa_dim}{\box_ht:N\box_dp:N}{xyz} +% \end{verbatim} +% Similarly, if we wanted the difference between height and depth, +% we could call it as +% \begin{verbatim} +% \calc_calculate_box_size:nnn +% {\dim_set:Nn\l_tmpa_dim}{\box_ht:N{-\box_dp:N}}{xyz} +% \end{verbatim} +% \end{function} +% +% \StopEventually{} +% +% \subsection{The Implementation} +% +% Since this is basically a re-worked version of the \textsf{calc} +% package, I haven't bothered with too many comments except for in the +% places where this package differs. This may (and should) change at +% some point. +% +% We start by ensuring that the required packages are loaded. +% \begin{macrocode} +%<*package> +\RequirePackage{l3int} +\RequirePackage{l3skip} +\RequirePackage{l3box} +%</package> +%<*initex|package> +% \end{macrocode} +% +% +% \begin{macro}{\l_calc_expression_tlp} +% \begin{macro}{\g_calc_A_register} +% \begin{macro}{\l_calc_B_register} +% \begin{macro}{\l_calc_current_type_int} +% Here we define some registers and pointers we will need. +% \begin{macrocode} +\tlp_new:Nn\l_calc_expression_tlp{} +\def_new:Npn \g_calc_A_register{} +\def_new:Npn \l_calc_B_register{} +\int_new:N \l_calc_current_type_int +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\g_calc_A_int} +% \begin{macro}{\l_calc_B_int} +% \begin{macro}{\l_calc_C_int} +% \begin{macro}{\g_calc_A_dim} +% \begin{macro}{\l_calc_B_dim} +% \begin{macro}{\l_calc_C_dim} +% \begin{macro}{\g_calc_A_skip} +% \begin{macro}{\l_calc_B_skip} +% \begin{macro}{\l_calc_C_skip} +% \begin{macro}{\g_calc_A_muskip} +% \begin{macro}{\l_calc_B_muskip} +% \begin{macro}{\l_calc_C_muskip} +% For each type of register we will need three registers to do our +% manipulations. +% \begin{macrocode} +\int_new:N \g_calc_A_int +\int_new:N \l_calc_B_int +\int_new:N \l_calc_C_int +\dim_new:N \g_calc_A_dim +\dim_new:N \l_calc_B_dim +\dim_new:N \l_calc_C_dim +\skip_new:N \g_calc_A_skip +\skip_new:N \l_calc_B_skip +\skip_new:N \l_calc_C_skip +\muskip_new:N \g_calc_A_muskip +\muskip_new:N \l_calc_B_muskip +\muskip_new:N \l_calc_C_muskip +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \begin{macro}{\calc_assign_generic:NNNNNn} +% The generic function. |#1| is a number denoting which type we are +% doing. (0=int, 1=dim, 2=skip, 3=muskip), |#2| = temp register A, +% |#3| = temp register B, |#4| is a function acting on |#5| which is +% the register to be set. |#6| is the calc expression. This version +% relies on |\real| and |\ratio| having our definitions. +% \begin{macrocode} +\def_long_new:Npn \calc_assign_generic:NNNNNn#1#2#3#4#5#6{ + \let:NN\g_calc_A_register#2\let:NN\l_calc_B_register#3 + \int_set:Nn \l_calc_current_type_int {#1} + \tlp_set:Nx\l_calc_expression_tlp{#6} + \exp_after:NN\calc_open:w\exp_after:NN(\l_calc_expression_tlp! + \pref_global:D\g_calc_A_register\l_calc_B_register + \group_end: + #4#5\l_calc_B_register +} +% \end{macrocode} +% One could lift these restrictions by defining |\calc_generic:NNNNNn| +% like this: +% \begin{verbatim} +% \def_long_new:Npn \calc_assign_generic:NNNNNn#1#2#3#4#5#6{ +% \let:NN\g_calc_A_register#2\let:NN\l_calc_B_register#3 +% \int_set:Nn \l_calc_current_type_int {#1} +% \group_begin: +% \let:NN \real\calc_real:n +% \let:NN \ratio\calc_ratio:nn +% \tlp_set:Nx\l_calc_expression_tlp{#6} +% \exp_after:NN +% \group_end: +% \exp_after:NN\calc_open:w\exp_after:NN(\l_calc_expression_tlp! +% \pref_global:D\g_calc_A_register\l_calc_B_register +% \group_end: +% #4#5\l_calc_B_register +% } +% \end{verbatim} +% \end{macro} +% +% +% +% \begin{macro}{\calc_int_set:Nn} +% \begin{macro}{\calc_int_gset:Nn} +% \begin{macro}{\calc_int_add:Nn} +% \begin{macro}{\calc_int_gadd:Nn} +% \begin{macro}{\calc_int_sub:Nn} +% \begin{macro}{\calc_int_gsub:Nn} +% Here are the individual versions for the different register +% types. First integer registers. +% \begin{macrocode} +\def_new:Npn\calc_int_set:Nn{ + \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_set:Nn +} +\def_new:Npn\calc_int_gset:Nn{ + \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_gset:Nn +} +\def_new:Npn\calc_int_add:Nn{ + \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_add:Nn +} +\def_new:Npn\calc_int_gadd:Nn{ + \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_gadd:Nn +} +\def_new:Npn\calc_int_sub:Nn{ + \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_sub:Nn +} +\def_new:Npn\calc_int_gsub:Nn{ + \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_gsub:Nn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_dim_set:Nn} +% \begin{macro}{\calc_dim_gset:Nn} +% \begin{macro}{\calc_dim_add:Nn} +% \begin{macro}{\calc_dim_gadd:Nn} +% \begin{macro}{\calc_dim_sub:Nn} +% \begin{macro}{\calc_dim_gsub:Nn} +% Dimens. +% \begin{macrocode} +\def_new:Npn\calc_dim_set:Nn{ + \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_set:Nn +} +\def_new:Npn\calc_dim_gset:Nn{ + \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_gset:Nn +} +\def_new:Npn\calc_dim_add:Nn{ + \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_add:Nn +} +\def_new:Npn\calc_dim_gadd:Nn{ + \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_gadd:Nn +} +\def_new:Npn\calc_dim_sub:Nn{ + \calc_assign_generic:NNNNNn\c_one\g_calc_A_int\l_calc_B_int\dim_sub:Nn +} +\def_new:Npn\calc_dim_gsub:Nn{ + \calc_assign_generic:NNNNNn\c_one\g_calc_A_int\l_calc_B_int\dim_gsub:Nn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_skip_set:Nn} +% \begin{macro}{\calc_skip_gset:Nn} +% \begin{macro}{\calc_skip_add:Nn} +% \begin{macro}{\calc_skip_gadd:Nn} +% \begin{macro}{\calc_skip_sub:Nn} +% \begin{macro}{\calc_skip_gsub:Nn} +% Skips. +% \begin{macrocode} +\def_new:Npn\calc_skip_set:Nn{ + \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_set:Nn +} +\def_new:Npn\calc_skip_gset:Nn{ + \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_gset:Nn +} +\def_new:Npn\calc_skip_add:Nn{ + \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_add:Nn +} +\def_new:Npn\calc_skip_gadd:Nn{ + \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_gadd:Nn +} +\def_new:Npn\calc_skip_sub:Nn{ + \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_sub:Nn +} +\def_new:Npn\calc_skip_gsub:Nn{ + \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_gsub:Nn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_muskip_set:Nn} +% \begin{macro}{\calc_muskip_gset:Nn} +% \begin{macro}{\calc_muskip_add:Nn} +% \begin{macro}{\calc_muskip_gadd:Nn} +% \begin{macro}{\calc_muskip_sub:Nn} +% \begin{macro}{\calc_muskip_gsub:Nn} +% Muskips. +% \begin{macrocode} +\def_new:Npn\calc_muskip_set:Nn{ + \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_set:Nn +} +\def_new:Npn\calc_muskip_gset:Nn{ + \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_gset:Nn +} +\def_new:Npn\calc_muskip_add:Nn{ + \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_add:Nn +} +\def_new:Npn\calc_muskip_gadd:Nn{ + \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_gadd:Nn +} +\def_new:Npn\calc_muskip_sub:Nn{ + \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_add:Nn +} +\def_new:Npn\calc_muskip_gsub:Nn{ + \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_gadd:Nn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\calc_pre_scan:N} +% In case we found one of the special operations, this should just +% be executed. +% \begin{macrocode} +\def_new:Npn \calc_pre_scan:N #1{ + \if_meaning:NN(#1 + \exp_after:NN\calc_open:w + \else: + \if_meaning:NN \calc_textsize:Nn #1 + \else: + \if_meaning:NN \calc_maxmin_operation:Nnn #1 + \else: +% \end{macrocode} +% |\calc_numeric:| uses a primitive assignment so doesn't care about +% these dangling |\fi:|s. +% \begin{macrocode} + \calc_numeric: + \fi: + \fi: + \fi: + #1} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\calc_open:w} +% \begin{macrocode} +\def_new:Npn \calc_open:w({ + \group_begin:\group_execute_after:N\calc_init_B: + \group_begin:\group_execute_after:N\calc_init_B: + \calc_pre_scan:N +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\calc_init_B:} +% \begin{macro}{\calc_numeric:} +% \begin{macro}{\calc_close:} +% \begin{macrocode} +\def_new:Npn\calc_init_B:{\l_calc_B_register\g_calc_A_register} +\def_new:Npn\calc_numeric:{ + \tex_afterassignment:D\calc_post_scan:N + \pref_global:D\g_calc_A_register +} +\def_new:Npn\calc_close:{ + \group_end:\pref_global:D\g_calc_A_register\l_calc_B_register + \group_end:\pref_global:D\g_calc_A_register\l_calc_B_register + \calc_post_scan:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_post_scan:N} +% Look at what token we have and decide where to go. +% \begin{macrocode} +\def_new:Npn\calc_post_scan:N#1{ + \if_meaning:NN#1!\let:NN\calc_next:w\group_end: \else: + \if_meaning:NN#1+\let:NN\calc_next:w\calc_add: \else: + \if_meaning:NN#1-\let:NN\calc_next:w\calc_subtract: \else: + \if_meaning:NN#1*\let:NN\calc_next:w\calc_multiply:N \else: + \if_meaning:NN#1/\let:NN\calc_next:w\calc_divide:N \else: + \if_meaning:NN#1)\let:NN\calc_next:w\calc_close: \else: +% \end{macrocode} +% If we get here, there is an error but let's also disable +% |\calc_next:w| since it is otherwise undefined. No need to give +% extra errors just for that. +% \begin{macrocode} + \let:NN \calc_next:w \scan_stop: + \calc_error:N#1 + \fi: + \fi: + \fi: + \fi: + \fi: + \fi: + \calc_next:w} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\calc_multiply:N} +% \begin{macro}{\calc_divide:N} +% The switches for multiplication and division. +% \begin{macrocode} +\def_new:Npn \calc_multiply:N #1{ + \if_meaning:NN \calc_maxmin_operation:Nnn #1 + \let:NN \calc_next:w \calc_maxmin_multiply: + \else: + \if_meaning:NN \calc_ratio_multiply:nn #1 + \let:NN \calc_next:w \calc_ratio_multiply:nn + \else: + \if_meaning:NN \calc_real_evaluate:nn #1 + \let:NN \calc_next:w \calc_real_multiply:n + \else: + \def:Npn \calc_next:w{\calc_multiply: #1} + \fi: + \fi: + \fi: + \calc_next:w +} +\def_new:Npn \calc_divide:N #1{ + \if_meaning:NN \calc_maxmin_operation:Nnn #1 + \let:NN \calc_next:w \calc_maxmin_divide: + \else: + \if_meaning:NN \calc_ratio_multiply:nn #1 + \let:NN \calc_next:w \calc_ratio_divide:nn + \else: + \if_meaning:NN \calc_real_evaluate:nn #1 + \let:NN \calc_next:w \calc_real_divide:n + \else: + \def:Npn \calc_next:w{\calc_divide: #1} + \fi: + \fi: + \fi: + \calc_next:w +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_generic_add:N} +% \begin{macro}{\calc_add:} +% \begin{macro}{\calc_subtract:} +% \begin{macro}{\calc_add_A_to_B:} +% \begin{macro}{\calc_subtract_A_from_B:} +% Here is how we add and subtract. +% \begin{macrocode} +\def_new:Npn\calc_generic_add_or_subtract:N#1{ + \group_end: + \pref_global:D\g_calc_A_register\l_calc_B_register\group_end: + \group_begin:\group_execute_after:N#1\group_begin: + \group_execute_after:N\calc_init_B: + \calc_pre_scan:N} +\def_new:Npn\calc_add:{\calc_generic_add_or_subtract:N\calc_add_A_to_B:} +\def_new:Npn\calc_subtract:{ + \calc_generic_add_or_subtract:N\calc_subtract_A_from_B:} +% \end{macrocode} +% Don't use |\tex_advance:D| since it allows overflows. +% \begin{macrocode} +\def_new:Npn\calc_add_A_to_B:{ + \l_calc_B_register + \if_case:w\l_calc_current_type_int + \etex_numexpr:D\or: + \etex_dimexpr:D\or: + \etex_glueexpr:D\or: + \etex_muexpr:D\fi: + \l_calc_B_register + \g_calc_A_register\scan_stop: +} +\def_new:Npn\calc_subtract_A_from_B:{ + \l_calc_B_register + \if_case:w\l_calc_current_type_int + \etex_numexpr:D\or: + \etex_dimexpr:D\or: + \etex_glueexpr:D\or: + \etex_muexpr:D\fi: + \l_calc_B_register - \g_calc_A_register\scan_stop: +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_generic_multiply_or_divide:N} +% \begin{macro}{\calc_multiply_B_by_A:} +% \begin{macro}{\calc_divide_B_by_A:} +% \begin{macro}{\calc_multiply:} +% \begin{macro}{\calc_divide:} +% And here is how we multiply and divide. Note that we do not use the +% primitive \TeX{} operations but the expandable operations provided +% by \eTeX. This means that all results are rounded not truncated! +% \begin{macrocode} +\def_new:Npn\calc_generic_multiply_or_divide:N#1{ + \group_end: + \group_begin: + \let:NN\g_calc_A_register\g_calc_A_int + \let:NN\l_calc_B_register\l_calc_B_int + \group_execute_after:N#1\calc_pre_scan:N +} +\def_new:Npn\calc_multiply_B_by_A:{ + \l_calc_B_register + \if_case:w\l_calc_current_type_int + \etex_numexpr:D\or: + \etex_dimexpr:D\or: + \etex_glueexpr:D\or: + \etex_muexpr:D\fi: + \l_calc_B_register*\g_calc_A_int\scan_stop: +} +\def_new:Npn\calc_divide_B_by_A:{ + \l_calc_B_register + \if_case:w\l_calc_current_type_int + \etex_numexpr:D\or: + \etex_dimexpr:D\or: + \etex_glueexpr:D\or: + \etex_muexpr:D\fi: + \l_calc_B_register/\g_calc_A_int\scan_stop: +} +\def_new:Npn\calc_multiply:{ + \calc_generic_multiply_or_divide:N\calc_multiply_B_by_A:} +\def_new:Npn\calc_divide:{ + \calc_generic_multiply_or_divide:N\calc_divide_B_by_A:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_calculate_box_size:nnn} +% \begin{macro}{\calc_calculate_box_size_aux:n} +% Put something in a box and measure it. |#1| is a list of +% |\box_ht:N| etc., |#2| should be |\dim_set:Nn|\meta{dim register} +% or |\dim_gset:Nn|\meta{dim register} and |#3| is the contents. +% \begin{macrocode} +\def_long_new:Npn \calc_calculate_box_size:nnn #1#2#3{ + \hbox_set:Nn \l_tmpa_box {{#3}} + #2{\c_zero_dim \tlist_map_function:nN{#1}\calc_calculate_box_size_aux:n} +} +% \end{macrocode} +% Helper for calculating the final dimension. +% \begin{macrocode} +\def:Npn \calc_calculate_box_size_aux:n#1{ + #1\l_tmpa_box} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\calc_textsize:Nn} +% Now we can define |\calc_textsize:Nn|. +% \begin{macrocode} +\def_protected_long:Npn \calc_textsize:Nn#1#2{ + \group_begin: + \let:NN\widthof\box_wd:N + \let:NN\heightof\box_ht:N + \let:NN\depthof\box_dp:N + \def:Npn\totalheightof{\box_ht:N\box_dp:N} + \exp_args:No\calc_calculate_box_size:nnn{#1} + {\dim_gset:Nn\g_calc_A_register} +% \end{macrocode} +% Restore the four user commands here since there might be a recursive +% call. +% \begin{macrocode} + { + \let:NN \depthof\calc_depthof:n + \let:NN \widthof\calc_widthof:n + \let:NN \heightof\calc_heightof:n + \let:NN \totalheightof\calc_totalheightof:n + #2 + } + \group_end: + \calc_post_scan:N +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\calc_ratio_multiply:nn} +% \begin{macro}{\calc_ratio_divide:nn} +% Evaluate a ratio. If we were already evaluation a \meta{muskip} +% register, the ratio is probably also done with this type and we'll +% have to convert them to regular points. +% \begin{macrocode} +\def_protected_long:Npn\calc_ratio_multiply:nn#1#2{ + \group_end:\group_begin: + \if_num:w\l_calc_current_type_int < \c_three + \calc_dim_set:Nn\l_calc_B_int{#1} + \calc_dim_set:Nn\l_calc_C_int{#2} + \else: + \calc_dim_muskip:Nn{\l_calc_B_int\etex_mutoglue:D}{#1} + \calc_dim_muskip:Nn{\l_calc_C_int\etex_mutoglue:D}{#2} + \fi: +% \end{macrocode} +% Then store the ratio as a fraction, which we just pass on. +% \begin{macrocode} + \gdef:Npx\calc_calculated_ratio:{ + \int_use:N\l_calc_B_int/\int_use:N\l_calc_C_int + } + \group_end: +% \end{macrocode} +% Here we set the new value of |\l_calc_B_register| and remember to +% evaluate it as the correct type. Note that the intermediate +% calculation is a scaled operation (meaning the intermediate value is +% 64-bit) so we don't get into trouble when first multiplying by a +% large number and then dividing. +% \begin{macrocode} + \l_calc_B_register + \if_case:w\l_calc_current_type_int + \etex_numexpr:D\or: + \etex_dimexpr:D\or: + \etex_glueexpr:D\or: + \etex_muexpr:D\fi: + \l_calc_B_register*\calc_calculated_ratio:\scan_stop: + \group_begin: + \calc_post_scan:N} +% \end{macrocode} +% Division is just flipping the arguments around. +% \begin{macrocode} +\def_long_new:Npn \calc_ratio_divide:nn#1#2{\calc_ratio_multiply:nn{#2}{#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_real_evaluate:nn} +% \begin{macro}{\calc_real_multiply:n} +% \begin{macro}{\calc_real_divide:n} +% Although we could define the |\real| function as a subcase of +% |\ratio|, this is horribly inefficient since we just want to convert +% the decimal to a fraction. +% \begin{macrocode} +\def_protected_new:Npn\calc_real_evaluate:nn #1#2{ + \group_end: + \l_calc_B_register + \if_case:w\l_calc_current_type_int + \etex_numexpr:D\or: + \etex_dimexpr:D\or: + \etex_glueexpr:D\or: + \etex_muexpr:D\fi: + \l_calc_B_register * + \tex_number:D \dim_eval:n{#1pt}/ + \tex_number:D\dim_eval:n{#2pt} + \scan_stop: + \group_begin: + \calc_post_scan:N} +\def_new:Npn \calc_real_multiply:n #1{\calc_real_evaluate:nn{#1}{1}} +\def_new:Npn \calc_real_divide:n {\calc_real_evaluate:nn{1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_maxmin_operation:Nnn} +% \begin{macro}{\calc_maxmin_generic:Nnn} +% \begin{macro}{\calc_maxmin_div_or_mul:NNnn} +% \begin{macro}{\calc_maxmin_multiply:} +% \begin{macro}{\calc_maxmin_multiply:} +% The max and min functions. +% \begin{macrocode} +\def_protected_long:Npn\calc_maxmin_operation:Nnn#1#2#3{ + \group_begin: + \calc_maxmin_generic:Nnn#1{#2}{#3} + \group_end: + \calc_post_scan:N +} +% \end{macrocode} +% |#1| is either |>| or |<| and was expanded into this initially. +% \begin{macrocode} +\def_protected_long_new:Npn \calc_maxmin_generic:Nnn#1#2#3{ + \group_begin: + \if_case:w\l_calc_current_type_int + \calc_int_set:Nn\l_calc_C_int{#2}% + \calc_int_set:Nn\l_calc_B_int{#3}% + \pref_global:D\g_calc_A_register + \if_num:w\l_calc_C_int#1\l_calc_B_int + \l_calc_C_int\else:\l_calc_B_int\fi: + \or: + \calc_dim_set:Nn\l_calc_C_dim{#2}% + \calc_dim_set:Nn\l_calc_B_dim{#3}% + \pref_global:D\g_calc_A_register + \if_dim:w\l_calc_C_dim#1\l_calc_B_dim + \l_calc_C_dim\else:\l_calc_B_dim\fi: + \or: + \calc_skip_set:Nn\l_calc_C_skip{#2}% + \calc_skip_set:Nn\l_calc_B_skip{#3}% + \pref_global:D\g_calc_A_register + \if_dim:w\l_calc_C_skip#1\l_calc_B_skip + \l_calc_C_skip\else:\l_calc_B_skip\fi: + \else: + \calc_muskip_set:Nn\l_calc_C_muskip{#2}% + \calc_muskip_set:Nn\l_calc_B_muskip{#3}% + \pref_global:D\g_calc_A_register + \if_dim:w\l_calc_C_muskip#1\l_calc_B_muskip + \l_calc_C_muskip\else:\l_calc_B_muskip\fi: + \fi: + \group_end: +} +\def_long_new:Npn\calc_maxmin_div_or_mul:NNnn#1#2#3#4{ + \group_end: + \group_begin: + \int_zero:N\l_calc_current_type_int + \group_execute_after:N#1 + \calc_maxmin_generic:Nnn#2{#3}{#4} + \group_end: + \group_begin: + \calc_post_scan:N +} +\def_new:Npn\calc_maxmin_multiply:{ + \calc_maxmin_div_or_mul:NNnn\calc_multiply_B_by_A:} +\def_new:Npn\calc_maxmin_divide: { + \calc_maxmin_div_or_mul:NNnn\calc_divide_B_by_A:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_error:N} +% The error message. +% \begin{macrocode} +\def_new:Npn\calc_error:N#1{ + \PackageError{calc} + {`\token_to_string:N#1'~ invalid~ at~ this~ point} + {I~ expected~ to~ see~ one~ of:~ +~ -~ *~ /~ )} +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Higher level commands} +% +% The various operations allowed. +% +% \begin{macro}{\calc_maxof:nn} +% \begin{macro}{\calc_minof:nn} +% \begin{macro}{\maxof} +% \begin{macro}{\minof} +% Max and min operations +% \begin{macrocode} +\def_long_new:Npn \calc_maxof:nn#1#2{ + \calc_maxmin_operation:Nnn > \exp_not:n{{#1}{#2}} +} +\def_long_new:Npn \calc_minof:nn#1#2{ + \calc_maxmin_operation:Nnn < \exp_not:n{{#1}{#2}} +} +\let_new:NN \maxof \calc_maxof:nn +\let_new:NN \minof \calc_minof:nn +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_widthof:n} +% \begin{macro}{\calc_heightof:n} +% \begin{macro}{\calc_depthof:n} +% \begin{macro}{\calc_totalheightof:n} +% \begin{macro}{\widthof} +% \begin{macro}{\heightof} +% \begin{macro}{\depthof} +% \begin{macro}{\totalheightof} +% Text dimension commands. +% \begin{macrocode} +\def_long_new:Npn \calc_widthof:n#1{ + \calc_textsize:Nn \exp_not:N\widthof\exp_not:n{{#1}} +} +\def_long_new:Npn \calc_heightof:n#1{ + \calc_textsize:Nn \exp_not:N\heightof\exp_not:n{{#1}} +} +\def_long_new:Npn \calc_depthof:n#1{ + \calc_textsize:Nn \exp_not:N\depthof\exp_not:n{{#1}} +} +\def_long_new:Npn \calc_totalheightof:n#1{ + \calc_textsize:Nn \exp_not:N\totalheightof\exp_not:n{{#1}} +} +\let:NN \depthof\calc_depthof:n +\let:NN \widthof\calc_widthof:n +\let:NN \heightof\calc_heightof:n +\let:NN \totalheightof\calc_totalheightof:n +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_ratio:nn} +% \begin{macro}{\calc_real:n} +% \begin{macro}{\ratio} +% \begin{macro}{\real} +% Ratio and real. +% \begin{macrocode} +\def_long_new:Npn \calc_ratio:nn#1#2{ + \calc_ratio_multiply:nn\exp_not:n{{#1}{#2}}} +\let_new:NN \calc_real:n \calc_real_evaluate:nn +% \end{macrocode} +% We can implement real and ratio without actually using these +% names. We'll see. +% \begin{macrocode} +\let_new:NN \ratio\calc_ratio:nn +\let_new:NN \real\calc_real:n +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macrocode} +%</initex|package> +%<*showmemory> +\showMemUsage +%</showmemory> +% \end{macrocode} +% +% \endinput +% +% $Log$ +% Revision 1.2 2006/01/27 23:11:47 morten +% Fixed bug in \calc_pre_scan:N and avoid using \advance in order to +% catch overflows. +% +% Revision 1.1 2006/01/27 07:51:13 morten +% Initial version of a calc module +% diff --git a/Master/texmf-dist/source/latex/expl3/l3chk.dtx b/Master/texmf-dist/source/latex/expl3/l3chk.dtx index 56b9cf5c34c..f492a516903 100644 --- a/Master/texmf-dist/source/latex/expl3/l3chk.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3chk.dtx @@ -1,16 +1,50 @@ % \iffalse -%% File: l3chk.dtx Copyright (C) 1990-1998 LaTeX3 project -% +%% File: l3chk.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +%<package>\RequirePackage{l3names} %<*dtx> - \ProvidesFile{l3chk.dtx} +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse %</dtx> -%<package>\NeedsTeXFormat{LaTeX2e} -%<package>\ProvidesPackage{l3chk} -%<driver> \ProvidesFile{l3chk.drv} -% \fi -% \ProvidesFile{l3chk.dtx} - [1998/04/20 v1.0e L3 Experimental check module] -% +%\fi +\GetIdInfo$Id: l3chk.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental check module} % \iffalse %<*driver> \documentclass{l3doc} @@ -21,7 +55,6 @@ %</driver> % \fi % -% \GetFileInfo{l3chk.dtx} % \title{The \textsf{l3chk} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ @@ -35,11 +68,12 @@ % To ensure that functions and variables are properly used certain % checking functions are implemented that may or may not be compiled % into the final format. -% +% % \subsection{Functions} -% +% % \begin{function}{% % \chk_var_or_const:N | +% \chk_var_or_const:c | % } % \begin{syntax} % "\chk_var_or_const:N" <cs> @@ -47,10 +81,12 @@ % Checks that <cs> is a proper variable or constant which means that its % name starts out with "\L", "\l", "\G", "\g", "\R", "\C", "\c", or "\q". % \end{function} -% +% % \begin{function}{% % \chk_local:N | +% \chk_local:c | % \chk_global:N | +% \chk_global:c | % } % \begin{syntax} % "\chk_local:N" <cs> @@ -58,7 +94,7 @@ % Checks that <cs> is a proper local or global variable. This means that % its name starts out with "\L", "\l", or "\G", "\g" respectively. % \end{function} -% +% % \begin{function}{% % \chk_local_or_pref_global:N | % \pref_global_chk: | @@ -82,16 +118,16 @@ % "\pref_global:D" turns its operation into a global one. See % implementation for details. % \end{function} -% +% % \subsection{Constants} -% +% % \begin{variable}{\c_undefined} % This constant is always undefined and therefore can be used to check % for free function names. % \end{variable} -% +% % \subsection{Internal functions} -% +% % \begin{function}{% % \chk_global_aux:w | % \chk_local_aux:w | @@ -102,13 +138,13 @@ % % \StopEventually{} % -% \section{The code} +% \subsection{The Implementation} % % We start by ensuring that the required packages are loaded. % \begin{macrocode} %<package>\RequirePackage{l3basics} -%<package>\RequirePackage{l3int} -%<*package> +%<package>\RequirePackage{l3int,l3prg} +%<*initex|package> % \end{macrocode} % % The |\chk| module contains those functions that are used primarily @@ -116,33 +152,34 @@ % too badly. All these functions are of type `{\tt e}' since they % issue error messages if certain conditions are violated. % -% \subsection{Checking variable assignments} +% \subsubsection{Checking variable assignments} % % \begin{macro}{\chk_local:N} % \begin{macro}{\chk_local_aux:w} % This function checks that its argument is a proper local -% variable, i.e.\ its name starts with |\l| or |\L|. +% variable, i.e.\ its name starts with |\l| or |\L|. % It is not allowed that the name starts with |\g| or |\G|, % which means that we do not allow to update global -% variables locally. But see |\pref_global_chk:| below for +% variables locally. But see |\pref_global_chk:| below for % the encoding of functions that might accept global variables % in certain situations. Not checked is the case that the -% argument isn't a variable at all, i.e.\ it doesn't have +% argument isn't a variable at all, i.e.\ it doesn't have % a |_| as second letter. Maybe we should add this for safety % during the implementation since it will find certain errors % involving wrong expansion in earlier stage. % \begin{macrocode} -\def_new:Npn \chk_local:N #1{\exp_after:NN - \chk_local_aux:w \token_to_string:N#1\q_stop} +\def_new:Npn \chk_local:N #1{ + \exp_after:NN \chk_local_aux:w \token_to_string:N#1\q_stop} + \def_new:Npn \chk_local_aux:w #1#2#3\q_stop{ \if_num:w\tex_uccode:D`#2=`G\scan_stop: - \err_latex_bug:n{Local~mismatch:~local~function~called~with~ + \err_latex_bug:x{Local~mismatch:~local~function~called~with~ global~variable:^^J\text_put_four_sp: #1#2#3~ on~line~\tex_the:D\tex_inputlineno:D} \else: \if_num:w\tex_uccode:D`#2=`L\scan_stop: \else: - \err_latex_bug:n{Variable~mismatch:~function~not~called~with~ + \err_latex_bug:x{Variable~mismatch:~function~not~called~with~ proper~variable:^^J\text_put_four_sp: #1#2#3~ on~line~\tex_the:D\tex_inputlineno:D}\fi: \fi:} @@ -164,13 +201,13 @@ \chk_global_aux:w \token_to_string:N#1\q_stop} \def_new:Npn \chk_global_aux:w #1#2#3\q_stop{ \if_num:w\tex_uccode:D`#2=`L\scan_stop: - \err_latex_bug:n{Global~mismatch:~global~function~called~with~ + \err_latex_bug:x{Global~mismatch:~global~function~called~with~ local~variable:~#1#2#3~ on~line~\tex_the:D\tex_inputlineno:D} \else: \if_num:w\tex_uccode:D`#2=`G\scan_stop: \else: - \err_latex_bug:n{Variable~mismatch:~function~not~called~with~ + \err_latex_bug:x{Variable~mismatch:~function~not~called~with~ proper~variable:~#1#2#3~ on~line~\tex_the:D\tex_inputlineno:D}\fi:\fi:} % \end{macrocode} @@ -230,7 +267,7 @@ % \end{macrocode} % We also allow the beast to be a quark, i.e.\ to start with |\q|. % \begin{macrocode} - \if_char_code:w#2q\scan_stop: + \if_charcode:w#2q\scan_stop: \else: % \end{macrocode} % We might also want to allow that it is a user definable @@ -238,7 +275,7 @@ % could check this by testing that there is no |_|, but this is not % implemented so far. % \begin{macrocode} - \err_latex_bug:n{Variable~mismatch:~function~not~called~with~ + \err_latex_bug:x{Variable~mismatch:~function~not~called~with~ proper~variable:^^J\text_put_four_sp: #1#2#3~ on~line~\tex_the:D\tex_inputlineno:D}\fi:\fi:\fi: \fi:} @@ -247,7 +284,7 @@ % \end{macro} % % -% \subsection{Doing some tracing} +% \subsubsection{Doing some tracing} % % \begin{macro}{\tracingall} % \begin{macro}{\absolutelytracingall} @@ -288,7 +325,7 @@ \pref_global:D\g_trace_box_breadth_int\c_ten_thousand \pref_global:D\g_trace_box_depth_int\c_ten_thousand \pref_global:D\g_trace_online_status\c_one - \mode_errorstop:D} + \tex_errorstopmode:D} % % Use LaTeX2e definition for now. %\def_new:Npn\tracingall{ @@ -323,27 +360,29 @@ % \end{macrocode} % \end{macro} % -% \subsection{Tracing modules} +% \subsubsection{Tracing modules} % % \begin{macro}{\traceon} % \begin{macro}{\traceoff} % Turning the tracing of modules on or off. (primitive version). % \begin{macrocode} %<*trace> -\def_new:Npn\traceon#1{\for_clist:Nnn\l_tmpa_tlp{#1} - { - \cs_free:cF{g_trace_\l_tmpa_tlp _status} - {\int_gincr:c{g_trace_\l_tmpa_tlp _status}} - }} -\def_new:Npn\traceoff#1{\for_clist:Nnn\l_tmpa_tlp{#1} - { - \cs_free:cF{g_trace_\l_tmpa_tlp _status} - {\int_gdecr:c{g_trace_\l_tmpa_tlp _status}} - }} +\def_new:Npn\traceon#1{ + \clist_map_inline:nn {#1}{ + \cs_free:cF{g_trace_ ##1 _status} + {\int_gincr:c{g_trace_ ##1 _status}} + } +} +\def_new:Npn\traceoff#1{ + \clist_map_inline:nn {#1}{ + \cs_free:cF{g_trace_ ##1 _status} + {\int_gdecr:c{g_trace_ ##1 _status}} + } +} %</trace> %<-trace>\let_new:NN\traceon\use_none:n %<-trace>\let_new:NN\traceoff\use_none:n -%</package> +%</initex|package> % \end{macrocode} % \end{macro} % \end{macro} @@ -356,3 +395,22 @@ %</showmemory> % \end{macrocode} % +% \endinput +% +% $Log$ +% Revision 1.14 2006/03/20 18:26:34 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.13 2005/12/27 09:58:01 morten +% Minor changes plus changed RCS information retrieval +% +% Revision 1.12 2005/04/12 12:07:53 morten +% Removed unnecessary functions +% +% Revision 1.11 2005/03/15 23:31:54 braams +% Some fiddling with docstrip guards for initex use +% +% Revision 1.10 2005/03/11 21:33:31 braams +% Fixed the use of RCS information +% diff --git a/Master/texmf-dist/source/latex/expl3/l3clist.dtx b/Master/texmf-dist/source/latex/expl3/l3clist.dtx new file mode 100644 index 00000000000..f8fdba275bb --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3clist.dtx @@ -0,0 +1,1082 @@ +% \iffalse +%% File: l3clist.dtx Copyright (C) 2005-2006 Frank Mittelbach, LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3clist.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental comma separated lists} +% +% \iffalse +%<*driver> +\documentclass{l3doc} +\begin{document} +\DocInput{l3clist.dtx} +\end{document} +%</driver> +% \fi +% +% +% +% \title{The \textsf{l3clist} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}\\ +% Comma separated lists} +% \author{Frank Mittelbach} +% \date{\filedate} +% \maketitle +% +% +% +% \section{Comma lists} +% +% \LaTeX3 implements a data type called `clist (comma-lists)'. These +% are special +% token lists that can be accessed via special function on the `left'. +% Appending tokens is possible at both ends. Appended token lists can be +% accessed only as a union. The token lists that form the individual +% items of a comma-list might contain any tokens except for commas that +% are used to structure comma-lists (braces are need if commas are +% part of the value). It is also possible to map functions on such +% comma-lists so that they are executed for every item of the comma-list. +% +% All functions that return items from a comma-list in some \m{tlp} assume +% that the \m{tlp} is local. See remarks below if you need a global +% returned value. +% +% The defined functions are not orthogonal in the sense that every +% possible variation possible is actually available. If you need a new +% variant use the expansion functions described in the package +% \texttt{l3expan} to build it. +% +% Adding items to the left of a comma-list can currently be done with +% either something like "\clist_put_left:Nn" or with a ``stack'' function +% like "\clist_push:Nn" which has the same effect. Maybe one should +% therefore remove the ``left'' functions totally. +% +% \subsection{Functions} +% +% \begin{function}{% +% \clist_new:N | +% \clist_new:c | +% } +% \begin{syntax} +% "\clist_new:N" <comma-list> +% \end{syntax} +% Defines <comma-list> to be a variable of type clist. +% \end{function} +% +% \begin{function}{% +% \clist_clear:N | +% \clist_clear:c | +% \clist_gclear:N | +% \clist_gclear:c | +% } +% \begin{syntax} +% "\clist_clear:N" <comma-list> +% \end{syntax} +% These functions locally or globally clear <comma-list>. +% \end{function} +% +% \begin{function}{% +% \clist_put_left:Nn | +% \clist_put_left:No | +% \clist_put_left:Nx | +% \clist_put_left:cn | +% \clist_put_right:Nn | +% \clist_put_right:No | +% \clist_put_right:Nx | +% } +% \begin{syntax} +% "\clist_put_left:Nn" <comma-list> <token list> +% \end{syntax} +% Locally appends <token list> as a single item to the left +% or right of <comma-list>. <token list> might get expanded before +% appending. +% \end{function} +% +% \begin{function}{% +% \clist_gput_left:Nn | +% \clist_gput_right:Nn | +% \clist_gput_right:No | +% \clist_gput_right:cn | +% \clist_gput_right:co | +% \clist_gput_right:cc | +% } +% \begin{syntax} +% "\clist_gput_left:Nn" <comma-list> <token list> +% \end{syntax} +% Globally appends <token list> as a single item to the left +% or right of <comma-list>. +% \end{function} +% +% \begin{function}{% +% \clist_get:NN | +% \clist_get:cN | +% } +% \begin{syntax} +% "\clist_get:NN" <comma-list> <tlp> +% \end{syntax} +% Functions that locally assign the left-most item of <comma-list> to the +% token list pointer <tlp>. Item is not removed from <comma-list>! If you +% need a global return value you need to code something like this: +% \begin{quote} +% "\clist_get:NN" <comma-list> "\l_tmpa_tlp" \\ +% "\tlp_gset_eq:NN" <global tlp> "\l_tmpa_tlp" +% \end{quote} +% But if this kind of construction is used often enough a separate +% function should be provided. +% \end{function} +% +% \begin{function}{% +% \clist_set_eq:NN +% } +% \begin{syntax} +% "\clist_set_eq:NN" <clist1> <clist2> +% \end{syntax} +% Function that locally makes <clist1> identical to <clist2>. +% \end{function} +% +% +% \begin{function}{% +% \clist_gset_eq:NN | +% \clist_gset_eq:cN | +% \clist_gset_eq:Nc | +% \clist_gset_eq:cc +% } +% \begin{syntax} +% "\clist_gset_eq:NN" <clist1> <clist2> +% \end{syntax} +% Function that globally makes <clist1> identical to <clist2>. +% \end{function} +% +% +% \begin{function}{% +% \clist_concat:NNN | +% \clist_gconcat:NNN | +% \clist_gconcat:NNc | +% \clist_gconcat:ccc | +% } +% \begin{syntax} +% "\clist_gconcat:NNN" <clist1> <clist2> <clist3> +% \end{syntax} +% Function that concatenates <clist2> and <clist3> and globally assigns the +% result to <clist1>. +% \end{function} +% +% +% \begin{function}{% +% \clist_remove_duplicates:N | +% \clist_gremove_duplicates:N | +% } +% \begin{syntax} +% "\clist_gremove_duplicates:N" <clist> +% \end{syntax} +% Function that removes any duplicate entries in <clist>. +% \end{function} +% +% \begin{function}{% +% \clist_use:N | +% \clist_use:c +% } +% \begin{syntax} +% "\clist_use:N" <clist> +% \end{syntax} +% Function that inserts the <clist> into the processing stream. Mainly +% useful if one knows what the <clist> contains, e.g., for displaying +% the content of template parameters. +% \end{function} +% +% +% \subsection{Mapping functions} +% +% +% We provide three types of mapping functions, each with their own +% strengths. The "\clist_map_function:NN" is expandable whereas +% "\clist_map_inline:Nn" type uses "##1" as a placeholder for the +% current item in \m{clist}. Finally we have the +% "\clist_map_variable:NNn" type which uses a user-defined variable as +% placeholder. Both the |_inline| and |_variable| versions are nestable. +% +% +% \begin{function}{\clist_map_function:NN| +% \clist_map_function:cN| +% \clist_map_function:nN +% } +% \begin{syntax} +% "\clist_map_function:NN" <comma-list> <function> +% \end{syntax} +% This function applies <function> (which must be a function with one +% argument) to every item of <comma-list>. <function> is not executed +% within a sub-group so that side effects can be achieved locally. The +% operation is expandable which means that it can be used within write +% operations etc. +% \end{function} +% +% \begin{function}{\clist_map_inline:Nn | +% \clist_map_inline:cn | +% \clist_map_inline:nn | +% } +% \begin{syntax} +% "\clist_map_inline:Nn" <comma-list> "{" <inline function> "}" +% \end{syntax} +% Applies <inline function> (which should be the direct coding for a +% function with one argument (i.e.\ use "##1" as the placeholder for +% this argument)) to every item of <comma-list>. <inline function> is not +% executed within a sub-group so that side effects can be achieved locally. +% The operation is not expandable which means that it can't be used +% within write operations etc. These functions can be nested. +% \end{function} +% +% +% \begin{function}{\clist_map_variable:NNn | +% \clist_map_variable:cNn | +% \clist_map_variable:nNn | +% } +% \begin{syntax} +% "\clist_map_variable:NNn" <comma-list> <temp-var> "{" <action> "}" +% \end{syntax} +% Assigns <temp-var> to each element in <clist> and then executes +% <action> which should contain <temp-var>. As the +% operation performs an assignment, it is not expandable. +% \begin{texnote} +% These functions resemble the \LaTeXe{} function \tn{@for} but does +% not borrow the somewhat strange syntax. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \clist_map_break:w | +% } +% \begin{syntax} +% "\clist_map_break:w" +% \end{syntax} +% For breaking out of a loop. To be used inside "TF" type functions as +% in the example below. +% \begin{verbatim} +% \def_new:Npn \test_function:n #1 { +% \int_compare:nNnTF {#1}> 3 {\clist_map_break:w}{``#1''} +% } +% \clist_map_function:nN {1,2,3,4,5,6,7,8}\test_function:n +% \end{verbatim} +% This would return "``1''``2''``3''". +% \end{function} +% +% +% \subsection{Predicates and conditionals} +% +% \begin{function}{\clist_if_empty_p:N} +% \begin{syntax} +% "\clist_if_empty_p:N" <comma-list> +% \end{syntax} +% This predicate returns `true' if <comma-list> is `empty' i.e., doesn't +% contain any tokens. +% \end{function} +% +% \begin{function}{% +% \clist_if_empty:NTF | +% \clist_if_empty:cTF | +% \clist_if_empty:NF | +% \clist_if_empty:cF | +% } +% \begin{syntax} +% "\clist_if_empty:NTF" <comma-list> "{" <true code> "}{" <false code> "}" +% \end{syntax} +% Set of conditionals that test whether or not a particular <comma-list> +% is empty and if so executes either <true code> or <false code>. +% \end{function} +% +% \begin{function}{% +% \clist_if_eq:NNTF | +% } +% \begin{syntax} +% "\clist_if_eq:NNTF" <comma-list1> <comma-list2> "{" <true code> +% "}{" <false code> "}" +% \end{syntax} +% Check if <comma-list1> and <comma-list2> are equal and execute +% either <true code> or <false code> accordingly. +% \end{function} +% +% \begin{function}{% +% \clist_if_in:NnTF | +% \clist_if_in:NoTF | +% \clist_if_in:cnTF | +% \clist_if_in:coTF | +% } +% \begin{syntax} +% "\clist_if_in:NnTF" <comma-list> "{" <item> "}{" <true code> "}{" +% <false code> "}" +% \end{syntax} +% Function that tests if <item> is in <comma-list>. Depending on the result +% either <true code> or <false code> is executed. +% \end{function} +% +% \subsection{Internal functions} +% +% \begin{function}{\clist_if_empty_err:N} +% \begin{syntax} +% "\clist_if_empty_err:N" <comma-list> +% \end{syntax} +% Signals an \LaTeX3 error if <comma-list> is empty. +% \end{function} +% +% \begin{function}{\clist_pop_aux:nnNN} +% \begin{syntax} +% "\clist_pop_aux:nnNN" <assign1> <assign2> <comma-list> <tlp> +% \end{syntax} +% Function that assigns the left-most item of <comma-list> to <tlp> using +% <assign1> and assigns the tail to <comma-list> using <assign2>. This +% function could be used to implement a global return function. +% \end{function} +% +% \begin{function}{% +% \clist_get_aux:w | +% \clist_pop_aux:w | +% \clist_pop_auxi:w | +% \clist_put_aux:NNnnNn | +% } +% \begin{syntax}\end{syntax} +% Functions used to implement put and get operations. They are not for +% meant for direct use. +% \end{function} +% +% +% +% \begin{function}{% +% \clist_map_function_aux:Nw | +% \clist_map_inline_aux:Nw | +% \clist_map_variable_aux:Nnw | +% } +% \begin{syntax}\end{syntax} +% Internal helper functions for the <clist> mapping functions. +% \end{function} +% +% +% \begin{function}{% +% \clist_concat_aux:NNNN | +% \clist_remove_duplicates_aux:NN | +% \clist_remove_duplicates_aux:n | +% \l_clist_remove_duplicates_clist | +% } +% \begin{syntax}\end{syntax} +% Functions that help concatenate <clist>s and remove duplicate +% elements from a <clist>. +% \end{function} +% +% +% +% \subsection{Comma list Stacks} +% +% Special comma-lists in \LaTeX3 are `stacks' with their usual operations +% of `push', `pop', and `top'. They are internally implemented as +% comma-lists and share some of the functions (like "\clist_new:N" etc.) +% +% +% \begin{function}{% +% \clist_push:Nn | +% \clist_push:No | +% \clist_push:cn | +% \clist_gpush:Nn | +% \clist_gpush:No | +% \clist_gpush:cn | +% } +% \begin{syntax} +% "\clist_push:Nn" <stack> "{" <token list> "}" +% \end{syntax} +% Locally or globally pushes <token list> as a single item onto the +% <stack>. <token list> might get expanded before the operation. +% \end{function} +% +% \begin{function}{% +% \clist_pop:NN | +% \clist_pop:cN | +% \clist_gpop:NN | +% \clist_gpop:cN | +% } +% \begin{syntax} +% "\clist_pop:NN" <stack> <tlp> +% \end{syntax} +% Functions that assign the top item of <stack> to the token +% list pointer <tlp> and removes it from <stack>! +% \end{function} +% +% \begin{function}{% +% \clist_top:NN | +% \clist_top:cN | +% } +% \begin{syntax} +% "\clist_top:NN" <stack> <tlp> +% \end{syntax} +% Functions that locally assign the top item of <stack> to the token +% list pointer <tlp>. Item is not removed from <stack>! +% \end{function} +% +% \StopEventually{} +% +% Use "clist" functions. +% +% +% \subsection {The Implementation} +% +% We start by ensuring that the required packages are loaded. +% \begin{macrocode} +%<*package> +\NeedsTeXFormat{LaTeX2e} +%<!check>\RequirePackage{l3prg,l3quark} +%<check>\RequirePackage{l3chk} +%</package> +%<*initex|package> +% \end{macrocode} +% +% +% \begin{macro}{\clist_new:N} +% \begin{macro}{\clist_new:c} +% Comma-Lists are implemented using token lists. +% \begin{macrocode} +\def_new:Npn \clist_new:N #1{\tlp_new:Nn #1{}} +\def_new:Npn \clist_new:c {\exp_args:Nc \clist_new:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_clear:N} +% \begin{macro}{\clist_clear:c} +% \begin{macro}{\clist_gclear:N} +% \begin{macro}{\clist_gclear:c} +% Clearing a comma-list is the same as clearing a token list. +% \begin{macrocode} +\let_new:NN \clist_clear:N \tlp_clear:N +\let_new:NN \clist_clear:c \tlp_clear:c +\let_new:NN \clist_gclear:N \tlp_gclear:N +\let_new:NN \clist_gclear:c \tlp_gclear:c +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\clist_set_eq:NN} +% We can set one \meta{clist} equal to another. +% \begin{macrocode} +\let_new:NN \clist_set_eq:NN \let:NN +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\clist_set_eq:NN} +% \begin{macro}{\clist_set_eq:cN} +% \begin{macro}{\clist_set_eq:Nc} +% \begin{macro}{\clist_set_eq:cc} +% An of course globally which seems to be needed far more often. +% \begin{macrocode} +\let_new:NN \clist_gset_eq:NN \glet:NN +\def_new:Npn \clist_gset_eq:cN {\exp_args:Nc \clist_gset_eq:NN} +\def_new:Npn \clist_gset_eq:Nc {\exp_args:NNc \clist_gset_eq:NN} +\def_new:Npn \clist_gset_eq:cc {\exp_args:Ncc \clist_gset_eq:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\clist_if_empty_p:N} +% A predicate which evaluates to |\c_true| iff the comma-list is empty. +% \begin{macrocode} +\let_new:NN \clist_if_empty_p:N \tlp_if_empty_p:N +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_if_empty:NTF} +% \begin{macro}{\clist_if_empty:NT} +% \begin{macro}{\clist_if_empty:NF} +% \begin{macro}{\clist_if_empty:cTF} +% \begin{macro}{\clist_if_empty:cT} +% \begin{macro}{\clist_if_empty:cF} +% |\clist_if_empty:NTF|\m{clist}\m{true~case}\m{false~case} will check +% whether the \m{clist} is empty and then select one of the other +% arguments. |\clist_if_empty:cTF| turns its first argument into a +% control comma-list to get the name of the comma-list. +% \begin{macrocode} +\def_test_function_new:npn {clist_if_empty:N}#1{\if_meaning:NN#1\c_empty_tlp} +\def_new:Npn \clist_if_empty:cTF {\exp_args:Nc\clist_if_empty:NTF} +\def_new:Npn \clist_if_empty:cT {\exp_args:Nc\clist_if_empty:NT} +\def_new:Npn \clist_if_empty:cF {\exp_args:Nc\clist_if_empty:NF} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\clist_if_empty_err:N} +% Signals an error if the comma-list is empty. +% \begin{macrocode} +\def_new:Npn \clist_if_empty_err:N #1{ + \if_meaning:NN#1\c_empty_tlp + \tlp_clear:N \l_testa_tlp % catch prefixes + \err_latex_bug:x{Empty~comma-list~`\token_to_string:N#1'} + \fi:} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_if_eq:NNTF} +% As comma lists are token list pointers internally this is just an +% alias. +% \begin{macrocode} +\let_new:NN \clist_if_eq:NNTF \tlp_if_eq:NNTF +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_get:NN} +% \begin{macro}{\clist_get:cN} +% |\clist_get:NN |\zz{comma-list}\zz{cmd} defines \zz{cmd} to be the +% left-most element of \zz{comma-list}. +% \begin{macrocode} +\def_new:Npn \clist_get:NN #1{ + \clist_if_empty_err:N #1 + \exp_after:NN\clist_get_aux:w #1,\q_stop} +% \end{macrocode} +% \begin{macrocode} +\def_new:Npn \clist_get_aux:w #1,#2\q_stop #3{\tlp_set:Nn #3{#1}} +% \end{macrocode} +% \begin{macrocode} +\def_new:Npn \clist_get:cN {\exp_args:Nc \clist_get:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_pop_aux:nnNN} +% \begin{macro}{\clist_pop_aux:w} +% \begin{macro}{\clist_pop_auxi:w} +% |\clist_pop_aux:nnNN| \zz{def$\sb1$} \zz{def$\sb2$} \zz{comma-list} +% \zz{cmd} assigns the left-most element of \zz{comma-list} to +% \zz{cmd} using \zz{def$\sb2$}, and assigns the tail of +% \zz{comma-list} to \zz{comma-list} using \zz{def$\sb1$}. +% \begin{macrocode} +\def_new:Npn \clist_pop_aux:nnNN #1#2#3{ + \clist_if_empty_err:N #3 + \exp_after:NN\clist_pop_aux:w #3,\q_nil\q_stop #1#2#3} +% \end{macrocode} +% \begin{macrocode} +\def_new:Npn \clist_pop_aux:w #1,#2\q_stop #3#4#5#6{ + #4#6{#1} + #3#5{#2} +% \end{macrocode} +% If there was only one element in the original clist, it now contains +% only |\q_nil|. +% \begin{macrocode} + \quark_if_nil:NTF #5 + { #3#5{} } + { \clist_pop_auxi:w #2 #3#5 } +} +% \end{macrocode} +% \begin{macrocode} +\def_new:Npn\clist_pop_auxi:w #1,\q_nil #2#3 {#2#3{#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_put_aux:NNnnNn} +% The generic put function. +% \begin{macrocode} +\def_new:Npn \clist_put_aux:NNnnNn #1#2#3#4#5#6{ +% \end{macrocode} +% When adding we have to distinguish between an empty \meta{clist} +% and one that contains at least one item (otherwise we accumulate +% commas). +% \begin{macrocode} + \clist_if_empty:NTF#5 {#1 #5{#6}} +% \end{macrocode} +% MH says: Perhaps we should make sure that empty arguments don't get +% on the stack as that is probably a mistake. That's what I've +% implemented here. Since |\tlist_if_empty:nF| is expandable prefixes +% are still allowed. +% \begin{macrocode} + { \tlist_if_empty:nF {#6}{ #2 #5{#3#6#4} } } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\clist_put_left:Nn} +% \begin{macro}{\clist_put_left:No} +% \begin{macro}{\clist_put_left:Nx} +% \begin{macro}{\clist_put_left:cn} +% The operations for adding to the left. +% \begin{macrocode} +\def_new:Npn \clist_put_left:Nn { + \clist_put_aux:NNnnNn \tlp_set:Nn \tlp_put_left:Nn {} , +} +\def_new:Npn \clist_put_left:cn {\exp_args:Nc \clist_put_left:Nn} +\def_new:Npn \clist_put_left:No {\exp_args:NNo\clist_put_left:Nn} +\def_new:Npn \clist_put_left:Nx {\exp_args:Nnx\clist_put_left:Nn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\clist_gput_left:Nn} +% Global versions. +% \begin{macrocode} +\def_new:Npn \clist_gput_left:Nn { + \clist_put_aux:NNnnNn \tlp_gset:Nn \tlp_gput_left:Nn {} , +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_put_right:Nn} +% \begin{macro}{\clist_put_right:cn} +% \begin{macro}{\clist_put_right:No} +% \begin{macro}{\clist_put_right:Nx} +% Adding something to the right side is almost the same. +% \begin{macrocode} +\def_new:Npn \clist_put_right:Nn { + \clist_put_aux:NNnnNn \tlp_set:Nn \tlp_put_right:Nn , {} +} +\def_new:Npn \clist_put_right:cn {\exp_args:Nc \clist_put_right:Nn} +\def_new:Npn \clist_put_right:No {\exp_args:Nno\clist_put_right:Nn} +\def_new:Npn \clist_put_right:Nx {\exp_args:Nnx\clist_put_right:Nn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_gput_right:Nn} +% \begin{macro}{\clist_gput_right:No} +% \begin{macro}{\clist_gput_right:cn} +% \begin{macro}{\clist_gput_right:co} +% \begin{macro}{\clist_gput_right:cc} +% \begin{macro}{\clist_gput_right:NC} +% An here the global variants. +% \begin{macrocode} +\def_new:Npn \clist_gput_right:Nn { + \clist_put_aux:NNnnNn \tlp_set:Nn \tlp_put_right:Nn , {} +} +\def_new:Npn \clist_gput_right:No {\exp_args:NNo \clist_gput_right:Nn} +\def_new:Npn \clist_gput_right:cn {\exp_args:Nc \clist_gput_right:Nn} +\def_new:Npn \clist_gput_right:co {\exp_args:Nco \clist_gput_right:Nn} +\def_new:Npn \clist_gput_right:cc {\exp_args:Ncc \clist_gput_right:Nn} +% \end{macrocode} +% \begin{macrocode} +\def_new:Npn \clist_gput_right:NC {\exp_args:NNC \clist_gput_right:Nn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_map_function:nN} +% \begin{macro}{\clist_map_function:cN} +% \begin{macro}{\clist_map_function:NN} +% |\clist_map_function:NN| \zz{comma-list} \zz{cmd} applies \zz{cmd} to each +% element of \zz{comma-list}, from left to right. +% \begin{macrocode} +\def_new:Npn \clist_map_function:NN #1#2{ + \clist_if_empty:NF #1 + { + \exp_after:NN \clist_map_function_aux:Nw + \exp_after:NN #2 #1 , \q_nil , \q_stop + } +} +\def_new:Npn \clist_map_function:cN{\exp_args:Nc\clist_map_function:NN} +\def_new:Npn \clist_map_function:nN #1#2{ + \tlist_if_empty:nF {#1} + { \clist_map_function_aux:Nw #2 #1 , \q_nil , \q_stop } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_map_function_aux:Nw} +% The general loop. Tests if we hit the first stop marker and exits if +% we did. If we didn't, place the function "#1" in front of the +% element "#2", which is surrounded by braces. +% \begin{macrocode} +\def_new:Npn \clist_map_function_aux:Nw #1#2,{ + \quark_if_nil:nT{#2} \clist_map_break:w + #1{#2} + \clist_map_function_aux:Nw #1 +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_map_break:w} +% The break statement is easy: Just gobble everything op to the last +% of the two stop markers "\q_stop" waiting at the end and close the +% "\if_..." we're in. Technically this should get an "w" specifier, +% but it doesn't take any arguments when you call it -- at least not +% any you would expect. +% \begin{macrocode} +\let_new:NN \clist_map_break:w \use_none_delimit_by_q_stop:w +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_map_inline:Nn} +% \begin{macro}{\clist_map_inline:cn} +% \begin{macro}{\clist_map_inline:nn} +% The inline type is faster but not expandable. In order to make it +% nestable, we use a counter to keep track of the nesting level so +% that all of the functions called have distict names. A simpler +% approach would of course be to use grouping and thus the save +% stack but then you lose the ability to do things locally. +% \begin{macrocode} +\int_new:N \l_clist_inline_level_int +\def_new:Npn \clist_map_inline:Nn #1#2{ + \clist_if_empty:NF #1 + { + \int_incr:N \l_clist_inline_level_int + \def:cpn {clist_map_inline_ \int_use:N \l_clist_inline_level_int :n} + ##1{#2} +% \end{macrocode} +% Recall that the |E| in |\exp_args:NcE| means `single token expanded +% once and no braces added'. It is a lot more efficient to carry over +% the special function rather than constructing the same csname over +% and over again, so we just do it once. We reuse +% |\clist_map_function_aux:Nw| for the actual loop. +% \begin{macrocode} + \exp_args:NcE \clist_map_function_aux:Nw + {clist_map_inline_ \int_use:N \l_clist_inline_level_int :n} + #1 , \q_nil , \q_stop + \int_decr:N \l_clist_inline_level_int + } +} +\def_new:Npn \clist_map_inline:cn{\exp_args:Nc\clist_map_inline:Nn} +\def_new:Npn \clist_map_inline:nn #1#2{ + \tlist_if_empty:nF {#1} + { + \int_incr:N \l_clist_inline_level_int + \def:cpn {clist_map_inline_ \int_use:N \l_clist_inline_level_int :n} + ##1{#2} + \exp_args:Nc \clist_map_function_aux:Nw + {clist_map_inline_ \int_use:N \l_clist_inline_level_int :n} + #1 , \q_nil , \q_stop + \int_decr:N \l_clist_inline_level_int + } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\clist_map_variable:nNn} +% \begin{macro}{\clist_map_variable:NNn} +% \begin{macro}{\clist_map_variable:cNn} +% |\clist_map:NNn| \zz{comma-list} \zz{temp} \zz{action} assigns +% \zz{temp} to each element and executes \zz{action}. +% \begin{macrocode} +\def_new:Npn \clist_map_variable:nNn #1#2#3{ + \tlist_if_empty:nF{#1} + { + \clist_map_variable_aux:Nnw #2 {#3} #1 , \q_nil , \q_stop + } +} +\def_new:Npn \clist_map_variable:NNn {\exp_args:No \clist_map_variable:nNn} +\def_new:Npn \clist_map_variable:cNn {\exp_args:Nc \clist_map_variable:NNn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_map_variable_aux:Nnw} +% The general loop. Assign the temp variable |#1| to the current item +% |#3| and then check if that's the stop marker. If it is, break the +% loop. If not, execute the action |#2| and continue. +% \begin{macrocode} +\def_new:Npn \clist_map_variable_aux:Nnw #1#2#3,{ + \def:Npn #1{#3} + \quark_if_nil:NT #1 \clist_map_break:w + #2 \clist_map_variable_aux:Nnw #1{#2} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_concat_aux:NNNN} +% \begin{macro}{\clist_concat:NNN} +% \begin{macro}{\clist_gconcat:NNN} +% \begin{macro}{\clist_gconcat:NNc} +% \begin{macro}{\clist_gconcat:ccc} +% |\clist_gconcat:NNN| \m{clist~1} \m{clist~2} \m{clist~3} will globally +% assign \m{clist~1} the concatenation of \m{clist~2} and +% \m{clist~3}. +% \begin{macrocode} +\def_new:Npn \clist_concat_aux:NNNN #1#2#3#4{ + \toks_set:No \l_tmpa_toks {#3} + \toks_set:No \l_tmpb_toks {#4} + #1 #2 { + \toks_use:N \l_tmpa_toks +% \end{macrocode} +% Again the situation is a bit more complicated because of the use +% of commas between items, so if either list is empty we have to avoid +% adding a comma. +% \begin{macrocode} + \toks_if_empty:NF \l_tmpa_toks {\toks_if_empty:NF \l_tmpb_toks ,} + \toks_use:N \l_tmpb_toks + } +} +\def_new:Npn \clist_concat:NNN {\clist_concat_aux:NNNN \tlp_set:Nx} +\def_new:Npn \clist_gconcat:NNN {\clist_concat_aux:NNNN \tlp_gset:Nx} +% \end{macrocode} +% And the usual versions. +% \begin{macrocode} +\def_new:Npn \clist_gconcat:NNc{\exp_args:Nnnc\clist_gconcat:NNN} +\def_new:Npn \clist_gconcat:ccc{\exp_args:Nccc\clist_gconcat:NNN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\clist_remove_duplicates_aux:NN} +% \begin{macro}{\clist_remove_duplicates_aux:n} +% \begin{macro}{\clist_remove_duplicates:N} +% \begin{macro}{\clist_gremove_duplicates:N} +% Removing duplicate entries in a \meta{clist} is fairly straight +% forward. We use a temporary variable and then go through the list +% from left to right. For each element check if the element is +% already present in the list. +% \begin{macrocode} +\def:Npn \clist_remove_duplicates_aux:NN #1#2 { + \clist_clear:N \l_clist_remove_duplicates_clist + \clist_map_function:NN #2 \clist_remove_duplicates_aux:n + #1 #2 \l_clist_remove_duplicates_clist +} +\def:Npn \clist_remove_duplicates_aux:n #1 { + \clist_if_in:NnTF \l_clist_remove_duplicates_clist {#1} {} + {\clist_put_right:Nn \l_clist_remove_duplicates_clist {#1}} +} +% \end{macrocode} +% The high level functions are just for telling if it should be a +% local or global setting. +% \begin{macrocode} +\def_new:Npn \clist_remove_duplicates:N { + \clist_remove_duplicates_aux:NN \clist_set_eq:NN +} +\def_new:Npn \clist_gremove_duplicates:N { + \clist_remove_duplicates_aux:NN \clist_gset_eq:NN +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\l_clist_remove_duplicates_clist} +% \begin{macrocode} +\clist_new:N \l_clist_remove_duplicates_clist +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_use:N} +% \begin{macro}{\clist_use:c} +% Using a \meta{clist} is just executing it but\dots +% \begin{macrocode} +\def_new:Npn \clist_use:N #1 { + \if_meaning:NN #1 \scan_stop: +% \end{macrocode} +% \dots\ if \m{clist} equals |\scan_stop:| it is probably stemming +% from a |\cs:w ... \cd_end:| that was created by mistake somewhere. +% \begin{macrocode} + \err_latex_bug:x {Comma~list~ `\token_to_string:N #1'~ + has~ an~ erroneous~ structure!} + \else: + \exp_after:NN #1 + \fi: +} +\def_new:Npn \clist_use:c {\exp_args:Nc \clist_use:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_if_in:NnTF} +% \begin{macro}{\clist_if_in:NoTF} +% \begin{macro}{\clist_if_in:cnTF} +% \begin{macro}{\clist_if_in:coTF} +% |\clist_if_in:NnTF| \m{clist}\m{item} \m{true~case} \m{false~case} +% will check whether \m{item} is in \m{clist} and then either execute +% the \m{true~case} or the \m{false~case}. \m{true~case} and +% \m{false~case} may contain incomplete |\if_charcode:w| +% statements. +% \begin{macrocode} +\def_new:Npn \clist_if_in:NnTF #1#2{ + \def:Npn \tmp:w ##1 ,#2, ##2##3\q_stop{ + \if_meaning:NN\q_no_value##2 + \exp_after:NN\use_arg_ii:nn + \else: + \exp_after:NN\use_arg_i:nn + \fi: + } + \exp_after:NN \tmp:w + \exp_after:NN , #1, #2, \q_no_value \q_stop +} +\def_new:Npn \clist_if_in:NoTF {\exp_args:NNo \clist_if_in:NnTF} +\def_new:Npn \clist_if_in:coTF {\exp_args:Nco \clist_if_in:NnTF} +\def_new:Npn \clist_if_in:cnTF {\exp_args:Nc \clist_if_in:NnTF} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \subsubsection{Stack operations} +% +% We build stacks from comma-lists, but here we put the +% specific functions together. +% +% +% \begin{macro}{\clist_push:Nn} +% \begin{macro}{\clist_push:No} +% \begin{macro}{\clist_push:cn} +% \begin{macro}{\clist_pop:NN} +% \begin{macro}{\clist_pop:cN} +% Since comma-lists can be used as stacks, we ought to have both +% `push' and `pop'. In most cases they are nothing more then new +% names for old functions. +% \begin{macrocode} +\let_new:NN \clist_push:Nn \clist_put_left:Nn +\let_new:NN \clist_push:No \clist_put_left:No +\let_new:NN \clist_push:cn \clist_put_left:cn +\def_new:Npn \clist_pop:NN {\clist_pop_aux:nnNN \tlp_set:Nn \tlp_set:Nn} +\def_new:Npn \clist_pop:cN {\exp_args:Nc \clist_pop:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \begin{macro}{\clist_gpush:Nn} +% \begin{macro}{\clist_gpush:No} +% \begin{macro}{\clist_gpush:cn} +% \begin{macro}{\clist_gpop:NN} +% \begin{macro}{\clist_gpop:cN} +% I don't agree with Denys that one needs only local stacks, +% actually I believe that one will probably need the functions +% here more often. In case of |\clist_gpop:NN| the value is +% nevertheless returned locally. +% \begin{macrocode} +\let_new:NN \clist_gpush:Nn \clist_gput_left:Nn +\def_new:Npn \clist_gpush:No {\exp_args:NNo \clist_gpush:Nn} +\def_new:Npn \clist_gpush:cn {\exp_args:Nc \clist_gpush:Nn} +\def_new:Npn \clist_gpop:NN {\clist_pop_aux:nnNN \tlp_gset:Nn \tlp_set:Nn} +\def_new:Npn \clist_gpop:cN {\exp_args:Nc \clist_gpop:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\clist_top:NN} +% \begin{macro}{\clist_top:cN} +% Looking at the top element of the stack without removing it is +% done with this operation. +% \begin{macrocode} +\let_new:NN \clist_top:NN \clist_get:NN +\let_new:NN \clist_top:cN \clist_get:cN +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% Show token usage: +% \begin{macrocode} +%</initex|package> +%<*showmemory> +%\showMemUsage +%</showmemory> +% \end{macrocode} +% +% +% +% \endinput +% +% $Log$ +% Revision 1.16 2006/07/30 15:45:46 morten +% Made \clist_map_inline:Nn and variants nestable plus a little cleanup. +% +% Revision 1.15 2006/03/20 18:26:34 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.14 2006/01/04 01:32:09 morten +% Minor changes to code to reflect changes in l3tlp. +% +% Revision 1.13 2005/12/27 09:52:51 morten +% Minor changes plus changed RCS information retrieval +% +% Revision 1.12 2005/10/27 23:14:49 morten +% Improved loops. +% +% Revision 1.11 2005/04/12 16:45:22 morten +% Enabled put operations. Added function that removes duplicate entries (mostly for +% use after concatenating to clists) +% +% Revision 1.10 2005/04/12 13:22:13 morten +% Mostly cosmetic changes. \clist_gconcat:NNN reprogrammed using "proper" methods, \clist_put_right:Nn likewise. +% +% Revision 1.9 2005/03/22 23:26:54 morten +% Fix error message +% +% Revision 1.8 2005/03/16 22:36:43 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.7 2005/03/11 21:36:36 braams +% Fixed the use of RCS information; +% Fixed a few documentation typos; added \StopEventually +% Replaced \ifx by \if_meaning:NN, \c_if_empty_toks became \c_empty_toks +% but needs further work according to Morten +% diff --git a/Master/texmf-dist/source/latex/expl3/l3expan.dtx b/Master/texmf-dist/source/latex/expl3/l3expan.dtx index 7f634d74f77..8eaac134482 100644 --- a/Master/texmf-dist/source/latex/expl3/l3expan.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3expan.dtx @@ -1,15 +1,50 @@ % \iffalse -%% File: l3expan.dtx Copyright (C) 1990-1998 LaTeX3 project -% +%% File: l3expan.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} %<*dtx> - \ProvidesFile{l3expan.dtx} +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse %</dtx> -%<package>\NeedsTeXFormat{LaTeX2e} -%<package>\ProvidesPackage{l3expan} -%<driver> \ProvidesFile{l3expan.drv} -% \fi -% \ProvidesFile{l3expan.dtx} - [1998/04/20 v1.0e L3 Experimental Argument Expansion module] +%\fi +\GetIdInfo$Id: l3expan.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental Argument Expansion module} % % \iffalse %<*driver> @@ -22,7 +57,6 @@ % \fi % % -% \GetFileInfo{l3expan.dtx} % \title{The \textsf{l3expan} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ @@ -33,7 +67,7 @@ % % % \section{\LaTeX3 functions} -% +% % All \LaTeX3 functions contain a colon in their % name. Characters following the colon are used to denote the number and % the ``type'' of arguments that the function takes. An uppercase "N" is @@ -46,12 +80,12 @@ % is a function that takes two arguments, the first is a single token % (the sequence) and the second may consist of several tokens surrounded % by braces. -% +% % This concept of argument specification makes it easy to read the code % and should be followed when defining new functions. -% +% % \subsection{Expanding arguments of functions} -% +% % Within code it is often necessary to expand or partially expand % arguments before passing it on to some function. For example, if the % token list pointer "\l_tmpa_tlp" contains the current file @@ -73,7 +107,7 @@ % "\exp_after:NN" \\ % " {\l_tmpa_tlp}" % \end{quote} -% +% % The above example is probably the simplest case but is already shows % how the code changes to something difficult to understand. Therefore % \LaTeX3 provides the programmer with a general scheme that keeps the @@ -88,7 +122,7 @@ % \end{quote} % to achieve the desired effect. Here the "o" stands for expand this % (the second) argument once before passing it to the function. -% +% % The following letters can be used to denote special treatment of % arguments before passing it to the basic function: % \begin{description} @@ -96,18 +130,24 @@ % effectively only the first token in the list gets expanded. Since % the expansion might result in more than one token, the result is % surrounded for further processing with braces. -% +% % \item[x] Fully expanded token or token-list. Like "o" but the % argument is expanded using "\def:Npx" before it is passed on. This means -% that expansion takes place until only unexpandable tokens are left. -% +% that expansion takes place until only unexpandable tokens are left. +% +% \item[f] Almost the same as the |x| type except here the token list +% is expanded fully until the first unexpandable token is found and +% the rest is left unchanged. Note that if this function finds a +% space at the beginning of the argument it will gobble it and not +% expand the next argument. +% % \item[N,O,X] Like "n", "o", "x" but the argument must be a single % token without any braces around it. -% +% % \item[c] A character string or a token-list that ultimately expands % to characters. This string (after expansion) is used to construct a % command name that is eventually passed on. -% +% % \item[C] A character string or a token-list that ultimately expands % to characters. From this string (after expansion) a command name is % constructed and then this command name is expanded once (like "o"). @@ -118,24 +158,48 @@ % " {l_tmpa_tlp}" % \end{quote} % Has the same effect as the example above. -% -% -% +% +% % \end{description} % +% Here are three new expansion types that may be useful but I'm not +% sure yet. Only time will tell\dots{} Proper documentation of these +% functions is postponed until later. +% \begin{description} +% \item[d] This is pretty much like the |o| type except the token list +% get's expanded twice before being passed on. (|d| is for double) +% +% \item[E] Sometimes you need to unpack a token list or something else +% but you don't want it to add the braces that the |o| type +% does. This is where you usually wind up with a lot of +% |\exp_after:NN|s and we would like to avoid that. This type works +% quite well with the other syntax but it won't work in certain +% circumstances: Since the generic expansion functions read their +% arguments when the expanded code is shuffled around, this type +% will have a problem if the last token you want to expand once is +% |\token_to_str:N| \emph{and} you're in an argument expansion +% process involving arguments in braces such as the |n| and |o| type +% arguments. If you stick to functions invloving only |N| and |E| +% everything will work just fine. (|E| is for expanded, single +% token.) +% +% \item[e] Same as above but the argument must be given in braces. +% \end{description} +% % Due to memory constraints not all possible variations are implemented % for every base function. Instead only those that are used within the -% \LaTeX3 kernel or otherwise seem of general interest are implemented. +% \LaTeX3 kernel or otherwise seem to be of general interest are +% implemented. % Consult the module description to find out which functions are % actually defined. The next section explains how to define missing % variants. -% +% % \subsection{Defining new variants} -% +% % The definition of variant forms for base functions may be necessary % when writing new functions or when applying a kernel function in a % situation that we haven't thought of before. -% +% % Internally preprocessing of arguments is done with functions from the % "\exp_" module. They all look alike, an example would be % "\exp_args:NNo". This function has three arguments, the first and the @@ -162,7 +226,37 @@ % new definition is identical to an already given one. Therefore adding % such definition to later releases of the kernel will not make such % style files obsolete. -% +% +% The |f| type is so special that it deserves an example. +% Let's pretend we want to set "\aaa" equal to the control sequence +% stemming from turning "b \l_tmpa_tlp b" into a control +% sequence. Furthermore we want to store the execution of it in a +% \m{toks} register. In this example we assume "\l_tmpa_tlp" contains +% the text string "lur". The straight forward approach is +% \begin{quote} +% "\toks_set:No \l_tmpa_toks {\let:Nc \aaa {b \l_tmpa_tlp b}}" +% \end{quote} +% Unfortunately this only puts +% "\exp_args:NNc \let:NN \aaa {b \l_tmpa_tlp b}" into "\l_tmpa_toks" +% and not "\let:NwN \aaa = \blurb" as we probably wanted. Using +% "\toks_set:Nx" is not an option as that will die horribly. Instead +% we can do a +% \begin{quote} +% "\toks_set:Nf \l_tmpa_toks {\let:Nc \aaa {b \l_tmpa_tlp b}}" +% \end{quote} +% which puts the desired result in "\l_tmpa_toks". It requires +% "\toks_set:Nf" to be defined as +% \begin{quote} +% "\def:Npn \toks_set:Nf {\exp_args:NNf \toks_set:Nn}" +% \end{quote} +% If you use this type of expansion in conditional processing then +% you should stick to using "TF" type functions only as it does not +% try to finish any "\if... \fi:" itself! +% +% +% +% +% % The available internal functions for argument expansion come in to % flavours, some of them are faster then others. Therefore it is usually % best to follow the following guidelines when defining new functions @@ -176,17 +270,17 @@ % \item % Arguments that need full expansion (i.e., are denoted with "x") % should be avoided if possible as they can not be processed very fast. -% \item -% In general "n", "x", and "o" (if not in the last position) will -% need special processing which is not fast and not expandable, i.e., -% functions of this type may not work correctly in arguments that are -% itself subject to "x" expansion. Therefore it is best to use the -% ``expandable'' functions (i.e., those that contain only "c", "N", "O" -% or "o" in the last position) whenever possible. +% \item +% In general "n", "x", and "o" (if not in the last position) will +% need special processing which is not fast and not expandable, +% i.e., functions of this type may not work correctly in arguments +% that are itself subject to "x" expansion. Therefore it is best to +% use the ``expandable'' functions (i.e., those that contain only +% "c", "N", "O", "o" or "f" in the last position) whenever possible. % \end{itemize} -% +% % \subsection{Manipulating the first argument} -% +% % \begin{function}{% % \exp_args:No % } @@ -197,7 +291,7 @@ % result is surrounded by braces and passed to <funct>. <funct> may have % more than one argument---all others are passed unchanged. % \end{function} -% +% % \begin{function}{% % \exp_args:Nc % } @@ -210,7 +304,7 @@ % sequence and passed to <funct> as the first argument. <funct> may have % more than one argument---all others are passed unchanged. % \end{function} -% +% % \begin{function}{% % \exp_args:NC % } @@ -224,7 +318,7 @@ % passed to <funct> as the first argument. <funct> may have more than % one argument---all others are passed unchanged. % \end{function} -% +% % \begin{function}{% % \exp_args:Nx % } @@ -237,62 +331,84 @@ % others are passed unchanged. % As mentioned before, this type of function is relatively slow. % \end{function} -% +% +% \begin{function}{% +% \exp_args:Nf +% } +% \begin{syntax} +% " \exp_args:Nf" <funct> <arg1> <arg2> "..." +% \end{syntax} +% The first argument of <funct> (i.e., <arg1>) undergoes full +% expansion until the first unexpandable token is encountered, the +% result is surrounded by braces and passed to <funct>. <funct> may +% have more than one argument---all others are passed unchanged. +% Beware of its special behavior as explained above. +% \end{function} +% +% % \subsection{Manipulating two arguments} -% +% % \begin{function}{% -% \exp_args:Nno | % \exp_args:NNx | % \exp_args:Nnx | -% \exp_args:Noo | +% \exp_args:Ncx | % \exp_args:Nox | % \exp_args:Nxo | % \exp_args:Nxx | % } % \begin{syntax} -% "\exp_args:Nno" <funct> <arg1> <arg2> "..." +% "\exp_args:Nnx" <funct> <arg1> <arg2> "..." % \end{syntax} % The above functions all manipulate the first two arguments of <funct>. % They are all slow and non-expandable. % \end{function} -% +% % \begin{function}{% % \exp_args:NNo | +% \exp_args:NNf | +% \exp_args:Nno | % \exp_args:NNc | +% \exp_args:Noo | % \exp_args:NOo | % \exp_args:NOc | % \exp_args:Nco | % \exp_args:Ncc | +% \exp_args:NNC | % } % \begin{syntax} % "\exp_args:NNo" <funct> <arg1> <arg2> "..." % \end{syntax} % These are the fast and expandable functions for the first two arguments. % \end{function} -% +% % \subsection{Manipulating three arguments} -% +% % So far not all possible functions are provided and even the selection % below may be reduced in the future as far as the non-expandable % functions are concerned. -% +% % \begin{function}{% -% \exp_args:Nnno | % \exp_args:Nnnx | % \exp_args:Noox | % \exp_args:Nnox | % \exp_args:Ncnx | % } % \begin{syntax} -% "\exp_args:Nnno" <funct> <arg1> <arg2> <arg3> "..." +% "\exp_args:Nnnx" <funct> <arg1> <arg2> <arg3> "..." % \end{syntax} % All the above functions are non-expandable. % \end{function} -% +% % \begin{function}{% +% \exp_args:NnnN | +% \exp_args:Nnno | % \exp_args:NNOo | % \exp_args:NOOo | % \exp_args:Nccc | +% \exp_args:NcNc | +% \exp_args:Nnnc | +% \exp_args:NcNo | +% \exp_args:Ncco | % } % \begin{syntax} % "\exp_args:NNOo" <funct> <arg1> <arg2> <arg3> "..." @@ -300,9 +416,9 @@ % These are the fast and expandable functions for the first three % arguments. % \end{function} -% +% % \subsection{Internal functions and variables} -% +% % \begin{function}{\exp_after:NN} % \begin{syntax} % "\exp_after:NN" <token1> <token2> @@ -315,41 +431,53 @@ % the naming conventions of \LaTeX3. % \end{texnote} % \end{function} -% +% % \begin{function}{\exp_not:N | -% \exp_not:c } +% \exp_not:c | +% \exp_not:n } % \begin{syntax} % "\exp_not:N" <token> +% "\exp_not:n" "{" <token list> "}" % \end{syntax} % This function will prohibit the expansion of <token> in situation % where <token> would otherwise be replaced by it definition, e.g., % inside an argument that is handled by the "x" convention. % \begin{texnote} -% "\exp_not:N" is the primitive \tn{noexpand} renamed. +% "\exp_not:N" is the primitive \tn{noexpand} renamed and "\exp_not:n" +% is the \eTeX{} primitive \tn{unexpanded}. % \end{texnote} % \end{function} -% -% +% +% % \begin{function}{\exp_not:o} % \begin{syntax} -% "\exp_not:o" <token> +% "\exp_not:o" "{"<token list>"}" % \end{syntax} +% Same as "\exp_not:n" except <token list> is expanded once and the +% result of this expansion is then prohibited from being expanded +% further. +% \end{function} % +% \begin{function}{\exp_not:E} +% \begin{syntax} +% "\exp_not:E" <token> +% \end{syntax} % The name of this command is a lie. Perhaps it should be called -% ``"exp_perhaps_once"''. What it actually does is, it expands <token> and -% then issues an "\exp_not:N" to prohibit further expansion of the -% first token in the replacement text of <token>. This means that if the -% replacement text of <token> consists of more than one token all -% further tokens are still subject to full expansion. The command is, for -% example, useful when generating a new cs name inside a "x" situation -% that shouldn't be expanded further, e.g., "\exp_not:o" "\cs:w" "foo" -% "\cs_end:". +% ``"exp_perhaps_once"''. What it actually does is, it expands <token> +% and then issues an "\exp_not:N" to prohibit further expansion of the +% first token in the replacement text of <token>. This means that if +% the replacement text of <token> consists of more than one token all +% further tokens are still subject to full expansion. % \begin{texnote} % This command has no equivalent. % \end{texnote} % \end{function} % -% \begin{variable}{\l_exp_tlp | \l_exp_toks} +% +% +% +% \begin{variable}{\l_exp_tlp | } +% \begin{syntax}\end{syntax} % The "\exp_" module has its private variables to temporarily store % results of the argument expansion. This is done to avoid interference % with other functions using temporary variables. @@ -357,23 +485,25 @@ % % \StopEventually{} % -% \section {Argument Expansion} +% \subsection {The Implementation} % % We start by ensuring that the required packages are loaded. % \begin{macrocode} -%<package>\RequirePackage{l3basics} %<package>\RequirePackage{l3tlp} -%<*package> +%<*initex|package> % \end{macrocode} -% -% \subsection{General expansion} +% +% \subsubsection{General expansion} % % In this section a general mechanism for defining functions to handle -% argument handling is defined. -% These general expansion functions are expandable unless |x| is used. -% (Any version of |x| is going to have to use -% one of the \LaTeX3\ names for |\def:Npx| at some point, and so is never -% going to be expandable.) +% argument handling is defined. These general expansion functions are +% expandable unless |x| is used. (Any version of |x| is going to have +% to use one of the \LaTeX3\ names for |\def:Npx| at some point, and +% so is never going to be expandable.\footnote{However, some +% primitives have certain characteristics that means that their +% arguments undergo an \texttt{x} type expansion but the primitive +% is in fact still expandable. We shall make it very clear when such +% a function is expandable.}) % % In a later section some common cases are coded by a more direct % method, typically using calls to |\exp_after:NN|. @@ -390,8 +520,9 @@ % \begin{macro}{\exp_arg_next:nnn} % This is basically the same function as |\Dexp_arg_next:nnn|. % \begin{macrocode} -\def_new:Npn\exp_arg_next:nnn#1#2#3{% - #2\:::{#3#1}} +\def_new:Npn\exp_arg_next:nnn#1#2#3{ + #2\:::{#3#1} +} % \end{macrocode} % \end{macro} % @@ -399,8 +530,9 @@ % This function is used to skip an argument that doesn't need to % be expanded. % \begin{macrocode} -\def_new:Npn\::n#1\:::#2#3{% - #1\:::{#2{#3}}} +\def_new:Npn\::n#1\:::#2#3{ + #1\:::{#2{#3}} +} % \end{macrocode} % \end{macro} % @@ -409,8 +541,9 @@ % single token and doesn't need to be expanded. %^^A was \let_new:NN\::N\::n (changed to match \;N above. % \begin{macrocode} -\def_new:Npn\::N#1\:::#2#3{% - #1\:::{#2#3}} +\def_new:Npn\::N#1\:::#2#3{ + #1\:::{#2#3} +} % \end{macrocode} % \end{macro} % @@ -418,25 +551,52 @@ % This function is used to skip an argument that is turned into % as control sequence without expansion. % \begin{macrocode} -\def_new:Npn\::c#1\:::#2#3{% - \exp_after:NN\exp_arg_next:nnn\cs:w #3\cs_end:{#1}{#2}} +\def_new:Npn\::c#1\:::#2#3{ + \exp_after:NN\exp_arg_next:nnn\cs:w #3\cs_end:{#1}{#2} +} % \end{macrocode} % \end{macro} % % \begin{macro}{\::o} % This function is used to expand an argument once. % \begin{macrocode} -\def_new:Npn\::o#1\:::#2#3{% - \exp_after:NN\exp_arg_next:nnn\exp_after:NN{\exp_after:NN{#3}}{#1}{#2}} +\def_new:Npn\::o#1\:::#2#3{ + \exp_after:NN\exp_arg_next:nnn\exp_after:NN{\exp_after:NN{#3}}{#1}{#2} +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\::f} +% This function is used to expand a token list until the first +% unexpandable token is found. +% The underlying "\int_to_roman:w -`0" expands everything in its +% way to find something terminating the number and thereby expands the +% function in front of it. This scanning procedure is terminated once +% the expansion hits something non-expandable or a space; in case the +% scanner hits a number, this number also terminates the scanning and +% is left untouched. In the example shown earlier the scanning was +% stopped once \TeX{} had fully expanded +% "\let:Nc \aaa {b \l_tmpa_tlp b}" into "\let:NwN \aaa = \blurb" which +% then turned out to contain the non-expandable token "\let:NwN". +% Since the expansion of "\int_to_roman:w -`0" is \m{null}, we +% wind up with a fully expanded list, only \TeX{} has not tried to +% execute any of the non-expandable tokens. This is what +% differentiates this function from the "x" argument type. +% \begin{macrocode} +\def_new:Npn\::f#1\:::#2#3{ + \exp_after:NN\exp_arg_next:nnn + \exp_after:NN{\exp_after:NN{\int_to_roman:w -`0 #3}} + {#1}{#2} +} % \end{macrocode} % \end{macro} % % \begin{macro}{\::x} % This function is used to expand an argument fully. -% % \begin{macrocode} -\def_new:Npn\::x#1\:::#2#3{% - \tlp_set:Nx\l_exp_tlp{{{#3}}}% +\def_new:Npn\::x#1\:::#2#3{ + \tlp_set:Nx\l_exp_tlp{{{#3}}} \exp_after:NN\exp_arg_next:nnn\l_exp_tlp{#1}{#2}} % \end{macrocode} % \end{macro} @@ -452,7 +612,7 @@ % This function creates a control sequence out of |#3| and expands % that once before passing it on to |\exp_arg_next:nnn|. % \begin{macrocode} -\def_new:Npn\::C#1\:::#2#3{% +\def_new:Npn\::C#1\:::#2#3{ \exp_after:NN\exp_C_aux:nnn\cs:w #3\cs_end:{#1}{#2}} % \end{macrocode} % \end{macro} @@ -474,10 +634,64 @@ % \end{macrocode} % \end{macro} % +% Here are some that might not stay but let's see. +% \begin{macro}{\::E} +% This function is used to expand an argument once and return it +% \emph{without} braces. Use this only when you feel pretty +% comfortable about your input! Actually this is pretty much just +% generic wrapper for |\exp_after:NN|. +% \begin{macrocode} +\def:Npn\::E#1\:::#2#3{ + \exp_after:NN\exp_arg_next:nnn \exp_after:NN{#3}{#1}{#2} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\::e} +% Same as |\::E| really but conceptually they are different. +% \begin{macrocode} +\def:Npn\::e#1\:::#2#3{ + \exp_after:NN\exp_arg_next:nnn \exp_after:NN{#3}{#1}{#2} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\::d} +% This function is used to expand an argument twice. Mostly useful +% for |toks| type things. +% \begin{macrocode} +\def:Npn\::d#1\:::#2#3{ + \exp_after:NN\exp_after:NN\exp_after:NN\exp_arg_next:nnn + \exp_after:NN\exp_after:NN\exp_after:NN{ + \exp_after:NN\exp_after:NN\exp_after:NN{#3}}{#1}{#2} +} +% \end{macrocode} +% \end{macro} +% +% We do most of them by hand here. This also means that we get a name +% for |\exp_after:NN| that fits with the rest of the code. +% \begin{macrocode} +\let:NN \exp_args:NE \exp_after:NN +\def:Npn \exp_args:NNE #1{\exp_args:NE#1\exp_args:NE} +\def:Npn \exp_args:NNNE #1#2{\exp_args:NE#1\exp_args:NE#2\exp_args:NE} +\def:Npn \exp_args:NEE #1{\exp_args:NE\exp_args:NE\exp_args:NE#1\exp_args:NE} +\def:Npn \exp_args:NcE #1#2{\exp_after:NN #1\cs:w #2\exp_after:NN\cs_end:} +\def:Npn \exp_args:Nd {\::d\:::} +\def:Npn \exp_args:NNd {\::N\::d\:::} +% \end{macrocode} +% % \begin{macro}{\exp_args:NC} +% \begin{macro}{\exp_args:Ncx} +% \begin{macro}{\exp_args:Ncco} % \begin{macro}{\exp_args:Nccx} % \begin{macro}{\exp_args:Ncnx} +% \begin{macro}{\exp_args:NcNc} +% \begin{macro}{\exp_args:Nf} +% \begin{macro}{\exp_args:NNf} +% \begin{macro}{\exp_args:Nfo} +% \begin{macro}{\exp_args:Nnf} % \begin{macro}{\exp_args:NNno} +% \begin{macro}{\exp_args:NnnN} % \begin{macro}{\exp_args:Nnno} % \begin{macro}{\exp_args:Nnnx} % \begin{macro}{\exp_args:Nno} @@ -490,6 +704,8 @@ % \begin{macro}{\exp_args:Nx} % \begin{macro}{\exp_args:Nxx} % \begin{macro}{\exp_args:Nxx} +% \begin{macro}{\exp_args:NNC} +% \begin{macro}{\exp_args:Nnnc} % Here are the actual function definitions, using the helper functions % above. % \begin{macrocode} @@ -497,12 +713,23 @@ %\def:Npn \exp_args:Nc {\::c\:::} %\def:Npn \exp_args:Ncc {\::c\::c\:::} %\def:Npn \exp_args:Nccc {\::c\::c\::c\:::} +\def:Npn \exp_args:Ncx {\::c\::x\:::} +\def:Npn \exp_args:Ncco {\::c\::c\::o\:::} \def:Npn \exp_args:Nccx {\::c\::c\::x\:::} \def:Npn \exp_args:Ncnx {\::c\::n\::x\:::} +\def:Npn \exp_args:NcNc {\::c\::N\::c\:::} +\def:Npn \exp_args:NcNo {\::c\::N\::o\:::} +\def:Npn \exp_args:Ncco {\::c\::c\::o\:::} %\def:Npn \exp_args:Nco {\::c\::o\:::} %\def:Npn \exp_args:NNc {\::N\::c\:::} +\def:Npn \exp_args:Nf {\::f\:::} +\def:Npn \exp_args:NNf {\::N\::f\:::} +\def:Npn \exp_args:Nfo{\::f\::o\:::} +\def:Npn \exp_args:Nnf {\::n\::f\:::} %\def:Npn \exp_args:NNNo {\::N\::N\::o\:::} \def:Npn \exp_args:NNno {\::N\::n\::o\:::} +%% Strange one this next one... +\def:Npn \exp_args:NnnN {\::n\::n\::N\:::} \def:Npn \exp_args:Nnno {\::n\::n\::o\:::} \def:Npn \exp_args:Nnnx {\::n\::n\::x\:::} %\def:Npn \exp_args:NNo {\::N\::o\::\:::} @@ -521,6 +748,8 @@ \def:Npn \exp_args:Nx {\::x\:::} \def:Npn \exp_args:Nxo {\::x\::o\:::} \def:Npn \exp_args:Nxx {\::x\::x\:::} +\def:Npn \exp_args:NNC {\::N\::C\:::} +\def:Npn \exp_args:Nnnc {\::n\::n\::c\:::} % \end{macrocode} % \end{macro} % \end{macro} @@ -538,25 +767,39 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % -% \subsection{Preventing expansion} +% \subsubsection{Preventing expansion} % -% \begin{macro}{\exp_not:N} -% This is the \TeX\ primitive that was defined earlier. -% \end{macro} % % \begin{macro}{\exp_not:o} +% \begin{macrocode} +\def_new:Npn\exp_not:o#1{\exp_not:n\exp_after:NN{#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\exp_not:E} % \begin{macro}{\exp_not:c} % Two helper functions, which we can probably live without it. % \begin{macrocode} -\def_new:Npn\exp_not:o{\exp_after:NN\exp_not:N} +\def_new:Npn\exp_not:E{\exp_after:NN\exp_not:N} \def_new:Npn\exp_not:c#1{\exp_after:NN\exp_not:N\cs:w#1\cs_end:} % \end{macrocode} % \end{macro} % \end{macro} % -% \subsection{Single token expansion} +% +% \subsubsection{Single token expansion} % % Expansion for arguments that are single tokens is done with the % functions below. I first thought of using a different module name @@ -575,6 +818,7 @@ % \begin{macro}{\exp_args:No} % \begin{macro}{\exp_args:NOo} % \begin{macro}{\exp_args:NNo} +% \begin{macro}{\exp_args:NNO} % \begin{macro}{\exp_args:NOOo} % \begin{macro}{\exp_args:NNOo} % \begin{macro}{\exp_args:NNNo} @@ -589,6 +833,8 @@ \exp_after:NN#1\exp_after:NN#2\exp_after:NN#3\exp_after:NN{#4}} \def_new:Npn \exp_args:NNo #1#2#3{\exp_after:NN#1\exp_after:NN#2 \exp_after:NN{#3}} +\def_new:Npn \exp_args:NNO #1#2#3 {\exp_after:NN#1 + \exp_after:NN#2 #3} \def_new:Npn \exp_args:NNOo #1#2#3#4{\exp_after:NN\exp_args:NNo \exp_after:NN#1\exp_after:NN#2\exp_after:NN#3\exp_after:NN{#4}} \def_new:Npn \exp_args:NNNo #1#2#3#4{\exp_after:NN#1\exp_after:NN#2 @@ -600,6 +846,7 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} % % % \begin{macro}{\exp_args:Nc} @@ -640,35 +887,35 @@ % % % \begin{macro}{\exp_def_form:nnn} -% This command is a recent addition which was actually added +% This command is a recent addition which was actually added % when we wrote the article for TUGboat (while most of the other % code goes way back to 1993). % \begin{macrocode} \def:Npn\exp_def_form:nnn#1#2#3{ \exp_after:NN \def:Npn - \cs:w - #1:#3 + \cs:w + #1:#3 \exp_after:NN \cs_end: \exp_after:NN { - \cs:w - exp_args:N#3 + \cs:w + exp_args:N#3 \exp_after:NN \cs_end: - \cs:w + \cs:w #1:#2 \cs_end: } % \end{macrocode} -% We also have to test if |exp_arg:N#3| is already defined +% We also have to test if |exp_args:N#3| is already defined % and if not define it via the % |\::| commands using the chars in |#3| % \begin{macrocode} - \cs_free:cT + \cs_if_free:cT {exp_args:N#3} - {\def:cpx {exp_args:N#3} + {\def:cpx {exp_args:N#3} {\exp_args_form_x:w #3 :} } } @@ -677,29 +924,80 @@ % % % \begin{macro}{\exp_args_form_x:w} -% This command graps char by char outputting |\::#1| (not expanded +% This command grabs char by char outputting |\::#1| (not expanded % further) until we see a |:|. That colon is in fact also turned into % |\:::| so that the required structure for |\exp_args...| commands % is correctly terminated. % \begin{macrocode} \def_new:Npn\exp_args_form_x:w #1 { - \exp_after:NN \exp_not:N \cs:w ::#1 \cs_end: + \exp_not:c{::#1} \if_meaning:NN #1 : \else: \exp_after:NN\exp_args_form_x:w \fi:} % \end{macrocode} % \end{macro} - +% % Show token usage: % \begin{macrocode} -%</package> +%</initex|package> %<*showmemory> \showMemUsage %</showmemory> % \end{macrocode} % +% \endinput +% +% $Log$ +% Revision 1.29 2006/07/30 15:43:38 morten +% Minor touch-up plus added functions needed by clist module +% +% Revision 1.28 2006/06/03 18:56:31 morten +% A few more functions +% +% Revision 1.27 2006/03/20 18:26:35 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.26 2006/02/17 23:01:47 braams +% Imported \exp_args:NNO from l3messages +% +% Revision 1.25 2005/12/27 10:00:45 morten +% Changed RCS information retrieval +% +% Revision 1.24 2005/12/22 13:56:03 morten +% Fixed error in \exp_args:NNd +% +% Revision 1.23 2005/12/21 20:44:30 morten +% Corrected typo. +% +% Revision 1.22 2005/12/06 15:34:46 morten +% Made \exp_not:o do what you'd expect +% +% Revision 1.21 2005/11/23 07:37:29 morten +% A few new expansion types, we shall see if they will be useful. +% +% Revision 1.20 2005/04/12 16:44:06 morten +% Fix to make it run as a package +% +% Revision 1.19 2005/04/12 13:24:07 morten +% Minor updates +% +% Revision 1.18 2005/04/09 21:06:46 morten +% Added yet another function. +% +% Revision 1.17 2005/04/06 21:38:10 morten +% Added more functions. +% +% Revision 1.16 2005/03/26 21:09:44 morten +% Added f argument type for "force expansion" +% +% Revision 1.15 2005/03/22 23:24:40 morten +% Fixed documentation error. +% +% Revision 1.14 2005/03/16 22:36:37 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.13 2005/03/11 21:37:37 braams +% Fixed the use of RCS information % - - - diff --git a/Master/texmf-dist/source/latex/expl3/l3final.dtx b/Master/texmf-dist/source/latex/expl3/l3final.dtx new file mode 100644 index 00000000000..2eb42fb4a41 --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3final.dtx @@ -0,0 +1,129 @@ +% \iffalse +%% File: l3final.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +%<*!ini> +\GetIdInfo$Id: l3final.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental final module} +%</!ini> +% +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3final.dtx} +\end{document} +%</driver> +% \fi +% +% \section{Final Wrap-up} +% +% This module will contain all the last minute coding necessary to +% round off the format. +% +% \subsection{Cleaning up} +% +% Some of the macros needed in creating the format are no longer +% needed and will either be removed are modified to generate error +% messages. +%<*initex> +% +% \subsection{Closing the error file} +% +% Earlier on in the format a file was opened to collect all the +% error messages. This file needs to be closed before the format is +% dumped. +% \begin{macrocode} +\err_file_close:N\c_kernel_err_tlp +% \end{macrocode} +% +% \subsection{Dumping the format} +% +% The last action to take is to dump the format. +% \begin{macrocode} +\tex_dump:D +% \end{macrocode} +%</initex> +% \subsection{Creating the format} +% +% There is one more thing needed for creating the format; a file +% called \file{lbase.ini}. For now this is included here. +%<*ini> +% \begin{macrocode} +%% Derived from a file by Thomas Esser + +\ifx\pdfoutput\undefined \else + \ifx\pdfoutput\relax \else + % We're building the latex format with the pdfetex engine (started 2004). + % See this file for details. + \input pdftex-dvi.tex + \fi +\fi + +%% the usual format initialization. +%%\scrollmode +\input lbase.ltx +\endinput +% \end{macrocode} +%</ini> +% \endinput +% +% $Log$ +% Revision 1.5 2006/03/19 15:03:22 braams +% Added code to close the kernel error file +% +% Revision 1.4 2006/01/13 23:20:07 braams +% Added lbase.ini to be generated from this file +% +% Revision 1.3 2005/12/27 16:01:48 morten +% Changed RCS information retrieval +% +% Revision 1.2 2005/04/12 22:48:24 braams +% Corrected a slight mistake +% +% Revision 1.1 2005/04/12 22:41:38 braams +% This file will contain al the last minute things needed in the format. +% For starters it just dumps the format. +% diff --git a/Master/texmf-dist/source/latex/expl3/l3format.ins b/Master/texmf-dist/source/latex/expl3/l3format.ins new file mode 100644 index 00000000000..cc3d0d984b8 --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3format.ins @@ -0,0 +1,72 @@ + +\input docstrip.tex +\askforoverwritefalse + +\preamble + + +EXPERIMENTAL CODE + +Do not distribute this file without also distributing the +source files specified above. + +Do not distribute a modified version of this file. + + +\endpreamble +% stop docstrip adding \endinput +\postamble +\endpostamble + +\keepsilent + +% generate the format file +\generate{% + \file{lbase.ltx}{% + \from{l3names.dtx}{initex} % The naming conventions + \from{l3basics.dtx}{initex} % Initialisations + \from{l3chk.dtx}{initex} % Checking functions + \from{l3tlp.dtx}{initex} % token list pointers + \from{l3expan.dtx}{initex} % Controlling expansion of arguments + \from{l3quark.dtx}{initex} % quarks + \from{l3num.dtx}{initex} % Storing integers in macros + \from{l3seq.dtx}{initex} % Sequences and Stacks + \from{l3alloc.dtx}{initex} % Register allocations + \from{l3io.dtx}{initex} % dealing with I/O + \from{l3int.dtx}{initex} % dealing with integer registers + \from{l3clist.dtx}{initex} % Comma separated lists + \from{l3prop.dtx}{initex} % property lists + \from{l3token.dtx}{initex} % token investigation +% + \from{l3vers.dtx}{initex} % Version information +% + \from{l3skip.dtx}{initex} % dealing with skip registers + \from{l3toks.dtx}{initex} % dealing with token registers + \from{l3messages.dtx}{initex} % seting up for user communication + \from{l3box.dtx}{initex} % dealing with box registers + \from{l3precom.dtx}{initex,precompile} % + \from{l3prg.dtx}{initex} % Program control structures + \from{l3xref.dtx}{initex} % Cross references +% + \from{l3final.dtx}{initex} % Final wrap-up + } +} +% generate the format initialisation file +\generate{% + \file{lbase.ini}{% + \from{l3final.dtx}{ini} + } +} + +\Msg{} +\Msg{*************************************} +\Msg{*} +\Msg{* Now run (PDF)EINITEX on *lbase.ini} +\Msg{*} +\Msg{* On an up to date system, run } +\Msg{* pdfetex -ini "*lbase.ini" } +\Msg{*} +\Msg{*************************************} +\Msg{} + +\endbatchfile diff --git a/Master/texmf-dist/source/latex/expl3/l3int.dtx b/Master/texmf-dist/source/latex/expl3/l3int.dtx index d219a9d27bb..f4e582ec12f 100644 --- a/Master/texmf-dist/source/latex/expl3/l3int.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3int.dtx @@ -1,15 +1,50 @@ % \iffalse -%% File: l3int.dtx Copyright (C) 1990-1998 LaTeX3 project -% +%% File: l3int.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} %<*dtx> - \ProvidesFile{l3int.dtx} +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse %</dtx> -%<package>\NeedsTeXFormat{LaTeX2e} -%<package>\ProvidesPackage{l3int} -%<driver> \ProvidesFile{l3int.drv} -% \fi -% \ProvidesFile{l3int.dtx} - [1998/04/20 v1.0c L3 Experimental Integer module] +%\fi +\GetIdInfo$Id: l3int.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental Integer module} % % \iffalse %<*driver> @@ -22,7 +57,6 @@ % \fi % % -% \GetFileInfo{l3int.dtx} % \title{The \textsf{l3int} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ @@ -31,40 +65,32 @@ % \date{\filedate} % \maketitle % -% \section{Counters} +% \section{Integers} % % \LaTeX3 maintains two type of integer registers for internal use. -% One (associated with the name "int") uses the builtin counter -% registers of \TeX{} and is therefore relatively fast and one -% (associated with the name "fint" for fake counter) that implements the -% operations within the \TeX{} macro language and is therefore much -% slower in processing. This type of counter is also far more restricted -% in its range. -% -% The fake counter should be used for variables that are not accessed -% very often since this saves the important fast internal registers -% (\TeX{} has only 255 of those). For example, all allocation routines -% in \LaTeX3 make use of fake counters to remember the values of recent -% allocated register numbers etc. -% -% Since all functions for both types are very similar (they usually -% differ only in the initial "f") we describe them together. But -% remember that you need to use "fint" variables when using "fint" -% functions. +% One (associated with the name "num") for low level uses in the +% allocation mechanism using macros only and "int": the one described +% here. +% +% The "int" type uses the built-in counter registers of \TeX{} and is +% therefore relatively fast compared to the "num" type and should be +% preferred in all cases as there is little chance we should ever run +% out of registers when being based on at least \eTeX. % % \subsection{Functions} % % \begin{function}{% % \int_new:N | % \int_new:c | -% \fint_new:N | +% \int_new_l:N | % } % \begin{syntax} % "\int_new:N" <int> -% "\fint_new:N" <fint> % \end{syntax} -% Defines <int> to be a new variable of type "int". There is no way to -% define constant counters with these functions. +% Globally defines <int> to be a new variable of type "int" although +% you can still choose if it should be a an "\l_" or "\g_" type. +% There is no way to define constant counters with these functions. +% The function "\int_new_l:N" defines <int> locally only. % \begin{texnote} % "\int_new:N" is the equivalent to plain \TeX{}'s \tn{newcount}. % However, the internal register allocation is done differently. @@ -75,12 +101,9 @@ % \int_incr:N | % \int_gincr:N | % \int_gincr:c | -% \fint_incr:N | -% \fint_gincr:N | % } % \begin{syntax} % "\int_incr:N" <int> -% "\fint_incr:N" <fint> % \end{syntax} % Increments <int> by one. For global variables the global versions % should be used. @@ -90,12 +113,9 @@ % \int_decr:N | % \int_gdecr:N | % \int_gdecr:c | -% \fint_decr:N | -% \fint_gdecr:N | % } % \begin{syntax} % "\int_decr:N" <int> -% "\fint_decr:N" <fint> % \end{syntax} % Decrements <int> by one. For global variables the global versions % should be used. @@ -106,119 +126,101 @@ % \int_set:cn | % \int_gset:Nn | % \int_gset:cn | -% \fint_set:Nn | -% \fint_gset:Nn | % } % \begin{syntax} -% "\int_set:Nn" <int> "{" <integer> "}" -% "\fint_set:Nn" <fint> "{" <integer> "}" +% "\int_set:Nn" <int> "{" <integer expr> "}" % \end{syntax} -% These functions will set the <int> register to the <integer> value. +% These functions will set the <int> register to the <integer expr> +% value. This value can contain simple calc-like expressions as +% provided by \eTeX. % \end{function} % +% % \begin{function}{% -% \fint_set_eq:NN | -% \fint_gset_eq:NN | +% \int_zero:N | +% \int_zero:c | +% \int_gzero:N | +% \int_gzero:c | % } % \begin{syntax} -% "\fint_set_eq:NN" <fint1> <fint2> +% "\int_zero:N" <int> % \end{syntax} -% Fast form for -% \begin{syntax} -% "\fint_set:No" <fint1> "{\fint_use:N" <fint2> "}" -% \end{syntax} -% when <fint2> is known to be a variable of fake counter. Note that a -% corresponding function for real counters is not implemented since the -% "\int_set:Nn" function does this operation sufficiently when then second -% argument is a <int> instead of "{"<integer>"}" value. +% These functions sets the <int> register to zero either locally +% or globally. % \end{function} % +% % \begin{function}{% % \int_add:Nn | % \int_add:cn | % \int_gadd:Nn | -% \fint_add:Nn | -% \fint_gadd:Nn | % } % \begin{syntax} -% "\int_add:Nn" <int> "{" <integer> "}" -% "\fint_add:Nn" <fint> "{" <integer> "}" +% "\int_add:Nn" <int> "{" <integer expr> "}" % \end{syntax} -% These functions will add to the <int> register the value <integer>. If -% the second argument is a <int> register too, the surrounding braces -% can be left out. -% -% It not allowed to use a <fint> instead of the <integer>. If a fake -% counter should be used as the second argument one needs to turn the -% <fint> first into an <integer> by applying "\fint_use:N". +% These functions will add to the <int> register the value <integer +% expr>. If the second argument is a <int> register too, the +% surrounding braces can be left out. % \end{function} % % \begin{function}{% % \int_sub:Nn | % \int_gsub:Nn | -% \fint_sub:Nn | -% \fint_gsub:Nn | % } % \begin{syntax} -% "\int_gsub:Nn" <int> "{" <integer> "}" -% "\fint_gsub:Nn" <fint> "{" <integer> "}" +% "\int_gsub:Nn" <int> "{" <integer expr> "}" % \end{syntax} % These functions will subtract from the <int> register the value -% <integer>. If the second argument is a <int> register too, the +% <integer expr>. If the second argument is a <int> register too, the % surrounding braces can be left out. -% -% It is not allowed to use a <fint> instead of the <integer>. If a fake -% counter should be used as the second argument one needs to turn the -% <fint> first into an <integer> by applying "\fint_use:N". % \end{function} % % \begin{function}{% % \int_use:N | % \int_use:c | -% \fint_use:N | % } % \begin{syntax} % "\int_use:N" <int> -% "\fint_use:N" <fint> % \end{syntax} % This function returns the integer value kept in <int> in a way -% suitable for further processing. Be sure to use "\fint_use:N" if you -% are accessing the value of a fake counter because otherwise your -% result will be to some surprise to you (there is no check). +% suitable for further processing. % \begin{texnote} % The function "\int_use:N" could be implemented directly as the \TeX{} % primitive "\tex_the:D" which is also responsible to produce the values for % other internal quantities. We have chosen to use individual functions -% for counters, dimenions etc.\ to allow checks and to make the code -% more selfexplaining. +% for counters, dimensions etc.\ to allow checks and to make the code +% more self-explaining. % \end{texnote} % \end{function} % % \subsection{Formatting a counter value} % -% \begin{function}{\int_to_arabic:n | -% \int_to_alph:n | -% \int_to_Alph:n | -% \int_to_roman:n | -% \int_to_Roman:n | -% \int_to_symbol:n | +% \begin{function}{ +% \int_to_arabic:n | +% \int_to_alph:n | +% \int_to_Alph:n | +% \int_to_roman:n | +% \int_to_Roman:n | +% \int_to_symbol:n | % } % \begin{syntax} % "\int_to_alph:n" "{" <integer> "}" % "\int_to_alph:n" <int> -% "\int_to_alph:n" "{" "\fint_use:N" <fint> "}" % \end{syntax} % If some <integer> or the the current value of a <int> should be % displayed or typeset in a special ways (e.g., as uppercase roman -% numerals) these function can be used. We need braces if the argument -% is a simple <integer>, they can be omitted in case of a <int>. -% -% To format <fint>s with these functions it is necessary to turn the -% value of the <fint> first into an <integer> by applying "\fint_use:N" -% within the argument braces. +% numerals) these function can be used. We need braces if the +% argument is a simple <integer>, they can be omitted in case of a +% <int>. By default the letters produced by "\int_to_roman:n" and +% "\int_to_Roman:n" have catcode~11. % % All functions are fully expandable and will therefore produce the -% correct output when used inside of deferred writes, etc. +% correct output when used inside of deferred writes, etc. In case the +% number in an |alph| or |Alph| function is greater than the default +% base number (26) it follows a simple conversion rule so that 27 is +% turned into |aa|, 50 into |ax| and so on and so forth. These two +% functions can be modified quite easily to take a different base +% number and conversion rule so that other languages can be supported. % \begin{texnote} % These are more or less the internal \LaTeX2 functions \tn{@arabic}, % \tn{@alph}, \tn{Alph}, \tn{@roman}, \tn{@Roman}, and \tn{@fnsymbol} @@ -226,36 +228,65 @@ % \end{texnote} % \end{function} % -% \subsection{Variable and constants} +% \subsubsection{Internal functions} % -% \begin{variable}{% -% \c_int_max | -% \c_fint_max | +% \begin{function}{\int_to_roman:w} +% \begin{syntax} +% "\int_to_roman:w" <integer> <space> \textit{or} <non-expandable token> +% \end{syntax} +% Converts <integer> to it lowercase roman representation. Note that +% it produces a string of letters with catcode 12. +% \begin{texnote} +% This is the \TeX{} primitive \tn{romannumeral} renamed. +% \end{texnote} +% \end{function} +% \begin{function}{ +% \int_roman_lcuc_mapping:Nnn | +% \int_to_roman_lcuc:NN | % } -% Constant that denote the maximum value which can be stored in a <int> -% or <fint> register. -% \end{variable} +% \begin{syntax} +% "\int_roman_lcuc_mapping:Nnn" <roman_char> "{"<licr>"}" "{"<LICR>"}" +% "\int_to_roman_lcuc:NN" <roman_char> <char> +% \end{syntax} +% "\int_roman_lcuc_mapping:Nnn" specifies how the roman +% numeral <roman\_ char> (i, v, x, l, c, d, or m) should be +% interpreted when converting the number. <licr> is the lower case and +% <LICR> is the uppercase mapping. "\int_to_roman_lcuc:NN" is a +% recursive function converting the roman numerals. +% \end{function} +% +% +% \begin{function}{ +% \int_convert_number_with_rule:nnN | +% \int_alph_default_conversion_rule:n | +% \int_Alph_default_conversion_rule:n | +% \int_symbol_math_conversion_rule:n | +% \int_symbol_text_conversion_rule:n | +% } +% \begin{syntax} +% "\int_convert_number_with_rule:nnN" "{"<int1>"}" "{"<int2>"}" <function> +% "\int_alph_default_conversion_rule:n" "{"<int>"}" +% \end{syntax} +% "\int_convert_number_with_rule:nnN" converts <int1> into letters, +% symbols, whatever as defined by <function>. <int2> denotes the base +% number for the conversion. +% \end{function} +% +% +% +% +% +% +% \subsection{Variable and constants} % % \begin{variable}{% -% \c_minus_one | -% \c_zero | -% \c_one | -% \c_two | -% \c_three | -% \c_sixteen | -% \c_twohundred_fifty_five | -% \c_twohundredfiftysix | -% \c_thousand | -% \c_ten_thousand | -% \c_twenty_thousand | +% \c_max_int | % } -% Set of constants denoting useful values. -% \begin{texnote} -% Most of these constants have been available under \LaTeX2 under names -% like \tn{tw@}, \tn{thr@@} etc. -% \end{texnote} +% Constant that denote the maximum value which can be stored in an +% <int> register. % \end{variable} % +% % \begin{variable}{% % \l_tmpa_int | % \l_tmpb_int | @@ -268,16 +299,143 @@ % \end{variable} % % -% \section{Integer registers} +% \subsection{Testing and evaluating integer expressions} +% +% \begin{function}{% +% \int_eval:n | +% \int_div_truncate:nn | +% \int_div_round:nn | +% \int_mod:nn | +% } +% \begin{syntax} +% "\int_eval:n" "{"<int~expr>"}" \\ +% "\int_div_truncate:n" "{"<int~expr>"}" "{"<int~expr>"}" \\ +% "\int_mod:nn" "{"<int~expr>"}" "{"<int~expr>"}" +% \end{syntax} +% Evaluates the value of a integer expression so that +% "\int_eval:n {3*5/4}" puts "4" back into the input stream. Note that +% the results of divisions are rounded by the primitive operations. If +% you want the result of a division to be truncated use +% "\int_div_truncate:nn". "\int_div_round:nn" is added for +% completeness. "\int_mod:nn" returns the remainder of a division. All +% of these functions are expandable. +% \begin{texnote} +% "\int_eval:n" is the \eTeX primitive \tn{numexpr} turned into a function +% taking an argument. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \int_compare:nNnTF | +% \int_compare:nNnT | +% \int_compare:nNnF | +% } +% \begin{syntax} +% "\int_compare:nNnTF" "{"<int~expr>"}" <rel> "{"<int~expr>"}" +% "{"<true>"}" "{"<false>"}" +% \end{syntax} +% These functions test two integer expressions against each other. They +% are both evaluated by "\int_eval:n". Note that if both expressions +% are normal integer variables as in +% \begin{quote} +% "\int_compare:nNnTF \l_temp_int < \c_zero {negative}{non-negative}" +% \end{quote} +% you can safely omit the braces. +% \begin{texnote} +% This is the \TeX{} primitive \tn{ifnum} turned into a function. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \int_compare_p:nNn | +% } +% \begin{syntax} +% "\int_compare_p:nNn" "{"<int~expr>"}" <rel> "{"<int~expr>"}" +% \end{syntax} +% A predicate version of the above mentioned functions. +% \end{function} +% +% \begin{function}{% +% \int_if_odd:nTF | +% \int_if_odd_p:n | +% } +% \begin{syntax} +% "\int_if_odd:nTF" "{"<int~expr>"}" "{"<true>"}" "{"<false>"}" +% \end{syntax} +% These functions test if an integer expression is even or odd. We +% also define a predicate version of it. +% \begin{texnote} +% This is the \TeX{} primitive \tn{ifodd} turned into a function. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \int_whiledo:nNnT | +% \int_whiledo:nNnF | +% \int_dowhile:nNnT | +% \int_dowhile:nNnF | +% } +% \begin{syntax} +% "\int_whiledo:nNnT" <int expr> <rel> <int~expr> "{"<true>"}" +% \end{syntax} +% "\int_whiledo:nNnT" tests the integer expressions and if true performs +% the body "T" until the test fails. "\int_dowhile:nNnT" is similar +% but executes the body first and then performs the check, thus +% ensuring that the body is executed at least once. The "F" versions +% are similar but continue the loop as long as the test is false. They +% could be omitted as it is just a matter of switching the arguments +% in the test. +% \end{function} +% + +% \subsection{Conversion} +% +% \begin{function}{% +% \int_convert_from_base_ten:nn | +% } +% \begin{syntax} +% "\int_convert_from_base_ten:nn" "{"<number>"}""{"<base>"}" +% \end{syntax} +% Converts the base~10 number <number> into its equivalent +% representation written in base~<base>. Expandable. +% \end{function} +% +% +% \begin{function}{% +% \int_convert_to_base_ten:nn | +% } +% \begin{syntax} +% "\int_convert_to_base_ten:nn" "{"<number>"}""{"<base>"}" +% \end{syntax} +% Converts the base~<base> number <number> into its equivalent +% representation written in base~10. <number> can consist of digits +% and ascii letters. Expandable. +% \end{function} +% +% +% \StopEventually{} +% \subsection{The Implementation} +% % -% % We start by ensuring that the required packages are loaded. % \begin{macrocode} -%<package&!check>\RequirePackage{l3basics}\par -%<package&check>\RequirePackage{l3chk}\par -%<*package> +%<package&!check>\RequirePackage{l3num} +%<package&check>\RequirePackage{l3chk} +%<*initex|package> % \end{macrocode} % +% \begin{macro}{\int_to_roman:w} +% \begin{macro}{\int_to_number:w} +% \begin{macro}{\int_advance:w} +% A new name for the primitives. +% \begin{macrocode} +\let_new:NN \int_to_roman:w \tex_romannumeral:D +\let_new:NN \int_to_number:w \tex_number:D +\let_new:NN \int_advance:w \tex_advance:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} % Functions that support \LaTeX's user accessible counters should be % added here, too. But first the internal counters. % @@ -288,12 +446,12 @@ % Incrementing and decrementing of integer registers is done with % the following functions. % \begin{macrocode} -\def_new:Npn \int_incr:N #1{\tex_advance:D#1\c_one +\def_new:Npn \int_incr:N #1{\int_advance:w#1\c_one %<*check> \chk_local_or_pref_global:N #1 %</check> } -\def_new:Npn \int_decr:N #1{\tex_advance:D#1\c_minus_one +\def_new:Npn \int_decr:N #1{\int_advance:w#1\c_minus_one %<*check> \chk_local_or_pref_global:N #1 %</check> @@ -335,16 +493,22 @@ % % % \begin{macro}{\int_new:N} +% \begin{macro}{\int_new_l:N} % \begin{macro}{\int_new:c} % Allocation of a new internal counter is already done above. Here we define % the next likely variant. % \begin{macrocode} -\def_new:Npn \int_new:N {} % but since we don't distribute -\let:NN \int_new:N \newcount % allocation better nick the LaTeX one ... +%<*initex> +\alloc_setup_type:nnn {int} \c_eleven \c_max_register_num +\def_new:Npn \int_new:N #1 {\alloc_reg:NnNN g {int} \tex_countdef:D#1} +\def_new:Npn \int_new_l:N #1 {\alloc_reg:NnNN l {int} \tex_countdef:D#1} +%</initex> +%<package>\let:NN \int_new:N \newcount% allocation better nick the LaTeX one... \def_new:Npn \int_new:c {\exp_args:Nc \int_new:N} % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % % \begin{macro}{\int_set:Nn} @@ -354,7 +518,7 @@ % Setting counters is again something that I would like to make % uniform at the moment to get a better overview. % \begin{macrocode} -\def_new:Npn \int_set:Nn #1#2{#1#2\scan_stop: +\def_new:Npn \int_set:Nn #1#2{#1 \int_eval:w #2\scan_stop: %<*check> \chk_local_or_pref_global:N #1 %</check> @@ -373,6 +537,21 @@ % \end{macro} % \end{macro} % +% \begin{macro}{\int_zero:N} +% \begin{macro}{\int_zero:c} +% \begin{macro}{\int_gzero:N} +% \begin{macro}{\int_gzero:c} +% Functions that reset an \m{int} register to zero. +% \begin{macrocode} +\def_new:Npn \int_zero:N #1 {#1=\c_zero} +\def_new:Npn \int_zero:c #1 {\exp_args:Nc \int_zero:N} +\def_new:Npn \int_gzero:N #1 {\pref_global:D #1=\c_zero} +\def_new:Npn \int_gzero:c {\exp_args:Nc \int_gzero:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\int_add:Nn} % \begin{macro}{\int_add:cn} @@ -383,14 +562,19 @@ % We should think of using these functions % \begin{macrocode} \def_new:Npn \int_add:Nn #1#2{ - \tex_advance:D#1#2\scan_stop: +% \end{macrocode} +% We need to say |by| in case the first argument is a register +% accessed by its number, e.g., |\count23|. Not that it should +% ever happen but\dots +% \begin{macrocode} + \int_advance:w #1 by \int_eval:w #2\scan_stop: %<*check> \chk_local_or_pref_global:N #1 %</check> } \def_new:Npn\int_add:cn{\exp_args:Nc\int_add:Nn} \def_new:Npn \int_sub:Nn #1#2{ - \tex_advance:D#1-#2\scan_stop: + \int_advance:w #1-\int_eval:w #2\scan_stop: %<*check> \chk_local_or_pref_global:N #1 %</check> @@ -415,341 +599,649 @@ % \end{macro} % % -% \begin{macro}{\int_use:N} -% \begin{macro}{\int_use:c} +% \begin{macro}{\int_use:N} +% \begin{macro}{\int_use:c} % Here is how counters are accessed: % \begin{macrocode} \let_new:NN \int_use:N \tex_the:D \def_new:Npn \int_use:c #1{\int_use:N \cs:w#1\cs_end:} % \end{macrocode} -% \end{macro} -% \end{macro} - +% \end{macro} +% \end{macro} % -% \begin{macro}{\int_gincr:c} -% \begin{macro}{\int_gdecr:c} +% +% \begin{macro}{\int_gincr:c} +% \begin{macro}{\int_gdecr:c} % We also need \ldots % \begin{macrocode} \def_new:Npn \int_gincr:c {\exp_args:Nc \int_gincr:N} \def_new:Npn \int_gdecr:c {\exp_args:Nc \int_gdecr:N} % \end{macrocode} -% \end{macro} -% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\int_to_arabic:n} +% Nothing exciting here. +% \begin{macrocode} +\def_new:Npn \int_to_arabic:n #1{\int_to_number:w \int_eval:n{#1}} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\int_roman_lcuc_mapping:Nnn} +% Using \TeX's built-in feature for producing roman numerals has some +% surprising features. One is the the characters resulting from +% |\int_to_roman:w| have category code~12 so they may fail in +% certain comparison tests. Therefore we use a mapping from the +% character \TeX{} produces to the character we actually want which +% will give us letters with category code~11.% +% \begin{macrocode} +\def_new:Npn \int_roman_lcuc_mapping:Nnn #1#2#3{ + \def:cpn {int_to_lc_roman_#1:}{#2} + \def:cpn {int_to_uc_roman_#1:}{#3} +} +% \end{macrocode} +% \end{macro} +% Here are the default mappings. I haven't found any examples of say +% Turkish doing the mapping |i \i I| but at least there is a +% possibility for it if needed. Note: I have now asked a Turkish +% person and he tells me they do the |i I| mapping. +% \begin{macrocode} +\int_roman_lcuc_mapping:Nnn i i I +\int_roman_lcuc_mapping:Nnn v v V +\int_roman_lcuc_mapping:Nnn x x X +\int_roman_lcuc_mapping:Nnn l l L +\int_roman_lcuc_mapping:Nnn c c C +\int_roman_lcuc_mapping:Nnn d d D +\int_roman_lcuc_mapping:Nnn m m M +% \end{macrocode} +% For the delimiter we cheat and let it gobble its arguments instead. +% \begin{macrocode} +\int_roman_lcuc_mapping:Nnn Q \use_none:nn \use_none:nn +% \end{macrocode} +% +% \begin{macro}{\int_to_roman:n} +% \begin{macro}{\int_to_Roman:n} +% \begin{macro}{\int_to_roman_lcuc:NN} +% The commands for producing the lower and upper case roman numerals +% run a loop on one character at a time and also carries some +% information for upper or lower case with it. We put it through +% |\int_eval:n| first which is safer and more flexible. +% \begin{macrocode} +\def_new:Npn \int_to_roman:n #1 { + \exp_after:NN \int_to_roman_lcuc:NN \exp_after:NN l + \int_to_roman:w \int_eval:n {#1} Q +} +\def_new:Npn \int_to_Roman:n #1 { + \exp_after:NN \int_to_roman_lcuc:NN \exp_after:NN u + \int_to_roman:w \int_eval:n {#1} Q +} +\def_new:Npn \int_to_roman_lcuc:NN #1#2{ + \cs_use:c {int_to_#1c_roman_#2:} + \int_to_roman_lcuc:NN #1 +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \begin{macro}{\int_convert_number_with_rule:nnN} +% This is our major workhorse for conversions. |#1| is the number we +% want converted, |#2| is the base number, and |#3| is the function +% converting the number. This function expects to receive a +% non-negative integer and as such is ideal for something using +% |\if_case:w| internally. +% +% The basic example is this: We want to convert the number 50 (|#1|) +% into an alphabetic equivalent |ax|. For the English language our +% list contains 26 elements so this is our argument |#2| while the +% function |#3| just turns |1| into |a|, |2| into |b|, etc. Hence our +% goal is to turn 50 into the sequence |#3{1}#1{24}| so what we do is +% to first divide 50 by 26 and truncating the result returning 1. +% Then before we execute this we call the function again but this time +% on the result of the remainder of the division. This goes on until +% the remainder is less than or equal to the base number where we just +% call the function |#3| directly on the number. +% +% We do a little pre-expansion of the arguments below as they +% otherwise have a tendency to grow quite large. +% \begin{macrocode} +\def:Npn \int_convert_number_with_rule:nnN #1#2#3{ + \int_compare:nNnTF {#1}>{#2} + { + \exp_args:No \int_convert_number_with_rule:nnN + { \int_use:N\int_div_truncate:nn {#1-1}{#2} }{#2} + #3 +% \end{macrocode} +% Note that we have to nudge our modulus function so it won't +% return~$0$ as that wouldn't work with |\if_case:w| when that +% expects a positive number to produce a letter. +% \begin{macrocode} + \exp_args:No #3 { \int_use:N\int_eval:n{1+\int_mod:nn {#1-1}{#2}} } + } + { \exp_args:No #3{ \int_use:N\int_eval:n{#1} } } +} +% \end{macrocode} +% As can be seen it is even simpler to convert to number systems +% that contain 0, since then we don't have to add or subtract 1 +% here and there. +% \end{macro} +% +% \begin{macro}{\int_alph_default_conversion_rule:n} +% \begin{macro}{\int_Alph_default_conversion_rule:n} +% Now we just set up a default conversion rule. Ideally every language +% should have one such rule, as say in Danish there are 29 letters in +% the alphabet. +% \begin{macrocode} +\def_new:Npn \int_alph_default_conversion_rule:n #1{ + \if_case:w #1 + \or: a\or: b\or: c\or: d\or: e\or: f + \or: g\or: h\or: i\or: j\or: k\or: l + \or: m\or: n\or: o\or: p\or: q\or: r + \or: s\or: t\or: u\or: v\or: w\or: x + \or: y\or: z + \fi: +} +\def_new:Npn \int_Alph_default_conversion_rule:n #1{ + \if_case:w #1 + \or: A\or: B\or: C\or: D\or: E\or: F + \or: G\or: H\or: I\or: J\or: K\or: L + \or: M\or: N\or: O\or: P\or: Q\or: R + \or: S\or: T\or: U\or: V\or: W\or: X + \or: Y\or: Z + \fi: +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\int_to_alph:n} +% \begin{macro}{\int_to_Alph:n} +% The actual functions are just instances of the generic function. The +% second argument of |\int_convert_number_with_rule:nnN| should of +% course match the number of |\or:|s in the conversion rule. +% \begin{macrocode} +\def_new:Npn \int_to_alph:n #1{ + \int_convert_number_with_rule:nnN {#1}{26} + \int_alph_default_conversion_rule:n +} +\def_new:Npn \int_to_Alph:n #1{ + \int_convert_number_with_rule:nnN {#1}{26} + \int_Alph_default_conversion_rule:n +} +% \end{macrocode} +% \end{macro} +% \end{macro} % +% \begin{macro}{\int_to_symbol:n} +% Turning a number into a symbol is also easy enough. +% \begin{macrocode} +\def_new:Npn \int_to_symbol:n #1{ + \mode_math:TF + { + \int_convert_number_with_rule:nnN {#1}{9} + \int_symbol_math_conversion_rule:n + } + { + \int_convert_number_with_rule:nnN {#1}{9} + \int_symbol_text_conversion_rule:n + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\int_symbol_math_conversion_rule:n} +% \begin{macro}{\int_symbol_text_conversion_rule:n} +% Nothing spectacular here. +% \begin{macrocode} +\def_new:Npn \int_symbol_math_conversion_rule:n #1 { + \if_case:w #1 + \or: * + \or: \dagger + \or: \ddagger + \or: \mathsection + \or: \mathparagraph + \or: \| + \or: ** + \or: \dagger\dagger + \or: \ddagger\ddagger + \fi: +} +\def_new:Npn \int_symbol_text_conversion_rule:n #1 { + \if_case:w #1 + \or: \textasteriskcentered + \or: \textdagger + \or: \textdaggerdbl + \or: \textsection + \or: \textparagraph + \or: \textbardbl + \or: \textasteriskcentered\textasteriskcentered + \or: \textdagger\textdagger + \or: \textdaggerdbl\textdaggerdbl + \fi: +} +% \end{macrocode} +% \end{macro} +% \end{macro} % % \begin{macro}{\l_tmpa_int} % \begin{macro}{\l_tmpb_int} % \begin{macro}{\l_tmpc_int} % \begin{macro}{\g_tmpa_int} % \begin{macro}{\g_tmpb_int} -% We provide two local and two global scratch counters, maybe we -% need more or less. Instead of using the allocation routines we -% partly allocate them by hand. -% \begin{macrocode} -\chk_new_cs:N \l_tmpa_int -% \end{macrocode} -% If it turns out that we don't need local counters then this -% register should be used for global counter. We might also think of -% using the |\l_last_alloc_fint| as a scratch register. +% \begin{macro}{\l_loop_int} +% We provide four local and two global scratch counters, maybe we +% need more or less. % \begin{macrocode} -\tex_countdef:D\l_tmpa_int 255 +\int_new:N \l_tmpa_int \int_new:N \l_tmpb_int \int_new:N \l_tmpc_int \int_new:N \g_tmpa_int \int_new:N \g_tmpb_int +\int_new:N \l_loop_int % a variable for use in loops (whilenum etc) % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} +% \end{macro} +% % -% \begin{macro}{\c_minus_one} -% \begin{macro}{\c_zero} -% \begin{macro}{\c_one} -% \begin{macro}{\c_two} -% \begin{macro}{\c_three} -% \begin{macro}{\c_four} -% \begin{macro}{\c_sixteen} -% \begin{macro}{\c_thirty_two} -% \begin{macro}{\c_twohundred_fifty_five} -% \begin{macro}{\c_twohundred_fifty_six} -% \begin{macro}{\c_thousand} -% \begin{macro}{\c_ten_thousand} -% \begin{macro}{\c_ten_thousand_one} -% \begin{macro}{\c_ten_thousand_two} -% \begin{macro}{\c_ten_thousand_three} -% \begin{macro}{\c_ten_thousand_four} -% \begin{macro}{\c_twenty_thousand} -% \begin{macro}{\c_int_max} -% And the usual constants, others are still missing. Please, make -% every constant a real constant at least for the moment. We can -% easily convert things in the end when we have found what -% constants are used in critical places and what not. +% \begin{macro}{\int_eval:n} +% \begin{macro}{\int_eval:w} +% Evaluating a calc expression using normal operators. Many of these +% are exactly the same as the ones in the \textsf{num} module so we +% just use them. % \begin{macrocode} -\tex_chardef:D \c_zero = 0 \scan_stop: -\tex_chardef:D \c_one = 1 \scan_stop: -\tex_chardef:D \c_two = 2 \scan_stop: -\tex_chardef:D \c_three = 3 \scan_stop: -\tex_chardef:D \c_four = 4 \scan_stop: -\tex_chardef:D \c_sixteen = 16 \scan_stop: -\tex_chardef:D \c_thirty_two = 32 \scan_stop: -\tex_chardef:D \c_twohundred_fifty_five = 255 \scan_stop: -\tex_mathchardef:D \c_twohundred_fifty_six = 256 \scan_stop: -\tex_mathchardef:D \c_thousand = 1000 \scan_stop: -\tex_mathchardef:D \c_ten_thousand = 10000 \scan_stop: -\tex_mathchardef:D \c_ten_thousand_one = 10001 \scan_stop: -\tex_mathchardef:D \c_ten_thousand_two = 10002 \scan_stop: -\tex_mathchardef:D \c_ten_thousand_three = 10003 \scan_stop: -\tex_mathchardef:D \c_ten_thousand_four = 10004 \scan_stop: -\tex_mathchardef:D \c_twenty_thousand = 20000 \scan_stop: -% already defined ... -%\int_new:N \c_minus_one -% \c_minus_one = -1 +\let_new:NN \int_eval:n \num_eval:n +\let_new:NN \int_eval:w \num_eval:w % \end{macrocode} -% The |\c_int_max| will be defined internally as the largest -% dimen. +% \end{macro} +% \end{macro} +% +% \begin{macro}{\c_max_int} +% The largest number allowed is $2^{31}-1$ % \begin{macrocode} -%\int_new:N \c_int_max -% \c_int_max = 2147483647 +\const_new:Nn \c_max_int {2147483647} % \end{macrocode} % \end{macro} +% +% \begin{macro}{\int_pre_eval_one_arg:Nn} +% \begin{macro}{\int_pre_eval_two_args:Nnn} +% These might be handy when handing down values to other +% functions. All they do is evaluate the number in advance. +% \begin{macrocode} +\def:Npn \int_pre_eval_one_arg:Nnn #1#2{\exp_args:No#1{\int_eval:w#2}} +\def:Npn \int_pre_eval_two_args:Nnn #1#2#3{ + \exp_args:Noo#1{\int_use:N\int_eval:w#2}{\int_use:N\int_eval:w#3} +} +% \end{macrocode} % \end{macro} % \end{macro} +% +% \begin{macro}{\int_div_truncate:nn} +% \begin{macro}{\int_div_round:nn} +% \begin{macro}{\int_mod:nn} +% \begin{macro}{\int_div_truncate_raw:nn} +% \begin{macro}{\int_div_round_raw:nn} +% \begin{macro}{\int_mod_raw:nn} +% As "\num_eval:w" rounds the result of a division we also +% provide a version that truncates the result. +% \begin{macrocode} +\def_new:Npn \int_div_truncate:nn { + \int_pre_eval_two_args:Nnn\int_div_truncate_raw:nn +} +\def_new:Npn \int_div_truncate_raw:nn #1#2 { + \int_eval:n{ (2*#1 - #2) / (2* #2) } +} +% \end{macrocode} +% For the sake of completeness: +% \begin{macrocode} +\def_new:Npn \int_div_round:nn { + \int_pre_eval_two_args:Nnn\int_div_round_raw:nn +} +\def_new:Npn \int_div_round_raw:nn #1#2 {\int_eval:n{#1/#2}} +% \end{macrocode} +% Finally there's the modulus operation. +% \begin{macrocode} +\def_new:Npn \int_mod:nn {\int_pre_eval_two_args:Nnn\int_mod_raw:nn} +\def_new:Npn \int_mod_raw:nn #1#2 { + \int_eval:n{ #1 - \int_div_truncate_raw:nn {#1}{#2} * #2 } +} +% \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} +% +% +% \begin{macro}{\int_compare:nNnTF} +% \begin{macro}{\int_compare:nNnT} +% \begin{macro}{\int_compare:nNnF} +% Simple comparison tests. +% \begin{macrocode} +\let_new:NN \int_compare:nNnTF \num_compare:nNnTF +\let_new:NN \int_compare:nNnT \num_compare:nNnT +\let_new:NN \int_compare:nNnF \num_compare:nNnF +% \end{macrocode} % \end{macro} % \end{macro} % \end{macro} +% +% \begin{macro}{\int_compare_p:nNn} +% A predicate function. +% \begin{macrocode} +\let_new:NN \int_compare_p:nNn \num_compare_p:nNn +% \end{macrocode} % \end{macro} +% +% \begin{macro}{\int_if_odd_p:n} +% \begin{macro}{\int_if_odd:nTF} +% \begin{macro}{\int_if_odd:nT} +% \begin{macro}{\int_if_odd:nF} +% A predicate function. +% \begin{macrocode} +\def_new:Npn \int_if_odd_p:n #1 { + \if_num_odd:w \int_eval:n{#1} + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {int_if_odd:n}#1{\if_num_odd:w \int_eval:n{#1}} +% \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} -% \end{macro} -% % -% Show token usage: +% \begin{macro}{\int_whiledo:nNnT} +% \begin{macro}{\int_whiledo:nNnF} +% \begin{macro}{\int_dowhile:nNnT} +% \begin{macro}{\int_dowhile:nNnF} +% These are quite easy given the above functions. The "while" versions +% test first and then execute the body. The "dowhile" does it the +% other way round. % \begin{macrocode} -%</package> -%<*showmemory> -\showMemUsage -%</showmemory> +\def_new:Npn \int_whiledo:nNnT #1#2#3#4{ + \int_compare:nNnT {#1}#2{#3}{#4 \int_whiledo:nNnT {#1}#2{#3}{#4}} +} +\def_new:Npn \int_whiledo:nNnF #1#2#3#4{ + \int_compare:nNnF {#1}#2{#3}{#4 \int_whiledo:nNnF {#1}#2{#3}{#4}} +} +\def_new:Npn \int_dowhile:nNnT #1#2#3#4{ + #4 \int_compare:nNnT {#1}#2{#3}{\int_dowhile:nNnT {#1}#2{#3}{#4}} +} +\def_new:Npn \int_dowhile:nNnF #1#2#3#4{ + #4 \int_compare:nNnF {#1}#2{#3}{\int_dowhile:nNnF {#1}#2{#3}{#4}} +} % \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % -% \section{Fake registers} -% -% Fake registers are registers which implement \m{counter}s, -% \m{dimen}s, etc.\ which aren't used often and therefore don't need -% to run efficiently. One possible way of using them is to prepare certain -% registers this way, but |\let:NN| the mutator functions to real -% \m{counter}s as long as we have a sufficient number available. Now -% if we are making real large formats (by adding Pic\TeX, for example) -% we can turn them easily into fake registers and everything will work -% as before (only a bit slower). -% -% -% I haven't implemented anything besides counters so far, but \m{dimen} -% and \m{skip} present no principal problem and should probably be -% added. +% \subsubsection{Scanning and conversion} % -% \subsection{Fake counters} % -% \begin{macro}{\fint_new:N} -% A fake counter is internally a \m{muskip} register. A count value -% \m{x} is saved as \m{x}|mu| (more exactly as \m{x}|.0mu|) in this -% register. This means that fake counter values are far more -% restricted then usual counters, the largest value is 16383, -% i.e.\ the |pt| part of \TeX{}'s largest \m{dimen}. This could be -% changed by using more complicated conversion routines, but it -% might be all right in usual applications. +% Conversion between different numbering schemes requires meticulous +% work. A number can be preceeded by any number of |+| and/or |-|. We +% define a generic function which will return the sign and/or the +% remainder. % -% Of course, we should make sure that we don't reach the borders, -% otherwise the user will be faced by the surprising message that -% some dimension got to large. (Not done yet). +% \begin{macro}{\int_get_sign_and_digits:n} +% \begin{macro}{\int_get_sign:n} +% \begin{macro}{\int_get_digits:n} +% \begin{macro}{\int_get_sign_and_digits_aux:nNNN} +% \begin{macro}{\int_get_sign_and_digits_aux:oNNN} +% A number may be preceeded by any number of |+|s and |-|s. Start out +% by assuming we have a positive number. % \begin{macrocode} -%<*package> -\let_new:NN \fint_new:N \newmuskip % nicked from LaTeX +\def_new:Npn \int_get_sign_and_digits:n #1{ + \int_get_sign_and_digits_aux:nNNN {#1} \c_true \c_true \c_true +} +\def_new:Npn \int_get_sign:n #1{ + \int_get_sign_and_digits_aux:nNNN {#1} \c_true \c_true \c_false +} +\def_new:Npn \int_get_digits:n #1{ + \int_get_sign_and_digits_aux:nNNN {#1} \c_true \c_false \c_true +} % \end{macrocode} -% \end{macro} -% -% -% \begin{macro}{\fint_use:N} -% \begin{macro}{\fint_use_aux:w} -% To use the value of a fake counter we have to get rid of |.0mu| in -% an expandable way, since we want to allow constructions like -% \begin{verbatim} -% \if_num:w\fint_use:N \l_test_fint > 55\scan_stop: ... -%\end{verbatim} -% The simplest way I came up with (not much thinking behind) was -% using parameter matching. +% Now check the first character in the string. Only a |-| can change +% if a number is positive or negative, hence we reverse the boolean +% governing this. Then gobble the |-| and start over. % \begin{macrocode} -\def_new:Npn \fint_use:N {\exp_after:NN\fint_use_aux:w\the_internal:D} +\def_new:Npn \int_get_sign_and_digits_aux:nNNN #1#2#3#4{ + \tlist_if_head_eq_charcode:fNTF {#1} - + { + \bool_if:NTF #2 + { \int_get_sign_and_digits_aux:oNNN {\use_none:n #1} \c_false #3#4 } + { \int_get_sign_and_digits_aux:oNNN {\use_none:n #1} \c_true #3#4 } + } % \end{macrocode} -% In the |\fint_use_aux:w| function we remove the |.0mu| and pass the -% the result back into the input stream. The only thing we -% have to think of, is that both |mu| have category code 12 when -% they are returned by |\the_internal:D|. +% The other cases are much simpler since we either just have to gobble +% the |+| or exit immediately and insert the correct sign. % \begin{macrocode} -\tex_lccode:D`\!=`\m \tex_lccode:D`\?=`\u -\tex_lowercase:D{\def_new:Npn \fint_use_aux:w #1.0!?{#1}} -\tex_lccode:D`\!=0\scan_stop: \tex_lccode:D`\?=0\scan_stop: + { + \tlist_if_head_eq_charcode:fNTF {#1} + + { \int_get_sign_and_digits_aux:oNNN {\use_none:n #1} #2#3#4} + { % \end{macrocode} -% \end{macro} -% \end{macro} -% -% -% \begin{macro}{\fint_set:Nn} -% \begin{macro}{\fint_gset:Nn} -% The way both routines are set up, the second argument might be -% either a \m{normal integer}, or an internal register. +% The boolean |#3| is for printing the sign while |#4| is for printing +% the digits. % \begin{macrocode} -\def_new:Npn \fint_set:Nn #1#2{#1#2~mu\scan_stop: -%<*check> - \chk_local_or_pref_global:N #1 -%</check> + \bool_double_if:NNnnnn #3#4 + { \bool_if:NF #2 - #1 } + { \bool_if:NF #2 - } + { #1 } { } + } + } +} +\def_new:Npn \int_get_sign_and_digits_aux:oNNN{ + \exp_args:No\int_get_sign_and_digits_aux:nNNN } -\def_new:Npn \fint_gset:Nn{ -%<*check> - \pref_global_chk: -%</check> -%<-check> \pref_global:D - \fint_set:Nn} % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % -% \begin{macro}{\fint_set_eq:NN} -% \begin{macro}{\fint_gset_eq:NN} -% We can easily set two fake counters equal to each other, but if -% fake counters and real counters are used, we have to use the -% slower |set| functions. +% \begin{macro}{\int_convert_from_base_ten:nn} +% \begin{macro}{\int_convert_from_base_ten_aux:nnn} +% \begin{macro}{\int_convert_from_base_ten_aux:non} +% \begin{macro}{\int_convert_from_base_ten_aux:fon} +% |#1| is the base 10 number to be converted to base |#2|. We split +% off the sign first, print if if there and then convert only the +% number. Since this is supposedly a base~10 number we can let \TeX\ +% do the reading of |+| and |-|. % \begin{macrocode} -\def_new:Npn \fint_set_eq:NN #1#2{#1#2 -%<*check> - \chk_local_or_pref_global:N #1\chk_var_or_const:N #2 -%</check> +\def:Npn \int_convert_from_base_ten:nn#1#2{ + \num_compare:nNnTF {#1}<\c_zero + { + - \int_convert_from_base_ten_aux:non {} + { \int_use:N \int_eval:n {-#1} } + } + { + \int_convert_from_base_ten_aux:non {} + { \int_use:N \int_eval:n {#1} } + } + {#2} } -\def_new:Npn \fint_gset_eq:NN { -%<*check> - \pref_global_chk: -%</check> -%<-check> \pref_global:D - \fint_set_eq:NN} % \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\fint_add:Nn} -% \begin{macro}{\fint_gadd:Nn} -% \begin{macro}{\fint_sub:Nn} -% \begin{macro}{\fint_gsub:Nn} -% Adding and substracting; we make use of the fact that internally -% \TeX{} always use the same primitives to advance a register. +% The algorithm runs like this: +% \begin{enumerate} +% \item If the number \meta{num} is greater than \meta{base}, +% calculate modulus of \meta{num} and \meta{base} and carry that +% over for next round. The remainder is calculated as a truncated +% division of \meta{num} and \meta{base}. Start over with these new +% values. +% \item If \meta{num} is less than or equal to \meta{base} convert it +% to the correct symbol, print the previously calculated digits and +% exit. +% \end{enumerate} +% |#1| is the carried over result, |#2| the remainder and |#3| the +% base number. % \begin{macrocode} -\def_new:Npn \fint_add:Nn #1#2{\int_add:Nn#1{#2mu}} -\def_new:Npn \fint_gadd:Nn { -%<*check> - \pref_global_chk: -%</check> -%<-check> \pref_global:D - \fint_add:Nn} -\def_new:Npn \fint_sub:Nn #1#2{\int_sub:Nn#1{#2mu}} -\def_new:Npn \fint_gsub:Nn { -%<*check> - \pref_global_chk: -%</check> -%<-check> \pref_global:D - \fint_sub:Nn} +\def_new:Npn \int_convert_from_base_ten_aux:nnn#1#2#3{ + \num_compare:nNnTF {#2}<{#3} + { \int_convert_number_to_letter:n{#2} #1 } + { + \int_convert_from_base_ten_aux:fon + { + \int_convert_number_to_letter:n {\int_use:N\int_mod_raw:nn {#2}{#3}} + #1 + } + {\int_use:N \int_div_truncate_raw:nn{#2}{#3}} + {#3} + } +} +\def:Npn \int_convert_from_base_ten_aux:non{ + \exp_args:Nno\int_convert_from_base_ten_aux:nnn +} +\def:Npn \int_convert_from_base_ten_aux:fon{ + \exp_args:Nfo\int_convert_from_base_ten_aux:nnn +} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} +% \begin{macro}{\int_convert_number_to_letter:n} +% Turning a number for a different base into a letter or digit. +% \begin{macrocode} +\def:Npn \int_convert_number_to_letter:n #1{ \if_case:w \int_eval:w + #1-10\scan_stop: \exp_after:NN A \or: \exp_after:NN B \or: + \exp_after:NN C \or: \exp_after:NN D \or: \exp_after:NN E \or: + \exp_after:NN F \or: \exp_after:NN G \or: \exp_after:NN H \or: + \exp_after:NN I \or: \exp_after:NN J \or: \exp_after:NN K \or: + \exp_after:NN L \or: \exp_after:NN M \or: \exp_after:NN N \or: + \exp_after:NN O \or: \exp_after:NN P \or: \exp_after:NN Q \or: + \exp_after:NN R \or: \exp_after:NN S \or: \exp_after:NN T \or: + \exp_after:NN U \or: \exp_after:NN V \or: \exp_after:NN W \or: + \exp_after:NN X \or: \exp_after:NN Y \or: \exp_after:NN Z \else: + \use_arg_i_after_fi:nw{ #1 }\fi: } +% \end{macrocode} +% \end{macro} % -% \begin{macro}{\fint_incr:N} -% \begin{macro}{\fint_gincr:N} -% \begin{macro}{\fint_decr:N} -% \begin{macro}{\fint_gdecr:N} -% Incrementing and decrementing the fake counters: +% \begin{macro}{\int_convert_to_base_ten:nn} +% |#1| is the number, |#2| is its base. First we get the sign, then +% use only the digits/letters from it and pass that onto a new +% function. % \begin{macrocode} -\def_new:Npn \fint_incr:N #1{\advance:D#1\c_one mu\scan_stop: -%<*check> - \chk_local_or_pref_global:N #1 -%</check> +\def:Npn \int_convert_to_base_ten:nn #1#2 { + \int_use:N\int_eval:n{ + \int_get_sign:n{#1} + \exp_args:Nf\int_convert_to_base_ten_aux:nn {\int_get_digits:n{#1}}{#2} + } } -\def_new:Npn \fint_decr:N #1{\advance:D#1\c_minus_one mu\scan_stop: -%<*check> - \chk_local_or_pref_global:N #1 -%</check> +% \end{macrocode} +% This is an intermediate function to get things started. +% \begin{macrocode} +\def_new:Npn \int_convert_to_base_ten_aux:nn #1#2{ + \int_convert_to_base_ten_auxi:nnN {0}{#2} #1 \q_nil } -\def_new:Npn \fint_gincr:N { -%<*check> - \pref_global_chk: -%</check> -%<-check> \pref_global:D - \fint_incr:N} -\def_new:Npn \fint_gdecr:N { -%<*check> - \pref_global_chk: -%</check> -%<-check> \pref_global:D - \fint_decr:N} % \end{macrocode} -% This can be achieved with less tokens but extra expansions: +% Here we check each letter/digit and calculate the next number. |#1| +% is the previously calculated result (to be multiplied by the base), +% |#2| is the base and |#3| is the next letter/digit to be added. % \begin{macrocode} -\def:Npn \fint_incr:N #1{\fint_add:Nn#1\c_one} -\def:Npn \fint_decr:N #1{\fint_add:Nn#1\c_minus_one} +\def_new:Npn \int_convert_to_base_ten_auxi:nnN#1#2#3{ + \quark_if_nil:NTF #3 + {#1} + {\exp_args:No\int_convert_to_base_ten_auxi:nnN + {\int_use:N \int_eval:n{ #1*#2+\int_convert_letter_to_number:N #3} } + {#2} + } +} % \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\c_fint_max} -% A constant, denoting the largest possible value for fake counters. +% This is for turning a letter or digit into a number. This function +% also takes care of handling lowercase and uppercase letters. Hence +% |a| is turned into |11| and so is |A|. % \begin{macrocode} -\tex_mathchardef:D\c_fint_max=16383 \scan_stop: +\def:Npn \int_convert_letter_to_number:N #1{ + \int_compare:nNnTF{`#1}<{58}{#1} + { + \int_eval:n{ `#1 - + \if:w\int_compare_p:nNn{`#1}<{91} + 55 + \else: + 87 + \fi: + } + } +} % \end{macrocode} % \end{macro} % % -% \subsection{Fake skip registers} % -% One has to convert simply from the \m{x}|pt| |plus| \m{y}|pt| |minus| -% \m{z}|pt| representation produced by |\the_internal:D|, to the -% corresponding |mu| representation. Complications arise from the -% possibility that |plus| and/or |minus| is not present,\footnote{This -% can be catched by adding a suitable constant and removing the -% corresponding constant in the other representation.} and by the -% possibility that the stretch or shrink component is a |fil| unit. % -% \subsection{Fake dimen registers} % -% I suppose this could be viewed as a subcase of the skip registers. -% See later section for a fake fake version for the moment. % % -% \subsection{Allocation routines} -% -% Counters are rare goods in \TeX{} and we are near the limit, if -% for example \LaTeX{} and Pic\TeX{} are merged. Therefore we should -% be careful not to throw away counter registers unnecessarily. One -% place for instance, where we can save some of them are the -% allocation routines. Instead of using counters we maintain the -% number of the last allocated register in a fake counter. -% -% +% Show token usage: % \begin{macrocode} -%</package> +%</initex|package> %<*showmemory> \showMemUsage %</showmemory> % \end{macrocode} - +% +% +% \endinput +% +% $Log$ +% Revision 1.26 2006/06/03 17:17:08 morten +% Functions for converting between number bases +% +% Revision 1.25 2006/03/20 18:26:35 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.24 2006/01/17 22:47:43 morten +% Changed \int_while:nNnT to \int_whiledo:nNnT to avoid confusion with +% the dowhile versions. +% +% Revision 1.23 2005/12/27 10:02:37 morten +% Minor changes plus changed RCS information retrieval +% +% Revision 1.22 2005/12/21 20:43:32 morten +% Fixed silly bugs! +% +% Revision 1.21 2005/12/06 17:31:23 morten +% fixed \int_convert_number_with_rule:nnN +% +% Revision 1.20 2005/12/06 14:49:36 morten +% Fixed primitive names plus a few minor touch-ups +% +% Revision 1.19 2005/04/25 15:02:47 morten +% Added ifodd functions +% +% Revision 1.18 2005/04/09 21:07:39 morten +% Added (extensible) implementations of \int_to_roman:n etc. +% +% Revision 1.17 2005/04/06 22:35:43 braams +% Now we have register allocation fitted +% +% Revision 1.16 2005/03/25 23:48:47 braams +% Added a missing \end{macro} +% +% Revision 1.15 2005/03/22 23:22:09 morten +% Moved definitions of constants to l3num +% +% Revision 1.14 2005/03/16 22:36:30 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.13 2005/03/11 21:38:31 braams +% Fixed the use of RCS information; added \StopEventually +% diff --git a/Master/texmf-dist/source/latex/expl3/l3io.dtx b/Master/texmf-dist/source/latex/expl3/l3io.dtx index ae155f4d2b3..04efa42b8d7 100644 --- a/Master/texmf-dist/source/latex/expl3/l3io.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3io.dtx @@ -1,15 +1,50 @@ % \iffalse -%% File: l3io.dtx Copyright (C) 1990-1998 LaTeX3 project -% +%% File: l3io.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} %<*dtx> - \ProvidesFile{l3io.dtx} +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse %</dtx> -%<package>\NeedsTeXFormat{LaTeX2e} -%<package>\ProvidesPackage{l3io} -%<driver> \ProvidesFile{l3io.drv} -% \fi -% \ProvidesFile{l3io.dtx} - [1998/04/20 v1.0c L3 Experimental i/o module] +%\fi +\GetIdInfo$Id: l3io.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental i/o module} % % \iffalse %<*driver> @@ -233,13 +268,6 @@ % prompting. % \end{variable} % -% \begin{variable}{\g_iow_newline_code} -% Global variable holding the character number of the character that -% denotes a new line when something is written to an output stream. -% \begin{texnote} -% A.k.a \tn{newlinechar}. -% \end{texnote} -% \end{variable} % % \subsection{Internal functions} % @@ -264,14 +292,15 @@ % \end{texnote} % \end{function} % +% \StopEventually{} % -% \section{Lowlevel i/o-commands} +% \subsection{The Implementation} % % We start by ensuring that the required packages are loaded. % \begin{macrocode} %<package&check>\RequirePackage{l3chk}\par %<package>\RequirePackage{l3toks}\par -%<*package> +%<*initex|package> % \end{macrocode} % % This section is primarily concerned with input and output streams. @@ -279,7 +308,7 @@ % (for write) as module names. e.g.\ |\c_ior_test_stream| is an input stream % variable called `test'. % -% \subsection{Output streams} +% \subsubsection{Output streams} % % \begin{macro}{\iow_new:N} % \begin{macro}{\iow_new:c} @@ -287,8 +316,11 @@ % As we currently do not distribute a new allocation module we nick % the |\newwrite| function. % \begin{macrocode} -\def_new:Npn \iow_new:N {} -\let:NN \iow_new:N \newwrite +%<*initex> +\alloc_setup_type:nnn {iow} \c_zero \c_sixteen +\def_new:Npn \iow_new:N #1 {\alloc_reg:NnNN g {iow} \tex_chardef:D #1} +%</initex> +%<package>\let:NN \iow_new:N \newwrite \def_new:Npn \iow_new:c {\exp_args:Nc \iow_new:N} % \end{macrocode} % \end{macro} @@ -301,7 +333,7 @@ % are provided. The streams are opened immediately. % % From some bad experiences on the mainframe, I learned that it is -% better to force the close before opening a dataset for writing. +% better to force the close before opening a dataset for writing. % We have to check whether this is also necessary in case of % |\tex_openin:D|. % \begin{macrocode} @@ -337,7 +369,7 @@ % \end{macro} % \end{macro} % -% \subsubsection{Immediate writing} +% \paragraph{Immediate writing} % % \begin{macro}{\iow_expanded:Nn} % An abbreviation for an often used operation, which immediately @@ -353,8 +385,8 @@ % If the first argument is no output stream at all, we get an % internal error. % \begin{macrocode} -\def_new:Npn \iow_unexpanded:Nn #1#2{\toks_gset:Nn \g_tmpa_toks {#2} - \iow_expanded:Nn #1{\toks_use:N \g_tmpa_toks}} +\def_new:Npn \iow_unexpanded:Nn #1#2{ + \iow_expanded:Nn #1{\exp_not:n{#2}}} % \end{macrocode} % \end{macro} % @@ -391,7 +423,7 @@ \def_new:Npn \iow_unexpanded_if_avail:Nn #1{ % \end{macrocode} % In this routine we have to check whether or not the output stream -% that was requested is defined at all. +% that was requested is defined at all. % So we check if the name is still free. % \begin{macrocode} \cs_free:NTF #1\use_none:n {\iow_unexpanded:Nn #1}} @@ -422,10 +454,10 @@ % % \begin{macrocode} \def_new:Npn \iow_long_expanded_aux:w #1#2#3{ - \group_begin:\g_iow_newline_code`\ #1#2{#3}\group_end:} -\def_new:Npn \iow_long_expanded:Nn {\iow_long_expanded_aux:w + \group_begin:\tex_newlinechar:D`\ #1#2{#3}\group_end:} +\def_new:Npn \iow_long_expanded:Nn {\iow_long_expanded_aux:w \iow_expanded:Nn} -\def_new:Npn \iow_long_unexpanded:Nn {\iow_long_expanded_aux:w +\def_new:Npn \iow_long_unexpanded:Nn {\iow_long_expanded_aux:w \iow_unexpanded:Nn} % \end{macrocode} % \end{macro} @@ -433,7 +465,10 @@ % \end{macro} % % -% \subsubsection{Deferred writing} +% \paragraph{Deferred writing} +% +% With \eTeX\ available deferred writing is easy. The comments below +% are old. % % Deferred writing to output streams is a bit more complicated because % there seems to be no nice hack for writing unexpanded. The only @@ -459,24 +494,35 @@ % Now the harder part: % \begin{macrocode} \def_new:Npn \iow_deferred_unexpanded:Nn #1#2{ - \tlp_set:Nn \l_tmpa_tlp {#2} - \tlp_set:Nx \l_tmpb_tlp - {\iow_deferred_expanded:Nn #1{\tlp_to_str:N \l_tmpa_tlp}} - \l_tmpb_tlp} + \iow_deferred_expanded:Nn{\exp_not:n{#2}} +} +%% Old implementation: +%\def_new:Npn \iow_deferred_unexpanded:Nn #1#2{ +% \tlp_set:Nn \l_tmpa_tlp {#2} +% \tlp_set:Nx \l_tmpb_tlp +% {\iow_deferred_expanded:Nn #1{\tlp_to_str:N \l_tmpa_tlp}} +% \l_tmpb_tlp} % \end{macrocode} % \end{macro} % % Long forms of these functions are not possible since the deferred -% writing will restore the value of |\g_iow_newline_code| before it will have +% writing will restore the value of |\tex_newlinechar:D| before it will have % a chance to act. But on the other hand it is nevertheless possible -% to make all deferred writes long by setting the |\g_iow_newline_code| +% to make all deferred writes long by setting the |\tex_newlinechar:D| % inside the output routine just before the |\tex_shipout:D|. The only % disadvantage of this method is the fact that messages to the % terminal during this time will also then break at spaces. But we % should consider this. % -% \subsubsection{Special characters for writing} +% \paragraph{Special characters for writing} % +% \begin{macro}{\iow_newline:} +% Global variable holding the character that forces a new line when +% something is written to an output stream. +% \begin{macrocode} +\def_new:Npn \iow_newline: {^^J} +% \end{macrocode} +% \end{macro} % % \begin{macro}{\c_iow_comment_char} % \begin{macro}{\c_iow_lbrace_char} @@ -485,44 +531,46 @@ % achieve this by defining global constants to expand into a version of % these characters with |\tex_catcode:D|${}=12$. % \begin{macrocode} -\tex_catcode:D `\%= 12 \scan_stop: -\tlp_new:Nn \c_iow_comment_char {%} -\tex_catcode:D `\%= 14 \scan_stop: +\tlp_new:Nx \c_iow_comment_char {\cs_to_str:N\%} % \end{macrocode} % To avoid another allocation function which is probably only % necessary here we use the |\def:Npx| command directly. % \begin{macrocode} -\tlp_new:Nn \c_iow_lbrace_char{} -\tlp_new:Nn \c_iow_rbrace_char{} -\def:Npx\c_iow_lbrace_char {\token_to_string:N{} -\def:Npx\c_iow_rbrace_char {\token_to_string:N}} +\tlp_new:Nx \c_iow_lbrace_char{\cs_to_str:N\{} +\tlp_new:Nx \c_iow_rbrace_char{\cs_to_str:N\}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % -% \subsection{Input streams} +% \subsubsection{Input streams} % % \begin{macro}{\ior_new:N} % Allocation of new input streams is done by this function. % As we currently do not distribute a new allocation module we nick % the |\newwread| function. % \begin{macrocode} -\def_new:Npn \ior_new:N {} -\let:NN \ior_new:N \newread +%<*initex> +\alloc_setup_type:nnn {ior} \c_zero \c_sixteen +\def_new:Npn \ior_new:N #1 {\alloc_reg:NnNN g {ior} \tex_chardef:D #1} +%</initex> +%<package>\let:NN \ior_new:N \newread % \end{macrocode} % \end{macro} % % \begin{macro}{\ior_open:Nn} +% \begin{macro}{\ior_close:Nn} % Processing of input-streams (via |\tex_openin:D| and |closein|) is % always `immediate' as far as \TeX{} is concerned. An extra % |\tex_immediate:D| is silently ignored. % \begin{macrocode} +\let:NN \ior_close:N \tex_closein:D \def_new:Npn \ior_open:Nn #1#2{\ior_close:N #1\scan_stop: \tex_openin:D#1#2\scan_stop:} % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro}{\ior_eof:NTF} % |\ior_eof:NTF | \m{stream} \m{true case} \m{false case}. To @@ -530,19 +578,22 @@ % conditional is provided: % \begin{macrocode} \def_new:Npn \ior_eof:NTF #1{\if_eof:w#1 - \exp_after:NN\use_choice_i:nn \else: - \exp_after:NN\use_choice_ii:nn \fi:} + \exp_after:NN\use_arg_i:nn \else: + \exp_after:NN\use_arg_ii:nn \fi:} % \end{macrocode} % \end{macro} % % \begin{macro}{\ior_eof:NF} +% \begin{macro}{\if_eof:w} % |\ior_eof:NF | \m{stream} \m{false case}. Do something if % if there is still something to read from this file: % \begin{macrocode} +\let:NN \if_eof:w \tex_ifeof:D \def_new:Npn \ior_eof:NF #1{\if_eof:w#1 - \exp_after:NN \use_none:nn \fi: \use:n} + \exp_after:NN \use_none:nn \fi: \use_arg_i:n} % \end{macrocode} % \end{macro} +% \end{macro} % % % \begin{macro}{\ior_to:NN} @@ -567,11 +618,35 @@ % % Show token usage: % \begin{macrocode} -%</package> +%</initex|package> %<*showmemory> \showMemUsage %</showmemory> % \end{macrocode} % +% \endinput +% +% $Log$ +% Revision 1.16 2006/03/20 18:26:36 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.15 2005/12/27 09:51:27 morten +% Changed the use of RCS information +% +% Revision 1.14 2005/11/07 17:59:48 morten +% Fixed definition of \iow_newline: (moved it to the right place) +% +% Revision 1.13 2005/04/29 22:29:23 braams +% Replaced the undefined \g_iow_newline_code with \tex_newlinechar:D +% and added the definition for \iow_newline: +% +% Revision 1.12 2005/04/06 22:35:37 braams +% Now we have register allocation fitted +% +% Revision 1.11 2005/03/16 22:36:24 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.10 2005/03/11 21:39:10 braams +% Fixed the use of RCS information; added \StopEventually % - diff --git a/Master/texmf-dist/source/latex/expl3/l3keyval.dtx b/Master/texmf-dist/source/latex/expl3/l3keyval.dtx new file mode 100644 index 00000000000..8848946602a --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3keyval.dtx @@ -0,0 +1,666 @@ +% \iffalse +%% File: l3keyval.dtx Copyright (C) 2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3keyval.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental keyval processing} +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3keyval.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3keyval} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}\\ +% Key-value parsing} +% \author{\Team} +% \date{\filedate} +% \maketitle +% +% \section{Introduction} +% +% Currently, this module only provides functions for extracting keys +% and values from a list. How this information is used is up to the +% programmer. +% +% A \meta{keyval list} is a list consisting of +% \begin{verbatim} +% key 1 = value 1 , +% key 2 , +% key 3 = value 3 , +% \end{verbatim} +% +% The function names for retrieving the keys and values are long but +% explain what they do. All these functions start with the name +% |\KV_parse_|. If a value is surrounded by braces, one level (and +% only one) is removed from the value. This is useful if you need to +% input a value which contains |=| or |,|. There are two primary +% actions we can take on a \meta{keyval list}. +% \begin{itemize} +% \item A \meta{keyval list} can be sanitized so that top level active +% commas or equal signs are converted into catcode 12. When +% declaring templates in the preamble one can probably safely assume +% that there are no active commas or equals; these things should +% only be active in the document. The name for this is either +% |no_sanitize| or |sanitize|. +% \item Spaces on either side of a key or value can be trimmed. When +% using the \LaTeX3 programming interface, spaces are automatically +% ignored so there it would be a waste of time to search for extra +% spaces since there would be none. At the document level however, +% spaces must be removed. The name for this is either +% |no_space_removal| or |space_removal|. Note that when +% |space_removal| is called you get an additional option where you +% can decide if one level of braces should be stripped from the key +% and/or value; see the description of the boolean +% |\l_KV_remove_one_level_of_braces_bool| for details. +% \end{itemize} +% +% During the parsing process, keys or values are not expanded and no +% |#|s are doubled. When the parsing process is over, the keys and +% values are executed in the form +% \begin{quote} +% "\KV_key_value_elt:nn{key 1}{value 1}" \\ +% "\KV_key_no_value_elt:n{key 2}" \\ +% "\KV_key_value_elt:nn{key 3}{value 3}" +% \end{quote} +% It is up to the programmer to provide a suitable definition of these +% two functions before starting the parsing process. +% +% +% \subsection{Functions} +% +% +% +% +% \begin{function}{ +% \KV_parse_no_space_removal_no_sanitize:n | +% } +% \begin{syntax} +% "\KV_parse_no_space_removal_no_sanitize:n" "{"<keyval list>"}" +% \end{syntax} +% Parses the keys and values literally. For use when spaces are +% ignored and |=| and |,| have normal catcodes. +% \end{function} +% +% \begin{function}{ +% \KV_parse_space_removal_no_sanitize:n | +% } +% \begin{syntax} +% "\KV_parse_space_removal_no_sanitize:n" "{"<keyval list>"}" +% \end{syntax} +% As above but also removes spaces around keys and values. For use +% when spaces are not ignored. +% \end{function} +% +% \begin{function}{ +% \KV_parse_space_removal_sanitize:n | +% } +% \begin{syntax} +% "\KV_parse_space_removal_sanitize:n" "{"<keyval list>"}" +% \end{syntax} +% As above but additionally also replaces top-level active |=| and +% |,| with harmless versions. +% \end{function} +% +% \begin{variable}{ +% \l_KV_remove_one_level_of_braces_bool | +% } +% \begin{syntax} +% \end{syntax} +% This boolean controls whether or not one level of braces is +% stripped from the key and value. The default value for this +% boolean is \meta{true} so that exactly one level of braces is +% stripped. For certain applications it is desirable to keep the +% braces in which case the programmer just has to set the boolean +% false temporarily. Setting this boolean has no effect when you +% call the |no_space_removal| functions since not stripping braces +% is a rare request and would clutter the otherwise elegant code of +% the |no_space_removal| functions for very little gain. If you need +% to preserve braces choose the slower |space_removal| functions. +% \end{variable} +% +% \begin{function}{ +% \KV_key_no_value_elt:n | +% \KV_key_value_elt:nn | +% } +% \begin{syntax} +% "\KV_key_no_value_elt:n" "{"<key>"}" \\ +% "\KV_key_value_elt:n" "{"<key>"}" "{"<value>"}" +% \end{syntax} +% Functions returned by the |\KV_parse_| functions. The default +% definition of these two functions is an error message! +% \end{function} +% +% +% \StopEventually{} +% +% \section{Implementation} +% +% +% We start by ensuring that the required packages are loaded. +% \begin{macrocode} +%<*package> +\RequirePackage{l3quark} +\RequirePackage{l3toks} +\RequirePackage{l3int} +\RequirePackage{l3token} +%</package> +%<*initex|package> +% \end{macrocode} +% +% +% +% +% \begin{macro}{\l_KV_tmpa_tlp} +% \begin{macro}{\l_KV_tmpb_tlp} +% \begin{macro}{\c_KV_single_equal_sign_tlp} +% Various useful things. +% \begin{macrocode} +\tlp_new:Nn\l_KV_tmpa_tlp{} +\tlp_new:Nn\l_KV_tmpb_tlp{} +\tlp_new:Nn \c_KV_single_equal_sign_tlp{=} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\l_KV_parse_toks} +% \begin{macro}{\l_KV_currkey_toks} +% \begin{macro}{\l_KV_currval_toks} +% Some more useful things. +% \begin{macrocode} +\toks_new:N \l_KV_parse_toks +\toks_new:N \l_KV_currkey_toks +\toks_new:N \l_KV_currval_toks +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\l_KV_remove_one_level_of_braces_bool} +% A boolean to control +% \begin{macrocode} +\bool_new:N \l_KV_remove_one_level_of_braces_bool +\bool_set_true:N \l_KV_remove_one_level_of_braces_bool +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KV_sanitize_outerlevel_active_equals:N} +% \begin{macro}{\KV_sanitize_outerlevel_active_commas:N} +% Some functions for sanitizing top level equals and commas. Replace +% |=|$\sb{13}$ and |,|$\sb{13}$ with |=|$\sb{12}$ and |,|$\sb{12}$ +% resp. +% \begin{macrocode} +\group_begin: +\char_set_catcode:nn{`\=}{13} +\char_set_catcode:nn{`\,}{13} +\char_set_lccode:nn{`\8}{`\=} +\char_set_lccode:nn{`\9}{`\,} +\tlist_to_lowercase:n{\group_end: +\def_new:Npn \KV_sanitize_outerlevel_active_equals:N #1{ + \tlp_replace_all_in:Nnn #1 = 8 +} +\def_new:Npn \KV_sanitize_outerlevel_active_commas:N #1{ + \tlp_replace_all_in:Nnn #1 , 9 +} +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% +% +% \begin{macro}{\KV_remove_surrounding_spaces:nw} +% \begin{macro}{\KV_remove_surrounding_spaces_auxi:w} +% \begin{macro}{\KV_remove_surrounding_spaces_auxii:w} +% \begin{macro}{\KV_set_key_element:w} +% \begin{macro}{\KV_set_value_element:w} +% The macro |\KV_remove_surrounding_spaces:Nw| removes a possible +% leading space plus a possible ending space from its second +% argument and stores it in the token register |#1|. +% +% Based on Around the Bend No.~15 but with some enhancements. For +% instance, this definition is purely expandable. +% +% We use a funny token |Q|$\sb3$ as a delimiter. +% \begin{macrocode} +\group_begin: +\char_set_catcode:nn{`\Q}{3} +% \end{macrocode} +% \begin{macrocode} +\gdef_long_new:Npn\KV_remove_surrounding_spaces:nw#1#2\q_nil{ +% \end{macrocode} +% The idea in this processing is to use a Q with strange catcode to +% remove a trailing space. But first, how to get this expansion going? +% +% If you have read the fine print in the \textsf{l3expan} module, +% you'll know that the |f| type expansion will expand until the first +% non-expandable token is seen and if this token is a space, it will +% be gobbled. Sounds useful for removing a leading space but we also +% need to make sure that it does nothing but removing that space! +% Therefore we prepend the argument to be trimmed with an +% |\exp_not:N|. Now why is that? |\exp_not:N| in itself is an +% expandable command so will allow the |f| expansion to continue. If +% the first token in the argument to be trimmed is a space, it will be +% gobbled and the expansion stop. If the first token isn't a space, +% the |\exp_not:N| turns it temporarily into |\scan_stop:| which is +% unexpandable. The processing stops but the token following directly +% after |\exp_not:N| is now back to normal. +% +% The function here allows you to insert arbitrary functions in the +% first argument but they should all be with an |f| type +% expansion. For the application in this module, we use +% |\toks_set:Nf|. +% +% Once the expansion has been kick-started, we apply +% |\KV_remove_surrounding_spaces_auxi:w| to the replacement text of +% |#2|, adding a leading |\exp_not:N|. Note that no braces are +% stripped off of the original argument. +% \begin{macrocode} + #1{\KV_remove_surrounding_spaces_auxi:w \exp_not:N#2Q~Q} +} +% \end{macrocode} +% |\KV_remove_surrounding_spaces_auxi:w| removes a trailing space if +% present, then calls |\KV_remove_surrounding_spaces_auxii:w| to clean +% up any leftover bizarre Qs. In order for +% |\KV_remove_surrounding_spaces_auxii:w| to work properly we need to +% put back a Q first. +% \begin{macrocode} +\gdef_long_new:Npn\KV_remove_surrounding_spaces_auxi:w#1~Q{ + \KV_remove_surrounding_spaces_auxii:w #1 Q +} +% \end{macrocode} +% Now all that is left to do is remove a leading space which should be +% taken care of by the function used to initiate the expansion. Simply +% return the argument before the funny Q. +% \begin{macrocode} +\gdef_long_new:Npn\KV_remove_surrounding_spaces_auxii:w#1Q#2{#1} +% \end{macrocode} +% Here are some specialized versions of the above. They do exactly +% what we want in one go. First trim spaces from the value and then +% put the result surrounded in braces onto |\l_KV_parse_toks|. +% \begin{macrocode} +\gdef_long_new:Npn\KV_add_value_element:w\q_stop#1\q_nil{ + \toks_set:Nf\l_KV_currval_toks { + \KV_remove_surrounding_spaces_auxi:w \exp_not:N#1Q~Q + } + \toks_put_right:No\l_KV_parse_toks{ + \exp_after:NN {\toks_use:N \l_KV_currval_toks} + } +} +% \end{macrocode} +% When storing the key we firstly remove spaces plus the prepended +% |\q_no_value|. +% \begin{macrocode} +\gdef_long_new:Npn\KV_set_key_element:w#1\q_nil{ + \toks_set:Nf\l_KV_currkey_toks + { + \exp_after:NN\KV_remove_surrounding_spaces_auxi:w + \exp_after:NN\exp_not:N\use_none:n #1Q~Q + } +% \end{macrocode} +% Afterwards we gobble an extra level of braces if that's what we are +% asked to do. +% \begin{macrocode} + \bool_if:NT \l_KV_remove_one_level_of_braces_bool + { + \toks_set:Nd \l_KV_currkey_toks{ + \exp_after:NN \KV_add_element_aux:w + \toks_use:N \l_KV_currkey_toks \q_nil + } + } +} +\group_end: +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\KV_add_element_aux:w} +% A helper function for fixing braces around keys and values. +% \begin{macrocode} +\def_long_new:Npn \KV_add_element_aux:w#1\q_nil{#1} +% \end{macrocode} +% \end{macro} +% +% +% Parse a list of keyvals, put them into list form with entries like +% |\KV_key_no_value_elt:n{key1}| and |\KV_key_value_elt:nn{key2}{val2}|. +% +% \begin{macro}{\KV_parse_sanitize_aux:n} +% The slow parsing algorithm sanitizes active commas and equal signs +% at the top level first. Then uses |#1| as inspector of each +% element in the comma list. +% \begin{macrocode} +\def_long_new:Npn \KV_parse_sanitize_aux:n #1{ + \group_begin: + \toks_clear:N \l_KV_parse_toks + \tlp_set:Nx\l_KV_tmpa_tlp{\exp_not:n{#1}} + \KV_sanitize_outerlevel_active_equals:N\l_KV_tmpa_tlp + \KV_sanitize_outerlevel_active_commas:N\l_KV_tmpa_tlp + \exp_after:NN \KV_parse_elt:w \exp_after:NN\q_no_value \l_KV_tmpa_tlp,\q_nil, +% \end{macrocode} +% We evaluate the parsed keys and values outside the group so the +% token register is restored to its previous value. +% \begin{macrocode} + \exp_after:NN\group_end: + \toks_use:N \l_KV_parse_toks +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\KV_parse_no_sanitize_aux:n} +% Like above but we don't waste time sanitizing. This is probably +% the one we will use for preamble parsing where catcodes of |=| and +% |,| are as expected! +% \begin{macrocode} +\def_long_new:Npn \KV_parse_no_sanitize_aux:n #1{ + \group_begin: + \toks_clear:N \l_KV_parse_toks + \KV_parse_elt:w \q_no_value #1,\q_nil, + \exp_after:NN\group_end: + \toks_use:N \l_KV_parse_toks +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\KV_parse_elt:w} +% This function will always have a |\q_no_value| stuffed in as the +% rightmost token in |#1|. In case there was a blank entry in the +% comma separated list we just run it again. The |\use_none:n| makes +% sure to gobble the quark |\q_no_value|. A similar test is made to +% check if we hit the end of the recursion. +% \begin{macrocode} +\def_long:Npn \KV_parse_elt:w #1,{ + \tlist_if_blank:oTF{\use_none:n #1} + { \KV_parse_elt:w \q_no_value } + { + \quark_if_nil:oF {\use_arg_ii:nn #1 } +% \end{macrocode} +% If we made it to here we can start parsing the key and value. When +% done try, try again. +% \begin{macrocode} + { + \KV_split_key_value_current:w #1==\q_nil + \KV_parse_elt:w \q_no_value + } + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\KV_split_key_value_current:w} +% The function called to split the keys and values. +% \begin{macrocode} +\let_new:NN \KV_split_key_value_current:w \ERROR +% \end{macrocode} +% \end{macro} +% +% We provide two functions for splitting keys and values. The reason +% being that most of the time, we should probably be in the special +% coding regime where spaces are ignored. Hence it makes no sense to +% spend time searching for extra space tokens and we can do the +% settings directly. When comparing these two versions (neither doing +% any sanitizing) the |no_space_removal| version is more than 40\% +% faster than |space_removal|. +% +% It is up to functions like |\DeclareTemplate| to check which catcode +% regime is active and then pick up the version best suited for it. +% +% +% +% \begin{macro}{\KV_split_key_value_space_removal:w} +% \begin{macro}{\KV_split_key_value_space_removal_detect_error:wTF} +% \begin{macro}{\KV_split_key_value_space_removal_aux:w} +% The code below removes extraneous spaces around the keys and +% values plus one set of braces around the entire value. +% +% Unlike the version to be used when spaces are ignored, this one +% only grabs the key which is everything up to the first = and save +% the rest for closer inspection. Reason is that if a user has +% entered |mykey={{myval}},| then the outer braces have already been +% removed before we even look at what might come after the key. So +% this is slightly more tedious (but only slightly) but at least it +% always removes only one level of braces. +% \begin{macrocode} +\def_long_new:Npn \KV_split_key_value_space_removal:w #1 = #2\q_nil{ +% \end{macrocode} +% First grab the key. +% \begin{macrocode} + \KV_set_key_element:w#1\q_nil +% \end{macrocode} +% Then we start checking. If only a key was entered, |#2| contains +% |=| and nothing else, so we test for that first. +% \begin{macrocode} + \tlp_set:Nx\l_KV_tmpa_tlp{\exp_not:n{#2}} + \tlp_if_eq:NNTF\l_KV_tmpa_tlp\c_KV_single_equal_sign_tlp +% \end{macrocode} +% Then we just insert the default key. +% \begin{macrocode} + { + \toks_put_right:No\l_KV_parse_toks{ + \exp_after:NN \KV_key_no_value_elt:n + \exp_after:NN {\toks_use:N\l_KV_currkey_toks} + } + } +% \end{macrocode} +% Otherwise we must take a closer look at what is left. The remainder +% of the original list up to the comma is now stored in |#2| plus an +% additional |==|, which wasn't gobbled during the initial reading of +% arguments. If there is an error then we can see at least one more +% |=| so we call an auxiliary function to check for this. +% \begin{macrocode} + { + \KV_split_key_value_space_removal_detect_error:wTF#2\q_no_value\q_nil + {\KV_split_key_value_space_removal_aux:w \q_stop #2} + {\ERROR} + } +} +% \end{macrocode} +% The error test. +% \begin{macrocode} +\def_long_new:Npn + \KV_split_key_value_space_removal_detect_error:wTF#1=#2#3\q_nil{ + \tlist_if_head_eq_meaning:nNTF{#3}\q_no_value +} +% \end{macrocode} +% Now we can start extracting the value. Recall that |#1| here starts +% with |\q_stop| so all braces are still there! First we try to see +% how much is left if we gobble three brace groups from |#1|. If |#1| +% is empty or blank, all three quarks are gobbled. If |#1| consists of +% exactly one token or brace group, only the latter quark is left. +% \begin{macrocode} +\def_long_new:Npn \KV_val_preserve_braces:NnN #1#2#3{{#2}} +\def_long_new:Npn\KV_split_key_value_space_removal_aux:w #1=={ + \tlp_set:Nx\l_KV_tmpa_tlp{\exp_not:o{\use_none:nnn#1\q_nil\q_nil}} + \toks_put_right:No\l_KV_parse_toks{ + \exp_after:NN \KV_key_value_elt:nn + \exp_after:NN {\toks_use:N\l_KV_currkey_toks} + } +% \end{macrocode} +% If there a blank space or nothing at all, |\l_KV_tmpa_tlp| is now +% completely empty. +% \begin{macrocode} + \tlp_if_empty:NTF\l_KV_tmpa_tlp +% \end{macrocode} +% We just put an empty value on the stack. +% \begin{macrocode} + { \toks_put_right:Nn\l_KV_parse_toks{{}} } + { +% \end{macrocode} +% If there was exactly one brace group or token in |#1|, +% |\l_KV_tmpa_tlp| is now equal to |\q_nil|. Then we can just pick it +% up as the second argument of |#1|. This will also take care of any +% spaces which might surround it. +% \begin{macrocode} + \quark_if_nil:NTF\l_KV_tmpa_tlp + { + \bool_if:NTF \l_KV_remove_one_level_of_braces_bool + { + \toks_put_right:No\l_KV_parse_toks{ + \exp_after:NN{\use_arg_ii:nnn #1\q_nil} + } + } + { + \toks_put_right:No\l_KV_parse_toks{ + \exp_after:NN{\KV_val_preserve_braces:NnN #1\q_nil} + } + } + } +% \end{macrocode} +% Otherwise we grab the value. +% \begin{macrocode} + { \KV_add_value_element:w #1\q_nil } + } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\KV_split_key_value_no_space_removal:w} +% This version is for when in the special coding regime where spaces +% are ignored so there is no need to do any fancy space hacks, +% however fun they may be. Since there are no spaces, a set of +% braces around a value is automatically stripped by \TeX. +% \begin{macrocode} +\def_long_new:Npn \KV_split_key_value_no_space_removal:w #1#2=#3=#4\q_nil{ + \tlp_set:Nn\l_KV_tmpa_tlp{#4} + \tlp_if_empty:NTF \l_KV_tmpa_tlp + { + \toks_put_right:Nn\l_KV_parse_toks{\KV_key_no_value_elt:n{#2}} + } + { + \tlp_if_eq:NNTF\c_KV_single_equal_sign_tlp\l_KV_tmpa_tlp + { + \toks_put_right:Nn\l_KV_parse_toks{\KV_key_value_elt:nn{#2}{#3}} + } + {\ERROR} + } +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\KV_key_no_value_elt:n} +% \begin{macro}{\KV_key_value_elt:nn} +% \begin{macrocode} +\def_long_new:Npn \KV_key_no_value_elt:n #1{\ERROR} +\def_long_new:Npn \KV_key_value_elt:nn #1#2{\ERROR} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% +% \begin{macro}{\KV_parse_no_space_removal_no_sanitize:n} +% Finally we can put all the things +% together. |\KV_parse_no_space_removal_no_sanitize:n| is the +% version that disallows unmatched conditional and does no space +% removal. +% \begin{macrocode} +\def_new:Npn \KV_parse_no_space_removal_no_sanitize:n { + \let:NN \KV_split_key_value_current:w \KV_split_key_value_no_space_removal:w + \KV_parse_no_sanitize_aux:n +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KV_parse_space_removal_sanitize:n} +% \begin{macro}{\KV_parse_space_removal_no_sanitize:n} +% The other varieties can be defined in a similar manner. For the +% version needed at the document level, we can use this one. +% \begin{macrocode} +\def_new:Npn \KV_parse_space_removal_sanitize:n { + \let:NN \KV_split_key_value_current:w \KV_split_key_value_space_removal:w + \KV_parse_sanitize_aux:n +} +% \end{macrocode} +% For preamble use by the non-programmer this is probably best. +% \begin{macrocode} +\def_new:Npn \KV_parse_space_removal_no_sanitize:n { + \let:NN \KV_split_key_value_current:w \KV_split_key_value_space_removal:w + \KV_parse_no_sanitize_aux:n +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macrocode} +%</initex|package> +%<*showmemory> +\showMemUsage +%</showmemory> +% \end{macrocode} +% +% \endinput +% +% $Log$ +% Revision 1.4 2006/07/25 22:38:58 morten +% Removed spurious \exp_after:NN in \KV_add_value_element:w. Sigh. +% +% Revision 1.3 2006/07/25 22:34:03 morten +% Fixed silly bug in \KV_set_key_element:w plus clean-up of code +% +% Revision 1.2 2006/07/25 16:21:30 morten +% Allow values to contain unmatched conditionals such as `val +% \fi:'. Provide option to not strip any braces at all. +% +% Revision 1.1 2006/01/27 10:14:24 morten +% Initial version of keyval parser +% diff --git a/Master/texmf-dist/source/latex/expl3/l3messages.dtx b/Master/texmf-dist/source/latex/expl3/l3messages.dtx new file mode 100644 index 00000000000..5aea5a26d35 --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3messages.dtx @@ -0,0 +1,972 @@ +% \iffalse +%% File: l3messages.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} +%<package>\RequirePackage{l3basics} +%<package>\RequirePackage{l3tlp} +%<package>\RequirePackage{l3expan} +%<package>\RequirePackage{l3num} +%<package>\RequirePackage{l3io} +%<package>\RequirePackage{l3int} +%<package>\RequirePackage{l3toks} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3messages.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental LaTeX Messages module} +% +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3messages.dtx} +\end{document} +%</driver> +% \fi +% +% +% \section{Communicating with the user} +% +% Sometimes it is necesary to pass information back to the user +% about what is going on. The information can be just that, +% information, or it can be a warning that something might not +% happen to his expectation. It could also be that something has +% gone awry and that processing can't reliably continue without +% some help from the user. In such a case an error is signalled. +% When things are really bad, processing may have to stop as there +% is no way to enter additional commands that put things right +% again. In such a case we have a fatal error and the \LaTeX\ run +% will be aborted. +% +% \subsection{Displaying the information} +% +% First of all we need a couple of fairly low level functions that +% deal with the job of passing the information to the user. +% +% Real information is usually only written to the log file, while +% warnings are displayed on the screen as well. +% \begin{function}{% +% \err_info:nn | +% \err_warn:nn +% } +% \begin{syntax} +% "\err_info:nn" "{" <message> "}" "{"<continuation>"}" +% \end{syntax} +% The <message> will be written to the log file. When it contains +% the command "\err_newline:" a line break will occur and the new +% line will start with the <continuation>. The function +% "\err_warn:nn" writes the message to the terminal as well. +% \end{function} +% When an erroneous situation is encountered, a message is +% displayed and the user is given the opportunity to enter some +% additional code in an attempt to put things right. He may first +% ask for some help, in which case some extra text will be +% displayed to him. +% \begin{function}{\err_interrupt:NNw} +% \begin{syntax} +% "\err_interrupt:NNw" <err id> <label> <more args> +% \end{syntax} +% This function signals a user error by searching the error file +% denoted by <err id> for an error message associated with <label>, +% i.e., specified by a corresponding "\err_interrupt_new:NNNnnn" +% command. Depending on the number of arguments specified as +% <argno> when the error message was defined, further arguments are +% read. Then the error message is displayed as explained in +% "\err_interrupt_new:NNNnnn". +% \end{function} +% +% Finally, when something really serious occurs, \LaTeX\ will tell +% the user about it and abort the run. +% \begin{function}{\err_fatal:nn} +% \begin{syntax} +% "\err_fatal:nn" "{" <message> "}" "{"<continuation>"}" +% \end{syntax} +% Just displays the <message> and then aborts the \LaTeX\ run. +% \end{function} +% +% \begin{function}{\err_newline:} +% \begin{syntax} +% "\err_newline:" +% \end{syntax} +% Is used to break an informational, warning or error message up +% into multiple lines. May be defined in such a way that the new +% line starts with a standard <continuation>. +% \end{function} +% +% \subsection{Storing the information} +% +% The informational and warning messages are usually short and can +% be stored as part of a macro; but error messages need to be more +% verbose. Therefor error messages are stored in external files +% which are read and searched for the correct error message at the +% time of the error. In this way it is possible to write extensive +% help texts without cluttering \TeX{}'s main memory. +% +% \subsubsection{Dealing with the error file} +% +% \begin{function}{\err_file_new:Nn} +% \begin{syntax} +% "\err_file_new:Nn" <err id> "{"<err file name>"}" +% \end{syntax} +% Opens a new error file to write errors to. <err id> is a unique +% identifier for the external <err file name>. By convention <err +% id> is declared as a constant (i.e., starts with "\c_") und ends +% with "_tlp". If this command is issued while some other error +% file is open we get an internal error message. +% \end{function} +% +% \begin{function}{\err_file_close:N} +% \begin{syntax} +% "\err_file_close:N" <err id> +% \end{syntax} +% Closes the currently open error file and checks that it matches +% <err id>, i.e., that everything is alright in the code. +% \end{function} +% +% \subsubsection{Declaring an error message in the error file} +% \begin{function}{\err_interrupt_new:NNNnnn} +% \begin{syntax} +% "\err_interrupt_new:NNNnnn" <err id> <label> <argno> +% "{" <short msg> "}" +% "{" <long msg> "}" +% "{" <recovery code> "}" +% \end{syntax} +% This function declares an new error message which can be +% addressed via "\err_interrupt:NNw". The pair (<err id>, <label>) +% has to be unique where <label> can be some otherwise arbitrary +% token (usually the function name in which the error routine is +% called. Actually, the pair (<err id>, expansion of <label>) has +% to be unique since for reasons of speed, tests are carried out +% using "\if_meaning:NN". +% +% <argno> specifies the number of extra arguments that will be +% supplied to the error routine when "\err_interrupt:NNw" is +% called. These arguments can be used within <short msg>, <long +% msg>, and/or <recovery code> to provide further information to +% the user. They are denoted with "#1", "#2", etc.\ within these +% arguments. +% +% The <short msg> is displayed directly on the terminal if the +% error occurs, <long msg> is displayed when the user types "h" in +% response to the error prompt of \TeX{}, and <recovery code> is +% executed afterwards. This means that <recovery code> is inserted +% after any deletions or insertions given by the user. All three +% arguments are expanded while they are written to the error file, +% therefore one has to prevent expansion of tokens with +% "\token_to_string:N" that should be expanded when the error is +% triggered. +% \end{function} +% +% \subsection{Internal functions} +% +% \begin{function}{\err_display_aux:w} +% This function is constructed on the fly while reading the error file. +% It grabs following arguments from the code (if any) and then displays +% the error message and inserts the <recovery code>. +% \end{function} +% +% \begin{function}{\err_interrupt_new_aux:w} +% Helper function used to write the error message info onto the error +% file. +% \end{function} +% +% \begin{function}{\err_msgline_aux:NNnnn} +% \begin{syntax} +% "\err_msgline_aux:NNnnn" <argno> <label> "{"<short>"}" +% "{"<long msg>"}{"<recovery code>"}" +% \end{syntax} +% Function written in front of every error message on the error file. It +% will be executed when the error file is read back in comparing <label> +% to "\l_err_label_token". If they are the same, "\err_display_aux:w" +% will be defined and the reading process will stop. +% \end{function} +% +% \begin{function}{\err_message:x} +% \begin{syntax} +% "\err_message:x" "{"<error message>"}" +% \end{syntax} +% Function that directly triggers \TeX{}'s error handler. It should +% not be used directly. +% \begin{texnote} +% This is the \LaTeX3 name for the \tn{errormessage} primitive. +% \end{texnote} +% \end{function} +% +% \subsection{Kernel specific functions} +% +% For a number of the functions described above specific variants +% are provided that are used in the kernel of \LaTeX3. +% +% \begin{function}{% +% \err_kernel_info:n | +% \err_kernel_warn:n | +% \err_kernel_fatal:n +% } +% \begin{syntax} +% "\err_kernel_info:n" "{"<message>"}" +% \end{syntax} +% \end{function} +% \begin{function}{% +% \err_kernel_interrupt:Nw | +% \err_kernel_interrupt_new:NNnnn | +% } +% Abbrivations for writing and accessing kernel error messages that +% go to the error file "\c_kernel_err_tlp". +% \end{function} +% +% \begin{function}{\err_latex_bug:x} +% \begin{syntax} +% "\err_latex_bug:x" "{"<error message>"}" +% \end{syntax} +% Creates an internal error message. This is intended to be used in +% places that should not be reached in normal operation. Something is +% wrong with the code. +% \end{function} +% +% \subsection{Variables and constants} +% +% \begin{variable}{\iow_newline} +% Identifier denoting the character that triggers a line break in +% the output. +% \end{variable} +% +% \begin{variable}{\c_iow_err_stream} +% Output stream used to access the error files during their +% generation. +% \end{variable} +% +% \begin{variable}{\c_kernel_err_tlp} +% Identifier denoting the kernel error file. (Its contents is the +% name of the external file.) +% \end{variable} +% +% \begin{variable}{\g_err_curr_fname} +% Global variable containing the name of the currently open error +% file. Empty when no such file is open for writing. +% \end{variable} +% +% \begin{variable}{\tex_errorcontextlines:D} +% Variable determining the amount of macro expansion contents shown +% to the user when an error is triggered. \LaTeX3 sets this to -1 +% since to the average user this contents is of no interest. +% \begin{texnote} +% This is the \LaTeX3 name for the \TeX3 primitive +% \tn{errorcontextlines}. +% \end{texnote} +% \end{variable} +% +% \begin{variable}{\g_err_help_toks} +% Token register that holds the message that will be shown if the +% user types "h" in response to an error message that was produced +% by "\err_message:x". +% \begin{texnote} +% This is the \LaTeX3 name for the \TeX\ primitive \tn{errhelp}. +% \end{texnote} +% \end{variable} +% +% \begin{variable}{\l_err_label_token} +% Variable holding the <label> to look up in an error file. +% \end{variable} +% +% \StopEventually{} +% +% \subsection{The implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \subsubsection{Code to be moved to other modules} +% +% \begin{macro}{\g_file_curr_name_tlp} +% This variable is used to store the name of the file currently +% being processed. It should be part of the code that defines the +% higher level I/O commands. +% \begin{macrocode} +\tlp_new:Nn \g_file_curr_name_tlp {no~file} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\err_message:x} +% The \LaTeX3 name for a \TeX\ primitive. This should perhaps move +% to \texttt{l3names.dtx}. +% \begin{macrocode} +\let_new:NN \err_message:x \tex_errmessage:D +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\text_put_sp:} +% \begin{macro}{\text_put_four_sp:} +% We need these functions for certain error and warning messages +% right away. They put one and four spaces into the message stream. +% \begin{macrocode} +\def_new:Npn \text_put_sp: {~} +\def_new:Npn \text_put_four_sp: {\text_put_sp: \text_put_sp: + \text_put_sp: \text_put_sp: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\cmd_arg_list_build} +% This macro takes a digit as its argument and creates a string of +% |#| characters and argument numbers, such as |##1##2##3|. This +% list can then later be used in defining a new macro. +% To do this it locally uses a count register and a token +% register. +% +% \begin{macrocode} +\def:Npn\cmd_arg_list_build#1{ +% \end{macrocode} +% First we need to make sure that the token register we will be +% using for temporary storage is empty. +% \begin{macrocode} + \toks_clear:N\l_tmpb_toks +% \end{macrocode} +% Then we can store the argument in a count register that will be +% decremented untill it's value is zero. Beacuse of the use of the +% result of this macro, the argument needs to be between 1 and 9; +% this could be tested, but such a test is not (yet) added. +% \begin{macrocode} + \int_set:Nn \l_tmpa_int {#1} + \int_while:nNnT \l_tmpa_int > \c_zero { +% \end{macrocode} +% In the loop we first add the value of our counter to the contents +% of the token register; +% \begin{macrocode} + \toks_put_left:No \l_tmpb_toks {\the_internal:D\l_tmpa_int} +% \end{macrocode} +% and precede it with two hash marks. +% \begin{macrocode} + \toks_put_left:Nn \l_tmpb_toks {##} +% \end{macrocode} +% Now the count register is decremented and another iteration will +% follow so long as zero isn't reached. +% \begin{macrocode} + \int_decr:N\l_tmpa_int + } +% \end{macrocode} +% Finally the contents of the token register needs to be copied as +% the expansion of a local variable. +% \begin{macrocode} + \def:Npx\l_cmd_arg_list{\the_internal:D\l_tmpb_toks} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\cmd_declare:Nnn} +% This macro is a first replacement for \LaTeXe's |\newcommand|. It +% takes the name of a new macro as its first argument, the number +% of arguments for the new macro is taken as the second argument. +% \begin{macrocode} +\def:Npn\cmd_declare:Nnn#1[#2]{ + \cmd_arg_list_build{#2} + \exp_args:NNO\def:Npn#1\l_cmd_arg_list +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\io_show_file_lineno:} +% A function to add the number of the line and the name of the file +% to a message as an indication of where the message was triggered. +% \begin{macrocode} +\def_new:Npn \io_show_file_lineno:{ + on~line~\the_internal:D\tex_inputlineno:D\text_put_sp:~of~ + file~\g_file_curr_name_tlp} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Variables and constants} +% +% \begin{macro}{\g_err_help_toks} +% A token register to store the help text for an error message in. +% \begin{macrocode} +\let:NwN \g_err_help_toks \tex_errhelp:D +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\l_err_label_token} +% This will hold the current error label. +% \begin{macrocode} +\def_new:Npn \l_err_label_token {} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tex_errorcontextlines:D} +% Since we are producing our own error and help messages we can +% turn off the nasty stack information coming from \TeX{}'s +% stomach. +% \begin{macrocode} +\int_set:Nn\tex_errorcontextlines:D\c_minus_one +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Displaying the information} +% +% Here we define the fairly low level commands needed to +% communicate with the user. +% +% \begin{macro}{\err_info:nn} +% \begin{macro}{\err_warn:nn} +% Write a message to the log file ("\err_info:nn") or to both the +% log file and the terminal ("\err_warn:nn"). +% \begin{macrocode} +\def_new:Npn \err_info:nn #1#2{ +% \end{macrocode} +% Make sure that the \emph{continuation} is part of "\err_newline:". +% \begin{macrocode} + \def:Npn\err_newline:{\iow_newline#2} +% \end{macrocode} +% Then write the message. +% \begin{macrocode} + \io_put_log:x {#1~\io_show_file_lineno:}} +\def_new:Npn \err_warn:nn #1#2{ + \def:Npn\err_newline:{\iow_newline#2} + \io_put_term:x {#1~\io_show_file_lineno:}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\err_info_noline:nn} +% \begin{macro}{\err_warn_noline:nn} +% These variants of the above two functions don't add the +% linenumber to the message. +% \begin{macrocode} +\def_new:Npn \err_info_noline:nn #1#2{ + \def:Npn\err_newline:{\iow_newline#2} + \io_put_log:x {#1}} +\def_new:Npn \err_warn_noline:nn #1#2{ + \def:Npn\err_newline:{\iow_newline#2} + \io_put_term:x {#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\err_interrupt:NNw} +% |\err_interrupt:NNw| is the function that is called when some error +% occurs in the code. It takes at least two arguments, the +% \m{errfile} which is a token list that holds the name of the file +% where the error message should be fetched from, and the label to +% identify the error message in the error file. However, it may +% have additional arguments that are picked up by the error handler +% extracted from the error file. This is specified in the third +% argument to |\err_interrupt_new:NNNnnn|. +% \begin{macrocode} +\def_new:Npn \err_interrupt:NNw #1#2{\let:NwN \l_err_label_token #2 + \group_begin: +% \end{macrocode} +% For some reason we get some |\par|s into the file if we use the +% current definition of |\iow_long_unxepanded:N| to write the messages. +% This is probably a consequence of using token registers to +% prohibit the expansion of code. +% \begin{macrocode} + \let:NwN \par\use_noop: +% \end{macrocode} +% We want to ensure that we are not in programmer's mode (no spaces) +% but we want to switch on internal naming conventions. +% \begin{macrocode} + \CodeStop + \NamesStart: +% \end{macrocode} +% We better clear all short references that are active, otherwise +% we may get surprising results. +% \begin{macrocode} + %\clearshortrefmaps + \tex_input:D #1~\err_display_aux:w} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\err_fatal:nn} +% \begin{macro}{\err_fatal_noline:nn} +% Write a message to the log file and to the terminal. +% \begin{macrocode} +\def_new:Npn \err_fatal:nn #1#2{ +% \end{macrocode} +% Make sure that the \emph{continuation} is part of "\err_newline". +% \begin{macrocode} + \def:Npn\err_newline:{\iow_newline#2} +% \end{macrocode} +% Then write the message. +% \begin{macrocode} + \io_put_term:x {#1~\io_show_file_lineno:} +% \end{macrocode} +% Finally abort the \LaTeX{} run. +% \begin{macrocode} + \tex_end:D + } +% \end{macrocode} +% A variant that doesn't include the line number where the error +% occured. +% \begin{macrocode} +\def_new:Npn \err_fatal_noline:nn #1#2{ + \def:Npn\err_newline:{\iow_newline#2} + \io_put_term:x {#1} + \tex_end:D + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\err_newline:} +% |\err_newline:| is used to introduce a new line in an error +% message. I would like to use |\\| but this would mean +% redefinition which should be avoided to make the error message +% the last action before control is given to the user (otherwise +% something like |\group_end:| would interfere with +% insertions/deletions by the user). "\err_newline:" will be +% redefined by the various functions displaying messages to include +% the correct \emph{continuation}. +% \begin{macrocode} +\def_new:Npn \err_newline: {^^J} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Dealing with the error file} +% +% This section contains code that combines Michaels original thoughts +% on the the subject with Denys' further ideas. +% +% \begin{macro}{\c_iow_err_stream} +% Error messages are logged using the output stream +% |\c_iow_err_stream|. +% \begin{macrocode} +\iow_new:N \c_iow_err_stream +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_err_curr_fname} +% A nick name for the currently open error file. It is empty +% if no error file is currently open. +% \begin{macrocode} +\tlp_new:Nn \g_err_curr_fname{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\err_file_new:Nn} +% This function defines a new error file. The first argument is a +% token list which should hold the name of the error file, the second +% argument is the name of the error file. The token list should be +% a constant defined by this function. +% \begin{macrocode} +\def_new:Npn \err_file_new:Nn #1#2{ + \tlp_if_empty:NF\g_err_curr_fname + {\err_latex_bug:x{Unclosed~error~file~`\g_err_curr_fname'}} + \iow_open:Nn \c_iow_err_stream {#2} + \err_kernel_info:n{Errorfile~`#2'~opened~for~output} + \tlp_gset:Nn \g_err_curr_fname{#2} + \tlp_new:Nn #1{#2}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\err_file_close:N} +% This function closes the current error file. +% \begin{macrocode} +\def_new:Npn \err_file_close:N#1{ +% \end{macrocode} +% Before we close the stream, we write out a final error handler +% that catches mismatch within error message labels and their +% calls. Actually this should be integrated into +% |\err_file_new:Nn|, too. +% \begin{macrocode} + \tlp_if_eq:NNF#1\g_err_curr_fname + {\err_latex_bug:x{You~closed~the~wrong~error~file~`#1'.~ + Open~is~`\g_err_curr_fname'.}} + \iow_long_unexpanded:Nn \c_iow_err_stream {\err_latex_bug:x{Didn't~find~the~ + correct~error~message~to~show.\iow_newline + Was~searching~for~a~function~ + with~the~following~meaning:\iow_newline + \token_to_string:N\token_to_meaning:N + \token_to_string:N\l_err_label_token} +% \end{macrocode} +% The |\group_end:| here matches the one from |\err_interrupt:NNw| that +% is used to hide changes to |\par| etc. +% \begin{macrocode} + \group_end:} + \iow_close:N \c_iow_err_stream + \err_kernel_info:n{Errorfile~`\g_err_curr_fname'~closed} + \tlp_gset_eq:NN\g_err_curr_fname\c_empty_tlp +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Declaring an error message in the error file} +% +% \begin{macro}{\err_interrupt_new:NNNnnn} +% This function declares a new error message. +% |\err_interrupt_new:NNNnnn| \m{errfile} \m{errlabel} \m{argno} +% \m{errmsg} \m{helpmsg} \m{code}. That error message is fetched +% from the error file \m{errfile}. The label to search for is +% \m{errlabel}, the error handler has \m{argno} number of arguments +% (actually \m{argno} + 3 since the \m{errmsg}, \m{helpmsg} and +% \m{code} are also arguments), and \m{errmsg} is the message to +% display, \m{helpmsg} is the message that is displayed when the +% user enters |h|, while \m{code} is extra code to perform when the +% error occurs. \m{code} is perhaps not necessary, we will see. +% +% We have to check that the label associated with the error message +% is unique. This means that its replacement text (labels are +% simply arbitrary functions) is different from the replacement +% text of any other label in the same error set. +% \begin{macrocode} +\def_new:Npn \err_interrupt_new:NNNnnn #1{ +% \end{macrocode} +% Both \m{errmsg} and \m{code} might contain hashmarks denoting +% arguments to the error handler. +% \begin{macrocode} + \group_begin: \tex_catcode:D`\#\c_other_char_code +% \end{macrocode} +% We also have to check that output goes to the correct error file. +% \begin{macrocode} + \if_meaning:NN#1\g_err_curr_fname + \else: + \err_latex_bug:x{Error~text~goes~to~wrong~err~file:~ + `\g_err_curr_fname'~is~open~but~you~requested~ + `#1'} + \fi: + \err_interrupt_new_aux:w} +\def_long_new:Npn \err_interrupt_new_aux:w #1#2#3#4#5{ + \iow_long_unexpanded:Nn \c_iow_err_stream + {\err_msgline_aux:NNnnn #1#2{#3}{#4}{#5}\use_noop:} + \group_end:} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\err_msgline_aux:NNnnn} +% This function is executed when an error file is read back by +% |\err_interrupt:NNw|. It compares its first argument against +% |\l_err_label_token| using |\if_meaning:NN| and if this fails the +% function does nothing; otherwise it defines |\err_display_aux:w| in +% a way that it will pick up the arguments (if any) from the code and +% generates a suitable error message. +% \begin{macrocode} +\def_new:Npn \err_msgline_aux:NNnnn #1#2#3#4#5{ + \if_meaning:NN#1\l_err_label_token +% \end{macrocode} +% At the moment we simply use the old \LaTeX{} error code and +% |\renewcommand| to generate the error handler. After displaying +% the error message we insert error code this can be manipulated by +% the user with the deletion/insertion facility of \TeX{}'s error +% mechanism. +% +% The |\group_end:| at the very beginning matches the +% |\group_begin:| when the file starts. +% \begin{macrocode} + \cmd_declare:Nnn\err_display_aux:w [#2]{ + \group_end: + \toks_gset:Nx\g_err_help_toks{#4} + \io_put_term:x{LaTeX~error~\io_show_file_lineno:.\iow_newline + \text_put_sp:\text_put_four_sp: \text_put_sp: + See~LaTeX~manual~for~explanation.\iow_newline + \text_put_sp:\text_put_four_sp: \text_put_sp: + Type~\text_put_sp: H~<return>~\text_put_sp: for~ + immediate~help.} + \err_message:x{#3} + #5} + \tex_endinput:D + \fi:} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\err_display_aux:w} +% We should make sure that this function is definable. +% \begin{macrocode} +\def_new:Npn \err_display_aux:w {} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Kernel specific functions} +% +% \begin{macro}{\err_kernel_interrupt:Nw} +% |\err_kernel_interrupt:Nw | is just the abbreviation to read from +% the standard system error file. +% \begin{macrocode} +\def_new:Npn \err_kernel_interrupt:Nw {\err_interrupt:NNw \c_kernel_err_tlp} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\err_kernel_interrupt_new:NNnnn} +% To ease the coding in case of system messages that should all go +% to one and the same error file (if!) we also have the following +% function. +% \begin{macrocode} +\def_new:Npn \err_kernel_interrupt_new:NNnnn { + \err_interrupt_new:NNNnnn \c_kernel_err_tlp} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\err_kernel_info:n} +% \begin{macro}{\err_kernel_warn:n} +% \begin{macro}{\err_kernel_fatal:n} +% \begin{macro}{\err_kernel_info_noline:n} +% \begin{macro}{\err_kernel_warn_noline:n} +% \begin{macro}{\err_kernel_fatal_noline:n} +% These variants are specific for the \LaTeX\ kernel. +% \begin{macrocode} +\def_new:Npn \err_kernel_info:n #1 { + \err_info:nn {LaTeX~Info:~#1} + {\text_put_four_sp:\text_put_four_sp:\text_put_four_sp:} + } +\def_new:Npn \err_kernel_warn:n #1 { + \err_warn:nn {LaTeX~Warning:~#1} + {\text_put_sp:\text_put_sp:\text_put_sp: + \text_put_four_sp:\text_put_four_sp:\text_put_four_sp:} + } +\def_new:Npn \err_kernel_fatal:n #1 { + \err_fatal:nn {LaTeX~Fatal:~#1} + {\text_put_sp: + \text_put_four_sp:\text_put_four_sp:\text_put_four_sp:} + } +\def_new:Npn \err_kernel_info_noline:n #1 { + \err_info_noline:nn {LaTeX~Info:~#1} + {\text_put_four_sp:\text_put_four_sp:\text_put_four_sp:} + } +\def_new:Npn \err_kernel_warn_noline:n #1 { + \err_warn_noline:nn {LaTeX~Warning:~#1} + {\text_put_sp:\text_put_sp:\text_put_sp: + \text_put_four_sp:\text_put_four_sp:\text_put_four_sp:} + } +\def_new:Npn \err_kernel_fatal_noline:n #1 { + \err_fatal_noline:nn {LaTeX~Fatal:~#1} + {\text_put_sp: + \text_put_four_sp:\text_put_four_sp:\text_put_four_sp:} + } +%</initex|package> +% \end{macrocode} +% At a later stage variants may be provided for what in \LaTeXe{} +% used to be called document classes and packages. +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\c_kernel_err_tlp} +% Most error messages will go to the system error file; it's name is +% stored in |\c_kernel_err_tlp|. +% \begin{macrocode} +%<initex>\err_file_new:Nn \c_kernel_err_tlp {ltxkernel.err} +%<package>\err_file_new:Nn \c_kernel_err_tlp {l3in2e.err} +% \end{macrocode} +% \end{macro} +% +% The code below is a temporary implementation of a few of +% \LaTeX209 error messages with the new syntax. They are only +% included in the package as the \LaTeX3 kernel will certainly have +% it's own error message definitions that differ from \LaTeXe's way +% of signalling errors. These primarily serve as an example on how +% to use this concept of dealing with errors. +% +% First we declare a couple of helper macros that contain texts +% that are used frequently throughout \LaTeX. +% \begin{macrocode} +%<*package> +\def:Npn\err_help_ignored: { + Your~command~was~ignored.\iow_newline + Type \text_put_sp: I~<command>~<return> + \text_put_sp: to~replace~it~with~another~command,\iow_newline + or~\text_put_sp: <return> \text_put_sp: to~continue~without~it.} + +\def:Npn\err_help_textlost: { + You've~lost~some~text.\text_put_sp: \err_help_return_or_X:} + +\def:Npn\err_help_return_or_X: { + Try~typing\text_put_sp: <return> + \text_put_sp: to~proceed.\iow_newline + If~that~doesn't~work,~type + \text_put_sp: X~<return>\text_put_sp: to~quit.} + +\def:Npn\err_help_trouble: { + You're~ in~ trouble~ here. + \text_put_sp:\err_help_return_or_X:} +% \end{macrocode} +% +% Below are the definitions of the complete messages +% \begin{macrocode} + +\err_kernel_interrupt_new:NNnnn\cs_free_p:N{1} + {Command~name~`\tex_string:D#1'~already~used} + {You~tried~to~define~a~command~which~already~has~ + a~meaning.\iow_newline + If~you~really~want~to~redefine~it~try~ + \token_to_string:N\cmd_declare:Nnn\text_put_sp: + next~time.\iow_newline + For~this~run~I~will~ignore~your~definition.} + {} + +\err_kernel_interrupt_new:NNnnn\newline{0} + {There's~no~line~here~to~end} + {You~tried~to~end~a~line~at~a~place~where~I~thought~ + we~were~already~between~paragraphs.} + {} + +\err_kernel_interrupt_new:NNnnn\newcnt{0} + {No~such~counter} + {The~counter~name~mentioned~in~the~operation~is~not~ + known~to~me.\iow_newline + Check~the~spelling.} + {} + +\err_kernel_interrupt_new:NNnnn\nodocument{0} + {Missing~\token_to_string:N\begin{document}} + {\err_help_trouble:} + {} + +\err_kernel_interrupt_new:NNnnn\badmath{0} + {Bad~math~environment~delimiter} + {\err_help_ignored:} + {} + +\err_kernel_interrupt_new:NNnnn\toodeep{0} + {Too~deeply~nested} + {\err_help_trouble:} + {} + +\err_kernel_interrupt_new:NNnnn\badpoptabs{0} + {\token_to_string:N\pushtabs \text_put_sp: + and~\token_to_string:N\poptabs + \text_put_sp: don't~match} + {\err_help_trouble:} + {} + +\err_kernel_interrupt_new:NNnnn\badtab{0} + {Undefined~tab~position} + {\err_help_trouble:} + {} + +\err_kernel_interrupt_new:NNnnn\preamerr{} + {\if_case:w #1~Illegal~character\or: + Missing~@-exp\or: Missing~p-arg\fi:\text_put_sp: + in~array~arg} + {\err_help_trouble:} + {} + +\err_kernel_interrupt_new:NNnnn\badlinearg{} + {Bad~\token_to_string:N\line + \text_put_sp: or~\token_to_string:N\vector + \text_put_sp: argument} + {\err_help_textlost:} + {} + +\err_kernel_interrupt_new:NNnnn\parmoderr{0} + {Not~in~outer~par~mode} + {\err_help_textlost:} + {} + +\err_kernel_interrupt_new:NNnnn\fltovf{0} + {Too~many~unprocessed~floats} + {\err_help_textlost:} + {} + +\err_kernel_interrupt_new:NNnnn\badcrerr{0} + {Bad~use~of~\token_to_string:N\\} + {\err_help_return_or_X:} + {} + +\err_kernel_interrupt_new:NNnnn\noitemerr{0} + {Something's~wrong--perhaps~a~missing~ + \token_to_string:N\item} + {\err_help_return_or_X:} + {} + +\err_kernel_interrupt_new:NNnnn\notprerr{0} + {Can~be~used~only~in~preamble} + {\err_help_ignored:} + {} + +\err_file_close:N\c_kernel_err_tlp +%<package> +% \end{macrocode} +% +% +% Show token usage: +% \begin{macrocode} +%<*showmemory> +\showMemUsage +%</showmemory> +% \end{macrocode} +% +% \endinput +% +% $Log$ +% Revision 1.9 2006/03/19 15:07:47 braams +% Moved some code to other modules, where it belongs; +% reverted \c_io_newline to \iow_newline (it'scontents might need to be +% modified sometine) +% Example messages are not part of the kernel, only for the package. +% +% Revision 1.8 2006/02/15 23:45:46 braams +% Rearranged the file; +% implemented \err_fatal:nn and \err_fatal_noline:nn +% Recode the remaining error definitions for testing purposes +% +% Revision 1.7 2006/01/15 09:48:54 braams +% Mostly textual changes +% +% Revision 1.6 2005/12/27 16:01:27 morten +% Changed RCS information retrieval plus a few minor changes +% +% Revision 1.5 2005/05/05 23:45:49 braams +% Worked on the documentation; +% added commands \err_info:nn, \err_warn:nn and kernel specific versions +% of these. +% Changed \iow_newline: into \c_io_newline; introduced \err_newline: to +% be used in messages with multiple lines to provide a continuation +% string. +% Renamed \style_names_start and \style_names_stop: into \NamesStart: +% and \NamesStop:. +% +% Revision 1.4 2005/05/03 23:34:52 braams +% Added code that performs the basic function of the old \renewcommand +% Added a couple of new functions that need to live in other modules +% Documentation still needs to be corrected +% The module now basically works +% +% Revision 1.3 2005/04/29 22:39:47 braams +% Another one +% +% Revision 1.2 2005/04/29 22:34:39 braams +% Small typo in the RCS tags +% +% Revision 1.1 2005/04/29 22:30:44 braams +% first version that can be loaded without producing errors. +% Just a translation from the old stuff, haven't looked at the docu yet
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/expl3/l3names.dtx b/Master/texmf-dist/source/latex/expl3/l3names.dtx index 1f981eb2d45..e9345ce37e0 100644 --- a/Master/texmf-dist/source/latex/expl3/l3names.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3names.dtx @@ -1,27 +1,78 @@ % \iffalse -%% File: l3names.dtx Copyright (C) 1990-1997 LaTeX3 project -% +%% File: l3names.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%^^A We need some basic initial character codes to be set up +%^^A immediately. +%<*initex> +\catcode`\{=1 % left brace is begin-group character +\catcode`\}=2 % right brace is end-group character +\catcode`\#=6 % hash mark is macro parameter character +\catcode`\^=7 % +\catcode`\^^I=10 % ascii tab is a blank space +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \immediate\write-1{#1; v#2, #3/#4/#5; #8}% +} +%</initex> +%<*package> +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesPackage{#1}[#3/#4/#5 v#2 #8]% +} +%</package> %<*dtx> - \ProvidesFile{l3names.dtx} +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse %</dtx> -%<package>\NeedsTeXFormat{LaTeX2e} -%<package>\ProvidesPackage{l3names} -%<driver> \ProvidesFile{l3names.drv} -% \fi -% \ProvidesFile{l3names.dtx} - [1998/04/20 v2.0b L3 Experimental Naming Scheme for TeX Primitives] +%\fi +\GetIdInfo$Id: l3names.dtx 577 2006-11-21 18:10:26Z morten $ + {L3 Experimental Naming Scheme for TeX Primitives} +% % % \iffalse %<*driver> \documentclass{l3doc} - \begin{document} \DocInput{l3names.dtx} \end{document} %</driver> % \fi % -% \GetFileInfo{l3names.dtx} % \title{The \textsf{l3names} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ @@ -108,7 +159,7 @@ % token without any braces around it. % % \item[w] One or more arguments with ``weird'' syntax that one has -% to know by hard or better leave it alone. +% to know by heart or better leave it alone. % % \item[p] Denotes parameter text specification part, e.g.\^^M % |#1#2\q_stop#3|. @@ -132,9 +183,9 @@ % \end{description} % % One could perhaps envisage an extended system which allocated -% lettters to denote the various primitive argument types available in +% letters to denote the various primitive argument types available in % \TeX, however it seems that this just complicates the system -% withoutadding any real benefit, as these primitives would never be +% without adding any real benefit, as these primitives would never be % used in production code, as higher level packages should offer a % better interface. Thus the following letters, although they were % considered have not been used. ``D'' is used in most cases in @@ -223,17 +274,17 @@ % % \end{description} % -% +% % % \section{Modules} -% +% % Nearly all operations of \LaTeX3 are carried out by calling control % sequences. For better programming concepts many types of functions are % identified and gathered in modules. Functions in such modules starts % with special prefixes, for example "\tlp_" is the prefix for functions % dealing with token list pointers. -% -% +% +% % % \StopEventually{} % @@ -295,7 +346,7 @@ % \begin{macrocode} %<*initex> \long\def\name_undefine:N#1{ - \tex_let:D#1\tex_undefined:} + \tex_let:D#1\c_undefined} %</initex> % \end{macrocode} % @@ -303,7 +354,7 @@ %<*package> \DeclareOption{removeoldnames}{ \long\def\name_undefine:N#1{ - \tex_let:D#1\tex_undefined:}} + \tex_let:D#1\c_undefined}} % \end{macrocode} % % \begin{macrocode} @@ -342,7 +393,7 @@ \name_primitive:NN \/ \tex_italiccor:D \name_primitive:NN \- \tex_hyphen:D % \end{macrocode} -% +% % Now all the other primitives. % \begin{macrocode} \name_primitive:NN \let \tex_let:D @@ -473,6 +524,7 @@ \name_primitive:NN \textstyle \tex_textstyle:D \name_primitive:NN \scriptstyle \tex_scriptstyle:D \name_primitive:NN \scriptscriptstyle \tex_scriptscriptstyle:D +\name_primitive:NN \nonscript \tex_nonscript:D \name_primitive:NN \eqno \tex_eqno:D \name_primitive:NN \leqno \tex_leqno:D \name_primitive:NN \abovedisplayshortskip \tex_abovedisplayshortskip:D @@ -568,6 +620,7 @@ \name_primitive:NN \tolerance \tex_tolerance:D \name_primitive:NN \spaceskip \tex_spaceskip:D \name_primitive:NN \xspaceskip \tex_xspaceskip:D +\name_primitive:NN \parfillskip \tex_parfillskip:D \name_primitive:NN \everypar \tex_everypar:D \name_primitive:NN \prevgraf \tex_prevgraf:D \name_primitive:NN \spacefactor \tex_spacefactor:D @@ -667,13 +720,206 @@ \name_primitive:NN \mathcode \tex_mathcode:D % \end{macrocode} % +% +% +% +% Since \LaTeX3 will require at least the \eTeX{} extensions, +% we also rename the additional primitives. These are all +% given the prefix |\etex_|. +% \begin{macrocode} +\name_primitive:NN \ifdefined \etex_ifdefined:D +\name_primitive:NN \ifcsname \etex_ifcsname:D +\name_primitive:NN \unless \etex_unless:D +\name_primitive:NN \eTeXversion \etex_eTeXversion:D +\name_primitive:NN \eTeXrevision \etex_eTeXrevision:D +\name_primitive:NN \marks \etex_marks:D +\name_primitive:NN \topmarks \etex_topmarks:D +\name_primitive:NN \firstmarks \etex_firstmarks:D +\name_primitive:NN \botmarks \etex_botmarks:D +\name_primitive:NN \splitfirstmarks \etex_splitfirstmarks:D +\name_primitive:NN \splitbotmarks \etex_splitbotmarks:D +\name_primitive:NN \unexpanded \etex_unexpanded:D +\name_primitive:NN \detokenize \etex_detokenize:D +\name_primitive:NN \scantokens \etex_scantokens:D +\name_primitive:NN \showtokens \etex_showtokens:D +\name_primitive:NN \readline \etex_readline:D +\name_primitive:NN \tracingassigns \etex_tracingassigns:D +\name_primitive:NN \tracingscantokens \etex_tracingscantokens:D +\name_primitive:NN \tracingnesting \etex_tracingnesting:D +\name_primitive:NN \tracingifs \etex_tracingifs:D +\name_primitive:NN \currentiflevel \etex_currentiflevel:D +\name_primitive:NN \currentifbranch \etex_currentifbranch:D +\name_primitive:NN \currentiftype \etex_currentiftype:D +\name_primitive:NN \tracinggroups \etex_tracinggroups:D +\name_primitive:NN \currentgrouplevel \etex_currentgrouplevel:D +\name_primitive:NN \currentgrouptype \etex_currentgrouptype:D +\name_primitive:NN \showgroups \etex_showgroups:D +\name_primitive:NN \showifs \etex_showifs:D +\name_primitive:NN \interactionmode \etex_interactionmode:D +\name_primitive:NN \lastnodetype \etex_lastnodetype:D +\name_primitive:NN \iffontchar \etex_iffontchar:D +\name_primitive:NN \fontcharht \etex_fontcharht:D +\name_primitive:NN \fontchardp \etex_fontchardp:D +\name_primitive:NN \fontcharwd \etex_fontcharwd:D +\name_primitive:NN \fontcharic \etex_fontcharic:D +\name_primitive:NN \parshapeindent \etex_parshapeindent:D +\name_primitive:NN \parshapelength \etex_parshapelength:D +\name_primitive:NN \parshapedimen \etex_parshapedimen:D +\name_primitive:NN \numexpr \etex_numexpr:D +\name_primitive:NN \dimexpr \etex_dimexpr:D +\name_primitive:NN \glueexpr \etex_glueexpr:D +\name_primitive:NN \muexpr \etex_muexpr:D +\name_primitive:NN \gluestretch \etex_gluestretch:D +\name_primitive:NN \glueshrink \etex_glueshrink:D +\name_primitive:NN \gluestretchorder \etex_gluestretchorder:D +\name_primitive:NN \glueshrinkorder \etex_glueshrinkorder:D +\name_primitive:NN \gluetomu \etex_gluetomu:D +\name_primitive:NN \mutoglue \etex_mutoglue:D +\name_primitive:NN \lastlinefit \etex_lastlinefit:D +\name_primitive:NN \interlinepenalties \etex_interlinepenalties:D +\name_primitive:NN \clubpenalties \etex_clubpenalties:D +\name_primitive:NN \widowpenalties \etex_widowpenalties:D +\name_primitive:NN \displaywidowpenalties \etex_displaywidowpenalties:D +\name_primitive:NN \middle \etex_middle:D +\name_primitive:NN \savinghyphcodes \etex_savinghyphcodes:D +\name_primitive:NN \savingvdiscards \etex_savingvdiscards:D +\name_primitive:NN \pagediscards \etex_pagediscards:D +\name_primitive:NN \splitdiscards \etex_splitdiscards:D +\name_primitive:NN \TeXXETstate \etex_TeXXETstate:D +\name_primitive:NN \beginL \etex_beginL:D +\name_primitive:NN \endL \etex_endL:D +\name_primitive:NN \beginR \etex_beginR:D +\name_primitive:NN \endR \etex_endR:D +\name_primitive:NN \predisplaydirection \etex_predisplaydirection:D +\name_primitive:NN \everyeof \etex_everyeof:D +\name_primitive:NN \protected \etex_protected:D +% \end{macrocode} +% +% +% All major distributions\footnote{At the time of writing MiK\TeX\ +% does not but I have a gut feeling that will change.} use +% pdf\eTeX{} as engine so we add these names as well. Since the +% pdf\TeX{} team has been very good at prefixing most primitives +% with |pdf| (so far only five do not start with |pdf|) we do not +% give then a double |pdf| prefix. The list below covers pdf\TeX +% v~1.30.4. +% \begin{macrocode} +%% integer registers: +\name_primitive:NN \pdfoutput \pdf_output:D +\name_primitive:NN \pdfminorversion \pdf_minorversion:D +\name_primitive:NN \pdfcompresslevel \pdf_compresslevel:D +\name_primitive:NN \pdfdecimaldigits \pdf_decimaldigits:D +\name_primitive:NN \pdfimageresolution \pdf_imageresolution:D +\name_primitive:NN \pdfpkresolution \pdf_pkresolution:D +\name_primitive:NN \pdftracingfonts \pdf_tracingfonts:D +\name_primitive:NN \pdfuniqueresname \pdf_uniqueresname:D +\name_primitive:NN \pdfadjustspacing \pdf_adjustspacing:D +\name_primitive:NN \pdfprotrudechars \pdf_protrudechars:D +\name_primitive:NN \efcode \pdf_efcode:D +\name_primitive:NN \lpcode \pdf_lpcode:D +\name_primitive:NN \rpcode \pdf_rpcode:D +\name_primitive:NN \pdfforcepagebox \pdf_forcepagebox:D +\name_primitive:NN \pdfoptionalwaysusepdfpagebox \pdf_optionalwaysusepdfpagebox:D +\name_primitive:NN \pdfinclusionerrorlevel\pdf_inclusionerrorlevel:D +\name_primitive:NN \pdfoptionpdfinclusionerrorlevel \pdf_optionpdfinclusionerrorlevel:D +\name_primitive:NN \pdfimagehicolor \pdf_imagehicolor:D +\name_primitive:NN \pdfimageapplygamma \pdf_imageapplygamma:D +\name_primitive:NN \pdfgamma \pdf_gamma:D +\name_primitive:NN \pdfimagegamma \pdf_imagegamma:D +%% dimen registers: +\name_primitive:NN \pdfhorigin \pdf_horigin:D +\name_primitive:NN \pdfvorigin \pdf_vorigin:D +\name_primitive:NN \pdfpagewidth \pdf_pagewidth:D +\name_primitive:NN \pdfpageheight \pdf_pageheight:D +\name_primitive:NN \pdflinkmargin \pdf_linkmargin:D +\name_primitive:NN \pdfdestmargin \pdf_destmargin:D +\name_primitive:NN \pdfthreadmargin \pdf_threadmargin:D +%% token registers: +\name_primitive:NN \pdfpagesattr \pdf_pagesattr:D +\name_primitive:NN \pdfpageattr \pdf_pageattr:D +\name_primitive:NN \pdfpageresources \pdf_pageresources:D +\name_primitive:NN \pdfpkmode \pdf_pkmode:D +%% expandable commands: +\name_primitive:NN \pdftexrevision \pdf_texrevision:D +\name_primitive:NN \pdftexbanner \pdf_texbanner:D +\name_primitive:NN \pdfcreationdate \pdf_creationdate:D +\name_primitive:NN \pdfpageref \pdf_pageref:D +\name_primitive:NN \pdfxformname \pdf_xformname:D +\name_primitive:NN \pdffontname \pdf_fontname:D +\name_primitive:NN \pdffontobjnum \pdf_fontobjnum:D +\name_primitive:NN \pdffontsize \pdf_fontsize:D +\name_primitive:NN \pdfincludechars \pdf_includechars:D +\name_primitive:NN \leftmarginkern \pdf_leftmarginkern:D +\name_primitive:NN \rightmarginkern \pdf_rightmarginkern:D +\name_primitive:NN \pdfescapestring \pdf_escapestring:D +\name_primitive:NN \pdfescapename \pdf_escapename:D +\name_primitive:NN \pdfescapehex \pdf_escapehex:D +\name_primitive:NN \pdfunescapehex \pdf_unescapehex:D +\name_primitive:NN \pdfstrcmp \pdf_strcmp:D +\name_primitive:NN \pdfuniformdeviate \pdf_uniformdeviate:D +\name_primitive:NN \pdfnormaldeviate \pdf_normaldeviate:D +\name_primitive:NN \pdfmdfivesum \pdf_mdfivesum:D +\name_primitive:NN \pdffilemoddate \pdf_filemoddate:D +\name_primitive:NN \pdffilesize \pdf_filesize:D +\name_primitive:NN \pdffiledump \pdf_filedump:D +%% read-only integers: +\name_primitive:NN \pdftexversion \pdf_texversion:D +\name_primitive:NN \pdflastobj \pdf_lastobj:D +\name_primitive:NN \pdflastxform \pdf_lastxform:D +\name_primitive:NN \pdflastximage \pdf_lastximage:D +\name_primitive:NN \pdflastximagepages \pdf_lastximagepages:D +\name_primitive:NN \pdflastannot \pdf_lastannot:D +\name_primitive:NN \pdflastxpos \pdf_lastxpos:D +\name_primitive:NN \pdflastypos \pdf_lastypos:D +\name_primitive:NN \pdflastdemerits \pdf_lastdemerits:D +\name_primitive:NN \pdfelapsedtime \pdf_elapsedtime:D +\name_primitive:NN \pdfrandomseed \pdf_randomseed:D +\name_primitive:NN \pdfshellescape \pdf_shellescape:D +%% general commands: +\name_primitive:NN \pdfobj \pdf_obj:D +\name_primitive:NN \pdfrefobj \pdf_refobj:D +\name_primitive:NN \pdfxform \pdf_xform:D +\name_primitive:NN \pdfrefxform \pdf_refxform:D +\name_primitive:NN \pdfximage \pdf_ximage:D +\name_primitive:NN \pdfrefximage \pdf_refximage:D +\name_primitive:NN \pdfannot \pdf_annot:D +\name_primitive:NN \pdfstartlink \pdf_startlink:D +\name_primitive:NN \pdfendlink \pdf_endlink:D +\name_primitive:NN \pdfoutline \pdf_outline:D +\name_primitive:NN \pdfdest \pdf_dest:D +\name_primitive:NN \pdfthread \pdf_thread:D +\name_primitive:NN \pdfstartthread \pdf_startthread:D +\name_primitive:NN \pdfendthread \pdf_endthread:D +\name_primitive:NN \pdfsavepos \pdf_savepos:D +\name_primitive:NN \pdfinfo \pdf_info:D +\name_primitive:NN \pdfcatalog \pdf_catalog:D +\name_primitive:NN \pdfnames \pdf_names:D +\name_primitive:NN \pdfmapfile \pdf_mapfile:D +\name_primitive:NN \pdfmapline \pdf_mapline:D +\name_primitive:NN \pdffontattr \pdf_fontattr:D +\name_primitive:NN \pdftrailer \pdf_trailer:D +\name_primitive:NN \pdffontexpand \pdf_fontexpand:D +%%\name_primitive:NN \vadjust [<pre spec>] <filler> { <vertical mode material> } (h, m) +\name_primitive:NN \pdfliteral \pdf_literal:D +%%\name_primitive:NN \special <pdfspecial spec> +\name_primitive:NN \pdfresettimer \pdf_resettimer:D +\name_primitive:NN \pdfsetrandomseed \pdf_setrandomseed:D +\name_primitive:NN \pdfnoligatures \pdf_noligatures:D +% \end{macrocode} +% +% What about Omega and Aleph? The status of both are unclear but let's +% start by adding a single primitive which we can use for testing if +% we have one of these engines. +% \begin{macrocode} +\name_primitive:NN \textdir \aleph_textdir:D +% \end{macrocode} % \begin{macro}{\CodeStart} % \begin{macro}{\CodeStop} % Here we define functions that are used to turn on and off the -% special conventions used in the kernel of \LaTeX3. +% special conventions used in the kernel of \LaTeX3. % % First of all, the space, tab and the return characters will all be -% ignored inside \LaTeX3 code. When space characters are needed in +% ignored inside \LaTeX3 code. When space characters are needed in % \LaTeX3 code the |~| character will be used for that purpose. % % \begin{macrocode} @@ -701,13 +947,72 @@ % \end{macro} % \end{macro} % -% +% \begin{macro}{\NamesStart} +% \begin{macro}{\NamesStop} +% Sometimes we need to be able to use names from the kernel of +% \LaTeX3 without adhering it's conventions according to space +% characters. These macros provide the necessary settings. +% \begin{macrocode} +\tex_def:D \NamesStart{ + \tex_catcode:D `\_=11\scan_stop: + \tex_catcode:D `\:=11\scan_stop: + } +\tex_def:D \NamesStop{ + \tex_catcode:D `\_=8\scan_stop: + \tex_catcode:D `\:=12\scan_stop: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%<*initex> +\tex_def:D\GetIdInfo{\CodeStop\GetIdInfoAux} +\tex_def:D\GetIdInfoAux$#1~#2.dtx~#3~#4-#5-#6~#7~#8$#9{% + \tex_immediate:D\tex_write:D-1{#2;~v#3,~#4/#5/#6;~#9}% + \CodeStart +} +%</initex> +% \end{macrocode} +% % Finally some corrections in the case we are running over \LaTeXe. % +% Every single experimental package should start by doing something +% like this: +% \begin{verbatim} +% \RequirePackage{l3names} +% \GetIdInfo$Id: l3names.dtx 577 2006-11-21 18:10:26Z morten $ +% {L3 Experimental sequences and stacks} +% \end{verbatim} +% \emph{OR} +% \begin{verbatim} +% \RequirePackage{l3names} +% \CodeStart +% \end{verbatim} +% Since we have to make |\GetIdInfo| stop the special catcode regime +% when reading the package in order to get the information extracted +% correctly, we might as well use it to also issue |\CodeStart|. This +% also means that we automatically get |\CodeStart| issued at the +% beginning of every package without tampering with |\ProvidesPackage| +% which can cause problems when using these experimental packages with +% code relying on characters having traditional catcodes, noticeably +% the catcode of the space character. We cannot simply use the code +% from the top of this file since it contains a call to |\def| which +% may not exist at this point. +% \begin{macrocode} +%<*package> +\tex_def:D\GetIdInfo{\CodeStop\GetIdInfoAux} +\tex_def:D\GetIdInfoAux$#1~#2.dtx~#3~#4-#5-#6~#7~#8$#9{% + \tex_def:D \fileversion{#3}% + \tex_def:D \filedate{#4/#5/#6}% + \ProvidesPackage{#2}[#4/#5/#6~ v#3~ #9]% + \CodeStart +} +% \end{macrocode} +% % A few of the `primitives' assigned above have already been stolen % by \LaTeX, so assign them by hand to the saved real primitive. % \begin{macrocode} -%<*package> \tex_let:D\tex_input:D \@@input \tex_let:D\tex_underline:D \@@underline \tex_let:D\tex_end:D \@@end @@ -723,40 +1028,20 @@ \tex_let:D\par \tex_par:D % \end{macrocode} % -% As mentioned above, The \LaTeXe\ package mechanism will insert some code -% to handle the filename stack, and reset the package options, this -% code will die if the \TeX\ primitives have gone, so skip past it -% and insert some equivalent code that will work. -% -% First a version of |\ProvidesPackage| that can cope. -% \begin{macrocode} -\tex_def:D\ProvidesPackage{ - \tex_begingroup:D - \CodeStop - \package_provides:w} -% \end{macrocode} % -% \begin{macrocode} -\tex_def:D\package_provides:w#1#2[#3]{ - \tex_endgroup:D - \tex_immediate:D\tex_write:D-1{Package: #1#2 #3} - \tex_expandafter:D\tex_xdef:D - \tex_csname:D ver@#1.sty\tex_endcsname:D{}} -% \end{macrocode} % % \begin{macrocode} \tex_ifx:D\name_undefine:N\@gobble % \end{macrocode} % % Normally just set the catcodes, and let \LaTeXe\ handle the -% package stack. If \LaTeXe\ resets @ reset the white space as well. +% package stack. If \LaTeXe\ resets @ reset the white space as well. % \begin{macrocode} \tex_def:D\name_pop_stack:w{} \g@addto@macro\@popfilename{% \tex_ifnum:D12=\tex_the:D\tex_catcode:D`@ \CodeStop \tex_fi:D} - \g@addto@macro\@pushfilename{\CodeStart} % \end{macrocode} % % \begin{macrocode} @@ -765,9 +1050,30 @@ % % But if traditional \TeX\ code is disabled, do this\ldots % -% In this case the catcode preserving stack is not maintained and +% As mentioned above, The \LaTeXe\ package mechanism will insert some code +% to handle the filename stack, and reset the package options, this +% code will die if the \TeX\ primitives have gone, so skip past it +% and insert some equivalent code that will work. +% +% First a version of |\ProvidesPackage| that can cope. +% \begin{macrocode} +\tex_def:D\ProvidesPackage{ + \tex_begingroup:D + \CodeStop + \package_provides:w} +% \end{macrocode} +% +% \begin{macrocode} +\tex_def:D\package_provides:w#1#2[#3]{ + \tex_endgroup:D + \tex_immediate:D\tex_write:D-1{Package:~#1#2~#3} + \tex_expandafter:D\tex_xdef:D + \tex_csname:D ver@#1.sty\tex_endcsname:D{#1}} +% \end{macrocode} +% +% In this case the catcode preserving stack is not maintained and % |\CodeStart| conventions stay in force once on. You'll need -% to turn then off explicitky with |\CodeStop| (although as currently +% to turn then off explicitly with |\CodeStop| (although as currently % built on 2e, nothing except very experimental code will run in % this mode!) Also note that |\RequirePackage| is a simple definition, just for % one file, with no options. @@ -791,14 +1097,15 @@ % \begin{macrocode} \tex_def:D\NeedsTeXFormat#1{} \tex_def:D\RequirePackage#1{ - \tex_expandafter:D\tex_ifx:D - \tex_csname:D ver@#1.sty\tex_endcsname:D\tex_relax:D - \CodeStart - \tex_input:D#1.sty\tex_relax:D - \tex_fi:D} + \tex_expandafter:D\tex_ifx:D + \tex_csname:D ver@#1.sty\tex_endcsname:D\tex_relax:D + \CodeStart + \tex_input:D#1.sty\tex_relax:D + \tex_fi:D} \tex_fi:D % \end{macrocode} % +% % The |\futurelet| just forces the special end of file marker to vanish, % so the argument of |\name_pop_stack:w| does not cause an end-of-file % error. (Normally I use |\expandafter| for this trick, but here the next @@ -808,3 +1115,36 @@ %</package> % \end{macrocode} % +% \endinput +% +% $Log$ +% Revision 1.17 2006/01/15 07:55:48 morten +% Fixed minor typo +% +% Revision 1.16 2006/01/15 07:17:43 morten +% Imported \NamesStart and \NamesStop from l3messages. +% +% Revision 1.15 2005/12/27 10:00:03 morten +% Changed RCS information retrieval, code to run as package under 2e +% changed slightly to not set special catcodes directly. +% +% Revision 1.14 2005/12/01 22:58:16 morten +% Added pdfTeX primitives +% +% Revision 1.13 2005/03/26 21:04:19 morten +% Fix typo. +% +% Revision 1.12 2005/03/22 23:23:57 morten +% Added an Aleph primitive +% +% Revision 1.11 2005/03/15 23:16:21 braams +% Some tweaking with the docstrip guards to get the documentation to +% come out right. +% +% Revision 1.10 2005/03/15 22:48:31 braams +% Made it possible to load this as the very first file with initex +% +% Revision 1.9 2005/03/11 21:29:56 braams +% Fixed the use of RCS information; moved definition of \eTeX +% to l3doc.cls +% diff --git a/Master/texmf-dist/source/latex/expl3/l3num.dtx b/Master/texmf-dist/source/latex/expl3/l3num.dtx new file mode 100644 index 00000000000..e74c57db79b --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3num.dtx @@ -0,0 +1,749 @@ +% \iffalse +%% File: l3num.dtx Copyright (C) 2005-2006 Frank Mittelbach, LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3num.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental token numbers} +% +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3num.dtx} +\end{document} +%</driver> +% \fi +% +% +% \title{The \textsf{l3num} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}\\ +% Integer in macros} +% \author{\Team} +% \date{\filedate} +% \maketitle +% +% \section{Macro Counters} +% +% Instead of using counter registers for manipulation of +% integer values it is sometimes useful to keep such values in +% macros. For this \LaTeX3 offers the type ``num''. +% +% One reason is the limited number of registers inside +% \TeX{}. However, when using \eTeX{} this is no longer an issue. It +% remains to be seen if there are other compelling reasons to keep +% this module. +% +% It turns out there might be as with a \meta{num} data type, the +% allocation module can do its bookkeeping without the aid of +% \meta{int} registers. +% +% \subsection{Functions} +% +% \begin{function}{% +% \num_new:N | +% \num_new:c | +% } +% \begin{syntax} +% "\num_new:N" <num> +% \end{syntax} +% Defines <num> to be a new variable of type "num" (initialized to +% zero). There is no way to +% define constant counters with these functions. +% \end{function} +% +% \begin{function}{% +% \num_incr:N | +% \num_incr:c | +% \num_gincr:N | +% \num_gincr:c +% } +% \begin{syntax} +% "\num_incr:N" <num> +% \end{syntax} +% Increments <num> by one. For global variables the global versions +% should be used. +% \end{function} +% +% \begin{function}{% +% \num_decr:N | +% \num_decr:c | +% \num_gdecr:N | +% \num_gdecr:c | +% } +% \begin{syntax} +% "\num_decr:N" <num> +% \end{syntax} +% Decrements <num> by one. For global variables the global versions +% should be used. +% \end{function} +% +% \begin{function}{% +% \num_zero:N | +% \num_zero:c | +% \num_gzero:N | +% \num_gzero:c | +% } +% \begin{syntax} +% "\num_zero:N" <num> +% \end{syntax} +% Resets <num> to zero. For global variables the global versions +% should be used. +% \end{function} +% +% \begin{function}{% +% \num_set:Nn | +% \num_set:cn | +% \num_gset:Nn | +% \num_gset:cn | +% } +% \begin{syntax} +% "\num_set:Nn" <num> "{" <integer> "}" +% \end{syntax} +% These functions will set the <num> register to the <integer> value. +% \end{function} +% +% \begin{function}{% +% \num_gset_eq:NN | +% \num_gset_eq:cN | +% \num_gset_eq:Nc | +% \num_gset_eq:cc | +% } +% \begin{syntax} +% "\num_gset_eq:NN" <num1> <num2> +% \end{syntax} +% These functions will set the <num1> register equal to <num2>. +% \end{function} +% +% \begin{function}{% +% \num_add:Nn | +% \num_gadd:Nn | +% } +% \begin{syntax} +% "\num_add:Nn" <num> "{" <integer> "}" +% \end{syntax} +% These functions will add to the <num> register the value <integer>. If +% the second argument is a <num> register too, the surrounding braces +% can be left out. +% +% \end{function} +% +% +% \begin{function}{% +% \num_use:N | +% \num_use:c | +% } +% \begin{syntax} +% "\num_use:N" <num> +% \end{syntax} +% This function returns the integer value kept in <num> in a way +% suitable for further processing. +% \begin{texnote} +% Since these <num>s are implemented as macros, the function +% "\num_use:N" is effectively a noop and mainly there for +% consistency with similar functions in other modules. +% \end{texnote} +% \end{function} +% +% +% \begin{function}{% +% \num_eval:n | +% } +% \begin{syntax} +% "\num_eval:n" "{" <integer-expr> "}" +% \end{syntax} +% Evaluates the integer expression allowing normal mathematical +% operators like |+-/*|. +% \end{function} +% +% +% \begin{function}{% +% \num_compare:nNnTF | +% \num_compare:cNcTF | +% \num_compare:nNnT | +% \num_compare:nNnF | +% } +% \begin{syntax} +% "\num_compare:nNnTF" "{"<num~expr>"}" <rel> "{"<num~expr>"}" +% "{"<true>"}" "{"<false>"}" +% \end{syntax} +% These functions test two \m{num} expressions against each other. They +% are both evaluated by "\num_eval:n". +% \end{function} +% +% \begin{function}{% +% \num_compare_p:nNn | +% } +% \begin{syntax} +% "\num_compare_p:nNn" "{"<num~expr>"}" <rel> "{"<num~expr>"}" +% \end{syntax} +% A predicate version of the above functions. +% \end{function} +% +% +% \subsection{Formatting a counter value} +% +% See the \textsf{l3int} module for ways of doing this. +% +% \subsection{Variable and constants} +% +% \begin{function}{% +% \const_new:Nn | +% } +% \begin{syntax} +% "\const_new:Nn" "\c_"<value> "{" <value> "}" +% \end{syntax} +% Defines a constant with <value>. If the constant is negative +% or very large it requires an <int> register. +% \end{function} +% +% \begin{variable}{% +% \c_minus_one | +% \c_zero | +% \c_one | +% \c_two | +% \c_three | +% \c_four | +% \c_six | +% \c_seven | +% \c_nine | +% \c_ten | +% \c_eleven | +% \c_sixteen | +% \c_hundred_one | +% \c_twohundred_fifty_five | +% \c_twohundred_fifty_six | +% \c_thousand | +% \c_ten_thousand | +% \c_twenty_thousand +% } +% \\ +% Set of constants denoting useful values. +% \begin{texnote} +% Most of these constants have been available under \LaTeX2 under names +% like \tn{tw@}, \tn{thr@@} etc. +% \end{texnote} +% \end{variable} +% +% \begin{variable}{% +% \l_tmpa_num | +% \l_tmpb_num | +% \l_tmpc_num | +% \g_tmpa_num | +% \g_tmpb_num | +% } +% \\ +% Scratch register for immediate use. They are not used by conditionals +% or predicate functions. +% \end{variable} +% +% \subsection{Primitive functions} +% +% +% \begin{function}{% +% \num_eval:w | +% } +% \begin{syntax} +% "\num_eval:w" <integer expression> "\scan_stop:" +% \end{syntax} +% Evaluates <integer expression>. The evaluation stops when an +% unexpandable token of catcode other than 12 is reached or +% "\scan_stop:" is read. The latter is gobbled by the scanner +% mechanism. +% \begin{texnote} +% This is the \eTeX{} primitive \tn{numexpr}. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \if_num:w | +% } +% \begin{syntax} +% "\if_num:w" <number1> <rel> <number2> <true> "\else:" <false> "\fi:" +% \end{syntax} +% Compare two numbers. It is recommended to use "\num_eval:n" to +% correctly evaluate and terminate these numbers. <rel> is one of +% "<", "=" or ">" with catcode 12. +% \begin{texnote} +% This is the \TeX{} primitive \tn{ifnum}. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \if_num_odd:w | +% } +% \begin{syntax} +% "\if_num_odd:w" <number> <true> "\else:" <false> "\fi:" +% \end{syntax} +% Execute <true> if <number> is odd, <false> otherwise. +% \begin{texnote} +% This is the \TeX{} primitive \tn{ifodd}. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \if_case:w | +% \or: | +% } +% \begin{syntax} +% "\if_case:w" <number> <case0> "\or:" <case1> "\or:" "..." "\else:" +% <default> "\fi:" +% \end{syntax} +% Chooses case<number>. If you wish to use negative numbers as well, +% you can offset them with "\num_eval:n". +% \begin{texnote} +% These are the \TeX{} primitives \tn{ifcase} and \tn{or}. +% \end{texnote} +% \end{function} +% +% \StopEventually{} +% +% \subsection{The Implementation} +% +% +% We start by ensuring that the required packages are loaded. +% \begin{macrocode} +%<package&!check>\RequirePackage{l3expan}\par +%<package&check>\RequirePackage{l3chk}\par +%<*initex|package> +% \end{macrocode} +% +% \begin{macro}{\num_eval:w} +% \begin{macro}{\if_num:w} +% \begin{macro}{\if_num_odd:w} +% \begin{macro}{\if_case:w} +% \begin{macro}{\or:} +% Here are the remaining primitives for number comparisons and +% expressions. +% \begin{macrocode} +\let_new:NN \num_eval:w \etex_numexpr:D +\let_new:NN \if_num:w \tex_ifnum:D +\let_new:NN \if_num_odd:w \tex_ifodd:D +\let_new:NN \if_case:w \tex_ifcase:D +\let_new:NN \or: \tex_or:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\use_arg_after_or:w} +% \begin{macro}{\use_arg_after_else:w} +% \begin{macro}{\use_arg_after_fi:w} +% When you're using the |\if_case:w| primitive it is not as easy as +% usual to get the code to be executed past the |\or:|, |\else:| and +% |\fi:|. If you know that there is only one token, then prefix it +% with |\exp_after:NN|, else you can use these functions. Be sure to +% hide any |\if| functions in the skipped text! +% +% All other conditionals are two way switches for which you can just +% use the safe methods provided by the TF type functions. +% \begin{macrocode} +\def_long_new:Npn \use_arg_after_or:w #1\or: #2\fi:{\fi: #1} +\def_long_new:Npn \use_arg_after_else:w #1\else: #2\fi:{\fi: #1} +\def_long_new:Npn \use_arg_after_fi:w #1\fi:{\fi: #1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% Functions that support \LaTeX's user accessible counters should be +% added here, too. But first the internal counters. +% +% \begin{macro}{\num_incr:N} +% \begin{macro}{\num_decr:N} +% \begin{macro}{\num_gincr:N} +% \begin{macro}{\num_gdecr:N} +% Incrementing and decrementing of integer registers is done with +% the following functions. +% \begin{macrocode} +\def:Npn \num_incr:N #1{\num_add:Nn#1 1} +\def:Npn \num_decr:N #1{\num_add:Nn#1 \c_minus_one} +\def:Npn \num_gincr:N #1{\num_gadd:Nn#1 1} +\def:Npn \num_gdecr:N #1{\num_gadd:Nn#1 \c_minus_one} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\num_incr:c} +% \begin{macro}{\num_decr:c} +% \begin{macro}{\num_gincr:c} +% \begin{macro}{\num_gdecr:c} +% We also need \ldots +% \begin{macrocode} +\def_new:Npn \num_incr:c {\exp_args:Nc \num_incr:N} +\def_new:Npn \num_decr:c {\exp_args:Nc \num_decr:N} +\def_new:Npn \num_gincr:c {\exp_args:Nc \num_gincr:N} +\def_new:Npn \num_gdecr:c {\exp_args:Nc \num_gdecr:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\num_zero:N} +% \begin{macro}{\num_zero:c} +% \begin{macro}{\num_gzero:N} +% \begin{macro}{\num_gzero:c} +% We also need \ldots +% \begin{macrocode} +\def_new:Npn \num_zero:N #1 {\num_set:Nn #1 0} +\def_new:Npn \num_gzero:N #1 {\num_gset:Nn #1 0} +\def_new:Npn \num_zero:c {\exp_args:Nc \num_zero:N} +\def_new:Npn \num_gzero:c {\exp_args:Nc \num_gzero:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \begin{macro}{\num_new:N} +% \begin{macro}{\num_new:c} +% Allocate a new \m{num} variable and initialize it with zero. +% \begin{macrocode} +\def_new:Npn \num_new:N #1{\tlp_new:Nn #1{0}} +\def_new:Npn \num_new:c {\exp_args:Nc \num_new:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\num_eval:n} +% This function enables us to do all the operations without the aid of +% an \m{int} register. +% \begin{macrocode} +\def_new:Npn \num_eval:n #1{\num_eval:w #1\scan_stop:} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\num_set:Nn} +% \begin{macro}{\num_set:cn} +% \begin{macro}{\num_gset:Nn} +% \begin{macro}{\num_gset:cn} +% Assigning values to \m{num} registers. +% \begin{macrocode} +\def_new:Npn \num_set:Nn #1#2{ + \tlp_set:No #1{ \tex_number:D \num_eval:n {#2} } +} +\def_new:Npn \num_gset:Nn {\pref_global:D \num_set:Nn} +\def_new:Npn \num_set:cn {\exp_args:Nc \num_set:Nn } +\def_new:Npn \num_gset:cn {\exp_args:Nc \num_gset:Nn } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\num_set_eq:NN} +% \begin{macro}{\num_set_eq:cN} +% \begin{macro}{\num_set_eq:Nc} +% \begin{macro}{\num_set_eq:cc} +% Setting \m{num} registers equal to each other. +% \begin{macrocode} +\let_new:NN \num_set_eq:NN \tlp_set_eq:NN +\def_new:Npn \num_set_eq:cN {\exp_args:Nc \num_set_eq:NN} +\def_new:Npn \num_set_eq:Nc {\exp_args:NNc \num_set_eq:NN} +\def_new:Npn \num_set_eq:cc {\exp_args:Ncc \num_set_eq:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\num_gset_eq:NN} +% \begin{macro}{\num_gset_eq:cN} +% \begin{macro}{\num_gset_eq:Nc} +% \begin{macro}{\num_gset_eq:cc} +% Setting \m{num} registers equal to each other. +% \begin{macrocode} +\let_new:NN \num_gset_eq:NN \tlp_gset_eq:NN +\def_new:Npn \num_gset_eq:cN {\exp_args:Nc \num_gset_eq:NN} +\def_new:Npn \num_gset_eq:Nc {\exp_args:NNc \num_gset_eq:NN} +\def_new:Npn \num_gset_eq:cc {\exp_args:Ncc \num_gset_eq:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\num_add:Nn} +% \begin{macro}{\num_gadd:Nn} +% Adding is easily done as the second argument goes through +% |\num_eval:n|. +% \begin{macrocode} +\def_new:Npn \num_add:Nn #1#2 {\num_set:Nn #1{#1+#2}} +\def_new:Npn \num_gadd:Nn {\pref_global:D \num_add:Nn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\num_use:N} +% \begin{macro}{\num_use:c} +% Here is how num macros are accessed: +% \begin{macrocode} +\let_new:NN\num_use:N \use_arg_i:n +\let_new:NN\num_use:c \cs_use:c +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\num_compare:nNnTF} +% \begin{macro}{\num_compare:nNnT} +% \begin{macro}{\num_compare:nNnF} +% Simple comparison tests. +% \begin{macrocode} +\def_test_function_new:npn {num_compare:nNn}#1#2#3{ + \if_num:w \num_eval:n {#1}#2\num_eval:n {#3} +} +\def_new:Npn \num_compare:cNcTF { \exp_args:NcNc\num_compare:nNnTF } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\num_compare_p:nNn} +% A predicate function. +% \begin{macrocode} +\def_new:Npn \num_compare_p:nNn #1#2#3{ + \if_num:w \num_eval:n {#1}#2\num_eval:n {#3} + \c_true + \else: + \c_false + \fi: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\l_tmpa_num} +% \begin{macro}{\l_tmpb_num} +% \begin{macro}{\l_tmpc_num} +% \begin{macro}{\g_tmpa_num} +% \begin{macro}{\g_tmpb_num} +% We provide an number local and two global \m{num}s, maybe we +% need more or less. +% \begin{macrocode} +\num_new:N \l_tmpa_num +\num_new:N \l_tmpb_num +\num_new:N \l_tmpc_num +\num_new:N \g_tmpa_num +\num_new:N \g_tmpb_num +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsubsection{Defining constants} +% As stated, most constants can be defined as |\tex_chardef:D| or +% |\tex_mathchardef:D| but that's engine dependent. Omega/Aleph +% allows |\tex_chardef:D|s up to 65535 which is also the maximum +% number of registers of all types. +% \begin{macro}{\const_new:Nn} +% \begin{macro}{\c_max_register_num} +% \begin{macro}{\const_new_aux:Nw} +% \begin{macrocode} +% \begin{macrocode} +\engine_aleph:TF +{ + \let_new:NN \const_new_aux:Nw \tex_chardef:D + \const_new_aux:Nw \c_max_register_num = 65535 \scan_stop: +} +{ + \let_new:NN \const_new_aux:Nw \tex_mathchardef:D + \const_new_aux:Nw \c_max_register_num = 32767 \scan_stop: +} +\def_new:Npn \const_new:Nn #1#2 { + \num_compare:nNnTF {#2} > \c_minus_one + { + \num_compare:nNnTF {#2} > \c_max_register_num + {\int_new:N #1 \int_set:Nn #1{#2}} + {\chk_new_cs:N #1 \const_new_aux:Nw #1 = #2 \scan_stop: } + } + {\int_new:N #1 \int_set:Nn #1{#2}} +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\c_minus_one} +% \begin{macro}{\c_zero} +% \begin{macro}{\c_one} +% \begin{macro}{\c_two} +% \begin{macro}{\c_three} +% \begin{macro}{\c_four} +% \begin{macro}{\c_six} +% \begin{macro}{\c_seven} +% \begin{macro}{\c_nine} +% \begin{macro}{\c_ten} +% \begin{macro}{\c_eleven} +% \begin{macro}{\c_sixteen} +% \begin{macro}{\c_thirty_two} +% \begin{macro}{\c_hundred_one} +% \begin{macro}{\c_twohundred_fifty_five} +% \begin{macro}{\c_twohundred_fifty_six} +% \begin{macro}{\c_thousand} +% \begin{macro}{\c_ten_thousand} +% \begin{macro}{\c_ten_thousand_one} +% \begin{macro}{\c_ten_thousand_two} +% \begin{macro}{\c_ten_thousand_three} +% \begin{macro}{\c_ten_thousand_four} +% \begin{macro}{\c_twenty_thousand} +% And the usual constants, others are still missing. Please, make +% every constant a real constant at least for the moment. We can +% easily convert things in the end when we have found what +% constants are used in critical places and what not. +% \begin{macrocode} + %% \tex_countdef:D \c_minus_one = 10 \scan_stop: + %% \c_minus_one = -1 \scan_stop: %% in l3basics + %% \tex_chardef:D \c_sixteen = 16\scan_stop: %% in l3basics +\const_new:Nn \c_zero {0} +\const_new:Nn \c_one {1} +\const_new:Nn \c_two {2} +\const_new:Nn \c_three {3} +\const_new:Nn \c_four {4} +\const_new:Nn \c_six {6} +\const_new:Nn \c_seven {7} +\const_new:Nn \c_nine {9} +\const_new:Nn \c_ten {10} +\const_new:Nn \c_eleven {11} +\const_new:Nn \c_thirty_two {32} +% \end{macrocode} +% The next one may seem a little odd (obviously!) but is useful when +% dealing with logical operators. +% \begin{macrocode} +\const_new:Nn \c_hundred_one {101} +\const_new:Nn \c_twohundred_fifty_five {255} +\const_new:Nn \c_twohundred_fifty_six {256} +\const_new:Nn \c_thousand {1000} +\const_new:Nn \c_ten_thousand {10000} +\const_new:Nn \c_ten_thousand_one {10001} +\const_new:Nn \c_ten_thousand_two {10002} +\const_new:Nn \c_ten_thousand_three {10003} +\const_new:Nn \c_ten_thousand_four {10004} +\const_new:Nn \c_twenty_thousand {20000} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \endinput +% +% $Log$ +% Revision 1.17 2006/03/20 18:26:37 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.16 2005/12/27 10:03:01 morten +% Changed RCS information retrieval +% +% Revision 1.15 2005/12/06 13:41:02 morten +% Added a few functions to ease processing with \if_case:w +% +% Revision 1.14 2005/12/03 12:57:36 morten +% Minor touch-ups. +% +% Revision 1.13 2005/10/27 22:39:02 morten +% Forgot to add \if_num_odd:w +% +% Revision 1.12 2005/10/27 22:34:26 morten +% Added \if_num:w, \if_case:w and \or: as they really belong here. +% +% Revision 1.11 2005/04/06 22:36:53 braams +% Missed one occurence of \c_max_register_int +% +% Revision 1.10 2005/04/06 21:38:46 morten +% Removed dependency on l3prg and added a missing function. +% +% Revision 1.9 2005/04/05 22:05:38 braams +% Renamed \c_max_regsiter_int to \c_max_register_num, +% Fixed const_new to allow 32767 as a value for \tex_mathchardef:D +% Added \c_ten and \c_eleven as constants +% +% Revision 1.8 2005/03/26 21:06:35 morten +% Update documentation +% +% Revision 1.7 2005/03/22 23:21:32 morten +% Now independent of l3int and can be used as a very primitive module. +% +% Revision 1.6 2005/03/16 22:36:20 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.5 2005/03/11 21:39:47 braams +% Fixed the use of RCS information; added \StopEventually +% diff --git a/Master/texmf-dist/source/latex/expl3/l3precom.dtx b/Master/texmf-dist/source/latex/expl3/l3precom.dtx index 69c1bc4e7cd..de22e1fe5ab 100644 --- a/Master/texmf-dist/source/latex/expl3/l3precom.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3precom.dtx @@ -1,15 +1,50 @@ % \iffalse -%% File: l3precom.dtx Copyright (C) 1990-1998 LaTeX3 project -% +%% File: l3precom.dtx Copyright (C) 1990-2006 Frank Mittelbach, LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} %<*dtx> - \ProvidesFile{l3precom.dtx} +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse %</dtx> -%<package>\NeedsTeXFormat{LaTeX2e} -%<package>\ProvidesPackage{l3precom} -%<driver> \ProvidesFile{l3precom.drv} -% \fi -% \ProvidesFile{l3precom.dtx} - [1998/04/20 v1.0b L3 Experimental precompilation module] +%\fi +\GetIdInfo$Id: l3precom.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental precompilation module} % % \iffalse %<*driver> @@ -34,7 +69,7 @@ % using the roman numeral representation of some special counters % together with a prefix of "\l*" (local) or "\g*"( global). % \end{function} -% +% % \begin{function}{\cs_record_name:N} % \begin{syntax} % "\cs_record_name:N" <cs> @@ -45,7 +80,7 @@ % internally automatically used to record all symbols generated by % "\cs_gen_sym:N" and "\cs_ggen_sym:N". % \end{function} -% +% % \begin{function}{\cs_load_dump:n} % \begin{syntax} % "\cs_load_dump:n" "{" <file name> "}" @@ -57,7 +92,7 @@ % scanned. Then all symbols marked for dumping are dumped into <file % name>. % \end{function} -% +% % \begin{function}{\cs_dump:} % Dumps the symbols recorded by "\cs_record_name:N" in the file given % by the argument in "\cs_load_dump:n". Dumping means that for every @@ -71,30 +106,31 @@ % % % \subsection{Internal variables} -% -% \begin{variable}{\g_gen_sym_fint | -% \g_ggen_sym_fint} Holds the number of the last +% +% \begin{variable}{\g_gen_sym_num | +% \g_ggen_sym_num} Holds the number of the last % generated symbol by "\cs_gen_sym:N" or "\cs_ggen_sym:N". % \end{variable} -% +% % \begin{variable}{\g_cs_dump_seq} % Sequence in which the symbols to be dumped are stored. % \end{variable} -% +% % \begin{variable}{\c_cs_dump_stream} % Output stream used for writing out the definitions of the % recorded <tlp>. % \end{variable} -% -% -% -% \section{Precompiling some functions} +% +% \StopEventually{} +% +% \subsection{The Implementation} % % We start by ensuring that the required packages are loaded. % \begin{macrocode} -%<package>\RequirePackage{l3int} +%<package>\RequirePackage{l3num} %<package>\RequirePackage{l3io} %<package>\RequirePackage{l3seq} +%<package>\RequirePackage{l3int} % \end{macrocode} % % It might speed up the processing of documents when certain parts @@ -107,7 +143,7 @@ % Stream number for the dump. % % \begin{macrocode} -%<*package> +%<*initex|package> %<*precompile> \iow_new:N\c_cs_dump_stream % \end{macrocode} @@ -135,18 +171,18 @@ % \begin{macro}{\cs_record_name:N} % \begin{macro}{\cs_record_name:c} % These functions mark a control sequence for dumping into a -% precompiled style. +% precompiled style. % % When the {\sf trace} `module' is included in the code we also write % information about the control sequence into a |.dmp| file. % \begin{macrocode} \def_new:Npn\cs_record_name:N#1{ %<*trace> - \seq_gput_left:Nn - \g_cs_trace_seq#1 +\seq_gput_left:Nn + \g_cs_trace_seq#1 %</trace> - \seq_gput_left:Nn - \g_cs_dump_seq#1} +\seq_gput_left:Nn + \g_cs_dump_seq#1} \def_new:Npn\cs_record_name:c{\exp_args:Nc\cs_record_name:N} % \end{macrocode} % \end{macro} @@ -163,49 +199,45 @@ % `user' of this fact. % \begin{macrocode} \def_new:Npn\cs_dump:{ - \iow_expanded_term:n{Precompiling~style~into~(\g_cs_dump_name_tlp)} - \iow_open:Nn\c_cs_dump_stream{\g_cs_dump_name_tlp} +\iow_expanded_term:n{Precompiling~style~into~(\g_cs_dump_name_tlp)} +\iow_open:Nn\c_cs_dump_stream{\g_cs_dump_name_tlp} % \end{macrocode} % The first thing we write on a `dump' file is a command that -% allows us to use |*| in control sequences. We also need to be +% allows us to use |*| in control sequences. We also need to be % able to write to (and read from) the file internal control % sequences, containing |_| and |:|. % \begin{macrocode} - \iow_expanded:Nn\c_cs_dump_stream - {\group_begin: - \tex_catcode:D`\token_to_string:N\*=11\scan_stop: - \token_to_string:N\CodeStart - } - \seq_map_inline:Nn - \g_cs_dump_seq - {\tex_message:D{.} - \iow_expanded:Nn\c_cs_dump_stream +\iow_expanded:Nn\c_cs_dump_stream +{\group_begin: +\tex_catcode:D`\token_to_string:N\*=11\scan_stop: +\token_to_string:N\CodeStart +} +\seq_map_inline:Nn +\g_cs_dump_seq +{\tex_message:D{.} +\iow_expanded:Nn\c_cs_dump_stream % \end{macrocode} % We use a direct |\gdef:Npn| to disable any type of local/global % check on the pointers. % \begin{macrocode} - {\token_to_string:N\gdef:Npn - \token_to_string:N##1 - {\tlp_to_str:N##1}} - } + {\exp_not:n{\gdef:Npn ##1} + {\tlp_to_str:N##1}} +} % \end{macrocode} % We also need to remember the current values of the -% |\g_gen_sym_fint| and |\g_ggen_sym_fint| counters to allow +% |\g_gen_sym_num| and |\g_ggen_sym_num| counters to allow % further updates after a database was dumped. % \begin{macrocode} - \iow_expanded:Nn - \c_cs_dump_stream - {\token_to_string:N\fint_gset:Nn - \g_gen_sym_fint - {\fint_use:N\g_gen_sym_fint}^^J - \token_to_string:N\fint_gset:Nn - \g_ggen_sym_fint - {\fint_use:N\g_ggen_sym_fint}} - \iow_expanded:Nn - \c_cs_dump_stream - {\group_end:} - \iow_close:N\c_cs_dump_stream - \tex_message:D{~finished} +\iow_expanded:Nn \c_cs_dump_stream {\exp_not:n{\num_gset:Nn + \g_gen_sym_num} + {\num_use:N\g_gen_sym_num}^^J +\exp_not:n{\num_gset:Nn \g_ggen_sym_num} + {\num_use:N\g_ggen_sym_num}} +\iow_expanded:Nn +\c_cs_dump_stream +{\group_end:} +\iow_close:N\c_cs_dump_stream +\tex_message:D{~finished} } %</precompile> % \end{macrocode} @@ -218,27 +250,25 @@ % dump file. % \begin{macrocode} \def_new:Npn\cs_load_dump:n#1{ - \file_not_found:nTF{#1.cmp} +\file_not_found:nTF{#1.cmp} %<*precompile> - {\tlp_gset:Nn\g_cs_dump_name_tlp{#1.cmp}} +{\tlp_gset:Nn\g_cs_dump_name_tlp{#1.cmp}} %</precompile> %<-precompile> {\tex_errmessage:D{Cannot~ dump~ with~ this~ format}} - {\input{#1.cmp} - \let:NN\cs_dump:\fi: - \if_false:}} +{\input{#1.cmp} +\let:NN\cs_dump:\fi: +\if_false:}} % \end{macrocode} % \end{macro} % -% \begin{macro}{\g_gen_sym_fint} -% \begin{macro}{\g_ggen_sym_fint} -% Two counters to make up new local or global {\sl short\/} names -% in pointer structures like the {\sc ldb}. +% \begin{macro}{\g_gen_sym_num} +% \begin{macro}{\g_ggen_sym_num} +% Two counters to make up new local or global \textsl{short} names +% in pointer structures like the \textsc{ldb}. % We use a fake counters since operations with them are seldom. % \begin{macrocode} -\fint_new:N\g_gen_sym_fint -\fint_gset:Nn\g_gen_sym_fint{0} -\fint_new:N\g_ggen_sym_fint -\fint_gset:Nn\g_ggen_sym_fint{0} +\num_new:N\g_gen_sym_num \num_gset:Nn\g_gen_sym_num{0} +\num_new:N\g_ggen_sym_num \num_gset:Nn\g_ggen_sym_num{0} % \end{macrocode} % \end{macro} % \end{macro} @@ -247,40 +277,40 @@ % \begin{macro}{\cs_ggen_sym:N} % We need to be able to generate control sequences on the fly. % They will exist of a prefix, either |l*| or |g*|, followed -% by the value of the counter |\g_gen_sym_fint| (|\g_ggen_sym_fint|) +% by the value of the counter |\g_gen_sym_num| (|\g_ggen_sym_num|) % in roman numeral representation. The generated control sequence % is locally stored in the token that was passed in |#1|. % % \begin{macrocode} \def_new:Npn\cs_gen_sym:N#1{ - \fint_gincr:N\g_gen_sym_fint - \tlp_set:Nc#1{l*\tex_romannumeral:D\fint_use:N\g_gen_sym_fint} +\num_gincr:N\g_gen_sym_num +\tlp_set:Nc#1{l*\tex_romannumeral:D\num_use:N\g_gen_sym_num} %<*precompile> - \exp_after:NN\cs_record_name:N#1 +\exp_after:NN\cs_record_name:N#1 %</precompile> % \end{macrocode} % We still want to define the initial value for the new symbol % globally to make sure that during compilation something is % written to the output file. % \begin{macrocode} - \exp_after:NN\tlp_clear_new:N#1} +\exp_after:NN\tlp_clear_new:N#1} % \end{macrocode} % The global variant % \begin{macrocode} \def_new:Npn\cs_ggen_sym:N#1{ - \fint_gincr:N\g_ggen_sym_fint - \tlp_set:Nc#1{g*\tex_romannumeral:D\fint_use:N\g_ggen_sym_fint} +\num_gincr:N\g_ggen_sym_num +\tlp_set:Nc#1{g*\tex_romannumeral:D\num_use:N\g_ggen_sym_num} %<*precompile> - \exp_after:NN\cs_record_name:N#1 +\exp_after:NN\cs_record_name:N#1 %</precompile> - \exp_after:NN\tlp_clear_new:N#1} +\exp_after:NN\tlp_clear_new:N#1} % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\g_cs_trace_seq} -% A sequence which holds the control sequence names that are to +% A sequence which holds the control sequence names that are to % be dumped. They are stored together with their meaning. % % ATTENTION: as we currently don't distribute allocation routines @@ -306,8 +336,8 @@ % Function marking a control sequence for dumping with meaning. % \begin{macrocode} \def:Npn\cs_record_meaning:N#1{ - \seq_gput_left:Nn - \g_cs_trace_seq#1} +\seq_gput_left:Nn + \g_cs_trace_seq#1} % \end{macrocode} % \end{macro} % @@ -315,8 +345,8 @@ % Function marking a register for dumping with value. % \begin{macrocode} \def:Npn\register_record_name:N#1{ - \seq_gput_left:Nn - \g_register_trace_seq#1} +\seq_gput_left:Nn + \g_register_trace_seq#1} % \end{macrocode} % \end{macro} % @@ -324,7 +354,7 @@ % \begin{macro}{\dumpLaTeXstate} % The function |\dumpLaTeXstate| is used to write control sequences % and registers, together with their meaning or value in the |.dmp| -% file. We write informational messages to the terminal during the +% file. We write informational messages to the terminal during the % dump. % % ATTENTION: as we currently don't distribute allocation routines @@ -352,7 +382,7 @@ \tex_message:D{~finished} } %</trace> -%</package> +%</initex|package> % \end{macrocode} % \end{macro} % @@ -364,6 +394,26 @@ %</showmemory> % \end{macrocode} % +% \endinput +% +% $Log$ +% Revision 1.7 2006/03/20 18:26:37 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.6 2005/12/27 16:03:21 morten +% Changed RCS information retrieval plus a few name changes +% +% Revision 1.5 2005/04/12 12:06:30 morten +% Fixed the use of fake integers (now known as "num") +% +% Revision 1.4 2005/03/16 22:36:14 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.3 2005/03/11 21:51:50 braams +% Just another small mistake to be corrected +% +% Revision 1.2 2005/03/11 21:21:01 braams +% Added the header for CVS public read access and fixed the +% use of RCS data % - - diff --git a/Master/texmf-dist/source/latex/expl3/l3prg.dtx b/Master/texmf-dist/source/latex/expl3/l3prg.dtx new file mode 100644 index 00000000000..43e2e77448a --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3prg.dtx @@ -0,0 +1,1374 @@ +% \iffalse +%% File: l3prg.dtx Copyright (C) 2005-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3prg.dtx 574 2006-08-21 23:30:10Z morten $ + {L3 Experimental control structures} +% +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3prg.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3prg} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}\\ +% Program control structures} +% \author{\Team} +% \date{\filedate} +% \maketitle +% +% +% \section{Control structures} +% +% \subsection{Choosing modes} +% +% \begin{function}{\mode_vertical_p:| +% \mode_vertical:TF | +% \mode_vertical:T | +% \mode_vertical:F +% } +% \begin{syntax} +% "\mode_vertical:TF" "{"<true code>"}" "{"<false code>"}" +% \end{syntax} +% Determines if \TeX{} is in vertical mode or not and executes either +% <true code> or <false code> accordingly. +% \end{function} +% +% \begin{function}{\mode_horizontal_p:| +% \mode_horizontal:TF | +% \mode_horizontal:T | +% \mode_horizontal:F +% } +% \begin{syntax} +% "\mode_horizontal:TF" "{"<true code>"}" "{"<false code>"}" +% \end{syntax} +% Determines if \TeX{} is in horizontal mode or not and executes either +% <true code> or <false code> accordingly. +% \end{function} +% +% +% \begin{function}{ +% \mode_inner_p:| +% \mode_inner:TF| +% \mode_inner:T| +% \mode_inner:F +% } +% \begin{syntax} +% "\mode_inner:TF" "{"<true code>"}" "{"<false code>"}" +% \end{syntax} +% Determines if \TeX{} is in inner mode or not and executes either +% <true code> or <false code> accordingly. +% \end{function} +% +% \begin{function}{ +% \mode_math:TF| +% \mode_math:T| +% \mode_math:F| +% } +% \begin{syntax} +% "\mode_math:TF" "{"<true code>"}" "{"<false code>"}" +% \end{syntax} +% Determines if \TeX{} is in math mode or not and executes either +% <true code> or <false code> accordingly. +% \begin{texnote} +% This version will choose the right branch even at the beginning of +% an alignment cell. +% \end{texnote} +% \end{function} +% +% +% \subsubsection{Alignment safe grouping and scanning} +% +% \begin{function}{\scan_align_safe_stop:} +% \begin{syntax} +% "\scan_align_safe_stop:" +% \end{syntax} +% This function gets \TeX{} on the right track inside an alignment +% cell but without destroying any kerning. +% \end{function} +% +% +% \begin{function}{\group_align_safe_begin:| +% \group_align_safe_end:} +% \begin{syntax} +% "\group_align_safe_begin:" <...> "\group_align_safe_end:" +% \end{syntax} +% Encloses <...> inside a group but is safe inside an alignment cell. +% See the implementation of |\peek_token_generic:NNTF| for an +% application. +% \end{function} +% +% +% \subsection{Producing $n$ copies} +% +% There are often several different requirements for producing +% multiple copies of something. Sometimes one might want to produce a +% number of identical copies of a sequence of tokens whereas at other +% times the goal is to simulate a for loop as known from most real +% programming languages. +% +% \begin{function}{\prg_replicate:nn } +% \begin{syntax} +% "\prg_replicate:nn" "{" <number> "}" "{" <arg> "}" +% \end{syntax} +% Creates <number> copies of <arg>. Expandable. +% \end{function} +% +% +% \begin{function}{\prg_stepwise_function:nnnN} +% \begin{syntax} +% "\prg_stepwise_function:nnnN" "{"<start>"}" "{"<step>"}" +% "{"<end>"}" <function> +% \end{syntax} +% This function performs <action> once for each step starting at +% <start> and ending once <end> is passed. <function> is placed +% directly in front of a brace group holding the current number so it +% should usually be a function taking one argument. The +% |\prg_stepwise_function:nnnN| function is expandable. +% \end{function} +% +% \begin{function}{\prg_stepwise_inline:nnnn} +% \begin{syntax} +% "\prg_stepwise_inline:nnnn" "{"<start>"}" "{"<step>"}" "{"<end>"}" +% "{"<action>"}" +% \end{syntax} +% Same as |\prg_stepwise_function:nnnN| except here <action> is +% performed each time with |##1| as a placeholder for the number +% currently being tested. This function is not expandable and it is +% nestable. +% \end{function} +% +% \begin{function}{\prg_stepwise_variable:nnnNn} +% \begin{syntax} +% "\prg_stepwise_variable:nnnn" "{"<start>"}" "{"<step>"}" "{"<end>"}" +% <temp-var> "{"<action>"}" +% \end{syntax} +% Same as |\prg_stepwise_inline:nnnn| except here the current value is +% stored in <temp-var> and the programmer can use it in <action>. This +% function is not expandable. +% \end{function} +% +% +% +% \subsection{Conditionals and logical operations} +% +% +% \LaTeX3 has two primary forms of conditional flow processing. The +% one type deals with the truth value of a test directly as in +% "\cs_free:NTF" where you test if a control sequence was undefined +% and then execute either the \m{true} or \m{false} part depending on +% the result and after exiting the underlying "\if...\fi:" structure. +% The second type has to do with predicate functions like +% "\cs_free_p:N" which return either "\c_true" or "\c_false" to be +% used in testing with "\if:w". +% +% +% This section describes a boolean data type which is closely +% connected to both parts as sometimes you want to execute some code +% depending on the value of a switch (e.g.,~draft/final) and other +% times you perhaps want to use it as a predicate function in an +% "\if:w" test. Here \TeX's original concept with "\iffalse" and +% "\iftrue" is a little difficult to handle so the easiest is simply +% to let a boolean either be "\c_true" or "\c_false". This also means +% we get the logical operations And, Or, and Not which can then be +% used on both the boolean type and predicate functions. All +% functions by the name |\prg_if_predicate_| are expandable and +% expect the input to also be fully expandable. More generic +% constructs do not contain |predicate| in their names. +% +% +% \subsubsection{The boolean data type} +% +% \begin{function}{% +% \bool_new:N | +% \bool_new:c | +% } +% \begin{syntax} +% "\bool_new:N" <bool> +% \end{syntax} +% Define a new boolean variable. The initial value is <false>. A +% boolean is actually just either "\c_true" or "\c_false". +% \end{function} +% +% \begin{function}{% +% \bool_set_true:N | +% \bool_set_true:c | +% \bool_set_false:N | +% \bool_set_false:c | +% \bool_gset_true:N | +% \bool_gset_true:c | +% \bool_gset_false:N | +% \bool_gset_false:c | +% } +% \begin{syntax} +% "\bool_gset_false:N" <bool> +% \end{syntax} +% Set <bool> either true or false. We can also do this globally. +% \end{function} +% +% +% \begin{function}{% +% \bool_set_eq:NN | +% \bool_set_eq:Nc | +% \bool_set_eq:cN | +% \bool_set_eq:cc | +% \bool_gset_eq:NN | +% \bool_gset_eq:Nc | +% \bool_gset_eq:cN | +% \bool_gset_eq:cc | +% +% } +% \begin{syntax} +% "\bool_set_eq:NN" <bool1> <bool2> +% \end{syntax} +% Set <bool1> equal to the value of <bool2>. +% \end{function} +% +% \begin{function}{% +% \bool_if:NTF | +% \bool_if:NT | +% \bool_if:NF | +% \bool_if_p:N | +% +% } +% \begin{syntax} +% "\bool_if:NTF" <bool> "{"\m{true}"}" "{"\m{false}"}" \\ +% "\bool_if_p:N" <bool> +% \end{syntax} +% Test the truth value of the boolean and execute the \m{true} or +% \m{false} code. "\bool_if_p:N" is a predicate function for use in +% "\if:w" tests. +% \end{function} +% +% \begin{function}{% +% \bool_whiledo:NT | +% \bool_whiledo:NF | +% \bool_dowhile:NT | +% \bool_dowhile:NF | +% +% } +% \begin{syntax} +% "\bool_whiledo:NT" <bool> "{"\m{true}"}" \\ +% "\bool_whiledo:NF" <bool> "{"\m{false}"}" \\ +% \end{syntax} +% The "T" versions execute the \m{true} code as long as the boolean is +% true and the "F" versions execute the \m{false} code as long as the +% boolean is false. The "whiledo" functions execute the body after +% testing the boolean and the "dowhile" functions executes the body +% first and then tests the boolean. +% \end{function} +% +% +% \begin{function}{% +% \l_tmpa_bool | +% \g_tmpa_bool | +% +% } +% \begin{syntax} +% \end{syntax} +% Reserved booleans. +% \end{function} +% +% \subsubsection{Logical operations} +% +% Somewhat related to the subject of conditional flow processing is +% logical operators as these deal with \m{true} and \m{false} +% statements which is precisely what the predicate functions return. +% +% +% \begin{function}{% +% \prg_if_predicate:nTF | +% \prg_if_predicate:nT | +% \prg_if_predicate:nF | +% } +% \begin{syntax} +% "\prg_if_predicate:nTF" "{"<predicate>"}" "{"<true>"}" "{"<false>"}" \\ +% \end{syntax} +% The first argument can either be a predicate function like +% "\cs_free_p:N \foo" or one of the logic tests below. +% \end{function} +% +% +% +% +% \begin{function}{% +% \prg_if_predicate_ors_p:n | +% \prg_if_predicate_or_p:nn | +% \prg_if_predicate_ands_p:n | +% \prg_if_predicate_and_p:nn | +% \prg_if_predicate_not_p:n | +% } +% \begin{syntax} +% "\prg_if_predicate_ors_p:n" "{"<predicate> <predicate> ..."}" \\ +% "\prg_if_predicate_or_p:nn" "{"<predicate>"}" "{"<predicate>"}" \\ +% "\prg_if_predicate_ands_p:n" "{"<predicate> <predicate> ..."}" \\ +% "\prg_if_predicate_and_p:nn" "{"<predicate>"}" "{"<predicate>"}" \\ +% "\prg_if_predicate_not_p:n" "{"<predicate>"}" +% \end{syntax} +% "\prg_if_predicate_or_p:nn" compares the outcome of two predicate +% functions (or other logic tests) and if either turns out to be +% \m{true} returns \m{true} itself. "\prg_if_predicate_and_p:nn" +% works in a similar way but requires both outcomes to be \m{true} in +% order for it to return \m{true} itself. "\prg_if_predicate_not_p:n" +% reverses the truth value of a predicate test or a logic +% operation. Thus +% \begin{quote} +% "\prg_if_predicate_not_p:n {\prg_if_predicate_not_p:n {\c_true}}" +% \end{quote} +% ultimately returns \m{true}. The argument of the functions +% "\prg_if_predicate_ors_p:n" and "\prg_if_predicate_ands_p:n" take a +% list of predicate functions (and their arguments) and return either +% \m{true} or \m{false}. +% \end{function} +% +% \subsubsection{Generic loops} +% +% +% \begin{function}{ +% \prg_whiledo:nT | +% \prg_whiledo:nF | +% \prg_dowhile:nT | +% \prg_dowhile:nF | +% +% } +% \begin{syntax} +% "\prg_whiledo:nT" "{"<test>"}" "{"\m{true}"}" \\ +% "\prg_whiledo:nF" "{"<test>"}" "{"\m{false}"}" +% \end{syntax} +% The "T" versions execute the \m{true} code as long as <test> is +% true and the "F" versions execute the \m{false} code as long as +% <test> is false. The "whiledo" functions execute the body after +% testing the boolean and the "dowhile" functions executes the body +% first and then tests the boolean. For the "T" versions, <test> +% should end with a function executing only the \meta{true} code for +% some test such as |\tlp_if_eq:NNT|. Similarly the "F" types should +% end with |\tlp_if_eq:NNF|. +% \end{function} +% +% \subsection{Sorting} +% +% +% \begin{function}{ +% \prg_quicksort:n | +% } +% \begin{syntax} +% "\prg_quicksort:n" "{" "{"<element~1>"}" "{"<element~2>"}" +% \dots\space "{"<element~n>"}" "}" +% \end{syntax} +% Performs a Quicksort on the token list. The comparisons are +% performed by the function |\prg_quicksort_compare:nnTF| which is up +% to the programmer to define. When the sorting process is over, all +% elements are given as argument to the function +% |\prg_quicksort_function:n| which the programmer also controls. +% \end{function} +% +% \begin{function}{ +% \prg_quicksort_function:n | +% \prg_quicksort_compare:nnTF +% } +% \begin{syntax} +% "\prg_quicksort_function:n" "{"<element>"}" \\ +% "\prg_quicksort_compare:nnTF" "{"<element 1>"}" "{"<element 2>"}"\\ +% \end{syntax} +% The two functions the programmer must define before calling +% |\prg_quicksort:n|. As an example we could define +% \begin{quote} +% |\def:NNn\prg_quicksort_function:n 1{{#1}}|\\ +% |\def:NNn\prg_quicksort_compare:nnTF 2{\num_compare:nNnTF{#1}>{#2}}| +% \end{quote} +% Then the function call +% \begin{quote} +% |\prg_quicksort:n {876234520}| +% \end{quote} +% would return |{0}{2}{2}{3}{4}{5}{6}{7}{8}|. An alternative example +% where one sorts a list of words, |\prg_quicksort_compare:nnTF| could +% be defined as +% \begin{quote} +% |\def:NNn\prg_quicksort_compare:nnTF 2{|\\ +% | \num_compare:nNnTF{\tlist_compare:nn{#1}{#2}}>\c_zero }| +% \end{quote} +% +% \end{function} +% +% +% \StopEventually{} +% +% \subsection{The Implementation} +% +% +% We start by ensuring that the required packages are loaded. +% \begin{macrocode} +%<*package> +\RequirePackage{l3quark} +\RequirePackage{l3toks} +\RequirePackage{l3int} +%</package> +%<*initex|package> +% \end{macrocode} +% +% +% \subsubsection{Choosing modes} +% +% \begin{macro}{\mode_vertical_p:} +% \begin{macro}{\mode_vertical:TF} +% \begin{macro}{\mode_vertical:T} +% \begin{macro}{\mode_vertical:F} +% For testing vertical mode. +% \begin{macrocode} +\def_new:Npn \mode_vertical_p: { + \if_mode_vertical: \c_true \else: \c_false\fi:} +\def_test_function_new:npn{mode_vertical:}{\if_mode_vertical:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\mode_horizontal_p:} +% \begin{macro}{\mode_horizontal:TF} +% \begin{macro}{\mode_horizontal:T} +% \begin{macro}{\mode_horizontal:F} +% For testing horizontal mode. +% \begin{macrocode} +\def_new:Npn \mode_horizontal_p: { + \if_mode_horizontal: \c_true \else: \c_false\fi:} +\def_test_function_new:npn{mode_horizontal:}{\if_mode_horizontal:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\mode_inner_p:} +% \begin{macro}{\mode_inner:TF} +% \begin{macro}{\mode_inner:T} +% \begin{macro}{\mode_inner:F} +% For testing inner mode. +% \begin{macrocode} +\def_new:Npn \mode_inner_p: { + \if_mode_inner: \c_true \else: \c_false\fi:} +\def_test_function_new:npn{mode_inner:}{\if_mode_inner:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\mode_math:TF} +% \begin{macro}{\mode_math:T} +% \begin{macro}{\mode_math:F} +% For testing math mode. Uses the kern-save |\scan_align_safe_stop:|. +% \begin{macrocode} +\def_test_function_new:npn{mode_math:} { + \scan_align_safe_stop: \if_mode_math: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \paragraph{Alignment safe grouping and scanning} +% +% +% \begin{macro}{\group_align_safe_begin:} +% \begin{macro}{\group_align_safe_end:} +% \TeX's alignment structures present many problems. As Knuth says +% himself in \emph{\TeX: The Program}: ``It's sort of a miracle +% whenever |\halign| or |\valign| work, [\ldots]'' One problem relates +% to commands that internally issues a |\cr| but also peek ahead for +% the next character for use in, say, an optional argument. If the +% next token happens to be a |&| with category code~4 we will get some +% sort of weird error message because the underlying +% |\tex_futurelet:D| will store the token at the end of the alignment +% template. This could be a |&|$\sb4$ giving a message like +% |! Misplaced \cr.| or even worse: it could be the |\endtemplate| +% token causing even more trouble! To solve this we have to open a +% special group so that \TeX{} still thinks it's on safe ground but at +% the same time we don't want to introduce any brace group that may +% find its way to the output. The following functions help with this +% by using code documented only in Appendix~D of +% \emph{The \TeX book}\dots +% \begin{macrocode} +\def_new:Npn \group_align_safe_begin: {\if_false:{\fi:\if_num:w0=`}\fi:} +\def_new:Npn \group_align_safe_end: {\if_num:w0=`{\fi:\if_false:}\fi:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\scan_align_safe_stop:} +% When \TeX{} is in the beginning of an align cell (right after the +% |\cr|) it is in a somewhat strange mode as it is looking ahead to +% find an |\tex_omit:D| or |\tex_noalign:D| and hasn't looked at the +% preamble yet. Thus an |\tex_ifmmode:D| test will always fail unless +% we insert |\scan_stop:| to stop \TeX's scanning ahead. On the other +% hand we don't want to insert a |\scan_stop:| every time as that will +% destroy kerning between letters\footnote{Unless we enforce an extra +% pass with an appropriate value of \texttt{\string\pretolerance}.} +% Unfortunately there is no way to detect if we're in the beginning of +% an alignment cell as they have different characteristics depending +% on column number etc. However we \emph{can} detect if we're in an +% alignment cell by checking the current group type and we can also +% check if the previous node was a character or ligature. What is done +% here is that |\scan_stop:| is only inserted iff a)~we're in the +% outer part of an alignment cell and b)~the last node \emph{wasn't} a +% char node or a ligature node. +% \begin{macrocode} +\def_new:Npn \scan_align_safe_stop: { + \num_compare:nNnT \etex_currentgrouptype:D = \c_six + { + \num_compare:nNnF \etex_lastnodetype:D = \c_zero + { + \num_compare:nNnF \etex_lastnodetype:D = \c_seven + \scan_stop: + } + } +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Making $n$ copies} +% +% \begin{macro}{\prg_replicate:nn} +% \begin{macro}{\prg_replicate_aux:N} +% \begin{macro}{\prg_replicate_first_aux:N} +% This function uses a cascading csname technique by David Kastrup +% (who else :-) +% +% The idea is to make the input "25" result in first adding five, and +% then 20 copies of the code to be replicated. The technique uses +% cascading csnames which means that we start building several csnames +% so we end up with a list of functions to be called in reverse +% order. This is important here (and other places) because it means +% that we can for instance make the function that inserts five copies +% of something to also hand down ten to the next function in +% line. This is exactly what happens here: in the example with "25" +% then the next function is the one that inserts two copies but it +% sees the ten copies handed down by the previous function. In order +% to avoid the last function to insert say, 100 copies of the original +% argument just to gobble them again we define separate functions to +% be inserted first. Finally we must ensure that the cascade comes to +% a peaceful end so we make it so that the original csname \TeX{} is +% creating is simply "\use_noop:" expanding to nothing. +% +% This function has one flaw though: Since it constantly passes down +% ten copies of its previous argument it will severely affect the main +% memory once you start demanding hundreds of thousands of copies. Now +% I don't think this is a real limitation for any ordinary use. An +% alternative approach is to create a string of "m"'s with +% "\int_to_roman:w" which can be done with just four macros but that +% method has its own problems since it can exhaust the string +% pool. Also, it is considerably slower than what we use here so the +% few extra csnames are well spent I would say. +% \begin{macrocode} +\def_new:Npn \prg_replicate:nn #1{ + \cs:w use_noop: + \exp_after:NN\prg_replicate_first_aux:N + \int_use:N \int_eval:n{#1} \cs_end: + \cs_end: +} +\def_new:Npn \prg_replicate_aux:N#1{ + \cs:w prg_replicate_#1:n\prg_replicate_aux:N +} +\def_new:Npn \prg_replicate_first_aux:N#1{ + \cs:w prg_replicate_first_#1:n\prg_replicate_aux:N +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% Then comes all the functions that do the hard work of inserting all +% the copies. +% \begin{macrocode} +\def_new:Npn \prg_replicate_ :n #1{}% no, this is not a typo! +\def_long_new:cpn {prg_replicate_0:n}#1{\cs_end:{#1#1#1#1#1#1#1#1#1#1}} +\def_long_new:cpn {prg_replicate_1:n}#1{\cs_end:{#1#1#1#1#1#1#1#1#1#1}#1} +\def_long_new:cpn {prg_replicate_2:n}#1{\cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1} +\def_long_new:cpn {prg_replicate_3:n}#1{ + \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1} +\def_long_new:cpn {prg_replicate_4:n}#1{ + \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1} +\def_long_new:cpn {prg_replicate_5:n}#1{ + \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1} +\def_long_new:cpn {prg_replicate_6:n}#1{ + \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1} +\def_long_new:cpn {prg_replicate_7:n}#1{ + \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1#1} +\def_long_new:cpn {prg_replicate_8:n}#1{ + \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1#1#1} +\def_long_new:cpn {prg_replicate_9:n}#1{ + \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1#1#1#1} +% \end{macrocode} +% Users shouldn't ask for something to be replicated once or even +% not at all but\dots +% \begin{macrocode} +\def_long_new:cpn {prg_replicate_first_0:n}#1{\cs_end: } +\def_long_new:cpn {prg_replicate_first_1:n}#1{\cs_end: #1} +\def_long_new:cpn {prg_replicate_first_2:n}#1{\cs_end: #1#1} +\def_long_new:cpn {prg_replicate_first_3:n}#1{\cs_end: #1#1#1} +\def_long_new:cpn {prg_replicate_first_4:n}#1{\cs_end: #1#1#1#1} +\def_long_new:cpn {prg_replicate_first_5:n}#1{\cs_end: #1#1#1#1#1} +\def_long_new:cpn {prg_replicate_first_6:n}#1{\cs_end: #1#1#1#1#1#1} +\def_long_new:cpn {prg_replicate_first_7:n}#1{\cs_end: #1#1#1#1#1#1#1} +\def_long_new:cpn {prg_replicate_first_8:n}#1{\cs_end: #1#1#1#1#1#1#1#1} +\def_long_new:cpn {prg_replicate_first_9:n}#1{\cs_end: #1#1#1#1#1#1#1#1#1} +% \end{macrocode} +% +% +% +% +% \begin{macro}{\prg_stepwise_function:nnnN} +% \begin{macro}{\prg_stepwise_function_incr:nnnN} +% \begin{macro}{\prg_stepwise_function_decr:nnnN} +% A stepwise function. Firstly we check the direction of the steps +% |#2| since that will depend on which test we should use. If the +% step is positive we use a greater than test, otherwise a less than +% test. If the test comes out true exit, otherwise perform |#4|, +% add the step to |#1| and try again with this new value of |#1|. +% \begin{macrocode} +\def_long_new:NNn \prg_stepwise_function:nnnN 2{ + \num_compare:nNnTF{#2}<\c_zero + {\exp_args:No\prg_stepwise_function_decr:nnnN } + {\exp_args:No\prg_stepwise_function_incr:nnnN } + {\int_use:N\int_eval:n{#1}}{#2} +} +\def_long_new:NNn \prg_stepwise_function_incr:nnnN 4{ + \num_compare:nNnF {#1}>{#3} + { + #4{#1} + \exp_args:No \prg_stepwise_function_incr:nnnN + {\int_use:N\int_eval:n{#1 + #2}} + {#2}{#3}{#4} + } +} +\def_long_new:NNn \prg_stepwise_function_decr:nnnN 4{ + \num_compare:nNnF {#1}<{#3} + { + #4{#1} + \exp_args:No \prg_stepwise_function_decr:nnnN + {\int_use:N\int_eval:n{#1 + #2}} + {#2}{#3}{#4} + } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\l_prg_inline_level_int} +% \begin{macro}{\prg_stepwise_inline:nnnn} +% \begin{macro}{\prg_stepwise_inline_decr:nnnn} +% \begin{macro}{\prg_stepwise_inline_incr:nnnn} +% This function uses the same approach as for instance +% |\clist_map_inline:Nn| to allow arbitrary nesting. First construct +% the special function and then call an auxiliary one which just +% carries the newly constructed csname. +% \begin{macrocode} +\int_new:N\l_prg_inline_level_int +\def_long_new:NNn\prg_stepwise_inline:nnnn 4{ + \int_incr:N \l_prg_inline_level_int + \def:cpn{prg_stepwise_inline_\int_use:N\l_prg_inline_level_int :n}##1{#4} + \num_compare:nNnTF {#2}<\c_zero + {\exp_args:Nco \prg_stepwise_inline_decr:Nnnn } + {\exp_args:Nco \prg_stepwise_inline_incr:Nnnn } + {prg_stepwise_inline_\int_use:N\l_prg_inline_level_int :n} + {\int_use:N\int_eval:n{#1}} {#2} {#3} + \int_decr:N \l_prg_inline_level_int +} +\def_long_new:NNn \prg_stepwise_inline_incr:Nnnn 4{ + \num_compare:nNnF {#2}>{#4} + { + #1{#2} + \exp_args:NNo \prg_stepwise_inline_incr:Nnnn #1 + {\int_use:N\int_eval:n{#2 + #3}} {#3}{#4} + } +} +\def_long_new:NNn \prg_stepwise_inline_decr:Nnnn 4{ + \num_compare:nNnF {#2}<{#4} + { + #1{#2} + \exp_args:NNo \prg_stepwise_inline_decr:Nnnn #1 + {\int_use:N\int_eval:n{#2 + #3}} {#3}{#4} + } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prg_stepwise_variable:nnnNn} +% \begin{macro}{\prg_stepwise_variable_decr:nnnNn} +% \begin{macro}{\prg_stepwise_variable_incr:nnnNn} +% Almost the same as above. Just store the value in |#4| and execute +% |#5|. +% \begin{macrocode} +\def_long_new:NNn \prg_stepwise_variable:nnnNn 2 { + \num_compare:nNnTF {#2}<\c_zero + {\exp_args:No\prg_stepwise_variable_decr:nnnNn} + {\exp_args:No\prg_stepwise_variable_incr:nnnNn} + {\int_use:N\int_eval:n{#1}}{#2} +} +\def_long_new:NNn \prg_stepwise_variable_incr:nnnNn 5 { + \num_compare:nNnF {#1}>{#3} + { + \def:Npn #4{#1} #5 + \exp_args:No \prg_stepwise_variable_incr:nnnNn + {\int_use:N\int_eval:n{#1 + #2}}{#2}{#3}#4{#5} + } +} +\def_long_new:NNn \prg_stepwise_variable_decr:nnnNn 5 { + \num_compare:nNnF {#1}<{#3} + { + \def:Npn #4{#1} #5 + \exp_args:No \prg_stepwise_variable_decr:nnnNn + {\int_use:N\int_eval:n{#1 + #2}}{#2}{#3}#4{#5} + } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \subsubsection{Booleans} +% For normal booleans we set them to either "\c_true" or "\c_false" +% and then use "\if:w" to choose the right branch. The functions +% return either the TF, T, or F case \emph{after} ending the |\if:w|. +% We only define the |N| versions here as the |c| versions can easily +% be constructed with the expansion module. +% +% \begin{macro}{\bool_new:N} +% \begin{macro}{\bool_new:c} +% \begin{macro}{\bool_set_true:N} +% \begin{macro}{\bool_set_true:c} +% \begin{macro}{\bool_set_false:N} +% \begin{macro}{\bool_set_false:c} +% \begin{macro}{\bool_gset_true:N} +% \begin{macro}{\bool_gset_true:c} +% \begin{macro}{\bool_gset_false:N} +% \begin{macro}{\bool_gset_false:c} +% Defining and setting a boolean is easy. +% \begin{macrocode} +\def_new:Npn \bool_new:N #1 { \let_new:NN #1 \c_false } +\def_new:Npn \bool_new:c #1 { \let_new:cN #1 \c_false } +\def_new:Npn \bool_set_true:N #1 { \let:NN #1 \c_true } +\def_new:Npn \bool_set_true:c #1 { \let:cN #1 \c_true } +\def_new:Npn \bool_set_false:N #1 { \let:NN #1 \c_false } +\def_new:Npn \bool_set_false:c #1 { \let:cN #1 \c_false } +\def_new:Npn \bool_gset_true:N #1 { \glet:NN #1 \c_true } +\def_new:Npn \bool_gset_true:c #1 { \glet:cN #1 \c_true } +\def_new:Npn \bool_gset_false:N #1 { \glet:NN #1 \c_false } +\def_new:Npn \bool_gset_false:c #1 { \glet:cN #1 \c_false } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\bool_set_eq:NN} +% \begin{macro}{\bool_set_eq:Nc} +% \begin{macro}{\bool_set_eq:cN} +% \begin{macro}{\bool_set_eq:cc} +% \begin{macro}{\bool_gset_eq:NN} +% \begin{macro}{\bool_gset_eq:Nc} +% \begin{macro}{\bool_gset_eq:cN} +% \begin{macro}{\bool_gset_eq:cc} +% Setting a boolean to another is also pretty easy. +% \begin{macrocode} +\let_new:NN \bool_set_eq:NN \let:NN +\let_new:NN \bool_set_eq:Nc \let:Nc +\let_new:NN \bool_set_eq:cN \let:cN +\let_new:NN \bool_set_eq:cc \let:cc +\let_new:NN \bool_gset_eq:NN \glet:NN +\let_new:NN \bool_gset_eq:Nc \glet:Nc +\let_new:NN \bool_gset_eq:cN \glet:cN +\let_new:NN \bool_gset_eq:cc \glet:cc +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\l_tmpa_bool} +% \begin{macro}{\g_tmpa_bool} +% A few booleans just if you need them. +% \begin{macrocode} +\bool_new:N \l_tmpa_bool +\bool_new:N \g_tmpa_bool +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\bool_if:NTF} +% \begin{macro}{\bool_if:NT} +% \begin{macro}{\bool_if:NF} +% \begin{macro}{\bool_if:cTF} +% \begin{macro}{\bool_if:cT} +% \begin{macro}{\bool_if:cF} +% Straight forward here. +% \begin{macrocode} +\def_test_function_new:npn{bool_if:N}#1{\if:w #1} +\def_new:Npn \bool_if:cTF{\exp_args:Nc\bool_if:NTF} +\def_new:Npn \bool_if:cT{\exp_args:Nc\bool_if:NT} +\def_new:Npn \bool_if:cF{\exp_args:Nc\bool_if:NF} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\bool_if_p:N} +% \begin{macro}{\bool_if_p:c} +% We also make a predicate function for the "bool" data type but since +% we use "\c_true" and "\c_false" it's rather simple\dots{} +% Not that there's anything wrong in simplicity -- on the contrary! +% \begin{macrocode} +\def_new:Npn \bool_if_p:N #1 { #1 } +\let_new:NN \bool_if_p:c \cs_use:c +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\bool_whiledo:NT} +% \begin{macro}{\bool_whiledo:cT} +% \begin{macro}{\bool_whiledo:NF} +% \begin{macro}{\bool_whiledo:cF} +% A "while" loop where the boolean is tested before executing the +% statement. The "NT" version executes the "T" part as long as the +% boolean is true while the "NF" version executes the "F" part as +% long as the boolean is false. +% \begin{macrocode} +\def_long_new:Npn \bool_whiledo:NT #1 #2 { + \bool_if:NT #1 {#2 \bool_whiledo:NT #1 {#2}} +} +\def_new:Npn \bool_whiledo:cT{\exp_args:Nc\bool_whiledo:NT} +\def_long_new:Npn \bool_whiledo:NF #1 #2 { + \bool_if:NF #1 {#2 \bool_whiledo:NF #1 {#2}} +} +\def_new:Npn \bool_whiledo:cF{\exp_args:Nc\bool_whiledo:NF} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\bool_dowhile:NT} +% \begin{macro}{\bool_dowhile:cT} +% \begin{macro}{\bool_dowhile:NF} +% \begin{macro}{\bool_dowhile:cF} +% A "do-while" loop where the body is performed at least once and the +% boolean is tested after executing the body. Otherwise identical to +% the above functions. +% \begin{macrocode} +\def_long_new:Npn \bool_dowhile:NT #1 #2 { + #2 \bool_if:NT #1 {\bool_dowhile:NT #1 {#2}} +} +\def_new:Npn \bool_dowhile:cT{\exp_args:Nc\bool_dowhile:NT} +\def_long_new:Npn \bool_dowhile:NF #1 #2 { + #2 \bool_if:NF #1 {\bool_dowhile:NF #1 {#2}} +} +\def_new:Npn \bool_dowhiledo:cF{\exp_args:Nc\bool_dowhile:cF} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\bool_double_if:NNnnnn} +% \begin{macro}{\bool_double_if:cNnnnn} +% \begin{macro}{\bool_double_if:Ncnnnn} +% \begin{macro}{\bool_double_if:ccnnnn} +% Execute |#3| iff TT, |#4| iff TF, |#5| iff FT and |#6| iff +% FF. The name isn't that great but I'll have to think about +% that. Ideally it should be something with |TF| since only one of +% the cases is executed but we haven't got any naming scheme for +% this kind of thing so for now I'll just stick to simple |nnnn|. +% \begin{macrocode} +\def_new:Npn \bool_double_if:NNnnnn#1#2{ + \if_case:w \num_eval:w #1\scan_stop: + \if_case:w \num_eval:w #2\scan_stop: + \exp_after:NN\exp_after:NN\exp_after:NN \use_arg_i:nnnn + \else: + \exp_after:NN\exp_after:NN\exp_after:NN \use_arg_ii:nnnn + \fi: + \else: + \if_case:w \num_eval:w #2\scan_stop: + \exp_after:NN\exp_after:NN\exp_after:NN \use_arg_iii:nnnn + \else: + \exp_after:NN\exp_after:NN\exp_after:NN \use_arg_iv:nnnn + \fi: + \fi: +} +\def_new:Npn \bool_double_if:cNnnnn{\exp_args:Nc\bool_double_if:NNnnnn} +\def_new:Npn \bool_double_if:Ncnnnn{\exp_args:NNc\bool_double_if:NNnnnn} +\def_new:Npn \bool_double_if:ccnnnn{\exp_args:Ncc\bool_double_if:NNnnnn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \subsubsection{Generic testing} +% +% \begin{macro}{\prg_whiledo:nT} +% \begin{macro}{\prg_whiledo:nF} +% \begin{macro}{\prg_dowhile:nT} +% \begin{macro}{\prg_dowhile:nF} +% We provide these four generic while loops. |#1| is a test function +% and for the |T| functions it should be a test function ending with +% just the true case. Similar for the |F| types. +% \begin{macrocode} +\def_long_new:Npn \prg_whiledo:nT #1#2{ + #1 {#2 \prg_whiledo:nT {#1}{#2}} +} +\def_long_new:Npn \prg_whiledo:nF #1#2{ + #1 {#2 \prg_whiledo:nF {#1}{#2}} +} +\def_long_new:Npn \prg_dowhile:nT #1#2{ + #2 #1 {\prg_dowhile:nT {#1}{#2}} +} +\def_long_new:Npn \prg_dowhile:nF #1#2{ + #2 #1 {\prg_dowhile:nF {#1}{#2}} +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prg_if_predicate:nTF} +% \begin{macro}{\prg_if_predicate:nT} +% \begin{macro}{\prg_if_predicate:nF} +% As the boolean type is actually a predicate function, the next ones +% are just aliases. +% \begin{macrocode} +\let_new:NN \prg_if_predicate:nTF \bool_if:NTF +\let_new:NN \prg_if_predicate:nT \bool_if:NT +\let_new:NN \prg_if_predicate:nF \bool_if:NF +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\prg_if_predicate_or_p:nn} +% \begin{macro}{\prg_if_predicate_and_p:nn} +% \begin{macro}{\prg_if_predicate_not_p:n} +% The logic operations require a little more work. The idea is to have +% the end result of the logic "and" and "or" functions return "00" and +% "01" resp.\ to be used in an "\if:w" test. The arguments of the +% functions are always something expanding to "\c_true" or "\c_false" +% which is usually resulting from a predicate function or from another +% logical operation. All the functions start with a "0" and depending +% on the results of the tests return either "0" or "1" to the input +% stream to form a new true or false statement. +% +% The comments in the following is mostly to convince myseld of the +% validity of the code. +% \begin{macrocode} +\def_new:Npn \prg_if_predicate_or_p:nn #1#2{ +% \end{macrocode} +% Form a number of the input which is one of "0000", "0001", "0100", or +% "0101". If the truth value of both tests are false we get the "0101" +% else we get a number less than that. So we check if the number formed +% is less than $101$. +% \begin{macrocode} + \if_num:w #1#2<\c_hundred_one +% \end{macrocode} +% If it is we put a "\c_true" back into the input stream. +% \begin{macrocode} + \c_true + \else: +% \end{macrocode} +% Otherwise we insert "\c_false". +% \begin{macrocode} + \c_false + \fi: +} +% \end{macrocode} +% The "and" function is a little different. Again we can have input of +% the types "0000", "0001", "0100", or "0101". As we require both +% values to be \m{true} in order to continue we simply check if the +% number formed by the input is "0" or not and then put the +% corresponding "0" or "1" back in the input stream as above. We could +% use "\if_num:w" for this test as well but that'll require us to read +% the additional "=\c_zero" which runs a little slower than using +% "\if_case:w" directly, so we use the latter. +% \begin{macrocode} +\def_new:Npn \prg_if_predicate_and_p:nn #1#2{ + \if_case:w #1#2 ~ + \c_true + \else: + \c_false + \fi: +} +% \end{macrocode} +% The "not" function checks a single truth value and reverses it. Here +% we either get a "00" or "01". If the input equals "0" we put a "1" +% in the input stream, else we put a "0". Again we use "\if_case:w" +% because it's slightly faster. +% \begin{macrocode} +\def_new:Npn \prg_if_predicate_not_p:n #1{ + \if_case:w #1 ~ + \c_false + \or: + \c_true + \fi: +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\prg_if_predicate_ors_p:n} +% \begin{macro}{\prg_if_predicate_ands_p:n} +% \begin{macro}{\prg_if_predicate_andor_aux:NNN} +% \begin{macro}{\prg_if_predicate_andor_break:NNN } +% For longer lists of predicates we can't rely on such structures +% as above. The "\prg_if_predicate_ands_p:n" would have been easy to +% program as simply +% \begin{verbatim} +% \def_new:Npn \prg_if_predicate_and_p:n #1 { +% 0\tex_ifcase:D #1 ~ \exp_after:NN 0 \else: \exp_after:NN 1 \fi: +% } +% \end{verbatim} +% but this would fail with a "! Number too big." in case we were +% testing six predicate functions where the first was false. This +% would mean we would have to first convert the string from binary +% into numerical and then check. While challenging and interesting +% in itself (See \textsf{binhex}) it still imposes a restriction of +% 15 predicate functions\footnote{We would probably never hit that +% limit but why create a restriction when we can avoid it?} and we +% haven't dealt with the "or" case either. +% +% The solution below expands a predicate function until |\c_false| or +% |\c_true| are seen and expanded to |01| or |00| respectively. If +% we're testing the logical AND operation, all predicate functions +% must return \meta{true}; if they don't we can exit and return +% \meta{false}. In an OR operation, we just need one predicate +% function to return \meta{true}, the rest don't matter. Since every +% expansion in the internal loop results in a result of either |00| +% or |01|, we can test against this number to decide what to do. +% +% First up is the top level functions. +% \begin{macrocode} +\def_long_new:Npn \prg_if_predicate_ands_p:n #1{ + \exp_after:NN \prg_if_predicate_andor_aux:NNN \exp_after:NN \c_true + \int_to_roman:w -`0 #1 \scan_stop: \scan_stop: +} +\def_long_new:Npn \prg_if_predicate_ors_p:n #1{ + \exp_after:NN \prg_if_predicate_andor_aux:NNN \exp_after:NN \c_false + \int_to_roman:w -`0 #1 \scan_stop: \scan_stop: +} +% \end{macrocode} +% When we reach the inner loop we have already expanded all tokens in +% the first predicate function as far as possible. This means that +% either are arguments |#2| and |#3| \emph{both} |\scan_stop:| or else +% |#2| is |0| and |#3| is |0| if the predicate returned \meta{true} or +% |1| if it returned \meta{false}. If we reached the end we return +% \meta{true} for the AND function and \meta{false} for the OR +% function. If |#3| is |0| and we are doing the OR test, we want to +% exit and return \meta{true}. If |#3| is |0| and we are in the AND +% test we must continue to check the remaining predicate functions. If +% |#3| is |1| and we are in the OR test we continue in case a later +% predicate function returns \meta{true}. Finally, if |#3| is |1| and +% we are in the AND test we can exit and return \meta{false} before +% deciding what to do. +% \begin{macrocode} +\def_new:Npn \prg_if_predicate_andor_aux:NNN #1#2#3{ + \token_if_eq_meaning:NNTF \scan_stop: #2 + { #1 } + { + \int_compare:nNnTF #3 = #1 + { \exp_after:NN \prg_if_predicate_andor_aux:NNN } + { \exp_after:NN \prg_if_predicate_andor_break:NNN } + \exp_after:NN #1 \int_to_roman:w -`0 + } +} +% \end{macrocode} +% The break loop is called when we know what the final outcome +% is. However we keep expanding because a)~we don't know which tokens +% we might have left dangling ahead and b)~it also provides error +% checking on the remaining predicate functions. |#1| is \meta{false} +% for the OR function and \meta{true} for the AND function so we +% reverse them here. +% \begin{macrocode} +\def_new:Npn \prg_if_predicate_andor_break:NNN #1#2#3{ + \token_if_eq_meaning:NNTF \scan_stop: #2 + { \if:w #1\c_false\else:\c_true\fi: } + { + \exp_after:NN \prg_if_predicate_andor_break:NNN \exp_after:NN #1 + \int_to_roman:w -`0 + } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsubsection{Sorting} +% +% +% \begin{macro}{\prg_define_quicksort:nnn} +% |#1| is the name, |#2| and |#3| are the tokens enclosing the +% argument. For the somewhat strange \meta{clist} type which doesn't +% enclose the items but uses a separator we define it by hand +% afterwards. When doing the first pass, the algorithm wraps all +% elements in braces and then uses a generic quicksort which works +% on token lists. +% +% As an example +% \begin{quote} +% |\prg_define_quicksort:nnn{seq}{\seq_elt:w}{\seq_elt_end:w}| +% \end{quote} +% defines the user function |\seq_quicksort:n| and furthermore +% expects to use the two functions |\seq_quicksort_compare:nnTF| +% which compares the items and |\seq_quicksort_function:n| which is +% placed before each sorted item. It is up to the programmer to +% define these functions when needed. For the |seq| type a sequence +% is a token list pointer, so one additionally has to define +% \begin{quote} +% |\def:Npn \seq_quicksort:N{\exp_args:No\seq_quicksort:n}| +% \end{quote} +% +% +% For details on the implementation see ``Sorting in \TeX's Mouth'' +% by Bernd Raichle. Firstly we define the function for parsing the +% ininital list and then the braced list afterwards. +% \begin{macrocode} +\def_new:NNn \prg_define_quicksort:nnn 3 { + \def_long:cNx{#1_quicksort:n}1{ + \exp_not:c{#1_quicksort_start_partition:w} ##1 + \exp_not:n{#2\q_nil#3\q_stop} + } + \def_long:cNx{#1_quicksort_braced:n}1{ + \exp_not:c{#1_quicksort_start_partition_braced:n} ##1 + \exp_not:N\q_nil\exp_not:N\q_stop + } + \def_long:cpx {#1_quicksort_start_partition:w} #2 ##1 #3{ + \exp_not:N \quark_if_nil:nT {##1}\exp_not:N \use_none_delimit_by_q_stop:w + \exp_not:c{#1_quicksort_do_partition_i:nnnw} {##1}{}{} + } + \def_long:cNx {#1_quicksort_start_partition_braced:n} 1 { + \exp_not:N \quark_if_nil:nT {##1}\exp_not:N \use_none_delimit_by_q_stop:w + \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn} {##1}{}{} + } +% \end{macrocode} +% Now for doing the partitions. +% \begin{macrocode} + \def_long:cpx {#1_quicksort_do_partition_i:nnnw} ##1##2##3 #2 ##4 #3 { + \exp_not:N \quark_if_nil:nTF {##4} \exp_not:c {#1_do_quicksort_braced:nnnnw} + { + \exp_not:c{#1_quicksort_compare:nnTF}{##1}{##4} + \exp_not:c{#1_quicksort_partition_greater_ii:nnnn} + \exp_not:c{#1_quicksort_partition_less_ii:nnnn} + } + {##1}{##2}{##3}{##4} + } + \def_long:cNx {#1_quicksort_do_partition_i_braced:nnnn} 4 { + \exp_not:N \quark_if_nil:nTF {##4} \exp_not:c {#1_do_quicksort_braced:nnnnw} + { + \exp_not:c{#1_quicksort_compare:nnTF}{##1}{##4} + \exp_not:c{#1_quicksort_partition_greater_ii_braced:nnnn} + \exp_not:c{#1_quicksort_partition_less_ii_braced:nnnn} + } + {##1}{##2}{##3}{##4} + } + \def_long:cpx {#1_quicksort_do_partition_ii:nnnw} ##1##2##3 #2 ##4 #3 { + \exp_not:N \quark_if_nil:nTF {##4} \exp_not:c {#1_do_quicksort_braced:nnnnw} + { + \exp_not:c{#1_quicksort_compare:nnTF}{##4}{##1} + \exp_not:c{#1_quicksort_partition_less_i:nnnn} + \exp_not:c{#1_quicksort_partition_greater_i:nnnn} + } + {##1}{##2}{##3}{##4} + } + \def_long:cNx {#1_quicksort_do_partition_ii_braced:nnnn} 4 { + \exp_not:N \quark_if_nil:nTF {##4} \exp_not:c {#1_do_quicksort_braced:nnnnw} + { + \exp_not:c{#1_quicksort_compare:nnTF}{##4}{##1} + \exp_not:c{#1_quicksort_partition_less_i_braced:nnnn} + \exp_not:c{#1_quicksort_partition_greater_i_braced:nnnn} + } + {##1}{##2}{##3}{##4} + } +% \end{macrocode} +% This part of the code handles the two branches in each +% sorting. Again we will also have to do it braced. +% \begin{macrocode} + \def_long:cNx {#1_quicksort_partition_less_i:nnnn} 4{ + \exp_not:c{#1_quicksort_do_partition_i:nnnw}{##1}{##2}{{##4}##3}} + \def_long:cNx {#1_quicksort_partition_less_ii:nnnn} 4{ + \exp_not:c{#1_quicksort_do_partition_ii:nnnw}{##1}{##2}{##3{##4}}} + \def_long:cNx {#1_quicksort_partition_greater_i:nnnn} 4{ + \exp_not:c{#1_quicksort_do_partition_i:nnnw}{##1}{{##4}##2}{##3}} + \def_long:cNx {#1_quicksort_partition_greater_ii:nnnn} 4{ + \exp_not:c{#1_quicksort_do_partition_ii:nnnw}{##1}{##2{##4}}{##3}} + \def_long:cNx {#1_quicksort_partition_less_i_braced:nnnn} 4{ + \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn}{##1}{##2}{{##4}##3}} + \def_long:cNx {#1_quicksort_partition_less_ii_braced:nnnn} 4{ + \exp_not:c{#1_quicksort_do_partition_ii_braced:nnnn}{##1}{##2}{##3{##4}}} + \def_long:cNx {#1_quicksort_partition_greater_i_braced:nnnn} 4{ + \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn}{##1}{{##4}##2}{##3}} + \def_long:cNx {#1_quicksort_partition_greater_ii_braced:nnnn} 4{ + \exp_not:c{#1_quicksort_do_partition_ii_braced:nnnn}{##1}{##2{##4}}{##3}} +% \end{macrocode} +% Finally, the big kahuna! This is where the sub-lists are sorted. +% \begin{macrocode} + \def_long:cpx {#1_do_quicksort_braced:nnnnw} ##1##2##3##4\q_stop { + \exp_not:c{#1_quicksort_braced:n}{##2} + \exp_not:c{#1_quicksort_function:n}{##1} + \exp_not:c{#1_quicksort_braced:n}{##3} + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\prg_quicksort:n} +% A simple version. Sorts a list of tokens, uses the function +% |\prg_quicksort_compare:nnTF| to compare items, and places the +% function |\prg_quicksort_function:n| in front of each of them. +% \begin{macrocode} +\prg_define_quicksort:nnn {prg}{}{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prg_quicksort_function:n} +% \begin{macro}{\prg_quicksort_compare:nnTF} +% \begin{macrocode} +\let:NN \prg_quicksort_function:n \ERROR +\let:NN \prg_quicksort_compare:nnTF \ERROR +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% That's it (for now). +% \begin{macrocode} +%</initex|package> +%<*showmemory> +\showMemUsage +%</showmemory> +% \end{macrocode} +% +% \endinput +% +% $Log$ +% Revision 1.19 2006/08/08 10:26:09 morten +% Fixed bugs in stepwise functions +% +% Revision 1.18 2006/07/30 14:41:28 morten +% Added stepwise functions (loops going from i to k with step of j) plus quicksort. +% +% Revision 1.17 2006/07/06 14:57:13 morten +% Moved code in the `miscellaneus' section to l3basics. +% +% Revision 1.16 2006/06/03 18:55:12 morten +% Added special double boolean switches. +% +% Revision 1.15 2006/03/20 18:26:38 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.14 2006/01/19 22:31:56 morten +% Added \bool_set_eq:NN functions plus made function collection +% complete. +% +% Revision 1.13 2006/01/04 00:58:17 morten +% Added generic loops. Changed some names plus syntax for some of the +% logical operations. Added code for defining functions with specified +% number of arguments. +% +% Revision 1.12 2005/12/27 10:01:55 morten +% Changed RCS information retrieval. Moved tlist code to l3tlp. Added +% code for inserting n copies of something. Changed \bool_while to +% \bool_whiledo. +% +% Revision 1.11 2005/04/25 15:01:59 morten +% Fixed some names. Improved \peek_char_generic:NNTF to not use token registers. +% +% Revision 1.10 2005/04/23 14:36:12 morten +% Changed \c_left|right_brace_token to \c_group_begin_token and +% \c_group_end_token. Fixed definitions of \tlist_if_head_XXX functions. +% Added example for PR/3080. +% +% Revision 1.9 2005/04/09 21:08:43 morten +% Documentation blunders fixed +% +% Revision 1.8 2005/04/06 21:27:15 morten +% More tlist functions, Moved \engine_aleph:TF to l3basics, new peek-ahead functions, definitions of implicit characters. +% +% Revision 1.7 2005/03/26 21:11:14 morten +% Fix typo in \scan_align_safe_stop: +% +% Revision 1.6 2005/03/22 23:23:30 morten +% Moved \tlist_ functions from l3basics. Added align-safe versions of important functions. Reorganized documentation slightly. +% +% Revision 1.5 2005/03/16 22:36:10 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.4 2005/03/11 21:28:20 braams +% Fixed the use of RCS information; added \StopEventually +% diff --git a/Master/texmf-dist/source/latex/expl3/l3prop.dtx b/Master/texmf-dist/source/latex/expl3/l3prop.dtx index e430507aabf..2315892f1a6 100644 --- a/Master/texmf-dist/source/latex/expl3/l3prop.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3prop.dtx @@ -1,15 +1,50 @@ % \iffalse -%% File: l3prop.dtx Copyright (C) 1990-1998 LaTeX3 project -% +%% File: l3prop.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} %<*dtx> - \ProvidesFile{l3prop.dtx} +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse %</dtx> -%<package>\NeedsTeXFormat{LaTeX2e} -%<package>\ProvidesPackage{l3prop} -%<driver> \ProvidesFile{l3prop.drv} -% \fi -% \ProvidesFile{l3prop.dtx} - [1998/05/04 v1.0e L3 Experimental Property Lists] +%\fi +\GetIdInfo$Id: l3prop.dtx 581 2006-12-12 12:28:27Z morten $ + {L3 Experimental Property Lists} % % \iffalse %<*driver> @@ -22,7 +57,6 @@ % \fi % % -% \GetFileInfo{l3prop.dtx} % \title{The \textsf{l3prop} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ @@ -34,22 +68,22 @@ % % % \section{Property lists} -% +% % \LaTeX3 implements a data structure which allows to store information % associated with individual tokens. -% +% % \subsection{Functions} -% +% % \begin{function}{% % \prop_new:N | -% \prop_new:O | +% \prop_new:c | % } % \begin{syntax} % "\prop_new:N" <plist> % \end{syntax} % Defines <plist> to be a variable of type p-list. % \end{function} -% +% % \begin{function}{% % \prop_clear:N | % \prop_gclear:N | @@ -59,15 +93,19 @@ % \end{syntax} % These functions locally or globally clear <plist>. % \end{function} -% +% % \begin{function}{% % \prop_put:NNn | +% \prop_put:ccn | % \prop_gput:NNn | % \prop_gput:NNo | % \prop_gput:NOo | +% \prop_gput:Ncn | % \prop_gput:OOo | % \prop_gput:NOx | +% \prop_gput:cNn | % \prop_gput:ccn | +% \prop_gput:cco | % \prop_gput:ccx | % } % \begin{syntax} @@ -77,7 +115,7 @@ % <plist>. If <key> has already a meaning within <plist> this value is % overwritten. % \end{function} -% +% % \begin{function}{% % \prop_gput_if_new:NNn | % } @@ -88,10 +126,13 @@ % <plist> but only if <key> has so far no meaning within <plist>. % overwritten. % \end{function} -% +% % \begin{function}{% % \prop_get:NNN | +% \prop_get:cNN | % \prop_gget:NNN | +% \prop_gget:NcN | +% \prop_gget:cNN | % } % \begin{syntax} % "\prop_get:NNN" <plist> <key> <tlp> @@ -102,16 +143,19 @@ %^^A See section \ref{sec:quarks} to test this. % The assignment is done either locally or globally. % \end{function} -% +% % \begin{function}{% -% \prop_set_eq:NN +% \prop_set_eq:NN | +% \prop_set_eq:cc | +% \prop_gset_eq:NN | +% \prop_gset_eq:cc % } % \begin{syntax} % "\prop_set_eq:NN" <plist 1> <plist 2> % \end{syntax} % A fast assignment of <plist>s. % \end{function} -% +% % \begin{function}{% % \prop_get_gdel:NNN | % } @@ -121,7 +165,7 @@ % Like "\prop_get:NNN" but additionally removes <key> (and its <info>) % from <plist>. % \end{function} -% +% % \begin{function}{% % \prop_del:NN | % \prop_gdel:NN | @@ -132,43 +176,68 @@ % Locally or globally deletes <key> and its <info> from <plist> if % found. Otherwise does nothing. % \end{function} -% -% \begin{function}{\prop_map:NN | -% \prop_map:cN +% +% +% \begin{function}{\prop_map_function:NN | +% \prop_map_function:cN | +% \prop_map_function:cc | % } % \begin{syntax} -% "\prop_map:NN" <plist> <function> +% "\prop_map_function:NN" <plist> <function> % \end{syntax} % Maps <function> which should be a function with two arguments (<key> -% and <info>) over every <key> <info> pair of <plist>. +% and <info>) over every <key> <info> pair of <plist>. Expandable. % \end{function} -% +% % \begin{function}{\prop_map_inline:Nn | % \prop_map_inline:cn % } % \begin{syntax} % "\prop_map_inline:Nn" <plist> "{" <inline function> "}" % \end{syntax} -% Just like "\prop_map:NN" but with the function of two arguments -% supplied as inline code. Within <inline function> refer to the -% arguments via "##1" (<key>) and "##2" (<info>). -% -% Not implemented so far! +% Just like "\prop_map_function:NN" but with the function of two arguments +% supplied as inline code. Within <inline function> refer to the +% arguments via "##1" (<key>) and "##2" (<info>). Fast but not +% expandable. % \end{function} -% +% +% +% \begin{function}{% +% \prop_map_break:w | +% } +% \begin{syntax} +% "\prop_map_break:w" +% \end{syntax} +% For breaking out of a loop. To be used inside "TF" type functions. +% \end{function} +% +% +% % \subsection{Predicates and conditionals} -% -% \begin{function}{\prop_empty:NTF} +% +% \begin{function}{\prop_if_empty:NTF} % \begin{syntax} -% "\prop_empty:NTF" <plist> "{"<true code>"}{"<false code>"}" +% "\prop_if_empty:NTF" <plist> "{"<true code>"}{"<false code>"}" % \end{syntax} % Set of conditionals that test whether or not a particular <plist> % is empty. % \end{function} -% +% +% \begin{function}{\prop_if_eq:NNF | +% \prop_if_eq:ccF +% } +% \begin{syntax} +% "\prop_if_eq:NNF" <plist1> <plist2> "{"<false code>"}" +% \end{syntax} +% Execute <false code> if <plist1> doesn't hold the same token list as +% <plist2>. +% \end{function} +% +% % \begin{function}{% % \prop_if_in:NNTF | % \prop_if_in:NOTF | +% \prop_if_in:ccTF | % } % \begin{syntax} % "\prop_if_in:NNTF" <plist><key>"{"<true code>"}{"<false code>"}" @@ -176,16 +245,16 @@ % Tests if <key> is used in <plist> and then either executes <true code> % or <false code>. % \end{function} -% +% % \subsection{Internal functions} -% +% % \begin{function}{% % \prop_put_aux:w | % \prop_put_if_new_aux:w | % } % Internal functions implementing the put operations. % \end{function} -% +% % \begin{function}{% % \prop_get_aux:w | % \prop_get_del_aux:w | @@ -193,26 +262,27 @@ % } % Internal functions implementing the get and delete operations. % \end{function} -% +% % \begin{function}{% % \prop_if_in_aux:w | % } % Internal function implementing the key test operation. % \end{function} -% +% % \begin{function}{% -% \prop_map_aux:w | +% \prop_map_function_aux:NNn | +% \prop_map_inline_aux:Nn | % } -% Internal function implementing the map operation. +% Internal functions implementing the map operations. % \end{function} -% +% % \begin{function}{% -% \prop_map_funct:Nn | +% \l_prop_inline_level_num | % } -% Internal name for the function that is mapped over p-list during -% execution of "\prop_map:NN". +% Fake integer used in internal name for function used inside +% "\prop_map_inline:NN". % \end{function} -% +% % \begin{function}{\prop_split_aux:NNn} % \begin{syntax} % "\prop_split_aux:NNn" <plist> <key> <cmd> @@ -223,20 +293,21 @@ % <key> in <plist>, then the 2 arg is "\q_no_value " and the 3rd arg is % empty; otherwise the 3rd argument has the two extra tokens <prop> % "\q_no_value" at the end. -% +% % This function is used to implement various get operations. % \end{function} -% -% -% \section {Implementation} +% +% \StopEventually{} +% +% \subsection {The Implementation} % % We start by ensuring that the required packages are loaded. % \begin{macrocode} -%<package>\RequirePackage{l3seq}\par -%<*package> +%<package>\RequirePackage{l3toks}\par +%<*initex|package> % \end{macrocode} -% -% A property list is a control sequence whose top-level expansion is +% +% A property list is a token register whose contents is % of the form `\zz{tok$\sb1$}\zv{val$\sb1$} \ldots{} % \zz{tok$\sb{}n$}\zv{val$\sb{}n$}'. The properties have to be single % token, the values might be arbitrary token lists they get surrounded @@ -246,29 +317,39 @@ % the appropriate functions. % % \begin{macro}{\prop_new:N} -% \begin{macro}{\prop_new:O} % \begin{macro}{\prop_new:c} -% Property lists are a special case of sequences, so allocating -% them is the same as allocating sequences. +% Property lists are implemented as token lists. % \begin{macrocode} -\let_new:NN \prop_new:N \seq_new:N -\let_new:NN \prop_new:O \seq_new:O -\let_new:NN \prop_new:c \seq_new:c +\def_new:Npn \prop_new:N #1{\toks_new:N #1} +\def_new:Npn \prop_new:c {\exp_args:Nc \prop_new:N} % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} % % \begin{macro}{\prop_clear:N} +% \begin{macro}{\prop_clear:c} % \begin{macro}{\prop_gclear:N} +% \begin{macro}{\prop_gclear:c} % The same goes for clearing a property list, either % locally or globally. % \begin{macrocode} -\let_new:NN \prop_clear:N \seq_clear:N -\let_new:NN \prop_gclear:N \seq_gclear:N +\let_new:NN \prop_clear:N \toks_clear:N +\def_new:Npn \prop_clear:c {\exp_args:Nc\prop_clear:N} +\let_new:NN \prop_gclear:N \toks_gclear:N +\def_new:Npn \prop_gclear:c {\exp_args:Nc\prop_gclear:N} % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prop_use:N} +% The same goes for clearing a property list, either +% locally or globally. +% \begin{macrocode} +\let_new:NN \prop_use:N \toks_use:N +% \end{macrocode} +% \end{macro} % % \begin{macro}{\prop_split_aux:NNn} % |\prop_split_aux:NNn|\zz{plist}\zz{prop}\zz{cmd} invokes \zz{cmd} @@ -281,33 +362,42 @@ % \begin{macrocode} \def_long_new:Npn \prop_split_aux:NNn #1#2#3{ \def:Npn \tmp:w ##1#2##2##3\q_stop {#3{##1}{##2}{##3}} - \exp_after:NN\tmp:w #1#2\q_no_value \q_stop} + \exp_after:NN\tmp:w \prop_use:N#1#2\q_no_value \q_stop} % \end{macrocode} % \end{macro} % % \begin{macro}{\prop_get:NNN} +% \begin{macro}{\prop_get:cNN} % \begin{macro}{\prop_get_aux:w} % |\prop_get:NNN |\zz{plist}\zz{prop}\zz{tlp} defines % \zz{tlp} to be the value associated with \zz{prop} in \zz{plist}, % |\q_no_value| if not found. % \begin{macrocode} -\def_long_new:Npn \prop_get:NNN #1#2{\prop_split_aux:NNn - #1#2\prop_get_aux:w} -\def_long_new:Npn \prop_get_aux:w #1#2#3#4{\tlp_set:Nn#4{#2}} +\def_long_new:NNn \prop_get:NNN 2{ + \prop_split_aux:NNn #1#2\prop_get_aux:w} +\def_long_new:NNn \prop_get_aux:w 4{\toks_set:Nn#4{#2}} +\def_new:Npn \prop_get:cNN { \exp_args:Nc \prop_get:NNN } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}{\prop_gget:NNN} +% \begin{macro}{\prop_gget:NcN} +% \begin{macro}{\prop_gget:cNN} % \begin{macro}{\prop_gget_aux:w} % The global version of the previous function. % \begin{macrocode} -\def_long_new:Npn \prop_gget:NNN #1#2{\prop_split_aux:NNn - #1#2\prop_gget_aux:w} -\def_long_new:Npn \prop_gget_aux:w #1#2#3#4{\tlp_gset:Nn#4{#2}} +\def_long_new:NNn \prop_gget:NNN 2{ + \prop_split_aux:NNn #1#2\prop_gget_aux:w} +\def_new:Npn \prop_gget:NcN {\exp_args:NNc \prop_gget:NNN} +\def_new:Npn \prop_gget:cNN {\exp_args:Nc \prop_gget:NNN} +\def_long_new:NNn \prop_gget_aux:w 4{\toks_gset:Nn#4{#2}} % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\prop_get_gdel:NNN} % \begin{macro}{\prop_get_del_aux:w} @@ -316,45 +406,63 @@ % from \m{property_list}. One probably also needs the local % variants or only the local one, or\ldots\ We decide this later. % \begin{macrocode} -\def_long_new:Npn \prop_get_gdel:NNN #1#2#3{\prop_split_aux:NNn - #1#2{\prop_get_del_aux:w #3{\tlp_gset:Nn #1}#2}} -\def_long_new:Npn \prop_get_del_aux:w #1#2#3#4#5#6{ - \tlp_set:Nn #1{#5} - \quark_if_no_value:NF#1 - {\def:Npn \tmp:w ##1#3\q_no_value {#2{#4##1}} - \tmp:w #6}} +\def_long_new:NNn \prop_get_gdel:NNN 3{ + \prop_split_aux:NNn #1#2{\prop_get_del_aux:w #3{\toks_gset:Nn #1}#2}} +\def_long_new:NNn \prop_get_del_aux:w 6{ + \quark_if_no_value:nF{#5} { + \def:Npn \tmp:w ##1#3\q_no_value {#2{#4##1}} + \tmp:w #6} +} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\prop_put:NNn} -% \begin{macro}{\prop_put_aux:w} +% \begin{macro}{\prop_put:ccn} % \begin{macro}{\prop_gput:NNn} -% \begin{macro}{\prop_gput:NNx} % \begin{macro}{\prop_gput:NNo} +% \begin{macro}{\prop_gput:NNx} % \begin{macro}{\prop_gput:NOx} % \begin{macro}{\prop_gput:NOo} +% \begin{macro}{\prop_gput:Ncn} % \begin{macro}{\prop_gput:OOo} +% \begin{macro}{\prop_gput:cNn} +% \begin{macro}{\prop_gput:ccn} +% \begin{macro}{\prop_gput:cco} % \begin{macro}{\prop_gput:ccx} +% \begin{macro}{\prop_put_aux:w} % |\prop_put:NNn |\zz{plist}\zz{prop}\zv{val} adds/changes the % value associated with \zz{prop} in \zz{plist} to \zv{val}. % \begin{macrocode} -\def_long_new:Npn \prop_put:NNn #1#2{\prop_split_aux:NNn - #1#2{\prop_put_aux:w {\tlp_set:Nn #1}#2}} -\def_long_new:Npn \prop_gput:NNn #1#2{\prop_split_aux:NNn - #1#2{\prop_put_aux:w {\tlp_gset:Nn #1}#2}} +\def_long_new:NNn \prop_put:NNn 2{ + \prop_split_aux:NNn #1#2{ + \toks_clear:N #1 + \prop_put_aux:w {\toks_put_right:Nn #1}#2} +} +\def_new:Npn \prop_put:ccn {\exp_args:Ncc \prop_put:NNn } +\def_long_new:NNn \prop_gput:NNn 2{ + \prop_split_aux:NNn #1#2{ + \toks_gclear:N #1 + \prop_put_aux:w {\toks_gput_right:Nn #1}#2} +} \def_new:Npn \prop_gput:NNo {\exp_args:NNNo \prop_gput:NNn} -\def_new:Npn \prop_gput:NOx {\exp_args:Nnox \prop_gput:NNn} \def_new:Npn \prop_gput:NNx {\exp_args:Nnnx \prop_gput:NNn} +\def_new:Npn \prop_gput:NOx {\exp_args:Nnox \prop_gput:NNn} \def_new:Npn \prop_gput:NOo {\exp_args:NNOo \prop_gput:NNn} +\def_new:Npn \prop_gput:Ncn {\exp_args:NNc \prop_gput:NNn } \def_new:Npn \prop_gput:OOo {\exp_args:NOOo \prop_gput:NNn} +\def_new:Npn \prop_gput:cNn {\exp_args:Nc \prop_gput:NNn} \def_new:Npn \prop_gput:ccn {\exp_args:Ncc \prop_gput:NNn} +\def_new:Npn \prop_gput:cco {\exp_args:Ncco \prop_gput:NNn} \def_new:Npn \prop_gput:ccx {\exp_args:Nccx \prop_gput:NNn} -\def_long_new:Npn \prop_put_aux:w #1#2#3#4#5#6{ - \quark_if_no_value:nTF {#4} - {#1{#2{#6}#3}} - {\def:Npn \tmp:w ##1#2\q_no_value {#1{#3#2{#6}##1}} - \tmp:w #5}} +\def_long_new:NNn \prop_put_aux:w 6{ + #1{#2{#6}#3} + \quark_if_no_value:nF {#4} + { + \def:Npn \tmp:w ##1#2\q_no_value {#1{##1}} + \tmp:w #5 + } +} % \end{macrocode} % \end{macro} % \end{macro} @@ -365,6 +473,11 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\prop_del:NN} % \begin{macro}{\prop_gdel:NN} @@ -372,11 +485,11 @@ % |\prop_del:NN |\zz{plist}\zz{prop} deletes the entry for % \zz{prop} in \zz{plist}, if any. % \begin{macrocode} -\def_long_new:Npn \prop_del:NN #1#2{\prop_split_aux:NNn - #1#2{\prop_del_aux:w {\tlp_set:Nn #1}#2}} -\def_long_new:Npn \prop_gdel:NN #1#2{\prop_split_aux:NNn - #1#2{\prop_del_aux:w {\tlp_gset:Nn #1}#2}} -\def_long_new:Npn \prop_del_aux:w #1#2#3#4#5{\quark_if_no_value:nF {#4} +\def_long_new:NNn \prop_del:NN 2{ + \prop_split_aux:NNn #1#2{\prop_del_aux:w {\toks_set:Nn #1}#2}} +\def_long_new:NNn \prop_gdel:NN 2{ + \prop_split_aux:NNn #1#2{\prop_del_aux:w {\toks_gset:Nn #1}#2}} +\def_long_new:NNn \prop_del_aux:w 5{\quark_if_no_value:nF {#4} % \end{macrocode} % I see no reason for updating the property list if we don't find % any entry. @@ -392,20 +505,23 @@ % % \begin{macro}{\prop_if_in:NNTF} % \begin{macro}{\prop_if_in:NOTF} +% \begin{macro}{\prop_if_in:ccTF} % \begin{macro}{\prop_if_in_aux:w} % |\prop_if_in:NNTF| \m{property_list} \m{property_key} % \m{true_case} \m{false_case} will check whether or not % \m{property_key} is on the \m{property_list} and then select % either the true or false case. % \begin{macrocode} -\def_new:Npn \prop_if_in:NNTF #1#2{\prop_split_aux:NNn - #1#2\prop_if_in_aux:w} +\def_new:NNn \prop_if_in:NNTF 2{ + \prop_split_aux:NNn #1#2\prop_if_in_aux:w} \def_new:Npn \prop_if_in:NOTF {\exp_args:Nno \prop_if_in:NNTF} -\def_new:Npn \prop_if_in_aux:w #1#2#3{\quark_if_no_value:nTF {#2}} +\def_new:Npn \prop_if_in:ccTF {\exp_args:Ncc \prop_if_in:NNTF} +\def_new:NNn \prop_if_in_aux:w 3{\quark_if_no_value:nFT {#2}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}{\prop_gput_if_new:NNn} % |\prop_gput_if_new:NNn| \m{property_list} \m{property_key} @@ -423,66 +539,183 @@ % F. and Louis A. which makes writing macros sometimes difficult; I % find myself humming instead of working): % \begin{macrocode} -\def_long_new:Npn \prop_gput_if_new:NNn #1#2{\prop_split_aux:NNn #1#2 - {\prop_put_if_new_aux:w #1#2}} -\def_long_new:Npn \prop_put_if_new_aux:w #1#2#3#4#5#6{ +\def_long_new:NNn \prop_gput_if_new:NNn 2{ + \prop_split_aux:NNn #1#2{\prop_put_if_new_aux:w #1#2}} +\def_long_new:NNn \prop_put_if_new_aux:w 6{ \quark_if_no_value:nT {#4}{#1{#2{#6}#3}}} % \end{macrocode} % \end{macro} % % % \begin{macro}{\prop_set_eq:NN} +% \begin{macro}{\prop_set_eq:Nc} +% \begin{macro}{\prop_set_eq:cN} +% \begin{macro}{\prop_set_eq:cc} +% \begin{macro}{\prop_gset_eq:NN} +% \begin{macro}{\prop_gset_eq:Nc} +% \begin{macro}{\prop_gset_eq:cN} +% \begin{macro}{\prop_gset_eq:cc} % This makes two \m{plist}s have the same contents. % \begin{macrocode} -\let_new:NN\prop_set_eq:NN\tlp_set_eq:NN +\let_new:NN \prop_set_eq:NN \toks_set_eq:NN +\let_new:NN \prop_set_eq:Nc \toks_set_eq:Nc +\let_new:NN \prop_set_eq:cN \toks_set_eq:cN +\let_new:NN \prop_set_eq:cc \toks_set_eq:cc +\let_new:NN \prop_gset_eq:NN \toks_gset_eq:NN +\let_new:NN \prop_gset_eq:Nc \toks_gset_eq:Nc +\let_new:NN \prop_gset_eq:cN \toks_gset_eq:cN +\let_new:NN \prop_gset_eq:cc \toks_gset_eq:cc % \end{macrocode} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % -% \begin{macro}{\prop_empty:NTF} +% \begin{macro}{\prop_if_empty_p:N} +% \begin{macro}{\prop_if_empty_p:c} +% \begin{macro}{\prop_if_empty:NTF} +% \begin{macro}{\prop_if_empty:NT} +% \begin{macro}{\prop_if_empty:NF} +% \begin{macro}{\prop_if_empty:cTF} +% \begin{macro}{\prop_if_empty:cT} +% \begin{macro}{\prop_if_empty:cF} % This conditional takes a \m{plist} as its argument and evaluates % either the true or the false case, depending on whether or not % \m{plist} contains any properties. % \begin{macrocode} -\let_new:NN \prop_empty:NTF \tlp_empty:NTF +\let_new:NN \prop_if_empty_p:N \toks_if_empty_p:N +\let_new:NN \prop_if_empty_p:c \toks_if_empty_p:c +\let_new:NN \prop_if_empty:NTF \toks_if_empty:NTF +\let_new:NN \prop_if_empty:NT \toks_if_empty:NT +\let_new:NN \prop_if_empty:NF \toks_if_empty:NF +\let_new:NN \prop_if_empty:cTF \toks_if_empty:cTF +\let_new:NN \prop_if_empty:cT \toks_if_empty:cTF +\let_new:NN \prop_if_empty:cF \toks_if_empty:cF % \end{macrocode} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% % +% \begin{macro}{\prop_if_eq:NNTF} +% \begin{macro}{\prop_if_eq:NNT} +% \begin{macro}{\prop_if_eq:NNF} +% \begin{macro}{\prop_if_eq:NcTF} +% \begin{macro}{\prop_if_eq:NcT} +% \begin{macro}{\prop_if_eq:NcF} +% \begin{macro}{\prop_if_eq:cNTF} +% \begin{macro}{\prop_if_eq:cNT} +% \begin{macro}{\prop_if_eq:cNF} +% \begin{macro}{\prop_if_eq:ccTF} +% \begin{macro}{\prop_if_eq:ccT} +% \begin{macro}{\prop_if_eq:ccF} +% This function test whether the property lists that are in its first +% two arguments are equal; if they are not |#3| is executed. +% \begin{macrocode} +\def_new:NNn \prop_if_eq:NNTF 2 { + \tlist_if_eq:xxTF{\prop_use:N #1}{\prop_use:N #2} +} +\def_new:NNn \prop_if_eq:NNT 2 { + \tlist_if_eq:xxT{\prop_use:N #1}{\prop_use:N #2} +} +\def_new:NNn \prop_if_eq:NNF 2 { + \tlist_if_eq:xxF{\prop_use:N #1}{\prop_use:N #2} +} +\def_new:Npn \prop_if_eq:NcTF {\exp_args:NNc \prop_if_eq:NNTF} +\def_new:Npn \prop_if_eq:NcT {\exp_args:NNc \prop_if_eq:NNT} +\def_new:Npn \prop_if_eq:NcF {\exp_args:NNc \prop_if_eq:NNF} +\def_new:Npn \prop_if_eq:cNTF {\exp_args:Nc \prop_if_eq:NNTF} +\def_new:Npn \prop_if_eq:cNT {\exp_args:Nc \prop_if_eq:NNT} +\def_new:Npn \prop_if_eq:cNF {\exp_args:Nc \prop_if_eq:NNF} +\def_new:Npn \prop_if_eq:ccTF {\exp_args:Ncc \prop_if_eq:NNTF} +\def_new:Npn \prop_if_eq:ccT {\exp_args:Ncc \prop_if_eq:NNT} +\def_new:Npn \prop_if_eq:ccF {\exp_args:Ncc \prop_if_eq:NNF} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % -% \begin{macro}{\prop_map:NN} -% \begin{macro}{\prop_map:cN} -% \begin{macro}{\prop_map_funct:Nn} +% \begin{macro}{\prop_map_function:NN} +% \begin{macro}{\prop_map_function:cN} +% \begin{macro}{\prop_map_function:cc} +% \begin{macro}{\prop_map_function_aux:NNn} % Maps a function on every entry in the property list. The % function must take 2 arguments: a key and a value. % \begin{macrocode} -\let_new:NN \prop_map_funct:Nn \use_none:nn -\def_new:Npn \prop_map:NN #1#2{ - \let:NN \prop_map_funct:Nn #2 - \exp_after:NN\prop_map_aux:w #1\q_stop \q_stop} -\def_new:Npn \prop_map_aux:w #1#2{ - \if_meaning:NN#1\q_stop \else: - \prop_map_funct:Nn #1{#2} - \exp_after:NN\prop_map_aux:w - \fi:} -\def_new:Npn \prop_map:cN { \exp_args:Nc \prop_map:NN } +\def_new:Npn \prop_map_function:NN #1#2{ + \exp_after:NN \prop_map_function_aux:NNn + \exp_after:NN #2 \prop_use:N #1 \q_nil \q_no_value \q_stop +} +\def_new:Npn \prop_map_function_aux:NNn #1#2#3{ + \if_meaning:NN \q_nil #1 + \exp_after:NN \prop_map_break:w + \fi: + #1#2{#3} + \prop_map_function_aux:NNn #1 +} +\def_new:Npn \prop_map_function:cN {\exp_args:Nc \prop_map_function:NN } +\def_new:Npn \prop_map_function:cc {\exp_args:Ncc \prop_map_function:NN} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} -% +% \end{macro} % % \begin{macro}{\prop_map_inline:Nn} % \begin{macro}{\prop_map_inline:cn} -% To be supplied. +% \begin{macro}{\prop_map_inline_aux:Nn} +% \begin{macro}{\l_prop_inline_level_num} +% The inline functions are straight forward. It takes longer +% to test if the list is empty than to run it on an empty list so +% we don't waste time doing that. % \begin{macrocode} -\let_new:NN \prop_map_inline:Nn \ERROR -\let_new:NN \prop_map_inline:cn \ERROR +\num_new:N \l_prop_inline_level_num +\def_new:Npn \prop_map_inline:Nn #1#2 { + \num_incr:N \l_prop_inline_level_num + \def_long:cpn {prop_map_inline_ \num_use:N \l_prop_inline_level_num :n} + ##1##2{#2} + \exp_args:NcE \prop_map_function:N + {prop_map_inline_ \num_use:N \l_prop_inline_level_num :n} + \prop_use:N #1 + \q_nil \q_no_value \q_stop + \num_decr:N \l_prop_inline_level_num +} +\def_new:Npn \prop_map_inline:cN { \exp_args:Nc \prop_map_inline:NN } + % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prop_map_break:w} +% The break statement. +% \begin{macrocode} +\let_new:NN \prop_map_break:w \use_none_delimit_by_q_stop:w +% \end{macrocode} +% \end{macro} % % Show token usage: % \begin{macrocode} -%</package> +%</initex|package> %<*showmemory> %\showMemUsage %</showmemory> @@ -596,4 +829,22 @@ %</unused> % \end{macrocode} % - +% \endinput +% +% $Log$ +% Revision 1.15 2006/03/20 18:26:38 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.14 2005/12/27 16:00:44 morten +% Update map functions and changed RCS information retrieval +% +% Revision 1.13 2005/03/22 23:26:14 morten +% Added more functions, removed dependency of l3seq +% +% Revision 1.12 2005/03/16 22:36:04 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.11 2005/03/11 21:40:35 braams +% Fixed the use of RCS information; added \StopEventually +% diff --git a/Master/texmf-dist/source/latex/expl3/l3quark.dtx b/Master/texmf-dist/source/latex/expl3/l3quark.dtx index 1f95aa6fe71..2511109c1cf 100644 --- a/Master/texmf-dist/source/latex/expl3/l3quark.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3quark.dtx @@ -1,15 +1,50 @@ % \iffalse -%% File: l3quark.dtx Copyright (C) 1990-1998 LaTeX3 project +%% File: l3quark.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- % +%<package>\RequirePackage{l3names} %<*dtx> - \ProvidesFile{l3quark.dtx} +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse %</dtx> -%<package>\NeedsTeXFormat{LaTeX2e} -%<package>\ProvidesPackage{l3quark} -%<driver> \ProvidesFile{l3quark.drv} -% \fi -% \ProvidesFile{l3quark.dtx} - [1998/05/20 v1.0e L3 Experimental Quark Commands] +%\fi +\GetIdInfo$Id: l3quark.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental Quark Commands} % % \iffalse %<*driver> @@ -22,7 +57,6 @@ % \fi % % -% \GetFileInfo{l3quark.dtx} % \title{The \textsf{l3quark} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ @@ -34,23 +68,25 @@ % % \section{Quarks} %^^A \label{sec:quarks} -% -% +% +% % A special type of constants in \LaTeX3 are `quarks'. These are control % sequences that expand to themselves and should therefore NEVER be % executed directly in the code. This would result in an endless loop! -% -% They are meant to be used as delimiter is weird functions (for example -% as the stop token (i.e., "\q_stop"). They also permit the following -% ingenious trick: when you pick up a token in a temporary, and you want -% to know whether you have picked up a particular quark, all you have to -% do is compare the temporary to the quark using "\if_meaning:NN". A -% set of special quark testing functions is set up below. -% +% +% They are meant to be used as delimiter is weird functions (for +% example as the stop token (i.e., "\q_stop"). They also permit the +% following ingenious trick: when you pick up a token in a temporary, +% and you want to know whether you have picked up a particular quark, +% all you have to do is compare the temporary to the quark using +% "\if_meaning:NN". A set of special quark testing functions is set up +% below. All the quark testing functions are expandable although the +% ones testing only single tokens are much faster. +% % By convention all constants of type quark start out with "\q_". -% +% % \subsection{Functions} -% +% % \begin{function}{% % \quark_new:N | % } @@ -59,28 +95,33 @@ % \end{syntax} % Defines <quark> to be a new constant of type "quark". % \end{function} -% +% % \begin{function}{% +% \quark_if_no_value_p:n | % \quark_if_no_value:nTF | % \quark_if_no_value:nF | % \quark_if_no_value:nT | +% \quark_if_no_value_p:N | % \quark_if_no_value:NTF | +% \quark_if_no_value:NT | % \quark_if_no_value:NF | % } % \begin{syntax} -% "\quark_if_no_value:nTF" "{" <token list> "}" +% "\quark_if_no_value:nTF" "{"<token list>"}" % " {"<true code>"}{"<false code>"}" % "\quark_if_no_value:NTF" <tlp> % " {"<true code>"}{"<false code>"}" % \end{syntax} % This tests whether or not <token list> contains only the quark % "\q_no_value". -% +% % If <token list> to be tested is stored in a token list pointer use % "\quark_if_no_value:NTF", or "\quark_if_no_value:NF" or check the % value directly with "\if_meaning:NN". All those cases are faster then -% "\quark_if_no_value:nTF" so should be preferred. -% +% "\quark_if_no_value:nTF" so should be preferred.\footnote{Clarify +% semantic of the ``n'' case \ldots{} i think it is not implement +% according to what we originally intended /FMi} +% % \begin{texnote} % But be aware of the fact that "\if_meaning:NN" can result in an % overflow of \TeX{}'s parameter stack since it leaves the corresponding @@ -90,33 +131,75 @@ % and so allows tail-recursion. % \end{texnote} % \end{function} -% +% +% \begin{function}{% +% \quark_if_nil_p:N | +% \quark_if_nil:NTF | +% \quark_if_nil:NT | +% \quark_if_nil:NF | +% } +% \begin{syntax} +% "\quark_if_nil:NTF" <token> +% " {"<true code>"}{"<false code>"}" +% \end{syntax} +% This tests whether or not <token> is equal to the quark +% "\q_nil". +% +% This is a useful test for recursive loops which typically has +% "\q_nil" as an end marker. +% \end{function} +% +% +% \begin{function}{% +% \quark_if_nil_p:n | +% \quark_if_nil:nTF | +% \quark_if_nil:nT | +% \quark_if_nil:nF | +% \quark_if_nil_p:o | +% \quark_if_nil:oTF | +% \quark_if_nil:oT | +% \quark_if_nil:oF | +% } +% \begin{syntax} +% "\quark_if_nil:nTF" "{"<tokens>"}" +% "{"<true code>"}{"<false code>"}" +% \end{syntax} +% This tests whether or not <tokens> is equal to the quark +% "\q_nil". +% +% This is a useful test for recursive loops which typically has +% "\q_nil" as an end marker. +% \end{function} +% +% % \subsection{Constants} -% +% % \begin{variable}{\q_no_value} The canonical `missing value quark' % that is returned by certain functions to denote that a requested value % is not found in the data structure. % \end{variable} -% +% % \begin{variable}{\q_stop} % This constant is used as a a marker in parameter text. This allows a % scanning function to find the end of some input string. % \end{variable} -% +% % \begin{variable}{\q_nil} % This constant represent the nil pointer in pointer structures. % \end{variable} -% -% \section{Implementation} +% +% \StopEventually{} +% +% \subsection{The Implementation} % % We start by ensuring that the required packages are loaded. % We check for \texttt{l3expan} since this a basic package that is % essential for use of any higher-level package. % \begin{macrocode} %<package>\RequirePackage{l3expan}\par -%<*package> +%<*initex|package> % \end{macrocode} -% +% % \begin{macro}{\quark_new:N} % Allocate a new quark. % \begin{macrocode} @@ -153,60 +236,193 @@ % \end{macro} % % +% \begin{macro}{\quark_if_no_value_p:N} % \begin{macro}{\quark_if_no_value:NTF} +% \begin{macro}{\quark_if_no_value:NT} % \begin{macro}{\quark_if_no_value:NF} +% \begin{macro}{\quark_if_no_value_p:n} % \begin{macro}{\quark_if_no_value:nTF} % \begin{macro}{\quark_if_no_value:nT} % \begin{macro}{\quark_if_no_value:nF} +% \begin{macro}{\quark_if_no_value:nFT} % Here we test if we found a special quark as the first argument. -% The argument might contain an arbitrary list of tokens, therefore -% we have to wrap it up in a token list pointer. % \begin{macrocode} -\def_new:Npn \quark_if_no_value:NTF #1{ +\def_long_test_function_new:npn {quark_if_no_value:N} #1 { % \end{macrocode} % We better start with |\q_no_value| as the first argument since % the whole thing may otherwise loop if |#1| is wrongly given % a string like |aabc| instead of a single token.\footnote{It may % still loop in special circumstances however!} % \begin{macrocode} - \if_meaning:NN\q_no_value#1 - \exp_after:NN\use_choice_i:nn - \else: \exp_after:NN\use_choice_ii:nn \fi:} + \if_meaning:NN\q_no_value#1} +\def_long_new:Npn \quark_if_no_value_p:N #1{ + \if_meaning:NN \q_no_value #1 \c_true + \else: \c_false \fi: +} % \end{macrocode} -% It would be possible to speed up the following commands by -% providing individual implementations similar to the one above. -% Should perhaps be done if they are used often! +% We also provide an |n| type. If run under a sufficiently new +% pdf\eTeX, it uses a built-in primitive for string comparisons, +% otherwise it uses the slower |\str_if_eq_var_p:nf| function. In the +% latter case it would be faster to use a temporary token list pointer +% but it would render the function non-expandable. Using the pdf\eTeX\ +% primitive is the preferred approach. Note that we have to add a +% manual space token in the first part of the comparison, otherwise it +% is gobbled by |\str_if_eq_var_p:nf|. The reason for using this +% function instead of |\str_if_eq_p:nn| is that a sequence like +% \verb*+ \q_no_value+ will test equal to |\q_no_value| using the +% latter test function and unfortunately this example turned up in one +% application. % \begin{macrocode} -\def_new:Npn \quark_if_no_value:NF #1{\quark_if_no_value:NTF {#1}\use_noop:} -\def_new:Npn \quark_if_no_value:nTF #1{\tlp_gset:Nn \g_testa_tlp {#1} - \quark_if_no_value:NTF\g_testa_tlp} -\def_new:Npn \quark_if_no_value:nF #1{\quark_if_no_value:nTF {#1}\use_noop:} -\def_new:Npn \quark_if_no_value:nT #1#2{\quark_if_no_value:nTF {#1} - {#2}\use_noop:} +\cs_if_really_free:cTF{pdf_strcmp:D}{ + \def_long_new:Npn \quark_if_no_value_p:n #1{ + \if:w \exp_args:No \str_if_eq_var_p:nf +%<package> {\token_to_string:N\q_no_value\space} +%<initex> {\token_to_string:N\q_no_value\text_put_sp:} + {\tlist_to_str:n{#1}} + \c_true + \else: + \c_false + \fi: + } +} +{ + \def_long_new:Npn \quark_if_no_value_p:n #1{ + \if_num:w + \pdf_strcmp:D {\exp_not:N \q_no_value}{\exp_not:n{#1}}=\c_zero + \c_true \else: \c_false \fi: + } +} +\def_long_test_function_new:npn {quark_if_no_value:n} #1 { + \if:w \quark_if_no_value_p:n{#1}} % \end{macrocode} +% We also define a version where the true and false code is ordered +% differently. +% \begin{macrocode} +\def_long:Npn \quark_if_no_value:nFT #1{ + \if:w \quark_if_no_value_p:n{#1} + \exp_after:NN\use_arg_ii:nn + \else: + \exp_after:NN\use_arg_i:nn + \fi: +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % +% \begin{macro}{\quark_if_nil_p:N} % \begin{macro}{\quark_if_nil:NTF} +% \begin{macro}{\quark_if_nil:NT} +% \begin{macro}{\quark_if_nil:NF} +% A function to check for the presence of |\q_nil|. +% \begin{macrocode} +\def_long_new:Npn \quark_if_nil_p:N #1{ + \if_meaning:NN \q_nil #1 \c_true + \else: \c_false \fi: +} +\def_long_test_function_new:npn {quark_if_nil:N}#1{ + \if_meaning:NN\q_nil#1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\quark_if_nil_p:n} +% \begin{macro}{\quark_if_nil:nTF} +% \begin{macro}{\quark_if_nil:nT} +% \begin{macro}{\quark_if_nil:nF} +% \begin{macro}{\quark_if_nil_p:o} +% \begin{macro}{\quark_if_nil:oTF} +% \begin{macro}{\quark_if_nil:oT} +% \begin{macro}{\quark_if_nil:oF} % A function to check for the presence of |\q_nil|. % \begin{macrocode} -\def_new:Npn\quark_if_nil:NTF#1{ - \if_meaning:NN#1\q_nil - \exp_after:NN\use_choice_i:nn - \else: - \exp_after:NN\use_choice_ii:nn\fi:} +\cs_if_really_free:cTF{pdf_strcmp:D}{ + \def_long_new:Npn \quark_if_nil_p:n #1{ + \if:w \exp_args:No \str_if_eq_var_p:nf +%<package> {\token_to_string:N\q_nil\space} +%<initex> {\token_to_string:N\q_nil\text_put_sp:} + {\tlist_to_str:n{#1}} + \c_true + \else: + \c_false + \fi: + } +} +{ + \def_long_new:Npn \quark_if_nil_p:n #1{ + \if_num:w + \pdf_strcmp:D {\exp_not:N \q_nil}{\exp_not:n{#1}}=\c_zero + \c_true \else: \c_false \fi: + } +} +\def_long_test_function_new:npn {quark_if_nil:n} #1 { + \if:w \quark_if_nil_p:n{#1}} +\def_new:Npn \quark_if_nil_p:o{\exp_args:No\quark_if_nil_p:n} +\def_new:Npn \quark_if_nil:oTF{\exp_args:No\quark_if_nil:nTF} +\def_new:Npn \quark_if_nil:oT {\exp_args:No\quark_if_nil:nT} +\def_new:Npn \quark_if_nil:oF {\exp_args:No\quark_if_nil:nF} % \end{macrocode} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % Show token usage: % \begin{macrocode} -%</package> +%</initex|package> %<*showmemory> \showMemUsage %</showmemory> % \end{macrocode} % +% \endinput +% +% $Log$ +% Revision 1.22 2006/07/30 14:39:02 morten +% Changed all quark functions to be expandable regardless of whether +% \pdfstrcmp is available. +% +% Revision 1.21 2006/07/25 15:34:21 morten +% Added the non-expandable \quark_if_nil:nTF plus variants. +% +% Revision 1.20 2006/07/23 13:43:47 morten +% Fixed minor bug in \quark_if_no_value_p:n +% +% Revision 1.19 2006/03/20 18:26:38 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.18 2006/01/04 01:18:31 morten +% Changed \quark_if_no_value:nTF to be expandable. Added a few predicate +% functions and updated documentation. +% +% Revision 1.17 2005/12/27 10:04:41 morten +% Minor changes plus changed RCS information retrieval +% +% Revision 1.16 2005/10/27 14:12:28 morten +% Added gobble-until-quark functions. +% +% Revision 1.15 2005/07/14 18:50:31 morten +% Added \quark_if_nil:NF +% +% Revision 1.14 2005/04/06 13:55:57 morten +% Fixed \quark_if_nil:NTF +% +% Revision 1.13 2005/03/16 22:35:57 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.12 2005/03/11 21:41:27 braams +% Fixed the use of RCS information; added \StopEventually % diff --git a/Master/texmf-dist/source/latex/expl3/l3seq.dtx b/Master/texmf-dist/source/latex/expl3/l3seq.dtx index f3da69642ef..dff922a84d2 100644 --- a/Master/texmf-dist/source/latex/expl3/l3seq.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3seq.dtx @@ -1,15 +1,51 @@ % \iffalse -%% File: l3seq.dtx Copyright (C) 1990-1998 LaTeX3 project -% +%% File: l3seq.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} %<*dtx> - \ProvidesFile{l3seq.dtx} +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse %</dtx> -%<package>\NeedsTeXFormat{LaTeX2e} -%<package>\ProvidesPackage{l3seq} -%<driver> \ProvidesFile{l3seq.drv} -% \fi -% \ProvidesFile{l3seq.dtx} - [1998/04/20 v1.0d L3 Experimental Token List Pointers] +%\fi +\GetIdInfo$Id: l3seq.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental sequences and stacks} +% % % \iffalse %<*driver> @@ -22,7 +58,6 @@ % \fi % % -% \GetFileInfo{l3seq.dtx} % \title{The \textsf{l3seq} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ @@ -33,8 +68,8 @@ % % % -% \section{Sequence} -% +% \section{Sequences} +% % \LaTeX3 implements a data type called `sequences'. These are special % token lists that can be accessed via special function on the `left'. % Appending tokens is possible at both ends. Appended token lists can be @@ -43,26 +78,25 @@ % functions that are used to structure sequences (see section internal % functions below). It is also possible to map functions on such % sequences so that they are executed for every item on the sequence. -% -% All functions that return items from a sequence in some <tlp> assume -% that the <tlp> is local. See remarks below if you need a global +% +% All functions that return items from a sequence in some \m{tlp} assume +% that the \m{tlp} is local. See remarks below if you need a global % returned value. -% +% % The defined functions are not orthogonal in the sense that every % possible variation possible is actually available. If you need a new % variant use the expansion functions described in the package % \texttt{l3expan} to build it. -% +% % Adding items to the left of a sequence can currently be done with % either something like "\seq_put_left:Nn" or with a ``stack'' function % like "\seq_push:Nn" which has the same effect. Maybe one should % therefore remove the ``left'' functions totally. -% +% % \subsection{Functions} -% +% % \begin{function}{% % \seq_new:N | -% \seq_new:O | % \seq_new:c | % } % \begin{syntax} @@ -70,7 +104,7 @@ % \end{syntax} % Defines <sequence> to be a variable of type sequences. % \end{function} -% +% % \begin{function}{% % \seq_clear:N | % \seq_clear:c | @@ -82,7 +116,7 @@ % \end{syntax} % These functions locally or globally clear <sequence>. % \end{function} -% +% % \begin{function}{% % \seq_put_left:Nn | % \seq_put_left:No | @@ -99,10 +133,11 @@ % or right of <sequence>. <token list> might get expanded before % appending. % \end{function} -% +% % \begin{function}{% % \seq_gput_left:Nn | % \seq_gput_right:Nn | +% \seq_gput_right:Nc | % \seq_gput_right:No | % \seq_gput_right:cn | % \seq_gput_right:co | @@ -114,7 +149,7 @@ % Globally appends <token list> as a single item to the left % or right of <sequence>. % \end{function} -% +% % \begin{function}{% % \seq_get:NN | % \seq_get:cN | @@ -132,7 +167,30 @@ % But if this kind of construction is used often enough a separate % function should be provided. % \end{function} -% +% +% \begin{function}{% +% \seq_set_eq:NN +% } +% \begin{syntax} +% "\seq_set_eq:NN" <seq1> <seq2> +% \end{syntax} +% Function that locally makes <seq1> identical to <seq2>. +% \end{function} +% +% +% +% \begin{function}{% +% \seq_gset_eq:NN | +% \seq_gset_eq:cN | +% \seq_gset_eq:Nc | +% \seq_gset_eq:cc +% } +% \begin{syntax} +% "\seq_gset_eq:NN" <seq1> <seq2> +% \end{syntax} +% Function that globally makes <seq1> identical to <seq2>. +% \end{function} +% % \begin{function}{% % \seq_gconcat:NNN | % \seq_gconcat:ccc | @@ -143,7 +201,19 @@ % Function that conatenates <seq2> and <seq3> and globally assigns the % result to <seq1>. % \end{function} -% +% +% \begin{function}{\seq_map_variable:NNn | +% \seq_map_variable:cNn +% } +% \begin{syntax} +% "\seq_map_variable:NNn" <sequence> <tlp> "{" <code using tlp> "}" +% \end{syntax} +% Every element in <sequence> is assigned to <tlp> and then <code +% using tlp> is executed. The operation is not expandable which means +% that it can't be used within write operations etc. However, this +% function can be nested which the others can't. +% \end{function} +% % \begin{function}{\seq_map:NN} % \begin{syntax} % "\seq_map:NN" <sequences> <function> @@ -153,11 +223,11 @@ % within a sub-group so that side effects can be achieved locally. The % operation is not expandable which means that it can't be used within % write operations etc. -% +% % In the current implementation the next functions are more efficient and % should be preferred. % \end{function} -% +% % \begin{function}{\seq_map_inline:Nn | % \seq_map_inline:cn % } @@ -171,34 +241,37 @@ % The operation is not expandable which means that it can't be used % within write operations etc. % \end{function} -% +% % \subsection{Predicates and conditionals} -% -% \begin{function}{\seq_empty_p:N} +% +% \begin{function}{\seq_if_empty_p:N} % \begin{syntax} -% "\seq_empty_p:N" <sequence> +% "\seq_if_empty_p:N" <sequence> % \end{syntax} % This predicate returns `true' if <sequence> is `empty' i.e., doesn't % contain any tokens. % \end{function} -% +% % \begin{function}{% -% \seq_empty:NTF | -% \seq_empty:cTF | -% \seq_empty:NF | -% \seq_empty:cF | +% \seq_if_empty:NTF | +% \seq_if_empty:cTF | +% \seq_if_empty:NF | +% \seq_if_empty:cF | % } % \begin{syntax} -% "\seq_empty:NTF" <sequence> "{" <true code> "}{" <false code> "}" +% "\seq_if_empty:NTF" <sequence> "{" <true code> "}{" <false code> "}" % \end{syntax} % Set of conditionals that test whether or not a particular <sequence> % is empty and if so executes either <true code> or <false code>. % \end{function} -% +% % \begin{function}{% % \seq_if_in:NnTF | % \seq_if_in:cnTF | % \seq_if_in:coTF | +% \seq_if_in:cxTF | +% \seq_if_in:NnF | +% \seq_if_in:cnF | % } % \begin{syntax} % "\seq_if_in:NnTF" <sequ> "{" <item> "}{" <true code> "}{" <false code> "}" @@ -206,16 +279,16 @@ % Function that tests if <item> is in <sequ>. Depending on the result % either <true code> or <false code> is executed. % \end{function} -% +% % \subsection{Internal functions} -% -% \begin{function}{\seq_empty_err:N} +% +% \begin{function}{\seq_if_empty_err:N} % \begin{syntax} -% "\seq_empty_err:N" <sequence> +% "\seq_if_empty_err:N" <sequence> % \end{syntax} % Signals an \LaTeX3 error if <sequence> is empty. % \end{function} -% +% % \begin{function}{\seq_pop_aux:nnNN} % \begin{syntax} % "\seq_pop_aux:nnNN" <assign1> <assign2> <sequence> <tlp> @@ -224,7 +297,7 @@ % <assign1> and assigns the tail to <sequence> using <assign2>. This % function could be used to implement a global return function. % \end{function} -% +% % \begin{function}{% % \seq_get_aux:w | % \seq_pop_aux:w | @@ -234,7 +307,7 @@ % Functions used to implement put and get operations. They are not for % meant for direct use. % \end{function} -% +% % \begin{function}{% % \seq_elt:w | % \seq_elt_end: } @@ -243,19 +316,71 @@ % are not supposed to show up as tokens within an item appended to a % sequence. % \end{function} -% % -% \section {Implementation} +% \section{Sequence Stacks} +% +% Special sequences in \LaTeX3 are `stacks' with their usual operations +% of`push', `pop', and `top'. They are internally implemented as +% sequences and share some of the functions (like "\seq_new:N" etc.) +% +% \subsection{Functions} +% +% \begin{function}{% +% \seq_push:Nn | +% \seq_push:No | +% \seq_push:cn | +% \seq_gpush:Nn | +% \seq_gpush:No | +% \seq_gpush:cn | +% } +% \begin{syntax} +% "\seq_push:Nn" <stack> "{" <token list> "}" +% \end{syntax} +% Locally or globally pushes <token list> as a single item onto the +% <stack>. <token list> might get expanded before the operation. +% \end{function} +% +% \begin{function}{% +% \seq_pop:NN | +% \seq_pop:cN | +% \seq_gpop:NN | +% \seq_gpop:cN | +% } +% \begin{syntax} +% "\seq_pop:NN" <stack> <tlp> +% \end{syntax} +% Functions that assign the top item of <stack> to the token +% list pointer <tlp> and removes it from <stack>! +% \end{function} +% +% \begin{function}{% +% \seq_top:NN | +% \seq_top:cN | +% } +% \begin{syntax} +% "\seq_top:NN" <stack> <tlp> +% \end{syntax} +% Functions that locally assign the top item of <stack> to the token +% list pointer <tlp>. Item is not removed from <stack>! +% \end{function} +% +% \subsection{Predicates and conditionals} +% +% Use "seq" functions. +% +% \StopEventually{} +% +% \subsection {Implementation} +% % % We start by ensuring that the required packages are loaded. % \begin{macrocode} -%<package&!check>\RequirePackage{l3toks} %<package&!check>\RequirePackage{l3quark} +%<package&!check>\RequirePackage{l3tlp} %<package&check>\RequirePackage{l3chk} %<package>\RequirePackage{l3expan} -%<*package> % \end{macrocode} -% +% % A sequence is a control sequence whose top-level expansion is of the % form `|\seq_elt:w| \m{text$\sb1$} |\seq_elt_end:| \ldots{} % |\seq_elt:w| \zv{text$\sb{n}$} \ldots'. We use explicit delimiters @@ -264,27 +389,25 @@ % % \begin{macro}{\seq_elt:w} % \begin{macro}{\seq_elt_end:} -% We allocate the delimiters and make them noops as default. +% We allocate the delimiters and make them errors if executed. % \begin{macrocode} -\let_new:NN \seq_elt:w \use_noop: -\let_new:NN \seq_elt_end: \use_noop: +%<*initex|package> +\let_new:NN \seq_elt:w \ERROR +\let_new:NN \seq_elt_end: \ERROR % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\seq_new:N} -% \begin{macro}{\seq_new:O} % \begin{macro}{\seq_new:c} % Sequences are implemented using token lists. % \begin{macrocode} \def_new:Npn \seq_new:N #1{\tlp_new:Nn #1{}} \def_new:Npn \seq_new:c {\exp_args:Nc \seq_new:N} -\def_new:Npn \seq_new:O {\exp_args:No \seq_new:N} % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} % % \begin{macro}{\seq_clear:N} % \begin{macro}{\seq_clear:c} @@ -318,35 +441,30 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\seq_empty_p:N} +% \begin{macro}{\seq_if_empty_p:N} % A predicate which evaluates to |\c_true| iff the sequence is empty. % \begin{macrocode} -\let_new:NN \seq_empty_p:N \tlp_empty_p:N +\let_new:NN \seq_if_empty_p:N \tlp_if_empty_p:N % \end{macrocode} % \end{macro} % -% \begin{macro}{\seq_empty:NTF} -% \begin{macro}{\seq_empty:cTF} -% \begin{macro}{\seq_empty:NF} -% \begin{macro}{\seq_empty:cF} -% |\seq_empty:NTF|\m{seq}\m{true~case}\m{false~case} will check +% \begin{macro}{\seq_if_empty:NTF} +% \begin{macro}{\seq_if_empty:cTF} +% \begin{macro}{\seq_if_empty:NF} +% \begin{macro}{\seq_if_empty:cF} +% |\seq_if_empty:NTF|\m{seq}\m{true~case}\m{false~case} will check % whether the \m{seq} is empty and then select one of the other -% arguments. |seq_empty:cTF| turns its first argument into a +% arguments. |seq_if_empty:cTF| turns its first argument into a % control sequence to get the name of the sequence. % \begin{macrocode} -\def_new:Npn \seq_empty:NTF #1{ - \if_meaning:NN#1\c_empty_tlp - \exp_after:NN\use_choice_i:nn - \else: \exp_after:NN\use_choice_ii:nn \fi:} -\def_new:Npn \seq_empty:cTF {\exp_args:Nc\seq_empty:NTF} +\let_new:NN \seq_if_empty:NTF \tlp_if_empty:NTF +\def_new:Npn \seq_if_empty:cTF {\exp_args:Nc\seq_if_empty:NTF} % \end{macrocode} % A variant of this, is only to do something if the sequence is -% {\em not} empty. +% \emph{not} empty. % \begin{macrocode} -\def_new:Npn \seq_empty:NF #1{ - \if_meaning:NN#1\c_empty_tlp \exp_after:NN\use_none:n - \else: \exp_after:NN\use:n \fi:} -\def_new:Npn \seq_empty:cF {\exp_args:Nc\seq_empty:NF} +\let_new:NN \seq_if_empty:NF \tlp_if_empty:NF +\def_new:Npn \seq_if_empty:cF {\exp_args:Nc\seq_if_empty:NF} % \end{macrocode} % \end{macro} % \end{macro} @@ -354,10 +472,10 @@ % \end{macro} % % -% \begin{macro}{\seq_empty_err:N} +% \begin{macro}{\seq_if_empty_err:N} % Signals an error if the sequence is empty. % \begin{macrocode} -\def_new:Npn \seq_empty_err:N #1{\if_meaning:NN#1\c_empty_tlp +\def_new:Npn \seq_if_empty_err:N #1{\if_meaning:NN#1\c_empty_tlp % \end{macrocode} % As I said before, I don't think we need to provide checks for this % kind of error, since it is a severe internal macro package error @@ -365,7 +483,7 @@ % next line of code should be probably removed. % \begin{macrocode} \tlp_clear:N \l_testa_tlp % catch prefixes - \err_latex_bug:n{Empty~sequence~`\token_to_string:N#1'}\fi:} + \err_latex_bug:x{Empty~sequence~`\token_to_string:N#1'}\fi:} % \end{macrocode} % \end{macro} % @@ -375,7 +493,7 @@ % left_most element of \zz{sequence}. % \begin{macrocode} \def_new:Npn \seq_get:NN #1{ - \seq_empty_err:N #1 + \seq_if_empty_err:N #1 \exp_after:NN\seq_get_aux:w #1\q_stop} \def_new:Npn \seq_get_aux:w \seq_elt:w #1\seq_elt_end: #2\q_stop #3{\tlp_set:Nn #3{#1}} @@ -385,18 +503,20 @@ % \end{macro} % % \begin{macro}{\seq_pop_aux:nnNN} +% \begin{macro}{\seq_pop_aux:w} % |\seq_pop_aux:nnNN| \zz{def$\sb1$} \zz{def$\sb2$} \zz{sequence} % \zz{cmd} assigns the left_most element of \zz{sequence} to % \zz{cmd} using \zz{def$\sb2$}, and assigns the tail of % \zz{sequence} to \zz{sequence} using \zz{def$\sb1$}. % \begin{macrocode} \def_new:Npn \seq_pop_aux:nnNN #1#2#3{ - \seq_empty_err:N #3 + \seq_if_empty_err:N #3 \exp_after:NN\seq_pop_aux:w #3\q_stop #1#2#3} \def_new:Npn \seq_pop_aux:w \seq_elt:w #1\seq_elt_end: #2\q_stop #3#4#5#6{#3#5{#2}#4#6{#1}} % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro}{\seq_put_aux:Nnn} % |\seq_put_aux:Nnn| \zz{sequence} \zv{left} \zv{right} adds the @@ -430,8 +550,8 @@ \def_new:Npn \seq_put_left:Nx {\exp_args:Nnx\seq_put_left:Nn} \def_new:Npn \seq_put_right:Nn #1#2{ \seq_put_aux:Nnn #1{}{\seq_elt:w #2\seq_elt_end:}} -\def_new:Npn \seq_put_right:No {\exp_args:Nno\seq_put_right:Nn} -\def_new:Npn \seq_put_right:Nx {\exp_args:Nnx\seq_put_right:Nn} +\def_new:Npn \seq_put_right:No {\exp_args:NNo\seq_put_right:Nn} +\def_new:Npn \seq_put_right:Nx {\exp_args:NNx\seq_put_right:Nn} % \end{macrocode} % \end{macro} % \end{macro} @@ -443,6 +563,7 @@ % % \begin{macro}{\seq_gput_left:Nn} % \begin{macro}{\seq_gput_right:Nn} +% \begin{macro}{\seq_gput_right:Nc} % \begin{macro}{\seq_gput_right:No} % \begin{macro}{\seq_gput_right:cn} % \begin{macro}{\seq_gput_right:co} @@ -453,15 +574,16 @@ %<*check> \pref_global_chk: %</check> -%<_check> \pref_global:D +%<-check> \pref_global:D \seq_put_left:Nn} \def_new:Npn \seq_gput_right:Nn { %<*check> \pref_global_chk: %</check> -%<_check> \pref_global:D +%<-check> \pref_global:D \seq_put_right:Nn} \def_new:Npn \seq_gput_right:No {\exp_args:NNo \seq_gput_right:Nn} +\def_new:Npn \seq_gput_right:Nc {\exp_args:NNc \seq_gput_right:Nn} \def_new:Npn \seq_gput_right:cn {\exp_args:Nc \seq_gput_right:Nn} \def_new:Npn \seq_gput_right:co {\exp_args:Nco \seq_gput_right:Nn} \def_new:Npn \seq_gput_right:cc {\exp_args:Ncc \seq_gput_right:Nn} @@ -472,6 +594,33 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} +% +% \begin{macro}{\seq_map_variable:NNn} +% \begin{macro}{\seq_map_variable:cNn} +% \begin{macro}{\seq_map_variable_aux:nw} +% \begin{macro}{\seq_map_break:w} +% Nothing spectacular here. The shuffling of the arguments in +% |\seq_map_variable:NNn| below could also be done with +% |\exp_args:NNnE|. +% \begin{macrocode} +\def_new:Npn \seq_map_variable_aux:Nnw #1#2\seq_elt:w#3\seq_elt_end:{ + \tlp_set:Nn #1{#3} + \quark_if_nil:NT #1 \seq_map_break:w + #2 + \seq_map_variable_aux:Nnw #1{#2} +} +\def_new:Npn \seq_map_variable:NNn #1#2#3{ + \tlp_set:Nx #2 {\exp_not:n{\seq_map_variable_aux:Nnw #2{#3}}} + \exp_after:NN #2 #1 \seq_elt:w \q_nil\seq_elt_end: \q_stop +} +\def_new:Npn \seq_map_variable:cNn{\exp_args:Nc\seq_map_variable:Nn} +\let_new:NN \seq_map_break:w \use_none_delimit_by_q_stop:w +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\seq_map:NN} % |\seq_map:NN| \zz{sequence} \zz{cmd} applies \zz{cmd} to each @@ -481,7 +630,9 @@ % that is delimited by |\seq_elt_end:|. % \begin{macrocode} \def_new:Npn \seq_map:NN #1#2{ - \def:Npn \seq_elt:w ##1\seq_elt_end: {#2{##1}}#1} + \def:Npn \seq_elt:w ##1\seq_elt_end: {#2{##1}}#1 + \let:NN \seq_elt:w \ERROR +} % \end{macrocode} % \end{macro} % @@ -491,21 +642,51 @@ % natural. % \begin{macrocode} \def_new:Npn \seq_map_inline:Nn #1#2{ - \gdef:Npn \seq_elt:w ##1\seq_elt_end: {#2}#1} + \def:Npn \seq_elt:w ##1\seq_elt_end: {#2}#1 + \let:NN \seq_elt:w \ERROR +} \def_new:Npn \seq_map_inline:cn{\exp_args:Nc\seq_map_inline:Nn} % \end{macrocode} % \end{macro} % \end{macro} % +% \begin{macro}{\seq_set_eq:NN} +% \begin{macro}{\seq_set_eq:Nc} +% We can set one seq equal to another. +% \begin{macrocode} +\let_new:NN \seq_set_eq:NN \let:NN +\def_new:Npn \seq_set_eq:Nc {\exp_args:NNc \seq_set_eq:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\seq_gset_eq:NN} +% \begin{macro}{\seq_gset_eq:cN} +% \begin{macro}{\seq_gset_eq:Nc} +% \begin{macro}{\seq_gset_eq:cc} +% An of course globally which seems to be needed far more +% often.\footnote{To save a bit of space these functions could be made +% identical to those from the tlp or clist module.} +% \begin{macrocode} +\let_new:NN \seq_gset_eq:NN \glet:NN +\def_new:Npn \seq_gset_eq:cN {\exp_args:Nc \seq_gset_eq:NN} +\def_new:Npn \seq_gset_eq:Nc {\exp_args:NNc \seq_gset_eq:NN} +\def_new:Npn \seq_gset_eq:cc {\exp_args:Ncc \seq_gset_eq:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% % \begin{macro}{\seq_gconcat:NNN} % \begin{macro}{\seq_gconcat:ccc} % |\seq_gconcat:NNN| \m{seq~1} \m{seq~2} \m{seq~3} will globally % assign \m{seq~1} the concatenation of \m{seq~2} and \m{seq~3}. % \begin{macrocode} \def_new:Npn \seq_gconcat:NNN #1#2#3{ - \l_tmpa_toks \exp_after:NN{#2} - \l_tmpb_toks \exp_after:NN{#3} - \gdef:Npx #1{\toks_use:N \l_tmpa_toks \toks_use:N \l_tmpb_toks}} + \tlp_gset:Nx #1 {\exp_not:o{#2}\exp_not:o{#3}} +} \def_new:Npn \seq_gconcat:ccc{\exp_args:Nccc\seq_gconcat:NNN} % \end{macrocode} % \end{macro} @@ -514,10 +695,13 @@ % \begin{macro}{\seq_if_in:NnTF} % \begin{macro}{\seq_if_in:cnTF} % \begin{macro}{\seq_if_in:coTF} +% \begin{macro}{\seq_if_in:cxTF} +% \begin{macro}{\seq_if_in:NnF} +% \begin{macro}{\seq_if_in:cnF} % |\seq_if_in:NnTF| \m{seq}\m{item} \m{true~case} \m{false~case} % will check whether \m{item} is in \m{seq} and then either execute % the \m{true~case} or the \m{false~case}. \m{true~case} and -% \m{false~case} may contain incomplete |\if_char_code:w| +% \m{false~case} may contain incomplete |\if_charcode:w| % statements. % \begin{macrocode} \def_new:Npn \seq_if_in:NnTF #1#2{ @@ -528,9 +712,9 @@ % with |\q_no_value|. % \begin{macrocode} \if_meaning:NN\q_no_value##2 - \exp_after:NN\use_choice_ii:nn + \exp_after:NN\use_arg_ii:nn \else: - \exp_after:NN\use_choice_i:nn + \exp_after:NN\use_arg_i:nn \fi: } \exp_after:NN @@ -538,14 +722,23 @@ #2\seq_elt_end: \q_no_value \q_stop} \def_new:Npn \seq_if_in:coTF {\exp_args:Nco \seq_if_in:NnTF} \def_new:Npn \seq_if_in:cnTF {\exp_args:Nc \seq_if_in:NnTF} +\def_new:Npn \seq_if_in:cxTF {\exp_args:Ncx \seq_if_in:NnTF} % \end{macrocode} +% +% \begin{macrocode} +\def_new:Npn \seq_if_in:NnF #1#2 { \seq_if_in:NnTF #1{#2}\use_noop: } +\def_new:Npn \seq_if_in:cnF {\exp_args:Nc \seq_if_in:NnF} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % -% \subsection{Stack operations} +% \subsubsection{Stack operations} % % We build stacks from sequences, but here we put the % specific functions together. @@ -577,6 +770,7 @@ % \begin{macro}{\seq_gpush:Nn} % \begin{macro}{\seq_gpush:No} % \begin{macro}{\seq_gpush:cn} +% \begin{macro}{\seq_gpush:NC} % \begin{macro}{\seq_gpop:NN} % \begin{macro}{\seq_gpop:cN} % I don't agree with Denys that one needs only local stacks, @@ -587,6 +781,7 @@ \let_new:NN \seq_gpush:Nn \seq_gput_left:Nn \def_new:Npn \seq_gpush:No {\exp_args:NNo \seq_gpush:Nn} \def_new:Npn \seq_gpush:cn {\exp_args:Nc \seq_gpush:Nn} +\def_new:Npn \seq_gpush:NC {\exp_args:NNC \seq_gpush:Nn} \def_new:Npn \seq_gpop:NN {\seq_pop_aux:nnNN \tlp_gset:Nn \tlp_set:Nn} \def_new:Npn \seq_gpop:cN {\exp_args:Nc \seq_gpop:NN} % \end{macrocode} @@ -595,6 +790,7 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} % % % \begin{macro}{\seq_top:NN} @@ -611,12 +807,38 @@ % % Show token usage: % \begin{macrocode} -%</package> +%</initex|package> %<*showmemory> %\showMemUsage %</showmemory> % \end{macrocode} % +% \endinput % +% $Log$ +% Revision 1.23 2006/08/09 21:12:50 morten +% Minor change in \seq_gconcat:NNN +% +% Revision 1.22 2006/03/20 18:26:39 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.21 2005/12/29 01:28:29 morten +% Added a new mapping function (needed in xparse) +% +% Revision 1.20 2005/12/27 10:06:10 morten +% Minor changes plus changed RCS information retrieval +% +% Revision 1.19 2005/04/06 21:36:08 morten +% Removed dependency on l3toks and added an if_in variant +% +% Revision 1.18 2005/03/22 23:28:05 morten +% Fix coding as Benjamin pointed out +% +% Revision 1.17 2005/03/16 22:35:51 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.16 2005/03/11 21:42:10 braams +% Fixed the use of RCS information; added \StopEventually +% Fixed a few documentation typos % - diff --git a/Master/texmf-dist/source/latex/expl3/l3skip.dtx b/Master/texmf-dist/source/latex/expl3/l3skip.dtx new file mode 100644 index 00000000000..fee0baa4d0a --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3skip.dtx @@ -0,0 +1,1086 @@ +% \iffalse +%% File: l3skip.dtx Copyright (C) 2005-2006 Frank Mittelbach, LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3skip.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental skip registers} +% +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3skip.dtx} +\end{document} +%</driver> +% \fi +% +% +% \title{The \textsf{l3skip} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}\\ +% Dimension and skip registers} +% \author{\Team} +% \date{\filedate} +% \maketitle +% +% +% \section{Length registers} +% +% +% \LaTeX3 knows about two types of length registers for internal use: +% rubber lengths ("skip"s) and rigid lengths ("dim"s). +% +% \subsection{Skip registers} +% +% +% +% \subsubsection{Functions} +% +% \begin{function}{% +% \skip_new:N | +% \skip_new:c | +% \skip_new_l:N +% } +% \begin{syntax} +% "\skip_new:N" <skip> +% \end{syntax} +% Defines <skip> to be a new variable of type "skip". +% \begin{texnote} +% "\skip_new:N" is the equivalent to plain \TeX{}'s \tn{newskip}. +% However, the internal register allocation is done differently. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \skip_zero:N | +% \skip_zero:c | +% \skip_gzero:N | +% \skip_gzero:c | +% } +% \begin{syntax} +% "\skip_zero:N" <skip> +% \end{syntax} +% Locally or globally reset <skip> to zero. +% For global variables the global versions +% should be used. +% \end{function} +% +% +% \begin{function}{% +% \skip_set:Nn | +% \skip_set:cn | +% \skip_gset:Nn | +% \skip_gset:cn | +% } +% \begin{syntax} +% "\skip_set:Nn" <skip> "{" <skip value> "}" +% \end{syntax} +% These functions will set the <skip> register to the <length> value. +% \end{function} +% +% +% \begin{function}{% +% \skip_add:Nn | +% \skip_add:cn | +% \skip_gadd:Nn | +% } +% \begin{syntax} +% "\skip_add:Nn" <skip> "{" <length> "}" +% \end{syntax} +% These functions will add to the <skip> register the value <length>. If +% the second argument is a <skip> register too, the surrounding braces +% can be left out. +% \end{function} +% +% \begin{function}{% +% \skip_sub:Nn | +% \skip_gsub:Nn | +% } +% \begin{syntax} +% "\skip_gsub:Nn" <skip> "{" <length> "}" +% \end{syntax} +% These functions will subtract from the <skip> register the value +% <length>. If the second argument is a <skip> register too, the +% surrounding braces can be left out. +% \end{function} +% +% \begin{function}{% +% \skip_use:N | +% \skip_use:c | +% } +% \begin{syntax} +% "\skip_use:N" <skip> +% \end{syntax} +% This function returns the length value kept in <skip> in a way +% suitable for further processing. +% \begin{texnote} +% The function "\skip_use:N" could be implemented directly as the \TeX{} +% primitive "\tex_the:D" which is also responsible to produce the values for +% other internal quantities. We have chosen to use individual functions +% for counters, dimensions etc.\ to allow checks and to make the code +% more self-explanatory. +% \end{texnote} +% \end{function} +% +% +% \begin{function}{% +% \skip_horizontal:N | +% \skip_horizontal:c | +% \skip_horizontal:n | +% \skip_vertical:N | +% \skip_vertical:c | +% \skip_vertical:n | +% } +% \begin{syntax} +% "\skip_horizontal:N" <skip> \\ +% "\skip_horizontal:n" "{" <length> "}" +% \end{syntax} +% The "hor" functions insert <skip> or <length> with the \TeX\ +% primitive \tn{hskip}. The "vertical" variants do the same with +% \tn{vskip}. The "n" versions evaluate <length> with "\skip_eval:n". +% \end{function} +% +% +% \begin{function}{% +% \skip_infinite_glue:nTF | +% } +% \begin{syntax} +% "\skip_infinite_glue:nTF" "{"<skip>"}" "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Checks if <skip> contains infinite stretch or shrink components +% and executes either <true> or <false>. Also works on input like +% "3pt plus .5in". +% \end{function} +% +% +% +% \begin{function}{% +% \skip_split_finite_else_action:nnNN | +% } +% \begin{syntax} +% "\skip_split_finite_else_action:nnNN" "{"<skip>"}" "{"<action>"}" +% <dimen1> <dimen2> +% \end{syntax} +% Checks if <skip> contains finite glue. If it does then it assigns +% <dimen1> the stretch component and <dimen2> the shrink component. If +% it contains infinite glue set <dimen1> and <dimen2> to zero and execute +% "#2" which is usually an error or warning message of some sort. +% \end{function} +% +% +% +% \begin{function}{% +% \skip_eval:n | +% } +% \begin{syntax} +% "\skip_eval:n" "{"<skip expr>"}" +% \end{syntax} +% Evaluates the value of <skip expr> so that +% "\skip_eval:n {5pt plus 3fil + 3pt minus 1fil}" puts +% "8.0pt plus 3.0fil minus 1.0fil" back into the input stream. +% Expandable. +% \begin{texnote} +% This is the \eTeX{} primitive \tn{glueexpr} turned into a function +% taking an argument. +% \end{texnote} +% \end{function} +% +% +% \subsubsection{Formatting a skip register value} +% +% +% \subsubsection{Variable and constants} +% +% \begin{variable}{% +% \c_max_skip | +% } +% Constant that denotes the maximum value which can be stored in a <skip> +% register. +% \end{variable} +% +% \begin{variable}{% +% \c_zero_skip | +% } +% Set of constants denoting useful values. +% \end{variable} +% +% \begin{variable}{% +% \l_tmpa_skip | +% \l_tmpb_skip | +% \l_tmpc_skip | +% \g_tmpa_skip | +% \g_tmpb_skip | +% } +% Scratch register for immediate use. +% \end{variable} +% +% +% +% +% +% \subsection{Dim registers} +% +% +% \subsubsection{Functions} +% +% +% +% +% \begin{function}{% +% \dim_new:N | +% \dim_new:c | +% \dim_new_l:N +% } +% \begin{syntax} +% "\dim_new:N" <dim> +% \end{syntax} +% Defines <dim> to be a new variable of type "dim". +% \begin{texnote} +% "\dim_new:N" is the equivalent to plain \TeX{}'s \tn{newdimen}. +% However, the internal register allocation is done differently. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \dim_zero:N | +% \dim_zero:c | +% \dim_gzero:N | +% \dim_gzero:c | +% } +% \begin{syntax} +% "\dim_zero:N" <dim> +% \end{syntax} +% Locally or globally reset <dim> to zero. +% For global variables the global versions +% should be used. +% \end{function} +% +% +% \begin{function}{% +% \dim_set:Nn | +% \dim_set:cn | +% \dim_gset:Nn | +% \dim_gset:cn | +% } +% \begin{syntax} +% "\dim_set:Nn" <dim> "{" <dim value> "}" +% \end{syntax} +% These functions will set the <dim> register to the <dim value> value. +% \end{function} +% +% +% \begin{function}{% +% \dim_add:Nn | +% \dim_add:cn | +% \dim_gadd:Nn | +% } +% \begin{syntax} +% "\dim_add:Nn" <dim> "{" <length> "}" +% \end{syntax} +% These functions will add to the <dim> register the value <length>. If +% the second argument is a <dim> register too, the surrounding braces +% can be left out. +% \end{function} +% +% \begin{function}{% +% \dim_sub:Nn | +% \dim_gsub:Nn | +% } +% \begin{syntax} +% "\dim_gsub:Nn" <dim> "{" <length> "}" +% \end{syntax} +% These functions will subtract from the <dim> register the value +% <length>. If the second argument is a <dim> register too, the +% surrounding braces can be left out. +% \end{function} +% +% \begin{function}{% +% \dim_use:N | +% \dim_use:c | +% } +% \begin{syntax} +% "\dim_use:N" <dim> +% \end{syntax} +% This function returns the length value kept in <dim> in a way +% suitable for further processing. +% \begin{texnote} +% The function "\dim_use:N" could be implemented directly as the \TeX{} +% primitive "\tex_the:D" which is also responsible to produce the values for +% other internal quantities. We have chosen to use individual functions +% for counters, dimensions etc.\ to allow checks and to make the code +% more self-explanatory. +% \end{texnote} +% \end{function} +% +% +% +% \begin{function}{% +% \dim_eval:n | +% } +% \begin{syntax} +% "\dim_eval:n" "{"<dim expr>"}" +% \end{syntax} +% Evaluates the value of a dimension expression so that +% "\dim_eval:n {5pt+3pt}" puts "8pt" back into the input stream. +% Expandable. +% \begin{texnote} +% This is the \eTeX{} primitive \tn{dimexpr} turned into a function +% taking an argument. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \if_dim:w | +% } +% \begin{syntax} +% "\if_dim:w" <dimen1> <rel> <dimen2> <true> "\else:" <false> "\fi:" +% \end{syntax} +% Compare two dimensions. It is recommended to use "\dim_eval:n" to +% correctly evaluate and terminate these numbers. <rel> is one of +% "<", "=" or ">" with catcode 12. +% \begin{texnote} +% This is the \TeX{} primitive \tn{ifdim}. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \dim_compare:nNnTF | +% \dim_compare:nNnT | +% \dim_compare:nNnF | +% } +% \begin{syntax} +% "\dim_compare:nNnTF" "{"<dim~expr>"}" <rel> "{"<dim~expr>"}" +% "{"<true>"}" "{"<false>"}" +% \end{syntax} +% These functions test two dimension expressions against each other. They +% are both evaluated by "\dim_eval:n". Note that if both expressions +% are normal dimension variables as in +% \begin{verbatim} +% \dim_compare:nNnTF \l_temp_dim < \c_zero_skip {negative}{non-negative} +% \end{verbatim} +% you can safely omit the braces. +% \begin{texnote} +% This is the \TeX{} primitive \tn{ifdim} turned into a function. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \dim_compare_p:nNn | +% } +% \begin{syntax} +% "\dim_compare_p:nNn" "{"<dim~expr>"}" <rel> "{"<dim~expr>"}" +% \end{syntax} +% Predicate version of the above functions. +% \end{function} +% +% \begin{function}{% +% \dim_while:nNnT | +% \dim_while:nNnF | +% \dim_dowhile:nNnT | +% \dim_dowhile:nNnF | +% } +% \begin{syntax} +% "\dim_while:nNnT" <dim expr> <rel> <dim~expr> <true> +% \end{syntax} +% "\dim_while:nNnT" tests the dimension expressions and if true performs +% the body "T" until the test fails. "\dim_dowhile:nNnT" is similar +% but executes the body first and then performs the check, thus +% ensuring that the body is executed at least once. The "F" versions +% are similar but continue the loop as long as the test is false. +% \end{function} +% +% +% +% \subsubsection{Variable and constants} +% +% \begin{variable}{% +% \c_max_dim | +% } +% Constant that denotes the maximum value which can be stored in a <dim> +% register. +% \end{variable} +% +% \begin{variable}{% +% \c_zero_dim | +% } +% Set of constants denoting useful values. +% \end{variable} +% +% \begin{variable}{% +% \l_tmpa_dim | +% \l_tmpb_dim | +% \l_tmpc_dim | +% \l_tmpd_dim | +% \g_tmpa_dim | +% \g_tmpb_dim | +% } +% Scratch register for immediate use. +% \end{variable} +% +% \subsection{Muskips} +% +% \begin{function}{% +% \muskip_new:N | +% \muskip_new_l:N +% } +% \begin{syntax} +% "\muskip_new:N" <muskip> +% \end{syntax} +% Defines <muskip> to be a new variable of type "muskip". +% \begin{texnote} +% "\muskip_new:N" is the equivalent to plain \TeX{}'s \tn{newmuskip}. +% However, the internal register allocation is done differently. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \muskip_set:Nn | +% \muskip_gset:Nn | +% } +% \begin{syntax} +% "\muskip_set:Nn" <muskip> "{" <muskip value> "}" +% \end{syntax} +% These functions will set the <muskip> register to the <length> +% value. +% \end{function} +% +% +% \begin{function}{% +% \muskip_add:Nn | +% \muskip_gadd:Nn | +% } +% \begin{syntax} +% "\muskip_add:Nn" <muskip> "{" <length> "}" +% \end{syntax} +% These functions will add to the <muskip> register the value +% <length>. If the second argument is a <muskip> register too, the +% surrounding braces can be left out. +% \end{function} +% +% \begin{function}{% +% \muskip_sub:Nn | +% \muskip_gsub:Nn | +% } +% \begin{syntax} +% "\muskip_gsub:Nn" <muskip> "{" <length> "}" +% \end{syntax} +% These functions will subtract from the <muskip> register the value +% <length>. If the second argument is a <muskip> register too, the +% surrounding braces can be left out. +% \end{function} +% +% +% \StopEventually{} +% +% \subsection{The Implementation} +% +% +% We start by ensuring that the required packages are loaded. +% \begin{macrocode} +%<package&!check>\RequirePackage{l3int} +%<package&!check>\RequirePackage{l3prg} +%<package&check>\RequirePackage{l3chk} +%<*initex|package> +% \end{macrocode} +% +% \subsubsection{Skip registers} +% +% \begin{macro}{\skip_new:N} +% \begin{macro}{\skip_new:c} +% \begin{macro}{\skip_new_l:N} +% Allocation of a new internal registers. +% \begin{macrocode} +%<*initex> +\alloc_setup_type:nnn {skip} \c_zero \c_max_register_num +\def_new:Npn\skip_new:N #1 {\alloc_reg:NnNN g {skip} \tex_skipdef:D #1 } +\def_new:Npn\skip_new_l:N #1 {\alloc_reg:NnNN l {skip} \tex_skipdef:D #1 } +%</initex> +%<package>\let:NN \skip_new:N \newskip +\def_new:Npn \skip_new:c {\exp_args:Nc \skip_new:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\skip_set:Nn} +% \begin{macro}{\skip_set:cn} +% \begin{macro}{\skip_gset:Nn} +% \begin{macro}{\skip_gset:cn} +% Setting skips is again something that I would like to make +% uniform at the moment to get a better overview. +% \begin{macrocode} +\def_new:Npn \skip_set:Nn #1#2{#1\skip_eval:n{#2} +%<*check> +\chk_local_or_pref_global:N #1 +%</check> +} +\def_new:Npn \skip_gset:Nn { +%<*check> + \pref_global_chk: +%</check> +%<-check> \pref_global:D + \skip_set:Nn } +\def_new:Npn \skip_set:cn {\exp_args:Nc \skip_set:Nn } +\def_new:Npn \skip_gset:cn {\exp_args:Nc \skip_gset:Nn } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\skip_zero:N} +% \begin{macro}{\skip_gzero:N} +% \begin{macro}{\skip_zero:c} +% \begin{macro}{\skip_gzero:c} +% Reset the register to zero. +% \begin{macrocode} +\def_new:Npn \skip_zero:N #1{#1\c_zero_skip \scan_stop: +%<*check> + \chk_local_or_pref_global:N #1 +%</check> +} +\def_new:Npn \skip_gzero:N { +% \end{macrocode} +% We make sure that a local variable is not updated globally by +% changing the internal test (i.e.\ |\chk_local_or_pref_global:N|) before +% making the assignment. This is done by |\pref_global_chk:| which also +% issues the necessary |\pref_global:D|. This is not very efficient, but +% this code will be only included for debugging purposes. Using +% |\pref_global:D| in front of the local function is better in the +% production versions. +% \begin{macrocode} +%<*check> + \pref_global_chk: +%</check> +%<-check> \pref_global:D + \skip_zero:N} +\def_new:Npn \skip_zero:c {\exp_args:Nc \skip_zero:N} +\def_new:Npn \skip_gzero:c {\exp_args:Nc \skip_gzero:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\skip_add:Nn} +% \begin{macro}{\skip_add:cn} +% \begin{macro}{\skip_gadd:Nn} +% \begin{macro}{\skip_sub:Nn} +% \begin{macro}{\skip_gsub:Nn} +% Adding and subtracting to and from <skip>s +% \begin{macrocode} +\def_new:Npn \skip_add:Nn #1#2{ +% \end{macrocode} +% We need to say |by| in case the first argment is a register +% accessed by its number, e.g., |\skip23|. +% \begin{macrocode} + \tex_advance:D#1 by \skip_eval:n{#2} +%<*check> + \chk_local_or_pref_global:N #1 +%</check> +} +\def_new:Npn\skip_add:cn{\exp_args:Nc\skip_add:Nn} +\def_new:Npn \skip_sub:Nn #1#2{ + \tex_advance:D#1-\skip_eval:n{#2} +%<*check> +\chk_local_or_pref_global:N #1 +%</check> +} +\def_new:Npn \skip_gadd:Nn { +%<*check> + \pref_global_chk: +%</check> +%<-check> \pref_global:D + \skip_add:Nn } +\def_new:Npn \skip_gsub:Nn { +%<*check> + \pref_global_chk: +%</check> +%<-check> \pref_global:D + \skip_sub:Nn } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\skip_horizontal:N} +% \begin{macro}{\skip_horizontal:c} +% \begin{macro}{\skip_horizontal:n} +% \begin{macro}{\skip_vertical:N} +% \begin{macro}{\skip_vertical:c} +% \begin{macro}{\skip_vertical:n} +% Inserting skips. +% \begin{macrocode} +\let_new:NN \skip_horizontal:N \tex_hskip:D +\def_new:Npn \skip_horizontal:c {\exp_args:Nc\skip_horizontal:N} +\def_new:Npn \skip_horizontal:n #1{\skip_horizontal:N \skip_eval:n{#1}} +\let_new:NN \skip_vertical:N \tex_vskip:D +\def_new:Npn \skip_vertital:c {\exp_args:Nc\skip_vertical:N} +\def_new:Npn \skip_vertical:n #1{\skip_vertical:N \skip_eval:n{#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\skip_use:N} +% \begin{macro}{\skip_use:c} +% Here is how skip registers are accessed: +% \begin{macrocode} +\let_new:NN \skip_use:N \tex_the:D +\def_new:Npn \skip_use:c #1{\exp_args:Nc\skip_use:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\skip_eval:n} +% Evaluating a calc expression. +% \begin{macrocode} +\def_new:Npn \skip_eval:n #1 {\etex_glueexpr:D #1 \scan_stop:} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\l_tmpa_skip} +% \begin{macro}{\l_tmpb_skip} +% \begin{macro}{\l_tmpc_skip} +% \begin{macro}{\g_tmpa_skip} +% \begin{macro}{\g_tmpb_skip} +% We provide three local and two global scratch registers, maybe we +% need more or less. +% \begin{macrocode} +%%\chk_new_cs:N \l_tmpa_skip +%%\tex_skipdef:D\l_tmpa_skip 255 %currently taken up by \skip@ +\skip_new:N \l_tmpa_skip +\skip_new:N \l_tmpb_skip +\skip_new:N \l_tmpc_skip +\skip_new:N \g_tmpa_skip +\skip_new:N \g_tmpb_skip +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\c_zero_skip} +% \begin{macro}{\c_max_skip} +% \begin{macrocode} +%<*!package> +\skip_new:N \c_zero_skip +\skip_set:Nn \c_zero_skip {0pt} +\skip_new:N \c_max_skip +\skip_set:Nn \c_max_skip {16383.99999pt} +%</!package> +%<*!initex> +\let:NN \c_zero_skip \z@ +\let:NN \c_max_skip \maxdimen +%</!initex> +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% \begin{macro}{\skip_infinite_glue:nTF} +% With \eTeX{} we all of a sudden get access to a lot information we +% should otherwise consider ourselves lucky to get. One is +% the stretch and shrink components of a skip register and the order +% or those components. "\skip_infinite_glue:nTF" tests it directly by +% looking at the stretch and shrink order. If either of the predicate +% functions return \m{true} "\prg_logic_or_p:nn" will return \m{true} +% and the logic test will take the true branch. +% \begin{macrocode} +\def_new:Npn \skip_infinite_glue:nTF #1{ + \prg_logic_test:nTF { + \prg_logic_or_p:nn + { \int_compare_p:nNn {\etex_gluestretchorder:D #1 } > \c_zero } + { \int_compare_p:nNn {\etex_glueshrinkorder:D #1 } > \c_zero } + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\skip_split_finite_else_action:nnNN} +% This macro is useful when performing error checking in certain +% circumstances. If the \m{skip} register holds finite glue it sets +% "#3" and "#4" to the stretch and shrink component resp. If it holds +% infinite glue set "#3" and "#4" to zero and issue the special action +% "#2" which is probably an error message. +% Assignments are global. +% \begin{macrocode} +\def_new:Npn \skip_split_finite_else_action:nnNN #1#2#3#4{ + \skip_infinite_glue:nTF {#1} + { + #3 = \c_zero_skip + #4 = \c_zero_skip + #2 + } + { + #3 = \etex_gluestretch:D #1 \scan_stop: + #4 = \etex_glueshrink:D #1 \scan_stop: + } +} +% \end{macrocode} +% \end{macro} +% +% +% +% \subsubsection{Dimen registers} +% +% \begin{macro}{\dim_new:N} +% \begin{macro}{\dim_new:c} +% \begin{macro}{\dim_new_l:N} +% Allocating \meta{dim} registers... +% \begin{macrocode} +%<*initex> +\alloc_setup_type:nnn {dimen} \c_zero \c_max_register_num +\def_new:Npn \dim_new:N #1 {\alloc_reg:NnNN g {dimen} \tex_dimendef:D #1 } +\def_new:Npn \dim_new_l:N #1 {\alloc_reg:NnNN l {dimen} \tex_dimendef:D #1 } +%</initex> +%<package>\let:NN \dim_new:N \newdimen +\def_new:Npn \dim_new:c {\exp_args:Nc \dim_new:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dim_set:Nn} +% \begin{macro}{\dim_gset:Nn} +% \begin{macro}{\dim_set:cn} +% \begin{macro}{\dim_set:Nc} +% \begin{macro}{\dim_gset:cn} +% \begin{macro}{\dim_gset:Nc} +% \begin{macro}{\dim_gset:cc} +% We add |\dim_eval:n| in order to allow simple arithmetic +% and a space just for those using |\dimen1| or alike. See OR! +% \begin{macrocode} +\def_new:Npn \dim_set:Nn #1#2{#1~ \dim_eval:n{#2}} +\def_new:Npn \dim_gset:Nn {\pref_global:D \dim_set:Nn } +\def_new:Npn \dim_set:cn {\exp_args:Nc \dim_set:Nn } +\def_new:Npn \dim_set:Nc {\exp_args:NNc \dim_set:Nn } +\def_new:Npn \dim_gset:cn {\exp_args:Nc \dim_gset:Nn } +\def_new:Npn \dim_gset:Nc {\exp_args:NNc \dim_gset:Nn } +\def_new:Npn \dim_gset:cc {\exp_args:Ncc \dim_gset:Nn } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dim_zero:N} +% \begin{macro}{\dim_gzero:N} +% \begin{macro}{\dim_zero:c} +% \begin{macro}{\dim_gzero:N} +% Resetting. +% \begin{macrocode} +\def_new:Npn \dim_zero:N #1{#1\c_zero_skip} +\def_new:Npn \dim_gzero:N {\pref_global:D \dim_zero:N} +\def_new:Npn \dim_zero:c {\exp_args:Nc \dim_zero:N} +\def_new:Npn \dim_gzero:c {\exp_args:Nc \dim_gzero:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dim_add:Nn} +% \begin{macro}{\dim_add:cn} +% \begin{macro}{\dim_add:Nc} +% \begin{macro}{\dim_gadd:Nn} +% Addition. +% \begin{macrocode} +\def_new:Npn \dim_add:Nn #1#2{ +% \end{macrocode} +% We need to say |by| in case the first argment is a register +% accessed by its number, e.g., |\dimen23|. +% \begin{macrocode} + \tex_advance:D#1 by \dim_eval:n{#2}\scan_stop: +} +\def_new:Npn\dim_add:cn{\exp_args:Nc\dim_add:Nn} +\def_new:Npn\dim_add:Nc{\exp_args:NNc\dim_add:Nn} +\def_new:Npn \dim_gadd:Nn { \pref_global:D \dim_add:Nn } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dim_sub:Nn} +% \begin{macro}{\dim_sub:cn} +% \begin{macro}{\dim_sub:Nc} +% \begin{macro}{\dim_gsub:Nn} +% Subtracting. +% \begin{macrocode} +\def_new:Npn \dim_sub:Nn #1#2{\tex_advance:D#1-#2\scan_stop:} +\def_new:Npn\dim_sub:cn{\exp_args:Nc\dim_sub:Nn} +\def_new:Npn\dim_sub:Nc{\exp_args:NNc\dim_sub:Nn} +\def_new:Npn \dim_gsub:Nn {\pref_global:D \dim_sub:Nn } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dim_use:N} +% \begin{macro}{\dim_use:c} +% Accessing a \meta{dim}. +% \begin{macrocode} +\let_new:NN \dim_use:N \tex_the:D +\def_new:Npn \dim_use:c {\exp_args:Nc\dim_use:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\l_tmpa_dim} +% \begin{macro}{\l_tmpb_dim} +% \begin{macro}{\l_tmpc_dim} +% \begin{macro}{\l_tmpd_dim} +% \begin{macro}{\g_tmpa_dim} +% \begin{macro}{\g_tmpb_dim} +% Some scratch registers. +% \begin{macrocode} +\dim_new:N \l_tmpa_dim +\dim_new:N \l_tmpb_dim +\dim_new:N \l_tmpc_dim +\dim_new:N \l_tmpd_dim +\dim_new:N \g_tmpa_dim +\dim_new:N \g_tmpb_dim +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\c_zero_dim} +% \begin{macro}{\c_max_dim} +% Just aliases. +% \begin{macrocode} +\let_new:NN \c_zero_dim \c_zero_skip +\let_new:NN \c_max_dim \c_max_skip +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dim_eval:n} +% Evaluating a calc expression. +% \begin{macrocode} +\def_new:Npn \dim_eval:n #1 {\etex_dimexpr:D #1 \scan_stop:} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\if_dim:w} +% The comparison primitive. +% \begin{macrocode} +\let_new:NN \if_dim:w \tex_ifdim:D +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dim_compare:nNnTF} +% \begin{macro}{\dim_compare:nNnT} +% \begin{macro}{\dim_compare:nNnF} +% Check the expression and choose branch. +% \begin{macrocode} +\def_new:Npn \dim_compare:nNnTF #1#2#3{ + \if_dim:w \dim_eval:n {#1} #2 \dim_eval:n {#3} + \exp_after:NN \use_arg_i:nn + \else: + \exp_after:NN \use_arg_ii:nn + \fi: +} +\def_new:Npn \dim_compare:nNnT #1#2#3{ + \if_dim:w \dim_eval:n {#1} #2 \dim_eval:n {#3} + \exp_after:NN \use_arg_ii:nn + \fi: + \use_none:n +} +\def_new:Npn \dim_compare:nNnF #1#2#3{ + \if_dim:w \dim_eval:n {#1} #2 \dim_eval:n {#3} + \exp_after:NN \use_none:n + \else: + \exp_after:NN \use_arg_i:n + \fi: +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\dim_compare_p:nNn} +% A predicate function. +% \begin{macrocode} +\def_new:Npn \dim_compare_p:nNn #1#2#3{ + \if_dim:w \dim_eval:n {#1} #2 \dim_eval:n {#3} + \c_true + \else: + \c_false + \fi: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dim_while:nNnT} +% \begin{macro}{\dim_while:nNnF} +% \begin{macro}{\dim_dowhile:nNnT} +% \begin{macro}{\dim_dowhile:nNnF} +% "while" and "do-while" functions for dimensions. Same as for the +% "int" type only the names have changed. +% \begin{macrocode} +\def_new:Npn \dim_while:nNnT #1#2#3#4{ + \dim_compare:nNnT {#1}#2{#3}{#4 \dim_while:nNnT {#1}#2{#3}{#4}} +} +\def_new:Npn \dim_while:nNnF #1#2#3#4{ + \dim_compare:nNnF {#1}#2{#3}{#4 \dim_while:nNnF {#1}#2{#3}{#4}} +} +\def_new:Npn \dim_dowhile:nNnT #1#2#3#4{ + #4 \dim_compare:nNnT {#1}#2{#3}{\dim_dowhile:nNnT {#1}#2{#3}{#4}} +} +\def_new:Npn \dim_dowhile:nNnF #1#2#3#4{ + #4 \dim_compare:nNnF {#1}#2{#3}{\dim_dowhile:nNnF {#1}#2{#3}{#4}} +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \subsubsection{Muskips} +% +% \begin{macro}{\muskip_new:N} +% \begin{macro}{\muskip_new_l:N} +% And then we add muskips. +% \begin{macrocode} +%<*initex> +\alloc_setup_type:nnn {muskip} \c_zero \c_max_register_num +\def_new:Npn \muskip_new:N #1{\alloc_reg:NnNN g {muskip} \tex_muskipdef:D #1} +\def_new:Npn \muskip_new_l:N #1{\alloc_reg:NnNN l {muskip} \tex_muskipdef:D #1} +%</initex> +%<package>\let_new:NN \muskip_new:N \newmuskip % nicked from LaTeX +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\muskip_set:Nn} +% \begin{macro}{\muskip_gset:Nn} +% \begin{macro}{\muskip_add:Nn} +% \begin{macro}{\muskip_gadd:Nn} +% \begin{macro}{\muskip_sub:Nn} +% \begin{macro}{\muskip_gsub:Nn} +% Simple functions for muskips. +% \begin{macrocode} +\def_new:Npn \muskip_set:Nn#1#2{#1\etex_muexpr:D#2\scan_stop:} +\def_new:Npn \muskip_gset:Nn{\pref_global:D\muskip_set:Nn} +\def_new:Npn \muskip_add:Nn#1#2{\tex_advance:D#1\etex_muexpr:D#2\scan_stop:} +\def_new:Npn \muskip_gadd:Nn{\pref_global:D\muskip_add:Nn} +\def_new:Npn \muskip_sub:Nn#1#2{\tex_advance:D#1-\etex_muexpr:D#2\scan_stop:} +\def_new:Npn \muskip_gsub:Nn{\pref_global:D\muskip_sub:Nn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \endinput +% +% $Log$ +% Revision 1.18 2006/03/20 18:26:40 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.17 2006/01/27 11:22:38 morten +% Added \muskip_set:Nn and friends (since l3calc uses them). +% +% Revision 1.16 2006/01/17 22:46:37 morten +% Moved \skip_eval:n earlier to avoid error. +% +% Revision 1.15 2006/01/17 22:05:35 morten +% Minor updates +% +% Revision 1.14 2006/01/14 19:13:16 morten +% Added operations for \vskip and \hskip +% +% Revision 1.13 2005/12/27 15:54:44 morten +% Changed RCS information retrieval +% +% Revision 1.12 2005/10/27 22:56:15 morten +% Moved \if_dim:w to this module. +% +% Revision 1.11 2005/04/12 12:07:10 morten +% Added muskips +% +% Revision 1.10 2005/04/09 21:09:48 morten +% Both documentation and implementation cleaned up. +% +% Revision 1.9 2005/04/06 22:35:57 braams +% Now we have register allocation fitted +% +% Revision 1.8 2005/03/26 21:05:42 morten +% Make \c_zero_skip different from \c_zero +% +% Revision 1.7 2005/03/16 22:35:47 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.6 2005/03/11 21:42:48 braams +% Fixed the use of RCS information; added \StopEventually +% diff --git a/Master/texmf-dist/source/latex/expl3/l3tlp.dtx b/Master/texmf-dist/source/latex/expl3/l3tlp.dtx index ecc51de9b20..9cf83e3912b 100644 --- a/Master/texmf-dist/source/latex/expl3/l3tlp.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3tlp.dtx @@ -1,20 +1,54 @@ % \iffalse -%% File: l3tlp.dtx Copyright (C) 1990-1998 LaTeX3 project +%% File: l3tlp.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- % +%<package>\RequirePackage{l3names} %<*dtx> - \ProvidesFile{l3tlp.dtx} +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse %</dtx> -%<package>\NeedsTeXFormat{LaTeX2e} -%<package>\ProvidesPackage{l3tlp} -%<driver> \ProvidesFile{l3tlp.drv} -% \fi -% \ProvidesFile{l3tlp.dtx} - [1998/04/20 v1.0d L3 Experimental Token List Pointers] +%\fi +\GetIdInfo$Id: l3tlp.dtx 581 2006-12-12 12:28:27Z morten $ + {L3 Experimental Token List Pointers} % % \iffalse %<*driver> \documentclass{l3doc} - \begin{document} \DocInput{l3tlp.dtx} \end{document} @@ -22,7 +56,6 @@ % \fi % % -% \GetFileInfo{l3tlp.dtx} % \title{The \textsf{l3tlp} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ @@ -34,43 +67,65 @@ % % % \section {Token list pointers} -% +% % \LaTeX3 stores token lists in so called `token list pointers'. % Variables of this type get the suffix "tlp" and functions of this type % have the prefix "tlp". To use a token list pointer you simply call % the corresponding variable. -% +% +% Often you find yourself with not a token list pointer but an +% arbitrary token list which has to undergo certain tests. We will +% prefix these functions with "tlist". While token list pointers are +% always single tokens, token lists are always surrounded by +% braces. Perhaps these token lists should have their own module but +% for now I decided to put them here because there is quite a bit of +% overlap with token list pointers. +% % \subsection{Functions} -% -% \begin{function}{\tlp_new:Nn} +% +% \begin{function}{\tlp_new:Nn | +% \tlp_new:cn | +% \tlp_new:Nx } % \begin{syntax} % "\tlp_new:Nn" <tlp> "{" <initial token list> "}" % \end{syntax} -% Defines <varible> to be a new variable (or constant) of type token -% list pointer. <initial token list> is the initial value of -% <tlp>. This makes it possible to assign values to a constant -% token list pointer. +% Defines <tlp> to be a new variable (or constant) of type token list +% pointer. <initial token list> is the initial value of <tlp>. This +% makes it possible to assign values to a constant token list pointer. % \end{function} -% +% +% \begin{function}{% +% \tlp_use:N | +% \tlp_use:c +% } +% \begin{syntax} +% "\tlp_use:N" <tlp> +% \end{syntax} +% Function that inserts the <tlp> into the processing stream. +% \end{function} +% % \begin{function}{% % \tlp_set:Nn | % \tlp_set:Nc | % \tlp_set:No | +% \tlp_set:Nf | % \tlp_set:Nx | % \tlp_gset:Nn | % \tlp_gset:Nc | % \tlp_gset:No | -% \tlp_gset:Nx} +% \tlp_gset:Nx | +% \tlp_gset:cn | +% \tlp_gset:cx } % \begin{syntax} % "\tlp_set:Nn" <tlp> "{" <token list> "}" % \end{syntax} % Defines <tlp> to hold the token list <token list>. Global % variants of this command assign the value globally the other variants % expand the <token list> up to a certain level before the assignment -% or interpret the <tokenlist> as a character list and form a control +% or interpret the <token list> as a character list and form a control % sequence out of it. % \end{function} -% +% % \begin{function}{% % \tlp_clear:N | % \tlp_clear:c | @@ -84,10 +139,12 @@ % generate a control sequence name which is then interpreted as % <tlp> before clearing. % \end{function} -% +% % \begin{function}{% % \tlp_clear_new:N | % \tlp_clear_new:c | +% \tlp_gclear_new:N | +% \tlp_gclear_new:c | % } % \begin{syntax} % "\tlp_clear_new:N" <tlp> @@ -95,28 +152,37 @@ % These functions check if <tlp> exists. If it does it will be cleared; % if it doesn't it will be allocated. % \end{function} -% +% % \begin{function}{% % \tlp_put_left:Nn | % \tlp_put_left:No | % \tlp_gput_left:Nn | % \tlp_gput_left:No | +% \tlp_gput_left:Nx | % \tlp_put_right:Nn | % \tlp_put_right:cc | % \tlp_gput_right:Nn | -% \tlp_gput_right:No +% \tlp_gput_right:No| +% \tlp_gput_right:cn| +% \tlp_gput_right:co| % } % \begin{syntax} % "\tlp_put_left:Nn" <tlp> "{" <token list> "}" % \end{syntax} % These functions will append <token list> to the left or right of -% <tlp>. Assigment is done either locally or globally and <token -% list> might be subject to expansion before assigment. +% <tlp>. Assignment is done either locally or globally and <token +% list> might be subject to expansion before assignment. % \end{function} -% +% % \begin{function}{% % \tlp_set_eq:NN | -% \tlp_gset_eq:NN +% \tlp_set_eq:Nc | +% \tlp_set_eq:cN | +% \tlp_set_eq:cc | +% \tlp_gset_eq:NN | +% \tlp_gset_eq:Nc | +% \tlp_gset_eq:cN | +% \tlp_gset_eq:cc | % } % \begin{syntax} % "\tlp_set_eq:NN" <tlp1> <tlp2> @@ -127,7 +193,7 @@ % \end{syntax} % when <tlp2> is known to be a variable of type token list pointer. % \end{function} -% +% % \begin{function}{\tlp_to_str:N | % \tlp_to_str:c % } @@ -137,36 +203,240 @@ % This function returns the token list kept in <tlp> as a string list % with all characters catcoded to `other'. % \end{function} -% +% % \subsection{Predicates and conditionals} -% -% \begin{function}{\tlp_empty_p:N} +% +% \begin{function}{\tlp_if_empty_p:N| +% \tlp_if_empty_p:c +% } % \begin{syntax} -% "\tlp_empty_p:N" <tlp> +% "\tlp_if_empty_p:N" <tlp> % \end{syntax} % This predicate returns `true' if <tlp> is `empty' i.e., doesn't % contain any tokens. % \end{function} -% -% \begin{function}{\tlp_empty:NF| -% \tlp_empty:NTF} +% +% \begin{function}{\tlp_if_empty:NTF| +% \tlp_if_empty:NT| +% \tlp_if_empty:NF| +% \tlp_if_empty:cTF | +% \tlp_if_empty:cT | +% \tlp_if_empty:cF +% } % \begin{syntax} -% "\tlp_empty:NF" <tlp> "{"<false code>"}" +% "\tlp_if_empty:NTF" <tlp> "{"<true code>"}""{"<false code>"}" % \end{syntax} -% Execute <false code> if <tlp> is empty. -% contain any tokens. +% Execute <true code> if <tlp> is empty and <false code> if it +% contains any tokens. % \end{function} -% -% \begin{function}{\tlp_eq:NNF} +% +% \begin{function}{\tlp_if_eq_p:NN | +% \tlp_if_eq_p:cN | +% \tlp_if_eq_p:Nc | +% \tlp_if_eq_p:cc | +% } % \begin{syntax} -% "\tlp_eq:NNF" <tlp1> <tlp2> "{"<false code>"}" +% "\tlp_if_eq_p:NN" <tlp1> <tlp2> % \end{syntax} -% Execute <false code> if <tlp1> doesn't hold the same token list as -% <tlp2>. +% Predicate function which returns `true' if the two token list +% pointers are identical and `false' otherwise. % \end{function} -% -% \subsection{Variable and constants} -% +% +% \begin{function}{ +% \tlp_if_eq:NNTF | +% \tlp_if_eq:NNT | +% \tlp_if_eq:NNF | +% \tlp_if_eq:cNTF | +% \tlp_if_eq:cNT | +% \tlp_if_eq:cNF | +% \tlp_if_eq:NcTF | +% \tlp_if_eq:NcT | +% \tlp_if_eq:NcF | +% \tlp_if_eq:ccTF | +% \tlp_if_eq:ccT | +% \tlp_if_eq:ccF | +% } +% \begin{syntax} +% "\tlp_if_eq:NNTF" <tlp1> <tlp2> "{"<true code>"}""{"<false code>"}" +% \end{syntax} +% Execute <true code> if <tlp1> holds the same token list as <tlp2> +% and <false code> otherwise. +% \end{function} +% +% +% \subsection{Token lists} +% +% \begin{function}{\tlist_if_eq:nnTF | +% \tlist_if_eq:nnT | +% \tlist_if_eq:nnF | +% \tlist_if_eq:noTF | +% \tlist_if_eq:noT | +% \tlist_if_eq:noF | +% } +% \begin{syntax} +% "\tlist_if_eq:nnTF" "{"<tlist1>"}" "{"<tlist2>"}" "{"<true +% code>"}" "{"<false code>"}" +% \end{syntax} +% Execute <true code> if the two token lists <tlist1> and <tlist2> are +% identical. +% \end{function} +% +% +% \begin{function}{\tlist_if_empty_p:n | +% \tlist_if_empty_p:o | +% \tlist_if_empty:nTF | +% \tlist_if_empty:nT | +% \tlist_if_empty:nF | +% \tlist_if_empty:oTF | +% \tlist_if_empty:oT | +% \tlist_if_empty:oF | +% } +% \begin{syntax} +% "\tlist_if_empty:nTF" "{"<tlist>"}" "{"<true code>"}" "{"<false code>"}" +% \end{syntax} +% Execute <true code> if <tlist> doesn't contain any tokens and <false +% code> otherwise. +% \end{function} +% +% \begin{function}{\tlist_if_blank_p:n | +% \tlist_if_blank:nTF | +% \tlist_if_blank:nT | +% \tlist_if_blank:nF | +% \tlist_if_blank_p:o | +% \tlist_if_blank:oTF | +% \tlist_if_blank:oT | +% \tlist_if_blank:oF | +% } +% \begin{syntax} +% "\tlist_if_blank:nTF" "{"<tlist>"}" "{"<true code>"}" "{"<false code>"}" +% \end{syntax} +% Execute <true code> if <tlist> is blank meaning that it is either +% empty or contains only blank spaces. +% \end{function} +% +% \begin{function}{\tlist_to_lowercase:n | +% \tlist_to_uppercase:n +% } +% \begin{syntax} +% "\tlist_to_lowercase:n" "{"<tlist>"}" +% \end{syntax} +% "\tlist_to_lowercase:n" converts all tokens in <tlist> to their +% lower case representation. Similar for "\tlist_to_uppercase:n". +% \begin{texnote} +% These are the \TeX\ primitives \tn{lowercase} and \tn{uppercase} +% renamed. +% \end{texnote} +% \end{function} +% +% \begin{function}{\tlist_to_str:n +% } +% \begin{syntax} +% "\tlist_to_str:n" "{"<tlist>"}" +% \end{syntax} +% This function turns its argument into a string where all characters +% have catcode `other'. +% \begin{texnote} +% This is the \eTeX\ primitive \tn{detokenize}. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \tlist_map_function:nN | +% \tlp_map_function:NN | +% \tlp_map_function:cN | +% } +% \begin{syntax} +% "\tlist_map_function:nN" "{"<tlist>"}" <function> \\ +% "\tlp_map_function:NN" <tlp> <function> +% \end{syntax} +% Runs through all elements in a |tlist| from left to right and places +% <function> in front of each element. As this function will also pick +% up elements in brace groups, the element is returned with braces and +% hence <function> should be a function with a |:n| suffix even though +% it may very well only deal with a single token. This function uses a +% purely expandable loop function and will stay so as long as +% <function> is expandable too. +% \end{function} +% +% \begin{function}{% +% \tlist_map_inline:nn | +% \tlp_map_inline:Nn | +% \tlp_map_inline:cn | +% } +% \begin{syntax} +% "\tlist_map_inline:nn" "{"<tlist>"}" "{"<inline~function>"}" \\ +% "\tlp_map_inline:Nn" <tlp> "{"<inline~function>"}" +% \end{syntax} +% Allows a syntax like "\tlist_map_inline:nn" "{"<tlist>"}" +% "{\token_to_string:N ##1}". This renders it non-expandable though. +% Remember to double the "#"s for each level. +% \end{function} +% +% +% \begin{function}{% +% \tlist_map_variable:nNn | +% \tlp_map_variable:NNn | +% \tlp_map_variable:cNn | +% } +% \begin{syntax} +% "\tlist_map_variable:nNn" "{"<tlist>"}" <temp> "{"<action>"}" \\ +% "\tlp_map_variable:NNn" <tlp> <temp> "{"<action>"}" +% \end{syntax} +% Assigns <temp> to each element on <tlist> and executes <action>. +% As there is an assignment in this process it is not expandable. +% \begin{texnote} +% This is the \LaTeX2{} function \tn{@tfor} but with a more sane syntax. +% Also it works by tail recursion and so is faster as lists grow longer. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \tlist_map_break:w | +% \tlp_map_break:w | +% } +% \begin{syntax} +% "\tlist_map_break:w" +% \end{syntax} +% For breaking out of a loop. You should take note of the ":w" as +% its usage must be precise! +% \end{function} +% +% +% \begin{function}{% +% \tlist_reverse:n | +% } +% \begin{syntax} +% "\tlist_reverse:n" "{"<token$\sb1$><token$\sb2$>...<token$\sb n$>"}" +% \end{syntax} +% Reverse the token list to result in +% <token$\sb n$>\dots<token$\sb2$><token$\sb1$>. Note that spaces in this +% token list are gobbled in the process. +% \end{function} +% +% +% +% \subsubsection{Internal functions} +% +% +% \begin{function}{% +% \tlist_map_function_aux:Nn | +% \tlist_map_inline_aux:Nn | +% \tlist_map_variable_aux:Nnn | +% } +% \begin{syntax}\end{syntax} +% Internal helper functions for the <tlist> loops. +% \end{function} +% +% +% +% \begin{function}{\tlist_if_blank_p_aux:w +% } +% \end{function} +% +% +% +% \subsection{Variables and constants} +% % \begin{variable}{\C_job_name_tlp} % Constant that gets the `job name' assigned when \TeX{} starts. % \begin{texnote} @@ -175,19 +445,19 @@ % Therefore the "C" % \end{texnote} % \end{variable} -% +% % \begin{variable}{\c_empty_tlp} % Constant that is always empty. % \begin{texnote} % This was named \tn{@empty} in \LaTeX2 and \tn{empty} in plain \TeX{}. % \end{texnote} % \end{variable} -% +% % \begin{variable}{\c_relax_tlp} % Constant holding the token that is assigned to a newly created control % sequence by \TeX. % \end{variable} -% +% % \begin{variable}{% % \l_tmpa_tlp | % \l_tmpb_tlp | @@ -197,26 +467,200 @@ % Scratch register for immediate use. They are not used by conditionals % or predicate functions. % \end{variable} -% +% +% % \subsubsection{Internal functions} -% -% \begin{function}{\tlp_put_left:aux} +% +% \begin{variable}{% +% \l_replace_tlp | +% } +% Internal register used in the replace functions. +% \end{variable} +% +% \begin{variable}{% +% \l_testa_tlp | +% \l_testb_tlp | +% \g_testa_tlp | +% \g_testb_tlp | +% } +% Registers used for conditional processing if the engine doesn't +% support arbitrary string comparison. +% \end{variable} +% +% \begin{function}{\tlp_put_left_aux:w} % Used by "\tlp_put_left:Nn" and its variants. % \end{function} -% -% \begin{function}{\tlp_to_str:aux} +% +% \begin{function}{\tlp_to_str_aux:w} % Function used to implement "\tlp_to_str:N". % \end{function} +% +% +% \subsection{Search and replace} +% +% +% \begin{function}{ +% \tlp_if_in:NnTF | +% \tlp_if_in:cnTF | +% \tlp_if_in:NnT | +% \tlp_if_in:cnT | +% \tlp_if_in:NnF | +% \tlp_if_in:cnF | +% \tlist_if_in:nnTF | +% \tlist_if_in:onTF | +% } +% \begin{syntax} +% "\tlp_if_in:NnTF" <tlp> "{" <item> "}{" <true code> "}{" +% <false code> "}" +% \end{syntax} +% Function that tests if <item> is in <tlp>. Depending on the result +% either <true code> or <false code> is executed. Note that <item> +% cannot contain brace groups. +% \end{function} +% +% \begin{function}{ +% \tlp_replace_in:Nnn | +% \tlp_replace_in:cnn | +% \tlp_greplace_in:Nnn | +% \tlp_greplace_in:cnn | +% } +% \begin{syntax} +% "\tlp_replace_in:Nnn" <tlp> "{" <item1> "}{" <item2> "}" +% \end{syntax} +% Replaces the leftmost occurrence of <item1> in <tlp> with +% <item2> if present, otherwise the <tlp> is left untouched. +% \end{function} +% +% \begin{function}{ +% \tlp_replace_all_in:Nnn | +% \tlp_replace_all_in:cnn | +% \tlp_greplace_all_in:Nnn | +% \tlp_greplace_all_in:cnn | +% } +% \begin{syntax} +% "\tlp_replace_all_in:Nnn" <tlp> "{" <item1> "}{" <item2> "}" +% \end{syntax} +% Replaces \emph{all} occurrences of <item1> in <tlp> with +% <item2>. +% \end{function} +% +% +% \begin{function}{ +% \tlp_remove_in:Nn | +% \tlp_remove_in:cn | +% \tlp_gremove_in:Nn | +% \tlp_gremove_in:cn | +% } +% \begin{syntax} +% "\tlp_remove_in:Nn" <tlp> "{" <item> "}" +% \end{syntax} +% Removes the leftmost occurrence of <item> from <tlp> if present. +% \end{function} +% +% +% \begin{function}{ +% \tlp_remove_all_in:Nn | +% \tlp_remove_all_in:cn | +% \tlp_gremove_all_in:Nn | +% \tlp_gremove_all_in:cn | +% } +% \begin{syntax} +% "\tlp_remove_all_in:Nn" <tlp> "{" <item> "}" +% \end{syntax} +% Removes \emph{all} occurrences of <item> from <tlp>. +% \end{function} +% +% +% \subsection{Heads or tails?} +% +% Here are some functions for grabbing either the head or tail of a +% list and perform some tests on it. % +% \begin{function}{% +% \tlist_head:n | +% \tlist_tail:n | +% \tlist_head_iii:n | +% \tlist_head_iii:f | +% \tlist_head:w | +% \tlist_tail:w | +% \tlist_head_iii:w +% } +% \begin{syntax} +% "\tlist_head:n" "{" <token1><token2>...<token-n> "}" \\ +% "\tlist_tail:n" "{" <token1><token2>...<token-n> "}" +% \end{syntax} +% These functions return either the head or the tail of a list, thus in +% the above example "\tlist_head:n" would return <token1> and "\tlist_tail:n" +% would return <token2>\dots<token-n>. "\tlist_head_iii:n" returns the first +% three tokens. The ":w" versions require some care as they use a +% delimited argument internally. +% \begin{texnote} +% These are the Lisp functions "car" and "cdr" but with \LaTeX3 names. +% \end{texnote} +% \end{function} +% +% +% +% +% \begin{function}{% +% \tlist_if_head_eq_meaning_p:nN | +% \tlist_if_head_eq_meaning:nNTF | +% \tlist_if_head_eq_meaning:nNTF | +% \tlist_if_head_eq_meaning:nNTF | +% } +% \begin{syntax} +% "\tlist_if_head_eq_meaning:nNTF" "{" <token list> "}" <token> +% "{"<true>"}""{"<false>"}" +% \end{syntax} +% Returns <true> if the first token in <token list> is equal to +% <token> and <false> otherwise. The |meaning| version compares the +% two tokens with |\if_meaning:NN|. +% \end{function} +% +% \begin{function}{% +% \tlist_if_head_eq_charcode_p:nN | +% \tlist_if_head_eq_charcode:nNTF | +% \tlist_if_head_eq_charcode:nNTF | +% \tlist_if_head_eq_charcode:nNTF | +% } +% \begin{syntax} +% "\tlist_if_head_eq_charcode:nNTF" "{" <token list> "}" <token> +% "{"<true>"}""{"<false>"}" +% \end{syntax} +% Returns <true> if the first token in <token list> is equal to +% <token> and <false> otherwise. The |meaning| version compares the +% two tokens with |\if_charcode:w| but it prevents expansion of +% them. If you want them to expand, you can use an |f| type expansion +% first (define |\tlist_if_head_eq_charcode:fNTF| or similar). +% \end{function} +% +% \begin{function}{% +% \tlist_if_head_eq_catcode_p:nN | +% \tlist_if_head_eq_catcode:nNTF | +% \tlist_if_head_eq_catcode:nNTF | +% \tlist_if_head_eq_catcode:nNTF | +% } +% \begin{syntax} +% "\tlist_if_head_eq_catcode:nNTF" "{" <token list> "}" <token> +% "{"<true>"}""{"<false>"}" +% \end{syntax} +% Returns <true> if the first token in <token list> is equal to +% <token> and <false> otherwise. This version uses |\if_catcode:w| for +% the test but is otherwise identical to the |charcode| version. +% \end{function} +% +% % \StopEventually{} % -% \section{The code} -% +% \subsection{The Implementation} +% % We start by ensuring that the required packages are loaded. % \begin{macrocode} -%<package&!check>\RequirePackage{l3basics}\par -%<package&check>\RequirePackage{l3chk}\par -%<*package> +%<package&!check>\RequirePackage{l3basics} +%<package&check>\RequirePackage{l3chk} +% \end{macrocode} +% \begin{macrocode} +%<*initex|package> % \end{macrocode} % % A token list pointer is a control sequence that holds tokens. The @@ -224,48 +668,211 @@ % the behavior vis \'a vis |\def:Npx| etc. \ldots{} is different. (You % see this comes from Denys' implementation.) % -% We don't implement a |\tlp_use:n| function. Execution is done by -% calling the list. % % % \begin{macro}{\tlp_new:Nn} -% \begin{macro}{\tlp_clear:N} -% \begin{macro}{\tlp_gclear:N} +% \begin{macro}{\tlp_new:cn} +% \begin{macro}{\tlp_new:Nx} % We provide one allocation function (which checks that the name is % not used) and two clear functions that locally or globally clear % the token list. The allocation function has two arguments to % specify an initial value. This is the only way to give values to % constants. % \begin{macrocode} -%<*check> \def_long_new:Npn \tlp_new:Nn #1#2{ - \chk_new_cs:N #1 - \chk_var_or_const:N #1 + \chk_new_cs:N #1 +% \end{macrocode} +% If checking we don't allow constants to be defined. +% \begin{macrocode} +%<*check> + \chk_var_or_const:N #1 +%</check> +% \end{macrocode} +% Otherwise any variable type is allowed. +% \begin{macrocode} + \gdef:Npn #1{#2} +} +\def_new:Npn \tlp_new:cn {\exp_args:Nc \tlp_new:Nn } +\def_long_new:Npn \tlp_new:Nx #1#2{ + \chk_new_cs:N #1 +%<check> \chk_var_or_const:N #1 + \gdef:Npx #1{#2} +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\tlp_use:N} +% \begin{macro}{\tlp_use:c} +% Perhaps this should just be enabled when checking? +% \begin{macrocode} +\def_new:Npn \tlp_use:N #1 { + \if_meaning:NN #1 \scan_stop: +% \end{macrocode} +% If \m{tlp} equals |\scan_stop:| it is probably stemming from a +% |\cs:w ... \cd_end:| that was created by mistake somewhere. +% \begin{macrocode} + \err_latex_bug:x {Token~list~pointer~ `\token_to_string:N #1'~ + has~ an~ erroneous~ structure!} + \else: + \exp_after:NN #1 + \fi: +} +\def_new:Npn \tlp_use:c {\exp_args:Nc \tlp_use:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\tlp_set:Nn} +% \begin{macro}{\tlp_set:No} +% \begin{macro}{\tlp_set:Nf} +% \begin{macro}{\tlp_set:Nx} +% \begin{macro}{\tlp_set:cn} +% \begin{macro}{\tlp_set:co} +% \begin{macro}{\tlp_set:cx} +% \begin{macro}{\tlp_gset:Nn} +% \begin{macro}{\tlp_gset:No} +% \begin{macro}{\tlp_gset:Nx} +% \begin{macro}{\tlp_gset:cn} +% \begin{macro}{\tlp_gset:cx} +% To set token lists to a specific value to type of functions are +% available: |\tlp_set_eq:NN| takes two token-lists as its +% arguments assign the first the contents of the second; +% |\tlp_set:Nn| has as its second argument a `real' list of tokens. +% One can view |\tlp_set_eq:NN| as a special form of |\tlp_set:No|. +% Both functions have global counterparts. +% +% During development we check if the token list that is being +% assigned to exists. If not, a warning will be issued. +% \begin{macrocode} +%<*check> +\def_long_new:Npn \tlp_set:Nn #1#2{ + \chk_exist_cs:N #1 \def:Npn #1{#2} +% \end{macrocode} +% We use |\chk_local_or_pref_global:N| after the assignment to +% allow constructs with |\pref_global_chk:|. But one should note +% that this is less efficient then using the real global variant +% since they are built-in. +% \begin{macrocode} + \chk_local_or_pref_global:N #1 +} +\def_long_new:Npn \tlp_set:Nx #1#2{ + \chk_exist_cs:N #1 \def:Npx #1{#2} \chk_local:N #1 +} % \end{macrocode} -% The next line contains the token list assignments without any -% checking for variable types etc.\ since we want to allow to -% update constants here. +% The the global versions. % \begin{macrocode} - \gdef:Npn #1{#2}} +\def_long_new:Npn \tlp_gset:Nn #1#2{ + \chk_exist_cs:N #1 \gdef:Npn #1{#2} \chk_global:N #1 +} +\def_long_new:Npn \tlp_gset:Nx #1#2{ + \chk_exist_cs:N #1 \gdef:Npx #1{#2} \chk_global:N #1 +} %</check> -%<-check> \let_new:NN\tlp_new:Nn\gdef:Npn -\def_long_new:Npn \tlp_clear:N #1{\tlp_set_eq:NN #1\c_empty_tlp} -\def_long_new:Npn \tlp_gclear:N #1{\tlp_gset_eq:NN #1\c_empty_tlp} % \end{macrocode} +% For some functions like |\tlp_set:Nn| we need to define the +% `non-check' version with arguments since we want to allow +% constructions like |\tlp_set:Nn\l_tmpa_tlp\foo| and so we can't +% use the primitive \TeX{} command. +% \begin{macrocode} +%<*!check> +\def_long_new:Npn\tlp_set:Nn#1#2{\def:Npn#1{#2}} +\def_long_new:Npn\tlp_set:Nx#1#2{\def:Npx#1{#2}} +\def_long_new:Npn\tlp_gset:Nn#1#2{\gdef:Npn#1{#2}} +\def_long_new:Npn\tlp_gset:Nx#1#2{\gdef:Npx#1{#2}} +%</!check> +% \end{macrocode} +% The remaining functions can just be defined with help from the +% expansion module. +% \begin{macrocode} +\def_new:Npn \tlp_set:No {\exp_args:NNo \tlp_set:Nn} +\def_new:Npn \tlp_set:Nf {\exp_args:NNf \tlp_set:Nn} +\def_new:Npn \tlp_set:cn {\exp_args:Nc \tlp_set:Nn} +\def_new:Npn \tlp_set:co {\exp_args:Nco \tlp_set:Nn} +\def_new:Npn \tlp_set:cx {\exp_args:Nc \tlp_set:Nx} +\def_new:Npn \tlp_gset:No {\exp_args:NNo \tlp_gset:Nn} +\def_new:Npn \tlp_gset:cn {\exp_args:Nc \tlp_gset:Nn} +\def_new:Npn \tlp_gset:cx {\exp_args:Nc \tlp_gset:Nx} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % \end{macro} % \end{macro} % \end{macro} % +% \begin{macro}{\tlp_set_eq:NN} +% \begin{macro}{\tlp_set_eq:Nc} +% \begin{macro}{\tlp_set_eq:cN} +% \begin{macro}{\tlp_set_eq:cc} +% \begin{macro}{\tlp_gset_eq:NN} +% \begin{macro}{\tlp_gset_eq:Nc} +% \begin{macro}{\tlp_gset_eq:cN} +% \begin{macro}{\tlp_gset_eq:cc} +% For setting token list pointers equal to each other. First checking: +% \begin{macrocode} +%<*check> +\def_new:Npn \tlp_set_eq:NN #1#2{ + \chk_exist_cs:N #1 \let:NN #1#2 + \chk_local_or_pref_global:N #1 \chk_var_or_const:N #2 +} +\def_new:Npn \tlp_gset_eq:NN #1#2{ + \chk_exist_cs:N #1 \glet:NN #1#2 + \chk_global:N #1 \chk_var_or_const:N #2 +} +%</check> +% \end{macrocode} +% Non-checking versions are easy. +% \begin{macrocode} +%<*!check> +\let_new:NN \tlp_set_eq:NN \let:NN +\let_new:NN \tlp_gset_eq:NN \glet:NN +%</!check> +% \end{macrocode} +% The rest again with the expansion module. +% \begin{macrocode} +\def_new:Npn \tlp_set_eq:Nc {\exp_args:NNc \tlp_set_eq:NN} +\def_new:Npn \tlp_set_eq:cN {\exp_args:Nc \tlp_set_eq:NN} +\def_new:Npn \tlp_set_eq:cc {\exp_args:Ncc \tlp_set_eq:NN} +\def_new:Npn \tlp_gset_eq:Nc {\exp_args:NNc \tlp_gset_eq:NN} +\def_new:Npn \tlp_gset_eq:cN {\exp_args:Nc \tlp_gset_eq:NN} +\def_new:Npn \tlp_gset_eq:cc {\exp_args:Ncc \tlp_gset_eq:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \begin{macro}{\tlp_clear:N} % \begin{macro}{\tlp_clear:c} +% \begin{macro}{\tlp_gclear:N} % \begin{macro}{\tlp_gclear:c} -% We also define the variants that construct the token list name -% from a string. +% Clearing a token list pointer. % \begin{macrocode} +\def_new:Npn \tlp_clear:N #1{\tlp_set_eq:NN #1\c_empty_tlp} \def_new:Npn \tlp_clear:c {\exp_args:Nc \tlp_clear:N} +\def_new:Npn \tlp_gclear:N #1{\tlp_gset_eq:NN #1\c_empty_tlp} \def_new:Npn \tlp_gclear:c {\exp_args:Nc \tlp_gclear:N} % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\tlp_clear_new:N} % \begin{macro}{\tlp_clear_new:c} @@ -273,16 +880,17 @@ % is cleared, if it doesn't it is allocated. % \begin{macrocode} %<*check> -\def_long_new:Npn \tlp_clear_new:N #1{ - \chk_var_or_const:N #1 - \if:w \cs_exist_p:N #1 - \tlp_clear:N #1 - \else: - \tlp_new:Nn #1{} - \fi:} +\def_new:Npn \tlp_clear_new:N #1{ + \chk_var_or_const:N #1 + \if:w \cs_exist_p:N #1 + \tlp_clear:N #1 + \else: + \tlp_new:Nn #1{} + \fi: +} %</check> %<-check>\let_new:NN \tlp_clear_new:N \tlp_clear:N -\def_long_new:Npn \tlp_clear_new:c {\exp_args:Nc \tlp_clear_new:N} +\def_new:Npn \tlp_clear_new:c {\exp_args:Nc \tlp_clear_new:N} % \end{macrocode} % \end{macro} % \end{macro} @@ -292,16 +900,16 @@ % These are the global versions of the above. % \begin{macrocode} %<*check> -\def_long_new:Npn \tlp_gclear_new:N #1{ - \chk_var_or_const:N #1 - \if:w \cs_exist_p:N #1 - \tlp_gclear:N #1 - \else: - \tlp_new:Nn #1{} - \fi:} +\def_new:Npn \tlp_gclear_new:N #1{ + \chk_var_or_const:N #1 + \if:w \cs_exist_p:N #1 + \tlp_gclear:N #1 + \else: + \tlp_new:Nn #1{} + \fi:} %</check> %<-check>\let_new:NN \tlp_gclear_new:N \tlp_gclear:N -\def_long_new:Npn \tlp_gclear_new:c {\exp_args:Nc \tlp_gclear_new:N} +\def_new:Npn \tlp_gclear_new:c {\exp_args:Nc \tlp_gclear_new:N} % \end{macrocode} % \end{macro} % \end{macro} @@ -310,30 +918,33 @@ % \begin{macro}{\tlp_put_left:No} % \begin{macro}{\tlp_gput_left:Nn} % \begin{macro}{\tlp_gput_left:No} -% \begin{macro}{\tlp_put_left:aux} +% \begin{macro}{\tlp_gput_left:Nx} +% \begin{macro}{\tlp_put_left_aux:w} % We can add tokens to the left (either globally or locally). % \begin{macrocode} -\def_long_new:Npn \tlp_put_left:Nn #1{\exp_after:NN +\def_new:Npn \tlp_put_left:Nn #1{ % \end{macrocode} % We need expanding over a brace to ensure that if |#1| contains % just one token within braces the braces are preserved. % \begin{macrocode} - \tlp_put_left:aux\exp_after:NN{#1}#1} + \exp_args:No \tlp_put_left_aux:w {#1}#1} \def_new:Npn\tlp_put_left:No{\exp_args:NNo\tlp_put_left:Nn} -\def_long_new:Npn \tlp_gput_left:Nn { +\def_new:Npn \tlp_gput_left:Nn { %<*check> \pref_global_chk: %</check> %<-check> \pref_global:D - \tlp_put_left:Nn} + \tlp_put_left:Nn +} \def_new:Npn\tlp_gput_left:No{\exp_args:NNo\tlp_gput_left:Nn} -\def_long_new:Npn \tlp_put_left:aux #1#2#3{\def:Npn #2{#3#1} +\def_new:Npn\tlp_gput_left:Nx{\exp_args:NNx\tlp_gput_left:Nn} +\def_long_new:Npn \tlp_put_left_aux:w #1#2#3{\tlp_set:Nn #2{#3#1} % \end{macrocode} % We check the type afterwards to avoid conflicts with the use of % |\pref_global:D|. % \begin{macrocode} %<*check> - \chk_local_or_pref_global:N #2 + \chk_local_or_pref_global:N #2 %</check> } % \end{macrocode} @@ -342,6 +953,7 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}{\tlp_put_right:Nn} % \begin{macro}{\tlp_put_right:No} @@ -349,6 +961,8 @@ % \begin{macro}{\tlp_put_right:cc} % \begin{macro}{\tlp_gput_right:Nn} % \begin{macro}{\tlp_gput_right:No} +% \begin{macro}{\tlp_gput_right:cn} +% \begin{macro}{\tlp_gput_right:co} % \begin{macro}{\tlp_gput_right:Nx} % These are variants of the functions above, but for adding tokens % to the right. @@ -357,6 +971,8 @@ \def_long_new:Npn \tlp_gput_right:Nn #1#2{\tlp_gset:No #1{#1#2}} \def_new:Npn \tlp_gput_right:No {\exp_args:NNo \tlp_gput_right:Nn} \def_new:Npn \tlp_gput_right:Nx {\exp_args:NNx \tlp_gput_right:Nn} +\def_new:Npn \tlp_gput_right:cn {\exp_args:Nc \tlp_gput_right:Nn} +\def_new:Npn \tlp_gput_right:co {\exp_args:Nco \tlp_gput_right:Nn} \def_new:Npn \tlp_put_right:cc {\exp_args:Ncc \tlp_put_right:Nn} \def_new:Npn \tlp_put_right:No {\exp_args:NNo \tlp_put_right:Nn} \def_new:Npn \tlp_put_right:Nx {\exp_args:Nnx \tlp_put_right:Nn} @@ -368,85 +984,11 @@ % \end{macro} % \end{macro} % \end{macro} -% -% -% \begin{macro}{\tlp_set:Nn} -% \begin{macro}{\tlp_set:No} -% \begin{macro}{\tlp_set:Nx} -% \begin{macro}{\tlp_gset:Nn} -% \begin{macro}{\tlp_gset:No} -% \begin{macro}{\tlp_gset:Nx} -% \begin{macro}{\tlp_set_eq:NN} -% \begin{macro}{\tlp_gset_eq:NN} -% To set token lists to a specific value to type of functions are -% available: |\tlp_set_eq:NN| takes two token-lists as its -% arguments assign the first the contents of the second; -% |\tlp_set:Nn| has as its second argument a `real' list of tokens. -% One can view |\tlp_set_eq:NN| as a special form of |\tlp_set:No| -% (which is not implemented). Both functions have global -% counterparts. -% -% During development we check if the token list that is being -% assigned to exists. If not, a warning will be issued. -% \begin{macrocode} -%<*check> -\def_long_new:Npn \tlp_set:Nn #1#2{ - \chk_exist_cs:N #1 - \def:Npn #1{#2} -% \end{macrocode} -% We use |\chk_local_or_pref_global:N| after the assignment to -% allow constructs with |\pref_global_chk:|. But one should note -% that this is less efficient then using the real global variant -% since they are builtin. -% \begin{macrocode} - \chk_local_or_pref_global:N #1} -\def_long_new:Npn \tlp_set:No { - \exp_args:NNo \tlp_set:Nn} -\def_long_new:Npn \tlp_set:Nx #1#2{ - \chk_exist_cs:N #1 - \def:Npx #1{#2}\chk_local:N #1} -\def_long_new:Npn \tlp_gset:Nn #1#2{ - \chk_exist_cs:N #1 - \gdef:Npn #1{#2}\chk_global:N #1} -\def_long_new:Npn \tlp_gset:No { - \exp_args:NNo \tlp_gset:Nn} -\def_long_new:Npn \tlp_gset:Nx #1#2{ - \chk_exist_cs:N #1 - \gdef:Npx #1{#2}\chk_global:N #1} -\def_long_new:Npn \tlp_set_eq:NN #1#2{ - \chk_exist_cs:N #1 - \let:NwN #1#2 - \chk_local_or_pref_global:N #1\chk_var_or_const:N #2} -\def_long_new:Npn \tlp_gset_eq:NN #1#2{ - \chk_exist_cs:N #1 - \glet:NN #1#2 - \chk_global:N #1\chk_var_or_const:N #2} -%</check> -% \end{macrocode} -% For some functions like |\tlp_set:Nn| we need to define the -% `non-check' version with arguments since we want to allow -% constructions like |\tlp_set:Nn\l_tmpa_tlp\foo| and so we can't -% use the primitive \TeX{} command. -% \begin{macrocode} -%<-check> \def_new:Npn\tlp_set:Nn#1#2{\def:Npn#1{#2}} -%<-check> \def_new:Npn\tlp_set:Nx#1#2{\def:Npx#1{#2}} -%<-check> \def_new:Npn\tlp_gset:Nn#1#2{\gdef:Npn#1{#2}} -%<-check> \def_new:Npn\tlp_gset:Nx#1#2{\gdef:Npx#1{#2}} -%<-check> \let_new:NN\tlp_set:No\def:No -%<-check> \let_new:NN\tlp_gset:No\gdef:No -%<-check> \let_new:NN\tlp_set_eq:NN\let:NwN -%<-check> \let_new:NN\tlp_gset_eq:NN\glet:NN -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % \end{macro} % \end{macro} % % +% % \begin{macro}{\tlp_gset:Nc} % \begin{macro}{\tlp_set:Nc} % These two functions are included because they are necessary in @@ -459,10 +1001,10 @@ % \begin{macrocode} \def_new:Npn \tlp_gset:Nc { %<*check> - \pref_global_chk: + \pref_global_chk: %</check> %<-check> \pref_global:D - \tlp_set:Nc} + \tlp_set:Nc} % \end{macrocode} % |\pref_global_chk:| will turn the variable check in |\tlp_set:No| % into a global check. @@ -478,46 +1020,97 @@ % end, as explained elsewhere. % % -% \begin{macro}{\tlp_empty_p:N} +% \begin{macro}{\tlp_if_empty_p:N} +% \begin{macro}{\tlp_if_empty_p:c} % Returns |\c_true| iff the token list in the argument is empty. % \begin{macrocode} -\def_new:Npn \tlp_empty_p:N #1{ +\def_new:Npn \tlp_if_empty_p:N #1{ \if_meaning:NN#1\c_empty_tlp \c_true \else: \c_false \fi:} +\def_new:Npn \tlp_if_empty_p:c {\exp_args:Nc\tlp_if_empty_p:N} % \end{macrocode} % \end{macro} +% \end{macro} % % -% \begin{macro}{\tlp_empty:NF} -% \begin{macro}{\tlp_empty:NTF} -% These functions check whether the token list in the argument is +% \begin{macro}{\tlp_if_empty:NTF} +% \begin{macro}{\tlp_if_empty:NT} +% \begin{macro}{\tlp_if_empty:NF} +% \begin{macro}{\tlp_if_empty:cTF} +% \begin{macro}{\tlp_if_empty:cT} +% \begin{macro}{\tlp_if_empty:cF} +% These functions check whether the token list in the argument is % empty and execute the proper code from their argument(s). % \begin{macrocode} -\def_new:Npn \tlp_empty:NF #1{ - \if_meaning:NN#1\c_empty_tlp - \exp_after:NN\use_none:nn - \fi: - \use:n} -\def_new:Npn \tlp_empty:NTF #1{ - \if_meaning:NN#1\c_empty_tlp - \exp_after:NN\use_choice_i:nn - \else: - \exp_after:NN\use_choice_ii:nn - \fi:} +\def_test_function_new:npn {tlp_if_empty:N} #1{ + \if_meaning:NN#1\c_empty_tlp} +\def_new:Npn \tlp_if_empty:cTF {\exp_args:Nc \tlp_if_empty:NTF} +\def_new:Npn \tlp_if_empty:cT {\exp_args:Nc \tlp_if_empty:NT} +\def_new:Npn \tlp_if_empty:cF {\exp_args:Nc \tlp_if_empty:NF} % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % -% \begin{macro}{\tlp_eq:NNF} -% This function test whether the token lists that are in its first -% two arguments are equal; if they are not |#3| is executed. +% \begin{macro}{\tlp_if_eq_p:NN} +% \begin{macro}{\tlp_if_eq_p:Nc} +% \begin{macro}{\tlp_if_eq_p:cN} +% \begin{macro}{\tlp_if_eq_p:cc} +% Returns |\c_true| iff the two token list pointers are equal. % \begin{macrocode} -\def_new:Npn \tlp_eq:NNF #1#2{ - \if_meaning:NN#1#2 - \exp_after:NN\use_none:nn - \fi: - \use:n} +\def_new:Npn \tlp_if_eq_p:NN #1#2{ + \if_meaning:NN#1#2 \c_true \else: \c_false \fi:} +\def_new:Npn \tlp_if_eq_p:Nc {\exp_args:NNc\tlp_if_empty_p:NN} +\def_new:Npn \tlp_if_eq_p:cN {\exp_args:Nc\tlp_if_empty_p:NN} +\def_new:Npn \tlp_if_eq_p:cc {\exp_args:Ncc\tlp_if_empty_p:NN} % \end{macrocode} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tlp_if_eq:NNTF} +% \begin{macro}{\tlp_if_eq:NNT} +% \begin{macro}{\tlp_if_eq:NNF} +% \begin{macro}{\tlp_if_eq:NcTF} +% \begin{macro}{\tlp_if_eq:NcT} +% \begin{macro}{\tlp_if_eq:NcF} +% \begin{macro}{\tlp_if_eq:cNTF} +% \begin{macro}{\tlp_if_eq:cNT} +% \begin{macro}{\tlp_if_eq:cNF} +% \begin{macro}{\tlp_if_eq:ccTF} +% \begin{macro}{\tlp_if_eq:ccT} +% \begin{macro}{\tlp_if_eq:ccF} +% These function tests whether the token list pointers that are in its +% first two arguments are equal. +% \begin{macrocode} +\def_test_function_new:npn {tlp_if_eq:NN} #1#2{\if_meaning:NN#1#2} +\def_new:Npn \tlp_if_eq:cNTF{\exp_args:Nc \tlp_if_eq:NNTF} +\def_new:Npn \tlp_if_eq:cNT {\exp_args:Nc \tlp_if_eq:NNT} +\def_new:Npn \tlp_if_eq:cNF {\exp_args:Nc \tlp_if_eq:NNF} +\def_new:Npn \tlp_if_eq:NcTF{\exp_args:NNc \tlp_if_eq:NNTF} +\def_new:Npn \tlp_if_eq:NcT {\exp_args:NNc \tlp_if_eq:NNT} +\def_new:Npn \tlp_if_eq:NcF {\exp_args:NNc \tlp_if_eq:NNF} +\def_new:Npn \tlp_if_eq:ccTF{\exp_args:Ncc \tlp_if_eq:NNTF} +\def_new:Npn \tlp_if_eq:ccT {\exp_args:Ncc \tlp_if_eq:NNT} +\def_new:Npn \tlp_if_eq:ccF {\exp_args:Ncc \tlp_if_eq:NNF} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% % % \begin{macro}{\c_empty_tlp} % \begin{macro}{\c_relax_tlp} @@ -528,10 +1121,9 @@ % \end{macrocode} % \end{macro} % \end{macro} - % \begin{macro}{\g_tmpa_tlp} % \begin{macro}{\g_tmpb_tlp} -% Global temporary token list pointers. +% Global temporary token list pointers. % They are supposed to be set and used immediately, % with no delay between the definition and the use because you % can't count on other macros not to redefine them from under you. @@ -543,14 +1135,13 @@ % \end{macro} % \end{macro} % - % \begin{macro}{\l_testa_tlp} % \begin{macro}{\l_testb_tlp} % \begin{macro}{\g_testa_tlp} % \begin{macro}{\g_testb_tlp} % Global and local temporaries. These are the ones for test % routines. This means that one can safely use other temporaries -% when calling test routines. +% when calling test routines. % \begin{macrocode} \tlp_new:Nn \l_testa_tlp {} \tlp_new:Nn \l_testb_tlp {} @@ -562,7 +1153,6 @@ % \end{macro} % \end{macro} % - % \begin{macro}{\l_tmpa_tlp} % \begin{macro}{\l_tmpb_tlp} % These are local temporary token list pointers. @@ -573,16 +1163,15 @@ % \end{macro} % \end{macro} % -% % \begin{macro}{\tlp_to_str:N} % \begin{macro}{\tlp_to_str:c} -% \begin{macro}{\tlp_to_str:aux} +% \begin{macro}{\tlp_to_str_aux:w} % These functions return the replacement text of a token list as a % string list with all characters catcoded to `other'. % \begin{macrocode} -\def_new:Npn \tlp_to_str:N {\exp_after:NN\tlp_to_str:aux - \token_to_meaning:N} -\def_new:Npn \tlp_to_str:aux #1>{} +\def_new:Npn \tlp_to_str:N {\exp_after:NN\tlp_to_str_aux:w + \token_to_meaning:N} +\def_new:Npn \tlp_to_str_aux:w #1>{} \def_new:Npn\tlp_to_str:c{\exp_args:Nc\tlp_to_str:N} % \end{macrocode} % \end{macro} @@ -590,11 +1179,724 @@ % \end{macro} % % +% +% +% \begin{macro}{\tlist_if_empty_p:n} +% It would be tempting to just use "\if_meaning:NN\q_nil#1\q_nil" as +% a test since this works really well. However it fails on a token +% list starting with "\q_nil" of course but more troubling is the +% case where argument is a complete conditional such as "\if_true:" +% a "\else:" b "\fi:" because then "\if_true:" is used by +% "\if_meaning:NN", the test turns out false, the "\else:" executes +% the false branch, the "\fi:" ends it and the "\q_nil" at the end +% starts executing\dots{} A safer route is to convert the entire +% token list into harmless characters first and then compare +% that. This way the test will even accept "\q_nil" as the first +% token. +% \begin{macrocode} +\def_long_new:Npn \tlist_if_empty_p:n #1{ + \exp_after:NN\if_meaning:NN\exp_after:NN\q_nil\tlist_to_str:n{#1}\q_nil + \c_true + \else: + \c_false + \fi: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tlist_if_empty_p:o} +% \begin{macro}{\tlist_if_empty:nTF} +% \begin{macro}{\tlist_if_empty:nT} +% \begin{macro}{\tlist_if_empty:nF} +% \begin{macro}{\tlist_if_empty:oTF} +% \begin{macro}{\tlist_if_empty:oT} +% \begin{macro}{\tlist_if_empty:oF} +% \begin{macrocode} +\def_new:Npn \tlist_if_empty_p:o {\exp_args:No\tlist_if_empty_p:n} +\def_long_test_function_new:npn{tlist_if_empty:n}#1{ + \if:w\tlist_if_empty_p:n{#1}} +\def_long_test_function_new:npn{tlist_if_empty:o}#1{ + \if:w\tlist_if_empty_p:o{#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tlist_if_blank_p:n} +% \begin{macro}{\tlist_if_blank_p_aux:w} +% This is based on the answers in ``Around the Bend No~2'' but is +% safer as the tests listed there all have one small flaw: If the +% input in the test is two tokens with the same meaning as the +% internal delimiter, they will fail since one of them is mistaken +% for the actual delimiter. In our version below we make sure to +% pass the input through |\tlist_to_str:n| which ensures that all +% the tokens are converted to catcode 12. However we use an |a| with +% catcode 11 as delimiter so we can \emph{never} get into the same +% problem as the solutions in ``Around the Bend No~2''. +% \begin{macrocode} +\def_long_new:Npn \tlist_if_blank_p:n #1{ + \exp_after:NN\tlist_if_blank_p_aux:w\tlist_to_str:n{#1}aa..\q_nil +} +\def_new:Npn \tlist_if_blank_p_aux:w #1#2a#3#4\q_nil{ + \if_meaning:NN #3#4\c_true\else:\c_false\fi:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tlist_if_blank:nTF} +% \begin{macro}{\tlist_if_blank:nT} +% \begin{macro}{\tlist_if_blank:nF} +% \begin{macro}{\tlist_if_blank_p:o} +% \begin{macro}{\tlist_if_blank:oTF} +% \begin{macro}{\tlist_if_blank:oT} +% \begin{macro}{\tlist_if_blank:oF} +% Variations on the original function above. +% \begin{macrocode} +\def_long_test_function_new:npn{tlist_if_blank:n}#1{ + \if:w\tlist_if_blank_p:n{#1}} +\def:Npn \tlist_if_blank_p:o{\exp_args:No\tlist_if_blank_p:n} +\def_long_test_function_new:npn{tlist_if_blank:o}#1{ + \if:w\tlist_if_blank_p:o{#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tlist_to_lowercase:n} +% \begin{macro}{\tlist_to_uppercase:n} +% Just some names for a few primitives. +% \begin{macrocode} +\let_new:NN \tlist_to_lowercase:n \tex_lowercase:D +\let_new:NN \tlist_to_uppercase:n \tex_uppercase:D +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tlist_to_str:n} +% Another name for a primitive. +% \begin{macrocode} +\let_new:NN \tlist_to_str:n \etex_detokenize:D +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\tlist_map_function:nN} +% \begin{macro}{\tlp_map_function:NN} +% \begin{macro}{\tlp_map_function:cN} +% \begin{macro}{\tlist_map_function_aux:NN} +% Expandable loop macro for |tlist|s. These have the advantage of not +% needing to test if the argument is empty, because if it is, the stop +% marker will be read immediately and the loop terminated. +% \begin{macrocode} +\def_long_new:Npn \tlist_map_function:nN #1#2{ + \tlist_map_function_aux:Nn #2 #1 \q_nil \q_stop +} +\def_new:Npn \tlp_map_function:NN #1#2{ + \exp_after:NN \tlist_map_function_aux:Nn + \exp_after:NN #2 #1 \q_nil \q_stop +} +\def_long_new:Npn \tlist_map_function_aux:Nn #1#2{ + \quark_if_nil:nT{#2} \tlist_map_break:w + #1{#2} \tlist_map_function_aux:Nn #1 +} +\def_new:Npn\tlp_map_function:cN{\exp_args:Nc\tlp_map_function:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\tlist_map_inline:nn} +% \begin{macro}{\tlp_map_inline:Nn} +% \begin{macro}{\tlp_map_inline:cn} +% \begin{macro}{\tlist_map_inline_aux:n} +% \begin{macro}{\l_tlp_inline_level_num} +% The inline functions are straight forward by now. We use a little +% a trick with the fake counter |\l_tlp_inline_level_num| to make +% them nestable.\footnote{This should be a proper integer, but I +% don't want to mess with the dependencies right now\dots} We can +% also make use of |\tlist_map_function:Nn| from before. +% \begin{macrocode} +\def_long_new:Npn \tlist_map_inline:nn #1#2{ + \num_incr:N \l_tlp_inline_level_num + \def_long:cpn {tlist_map_inline_ \num_use:N \l_tlp_inline_level_num :n} + ##1{#2} + \exp_args:Nc \tlist_map_function_aux:Nn + {tlist_map_inline_ \num_use:N \l_tlp_inline_level_num :n} + #1 \q_nil\q_stop + \num_decr:N \l_tlp_inline_level_num +} +\def_long_new:Npn \tlp_map_inline:Nn #1#2{ + \num_incr:N \l_tlp_inline_level_num + \def_long:cpn {tlist_map_inline_ \num_use:N \l_tlp_inline_level_num :n} + ##1{#2} + \exp_args:NcE \tlist_map_function_aux:Nn + {tlist_map_inline_ \num_use:N \l_tlp_inline_level_num :n} + #1 \q_nil\q_stop + \num_decr:N \l_tlp_inline_level_num +} +\def_new:Npn\tlp_map_inline:cN{\exp_args:Nc\tlp_map_inline:NN} +\tlp_new:Nn \l_tlp_inline_level_num{0} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\tlist_map_variable:nNn} +% \begin{macro}{\tlp_map_variable:NNn} +% \begin{macro}{\tlp_map_variable:cNn} +% |\tlist_map:nNn| \zz{tlist} \zz{temp} \zz{action} assigns +% \zz{temp} to each element and executes \zz{action}. +% \begin{macrocode} +\def_long_new:Npn \tlist_map_variable:nNn #1#2#3{ + \tlist_map_variable_aux:Nnn #2 {#3} #1 \q_nil \q_stop +} +\def_new:Npn \tlp_map_variable:NNn {\exp_args:No \tlist_map_variable:nNn} +\def_new:Npn \tlp_map_variable:cNn {\exp_args:Nc \tlp_map_variable:NNn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tlist_map_variable_aux:NnN} +% The general loop. Assign the temp variable |#1| to the current item +% |#3| and then check if that's the stop marker. If it is, break the +% loop. If not, execute the action |#2| and continue. +% \begin{macrocode} +\def_long_new:Npn \tlist_map_variable_aux:Nnn #1#2#3{ + \tlp_set:Nn #1{#3} + \quark_if_nil:NT #1 \tlist_map_break:w + #2 \tlist_map_variable_aux:Nnn #1{#2} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tlist_map_break:w} +% \begin{macro}{\tlp_map_break:w} +% The break statement. +% \begin{macrocode} +\let_new:NN \tlist_map_break:w \use_none_delimit_by_q_stop:w +\let_new:NN \tlp_map_break:w \tlist_map_break:w +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% +% +% +% \begin{macro}{\tlist_if_eq:nnTF} +% \begin{macro}{\tlist_if_eq:nnT} +% \begin{macro}{\tlist_if_eq:nnF} +% Test if two token lists are identical. pdf\TeX\ contains a most +% interesting primitive for expandable string comparison so we make +% use of it if available. Presumable it will be in the final +% version. +% +% Firstly we give it an appropriate name. Note that this primitive +% actually performs an \texttt{x} type expansion but it is still +% expandable! Hence we must program these functions backwards to add +% \verb|\exp_not:n|. We provide the combinations for the types +% \texttt{n}, \texttt{o} and \texttt{x}. +% \begin{macrocode} +\let_new:NN \tlist_compare:xx \pdfstrcmp +\def_long_new:NNn \tlist_compare:nn 2{ + \tlist_compare:xx{\exp_not:n{#1}}{\exp_not:n{#2}} +} +\def_long_new:NNn \tlist_compare:nx 1{ + \tlist_compare:xx{\exp_not:n{#1}} +} +\def_long_new:NNn \tlist_compare:xn 2{ + \tlist_compare:xx{#1}{\exp_not:n{#2}} +} +\def_long_new:NNn \tlist_compare:no 2{ + \tlist_compare:xx{\exp_not:n{#1}}{\exp_not:n\exp_after:NN{#2}} +} +\def_long_new:NNn \tlist_compare:on 2{ + \tlist_compare:xx{\exp_not:n\exp_after:NN{#1}}{\exp_not:n{#2}} +} +\def_long_new:NNn \tlist_compare:oo 2{ + \tlist_compare:xx{\exp_not:n\exp_after:NN{#1}}{\exp_not:n\exp_after:NN{#2}} +} +\def_long_new:NNn \tlist_compare:xo 2{ + \tlist_compare:xx{#1}{\exp_not:n\exp_after:NN{#2}} +} +\def_long_new:NNn \tlist_compare:ox 2{ + \tlist_compare:xx{\exp_not:n\exp_after:NN{#1}}{\exp_not:n{#2}} +} +% \end{macrocode} +% Since we have a lot of basically identical functions to define we +% define one to define the rest. Unfortunately we aren't quite set up +% to use the new \verb|\tlist_map_inline:nn| function yet. +% \begin{macrocode} +\def:Npn \tmp:w #1{ + \def_long_new:cNx {tlist_if_eq_p:#1} 2{ + \exp_not:N \if_num:w + \exp_after:NN \exp_not:N \cs:w tlist_compare:#1\cs_end:{##1}{##2} + \exp_not:n{ =\c_zero \c_true \else: \c_false \fi: } + } + \def_long_test_function_new:npx{tlist_if_eq:#1}##1##2{ + \exp_not:N \if_num:w + \exp_after:NN \exp_not:N \cs:w tlist_compare:#1\cs_end:{##1}{##2} + \exp_not:n{ =\c_zero } + } +} +\tmp:w{xx} \tmp:w{nn} \tmp:w{oo} \tmp:w{xn} \tmp:w{nx} +\tmp:w{on} \tmp:w{no} \tmp:w{xo} \tmp:w{ox} +% \end{macrocode} +% However all of this only makes sense if we actually have that +% primitive. Therefore we disable it again if it is not there and +% define \verb|\tlist_if_eq:NN| the old fashioned (and unexpandable) +% way. +% \begin{macrocode} +\cs_if_really_free:cT{pdf_strcmp:D}{ + \def_long_test_function:npn{tlist_if_eq:nn}#1#2{ + \tlp_set:Nx \l_testa_tlp {\exp_not:n{#1}} + \tlp_set:Nx \l_testb_tlp {\exp_not:n{#2}} + \if_meaning:NN\l_testa_tlp \l_testb_tlp + } + \def_long_test_function:npn{tlist_if_eq:oo}#1#2{ + \tlp_set:Nx \l_testa_tlp {\exp_not:o{#1}} + \tlp_set:Nx \l_testb_tlp {\exp_not:o{#2}} + \if_meaning:NN\l_testa_tlp \l_testb_tlp + } + \def_long:Npn\tlist_compare:xx #1#2{\ERROR} +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% +% \subsubsection{Checking for and replacing tokens} +% +% \begin{macro}{\tlp_if_in:NnTF} +% \begin{macro}{\tlp_if_in:cnTF} +% \begin{macro}{\tlp_if_in:NnT} +% \begin{macro}{\tlp_if_in:cnT} +% \begin{macro}{\tlp_if_in:NnF} +% \begin{macro}{\tlp_if_in:cnF} +% \begin{macro}{\tlist_if_in:nnTF} +% \begin{macro}{\tlist_if_in:onTF} +% See the replace functions for further comments. In this part we +% don't care too much about brace stripping since we are not +% interested in passing on the tokens which are split off in the +% process. +% \begin{macrocode} +\def_long:Npn \tlp_if_in:NnTF #1#2{ + \def_long:Npn\tmp:w ##1 #2 ##2\q_stop{ + \quark_if_no_value:nFT{##2} + } + \exp_after:NN \tmp:w #1 #2 \q_no_value \q_stop +} +\def_new:Npn \tlp_if_in:cnTF {\exp_args:Nc\tlp_if_in:NnTF} +\def_long:Npn \tlp_if_in:NnT #1#2{ + \def_long:Npn\tmp:w ##1 #2 ##2\q_stop{ + \quark_if_no_value:nFT{##2} + } + \exp_after:NN \tmp:w #1 #2 \q_no_value \q_stop +} +\def_new:Npn \tlp_if_in:cnT {\exp_args:Nc\tlp_if_in:NnT} +\def_long:Npn \tlp_if_in:NnF #1#2{ + \def_long:Npn\tmp:w ##1 #2 ##2\q_stop{ + \quark_if_no_value:nT{##2} + } + \exp_after:NN \tmp:w #1 #2 \q_no_value \q_stop +} +\def_new:Npn \tlp_if_in:cnF {\exp_args:Nc\tlp_if_in:NnF} +\def_long_new:Npn \tlist_if_in:nnTF #1#2{ + \def_long:Npn\tmp:w ##1 #2 ##2\q_stop{ + \quark_if_no_value:nFT{##2} + } + \tmp:w #1 #2 \q_no_value \q_stop +} +\def_new:Npn \tlist_if_in:onTF {\exp_args:No\tlist_if_in:nnTF} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\l_tlp_replace_tlp} +% A temp variable for the replace operations. +% \begin{macrocode} +\tlp_new:Nn\l_tlp_replace_tlp{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tlp_replace_in:Nnn} +% \begin{macro}{\tlp_replace_in:cnn} +% \begin{macro}{\tlp_greplace_in:Nnn} +% \begin{macro}{\tlp_greplace_in:cnn} +% \begin{macro}{\tlp_replace_in_aux:NNnn} +% Replacing the first item in a token list pointer goes like this: +% Define a temporary function with delimited arguments containing +% the search term and take a closer look at what is left. We append +% the expansion of the tlp with the search term plus the quark +% |\q_no_value|. If the search term isn't present this last one is +% found and the following token is the quark, so we test for +% that. If the search term is present we will have to split off the +% |#3\q_no_value| we had, so we define yet another function with +% delimited arguments to do this. The advantage here is that now we +% have a special end sequence so there is no problem if the search +% term appears more than once. Only problem left is to prevent brace +% stripping in both ends, so we prepend the expansion of the tlp +% with |\q_mark| later to be gobbled and also prepend the remainder +% of the first split operation with |\q_mark| also to be gobbled +% again later on. +% \begin{macrocode} +\def_long_new:NNn \tlp_replace_in_aux:NNnn 4{ + \def:Npn \tmp:w ##1#3##2\q_stop{ + \quark_if_no_value:nF{##2} + { +% \end{macrocode} +% At this point |##1| starts with a |\q_mark| so remove it. +% \begin{macrocode} + \tlp_set:Nx\l_tlp_replace_tlp{\exp_not:o{\use_none:n##1#4}} + \def:Npn \tmp:w ####1#3\q_no_value{ + \tlp_put_right:Nx \l_tlp_replace_tlp {\exp_not:o{\use_none:n ####1}} + } + \tmp:w \q_mark ##2 + } +% \end{macrocode} +% Now all that is done is setting the token list pointer equal to the +% expansion of the token register. +% \begin{macrocode} + #1#2\l_tlp_replace_tlp + } +% \end{macrocode} +% Here is where we start the process. Note that the tlp might start +% with a space token so we use this little trick with |\use_arg_i:n| +% to prevent it from being removed. +% \begin{macrocode} + \use_arg_i:n{\exp_after:NN \tmp:w\exp_after:NN\q_mark} + #2#3 \q_no_value\q_stop +} +% \end{macrocode} +% Now the various versions doing the replacement either globally or +% locally. +% \begin{macrocode} +\def_new:Npn \tlp_replace_in:Nnn {\tlp_replace_in_aux:NNnn \tlp_set_eq:NN} +\def_new:Npn \tlp_replace_in:cnn{\exp_args:Nc\tlp_replace_in:Nnn} +\def_new:Npn \tlp_greplace_in:Nnn {\tlp_replace_in_aux:NNnn \tlp_gset_eq:NN} +\def_new:Npn \tlp_greplace_in:cnn{\exp_args:Nc\tlp_greplace_in:Nnn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tlp_replace_all_in:Nnn} +% \begin{macro}{\tlp_greplace_all_in:cnn} +% \begin{macro}{\tlp_replace_all_in:Nnn} +% \begin{macro}{\tlp_greplace_all_in:cnn} +% \begin{macro}{\tlp_replace_all_in_aux:NNnn} +% The version for replacing \emph{all} occurrences of the search +% term is fairly easy since we just have to keep doing the +% replacement on the split-off part until all are +% replaced. Otherwise it is pretty much the same as above. +% \begin{macrocode} +\def_long:NNn \tlp_replace_all_in_aux:NNnn 4{ + \tlp_clear:N \l_tlp_replace_tlp + \def:Npn \tmp:w ##1#3##2\q_stop{ + \quark_if_no_value:nTF{##2} + { + \tlp_put_right:Nx \l_tlp_replace_tlp {\exp_not:o{\use_none:n##1}} + } + { + \tlp_put_right:Nx \l_tlp_replace_tlp {\exp_not:o{\use_none:n##1 #4}} + \tmp:w \q_mark##2 \q_stop + } + } + \use_arg_i:n{\exp_after:NN \tmp:w\exp_after:NN\q_mark} + #2#3 \q_no_value\q_stop + #1#2\l_tlp_replace_tlp +} +% \end{macrocode} +% Now the various forms. +% \begin{macrocode} +\def_new:Npn \tlp_replace_all_in:Nnn { + \tlp_replace_all_in_aux:NNnn \tlp_set_eq:NN} +\def_new:Npn \tlp_replace_all_in:cnn{\exp_args:Nc\tlp_replace_all_in:Nnn} +\def_new:Npn \tlp_greplace_all_in:Nnn { + \tlp_replace_all_in_aux:NNnn \tlp_gset_eq:NN} +\def_new:Npn \tlp_greplace_all_in:cnn{\exp_args:Nc\tlp_greplace_all_in:Nnn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \begin{macro}{\tlp_remove_in:Nn} +% \begin{macro}{\tlp_remove_in:cn} +% \begin{macro}{\tlp_gremove_in:Nn} +% \begin{macro}{\tlp_gremove_in:cn} +% Next comes a series of removal functions. I have just implemented +% them as subcases of the replace functions for now (I'm lazy). +% \begin{macrocode} +\def_long_new:NNn \tlp_remove_in:Nn 2{\tlp_replace_in:Nnn #1{#2}{}} +\def_long_new:NNn \tlp_gremove_in:Nn 2{\tlp_greplace_in:Nnn #1{#2}{}} +\def_new:Npn \tlp_remove_in:cn{\exp_args:Nc\tlp_remove_in:Nn} +\def_new:Npn \tlp_gremove_in:cn{\exp_args:Nc\tlp_gremove_in:Nn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\tlp_remove_all_in:Nn} +% \begin{macro}{\tlp_remove_all_in:Nn} +% \begin{macro}{\tlp_gremove_all_in:Nn} +% \begin{macro}{\tlp_gremove_all_in:Nn} +% Same old, same old. +% \begin{macrocode} +\def_long_new:Npn \tlp_remove_all_in:Nn #1#2{ + \tlp_replace_all_in:Nnn #1{#2}{} +} +\def_long_new:Npn \tlp_gremove_all_in:Nn #1#2{ + \tlp_greplace_all_in:Nnn #1{#2}{} +} +\def_new:Npn \tlp_remove_all_in:cn{\exp_args:Nc\tlp_remove_all_in:Nn} +\def_new:Npn \tlp_gremove_all_in:cn{\exp_args:Nc\tlp_gremove_all_in:Nn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \subsubsection{Heads or tails?} +% +% \begin{macro}{\tlist_head:n} +% \begin{macro}{\tlist_head_i:n} +% \begin{macro}{\tlist_tail:n} +% \begin{macro}{\tlist_tail:f} +% \begin{macro}{\tlist_head_iii:n} +% \begin{macro}{\tlist_head_iii:f} +% \begin{macro}{\tlist_head:w} +% \begin{macro}{\tlist_tail:w} +% \begin{macro}{\tlist_head_iii:w} +% These functions pick up either the head or the tail of a list. +% "\tlist_head_iii:n" returns the first three items on a list. +% \begin{macrocode} +\def_long_new:Npn \tlist_head:n #1{\tlist_head:w #1\q_nil} +\let_new:NN \tlist_head_i:n \tlist_head:n +\def_long_new:Npn \tlist_tail:n #1{\tlist_tail:w #1\q_nil} +\def_new:Npn \tlist_tail:f {\exp_args:Nf \tlist_tail:n} +\def_long_new:Npn \tlist_head_iii:n #1{\tlist_head_iii:w #1\q_nil} +\def_new:Npn \tlist_head_iii:f {\exp_args:Nf \tlist_head_iii:n} +\let_new:NN \tlist_head:w \use_arg_i_delimit_by_q_nil:nw +\def_long_new:Npn \tlist_tail:w #1#2\q_nil{#2} +\def_long_new:Npn \tlist_head_iii:w #1#2#3#4\q_nil{#1#2#3} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\tlist_if_head_eq_meaning_p:nN} +% \begin{macro}{\tlist_if_head_eq_meaning:nNTF} +% \begin{macro}{\tlist_if_head_eq_meaning:nNT} +% \begin{macro}{\tlist_if_head_eq_meaning:nNF} +% \begin{macro}{\tlist_if_head_eq_charcode_p:nNTF} +% \begin{macro}{\tlist_if_head_eq_charcode:nNTF} +% \begin{macro}{\tlist_if_head_eq_charcode:nNT} +% \begin{macro}{\tlist_if_head_eq_charcode:nNF} +% \begin{macro}{\tlist_if_head_eq_catcode_p:nNTF} +% \begin{macro}{\tlist_if_head_eq_catcode:nNTF} +% \begin{macro}{\tlist_if_head_eq_catcode:nNT} +% \begin{macro}{\tlist_if_head_eq_catcode:nNF} +% When we want to check if the first token of a list equals something +% specific it is usually either to see if it is a control sequence or +% a character. Hence we make two different functions as the internal +% test is different. +% |\tlist_if_head_meaning_eq:nNTF| uses |\if_meaning:NN| and will +% consider the tokens |b|$\sb{11}$ and |b|$\sb{12}$ different. +% |\tlist_if_head_char_eq:nNTF| on the other hand only compares +% character codes so would regard |b|$\sb{11}$ and |b|$\sb{12}$ as +% equal but would also regard two primitives as equal. +% \begin{macrocode} +\def_long_new:Npn \tlist_if_head_eq_meaning_p:nN #1#2{ + \exp_after:NN \if_meaning:NN \tlist_head:w #1\q_nil#2 + \c_true + \else: + \c_false + \fi: +} +\def_long_test_function_new:npn {tlist_if_head_eq_meaning:nN}#1#2{ + \if:w \tlist_if_head_eq_meaning_p:nN{#1}#2} +% \end{macrocode} +% For the charcode and catcode versions we insert |\exp_not:N| in +% front of both tokens. If you need them to expand fully as \TeX{} +% does itself with these you can use an |f| type expansion. +% \begin{macrocode} +\def_long_new:Npn \tlist_if_head_eq_charcode_p:nN #1#2{ + \exp_after:NN\if_charcode:w \exp_after:NN\exp_not:N + \tlist_head:w #1\q_nil\exp_not:N#2 + \c_true + \else: + \c_false + \fi: +} +\def_long_test_function_new:npn {tlist_if_head_eq_charcode:nN}#1#2{ + \if:w\tlist_if_head_eq_charcode_p:nN{#1}#2} +% \end{macrocode} +% Actually the default is already an |f| type expansion. +% \begin{macrocode} +\def_long_new:Npn \tlist_if_head_eq_charcode_p:fN #1#2{ + \exp_after:NN\if_charcode:w \tlist_head:w #1\q_nil\exp_not:N#2 + \c_true + \else: + \c_false + \fi: +} +\def_long_test_function_new:npn {tlist_if_head_eq_charcode:fN}#1#2{ + \if:w\tlist_if_head_eq_charcode_p:fN{#1}#2} +\def_long_new:Npn \tlist_if_head_eq_catcode_p:nN #1#2{ + \exp_after:NN\if_charcode:w \exp_after:NN\exp_not:N + \tlist_head:w #1\q_nil\exp_not:N#2 + \c_true + \else: + \c_false + \fi: +} +\def_long_test_function_new:npn {tlist_if_head_eq_catcode:nN}#1#2{ + \if:w\tlist_if_head_eq_catcode_p:nN{#1}#2} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\tlist_reverse:n} +% \begin{macro}{\tlist_reverse_aux:nN} +% Reversal of a token list is done by taking one token at a time +% and putting it in front of the ones before it. +% \begin{macrocode} +\def_long_new:Npn \tlist_reverse:n #1{ + \tlist_reverse_aux:nN {} #1 \q_nil\q_stop +} +\def_long_new:Npn \tlist_reverse_aux:nN #1#2{ + \quark_if_nil:NT #2 + { \use_arg_i_delimit_by_q_stop:nw {#1} } + \tlist_reverse_aux:nN {#2#1} +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% As this package relies heavily on a lot of the expansion tricks used +% in \textsf{l3expan} we make sure to load it automatically at the end +% when used as a package. Probably not needed but I'm just such a nice +% guy\dots +% \begin{macrocode} +%<package>\RequirePackage{l3expan} +%<package>\RequirePackage{l3num}\par +% \end{macrocode} % Show token usage: % \begin{macrocode} -%</package> +%</initex|package> %<*showmemory> \showMemUsage %</showmemory> % \end{macrocode} % +% \endinput +% +% $Log$ +% Revision 1.28 2006/07/30 15:51:53 morten +% Made \tlist_map_inline:nn and variants nestable. Reimplemented +% \tlp_if_in:..., \tlp_replace_in:..., \tlp_replace_all_in:... +% +% Revision 1.27 2006/07/25 15:32:48 morten +% More \tlist_if_blank functions +% +% Revision 1.26 2006/07/06 14:58:50 morten +% Documentation touch-ups. Added more functions plus some new comparison +% functions which are dependent on a reasonably new pdfTeX. +% +% Revision 1.25 2006/06/05 14:55:14 morten +% Function for reversing a list of tokens. +% +% Revision 1.24 2006/06/03 16:31:19 morten +% Another version of \tlist_head... +% +% Revision 1.23 2006/03/20 18:26:41 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.22 2006/01/26 14:00:42 morten +% Added a few missing functions (that were documented to be there!) +% +% Revision 1.21 2006/01/19 22:27:08 morten +% Added \tlp_replace_ and \tlp_remove_if_in functions. +% +% Revision 1.20 2006/01/17 23:07:06 morten +% Added "if_in" functions. +% +% Revision 1.19 2005/12/27 10:09:07 morten +% Changed RCS information retrieval, imported all tlist functions since +% half of them dealt with token list pointers anyway +% +% Revision 1.18 2005/07/25 19:50:40 morten +% Fixed the \long-ness aspects. +% +% Revision 1.17 2005/04/12 16:43:03 morten +% Minor updates +% +% Revision 1.16 2005/04/12 12:10:28 morten +% Rearranged and cleaned up code to avoid much doubling. +% +% Revision 1.15 2005/04/06 21:34:07 morten +% Fixed all tlp_set:XX so that they're \long. Added \tlp_set:Nf +% +% Revision 1.14 2005/03/22 23:20:43 morten +% Fixed \long versions according to Benjamin's suggestions. Slightly reorganized. +% +% Revision 1.13 2005/03/16 22:35:41 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.12 2005/03/11 21:43:58 braams +% Fixed the use of RCS information; +% Fixed a documentation typo +% diff --git a/Master/texmf-dist/source/latex/expl3/l3token.dtx b/Master/texmf-dist/source/latex/expl3/l3token.dtx new file mode 100644 index 00000000000..43e8a4b5e81 --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3token.dtx @@ -0,0 +1,2004 @@ +% \iffalse +%% File: l3token.dtx Copyright (C) 2005-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3token.dtx 578 2006-11-21 18:13:24Z morten $ + {L3 Experimental token investigation and manipulation} +% +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3token.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3token} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}\\ +% Basic Definitions} +% \author{\Team} +% \date{\filedate} +% \maketitle +% +% +% \section{A token of my appreciation\dots} +% +% This module deals with tokens. Now this is perhaps not the most +% precise description so let's try with a better description: When +% programming in \TeX, it is often desirable to know just what a +% certain token is: is it a control sequence or something +% else. Similarly one often needs to know if a control sequence is +% expandable or not, a macro or a primitive, how many arguments it +% takes etc. Another thing of great importance (especially when it +% comes to document commands) is looking ahead in the token stream to +% see if a certain character is present and maybe even remove it or +% disregard other tokens while scanning. This module provides +% functions for both and as such will have two primary function +% categories: |\token| for anything that deals with tokens and +% |\peek| for looking ahead in the token stream. +% +% Most of the time we will be using the term `token' but most of the +% time the function we're describing can equally well by used on a +% control sequence as such one is one token as well. +% +% +% We shall refer to list of tokens as |tlist|s and such lists +% represented py a single control sequence is a `token list pointer' +% |tlp|. Functions for these two types are found in the \textsf{l3tlp} +% module. +% +% \subsection{Character tokens} +% +% Setting category codes of characters. +% +% +% \begin{function}{ +% \char_set_catcode:nn | +% \char_set_catcode:w | +% \char_value_catcode:n | +% \char_value_catcode:w | +% \char_show_value_catcode:n | +% \char_show_value_catcode:w +% } +% \begin{syntax} +% "\char_set_catcode:nn" "{"<char>"}" "{"<number>"}"\\ +% "\char_set_catcode:w" <char> = <number> \\ +% "\char_value_catcode:n" "{"<char>"}" \\ +% "\char_show_value_catcode:n" "{"<char>"}" +% \end{syntax} +% "\char_set_catcode:nn" sets the category code of a character, +% "\char_value_catcode:n" returns its value for use in integer tests +% and "\char_show_value_catcode:n" prints the value on the terminal +% and in the log file. The ":w" should be avoided unless you have to +% fiddle with the catcode of "{" or "}". +% \begin{texnote} +% "\char_set_catcode:w" is the \TeX\ primitive \tn{catcode} renamed. +% \end{texnote} +% \end{function} +% +% \begin{function}{ +% \char_set_lccode:nn | +% \char_set_lccode:w | +% \char_value_lccode:n | +% \char_value_lccode:w | +% \char_show_value_lccode:n | +% \char_show_value_lccode:w +% } +% \begin{syntax} +% "\char_set_lccode:nn" "{"<char>"}" "{"<number>"}" \\ +% "\char_set_lccode:w" <char> = <number> \\ +% "\char_value_lccode:n" "{"<char>"}"\\ +% "\char_show_value_lccode:n" "{"<char>"}" +% \end{syntax} +% Set the lower caser representation of <char> for when <char> is +% being converted in "\tlist_to_lowercase:n". As above, the +% ":w" form is only for people who really, really know what they are +% doing. +% \begin{texnote} +% "\char_set_lccode:w" is the \TeX\ primitive \tn{lccode} renamed. +% \end{texnote} +% \end{function} +% +% \begin{function}{ +% \char_set_uccode:nn | +% \char_set_uccode:w | +% \char_value_uccode:n | +% \char_value_uccode:w | +% \char_show_value_uccode:n | +% \char_show_value_uccode:w +% } +% \begin{syntax} +% "\char_set_uccode:nn" "{"<char>"}" "{"<number>"}"\\ +% "\char_set_uccode:w" <char> = <number> \\ +% "\char_value_uccode:n" "{"<char>"}"\\ +% "\char_show_value_uccode:n" "{"<char>"}" +% \end{syntax} +% Set the uppercase representation of <char> for when <char> is being +% converted in "\tlist_to_uppercase:n". As above, the ":w" +% form is only for people who really, really know what they are +% doing. +% \begin{texnote} +% "\char_set_uccode:w" is the \TeX\ primitive \tn{uccode} renamed. +% \end{texnote} +% \end{function} +% +% \begin{function}{ +% \char_set_sfcode:nn | +% \char_set_sfcode:w | +% \char_value_sfcode:n | +% \char_value_sfcode:w | +% \char_show_value_sfcode:n | +% \char_show_value_sfcode:w +% } +% \begin{syntax} +% "\char_set_sfcode:nn" "{"<char>"}" "{"<number>"}"\\ +% "\char_set_sfcode:w" <char> = <number> \\ +% "\char_value_sfcode:n" "{"<char>"}"\\ +% "\char_show_value_sfcode:n" "{"<char>"}" +% \end{syntax} +% Set the space factor for <char>. +% \begin{texnote} +% "\char_set_sfcode:w" is the \TeX\ primitive \tn{sfcode} renamed. +% \end{texnote} +% \end{function} +% +% +% \subsection{Generic tokens} +% +% \begin{function}{% +% \token_new:Nn | +% } +% \begin{syntax} +% "\token_new:Nn" <token 1> "{"<token 2>"}" +% \end{syntax} +% Defines <token 1> to globally be a snapshot of <token 2>. This will +% be an implicit representation of <token 2>. +% \end{function} +% +% \begin{variable}{% +% \c_group_begin_token | +% \c_group_end_token | +% \c_math_shift_token | +% \c_alignment_tab_token | +% \c_parameter_token | +% \c_math_superscript_token | +% \c_math_subscript_token | +% \c_space_token | +% \c_letter_token | +% \c_other_char_token | +% \c_active_char_token | +% } +% \begin{syntax} +% \end{syntax} +% Some useful constants. They have category codes~1, 2, 3, 4, 6, 7, +% 8, 10, 11, 12, and 13 respectively. They are all implicit tokens. +% \end{variable} +% +% \begin{function}{ +% \token_if_group_begin_p:N | +% \token_if_group_begin:NTF | +% \token_if_group_begin:NT | +% \token_if_group_begin:NF | +% } +% \begin{syntax} +% "\token_if_group_begin:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is a begin group token. +% \end{function} +% +% \begin{function}{ +% \token_if_group_end_p:N | +% \token_if_group_end:NTF | +% \token_if_group_end:NT | +% \token_if_group_end:NF | +% } +% \begin{syntax} +% "\token_if_group_end:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is an end group token. +% \end{function} +% +% \begin{function}{ +% \token_if_math_shift_p:N | +% \token_if_math_shift:NTF | +% \token_if_math_shift:NT | +% \token_if_math_shift:NF | +% } +% \begin{syntax} +% "\token_if_math_shift:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is a math shift token. +% \end{function} +% +% +% \begin{function}{ +% \token_if_aligment_tab_p:N | +% \token_if_aligment_tab:NTF | +% \token_if_aligment_tab:NT | +% \token_if_aligment_tab:NF | +% } +% \begin{syntax} +% "\token_if_aligment_tab:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is an aligment tab token. +% \end{function} +% +% \begin{function}{ +% \token_if_parameter_p:N | +% \token_if_parameter:NTF | +% \token_if_parameter:NT | +% \token_if_parameter:NF | +% } +% \begin{syntax} +% "\token_if_parameter:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is a parameter token. +% \end{function} +% +% \begin{function}{ +% \token_if_math_superscript_p:N | +% \token_if_math_superscript:NTF | +% \token_if_math_superscript:NT | +% \token_if_math_superscript:NF | +% } +% \begin{syntax} +% "\token_if_math_superscript:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is a math superscript token. +% \end{function} +% +% \begin{function}{ +% \token_if_math_subscript_p:N | +% \token_if_math_subscript:NTF | +% \token_if_math_subscript:NT | +% \token_if_math_subscript:NF | +% } +% \begin{syntax} +% "\token_if_math_subscript:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is a math subscript token. +% \end{function} +% +% \begin{function}{ +% \token_if_space_p:N | +% \token_if_space:NTF | +% \token_if_space:NT | +% \token_if_space:NF | +% } +% \begin{syntax} +% "\token_if_space:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is a space token. +% \end{function} +% +% +% \begin{function}{ +% \token_if_letter_p:N | +% \token_if_letter:NTF | +% \token_if_letter:NT | +% \token_if_letter:NF | +% } +% \begin{syntax} +% "\token_if_letter:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is a letter token. +% \end{function} +% +% +% \begin{function}{ +% \token_if_other_char_p:N | +% \token_if_other_char:NTF | +% \token_if_other_char:NT | +% \token_if_other_char:NF | +% } +% \begin{syntax} +% "\token_if_other_char:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is an other char token. +% \end{function} +% +% \begin{function}{ +% \token_if_active_char_p:N | +% \token_if_active_char:NTF | +% \token_if_active_char:NT | +% \token_if_active_char:NF | +% } +% \begin{syntax} +% "\token_if_active_char:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is an active char token. +% \end{function} +% +% +% \begin{function}{% +% \token_if_eq_meaning_p:NN | +% \token_if_eq_meaning:NNTF | +% \token_if_eq_meaning:NNT | +% \token_if_eq_meaning:NNF +% } +% \begin{syntax} +% "\token_if_eq_meaning:NNTF" <token1> <token2>"{"<true>"}""{"<false>"}" +% \end{syntax} +% Check if the meaning of two tokens are identical. +% \end{function} +% +% \begin{function}{% +% \token_if_eq_catcode_p:NN | +% \token_if_eq_catcode:NNTF | +% \token_if_eq_catcode:NNT | +% \token_if_eq_catcode:NNF +% } +% \begin{syntax} +% "\token_if_eq_catcode:NNTF" <token1> <token2>"{"<true>"}""{"<false>"}" +% \end{syntax} +% Check if the category codes of two tokens are equal. If both tokens +% are control sequences the test will be true. +% \end{function} +% +% \begin{function}{% +% \token_if_eq_charcode_p:NN | +% \token_if_eq_catcode:NNTF | +% \token_if_eq_catcode:NNT | +% \token_if_eq_catcode:NNF +% } +% \begin{syntax} +% "\token_if_eq_catcode:NNTF" <token1> <token2>"{"<true>"}""{"<false>"}" +% \end{syntax} +% Check if the character codes of two tokens are equal. If both tokens +% are control sequences the test will be true. +% \end{function} +% +% \begin{function}{ +% \token_if_macro_p:N | +% \token_if_macro:NTF | +% \token_if_macro:NT | +% \token_if_macro:NF | +% } +% \begin{syntax} +% "\token_if_macro:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is a macro. +% \end{function} +% +% +% \begin{function}{ +% \token_if_cs_p:N | +% \token_if_cs:NTF | +% \token_if_cs:NT | +% \token_if_cs:NF | +% } +% \begin{syntax} +% "\token_if_cs:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is a control sequence or not. This can be useful +% for situations where the next token in the input stream is being +% looked at and you want to determine what should be done to it. +% \end{function} +% +% +% +% +% \begin{function}{ +% \token_if_expandable_p:N | +% \token_if_expandable:NTF | +% \token_if_expandable:NT | +% \token_if_expandable:NF +% } +% \begin{syntax} +% "\token_if_expandable:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is expandable or not. Note that <token> can very +% well be an active character. +% \end{function} +% +% The next set of functions here are for picking apart control +% sequences. Sometimes it is useful to know if a control sequence has +% arguments and if so, how many. Similarly its status with respect to +% "\long" or "\protected" is good to have. Finally it can be very +% useful to know if a control sequence is of a certain type: Is this +% \m{toks} register we're trying to to something with really a +% \m{toks} register at all? +% +% \begin{function}{ +% \token_if_long_macro_p:N | +% \token_if_long_macro:NTF | +% \token_if_long_macro:NT | +% \token_if_long_macro:NF | +% } +% \begin{syntax} +% "\token_if_long_macro:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is a ``long'' macro. +% \end{function} +% +% +% \begin{function}{ +% \token_if_protected_macro_p:N | +% \token_if_protected_macro:NTF | +% \token_if_protected_macro:NT | +% \token_if_protected_macro:NF | +% } +% \begin{syntax} +% "\token_if_long_macro:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is a ``protected'' macro. This test does \emph{not} +% return <true> if the macro is also ``long'', see below. +% \end{function} +% +% \begin{function}{ +% \token_if_protected_long_macro_p:N | +% \token_if_protected_long_macro:NTF | +% \token_if_protected_long_macro:NT | +% \token_if_protected_long_macro:NF | +% } +% \begin{syntax} +% "\token_if_protected_long_macro:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is a ``protected long'' macro. +% \end{function} +% +% \begin{function}{ +% \token_if_chardef_p:N | +% \token_if_chardef:NTF | +% \token_if_chardef:NT | +% \token_if_chardef:NF | +% } +% \begin{syntax} +% "\token_if_chardef:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is defined to be a chardef. +% \end{function} +% +% \begin{function}{ +% \token_if_mathchardef_p:N | +% \token_if_mathchardef:NTF | +% \token_if_mathchardef:NT | +% \token_if_mathchardef:NF | +% } +% \begin{syntax} +% "\token_if_mathchardef:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is defined to be a mathchardef. +% \end{function} +% +% \begin{function}{ +% \token_if_int_register_p:N | +% \token_if_int_register:NTF | +% \token_if_int_register:NT | +% \token_if_int_register:NF | +% } +% \begin{syntax} +% "\token_if_int_register:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is defined to be an integer register. +% \end{function} +% +% \begin{function}{ +% \token_if_dim_register_p:N | +% \token_if_dim_register:NTF | +% \token_if_dim_register:NT | +% \token_if_dim_register:NF | +% } +% \begin{syntax} +% "\token_if_dim_register:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is defined to be a dimension register. +% \end{function} +% +% \begin{function}{ +% \token_if_skip_register_p:N | +% \token_if_skip_register:NTF | +% \token_if_skip_register:NT | +% \token_ifskip_register:NF | +% } +% \begin{syntax} +% "\token_if_skip_register:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is defined to be a skip register. +% \end{function} +% +% \begin{function}{ +% \token_if_toks_register_p:N | +% \token_if_toks_register:NTF | +% \token_if_toks_register:NT | +% \token_if_toks_register:NF | +% } +% \begin{syntax} +% "\token_if_toks_register:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is defined to be a toks register. +% \end{function} +% +% +% \begin{function}{ +% \token_get_prefix_spec:N | +% \token_get_arg_spec:N | +% \token_get_replacement_spec:N +% } +% \begin{syntax} +% "\token_get_arg_spec:N" <token> +% \end{syntax} +% If token is a macro with definition |\def_long:Npn||\next| +% |#1#2{x`#1--#2'y}|, the |prefix| function will return the string +% |\long|, the |arg| function returns the string |#1#2| and the +% |replacement| function returns the string |x`#1--#2'y|. If <token> +% isn't a macro, these functions return the |\scan_stop:| token. +% \end{function} +% +% \subsubsection{Useless code: because we can!} +% +% \begin{function}{ +% \token_if_primitive_p:N | +% \token_if_primitive:NTF | +% \token_if_primitive:NT | +% \token_if_primitive:NF | +% } +% \begin{syntax} +% "\token_if_primitive:NTF" <token> "{"<true>"}" "{"<false>"}" +% \end{syntax} +% Check if <token> is a primitive. Probably not a very useful function. +% \end{function} +% +% +% \subsection{Peeking ahead at the next token} +% +% +% +% +% +% \begin{variable}{% +% \l_peek_token | +% \g_peek_token | +% \l_peek_search_token | +% } +% \begin{syntax} +% \end{syntax} +% Some useful variables. Initially they are set to "?". +% \end{variable} +% +% +% \begin{function}{% +% \peek_after:NN | +% \peek_gafter:NN | +% } +% \begin{syntax} +% "\peek_after:NN" <function><token> +% \end{syntax} +% Assign <token> to "\l_peek_token" and then run <function> which +% should perform some sort of test on this token. Leaves <token> in +% the input stream. "\peek_gafter:NN" does this globally to the token +% "\g_peek_token". +% \begin{texnote} +% This is the primitive \tn{futurelet} turned into a function. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \peek_meaning:NTF | +% \peek_meaning_ignore_spaces:NTF | +% \peek_meaning_remove:NTF | +% \peek_meaning_remove_ignore_spaces:NTF +% } +% \begin{syntax} +% "\peek_meaning:NTF" <token> "{"<true>"}""{"<false>"}" +% \end{syntax} +% "\peek_meaning:NTF" checks (by using "\if_meaning:NN") if <token> +% equals the next token in the input stream and executes either <true +% code> or <false code> accordingly. "\peek_meaning_remove:NTF" does +% the same but additionally removes the token if found. The +% "ignore_spaces" versions skips blank spaces before making the +% decision. +% \end{function} +% +% \begin{function}{% +% \peek_charcode:NTF | +% \peek_charcode_ignore_spaces:NTF | +% \peek_charcode_remove:NTF | +% \peek_charcode_remove_ignore_spaces:NTF +% } +% \begin{syntax} +% "\peek_charcode:NTF" <token> "{"<true>"}""{"<false>"}" +% \end{syntax} +% Same as for the "\peek_meaning:NTF" functions above but these use +% "\if_charcode:w" to compare the tokens. +% \end{function} +% +% \begin{function}{% +% \peek_catcode:NTF | +% \peek_catcode_ignore_spaces:NTF | +% \peek_catcode_remove:NTF | +% \peek_catcode_remove_ignore_spaces:NTF +% } +% \begin{syntax} +% "\peek_catcode:NTF" <token> "{"<true>"}""{"<false>"}" +% \end{syntax} +% Same as for the "\peek_meaning:NTF" functions above but these use +% "\if_catcode:w" to compare the tokens. +% \end{function} +% +% +% \begin{function}{% +% \peek_token_generic:NNTF | +% \peek_token_remove_generic:NNTF +% } +% \begin{syntax} +% "\peek_token_generic:NNTF" <token><function> "{"<true>"}""{"<false>"}" +% \end{syntax} +% "\peek_token_generic:NNTF" looks ahead and checks if the next token +% in the input stream is equal to <token>. It uses <function> to make +% that decision. "\peek_token_remove_generic:NNTF" does the same +% thing but additionally removes <token> from the input stream if it +% is found. This also works if <token> is either +% "\c_group_begin_token" or "\c_group_end_token". +% \end{function} +% +% \begin{function}{% +% \peek_execute_branches_meaning: | +% \peek_execute_branches_charcode: | +% \peek_execute_branches_catcode: | +% } +% \begin{syntax} +% "\peek_execute_branches_meaning:" +% \end{syntax} +% These functions compare the token we are searching for with the +% token found (after optional ignoring of specific tokens). They come +% in the usual three versions when \TeX{} is comparing tokens: +% meaning, character code, and category code. +% \end{function} +% +% +% +% +% \subsubsection{Internal functions} +% +% \begin{variable}{% +% \l_peek_true_tlp | +% \l_peek_false_tlp | +% } +% \begin{syntax} +% \end{syntax} +% These token list pointers are used internally when choosing either +% the true or false branches of a test. +% \end{variable} +% +% \begin{function}{% +% \peek_tmp:w | +% } +% \begin{syntax} +% \end{syntax} +% Scratch function used to gobble tokens from the input stream. +% \end{function} +% +% \begin{variable}{% +% \l_peek_true_aux_tlp | +% \l_peek_true_remove_next_tlp | +% } +% \begin{syntax} +% \end{syntax} +% These token list pointers are used internally when choosing either +% the true or false branches of a test. +% \end{variable} +% +% \begin{function}{% +% \peek_ignore_spaces_execute_branches: | +% \peek_ignore_spaces_aux: | +% } +% \begin{syntax} +% \end{syntax} +% Functions used to ignore space tokens in the input stream. +% \end{function} +% +% +% +% \StopEventually{} +% +% +% \subsection{Implementation} +% First a few required packages to get this going. +% \begin{macrocode} +%<package>\RequirePackage{l3prg} +%<package>\RequirePackage{l3int} +%<*initex|package> +% \end{macrocode} +% +% \subsubsection{Character tokens} +% +% \begin{macro}{\char_set_catcode:w} +% \begin{macro}{\char_set_catcode:nn} +% \begin{macro}{\char_value_catcode:w} +% \begin{macro}{\char_value_catcode:n} +% \begin{macro}{\char_show_value_catcode:w} +% \begin{macro}{\char_show_value_catcode:n} +% \begin{macrocode} +\let_new:NN \char_set_catcode:w \tex_catcode:D +\def_new:Npn \char_set_catcode:nn #1#2{ + \char_set_catcode:w #1 = \int_eval:n{#2} +} +\def_new:Npn \char_value_catcode:w {\int_use:N\tex_catcode:D} +\def_new:Npn \char_value_catcode:n #1{\char_value_catcode:w \int_eval:n{#1}} +\def_new:Npn \char_show_value_catcode:w {\tex_showthe:D\tex_catcode:D} +\def_new:Npn \char_show_value_catcode:n #1{ + \char_show_value_catcode:w \int_eval:n{#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\char_set_lccode:w} +% \begin{macro}{\char_set_lccode:nn} +% \begin{macro}{\char_value_lccode:w} +% \begin{macro}{\char_value_lccode:n} +% \begin{macro}{\char_show_value_lccode:w} +% \begin{macro}{\char_show_value_lccode:n} +% \begin{macrocode} +\let_new:NN \char_set_lccode:w \tex_lccode:D +\def_new:Npn \char_set_lccode:nn #1#2{ + \char_set_lccode:w #1 = \int_eval:n{#2} +} +\def_new:Npn \char_value_lccode:w {\int_use:N\tex_lccode:D} +\def_new:Npn \char_value_lccode:n #1{\char_value_lccode:w \int_eval:n{#1}} +\def_new:Npn \char_show_value_lccode:w {\tex_showthe:D\tex_lccode:D} +\def_new:Npn \char_show_value_lccode:n #1{ + \char_show_value_lccode:w \int_eval:n{#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\char_set_uccode:w} +% \begin{macro}{\char_set_uccode:nn} +% \begin{macro}{\char_value_uccode:w} +% \begin{macro}{\char_value_uccode:n} +% \begin{macro}{\char_show_value_uccode:w} +% \begin{macro}{\char_show_value_uccode:n} +% \begin{macrocode} +\let_new:NN \char_set_uccode:w \tex_uccode:D +\def_new:Npn \char_set_uccode:nn #1#2{ + \char_set_uccode:w #1 = \int_eval:n{#2} +} +\def_new:Npn \char_value_uccode:w {\int_use:N\tex_uccode:D} +\def_new:Npn \char_value_uccode:n #1{\char_value_uccode:w \int_eval:n{#1}} +\def_new:Npn \char_show_value_uccode:w {\tex_showthe:D\tex_uccode:D} +\def_new:Npn \char_show_value_uccode:n #1{ + \char_show_value_uccode:w \int_eval:n{#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\char_set_sfcode:w} +% \begin{macro}{\char_set_sfcode:nn} +% \begin{macro}{\char_value_sfcode:w} +% \begin{macro}{\char_value_sfcode:n} +% \begin{macro}{\char_show_value_sfcode:w} +% \begin{macro}{\char_show_value_sfcode:n} +% \begin{macrocode} +\let_new:NN \char_set_sfcode:w \tex_sfcode:D +\def_new:Npn \char_set_sfcode:nn #1#2{ + \char_set_sfcode:w #1 = \int_eval:n{#2} +} +\def_new:Npn \char_value_sfcode:w {\int_use:N\tex_uccode:D} +\def_new:Npn \char_value_sfcode:n #1{\char_value_sfcode:w \int_eval:n{#1}} +\def_new:Npn \char_show_value_sfcode:w {\tex_showthe:D\tex_sfcode:D} +\def_new:Npn \char_show_value_sfcode:n #1{ + \char_show_value_sfcode:w \int_eval:n{#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsubsection{Generic tokens} +% +% +% \begin{macro}{\token_new:Nn} +% Creates a new token. +% \begin{macrocode} +\def_new:Npn \token_new:Nn #1#2{\glet_new:NN #1#2} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\c_group_begin_token} +% \begin{macro}{\c_group_end_token} +% \begin{macro}{\c_math_shift_token} +% \begin{macro}{\c_alignment_tab_token} +% \begin{macro}{\c_parameter_token} +% \begin{macro}{\c_math_superscript_token} +% \begin{macro}{\c_math_subscript_token} +% \begin{macro}{\c_space_token} +% \begin{macro}{\c_letter_token} +% \begin{macro}{\c_other_char_token} +% \begin{macro}{\c_active_char_token} +% We define these useful tokens. We have to do it by hand with the +% brace tokens for obvious reasons. +% \begin{macrocode} +\let_new:NN \c_group_begin_token { +\let_new:NN \c_group_end_token } +\group_begin: +\char_set_catcode:nn{`\*}{3} +\token_new:Nn \c_math_shift_token {*} +\char_set_catcode:nn{`\*}{4} +\token_new:Nn \c_alignment_tab_token {*} +\token_new:Nn \c_parameter_token {#} +\token_new:Nn \c_math_superscript_token {^} +\char_set_catcode:nn{`\*}{8} +\token_new:Nn \c_math_subscript_token {*} +\token_new:Nn \c_space_token {~} +\token_new:Nn \c_letter_token {a} +\token_new:Nn \c_other_char_token {1} +\char_set_catcode:nn{`\*}{13} +\token_new:Nn \c_active_char_token {*} +\group_end: +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_group_begin_p:N} +% \begin{macro}{\token_if_group_begin:NTF} +% \begin{macro}{\token_if_group_begin:NT} +% \begin{macro}{\token_if_group_begin:NF} +% Check if token is a begin group token. We use the constant +% "\c_group_begin_token" for this. +% \begin{macrocode} +\def_new:Npn \token_if_group_begin_p:N #1{ + \if_catcode:w \exp_not:N #1\c_group_begin_token + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_group_begin:N} #1{ + \if:w\token_if_group_begin_p:N #1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_group_end_p:N} +% \begin{macro}{\token_if_group_end:NTF} +% \begin{macro}{\token_if_group_end:NT} +% \begin{macro}{\token_if_group_end:NF} +% Check if token is a end group token. We use the constant +% "\c_group_end_token" for this. +% \begin{macrocode} +\def_new:Npn \token_if_group_end_p:N #1{ + \if_catcode:w \exp_not:N #1\c_group_end_token + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_group_end:N} #1{ + \if:w\token_if_group_end_p:N #1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\token_if_math_shift_p:N} +% \begin{macro}{\token_if_math_shift:NTF} +% \begin{macro}{\token_if_math_shift:NT} +% \begin{macro}{\token_if_math_shift:NF} +% Check if token is a math shift token. We use the constant +% "\c_math_shift_token" for this. +% \begin{macrocode} +\def_new:Npn \token_if_math_shift_p:N #1{ + \if_catcode:w \exp_not:N #1\c_math_shift_token + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_math_shift:N} #1{ + \if:w\token_if_math_shift_p:N#1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\token_if_alignment_tab_p:N} +% \begin{macro}{\token_if_alignment_tab:NTF} +% \begin{macro}{\token_if_alignment_tab:NT} +% \begin{macro}{\token_if_alignment_tab:NF} +% Check if token is an alignment tab token. We use the constant +% "\c_alignment_tab_token" for this. +% \begin{macrocode} +\def_new:Npn \token_if_alignment_tab_p:N #1{ + \if_catcode:w \exp_not:N #1\c_alignment_tab_token + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_alignment_tab:N} #1{ + \if:w\token_if_alignment_tab_p:N#1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\token_if_parameter_p:N} +% \begin{macro}{\token_if_parameter:NTF} +% \begin{macro}{\token_if_parameter:NT} +% \begin{macro}{\token_if_parameter:NF} +% Check if token is a parameter token. We use the constant +% "\c_parameter_token" for this. We have to trick \TeX{} a bit to +% avoid an error message. +% \begin{macrocode} +\def_new:Npn \token_if_parameter_p:N #1{ + \exp_after:NN\if_catcode:w \cs:w c_parameter_token\cs_end:\exp_not:N #1 + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_parameter:N} #1{ + \if:w\token_if_parameter_p:N#1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\token_if_math_superscript_p:N} +% \begin{macro}{\token_if_math_superscript:NTF} +% \begin{macro}{\token_if_math_superscript:NT} +% \begin{macro}{\token_if_math_superscript:NF} +% Check if token is a math superscript token. We use the constant +% "\c_math_superscript_token" for this. +% \begin{macrocode} +\def_new:Npn \token_if_math_superscript_p:N #1{ + \if_catcode:w \exp_not:N #1\c_math_superscript_token + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_math_superscript:N} #1{ + \if:w\token_if_math_superscript_p:N #1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\token_if_math_subscript_p:N} +% \begin{macro}{\token_if_math_subscript:NTF} +% \begin{macro}{\token_if_math_subscript:NT} +% \begin{macro}{\token_if_math_subscript:NF} +% Check if token is a math subscript token. We use the constant +% "\c_math_subscript_token" for this. +% \begin{macrocode} +\def_new:Npn \token_if_math_subscript_p:N #1{ + \if_catcode:w \exp_not:N #1\c_math_subscript_token + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_math_subscript:N} #1{ + \if:w\token_if_math_subscript_p:N #1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_space_p:N} +% \begin{macro}{\token_if_space:NTF} +% \begin{macro}{\token_if_space:NT} +% \begin{macro}{\token_if_space:NF} +% Check if token is a space token. We use the constant +% "\c_space_token" for this. +% \begin{macrocode} +\def_new:Npn \token_if_space_p:N #1{ + \if_catcode:w \exp_not:N #1\c_space_token + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_space:N} #1{ + \if:w\token_if_space_p:N #1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\token_if_letter_p:N} +% \begin{macro}{\token_if_letter:NTF} +% \begin{macro}{\token_if_letter:NT} +% \begin{macro}{\token_if_letter:NF} +% Check if token is a letter token. We use the constant +% "\c_letter_token" for this. +% \begin{macrocode} +\def_new:Npn \token_if_letter_p:N #1{ + \if_catcode:w \exp_not:N #1\c_letter_token + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_letter:N} #1{ + \if:w\token_if_letter_p:N #1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_other_char_p:N} +% \begin{macro}{\token_if_other_char:NTF} +% \begin{macro}{\token_if_other_char:NT} +% \begin{macro}{\token_if_other_char:NF} +% Check if token is an other char token. We use the constant +% "\c_other_char_token" for this. +% \begin{macrocode} +\def_new:Npn \token_if_other_char_p:N #1{ + \if_catcode:w \exp_not:N #1\c_other_char_token + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_other_char:N} #1{ + \if:w\token_if_other_char_p:N #1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_active_char_p:N} +% \begin{macro}{\token_if_active_char:NTF} +% \begin{macro}{\token_if_active_char:NT} +% \begin{macro}{\token_if_active_char:NF} +% Check if token is an active char token. We use the constant +% "\c_active_char_token" for this. +% \begin{macrocode} +\def_new:Npn \token_if_active_char_p:N #1{ + \if_catcode:w \exp_not:N #1\c_active_char_token + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_active_char:N} #1{ + \if:w\token_if_active_char_p:N #1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_eq_meaning_p:NN} +% \begin{macro}{\token_if_eq_meaning:NNTF} +% \begin{macro}{\token_if_eq_meaning:NNT} +% \begin{macro}{\token_if_eq_meaning:NNF} +% Check if the tokens |#1| and |#2| have same meaning. +% \begin{macrocode} +\def_new:Npn \token_if_eq_meaning_p:NN #1#2 { + \if_meaning:NN #1 #2 + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_eq_meaning:NN}#1#2{ + \if_meaning:NN #1 #2} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_eq_catcode_p:NN} +% \begin{macro}{\token_if_eq_catcode:NNTF} +% \begin{macro}{\token_if_eq_catcode:NNT} +% \begin{macro}{\token_if_eq_catcode:NNF} +% Check if the tokens |#1| and |#2| have same category code. +% \begin{macrocode} +\def_new:Npn \token_if_eq_catcode_p:NN #1#2 { + \if_catcode:w \exp_not:N #1 \exp_not:N #2 + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_eq_catcode:NN}#1#2{ + \if:w\token_if_eq_catcode_p:NN#1#2} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \begin{macro}{\token_if_eq_charcode_p:NN} +% \begin{macro}{\token_if_eq_charcode:NNTF} +% \begin{macro}{\token_if_eq_charcode:NNT} +% \begin{macro}{\token_if_eq_charcode:NNF} +% Check if the tokens |#1| and |#2| have same character code. +% \begin{macrocode} +\def_new:Npn \token_if_charcode_eq_p:NN #1#2 { + \if_charcode:w \exp_not:N #1 \exp_not:N #2 + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_eq_charcode:NN}#1#2{ + \if:w\token_if_eq_charcode_p:NN#1#2} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_macro_p:N} +% \begin{macro}{\token_if_macro_p_aux:w} +% \begin{macro}{\token_if_macro:NTF} +% \begin{macro}{\token_if_macro:NT} +% \begin{macro}{\token_if_macro:NF} +% When a token is a macro, "\token_to_meaning:N" will always output +% something like "\long macro:#1->#1" so we simply check to see if +% the meaning contains "->". Argument "#2" in the code below will be +% empty if the string "->" isn't present, proof that the token was +% not a macro (which is why we reverse the emptiness test). However +% this function will fail on its own auxiliary function (and a few +% other private functions as well) but that should certainly never +% be a problem! +% \begin{macrocode} +\def_new:Npn \token_if_macro_p:N #1 { + \exp_after:NN \token_if_macro_p_aux:w \token_to_meaning:N #1 -> \q_nil +} +\def_new:Npn \token_if_macro_p_aux:w #1 -> #2 \q_nil{ + \if:w \tlist_if_empty_p:n{#2} \c_false \else: \c_true \fi: +} +\def_test_function_new:npn {token_if_macro:N} #1{\if:w\token_if_macro_p:N#1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_cs_p:N} +% \begin{macro}{\token_if_cs:NTF} +% \begin{macro}{\token_if_cs:NT} +% \begin{macro}{\token_if_cs:NF} +% Check if token has same catcode as a control sequence. We use +% "\scan_stop:" for this. +% \begin{macrocode} +\def_new:Npn \token_if_cs_p:N {\token_if_eq_catcode_p:NN \scan_stop:} +\def_test_function_new:npn {token_if_cs:N} #1{ + \if:w \token_if_eq_catcode_p:NN \scan_stop: #1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\token_if_expandable_p:N} +% \begin{macro}{\token_if_expandable:NTF} +% \begin{macro}{\token_if_expandable:NT} +% \begin{macro}{\token_if_expandable:NF} +% Check if token is expandable. We use the fact that \TeX\ will +% temporarily convert "\exp_not:N" \m{token} into "\scan_stop:" if +% \m{token} is expandable. +% \begin{macrocode} +\def_new:Npn \token_if_expandable_p:N #1{ + \exp_after:NN \if_token_eq:NN \exp_not:N #1 \scan_stop: + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn {token_if_expandable:N} #1{ + \if:w\token_if_expandable_p:N#1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_chardef_p:N} +% \begin{macro}{\token_if_chardef_p_aux:w} +% \begin{macro}{\token_if_mathchardef_p:N} +% \begin{macro}{\token_if_mathchardef_p_aux:w} +% \begin{macro}{\token_if_int_register_p:N} +% \begin{macro}{\token_if_int_register_p_aux:w} +% \begin{macro}{\token_if_skip_register_p:N} +% \begin{macro}{\token_if_skip_register_p_aux:w} +% \begin{macro}{\token_if_dim_register_p:N} +% \begin{macro}{\token_if_dim_register_p_aux:w} +% \begin{macro}{\token_if_toks_register_p:N} +% \begin{macro}{\token_if_toks_register_p_aux:w} +% \begin{macro}{\token_if_protected_macro_p:N} +% \begin{macro}{\token_if_protected_macro_p_aux:w} +% \begin{macro}{\token_if_long_macro_p:N} +% \begin{macro}{\token_if_long_macro_p_aux:w} +% \begin{macro}{\token_if_protected_long_macro_p:N} +% \begin{macro}{\token_if_protected_long_macro_p_aux:w} +% Most of these functions have to check the meaning of the token in +% question so we need to do some checkups on which characters are +% output by |\token_to_meaning:N|. As usual, these characters have +% catcode 12 so we must do some serious substitutions in the code +% below\dots +% \begin{macrocode} +\group_begin: + \char_set_lccode:nn {`\X}{`\n} + \char_set_lccode:nn {`\Y}{`\t} + \char_set_lccode:nn {`\Z}{`\d} + \char_set_lccode:nn {`\?}{`\\} + \tlist_map_inline:nn{\X\Y\Z\M\T\C\H\A\R\O\U\S\K\I\P\L\G\P\E} + {\char_set_catcode:nn {`#1}{12}} +% \end{macrocode} +% We convert the token list to lowercase and restore the catcode and +% lowercase code changes. +% \begin{macrocode} +\tlist_to_lowercase:n{ + \group_end: +% \end{macrocode} +% First up is checking if something has been defined with +% |\tex_chardef:D| or |\tex_mathchardef:D|. This is easy since \TeX\ +% thinks of such tokens as hexadecimal so it stores them as +% |\char"|\meta{hex~number} or |\mathchar"|\meta{hex~number}. +% \begin{macrocode} +\def_new:Npn \token_if_chardef_p:N #1 { + \exp_after:NN \token_if_chardef_p_aux:w + \token_to_meaning:N #1?CHAR"\q_nil +} +\def_new:Npn \token_if_chardef_p_aux:w #1?CHAR"#2\q_nil{ + \tlist_if_empty_p:n{#1} +} +\def_new:Npn \token_if_mathchardef_p:N #1 { + \exp_after:NN \token_if_mathchardef_p_aux:w + \token_to_meaning:N #1?MAYHCHAR"\q_nil +} +\def_new:Npn \token_if_mathchardef_p_aux:w #1?MAYHCHAR"#2\q_nil{ + \tlist_if_empty_p:n{#1} +} +% \end{macrocode} +% Integer registers are a little more difficult since they expand to +% |\count|\meta{number} and there is also a primitive |\countdef|. So +% we have to check for that primitive as well. +% \begin{macrocode} +\def:Npn \token_if_int_register_p:N #1{ + \if_meaning:NN \tex_countdef:D #1 + \c_false + \else: + \exp_after:NN \token_if_int_register_p_aux:w + \token_to_meaning:N #1?COUXY\q_nil + \fi: +} +\def_new:Npn \token_if_int_register_p_aux:w #1?COUXY#2\q_nil{ + \tlist_if_empty_p:n{#1} +} +% \end{macrocode} +% Skip registers are done the same way as the integer registers. +% \begin{macrocode} +\def:Npn \token_if_skip_register_p:N #1{ + \if_meaning:NN \tex_skipdef:D #1 + \c_false + \else: + \exp_after:NN \token_if_skip_register_p_aux:w + \token_to_meaning:N #1?SKIP\q_nil + \fi: +} +\def_new:Npn \token_if_skip_register_p_aux:w #1?SKIP#2\q_nil{ + \tlist_if_empty_p:n{#1} +} +% \end{macrocode} +% Dim registers. No news here +% \begin{macrocode} +\def:Npn \token_if_dim_register_p:N #1{ + \if_meaning:NN \tex_dimendef:D #1 + \c_false + \else: + \exp_after:NN \token_if_dim_register_p_aux:w + \token_to_meaning:N #1?ZIMEX\q_nil + \fi: +} +\def_new:Npn \token_if_dim_register_p_aux:w #1?ZIMEX#2\q_nil{ + \tlist_if_empty_p:n{#1} +} +% \end{macrocode} +% Toks registers. Ho-hum. +% \begin{macrocode} +\def:Npn \token_if_toks_register_p:N #1{ + \if_meaning:NN \tex_toksdef:D #1 + \c_false + \else: + \exp_after:NN \token_if_toks_register_p_aux:w + \token_to_meaning:N #1?YOKS\q_nil + \fi: +} +\def_new:Npn \token_if_toks_register_p_aux:w #1?YOKS#2\q_nil{ + \tlist_if_empty_p:n{#1} +} +% \end{macrocode} +% Protected macros. +% \begin{macrocode} +\def_new:Npn \token_if_protected_macro_p:N #1 { + \exp_after:NN \token_if_protected_macro_p_aux:w + \token_to_meaning:N #1?PROYECYEZ~MACRO\q_nil +} +\def_new:Npn \token_if_protected_macro_p_aux:w #1?PROYECYEZ~MACRO#2\q_nil{ + \tlist_if_empty_p:n{#1} +} +% \end{macrocode} +% Long macros. +% \begin{macrocode} +\def_new:Npn \token_if_long_macro_p:N #1 { + \exp_after:NN \token_if_long_macro_p_aux:w + \token_to_meaning:N #1?LOXG~MACRO\q_nil +} +\def_new:Npn \token_if_long_macro_p_aux:w #1?LOXG~MACRO#2\q_nil{ + \tlist_if_empty_p:n{#1} +} +% \end{macrocode} +% Finally protected long macros where we for once don't have to add an +% extra test since there is no primitive for the combined prefixes. +% \begin{macrocode} +\def_new:Npn \token_if_protected_long_macro_p:N #1 { + \exp_after:NN \token_if_protected_long_macro_p_aux:w + \token_to_meaning:N #1?PROYECYEZ~?LOXG~MACRO\q_nil +} +\def_new:Npn \token_if_protected_long_macro_p_aux:w #1 + ?PROYECYEZ~?LOXG~MACRO#2\q_nil{ + \tlist_if_empty_p:n{#1} +} +% \end{macrocode} +% Finally the |\tlist_to_lowercase:n| ends! +% \begin{macrocode} +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_chardef:NTF} +% \begin{macro}{\token_if_chardef:NT} +% \begin{macro}{\token_if_chardef:NF} +% \begin{macrocode} +\def_test_function_new:npn {token_if_chardef:N} {\if:w \token_if_chardef_p:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_mathchardef:NTF} +% \begin{macro}{\token_if_mathchardef:NT} +% \begin{macro}{\token_if_mathchardef:NF} +% \begin{macrocode} +\def_test_function_new:npn {token_if_mathchardef:N} { + \if:w \token_if_mathchardef_p:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_long_macro:NTF} +% \begin{macro}{\token_if_long_macro:NT} +% \begin{macro}{\token_if_long_macro:NF} +% \begin{macrocode} +\def_test_function_new:npn {token_if_long_macro:N} { + \if:w \token_if_long_macro_p:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_protected_macro:NTF} +% \begin{macro}{\token_if_protected_macro:NT} +% \begin{macro}{\token_if_protected_macro:NF} +% \begin{macrocode} +\def_test_function_new:npn {token_if_protected_macro:N} { + \if:w \token_if_protected_macro_p:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_protected_long_macro:NTF} +% \begin{macro}{\token_if_protected_long_macro:NT} +% \begin{macro}{\token_if_protected_long_macro:NF} +% \begin{macrocode} +\def_test_function_new:npn {token_if_protected_long_macro:N} { + \if:w \token_if_protected_long_macro_p:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_dim_register:NTF} +% \begin{macro}{\token_if_dim_register:NT} +% \begin{macro}{\token_if_dim_register:NF} +% \begin{macrocode} +\def_test_function_new:npn {token_if_dim_register:N} { + \if:w \token_if_dim_register_p:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_skip_register:NTF} +% \begin{macro}{\token_if_skip_register:NT} +% \begin{macro}{\token_if_skip_register:NF} +% \begin{macrocode} +\def_test_function_new:npn {token_if_skip_register:N} { + \if:w \token_if_skip_register_p:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_int_register:NTF} +% \begin{macro}{\token_if_int_register:NT} +% \begin{macro}{\token_if_int_register:NF} +% \begin{macrocode} +\def_test_function_new:npn {token_if_int_register:N} { + \if:w \token_if_int_register_p:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\token_if_toks_register:NTF} +% \begin{macro}{\token_if_toks_register:NT} +% \begin{macro}{\token_if_toks_register:NF} +% \begin{macrocode} +\def_test_function_new:npn {token_if_toks_register:N} { + \if:w \token_if_toks_register_p:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% +% We do not provide a function for testing if a control sequence is +% ``outer'' since we don't use that in \LaTeX3. +% +% \begin{macro}{\token_get_prefix_arg_replacement_aux:w} +% \begin{macro}{\token_get_prefix_spec:N} +% \begin{macro}{\token_get_arg_spec:N} +% \begin{macro}{\token_get_replacement_spec:N} +% In the \textsf{xparse} package we sometimes want to test if a +% control sequence can be expanded to reveal a hidden +% value. However, we cannot just expand the macro blindly as it may +% have arguments and none might be present. Therefore we define +% these functions to pick either the prefix(es), the argument +% specification, or the replacement text from a macro. All of this +% information is returned as characters with catcode~12. If the +% token in question isn't a macro, the token |\scan_stop:| is +% returned instead. +% \begin{macrocode} +\group_begin: +\char_set_lccode:nn {`\?}{`\:} +\char_set_catcode:nn{`\M}{12} +\char_set_catcode:nn{`\A}{12} +\char_set_catcode:nn{`\C}{12} +\char_set_catcode:nn{`\R}{12} +\char_set_catcode:nn{`\O}{12} +\tlist_to_lowercase:n{ + \group_end: + \def_new:Npn \token_get_prefix_arg_replacement_aux:w #1MACRO?#2->#3\q_nil#4{ + #4{#1}{#2}{#3} + } + \def_new:Npn\token_get_prefix_spec:N #1{ + \token_if_macro:NTF #1{ + \exp_after:NN \token_get_prefix_arg_replacement_aux:w + \token_to_meaning:N #1\q_nil\use_arg_i:nnn + }{\scan_stop:} + } + \def_new:Npn\token_get_arg_spec:N #1{ + \token_if_macro:NTF #1{ + \exp_after:NN \token_get_prefix_arg_replacement_aux:w + \token_to_meaning:N #1\q_nil\use_arg_ii:nnn + }{\scan_stop:} + } + \def_new:Npn\token_get_replacement_spec:N #1{ + \token_if_macro:NTF #1{ + \exp_after:NN \token_get_prefix_arg_replacement_aux:w + \token_to_meaning:N #1\q_nil\use_arg_iii:nnn + }{\scan_stop:} + } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \paragraph{Useless code: because we can!} +% +% \begin{macro}{\token_if_primitive_p:N} +% \begin{macro}{\token_if_primitive_p_aux:N} +% \begin{macro}{\token_if_primitive:NTF} +% \begin{macro}{\token_if_primitive:NT} +% \begin{macro}{\token_if_primitive:NF} +% It is rather hard to determine if a token is a primitive. First we +% can check if it is a control sequence or active character. If +% either, we check if it is a macro. Then we can go through a +% tedious process of testing for different register types\dots{} I +% don't actually think this function is useful but you never know. +% \begin{macrocode} +\def_new:Npn \token_if_primitive_p:N #1{ + \if:w \token_if_cs_p:N #1\scan_stop: + \if:w \token_if_macro_p:N #1 + \c_false + \else: + \token_if_primitive_p_aux:N #1 + \fi: + \else: + \if:w \token_if_active_p:N #1 + \if:w \token_if_macro_p:N #1 + \c_false + \else: + \token_if_primitive_p_aux:N #1 + \fi: + \else: + \c_false + \fi: + \fi: +} +\def_new:Npn \token_if_primitive_p_aux:N #1{ + \if:w \token_if_chardef_p:N #1 \c_false + \else: + \if:w \token_if_mathchardef_p:N #1 \c_false + \else: + \if:w \token_if_int_register_p:N #1 \c_false + \else: + \if:w \token_if_skip_register_p:N #1 \c_false + \else: + \if:w \token_if_dim_register_p:N #1 \c_false + \else: + \if:w \token_if_toks_register_p:N #1 \c_false + \else: +% \end{macrocode} +% We made it! +% \begin{macrocode} + \c_true + \fi: + \fi: + \fi: + \fi: + \fi: + \fi: +} +\def_test_function_new:npn {token_if_primitive:N} #1{ + \if:w\token_if_primitive_p:N#1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% +% \subsubsection{Peeking ahead at the next token} +% +% +% +% +% +% +% \begin{macro}{\l_peek_token} +% \begin{macro}{\g_peek_token} +% \begin{macro}{\l_peek_search_token} +% We define some other tokens which will initially be the character +% |?|. +% \begin{macrocode} +\token_new:Nn \l_peek_token {?} +\token_new:Nn \g_peek_token {?} +\token_new:Nn \l_peek_search_token {?} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\peek_after:NN} +% \begin{macro}{\peek_gafter:NN} +% |\peek_after:NN| takes two argument where the first is a function +% acting on |\l_peek_token| and the second is the next token in the +% input stream which |\l_peek_token| is set equal to. +% |\peek_gafter:NN| does the same globally to |\g_peek_token|. +% \begin{macrocode} +\def_new:Npn \peek_after:NN {\tex_futurelet:D \l_peek_token } +\def_new:Npn \peek_gafter:NN { + \pref_global:D \tex_futurelet:D \g_peek_token +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% For normal purposes there are four main cases: +% \begin{enumerate} +% \item peek at the next token. +% \item peek at the next non-space token. +% \item peek at the next token and remove it. +% \item peek at the next non-space token and remove it. +% \end{enumerate} +% +% +% The generic functions will take four arguments: The token to search +% for, the test function to run on it and the true/false cases. +% The general algorithm is this: +% \begin{enumerate} +% \item +% Store the token to search for in |\l_peek_search_token|. +% \item +% In order to avoid doubling of hash marks where it seems unnatural +% we put the \meta{true} and \meta{false} cases through an |x| type +% expansion but using |\exp_not:n| to avoid any expansion. This has +% the same effect as putting it through a \meta{toks} register but +% is faster. Also put in a special alignment safe group end. +% \item +% Put in an alignment safe group begin. +% \item +% Peek ahead and call the function which will act on the next token +% in the input stream. +% \end{enumerate} +% +% \begin{macro}{\l_peek_true_tlp} +% \begin{macro}{\l_peek_false_tlp} +% Two dedicated token list pointers that store the true and false +% cases. +% \begin{macrocode} +\tlp_new:Nn \l_peek_true_tlp {} +\tlp_new:Nn \l_peek_false_tlp {} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\peek_tmp:w} +% Scratch function used for storing the token to be removed if +% found. +% \begin{macrocode} +\def_new:Npn \peek_tmp:w{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\l_peek_search_tlp} +% We also use this token list pointer for storing the token we want +% to compare. This turns out to be useful. +% \begin{macrocode} +\tlp_new:Nn \l_peek_search_tlp{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\peek_token_generic:NNTF} +% |#1| is the function to execute (obey or ignore spaces, etc.), +% |#2| is the special token we're looking for, and |#3| and |#4| +% are the \meta{true} and \meta{false} branches. +% \begin{macrocode} +\def_long_new:Npn \peek_token_generic:NNTF #1#2#3#4{ + \let:NN \l_peek_search_token #2 + \tlp_set:Nn \l_peek_search_tlp {#2} + \tlp_set:Nx \l_peek_true_tlp {\exp_not:n{\group_align_safe_end: #3}} + \tlp_set:Nx \l_peek_false_tlp {\exp_not:n{\group_align_safe_end: #4}} + \group_align_safe_begin: + \peek_after:NN #1 +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\peek_token_remove_generic:NNTF} +% If we want to be able to remove any character from the input +% stream we might as well do it the same way for all characters so +% we define this as little differently from above. +% \begin{macrocode} +\def_long_new:Npn \peek_token_remove_generic:NNTF #1#2#3#4{ + \let:NN \l_peek_search_token #2 + \tlp_set:Nn \l_peek_search_tlp {#2} + \tlp_set:Nx \l_peek_true_aux_tlp { \exp_not:n{ #3 } } + \tlp_set_eq:NN \l_peek_true_tlp \c_peek_true_remove_next_tlp + \tlp_set:Nx \l_peek_false_tlp {\exp_not:n{\group_align_safe_end: #4}} + \group_align_safe_begin: + \peek_after:NN #1 +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\l_peek_true_aux_tlp} +% \begin{macro}{\l_peek_true_remove_next_tlp} +% Two token list pointers to help with removing the character from +% the input stream. +% \begin{macrocode} +\tlp_new:Nn \l_peek_true_aux_tlp {} +\tlp_new:Nn \c_peek_true_remove_next_tlp {\group_align_safe_end: + \tex_afterassignment:D \l_peek_true_aux_tlp \let:NN \peek_tmp:w +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\peek_execute_braches_meaning:} +% \begin{macro}{\peek_execute_braches_catcode:} +% \begin{macro}{\peek_execute_braches_charcode:} +% \begin{macro}{\peek_execute_branches_charcode_aux:NN} +% There are three major tests between tokens in \TeX: meaning, +% catcode and charcode. Hence we define three basic test functions +% that set in after the ignoring phase is over and done with. +% \begin{macrocode} +\def_new:Npn \peek_execute_branches_meaning: { + \if_meaning:NN \l_peek_token \l_peek_search_token + \exp_after:NN \l_peek_true_tlp + \else: + \exp_after:NN \l_peek_false_tlp + \fi: +} +\def_new:Npn \peek_execute_branches_catcode: { + \if_catcode:w \exp_not:N\l_peek_token \exp_not:N\l_peek_search_token + \exp_after:NN \l_peek_true_tlp + \else: + \exp_after:NN \l_peek_false_tlp + \fi: +} +% \end{macrocode} +% For the charcode version we do things a little differently. We want +% to check the token directly but if we do this we face problems if +% the next thing in the input stream is a braced group or a space +% token. The braced group would be read as a complete argument and the +% space would be gobbled by \TeX's argument reading routines. Hence we +% test for both of these and if one of them is found we just execute +% the false result directly since no one should ever try to use the +% |charcode| function for searching for |\c_group_begin_token| or +% |\c_space_token|. +% \begin{macrocode} +\def_new:Npn \peek_execute_branches_charcode: { + \prg_if_predicate:nTF { + \prg_if_predicate_or_p:nn + {\token_if_eq_catcode_p:NN \l_peek_token \c_group_begin_token} + {\token_if_eq_meaning_p:NN \l_peek_token \c_space_token} + } + { \l_peek_false_tlp } +% \end{macrocode} +% Otherwise we call a small auxiliary function that just grabs the +% next token. We can do that because it really is a single token; we +% just have insert it again afterwards. Also we stored the token we +% were looking for in the token list pointer |\l_peek_search_tlp| so +% we unpack it again for this function. +% \begin{macrocode} + { \exp_after:NN \peek_execute_branches_charcode_aux:NN \l_peek_search_tlp } +} +% \end{macrocode} +% Then we just do the usual |\if_charcode:w| comparison. We also +% remember to insert |#2| again after executing the true or false +% branches. +% \begin{macrocode} +\def_long_new:Npn \peek_execute_branches_charcode_aux:NN #1#2{ + \if_charcode:w \exp_not:N #1\exp_not:N#2 + \exp_after:NN \l_peek_true_tlp + \else: + \exp_after:NN \l_peek_false_tlp + \fi: + #2 +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\peek_meaning:NTF} +% \begin{macro}{\peek_meaning_ignore_spaces:NTF} +% \begin{macro}{\peek_meaning_remove:NTF} +% \begin{macro}{\peek_meaning_remove_ignore_spaces:NTF} +% Here we use meaning comparison with |\if_meaning:NN|. +% \begin{macrocode} +\def_new:Npn \peek_meaning:NTF { + \peek_token_generic:NNTF \peek_execute_branches_meaning: +} +\def_new:Npn \peek_meaning_ignore_spaces:NTF { + \let:NN \peek_execute_branches: \peek_execute_branches_meaning: + \peek_token_generic:NNTF \peek_ignore_spaces_execute_branches: +} +\def_new:Npn \peek_meaning_remove:NTF { + \peek_token_remove_generic:NNTF \peek_execute_branches_meaning: +} +\def_new:Npn \peek_meaning_remove_ignore_spaces:NTF { + \let:NN \peek_execute_branches: \peek_execute_branches_meaning: + \peek_token_remove_generic:NNTF \peek_ignore_spaces_execute_branches: +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\peek_catcode:NTF} +% \begin{macro}{\peek_catcode_ignore_spaces:NTF} +% \begin{macro}{\peek_catcode_remove:NTF} +% \begin{macro}{\peek_catcode_remove_ignore_spaces:NTF} +% Here we use catcode comparison with |\if_catcode:w|. +% \begin{macrocode} +\def_new:Npn \peek_catcode:NTF { + \peek_token_generic:NNTF \peek_execute_branches_catcode: +} +\def_new:Npn \peek_catcode_ignore_spaces:NTF { + \let:NN \peek_execute_branches: \peek_execute_branches_catcode: + \peek_token_generic:NNTF \peek_ignore_spaces_execute_branches: +} +\def_new:Npn \peek_catcode_remove:NTF { + \peek_token_remove_generic:NNTF \peek_execute_branches_catcode: +} +\def_new:Npn \peek_catcode_remove_ignore_spaces:NTF { + \let:NN \peek_execute_branches: \peek_execute_branches_catcode: + \peek_token_remove_generic:NNTF \peek_ignore_spaces_execute_branches: +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\peek_charcode:NTF} +% \begin{macro}{\peek_charcode_ignore_spaces:NTF} +% \begin{macro}{\peek_charcode_remove:NTF} +% \begin{macro}{\peek_charcode_remove_ignore_spaces:NTF} +% Here we use charcode comparison with |\if_charcode:w|. +% \begin{macrocode} +\def_new:Npn \peek_charcode:NTF { + \peek_token_generic:NNTF \peek_execute_branches_charcode: +} +\def_new:Npn \peek_charcode_ignore_spaces:NTF { + \let:NN \peek_execute_branches: \peek_execute_branches_charcode: + \peek_token_generic:NNTF \peek_ignore_spaces_execute_branches: +} +\def_new:Npn \peek_charcode_remove:NTF { + \peek_token_remove_generic:NNTF \peek_execute_branches_charcode: +} + +\def_new:Npn \peek_charcode_remove_ignore_spaces:NTF { + \let:NN \peek_execute_branches: \peek_execute_branches_charcode: + \peek_token_remove_generic:NNTF \peek_ignore_spaces_execute_branches: +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\peek_ignore_spaces_aux:} +% \begin{macro}{\peek_ignore_spaces_execute_branches:} +% Throw away a space token and search again. We could define this in +% a more devious way where the auxiliary function gobbles the space +% token but then what do we do if we decide that a certain function +% should ignore more than one specific token? For example someone +% might find it interesting to define a |\peek_| function that +% ignores |a|'s and |b|'s! Or maybe different kinds of ``funny +% spaces''\dots{} Therefore I have decided to use this version which +% uses |\tex_afterassignment:D| to call the auxiliary function after +% the next token has been removed by |\let:NN|. That way it is +% easily extensible. +% \begin{macrocode} +\def_new:Npn \peek_ignore_spaces_aux: { + \peek_after:NN \peek_ignore_spaces_execute_branches: +} +\def_new:Npn \peek_ignore_spaces_execute_branches: { + \token_if_eq_meaning:NNTF \l_peek_token \c_space_token + { \tex_afterassignment:D \peek_ignore_spaces_aux: + \let:NN \peek_tmp:w + } + \peek_execute_branches: +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% +% \begin{macrocode} +%</initex|package> +%<*showmemory> +\showMemUsage +%</showmemory> +% \end{macrocode} +% +% \endinput +% +% $Log$ +% Revision 1.6 2006/03/20 18:26:40 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.5 2006/01/19 22:33:53 morten +% Minor changes in \char_set_XXXcode:nn functions. +% +% Revision 1.4 2006/01/04 01:28:06 morten +% Fixed \peek_execute_branches_charcode: properly. +% +% Revision 1.3 2005/12/29 12:17:32 morten +% Fixed \peek_execute_branches_charcode: plus minor bugs elsewhere +% +% Revision 1.2 2005/12/27 15:48:41 morten +% Fixing initial boo-boos. Updated documentation to reflect current code +% included +% +% Revision 1.1 2005/12/27 09:54:58 morten +% New module +% diff --git a/Master/texmf-dist/source/latex/expl3/l3toks.dtx b/Master/texmf-dist/source/latex/expl3/l3toks.dtx index 7e233e725fc..fd37864c815 100644 --- a/Master/texmf-dist/source/latex/expl3/l3toks.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3toks.dtx @@ -1,15 +1,50 @@ % \iffalse -%% File: l3toks.dtx Copyright (C) 1990-1998 LaTeX3 project +%% File: l3toks.dtx Copyright (C) 1990-2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- % +%<package>\RequirePackage{l3names} %<*dtx> - \ProvidesFile{l3toks.dtx} +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse %</dtx> -%<package>\NeedsTeXFormat{LaTeX2e} -%<package>\ProvidesPackage{l3toks} -%<driver> \ProvidesFile{l3toks.drv} -% \fi -% \ProvidesFile{l3toks.dtx} - [1998/05/14 v1.0g L3 Experimental Token Registers] +%\fi +\GetIdInfo$Id: l3toks.dtx 580 2006-11-26 15:56:47Z morten $ + {L3 Experimental Token Registers} % % \iffalse %<*driver> @@ -22,7 +57,6 @@ % \fi % % -% \GetFileInfo{l3toks.dtx} % \title{The \textsf{l3toks} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ @@ -32,38 +66,46 @@ % \maketitle % % \section {Token Registers} -% +% % There is a second form beside token list pointers in which \LaTeX3 % stores token lists, namely the internal \TeX{} token registers. % Functions dealing with these registers got the prefix "\toks_". Unlike % token list pointers we have an accessing function as one can see % below. -% -% The main difference between <toks> (token registers) and <tlp> (token -% list pointers) is their behavior regarding expansion. While <tlp>'s +% +% The main difference between \m{toks} (token registers) and \m{tlp} (token +% list pointers) is their behavior regarding expansion. While \m{tlp}'s % expand fully (i.e., until only unexpandable tokens are left) inside % an argument that is subject to expansion (i.e., denote by |x|) -% <toks>'s expand always only up to one level, i.e., passing their +% \m{toks}'s expand always only up to one level, i.e., passing their % contents without further expansion. -% +% % \subsection{Functions} -% -% \begin{function}{\toks_new:N} +% +% \begin{function}{% +% \toks_new:N | +% \toks_new:c | +% \toks_new_l:N} % \begin{syntax} % "\toks_new:N" <toks> % \end{syntax} % Defines <toks> to be a new token list register. -% token list pointer. % \begin{texnote} % This is the \LaTeX3 allocation for what was called \tn{newtoks} in % plain \TeX. % \end{texnote} % \end{function} -% +% % \begin{function}{% % \toks_set:Nn | % \toks_set:No | +% \toks_set:Nd | +% \toks_set:Nf | % \toks_set:Nx | +% \toks_set:cn | +% \toks_set:co | +% \toks_set:cf | +% \toks_set:cx | % \toks_gset:Nn | % \toks_gset:No | % \toks_gset:Nx} @@ -83,7 +125,7 @@ % \TeX. % \end{texnote} % \end{function} -% +% % \begin{function}{% % \toks_gset_eq:NN | % } @@ -94,7 +136,7 @@ % "\toks_gset:Nn" for this purpose if the second argument is also a % token register. % \end{function} -% +% % \begin{function}{% % \toks_clear:N | % \toks_gclear:N | @@ -104,12 +146,15 @@ % \end{syntax} % The <toks> is locally or globally cleared. % \end{function} -% +% % \begin{function}{% % \toks_put_left:Nn | % \toks_gput_left:Nn | % \toks_put_right:Nn | +% \toks_put_right:No | +% \toks_put_right:Nx | % \toks_gput_right:Nn | +% \toks_gput_right:No | % \toks_gput_right:Nx | % } % \begin{syntax} @@ -119,7 +164,7 @@ % <toks>. Assignment is done either locally or globally. If possible % append to the right since this operation is faster. % \end{function} -% +% % \begin{function}{\toks_use:N} % \begin{syntax} % "\toks_use:N" <toks> @@ -130,7 +175,7 @@ % Something like \tn{the} <toks>. % \end{texnote} % \end{function} -% +% % \begin{function}{\toks_use_clear:N | % \toks_use_gclear:N} % \begin{syntax} @@ -143,22 +188,31 @@ % function is not exactly the same as calling "\toks_use:N" <toks> % "\toks_clear:N" <toks> in sequence. % \end{function} -% -% \subsection{Predicates} -% -% \begin{function}{\toks_empty:NTF} +% +% \subsection{Predicates and conditionals} +% +% \begin{function}{ +% \toks_if_empty_p:N| +% \toks_if_empty:NTF| +% \toks_if_empty:NT | +% \toks_if_empty:NF| +% \toks_if_empty_p:c| +% \toks_if_empty:cTF | +% \toks_if_empty:cT | +% \toks_if_empty:cF +% } % \begin{syntax} -% "\toks_empty:NTF" <toks> "{"<true code>"}{"<false code>"}" +% "\toks_if_empty:NTF" <toks> "{"<true code>"}{"<false code>"}" % \end{syntax} % Tests if <toks> is empty. % \end{function} -% +% % \subsection{Variable and constants} -% +% % \begin{variable}{\c_empty_toks} % Constant that is always empty. % \end{variable} -% +% % \begin{variable}{% % \l_tmpa_toks | % \l_tmpb_toks | @@ -168,24 +222,24 @@ % Scratch register for immediate use. They are not used by conditionals % or predicate functions. % \end{variable} -% +% % \subsubsection{Internal functions} -% +% % \begin{function}{\toks_put_left_aux:w} % Used by "\toks_put_left:Nn" and its variants. % \end{function} -% -% \begin{function}{\def_toks:D} +% +% \begin{function}{\tex_toksdef:D} % Primitive function for defining a <cs> to correspond to a token % register should not be used by a programmer. % \begin{texnote} % This function was named \tn{toksdef}. % \end{texnote} % \end{function} -% +% % \StopEventually{} % -% \section{The code} +% \subsection{The Implementation} % % We start by ensuring that the required packages are loaded. % We check for \texttt{l3expan} since this a basic package that is @@ -193,16 +247,25 @@ % \begin{macrocode} %<package&check>\RequirePackage{l3chk}\par %<package>\RequirePackage{l3expan}\par -%<*package> +%<*initex|package> % \end{macrocode} % % \begin{macro}{\toks_new:N} +% \begin{macro}{\toks_new_l:N} +% \begin{macro}{\toks_new:c} % Allocates a new token register. This function is already defined above. % \begin{macrocode} -\def_new:Npn \toks_new:N {} -\let:NN \toks_new:N \newtoks % nick from LaTeX for the moment +%<*initex> +\alloc_setup_type:nnn {toks} \c_zero \c_max_register_num +\def_new:Npn \toks_new:N #1{\alloc_reg:NnNN g {toks} \tex_toksdef:D #1} +\def_new:Npn \toks_new_l:N #1{\alloc_reg:NnNN l {toks} \tex_toksdef:D #1} +%</initex> +%<package>\let:NN \toks_new:N \newtoks % nick from LaTeX for the moment +\def_new:Npn \toks_new:c {\exp_args:Nc\toks_new:N} % \end{macrocode} % \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\toks_clear:N} % \begin{macro}{\toks_gclear:N} @@ -224,11 +287,14 @@ % \end{macro} % % \begin{macro}{\toks_use:N} +% \begin{macro}{\toks_use:c} % This function just returns the contents of a token register. % \begin{macrocode} \let_new:NN \toks_use:N \the_internal:D +\def_new:Npn \toks_use:c {\exp_args:Nc\toks_use:N} % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro}{\toks_use_clear:N} % \begin{macro}{\toks_use_gclear:N} @@ -258,24 +324,35 @@ % \end{macro} % % \begin{macro}{\toks_put_left:Nn} +% \begin{macro}{\toks_put_left:No} % \begin{macro}{\toks_gput_left:Nn} -% |\toks_put_left:Nn |\zz{toks}\zv{stuff\/} adds the tokens of {\sl -% stuff\/} on the `left-side' of the token register \m{toks}. +% \begin{macro}{\toks_gput_left:Nx} +% \begin{macro}{\toks_put_left_aux:w} +% |\toks_put_left:Nn |\zz{toks}\zv{stuff\/} adds the tokens of +% \textsl{stuff} on the `left-side' of the token register +% \m{toks}. |\toks_put_left:No| does the same, but expands the +% tokens once. We need to look out for brace stripping so we add a +% token, which is then later removed. % \begin{macrocode} -\def_new:Npn \toks_put_left:Nn #1{\exp_after:NN\toks_put_left_aux:w +\def_new:Npn \toks_put_left:Nn #1{ + \exp_after:NN\toks_put_left_aux:w\exp_after:NN\q_mark \toks_use:N #1\q_stop #1} +\def_new:Npn \toks_put_left:No {\exp_args:NNo \toks_put_left:Nn} \def_new:Npn \toks_gput_left:Nn { %<*check> \pref_global_chk: %</check> %<-check> \pref_global:D \toks_put_left:Nn} +\def_new:Npn \toks_gput_left:Nx {\exp_args:NNx \toks_gput_left:Nn} % \end{macrocode} -% A helper function for |\toks_put_left:Nn|. Its arguments are -% subsequently the tokens of \zv{stuff\/}, the token register -% \zz{toks} and the current contents of \zz{toks}. +% A helper function for |\toks_put_left:Nn|. Its arguments are +% subsequently the tokens of \zv{stuff\/}, the token register +% \zz{toks} and the current contents of \zz{toks}. We make sure to +% remove the token we inserted earlier. % \begin{macrocode} -\def_long_new:Npn \toks_put_left_aux:w #1\q_stop #2#3{#2{#3#1} +\def_long_new:Npn \toks_put_left_aux:w #1\q_stop #2#3{ + #2\exp_after:NN{\use_arg_i:nn{#3}#1} %<*check> \chk_local_or_pref_global:N #2 %</check> @@ -283,9 +360,17 @@ % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\toks_put_right:Nn} % \begin{macro}{\toks_gput_right:Nn} +% \begin{macro}{\toks_put_right:No} +% \begin{macro}{\toks_put_right:Nd} +% \begin{macro}{\toks_put_right:Nf} +% \begin{macro}{\toks_put_right:Nx} +% \begin{macro}{\toks_gput_right:No} % \begin{macro}{\toks_gput_right:Nx} % These macros add a list of tokens to the right of a token register. % \begin{macrocode} @@ -303,15 +388,43 @@ % \end{macrocode} % |\toks_gput_right:Nx| expands its (second) argument. % \begin{macrocode} -\def_new:Npn \toks_gput_right:Nx {\exp_args:Nnx\toks_gput_right:Nn} +%<check>\def_new:Npn \toks_put_right:No {\exp_args:NNo \toks_put_right:Nn } +%<-check>\def_long_new:Npn\toks_put_right:No#1#2{#1\exp_after:NN\exp_after:NN +%<-check>\exp_after:NN{\exp_after:NN\toks_use:N\exp_after:NN #1#2}} +%<check>\def_new:Npn \toks_put_right:Nd {\exp_args:NNd \toks_put_right:Nn } +%<-check>\def_long_new:Npn\toks_put_right:Nd#1#2{ +%<-check> \exp_after:NN\toks_put_right:No\exp_after:NN#1\exp_after:NN{#2}} % \end{macrocode} +% We implement |\toks_put_right:Nf| by hand because I think I might +% use it in the \textsf{l3keyval} module in which case it is going to +% be used a lot. +% \begin{macrocode} +%<check>\def_new:Npn \toks_put_right:Nf {\exp_args:NNf \toks_put_right:Nn } +%<-check>\def_long_new:Npn \toks_put_right:Nf #1#2{ +%<-check> #1\exp_after:NN\exp_after:NN\exp_after:NN{ +%<-check> \exp_after:NN\toks_use:N\exp_after:NN #1\int_to_roman:w -`0#2}} +\def_new:Npn \toks_put_right:Nx {\exp_args:NNx \toks_put_right:Nn } +\def_new:Npn \toks_gput_right:No {\exp_args:NNo\toks_gput_right:Nn} +\def_new:Npn \toks_gput_right:Nx {\exp_args:NNx\toks_gput_right:Nn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\toks_set:Nn} % \begin{macro}{\toks_set:No} +% \begin{macro}{\toks_set:Nd} +% \begin{macro}{\toks_set:Nf} % \begin{macro}{\toks_set:Nx} +% \begin{macro}{\toks_set:cn} +% \begin{macro}{\toks_set:co} +% \begin{macro}{\toks_set:cf} +% \begin{macro}{\toks_set:cx} % |\toks_set:Nn|\m{toks}\m{stuff} stores \m{stuff} without expansion % in \m{toks}. |\toks_set:No| and |\toks_set:Nx| expand \m{stuff} once % and fully. @@ -320,13 +433,34 @@ \def_new:Npn \toks_set:Nn #1{\chk_local:N #1#1} %</check> % \end{macrocode} -% If we don't check if \m{toks} is a local register then the +% If we don't check if \m{toks} is a local register then the % |\toks_set:Nn| function has nothing to do. % \begin{macrocode} %<-check> \let_new:NN \toks_set:Nn\use_noop: -\def_new:Npn \toks_set:No {\exp_args:NNo \toks_set:Nn} +%<-check> \def_long_new:Npn \toks_set:No#1#2{#1\exp_after:NN{#2}} +%<-check> \def_long_new:Npn \toks_set:Nd#1#2{ +%<-check> #1\exp_after:NN\exp_after:NN\exp_after:NN{#2}} +%<check> \def_new:Npn \toks_set:No {\exp_args:NNo \toks_set:Nn} +%<check> \def_new:Npn \toks_set:Nd {\exp_args:NNd \toks_set:Nn} \def_new:Npn \toks_set:Nx {\exp_args:NNx \toks_set:Nn} % \end{macrocode} +% We implement |\toks_set:Nf| by hand when not checking because this +% is going to be used \emph{extensively} in keyval processing! +% \begin{macrocode} +%<check>\def_new:Npn \toks_set:Nf {\exp_args:NNf \toks_set:Nn} +%<-check>\def_long_new:Npn\toks_set:Nf #1#2{ +%<-check> #1\exp_after:NN{\int_to_roman:w -`0#2}} +\def_new:Npn \toks_set:cf {\exp_args:Nc\toks_set:Nf} +\def_new:Npn \toks_set:cn {\exp_args:Nc\toks_set:Nn} +\def_new:Npn \toks_set:co {\exp_args:Nc\toks_set:No} +\def_new:Npn \toks_set:cx {\exp_args:Nc\toks_set:Nx} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % \end{macro} % \end{macro} % \end{macro} @@ -334,6 +468,9 @@ % \begin{macro}{\toks_gset:Nn} % \begin{macro}{\toks_gset:No} % \begin{macro}{\toks_gset:Nx} +% \begin{macro}{\toks_gset:cn} +% \begin{macro}{\toks_gset:co} +% \begin{macro}{\toks_gset:cx} % These functions are the global variants of the above. % \begin{macrocode} %<*check> @@ -342,13 +479,25 @@ %<-check> \let_new:NN \toks_gset:Nn\pref_global:D \def_new:Npn \toks_gset:No {\exp_args:NNo \toks_gset:Nn} \def_new:Npn \toks_gset:Nx {\exp_args:NNx \toks_gset:Nn} +\def_new:Npn \toks_gset:cn {\exp_args:Nc \toks_gset:Nn} +\def_new:Npn \toks_gset:co {\exp_args:Nc \toks_gset:No} +\def_new:Npn \toks_gset:cx {\exp_args:Nc \toks_gset:Nx} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\toks_set_eq:NN} +% \begin{macro}{\toks_set_eq:Nc} +% \begin{macro}{\toks_set_eq:cN} +% \begin{macro}{\toks_set_eq:cc} % \begin{macro}{\toks_gset_eq:NN} +% \begin{macro}{\toks_gset_eq:Nc} +% \begin{macro}{\toks_gset_eq:cN} +% \begin{macro}{\toks_gset_eq:cc} % |\toks_set_eq:NN|\m{toks1}\m{toks2} copies the contents of \m{toks2} % in \m{toks1}. % \begin{macrocode} @@ -364,20 +513,102 @@ %</check> %<-check> \let_new:NN \toks_set_eq:NN \use_noop: %<-check> \let_new:NN \toks_gset_eq:NN \pref_global:D +\def_new:Npn \toks_set_eq:Nc {\exp_args:NNc\toks_set_eq:NN} +\def_new:Npn \toks_set_eq:cN {\exp_args:Nc\toks_set_eq:NN} +\def_new:Npn \toks_set_eq:cc {\exp_args:Ncc\toks_set_eq:NN} +\def_new:Npn \toks_gset_eq:Nc {\exp_args:NNc\toks_gset_eq:NN} +\def_new:Npn \toks_gset_eq:cN {\exp_args:Nc\toks_gset_eq:NN} +\def_new:Npn \toks_gset_eq:cc {\exp_args:Ncc\toks_gset_eq:NN} % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % -% \begin{macro}{\toks_empty:NTF} -% |\toks_empty:NTF|\m{toks}\m{true code}\m{false code} tests if -% a token register is empty and executes either \m{true code} or -% \m{false code}. +% \begin{macro}{\toks_if_empty_p:N} +% \begin{macro}{\toks_if_empty_p:c} +% \begin{macro}{\toks_if_empty:NTF} +% \begin{macro}{\toks_if_empty:cTF} +% \begin{macro}{\toks_if_empty:NT} +% \begin{macro}{\toks_if_empty:cT} +% \begin{macro}{\toks_if_empty:NF} +% \begin{macro}{\toks_if_empty:cF} +% |\toks_if_empty:NTF|\m{toks}\m{true code}\m{false code} tests if a +% token register is empty and executes either \m{true code} or +% \m{false code}. This test had the advantage of being +% expandable. Otherwise one has to do an |x| type expansion in order +% to prevent problems with parameter tokens. % \begin{macrocode} -\def_new:Npn\toks_empty:NTF#1{ - \tlp_set:No\l_testa_tlp{\toks_use:N#1} - \tlp_empty:NTF\l_testa_tlp} +\def_new:Npn\toks_if_empty_p:N#1{ + \if:w \tlist_if_empty_p:o{\toks_use:N #1} + \c_true + \else: + \c_false + \fi: +} +\def_test_function_new:npn{toks_if_empty:N}#1{\if:w \toks_if_empty_p:N #1} +\def_new:Npn\toks_if_empty:cTF{\exp_args:Nc\toks_if_empty:NTF} +\def_new:Npn\toks_if_empty:cT{\exp_args:Nc\toks_if_empty:NT} +\def_new:Npn\toks_if_empty:cF{\exp_args:Nc\toks_if_empty:NF} % \end{macrocode} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\toks_if_eq:NNTF} +% \begin{macro}{\toks_if_eq:NNT} +% \begin{macro}{\toks_if_eq:NNF} +% \begin{macro}{\toks_if_eq:NcTF} +% \begin{macro}{\toks_if_eq:NcT} +% \begin{macro}{\toks_if_eq:NcF} +% \begin{macro}{\toks_if_eq:cNTF} +% \begin{macro}{\toks_if_eq:cNT} +% \begin{macro}{\toks_if_eq:cNF} +% \begin{macro}{\toks_if_eq:ccTF} +% \begin{macro}{\toks_if_eq:ccT} +% \begin{macro}{\toks_if_eq:ccF} +% This function test whether two token registers contain the same. +% \begin{macrocode} +\def_new:NNn \toks_if_eq:NNTF 2 { + \tlist_if_eq:xxTF{\toks_use:N #1}{\toks_use:N #2} +} +\def_new:NNn \toks_if_eq:NNT 2 { + \tlist_if_eq:xxT{\toks_use:N #1}{\toks_use:N #2} +} +\def_new:NNn \toks_if_eq:NNF 2 { + \tlist_if_eq:xxF{\toks_use:N #1}{\toks_use:N #2} +} +\def_new:Npn \toks_if_eq:NcTF {\exp_args:NNc \toks_if_eq:NNTF} +\def_new:Npn \toks_if_eq:NcT {\exp_args:NNc \toks_if_eq:NNT} +\def_new:Npn \toks_if_eq:NcF {\exp_args:NNc \toks_if_eq:NNF} +\def_new:Npn \toks_if_eq:cNTF {\exp_args:Nc \toks_if_eq:NNTF} +\def_new:Npn \toks_if_eq:cNT {\exp_args:Nc \toks_if_eq:NNT} +\def_new:Npn \toks_if_eq:cNF {\exp_args:Nc \toks_if_eq:NNF} +\def_new:Npn \toks_if_eq:ccTF {\exp_args:Ncc \toks_if_eq:NNTF} +\def_new:Npn \toks_if_eq:ccT {\exp_args:Ncc \toks_if_eq:NNT} +\def_new:Npn \toks_if_eq:ccF {\exp_args:Ncc \toks_if_eq:NNF} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\l_tmpa_toks} % \begin{macro}{\l_tmpb_toks} @@ -388,6 +619,7 @@ % Some scratch register \ldots % \begin{macrocode} \tex_toksdef:D \l_tmpa_toks = 255 +%<initex>\seq_put_right:Nn \g_toks_allocation_seq {255} \toks_new:N \l_tmpb_toks \toks_new:N \l_tmpc_toks \toks_new:N \g_tmpa_toks @@ -408,10 +640,81 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\toks_remove_extra_brace_group:N} +% \begin{macro}{\toks_remove_extra_brace_group_aux:NNw} +% Small function for removing an extra brace group if present. Hmm, +% not really needed anymore. +% \begin{macrocode} +\def_new:Npn \toks_remove_extra_brace_group:N #1{ + \exp_after:NN \toks_remove_extra_brace_group_aux:NNw + \exp_after:NN \toks_set:Nn \exp_after:NN #1 + \toks_use:N#1\q_nil +} +\def_long_new:Npn\toks_remove_extra_brace_group_aux:NNw #1#2#3\q_nil{#1#2{#3}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% % Show token usage: % \begin{macrocode} -%</package> +%</initex|package> %<*showmemory> \showMemUsage %</showmemory> % \end{macrocode} +% +% \endinput +% +% $Log$ +% Revision 1.25 2006/08/01 01:54:12 morten +% Prevent brace stripping in \toks_put_left:Nn and friends. +% +% Revision 1.24 2006/03/20 18:26:40 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.23 2006/02/16 23:32:49 braams +% Imported \toks_put_left:No from l3messages +% +% Revision 1.22 2006/01/21 11:43:20 morten +% Tuned some of the \toks_set and \toks_put_right functions since they +% are going to be used intensively in the l3keyval module which is again +% going to be heavily used. +% +% Revision 1.21 2006/01/20 12:22:44 morten +% Minor changes plus added \toks_remove_extra_brace_group:N for l3keyval +% module +% +% Revision 1.20 2005/12/27 10:03:39 morten +% Changed RCS information retrieval +% +% Revision 1.19 2005/12/23 13:24:39 morten +% Added a few functions from template +% +% Revision 1.18 2005/12/21 20:44:04 morten +% Corrected typo. +% +% Revision 1.17 2005/12/02 15:56:48 morten +% Added some more functions and improved test for emptiness. +% +% Revision 1.16 2005/04/12 13:22:37 morten +% More functions added +% +% Revision 1.15 2005/04/07 08:18:17 morten +% Only put 255 in the toks stack when running initex +% +% Revision 1.14 2005/04/06 22:35:50 braams +% Now we have register allocation fitted +% +% Revision 1.13 2005/04/06 21:37:50 morten +% Added some more functions +% +% Revision 1.12 2005/03/15 23:39:21 braams +% Some fiddling to get it loaded by initex; needs a way to allocate +% token registers for it to work. +% +% Revision 1.11 2005/03/11 21:25:06 braams +% Changed copyright year, fixed use of RCS values; +% fixed a few typos in the documentation; +% \c_if_empty_toks had to be \c_empty_toks +% diff --git a/Master/texmf-dist/source/latex/expl3/l3vers.dtx b/Master/texmf-dist/source/latex/expl3/l3vers.dtx new file mode 100644 index 00000000000..06f9d44c694 --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3vers.dtx @@ -0,0 +1,145 @@ +% \iffalse +%% File: l3vers.dtx Copyright (C) 1990-2005 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3vers.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental LaTeX format version} +% +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3vers.dtx} +\end{document} +%</driver> +% \fi +% +% \section{Version Identification} +% Here we identify the date and version number of this release of +% \LaTeX3, and set |\tex_everyjob:D| so that it is printed at the start of +% every \LaTeX3 run. +% +% \StopEventually{} +% +% +% \begin{macro}{\c_format_name} +% \begin{macro}{\c_format_date} +% \begin{macrocode} +%<*initex> +\def:Npn\c_format_name{Experimental~ LaTeX3} +\def:Npn\c_format_date{2005/12/25} +%^^A\def:Npx\c_format_version{--release--date--goes--here--} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\c_fmt_too_old} +% \begin{macro}{\chk_format_age:w} +% Check that the format being made is not too old. While in development +% it should be a rather small number. +% \begin{macrocode} +\const_new:Nn \c_fmt_too_old{12} +\def:Npn\chk_format_age:w #1/#2/#3\q_stop{ +% \end{macrocode} +% We just calculate the age of this file in months and give a warning +% if deemed too old. +% \begin{macrocode} + \num_compare:nNnT{(\tex_year:D-#1)*12+\tex_month:D-#2}>\c_fmt_too_old + {\iow_expanded_term:n{^^J + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^J + !~~You~are~attempting~to~make~an~experimental~LaTeX3~format~from^^J + !~~source~files~that~are~more~than~ + \num_use:N\num_eval:n{\c_fmt_too_old}~months~old.^^J + !^^J + !~~If~you~enter~<return>~to~scroll~past~this~message~then~the~format^^J + !~~will~be~built,~but~please~consider~obtaining~newer~source~files^^J + !~~before~continuing~to~build~an~experimental~LaTeX3~format.^^J + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^^J + } + \tex_errhelp:D{ + To~avoid~this~error~message,~obtain~new~Experimental~LaTeX3~sources.} + \tex_errmessage:D{ + Experimental~LaTeX3~source~files~are~more~than~ + \num_use:N\num_eval:n{\c_fmt_too_old}~months~old!} + } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% Then we execute it. +% \begin{macrocode} +\exp_after:NN\chk_format_age:w\c_format_date\q_stop +% \end{macrocode} +% And since it's no longer needed we remove it again. +% \begin{macrocode} +\cs_gundefine:N \chk_format_age:w +% \end{macrocode} +% +% This startup banner may be further modified by the code in +% |ltfinal.dtx| if a patch file is present. +% \begin{macrocode} +\tex_everyjob:D{\io_put_term:x{\c_format_name,~<\c_format_date>}} +\io_put_term:x{\c_format_name,~<\c_format_date>} +%</initex> +% \end{macrocode} +% +% \endinput +% +% $Log$ +% Revision 1.5 2005/12/27 15:54:15 morten +% Changed RCS information retrieval +% +% Revision 1.4 2005/04/13 09:52:47 morten +% Fix spaces in messages, make fast calculation of format age, fixed \DocInput, added \endinput +% +% Revision 1.3 2005/04/12 22:42:22 braams +% Removed a few redundant lines with docstrip instructions +% +% Revision 1.2 2005/04/11 22:46:47 braams +% Translated this file into the ltx3 lingo +% This file may need further cleanup at a later stage +% +% Revision 1.1 2005/03/11 21:26:31 braams +% File copied from 2e for now, to hold the format version identification +% diff --git a/Master/texmf-dist/source/latex/expl3/l3xref.dtx b/Master/texmf-dist/source/latex/expl3/l3xref.dtx new file mode 100644 index 00000000000..2f03bf8b387 --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3xref.dtx @@ -0,0 +1,379 @@ +% \iffalse +%% File: l3xref.dtx Copyright (C) 2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} +%<*dtx|testfile> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% +%\iffalse +%<dtx> \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +%<-dtx> \ProvidesFile{\jobname.tex}[#3/#4/#5 v#2 #8]% +%\fi +} +%\iffalse +%</dtx|testfile> +%\fi +\GetIdInfo$Id: l3xref.dtx 579 2006-11-25 23:38:03Z morten $ + {L3 Experimental cross referencing} +% +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3xref.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3xref} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}\\ +% Cross references} +% \author{\Team} +% \date{\filedate} +% \maketitle +% +% +% \section{Cross references} +% +% \begin{function}{\xref_set_label:n} +% \begin{syntax} +% "\xref_set_label:n" "{"<name>"}" +% \end{syntax} +% Sets a label in the text. Note that this function does not do +% anything else than setting the correct labels. In particular, it +% does not try to fix any spacing around the write node; this is a +% task for the \textsf{galley2} module. +% \end{function} +% +% \begin{function}{\xref_new:nn} +% \begin{syntax} +% "\xref_new:nn" "{"<type>"}" "{"<value>"}" +% \end{syntax} +% Defines a new cross reference type <type>. This defines the token +% list pointer |\l_xref_curr_|<type>|_tlp| with default value +% <value> which gets written fully expanded when |\xref_set_label:n| +% is called. +% \end{function} +% +% +% \begin{function}{\xref_deferred_new:nn} +% \begin{syntax} +% "\xref_deferred_new:nn" "{"<type>"}" "{"<value>"}" +% \end{syntax} +% Same as |\xref_new:n| except for this one, the value written +% happens when \TeX\ ships out the page. Page numbers use this one +% obviously. +% \end{function} +% +% \begin{function}{\xref_get_value:nn} +% \begin{syntax} +% "\xref_get_value:nn" "{"<type>"}" "{"<name>"}" +% \end{syntax} +% Extracts the cross reference information of type <type> for the +% label <name>. This operation is expandable. +% \end{function} +% +% +% \StopEventually{} +% +% \subsection{Implementation} +% +% +% We start by ensuring that the required packages are loaded. +% \begin{macrocode} +%<*package> +\RequirePackage{l3quark} +\RequirePackage{l3toks} +\RequirePackage{l3io} +\RequirePackage{l3prop} +\RequirePackage{l3int} +\RequirePackage{l3token} +%</package> +%<*initex|package> +% \end{macrocode} +% +% +% +% There are two kinds of information, namely information which is +% \emph{immediate} like a section title and then there's \emph{deferred} +% information like page numbers. Each reference type belong to one of +% these categories, which we save internally as the property lists +% |\g_xref_all_curr_immediate_fields_plist| and +% |\g_xref_all_curr_deferred_fields_plist| and the reference type +% \meta{xyz} exists as the key-info pair |\xref_|\meta{xyz}|_key| +% |{\l_xref_curr_|\meta{xyz}|_tlp}| on one of these lists. This way each +% new entry type is just added as another key-info pair. +% +% When the cross references are generated at the beginning of the +% document each will turn into a control sequence. Thus |\label{mylab}| +% will internally refer to the property list |\g_xref_mylab_plist|. +% +% The extraction of values from this property list can be done in +% several different ways but we want to keep the operation +% expandable. Therefore we use a dedicated function for each type of +% cross reference, which looks like this: +% \begin{verbatim} +% \xref_get_value_xyz_aux:w -> #1 \xref_xyz_key #2#3\q_nil{#2} +% \end{verbatim} +% This will throw away all the bits we don't need. In case |xyz| is +% the first on the |mylab| property list |#1| is empty, if it's the +% last key-info pair |#3| is empty. The value of the field can be +% extracted with the function |\xref_get_value:nn| where the first +% argument is the type and the second the label name so here it would +% be |\xref_get_value:nn| |{xyz}| |{mylab}|. +% +% \begin{macro}{\g_xref_all_curr_immediate_fields_plist} +% \begin{macro}{\g_xref_all_curr_deferred_fields_plist} +% The two main property lists for storing information. They contain +% key-info pairs for all known types. +% \begin{macrocode} +\prop_new:N \g_xref_all_curr_immediate_fields_plist +\prop_new:N \g_xref_all_curr_deferred_fields_plist +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\xref_new:nn} +% \begin{macro}{\xref_deferred_new:nn} +% \begin{macro}{\xref_new_aux:nnn} +% Setting up a new cross reference type is fairly straight forward +% when we follow the game plan mentioned earlier. +% \begin{macrocode} +\def_new:Npn \xref_new:nn {\xref_new_aux:nnn{immediate}} +\def_new:Npn \xref_deferred_new:nn {\xref_new_aux:nnn{deferred}} +\def_new:Npn \xref_new_aux:nnn #1#2#3{ +% \end{macrocode} +% First put the new type in the relevant property list. +% \begin{macrocode} + \prop_gput:ccx {g_xref_all_curr_ #1 _fields_plist} + { xref_ #2 _key } + { \exp_not:c {l_xref_curr_#2_tlp }} +% \end{macrocode} +% Then define the key to be a protected macro.\footnote{We could also +% set it equal to \cs{scan_stop:} but this just feels ``cleaner''.} +% \begin{macrocode} + \def_protected:cpn { xref_#2_key }{} + \tlp_new:cn{l_xref_curr_#2_tlp}{#3} +% \end{macrocode} +% Now for the function extracting the value of a reference. We could +% do this with a simple |\prop_if_in| thing put since we want to do +% things in an expandable way we make a separate grabber for each +% type---this is also faster. The grabber function can be defined by +% using an intricate construction of |\exp_after:NN| and other goodies +% but I prefer readable code. The end result for the input |xyz| is +% \begin{verbatim} +% \def:Npn\xref_get_value_xyz_aux:w #1\xref_xyz_key #2#3\q_nil{#2} +% \end{verbatim} +% \begin{macrocode} + \toks_set:Nx \l_tmpa_toks { + \exp_not:n { \def:cpn {xref_get_value_#2_aux:w} ##1 } + \exp_not:c { xref_#2_key } + } + \toks_use:N \l_tmpa_toks ##2 ##3\q_nil {##2} +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\xref_get_value:nn} +% Getting the correct value for a given label-type pair is a matter +% of connecting the correct grabber functions and property list. +% \begin{macrocode} +\def_new:Npn \xref_get_value:nn #1#2 { + \cs_if_really_free:cTF{g_xref_#2_plist} + {??} + { +% \end{macrocode} +% This next expansion may look a little weird but it isn't if you +% think about it! +% \begin{macrocode} + \exp_args:NcNc \exp_after:NN {xref_get_value_#1_aux:w} + \prop_use:N {g_xref_#2_plist} +% \end{macrocode} +% Better put in the stop marker. +% \begin{macrocode} + \q_nil + } +} +\def:NNn \exp_after:cc 2 { + \exp_after:NN \exp_after:NN + \cs:w #1\exp_after:NN\cs_end: \cs:w #2\cs_end: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xref_define_label:nn} +% \begin{macro}{\xref_define_label_aux:nn} +% Define the property list for each label. We better do this in two +% steps because the special catcode regime is in effect and since +% some of the info fields are very likely to contain actual text, +% we better make sure spaces aren't ignored! As for the meaning of +% other characters then it is a possibility to also have a field +% containing catcode instructions which can then be activated with +% |\etex_scantokens:D|. +% \begin{macrocode} +\def_protected_new:Npn \xref_define_label:nn { + \group_begin: + \char_set_catcode:nn {`\ }\c_ten + \xref_define_label_aux:nn +} +% \end{macrocode} +% If the label is already taken we have a multiply defined label and +% we should do something about it. For now we don't do anything +% spectacular. +% \begin{macrocode} +\def_new:Npn \xref_define_label_aux:nn #1#2 { + \cs_if_really_free:cTF{g_xref_#1_plist} + {\prop_new:c{g_xref_#1_plist}}{\WARNING} + \toks_gset:cn{g_xref_#1_plist}{#2} + \group_end: +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\xref_set_label:n} +% Then the generic command for setting a label. We expand the +% immediate labels fully before calling the write function but make +% sure the deferred fields aren't expanded just yet. Due to property +% lists being implemented as token list registers we must expand the +% `immediate' fields twice. +% \begin{macrocode} +\def:Npn \xref_set_label:n #1{ + \def:Npx \tmp:w{\prop_use:N\g_xref_all_curr_immediate_fields_plist} + \exp_args:NNx\iow_deferred_expanded:Nn \xref_write{ + \xref_define_label:nn {#1} { + \tmp:w + \prop_use:N \g_xref_all_curr_deferred_fields_plist + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xref_write} +% A stream for writing cross references although they do not require +% to be in a separate file. +% \begin{macrocode} +\iow_new:N \xref_write +% \end{macrocode} +% \end{macro} +% +% That's it (for now). +% \begin{macrocode} +%</initex|package> +%<*showmemory> +\showMemUsage +%</showmemory> +% \end{macrocode} +% +% +% \begin{macrocode} +%<*testfile> +\documentclass{article} +\usepackage{l3xref} +\CodeStart +\def:Npn \startrecording {\iow_open:Nn \xref_write {\jobname.xref}} +\def:Npn \DefineCrossReferences { + \group_begin: + \NamesStart + \InputIfFileExists{\jobname.xref}{}{} + \group_end: +} +\AtBeginDocument{\DefineCrossReferences\startrecording} + +\xref_new:nn {name}{} +\def:Npn \setname{\tlp_set:Nn\l_xref_curr_name_tlp} +\def:Npn \getname{\xref_get_value:nn{name}} + +\xref_deferred_new:nn {page}{\thepage} +\def:Npn \getpage{\xref_get_value:nn{page}} + +\xref_deferred_new:nn {valuepage}{\number\value{page}} +\def:Npn \getvaluepage{\xref_get_value:nn{valuepage}} + +\let:NN \setlabel \xref_set_label:n + +\CodeStop +\begin{document} +\pagenumbering{roman} + +Text\setname{This is a name}\setlabel{testlabel1}. More +text\setname{This is another name}\setlabel{testlabel2}. \clearpage + +Text\setname{This is a third name}\setlabel{testlabel3}. More +text\setname{Hello World!}\setlabel{testlabel4}. \clearpage + +\pagenumbering{arabic} + +Text\setname{Name 5}\setlabel{testlabel5}. More text\setname{Name + 6}\setlabel{testlabel6}. \clearpage + +Text\setname{Name 7}\setlabel{testlabel 7}. More text\setname{Name + 8}\setlabel{testlabel8}. \clearpage + +Now let's extract some values. \getname{testlabel1} on page +\getpage{testlabel1} with value \getvaluepage{testlabel1}. + +Now let's extract some values. \getname{testlabel 7} on page +\getpage{testlabel 7} with value \getvaluepage{testlabel 7}. +\end{document} +%</testfile> +% \end{macrocode} +% +% +% \endinput +% +% $Log$ +% Revision 1.4 2006/03/20 18:26:42 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.3 2006/01/16 11:26:57 morten +% Minor changes +% +% Revision 1.2 2006/01/15 14:07:31 braams +% Activated \StopEventually{} +% +% Revision 1.1 2006/01/15 07:55:06 morten +% New cross reference module including test file. +% +%
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/expl3/readme.txt b/Master/texmf-dist/source/latex/expl3/readme.txt deleted file mode 100644 index ae888d040d9..00000000000 --- a/Master/texmf-dist/source/latex/expl3/readme.txt +++ /dev/null @@ -1,224 +0,0 @@ - - Experimental Packages Demonstrating - A Possible LaTeX3 Programming Convention - ======================================== - - 1998/04/20 - - -OVERVIEW --------- - -The packages in this directory implement a possible language for `low -level' programming in TeX. The syntax conventions described here are NOT -intended either for use in documents or for use in describing design -layouts in document class files. - -All aspects of these package are *experimental*. The names of the -packages, and the names of any commands that they define, may change -at any time. They are being released in this form to allow public -discussion and comment. - -Currently all the code is distributed in a format suitable for running -as LaTeX2e packages. Further documentation may be produced by processing -the .dtx files with LaTeX2e. The packages may be installed by processing -l3.ins with plain TeX or LaTeX. - -This code has be developed over time and has been used in previous -versions for prototype implementations, experiments, etc. Its internal -documentation (in the .dtx files) reflects the age of parts of it; it -often contains personal comments and it sometimes refers to parts that -not at present distributed. We kindly ask you to overlook its -deficiencies and inaccuracies --- if we had tried to clean this up it -would never have surfaced and, for the purpose of discussions and -comments, we hope its present form is adequate. - - -NOTE (docstrip version) ------------------------ - -If latex l3.ins -produces the `docstrip interactive mode' prompt: - - * First type the extension of your input file(s): * - \infileext= - -Then your version of docstrip is too old. -Quit (eg by hitting `enter' to all questions) and get a newer -docstrip.tex. It must be at least version 2.4. - -A suitable docstrip.tex may be found from `CTAN' archives such as -ftp.dante.de tex-archive/macros/latex/unpacked/docstrip.tex - -Docstrip is part of the base LaTeX distribution, so if you have -an old docstrip then your LaTeX is out of date and you may consider -getting the whole of that directory and re-installing LaTeX. -However you need to fetch only the file docstrip.tex to unpack -this expl3 distribution with your existing format. - - - -THE GUILTY PERSONS ------------------- - - Frank Mittelbach, Denys Duchier, Johannes Braams, Michael Downes, - David Carlisle, Alan Jeffrey, Chris Rowley, Rainer Schoepf - - -DISCUSSION ----------- - -Discussion concerning the approach, suggestions for improvements, changes, -additions, etc. should be addressed to the list LATEX-L. - -You can subscribe to this list by sending mail to - - listserv@urz.uni-heidelberg.de - -with the body containing - - subscribe LATEX-L <Your-First-Name> <Your-Second-Name> - - -BUGS ----- - -If you find a real bug that makes a package stop working you can -report it via the standard latexbug.tex mechanism of the LaTeX -distribution (see bugs.txt there) using the category "l3exp". -However please do *not* use this method for suggestions / comments / -improvements / etc. For this the list LATEX-L should be used instead. - -Also please don't expect these package to work with *any* code that -floats around in the LaTeX2e world. :-) - - - -MANIFEST --------- - -The following packages are in this release: - - -l3names -======= - -Documents the general naming scheme, and gives new names to all the TeX -primitives. - -If this package is used with the option [removeoldnames] then the -original TeX primitive names (\hbox, \def, ...) are made *undefined* and -so free to be defined for other purposes if needed. Of course this -breaks almost all existing LaTeX2 code, but it may be used for testing -purposes, see test2.tex. - -l3basics -======== - -Some basic definitions that are used by the other packages. - -l3chk -===== - -Functions that check definitions. -(Comparable to LaTeX2's \newcommand/\renewcommand.) - -l3tlp -===== - -Token List Pointers. A basic LaTeX3 datatype for storing token lists. -(These are essentially macros with no arguments.) -(Package can be compiled with checking enabled.) - -l3expan -======= - -The argument expansion module. One of the main features of the language -proposed here is a systematic treatment of the handling of argument -expansion. The basic functions for preprocessing command arguments are -defined here. - -l3quark -======= - -A `quark' is a command that is defined to expand to itself. So it may -not be directly used (it would generate an infinite loop) but has many -uses as special markers within LaTeX code. - -l3seq -===== - -A module implementing the basic list and stack datatypes. - -l3prop -====== - -Property lists are the datatype for handling key/value assignments. - -l3int -===== - -Integer and fake integer registers. With eTeX/Omega becoming more and -more accessible this module is, at least in parts only of historical -significance. (Can be compiled with checking enabled) - -l3toks -====== - -TeX's token registers. (Can be compiled with checking enabled) - -l3io -==== - -Low-level input and ouput. - -l3precom -========= - -Low-level pointer-related code, with further checking and tracing. - - -===================================================================== - -Install file -============= - -l3.ins -====== - -Process with plain TeX or LaTeX2e to generate the experimental -packages. - -===================================================================== - -Test Files -========== - -Two test files show the expansion module at work. - -test1.tex -========= - -Test document showing the expansion module at work. - -test2.tex -========= - -The same test as the file test1, but this time the l3names package is -loaded with [removeoldnames]. This is useful for testing, but as it -breaks all LaTeX2 code, it is not so useful for documents. (For -example {document} would generate an error.) In this mode -\RequirePackage may be used to load further packages, as demonstrated -in this file, but any other LaTeX2 command is likely to fail. - -test3.tex -========= - -This tests the io and precomp modules. - - -===================================================================== - ---- Copyright 1998 - The LaTeX3 Project. All rights reserved --- - diff --git a/Master/texmf-dist/source/latex/expl3/test1.dmp b/Master/texmf-dist/source/latex/expl3/test1.dmp deleted file mode 100644 index ecb21f24572..00000000000 --- a/Master/texmf-dist/source/latex/expl3/test1.dmp +++ /dev/null @@ -1 +0,0 @@ -\dumpLaTeXstate macro:#1->\iow_expanded_term:n {Dumping commands into (#1.dmp)}\iow_open:Nn \c_cs_dump_stream {#1.dmp}\seq_map_inline:Nn \g_cs_trace_seq {\tex_message:D {.}\iow_expanded:Nn \c_cs_dump_stream {\token_to_string:N ##1 \token_to_meaning:N ##1}}\tex_message:D { registers}\seq_map_inline:Nn \g_register_trace_seq {\tex_message:D {.}\iow_expanded:Nn \c_cs_dump_stream {\token_to_string:N ##1\the_internal:D ##1}}\tex_message:D { finished} diff --git a/Master/texmf-dist/source/latex/expl3/test2.dmp b/Master/texmf-dist/source/latex/expl3/test2.dmp deleted file mode 100644 index 3a93bfcdb53..00000000000 --- a/Master/texmf-dist/source/latex/expl3/test2.dmp +++ /dev/null @@ -1,2 +0,0 @@ -\dumpLaTeXstate macro:#1->\iow_expanded_term:n {Dumping commands into (#1.dmp)}\iow_open:Nn \c_cs_dump_stream {#1.dmp}\seq_map_inline:Nn \g_cs_trace_seq {\tex_message:D {.}\iow_expanded:Nn \c_cs_dump_stream {\token_to_string:N ##1 \token_to_meaning:N ##1}}\tex_message:D { registers}\seq_map_inline:Nn \g_register_trace_seq {\tex_message:D {.}\iow_expanded:Nn \c_cs_dump_stream {\token_to_string:N ##1\the_internal:D ##1}}\tex_message:D { finished} -\l_my_int42 diff --git a/Master/texmf-dist/source/latex/expl3/test3.dmp b/Master/texmf-dist/source/latex/expl3/test3.dmp deleted file mode 100644 index de4c6f395bc..00000000000 --- a/Master/texmf-dist/source/latex/expl3/test3.dmp +++ /dev/null @@ -1,2 +0,0 @@ -\dumpLaTeXstate macro:#1->\iow_expanded_term:n {Dumping commands into (#1.dmp)}\iow_open:Nn \c_cs_dump_stream {#1.dmp}\seq_map_inline:Nn \g_cs_trace_seq {\tex_message:D {.}\iow_expanded:Nn \c_cs_dump_stream {\token_to_string:N ##1 \token_to_meaning:N ##1}}\tex_message:D { registers}\seq_map_inline:Nn \g_register_trace_seq {\tex_message:D {.}\iow_expanded:Nn \c_cs_dump_stream {\token_to_string:N ##1\the_internal:D ##1}}\tex_message:D { finished} -\l_my_int0 diff --git a/Master/texmf-dist/source/latex/expl3/testdump.cmp b/Master/texmf-dist/source/latex/expl3/testdump.cmp deleted file mode 100644 index 081751f9871..00000000000 --- a/Master/texmf-dist/source/latex/expl3/testdump.cmp +++ /dev/null @@ -1,7 +0,0 @@ -\group_begin: \tex_catcode:D `\*=11\scan_stop: \CodeStart -\gdef:Npn\g*i{bar} -\gdef:Npn\l*i{foo} -\gdef:Npn\foo{somefoo} -\fint_gset:Nn\g_gen_sym_fint {1} -\fint_gset:Nn\g_ggen_sym_fint {1} -\group_end: |